Merge "Do not merge : cancel text select mode when pressing back, etc." into gingerbread
diff --git a/Android.mk b/Android.mk
index 29c8cb4..566b36f 100644
--- a/Android.mk
+++ b/Android.mk
@@ -352,6 +352,7 @@
 # The since flag (-since N.xml API_LEVEL) is used to add API Level information
 # to the reference documentation. Must be in order of oldest to newest.
 framework_docs_LOCAL_DROIDDOC_OPTIONS := \
+    -knowntags ./frameworks/base/docs/knowntags.txt \
     -since ./frameworks/base/api/1.xml 1 \
     -since ./frameworks/base/api/2.xml 2 \
     -since ./frameworks/base/api/3.xml 3 \
@@ -360,10 +361,13 @@
     -since ./frameworks/base/api/6.xml 6 \
     -since ./frameworks/base/api/7.xml 7 \
     -since ./frameworks/base/api/8.xml 8 \
-		-error 1 -error 2 -warning 3 -error 4 -error 6 -error 8 -error 14 \
-		-overview $(LOCAL_PATH)/core/java/overview.html
+    -werror -hide 13 \
+    -overview $(LOCAL_PATH)/core/java/overview.html
 
-framework_docs_LOCAL_ADDITIONAL_JAVA_DIR:=$(call intermediates-dir-for,JAVA_LIBRARIES,framework)
+framework_docs_LOCAL_ADDITIONAL_JAVA_DIR:= $(call intermediates-dir-for,JAVA_LIBRARIES,framework)
+
+framework_docs_LOCAL_ADDITIONAL_DEPENDENCIES := \
+    frameworks/base/docs/knowntags.txt
 
 sample_dir := development/samples
 
@@ -423,25 +427,12 @@
 framework_docs_SDK_VERSION:=2.2
   # release version (ie "Release x")  (full releases only)
 framework_docs_SDK_REL_ID:=1
-  # name of current SDK directory (full releases only)
-framework_docs_SDK_CURRENT_DIR:=$(framework_docs_SDK_VERSION)_r$(framework_docs_SDK_REL_ID)
   # flag to build offline docs for a preview release
 framework_docs_SDK_PREVIEW:=0
 
-## Latest ADT version identifiers, for reference from published docs
-framework_docs_ADT_VERSION:=0.9.8
-framework_docs_ADT_DOWNLOAD:=ADT-0.9.8.zip
-framework_docs_ADT_BYTES:=8703591
-framework_docs_ADT_CHECKSUM:=22070f8e52924605a3b3abf87c1ba39f
-
 framework_docs_LOCAL_DROIDDOC_OPTIONS += \
 		-hdf sdk.version $(framework_docs_SDK_VERSION) \
-		-hdf sdk.rel.id $(framework_docs_SDK_REL_ID) \
-		-hdf sdk.current $(framework_docs_SDK_CURRENT_DIR) \
-		-hdf adt.zip.version $(framework_docs_ADT_VERSION) \
-		-hdf adt.zip.download $(framework_docs_ADT_DOWNLOAD) \
-		-hdf adt.zip.bytes $(framework_docs_ADT_BYTES) \
-		-hdf adt.zip.checksum $(framework_docs_ADT_CHECKSUM) 
+		-hdf sdk.rel.id $(framework_docs_SDK_REL_ID)
 
 # ====  the api stubs and current.xml ===========================
 include $(CLEAR_VARS)
@@ -453,6 +444,7 @@
 LOCAL_DROIDDOC_SOURCE_PATH:=$(framework_docs_LOCAL_DROIDDOC_SOURCE_PATH)
 LOCAL_DROIDDOC_HTML_DIR:=$(framework_docs_LOCAL_DROIDDOC_HTML_DIR)
 LOCAL_ADDITIONAL_JAVA_DIR:=$(framework_docs_LOCAL_ADDITIONAL_JAVA_DIR)
+LOCAL_ADDITIONAL_DEPENDENCIES:=$(framework_docs_LOCAL_ADDITIONAL_DEPENDENCIES)
 
 LOCAL_MODULE := api-stubs
 
@@ -481,6 +473,7 @@
 LOCAL_DROIDDOC_SOURCE_PATH:=$(framework_docs_LOCAL_DROIDDOC_SOURCE_PATH)
 LOCAL_DROIDDOC_HTML_DIR:=$(framework_docs_LOCAL_DROIDDOC_HTML_DIR)
 LOCAL_ADDITIONAL_JAVA_DIR:=$(framework_docs_LOCAL_ADDITIONAL_JAVA_DIR)
+LOCAL_ADDITIONAL_DEPENDENCIES:=$(framework_docs_LOCAL_ADDITIONAL_DEPENDENCIES)
 
 LOCAL_MODULE := doc-comment-check
 
@@ -508,6 +501,7 @@
 LOCAL_DROIDDOC_SOURCE_PATH:=$(framework_docs_LOCAL_DROIDDOC_SOURCE_PATH)
 LOCAL_DROIDDOC_HTML_DIR:=$(framework_docs_LOCAL_DROIDDOC_HTML_DIR)
 LOCAL_ADDITIONAL_JAVA_DIR:=$(framework_docs_LOCAL_ADDITIONAL_JAVA_DIR)
+LOCAL_ADDITIONAL_DEPENDENCIES:=$(framework_docs_LOCAL_ADDITIONAL_DEPENDENCIES)
 
 LOCAL_MODULE := offline-sdk
 
@@ -522,7 +516,7 @@
 		-hdf android.whichdoc offline 
 
 ifeq ($(framework_docs_SDK_PREVIEW),true)
-  LOCAL_DROIDDOC_OPTIONS += -hdf sdk.current preview 
+  LOCAL_DROIDDOC_OPTIONS += -hdf sdk.preview true
 endif
 
 LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
@@ -551,6 +545,7 @@
 LOCAL_DROIDDOC_SOURCE_PATH:=$(framework_docs_LOCAL_DROIDDOC_SOURCE_PATH)
 LOCAL_DROIDDOC_HTML_DIR:=$(framework_docs_LOCAL_DROIDDOC_HTML_DIR)
 LOCAL_ADDITIONAL_JAVA_DIR:=$(framework_docs_LOCAL_ADDITIONAL_JAVA_DIR)
+LOCAL_ADDITIONAL_DEPENDENCIES:=$(framework_docs_LOCAL_ADDITIONAL_DEPENDENCIES)
 
 LOCAL_MODULE := online-sdk
 
@@ -579,6 +574,7 @@
 LOCAL_DROIDDOC_SOURCE_PATH:=$(framework_docs_LOCAL_DROIDDOC_SOURCE_PATH)
 LOCAL_DROIDDOC_HTML_DIR:=$(framework_docs_LOCAL_DROIDDOC_HTML_DIR)
 LOCAL_ADDITIONAL_JAVA_DIR:=$(call intermediates-dir-for,JAVA_LIBRARIES,framework)
+LOCAL_ADDITIONAL_DEPENDENCIES:=$(framework_docs_LOCAL_ADDITIONAL_DEPENDENCIES)
 
 LOCAL_MODULE := hidden
 LOCAL_DROIDDOC_OPTIONS:=\
@@ -608,7 +604,7 @@
 
 LOCAL_NO_STANDARD_LIBRARIES := true
 LOCAL_JAVA_LIBRARIES := core
-
+LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE := ext
 
 LOCAL_NO_EMMA_INSTRUMENT := true
diff --git a/api/current.xml b/api/current.xml
index d2e1f05..1d6feb5 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -5828,28 +5828,6 @@
  visibility="public"
 >
 </field>
-<field name="kraken_resource_pad58"
- type="int"
- transient="false"
- volatile="false"
- value="16843463"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="kraken_resource_pad59"
- type="int"
- transient="false"
- volatile="false"
- value="16843462"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="kraken_resource_pad6"
  type="int"
  transient="false"
@@ -5861,17 +5839,6 @@
  visibility="public"
 >
 </field>
-<field name="kraken_resource_pad60"
- type="int"
- transient="false"
- volatile="false"
- value="16843461"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="kraken_resource_pad7"
  type="int"
  transient="false"
@@ -9513,6 +9480,39 @@
  visibility="public"
 >
 </field>
+<field name="textSelectHandle"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843463"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="textSelectHandleLeft"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843461"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="textSelectHandleRight"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843462"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="textSize"
  type="int"
  transient="false"
@@ -33609,7 +33609,7 @@
  value="2743"
  static="true"
  final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </field>
@@ -75759,7 +75759,7 @@
  visibility="public"
 >
 </field>
-<field name="mFacing"
+<field name="facing"
  type="int"
  transient="false"
  volatile="false"
@@ -75769,7 +75769,7 @@
  visibility="public"
 >
 </field>
-<field name="mOrientation"
+<field name="orientation"
  type="int"
  transient="false"
  volatile="false"
@@ -76944,11 +76944,11 @@
  visibility="public"
 >
 </field>
-<field name="FOCUS_MODE_CONTINUOUS"
+<field name="FOCUS_MODE_CONTINUOUS_VIDEO"
  type="java.lang.String"
  transient="false"
  volatile="false"
- value="&quot;continuous&quot;"
+ value="&quot;continuous-video&quot;"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -82537,8 +82537,8 @@
 <exception name="IOException" type="java.io.IOException">
 </exception>
 </method>
-<method name="isImplemented"
- return="java.lang.Boolean"
+<method name="isPresent"
+ return="boolean"
  abstract="false"
  native="false"
  synchronized="false"
@@ -82549,75 +82549,6 @@
 >
 </method>
 </class>
-<class name="GeocoderParams"
- 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="getClientPackage"
- return="java.lang.String"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="getLocale"
- return="java.util.Locale"
- 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="GpsSatellite"
  extends="java.lang.Object"
  abstract="false"
@@ -84209,390 +84140,6 @@
 </field>
 </class>
 </package>
-<package name="android.location.provider"
->
-<class name="GeocodeProvider"
- extends="java.lang.Object"
- abstract="true"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<constructor name="GeocodeProvider"
- type="android.location.provider.GeocodeProvider"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</constructor>
-<method name="getBinder"
- return="android.os.IBinder"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="onGetFromLocation"
- return="java.lang.String"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="latitude" type="double">
-</parameter>
-<parameter name="longitude" type="double">
-</parameter>
-<parameter name="maxResults" type="int">
-</parameter>
-<parameter name="params" type="android.location.GeocoderParams">
-</parameter>
-<parameter name="addrs" type="java.util.List&lt;android.location.Address&gt;">
-</parameter>
-</method>
-<method name="onGetFromLocationName"
- return="java.lang.String"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="locationName" type="java.lang.String">
-</parameter>
-<parameter name="lowerLeftLatitude" type="double">
-</parameter>
-<parameter name="lowerLeftLongitude" type="double">
-</parameter>
-<parameter name="upperRightLatitude" type="double">
-</parameter>
-<parameter name="upperRightLongitude" type="double">
-</parameter>
-<parameter name="maxResults" type="int">
-</parameter>
-<parameter name="params" type="android.location.GeocoderParams">
-</parameter>
-<parameter name="addrs" type="java.util.List&lt;android.location.Address&gt;">
-</parameter>
-</method>
-</class>
-<class name="LocationProvider"
- extends="java.lang.Object"
- abstract="true"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<constructor name="LocationProvider"
- type="android.location.provider.LocationProvider"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</constructor>
-<method name="getBinder"
- return="android.os.IBinder"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="onAddListener"
- return="void"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="uid" type="int">
-</parameter>
-</method>
-<method name="onDisable"
- return="void"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="onEnable"
- return="void"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="onEnableLocationTracking"
- return="void"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="enable" type="boolean">
-</parameter>
-</method>
-<method name="onGetAccuracy"
- return="int"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="onGetInternalState"
- return="java.lang.String"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="onGetPowerRequirement"
- return="int"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="onGetStatus"
- return="int"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="extras" type="android.os.Bundle">
-</parameter>
-</method>
-<method name="onGetStatusUpdateTime"
- return="long"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="onHasMonetaryCost"
- return="boolean"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="onMeetsCriteria"
- return="boolean"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="criteria" type="android.location.Criteria">
-</parameter>
-</method>
-<method name="onRemoveListener"
- return="void"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="uid" type="int">
-</parameter>
-</method>
-<method name="onRequiresCell"
- return="boolean"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="onRequiresNetwork"
- return="boolean"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="onRequiresSatellite"
- return="boolean"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="onSendExtraCommand"
- return="boolean"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="command" type="java.lang.String">
-</parameter>
-<parameter name="extras" type="android.os.Bundle">
-</parameter>
-</method>
-<method name="onSetMinTime"
- return="void"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="minTime" type="long">
-</parameter>
-</method>
-<method name="onSupportsAltitude"
- return="boolean"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="onSupportsBearing"
- return="boolean"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="onSupportsSpeed"
- return="boolean"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="onUpdateLocation"
- return="void"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="location" type="android.location.Location">
-</parameter>
-</method>
-<method name="onUpdateNetworkState"
- return="void"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="state" type="int">
-</parameter>
-<parameter name="info" type="android.net.NetworkInfo">
-</parameter>
-</method>
-<method name="reportLocation"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="location" type="android.location.Location">
-</parameter>
-</method>
-</class>
-</package>
 <package name="android.media"
 >
 <class name="AsyncPlayer"
@@ -85182,6 +84729,39 @@
 <parameter name="value" type="short">
 </parameter>
 </method>
+<field name="ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.media.action.CLOSE_AUDIO_EFFECT_CONTROL_SESSION&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.media.action.DISPLAY_AUDIO_EFFECT_CONTROL_PANEL&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.media.action.OPEN_AUDIO_EFFECT_CONTROL_SESSION&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="ALREADY_EXISTS"
  type="int"
  transient="false"
@@ -85193,6 +84773,50 @@
  visibility="public"
 >
 </field>
+<field name="CONTENT_TYPE_GAME"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CONTENT_TYPE_MOVIE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CONTENT_TYPE_MUSIC"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CONTENT_TYPE_VOICE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="EFFECT_AUXILIARY"
  type="java.lang.String"
  transient="false"
@@ -85341,6 +84965,39 @@
  visibility="public"
 >
 </field>
+<field name="EXTRA_AUDIO_SESSION"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.media.extra.AUDIO_SESSION&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_CONTENT_TYPE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.media.extra.CONTENT_TYPE&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_PACKAGE_NAME"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.media.extra.PACKAGE_NAME&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="NATIVE_EVENT_CONTROL_STATUS"
  type="int"
  transient="false"
@@ -96350,6 +96007,17 @@
  visibility="public"
 >
 </field>
+<field name="ERROR_FILE_ALREADY_EXISTS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1009"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="ERROR_FILE_ERROR"
  type="int"
  transient="false"
@@ -101636,6 +101304,19 @@
 <parameter name="refCounted" type="boolean">
 </parameter>
 </method>
+<method name="setWorkSource"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="ws" type="android.os.WorkSource">
+</parameter>
+</method>
 </class>
 </package>
 <package name="android.opengl"
@@ -128447,6 +128128,19 @@
 <parameter name="value" type="boolean">
 </parameter>
 </method>
+<method name="setWorkSource"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="ws" type="android.os.WorkSource">
+</parameter>
+</method>
 </class>
 <class name="Process"
  extends="java.lang.Object"
@@ -129595,6 +129289,134 @@
 </parameter>
 </method>
 </class>
+<class name="WorkSource"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<constructor name="WorkSource"
+ type="android.os.WorkSource"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<constructor name="WorkSource"
+ type="android.os.WorkSource"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="orig" type="android.os.WorkSource">
+</parameter>
+</constructor>
+<method name="add"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="other" type="android.os.WorkSource">
+</parameter>
+</method>
+<method name="clear"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="diff"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="other" type="android.os.WorkSource">
+</parameter>
+</method>
+<method name="remove"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="other" type="android.os.WorkSource">
+</parameter>
+</method>
+<method name="set"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="other" type="android.os.WorkSource">
+</parameter>
+</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>
+</class>
 </package>
 <package name="android.os.storage"
 >
@@ -136759,7 +136581,7 @@
  visibility="public"
 >
 </field>
-<field name="TYPE_MAINDEN_NAME"
+<field name="TYPE_MAIDEN_NAME"
  type="int"
  transient="false"
  volatile="false"
@@ -136770,6 +136592,17 @@
  visibility="public"
 >
 </field>
+<field name="TYPE_MAINDEN_NAME"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="deprecated"
+ visibility="public"
+>
+</field>
 <field name="TYPE_OTHER_NAME"
  type="int"
  transient="false"
@@ -137525,8 +137358,40 @@
  deprecated="not deprecated"
  visibility="public"
 >
+<implements name="android.provider.ContactsContract.CommonDataKinds.CommonColumns">
+</implements>
 <implements name="android.provider.ContactsContract.DataColumnsWithJoins">
 </implements>
+<method name="getTypeLabel"
+ return="java.lang.CharSequence"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="res" type="android.content.res.Resources">
+</parameter>
+<parameter name="type" type="int">
+</parameter>
+<parameter name="label" type="java.lang.CharSequence">
+</parameter>
+</method>
+<method name="getTypeLabelResource"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="type" type="int">
+</parameter>
+</method>
 <field name="CONTENT_ITEM_TYPE"
  type="java.lang.String"
  transient="false"
@@ -137549,6 +137414,39 @@
  visibility="public"
 >
 </field>
+<field name="TYPE_HOME"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_OTHER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_WORK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 </class>
 <class name="ContactsContract.CommonDataKinds.StructuredName"
  extends="java.lang.Object"
@@ -151863,6 +151761,17 @@
  visibility="public"
 >
 </method>
+<method name="getPsc"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="setLacAndCid"
  return="void"
  abstract="false"
@@ -177504,17 +177413,6 @@
  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"
@@ -177570,39 +177468,6 @@
  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_LEFT"
- type="int"
- transient="false"
- volatile="false"
- value="16777232"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="SOURCE_JOYSTICK_RIGHT"
- type="int"
- transient="false"
- volatile="false"
- value="33554448"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="SOURCE_KEYBOARD"
  type="int"
  transient="false"
@@ -223734,8 +223599,19 @@
  visibility="public"
 >
 </method>
+<method name="isShowing"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="onTouchEvent"
- return="void"
+ return="boolean"
  abstract="true"
  native="false"
  synchronized="false"
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index c424281..b718299 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -36,24 +36,30 @@
 static const int32_t kIFramesIntervalSec = 1;
 static const int32_t kVideoBitRate = 512 * 1024;
 static const int32_t kAudioBitRate = 12200;
-static const int32_t kColorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
 static const int64_t kDurationUs = 10000000LL;  // 10 seconds
 
 #if 1
 class DummySource : public MediaSource {
 
 public:
-    DummySource(int width, int height)
+    DummySource(int width, int height, int colorFormat)
         : mWidth(width),
           mHeight(height),
+          mColorFormat(colorFormat),
           mSize((width * height * 3) / 2) {
         mGroup.add_buffer(new MediaBuffer(mSize));
+
+        // Check the color format to make sure
+        // that the buffer size mSize it set correctly above.
+        CHECK(colorFormat == OMX_COLOR_FormatYUV420SemiPlanar ||
+              colorFormat == OMX_COLOR_FormatYUV420Planar);
     }
 
     virtual sp<MetaData> getFormat() {
         sp<MetaData> meta = new MetaData;
         meta->setInt32(kKeyWidth, mWidth);
         meta->setInt32(kKeyHeight, mHeight);
+        meta->setInt32(kKeyColorFormat, mColorFormat);
         meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
 
         return meta;
@@ -100,6 +106,7 @@
 private:
     MediaBufferGroup mGroup;
     int mWidth, mHeight;
+    int mColorFormat;
     size_t mSize;
     int64_t mNumFramesOutput;;
 
@@ -139,20 +146,47 @@
     return source;
 }
 
+enum {
+    kYUV420SP = 0,
+    kYUV420P  = 1,
+};
+
+// returns -1 if mapping of the given color is unsuccessful
+// returns an omx color enum value otherwise
+static int translateColorToOmxEnumValue(int color) {
+    switch (color) {
+        case kYUV420SP:
+            return OMX_COLOR_FormatYUV420SemiPlanar;
+        case kYUV420P:
+            return OMX_COLOR_FormatYUV420Planar;
+        default:
+            fprintf(stderr, "Unsupported color: %d\n", color);
+            return -1;
+    }
+}
+
 int main(int argc, char **argv) {
     android::ProcessState::self()->startThreadPool();
 
     DataSource::RegisterDefaultSniffers();
 
 #if 1
-    if (argc != 2) {
-        fprintf(stderr, "usage: %s filename\n", argv[0]);
+    if (argc != 3) {
+        fprintf(stderr, "usage: %s <filename> <input_color_format>\n", argv[0]);
+        fprintf(stderr, "       <input_color_format>:  0 (YUV420SP) or 1 (YUV420P)\n");
         return 1;
     }
 
+    int colorFormat = translateColorToOmxEnumValue(atoi(argv[2]));
+    if (colorFormat == -1) {
+        fprintf(stderr, "input color format must be 0 (YUV420SP) or 1 (YUV420P)\n");
+        return 1;
+    }
     OMXClient client;
     CHECK_EQ(client.connect(), OK);
 
+    status_t err = OK;
+
 #if 0
     sp<MediaSource> source = createSource(argv[1]);
 
@@ -173,7 +207,7 @@
 #else
     int width = 720;
     int height = 480;
-    sp<MediaSource> decoder = new DummySource(width, height);
+    sp<MediaSource> decoder = new DummySource(width, height, colorFormat);
 #endif
 
     sp<MetaData> enc_meta = new MetaData;
@@ -187,7 +221,7 @@
     enc_meta->setInt32(kKeyStride, width);
     enc_meta->setInt32(kKeySliceHeight, height);
     enc_meta->setInt32(kKeyIFramesInterval, kIFramesIntervalSec);
-    enc_meta->setInt32(kKeyColorFormat, kColorFormat);
+    enc_meta->setInt32(kKeyColorFormat, colorFormat);
 
     sp<MediaSource> encoder =
         OMXCodec::Create(
@@ -197,14 +231,14 @@
     sp<MPEG4Writer> writer = new MPEG4Writer("/sdcard/output.mp4");
     writer->addSource(encoder);
     writer->setMaxFileDuration(kDurationUs);
-    writer->start();
+    CHECK_EQ(OK, writer->start());
     while (!writer->reachedEOS()) {
         fprintf(stderr, ".");
         usleep(100000);
     }
-    writer->stop();
+    err = writer->stop();
 #else
-    encoder->start();
+    CHECK_EQ(OK, encoder->start());
 
     MediaBuffer *buffer;
     while (encoder->read(&buffer) == OK) {
@@ -222,7 +256,7 @@
         buffer = NULL;
     }
 
-    encoder->stop();
+    err = encoder->stop();
 #endif
 
     printf("$\n");
@@ -247,12 +281,16 @@
         buffer = NULL;
     }
 
-    source->stop();
+    err = source->stop();
 
     delete source;
     source = NULL;
 #endif
 
+    if (err != OK && err != ERROR_END_OF_STREAM) {
+        fprintf(stderr, "record failed: %d\n", err);
+        return 1;
+    }
     return 0;
 }
 #else
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 4a1d27b..8ab94ad 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -60,7 +60,7 @@
     return (int64_t)tv.tv_usec + tv.tv_sec * 1000000ll;
 }
 
-static void playSource(OMXClient *client, const sp<MediaSource> &source) {
+static void playSource(OMXClient *client, sp<MediaSource> &source) {
     sp<MetaData> meta = source->getFormat();
 
     const char *mime;
@@ -81,6 +81,8 @@
         }
     }
 
+    source.clear();
+
     status_t err = rawSource->start();
 
     if (err != OK) {
diff --git a/cmds/svc/src/com/android/commands/svc/PowerCommand.java b/cmds/svc/src/com/android/commands/svc/PowerCommand.java
index d3ec3d9..e1d6619 100644
--- a/cmds/svc/src/com/android/commands/svc/PowerCommand.java
+++ b/cmds/svc/src/com/android/commands/svc/PowerCommand.java
@@ -64,7 +64,7 @@
                             = IPowerManager.Stub.asInterface(ServiceManager.getService(Context.POWER_SERVICE));
                     try {
                         IBinder lock = new Binder();
-                        pm.acquireWakeLock(PowerManager.FULL_WAKE_LOCK, lock, "svc power");
+                        pm.acquireWakeLock(PowerManager.FULL_WAKE_LOCK, lock, "svc power", null);
                         pm.setStayOnSetting(val);
                         pm.releaseWakeLock(lock, 0);
                     }
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 6e6e86f..72bf825 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1427,7 +1427,9 @@
      * <li> The function will be called between {@link #onStop} and
      * {@link #onDestroy}.
      * <li> A new instance of the activity will <em>always</em> be immediately
-     * created after this one's {@link #onDestroy()} is called.
+     * created after this one's {@link #onDestroy()} is called.  In particular,
+     * <em>no</em> messages will be dispatched during this time (when the returned
+     * object does not have an activity to be associated with).
      * <li> The object you return here will <em>always</em> be available from
      * the {@link #getLastNonConfigurationInstance()} method of the following
      * activity instance as described there.
@@ -1440,6 +1442,15 @@
      * may change based on the configuration, including any data loaded from
      * resources such as strings, layouts, or drawables.
      * 
+     * <p>The guarantee of no message handling during the switch to the next
+     * activity simplifies use with active objects.  For example if your retained
+     * state is an {@link android.os.AsyncTask} you are guaranteed that its
+     * call back functions (like {@link android.os.AsyncTask#onPostExecute}) will
+     * not be called from the call here until you execute the next instance's
+     * {@link #onCreate(Bundle)}.  (Note however that there is of course no such
+     * guarantee for {@link android.os.AsyncTask#doInBackground} since that is
+     * running in a separate thread.)
+     *
      * @return Return any Object holding the desired state to propagate to the
      * next activity instance.
      */
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index f8407c2..d8b5253 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3107,18 +3107,11 @@
         /**
          * For system applications on userdebug/eng builds, log stack
          * traces of disk and network access to dropbox for analysis.
-         *
-         * Similar logic exists in SystemServer.java.
          */
         if ((data.appInfo.flags &
              (ApplicationInfo.FLAG_SYSTEM |
-              ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) != 0 &&
-            !"user".equals(Build.TYPE)) {
-            StrictMode.setThreadPolicy(
-                StrictMode.DISALLOW_DISK_WRITE |
-                StrictMode.DISALLOW_DISK_READ |
-                StrictMode.DISALLOW_NETWORK |
-                StrictMode.PENALTY_DROPBOX);
+              ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) != 0) {
+            StrictMode.conditionallyEnableDebugLogging();
         }
 
         /**
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 7625c04..cd22fa1 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -588,7 +588,9 @@
      */
     private void updateVoiceButton(boolean empty) {
         int visibility = View.GONE;
-        if (mSearchable.getVoiceSearchEnabled() && empty) {
+        if ((mAppSearchData == null || !mAppSearchData.getBoolean(
+                SearchManager.DISABLE_VOICE_SEARCH, false))
+                && mSearchable.getVoiceSearchEnabled() && empty) {
             Intent testIntent = null;
             if (mSearchable.getVoiceSearchLaunchWebSearch()) {
                 testIntent = mVoiceWebSearchIntent;
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index a1ca707..2e9cd96 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -395,6 +395,14 @@
     public final static String CONTEXT_IS_VOICE = "android.search.CONTEXT_IS_VOICE";
 
     /**
+     * This means that the voice icon should not be shown at all, because the
+     * current search engine does not support voice search.
+     * @hide
+     */
+    public final static String DISABLE_VOICE_SEARCH
+            = "android.search.DISABLE_VOICE_SEARCH";
+
+    /**
      * Reference to the shared system search service.
      */
     private static ISearchManager mService;
diff --git a/core/java/android/app/backup/package.html b/core/java/android/app/backup/package.html
index ae29994..e140349 100644
--- a/core/java/android/app/backup/package.html
+++ b/core/java/android/app/backup/package.html
@@ -3,6 +3,9 @@
 <p>Contains the backup and restore functionality available to
 applications. If a user wipes the data on their device or upgrades to a new Android-powered
 device, all applications that have enabled backup will restore the user's previous data.</p>
+
+<p>For a detailed guide to using the backup APIs, see the <a
+href="{@docRoot}guide/topics/data/backup.html">Data Backup</a> developer guide.</p>
 {@more}
 
 <p>All backup and restore operations are controlled by the {@link
@@ -22,8 +25,5 @@
   <li>Restore the data saved to remote storage</li>
 </ul>
 
-<p>For a detailed guide to using the backup APIs, see the <a
-href="{@docRoot}guide/topics/data/backup.html">Data Backup</a> developer guide.</p>
-
 </BODY>
 </HTML>
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 16a8c57..33fd395 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -465,11 +465,11 @@
     }
 
     /**
-     * Set the friendly Bluetooth name of the local Bluetoth adapter.
+     * Set the friendly Bluetooth name of the local Bluetooth adapter.
      * <p>This name is visible to remote Bluetooth devices.
-     * <p>Valid Bluetooth names are a maximum of 248 UTF-8 characters, however
-     * many remote devices can only display the first 40 characters, and some
-     * may be limited to just 20.
+     * <p>Valid Bluetooth names are a maximum of 248 bytes using UTF-8
+     * encoding, although many remote devices can only display the first
+     * 40 characters, and some may be limited to just 20.
      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
      * will return false. After turning on Bluetooth,
      * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
@@ -488,7 +488,7 @@
     }
 
     /**
-     * Get the current Bluetooth scan mode of the local Bluetooth adaper.
+     * Get the current Bluetooth scan mode of the local Bluetooth adapter.
      * <p>The Bluetooth scan mode determines if the local adapter is
      * connectable and/or discoverable from remote Bluetooth devices.
      * <p>Possible values are:
@@ -611,7 +611,7 @@
     /**
      * Cancel the current device discovery process.
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
-     * <p>Because discovery is a heavyweight precedure for the Bluetooth
+     * <p>Because discovery is a heavyweight procedure for the Bluetooth
      * adapter, this method should always be called before attempting to connect
      * to a remote device with {@link
      * android.bluetooth.BluetoothSocket#connect()}. Discovery is not managed by
diff --git a/core/java/android/content/AbstractThreadedSyncAdapter.java b/core/java/android/content/AbstractThreadedSyncAdapter.java
index 9dd7b9f..c0a268f 100644
--- a/core/java/android/content/AbstractThreadedSyncAdapter.java
+++ b/core/java/android/content/AbstractThreadedSyncAdapter.java
@@ -37,8 +37,9 @@
 public abstract class AbstractThreadedSyncAdapter {
     /**
      * Kernel event log tag.  Also listed in data/etc/event-log-tags.
-     * @Deprecated
+     * @deprecated Private constant.  May go away in the next release.
      */
+    @Deprecated
     public static final int LOG_SYNC_DETAILS = 2743;
 
     private final Context mContext;
diff --git a/core/java/android/content/ContentProviderOperation.java b/core/java/android/content/ContentProviderOperation.java
index 7945f3f..12e9bab 100644
--- a/core/java/android/content/ContentProviderOperation.java
+++ b/core/java/android/content/ContentProviderOperation.java
@@ -272,13 +272,14 @@
      * The ContentValues back references are represented as a ContentValues object where the
      * key refers to a column and the value is an index of the back reference whose
      * valued should be associated with the column.
+     * <p>
+     * This is intended to be a private method but it is exposed for
+     * unit testing purposes
      * @param backRefs an array of previous results
      * @param numBackRefs the number of valid previous results in backRefs
      * @return the ContentValues that should be used in this operation application after
      * expansion of back references. This can be called if either mValues or mValuesBackReferences
      * is null
-     * @VisibleForTesting this is intended to be a private method but it is exposed for
-     * unit testing purposes
      */
     public ContentValues resolveValueBackReferences(
             ContentProviderResult[] backRefs, int numBackRefs) {
@@ -308,13 +309,14 @@
      * the key is an index into the selection argument array (see {@link Builder#withSelection})
      * and the value is the index of the previous result that should be used for that selection
      * argument array slot.
+     * <p>
+     * This is intended to be a private method but it is exposed for
+     * unit testing purposes
      * @param backRefs an array of previous results
      * @param numBackRefs the number of valid previous results in backRefs
      * @return the ContentValues that should be used in this operation application after
      * expansion of back references. This can be called if either mValues or mValuesBackReferences
      * is null
-     * @VisibleForTesting this is intended to be a private method but it is exposed for
-     * unit testing purposes
      */
     public String[] resolveSelectionArgsBackReferences(
             ContentProviderResult[] backRefs, int numBackRefs) {
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index d0b67cc..26b6ad7 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -45,6 +45,7 @@
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.os.WorkSource;
 import android.provider.Settings;
 import android.text.format.DateUtils;
 import android.text.format.Time;
@@ -126,8 +127,8 @@
 
     private static final int INITIALIZATION_UNBIND_DELAY_MS = 5000;
 
-    private static final String SYNC_WAKE_LOCK = "SyncManagerSyncWakeLock";
-    private static final String HANDLE_SYNC_ALARM_WAKE_LOCK = "SyncManagerHandleSyncAlarmWakeLock";
+    private static final String SYNC_WAKE_LOCK = "*sync*";
+    private static final String HANDLE_SYNC_ALARM_WAKE_LOCK = "SyncManagerHandleSyncAlarm";
 
     private Context mContext;
 
@@ -1700,10 +1701,12 @@
                 mActiveSyncContext.close();
                 mActiveSyncContext = null;
                 mSyncStorageEngine.setActiveSync(mActiveSyncContext);
+                mSyncWakeLock.setWorkSource(null);
                 runStateIdle();
                 return;
             }
 
+            mSyncWakeLock.setWorkSource(new WorkSource(syncAdapterInfo.uid));
             mSyncWakeLock.acquire();
             // no need to schedule an alarm, as that will be done by our caller.
 
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index ef72013..4bd9bd9 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -192,7 +192,7 @@
 
     /**
      * Signature check result: this is returned by {@link #checkSignatures}
-     * if the two packages have a matching signature.
+     * if all signatures on the two packages match.
      */
     public static final int SIGNATURE_MATCH = 0;
 
@@ -204,25 +204,25 @@
 
     /**
      * Signature check result: this is returned by {@link #checkSignatures}
-     * if the first package is not signed, but the second is.
+     * if the first package is not signed but the second is.
      */
     public static final int SIGNATURE_FIRST_NOT_SIGNED = -1;
 
     /**
      * Signature check result: this is returned by {@link #checkSignatures}
-     * if the second package is not signed, but the first is.
+     * if the second package is not signed but the first is.
      */
     public static final int SIGNATURE_SECOND_NOT_SIGNED = -2;
 
     /**
      * Signature check result: this is returned by {@link #checkSignatures}
-     * if both packages are signed but there is no matching signature.
+     * if not all signatures on both packages match.
      */
     public static final int SIGNATURE_NO_MATCH = -3;
 
     /**
      * Signature check result: this is returned by {@link #checkSignatures}
-     * if either of the given package names are not valid.
+     * if either of the packages are not valid.
      */
     public static final int SIGNATURE_UNKNOWN_PACKAGE = -4;
 
@@ -1230,20 +1230,14 @@
      *
      * @param pkg1 First package name whose signature will be compared.
      * @param pkg2 Second package name whose signature will be compared.
-     * @return Returns an integer indicating whether there is a matching
-     * signature: the value is >= 0 if there is a match (or neither package
-     * is signed), or < 0 if there is not a match.  The match result can be
-     * further distinguished with the success (>= 0) constants
-     * {@link #SIGNATURE_MATCH}, {@link #SIGNATURE_NEITHER_SIGNED}; or
-     * failure (< 0) constants {@link #SIGNATURE_FIRST_NOT_SIGNED},
-     * {@link #SIGNATURE_SECOND_NOT_SIGNED}, {@link #SIGNATURE_NO_MATCH},
-     * or {@link #SIGNATURE_UNKNOWN_PACKAGE}.
+     *
+     * @return Returns an integer indicating whether all signatures on the
+     * two packages match. The value is >= 0 ({@link #SIGNATURE_MATCH}) if
+     * all signatures match or < 0 if there is not a match ({@link
+     * #SIGNATURE_NO_MATCH} or {@link #SIGNATURE_UNKNOWN_PACKAGE}).
      *
      * @see #checkSignatures(int, int)
      * @see #SIGNATURE_MATCH
-     * @see #SIGNATURE_NEITHER_SIGNED
-     * @see #SIGNATURE_FIRST_NOT_SIGNED
-     * @see #SIGNATURE_SECOND_NOT_SIGNED
      * @see #SIGNATURE_NO_MATCH
      * @see #SIGNATURE_UNKNOWN_PACKAGE
      */
@@ -1258,20 +1252,14 @@
      *
      * @param uid1 First UID whose signature will be compared.
      * @param uid2 Second UID whose signature will be compared.
-     * @return Returns an integer indicating whether there is a matching
-     * signature: the value is >= 0 if there is a match (or neither package
-     * is signed), or < 0 if there is not a match.  The match result can be
-     * further distinguished with the success (>= 0) constants
-     * {@link #SIGNATURE_MATCH}, {@link #SIGNATURE_NEITHER_SIGNED}; or
-     * failure (< 0) constants {@link #SIGNATURE_FIRST_NOT_SIGNED},
-     * {@link #SIGNATURE_SECOND_NOT_SIGNED}, {@link #SIGNATURE_NO_MATCH},
-     * or {@link #SIGNATURE_UNKNOWN_PACKAGE}.
      *
-     * @see #checkSignatures(int, int)
+     * @return Returns an integer indicating whether all signatures on the
+     * two packages match. The value is >= 0 ({@link #SIGNATURE_MATCH}) if
+     * all signatures match or < 0 if there is not a match ({@link
+     * #SIGNATURE_NO_MATCH} or {@link #SIGNATURE_UNKNOWN_PACKAGE}).
+     *
+     * @see #checkSignatures(String, String)
      * @see #SIGNATURE_MATCH
-     * @see #SIGNATURE_NEITHER_SIGNED
-     * @see #SIGNATURE_FIRST_NOT_SIGNED
-     * @see #SIGNATURE_SECOND_NOT_SIGNED
      * @see #SIGNATURE_NO_MATCH
      * @see #SIGNATURE_UNKNOWN_PACKAGE
      */
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 3cc89e5..0d8228c 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -154,14 +154,21 @@
      * Information about a camera
      */
     public static class CameraInfo {
+        /**
+         * The facing of the camera is opposite to that of the screen.
+         */
         public static final int CAMERA_FACING_BACK = 0;
+
+        /**
+         * The facing of the camera is the same as that of the screen.
+         */
         public static final int CAMERA_FACING_FRONT = 1;
 
         /**
          * The direction that the camera faces to. It should be
          * CAMERA_FACING_BACK or CAMERA_FACING_FRONT.
          */
-        public int mFacing;
+        public int facing;
 
         /**
          * The orientation of the camera image. The value is the angle that the
@@ -175,7 +182,7 @@
          *
          * @see #setDisplayOrientation(int)
          */
-        public int mOrientation;
+        public int orientation;
     };
 
     /**
@@ -210,12 +217,14 @@
 
     /**
      * The id for the default camera.
+     * @see #open(int)
      */
     public static int CAMERA_ID_DEFAULT = 0;
 
     /**
      * Equivalent to Camera.open(Camera.CAMERA_ID_DEFAULT).
      * Creates a new Camera object to access the default camera.
+     * @see #open(int)
      */
     public static Camera open() {
         return new Camera(CAMERA_ID_DEFAULT);
@@ -787,7 +796,7 @@
      *         case Surface.ROTATION_270: degrees = 270; break;
      *     }
      *
-     *     int result = (info.mOrientation - degrees + 360) % 360;
+     *     int result = (info.orientation - degrees + 360) % 360;
      *     camera.setDisplayOrientation(result);
      * }
      * </pre>
@@ -1173,14 +1182,17 @@
         public static final String FOCUS_MODE_EDOF = "edof";
 
         /**
-         * Continuous auto focus mode. The camera continuously tries to focus.
-         * This is ideal for shooting video or shooting photo of moving object.
-         * Auto focus starts when the parameter is set. Applications should not
-         * call {@link #autoFocus(AutoFocusCallback)} in this mode. To stop
-         * continuous focus, applications should change the focus mode to other
-         * modes.
+         * Continuous auto focus mode intended for video recording. The camera
+         * continuously tries to focus. This is ideal for shooting video.
+         * Applications still can call {@link
+         * #takePicture(Camera.ShutterCallback, Camera.PictureCallback,
+         * Camera.PictureCallback)} in this mode but the subject may not be in
+         * focus. Auto focus starts when the parameter is set. Applications
+         * should not call {@link #autoFocus(AutoFocusCallback)} in this mode.
+         * To stop continuous focus, applications should change the focus mode
+         * to other modes.
          */
-        public static final String FOCUS_MODE_CONTINUOUS = "continuous";
+        public static final String FOCUS_MODE_CONTINUOUS_VIDEO = "continuous-video";
 
         // Indices for focus distance array.
         /**
@@ -2014,7 +2026,7 @@
          * @see #FOCUS_MODE_MACRO
          * @see #FOCUS_MODE_FIXED
          * @see #FOCUS_MODE_EDOF
-         * @see #FOCUS_MODE_CONTINUOUS
+         * @see #FOCUS_MODE_CONTINUOUS_VIDEO
          */
         public String getFocusMode() {
             return get(KEY_FOCUS_MODE);
@@ -2216,8 +2228,8 @@
          * #autoFocus(AutoFocusCallback)}, {@link #cancelAutoFocus}, or {@link
          * #startPreview()}. Applications can call {@link #getParameters()}
          * and this method anytime to get the latest focus distances. If the
-         * focus mode is FOCUS_MODE_CONTINUOUS, focus distances may change from
-         * time to time.
+         * focus mode is FOCUS_MODE_CONTINUOUS_VIDEO, focus distances may change
+         * from time to time.
          *
          * This method is intended to estimate the distance between the camera
          * and the subject. After autofocus, the subject distance may be within
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index 0068724..a271075 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -24,6 +24,7 @@
 import android.os.ServiceManager;
 import android.util.Log;
 import android.util.SparseArray;
+import android.util.SparseBooleanArray;
 import android.view.IRotationWatcher;
 import android.view.IWindowManager;
 import android.view.Surface;
@@ -446,12 +447,12 @@
                     int accuracy = status[0];
                     synchronized (sListeners) {
                         if (sensor == -1 || sListeners.isEmpty()) {
-                            if (sensor == -1) {
-                                // we lost the connection to the event stream. this happens
-                                // when the last listener is removed.
-                                Log.d(TAG, "_sensors_data_poll() failed, we bail out.");
+                            // we lost the connection to the event stream. this happens
+                            // when the last listener is removed or if there is an error
+                            if (sensor == -1 && !sListeners.isEmpty()) {
+                                // log a warning in case of abnormal termination
+                                Log.e(TAG, "_sensors_data_poll() failed, we bail out: sensors=" + sensor);
                             }
-
                             // we have no more listeners or polling failed, terminate the thread
                             sensors_destroy_queue(sQueue);
                             sQueue = 0;
@@ -487,7 +488,7 @@
         private final ArrayList<Sensor> mSensorList = new ArrayList<Sensor>();
         private final Handler mHandler;
         private SensorEvent mValuesPool;
-        public int mSensors;
+        public SparseBooleanArray mSensors = new SparseBooleanArray();
 
         ListenerDelegate(SensorEventListener listener, Sensor sensor, Handler handler) {
             mSensorEventListener = listener;
@@ -541,18 +542,17 @@
             return mSensorEventListener;
         }
 
-        int addSensor(Sensor sensor) {
-            mSensors |= 1<<sensor.getHandle();
+        void addSensor(Sensor sensor) {
+            mSensors.put(sensor.getHandle(), true);
             mSensorList.add(sensor);
-            return mSensors;
         }
         int removeSensor(Sensor sensor) {
-            mSensors &= ~(1<<sensor.getHandle());
+            mSensors.delete(sensor.getHandle());
             mSensorList.remove(sensor);
-            return mSensors;
+            return mSensors.size();
         }
         boolean hasSensor(Sensor sensor) {
-            return ((mSensors & (1<<sensor.getHandle())) != 0);
+            return mSensors.get(sensor.getHandle());
         }
         List<Sensor> getSensors() {
             return mSensorList;
@@ -971,6 +971,31 @@
         return registerListener(listener, sensor, rate, null);
     }
 
+    private boolean enableSensorLocked(Sensor sensor, int delay) {
+        boolean result = false;
+        for (ListenerDelegate i : sListeners) {
+            if (i.hasSensor(sensor)) {
+                String name = sensor.getName();
+                int handle = sensor.getHandle();
+                result = sensors_enable_sensor(sQueue, name, handle, delay);
+                break;
+            }
+        }
+        return result;
+    }
+
+    private boolean disableSensorLocked(Sensor sensor) {
+        for (ListenerDelegate i : sListeners) {
+            if (i.hasSensor(sensor)) {
+                // not an error, it's just that this sensor is still in use
+                return true;
+            }
+        }
+        String name = sensor.getName();
+        int handle = sensor.getHandle();
+        return sensors_enable_sensor(sQueue, name, handle, SENSOR_DISABLE);
+    }
+
     /**
      * Registers a {@link android.hardware.SensorEventListener
      * SensorEventListener} for the given sensor.
@@ -1008,7 +1033,7 @@
         if (listener == null || sensor == null) {
             return false;
         }
-        boolean result;
+        boolean result = true;
         int delay = -1;
         switch (rate) {
             case SENSOR_DELAY_FASTEST:
@@ -1029,6 +1054,7 @@
         }
 
         synchronized (sListeners) {
+            // look for this listener in our list
             ListenerDelegate l = null;
             for (ListenerDelegate i : sListeners) {
                 if (i.getListener() == listener) {
@@ -1037,29 +1063,37 @@
                 }
             }
 
-            String name = sensor.getName();
-            int handle = sensor.getHandle();
+            // if we don't find it, add it to the list
             if (l == null) {
-                result = false;
                 l = new ListenerDelegate(listener, sensor, handler);
                 sListeners.add(l);
+                // if the list is not empty, start our main thread
                 if (!sListeners.isEmpty()) {
-                    result = sSensorThread.startLocked();
-                    if (result) {
-                        result = sensors_enable_sensor(sQueue, name, handle, delay);
-                        if (!result) {
-                            // there was an error, remove the listeners
+                    if (sSensorThread.startLocked()) {
+                        if (!enableSensorLocked(sensor, delay)) {
+                            // oops. there was an error
                             sListeners.remove(l);
+                            result = false;
                         }
+                    } else {
+                        // there was an error, remove the listener
+                        sListeners.remove(l);
+                        result = false;
                     }
+                } else {
+                    // weird, we couldn't add the listener
+                    result = false;
                 }
             } else {
-                result = sensors_enable_sensor(sQueue, name, handle, delay);
-                if (result) {
-                    l.addSensor(sensor);
+                l.addSensor(sensor);
+                if (!enableSensorLocked(sensor, delay)) {
+                    // oops. there was an error
+                    l.removeSensor(sensor);
+                    result = false;
                 }
             }
         }
+
         return result;
     }
 
@@ -1067,23 +1101,21 @@
         if (listener == null || sensor == null) {
             return;
         }
+
         synchronized (sListeners) {
             final int size = sListeners.size();
             for (int i=0 ; i<size ; i++) {
                 ListenerDelegate l = sListeners.get(i);
                 if (l.getListener() == listener) {
-                    // disable these sensors
-                    String name = sensor.getName();
-                    int handle = sensor.getHandle();
-                    sensors_enable_sensor(sQueue, name, handle, SENSOR_DISABLE);
-                    // if we have no more sensors enabled on this listener,
-                    // take it off the list.
                     if (l.removeSensor(sensor) == 0) {
+                        // if we have no more sensors enabled on this listener,
+                        // take it off the list.
                         sListeners.remove(i);
                     }
                     break;
                 }
             }
+            disableSensorLocked(sensor);
         }
     }
 
@@ -1091,18 +1123,17 @@
         if (listener == null) {
             return;
         }
+
         synchronized (sListeners) {
             final int size = sListeners.size();
             for (int i=0 ; i<size ; i++) {
                 ListenerDelegate l = sListeners.get(i);
                 if (l.getListener() == listener) {
+                    sListeners.remove(i);
                     // disable all sensors for this listener
                     for (Sensor sensor : l.getSensors()) {
-                        String name = sensor.getName();
-                        int handle = sensor.getHandle();
-                        sensors_enable_sensor(sQueue, name, handle, SENSOR_DISABLE);
+                        disableSensorLocked(sensor);
                     }
-                    sListeners.remove(i);
                     break;
                 }
             }
diff --git a/core/java/android/inputmethodservice/Keyboard.java b/core/java/android/inputmethodservice/Keyboard.java
old mode 100755
new mode 100644
index 4814b0a..269e1c9
--- a/core/java/android/inputmethodservice/Keyboard.java
+++ b/core/java/android/inputmethodservice/Keyboard.java
@@ -307,6 +307,10 @@
         /** Create an empty key with no attributes. */
         public Key(Row parent) {
             keyboard = parent.parent;
+            height = parent.defaultHeight;
+            width = parent.defaultWidth;
+            gap = parent.defaultHorizontalGap;
+            edgeFlags = parent.rowEdgeFlags;
         }
         
         /** Create a key with the given top-left coordinate and extract its attributes from
@@ -564,9 +568,6 @@
             final Key key = new Key(row);
             key.x = x;
             key.y = y;
-            key.width = mDefaultWidth;
-            key.height = mDefaultHeight;
-            key.gap = mDefaultHorizontalGap;
             key.label = String.valueOf(c);
             key.codes = new int[] { c };
             column++;
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 331ce10..39681912 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -123,6 +123,17 @@
     public static final String ACTION_BACKGROUND_DATA_SETTING_CHANGED =
             "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED";
 
+
+    /**
+     * Broadcast Action: The network connection may not be good
+     * uses {@code ConnectivityManager.EXTRA_INET_CONDITION} and
+     * {@code ConnectivityManager.EXTRA_NETWORK_INFO} to specify
+     * the network and it's condition.
+     * @hide
+     */
+    public static final String INET_CONDITION_ACTION =
+            "android.net.conn.INET_CONDITION_ACTION";
+
     /**
      * Broadcast Action: A tetherable connection has come or gone
      * TODO - finish the doc
diff --git a/core/java/android/net/DownloadManager.java b/core/java/android/net/DownloadManager.java
index e8237c9..8bb747e 100644
--- a/core/java/android/net/DownloadManager.java
+++ b/core/java/android/net/DownloadManager.java
@@ -17,6 +17,7 @@
 package android.net;
 
 import android.content.ContentResolver;
+import android.content.ContentUris;
 import android.content.ContentValues;
 import android.database.Cursor;
 import android.database.CursorWrapper;
@@ -24,7 +25,6 @@
 import android.provider.BaseColumns;
 import android.provider.Downloads;
 
-import java.io.File;
 import java.io.FileNotFoundException;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -194,6 +194,12 @@
     public final static int ERROR_CANNOT_RESUME = 1008;
 
     /**
+     * Value of {@link #COLUMN_ERROR_CODE} when the requested destination file already exists (the
+     * download manager will not overwrite an existing file).
+     */
+    public final static int ERROR_FILE_ALREADY_EXISTS = 1009;
+
+    /**
      * Broadcast intent action sent by the download manager when a download completes.
      */
     public final static String ACTION_DOWNLOAD_COMPLETE = "android.intent.action.DOWNLOAD_COMPLETE";
@@ -234,10 +240,11 @@
         Downloads.COLUMN_URI,
         Downloads.COLUMN_MIME_TYPE,
         Downloads.COLUMN_TOTAL_BYTES,
-        Downloads._DATA,
         Downloads.COLUMN_STATUS,
         Downloads.COLUMN_CURRENT_BYTES,
         Downloads.COLUMN_LAST_MODIFICATION,
+        Downloads.COLUMN_DESTINATION,
+        Downloads.Impl.COLUMN_FILE_NAME_HINT,
     };
 
     private static final Set<String> LONG_COLUMNS = new HashSet<String>(
@@ -536,12 +543,12 @@
          * @param projection the projection to pass to ContentResolver.query()
          * @return the Cursor returned by ContentResolver.query()
          */
-        Cursor runQuery(ContentResolver resolver, String[] projection) {
-            Uri uri = Downloads.CONTENT_URI;
+        Cursor runQuery(ContentResolver resolver, String[] projection, Uri baseUri) {
+            Uri uri = baseUri;
             List<String> selectionParts = new ArrayList<String>();
 
             if (mId != null) {
-                uri = Uri.withAppendedPath(uri, mId.toString());
+                uri = ContentUris.withAppendedId(uri, mId);
             }
 
             if (mStatusFlags != null) {
@@ -597,6 +604,7 @@
 
     private ContentResolver mResolver;
     private String mPackageName;
+    private Uri mBaseUri = Downloads.Impl.CONTENT_URI;
 
     /**
      * @hide
@@ -607,6 +615,19 @@
     }
 
     /**
+     * Makes this object access the download provider through /all_downloads URIs rather than
+     * /my_downloads URIs, for clients that have permission to do so.
+     * @hide
+     */
+    public void setAccessAllDownloads(boolean accessAllDownloads) {
+        if (accessAllDownloads) {
+            mBaseUri = Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI;
+        } else {
+            mBaseUri = Downloads.Impl.CONTENT_URI;
+        }
+    }
+
+    /**
      * Enqueue a new download.  The download will start automatically once the download manager is
      * ready to execute it and connectivity is available.
      *
@@ -642,11 +663,11 @@
      * COLUMN_* constants.
      */
     public Cursor query(Query query) {
-        Cursor underlyingCursor = query.runQuery(mResolver, UNDERLYING_COLUMNS);
+        Cursor underlyingCursor = query.runQuery(mResolver, UNDERLYING_COLUMNS, mBaseUri);
         if (underlyingCursor == null) {
             return null;
         }
-        return new CursorTranslator(underlyingCursor);
+        return new CursorTranslator(underlyingCursor, mBaseUri);
     }
 
     /**
@@ -690,9 +711,8 @@
     /**
      * Get the DownloadProvider URI for the download with the given ID.
      */
-    private Uri getDownloadUri(long id) {
-        Uri downloadUri = Uri.withAppendedPath(Downloads.CONTENT_URI, Long.toString(id));
-        return downloadUri;
+    Uri getDownloadUri(long id) {
+        return ContentUris.withAppendedId(mBaseUri, id);
     }
 
     /**
@@ -702,8 +722,11 @@
      * underlying data.
      */
     private static class CursorTranslator extends CursorWrapper {
-        public CursorTranslator(Cursor cursor) {
+        private Uri mBaseUri;
+
+        public CursorTranslator(Cursor cursor, Uri baseUri) {
             super(cursor);
+            mBaseUri = baseUri;
         }
 
         @Override
@@ -799,11 +822,19 @@
             }
 
             assert column.equals(COLUMN_LOCAL_URI);
-            String localUri = getUnderlyingString(Downloads._DATA);
-            if (localUri == null) {
-                return null;
+            return getLocalUri();
+        }
+
+        private String getLocalUri() {
+            long destinationType = getUnderlyingLong(Downloads.Impl.COLUMN_DESTINATION);
+            if (destinationType == Downloads.Impl.DESTINATION_FILE_URI) {
+                // return client-provided file URI for external download
+                return getUnderlyingString(Downloads.Impl.COLUMN_FILE_NAME_HINT);
             }
-            return Uri.fromFile(new File(localUri)).toString();
+
+            // return content URI for cache download
+            long downloadId = getUnderlyingLong(Downloads.Impl._ID);
+            return ContentUris.withAppendedId(mBaseUri, downloadId).toString();
         }
 
         private long translateLong(String column) {
@@ -864,6 +895,9 @@
                 case Downloads.Impl.STATUS_CANNOT_RESUME:
                     return ERROR_CANNOT_RESUME;
 
+                case Downloads.Impl.STATUS_FILE_ALREADY_EXISTS_ERROR:
+                    return ERROR_FILE_ALREADY_EXISTS;
+
                 default:
                     return ERROR_UNKNOWN;
             }
diff --git a/core/java/android/net/LocalSocket.java b/core/java/android/net/LocalSocket.java
index 4039a69..3ee8a80 100644
--- a/core/java/android/net/LocalSocket.java
+++ b/core/java/android/net/LocalSocket.java
@@ -70,8 +70,11 @@
         if (!implCreated) {
             synchronized (this) {
                 if (!implCreated) {
-                    implCreated = true;
-                    impl.create(true);
+                    try {
+                        impl.create(true);
+                    } finally {
+                        implCreated = true;
+                    }
                 }
             }
         }
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index 9166019..b822b27 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -49,7 +49,6 @@
 import org.apache.harmony.xnet.provider.jsse.OpenSSLContextImpl;
 import org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl;
 import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache;
-import org.apache.harmony.xnet.provider.jsse.SSLParameters;
 
 /**
  * SSLSocketFactory implementation with several extra features:
@@ -211,7 +210,8 @@
     private SSLSocketFactory makeSocketFactory(TrustManager[] trustManagers) {
         try {
             OpenSSLContextImpl sslContext = new OpenSSLContextImpl();
-            sslContext.engineInit(null, trustManagers, null, mSessionCache, null);
+            sslContext.engineInit(null, trustManagers, null);
+            sslContext.engineGetClientSessionContext().setPersistentCache(mSessionCache);
             return sslContext.engineGetSocketFactory();
         } catch (KeyManagementException e) {
             Log.wtf(TAG, e);
diff --git a/core/java/android/net/http/CertificateChainValidator.java b/core/java/android/net/http/CertificateChainValidator.java
index c527fe4..4ca5903 100644
--- a/core/java/android/net/http/CertificateChainValidator.java
+++ b/core/java/android/net/http/CertificateChainValidator.java
@@ -19,7 +19,7 @@
 
 import com.android.internal.net.DomainNameValidator;
 
-import org.apache.harmony.xnet.provider.jsse.SSLParameters;
+import org.apache.harmony.xnet.provider.jsse.SSLParametersImpl;
 
 import java.io.IOException;
 
@@ -191,7 +191,7 @@
         // report back to the user.
         //
         try {
-            SSLParameters.getDefaultTrustManager().checkServerTrusted(
+            SSLParametersImpl.getDefaultTrustManager().checkServerTrusted(
                 newServerCertificates, "RSA");
 
             // no errors!!!
diff --git a/core/java/android/net/http/HttpsConnection.java b/core/java/android/net/http/HttpsConnection.java
index 8c9d013f..b361dca 100644
--- a/core/java/android/net/http/HttpsConnection.java
+++ b/core/java/android/net/http/HttpsConnection.java
@@ -98,7 +98,8 @@
                 }
             };
 
-            sslContext.engineInit(null, trustManagers, null, cache, null);
+            sslContext.engineInit(null, trustManagers, null);
+            sslContext.engineGetClientSessionContext().setPersistentCache(cache);
 
             synchronized (HttpsConnection.class) {
                 mSslSocketFactory = sslContext.engineGetSocketFactory();
diff --git a/core/java/android/os/AsyncTask.java b/core/java/android/os/AsyncTask.java
index d28148c..5fb1d7c 100644
--- a/core/java/android/os/AsyncTask.java
+++ b/core/java/android/os/AsyncTask.java
@@ -129,7 +129,7 @@
 
     private static final int CORE_POOL_SIZE = 5;
     private static final int MAXIMUM_POOL_SIZE = 128;
-    private static final int KEEP_ALIVE = 10;
+    private static final int KEEP_ALIVE = 1;
 
     private static final BlockingQueue<Runnable> sWorkQueue =
             new LinkedBlockingQueue<Runnable>(10);
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index f5b1e57..ba8014f2 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -56,9 +56,9 @@
     public static final int SENSOR = 3;
     
     /**
-     * A constant indicating a a wifi turn on timer
+     * A constant indicating a a wifi running timer
      */
-    public static final int WIFI_TURNED_ON = 4;
+    public static final int WIFI_RUNNING = 4;
     
     /**
      * A constant indicating a full wifi lock timer
@@ -249,8 +249,8 @@
          */
         public abstract long getTcpBytesSent(int which);
         
-        public abstract void noteWifiTurnedOnLocked();
-        public abstract void noteWifiTurnedOffLocked();
+        public abstract void noteWifiRunningLocked();
+        public abstract void noteWifiStoppedLocked();
         public abstract void noteFullWifiLockAcquiredLocked();
         public abstract void noteFullWifiLockReleasedLocked();
         public abstract void noteScanWifiLockAcquiredLocked();
@@ -261,7 +261,7 @@
         public abstract void noteAudioTurnedOffLocked();
         public abstract void noteVideoTurnedOnLocked();
         public abstract void noteVideoTurnedOffLocked();
-        public abstract long getWifiTurnedOnTime(long batteryRealtime, int which);
+        public abstract long getWifiRunningTime(long batteryRealtime, int which);
         public abstract long getFullWifiLockTime(long batteryRealtime, int which);
         public abstract long getScanWifiLockTime(long batteryRealtime, int which);
         public abstract long getWifiMulticastTime(long batteryRealtime,
@@ -397,13 +397,14 @@
         }
     }
 
-    public final class HistoryItem implements Parcelable {
+    public final static class HistoryItem implements Parcelable {
         public HistoryItem next;
         
         public long time;
         
         public static final byte CMD_UPDATE = 0;
         public static final byte CMD_START = 1;
+        public static final byte CMD_OVERFLOW = 2;
         
         public byte cmd;
         
@@ -481,6 +482,18 @@
             dest.writeInt(states);
         }
         
+        public void setTo(HistoryItem o) {
+            time = o.time;
+            cmd = o.cmd;
+            batteryLevel = o.batteryLevel;
+            batteryStatus = o.batteryStatus;
+            batteryHealth = o.batteryHealth;
+            batteryPlugType = o.batteryPlugType;
+            batteryTemperature = o.batteryTemperature;
+            batteryVoltage = o.batteryVoltage;
+            states = o.states;
+        }
+
         public void setTo(long time, byte cmd, HistoryItem o) {
             this.time = time;
             this.cmd = cmd;
@@ -525,6 +538,10 @@
         }
     }
     
+    public abstract boolean startIteratingHistoryLocked();
+
+    public abstract boolean getNextHistoryLocked(HistoryItem out);
+
     /**
      * Return the current history of battery state changes.
      */
@@ -700,7 +717,7 @@
      *
      * {@hide}
      */
-    public abstract long getWifiRunningTime(long batteryRealtime, int which);
+    public abstract long getGlobalWifiRunningTime(long batteryRealtime, int which);
 
     /**
      * Returns the time in microseconds that bluetooth has been on while the device was
@@ -976,7 +993,7 @@
         final long screenOnTime = getScreenOnTime(batteryRealtime, which);
         final long phoneOnTime = getPhoneOnTime(batteryRealtime, which);
         final long wifiOnTime = getWifiOnTime(batteryRealtime, which);
-        final long wifiRunningTime = getWifiRunningTime(batteryRealtime, which);
+        final long wifiRunningTime = getGlobalWifiRunningTime(batteryRealtime, which);
         final long bluetoothOnTime = getBluetoothOnTime(batteryRealtime, which);
        
         StringBuilder sb = new StringBuilder(128);
@@ -1090,14 +1107,14 @@
             long tx = u.getTcpBytesSent(which);
             long fullWifiLockOnTime = u.getFullWifiLockTime(batteryRealtime, which);
             long scanWifiLockOnTime = u.getScanWifiLockTime(batteryRealtime, which);
-            long wifiTurnedOnTime = u.getWifiTurnedOnTime(batteryRealtime, which);
+            long uidWifiRunningTime = u.getWifiRunningTime(batteryRealtime, which);
             
             if (rx > 0 || tx > 0) dumpLine(pw, uid, category, NETWORK_DATA, rx, tx);
             
             if (fullWifiLockOnTime != 0 || scanWifiLockOnTime != 0
-                    || wifiTurnedOnTime != 0) {
+                    || uidWifiRunningTime != 0) {
                 dumpLine(pw, uid, category, WIFI_LOCK_DATA, 
-                        fullWifiLockOnTime, scanWifiLockOnTime, wifiTurnedOnTime);
+                        fullWifiLockOnTime, scanWifiLockOnTime, uidWifiRunningTime);
             }
 
             if (u.hasUserActivity()) {
@@ -1239,7 +1256,7 @@
         
         final long screenOnTime = getScreenOnTime(batteryRealtime, which);
         final long phoneOnTime = getPhoneOnTime(batteryRealtime, which);
-        final long wifiRunningTime = getWifiRunningTime(batteryRealtime, which);
+        final long wifiRunningTime = getGlobalWifiRunningTime(batteryRealtime, which);
         final long wifiOnTime = getWifiOnTime(batteryRealtime, which);
         final long bluetoothOnTime = getBluetoothOnTime(batteryRealtime, which);
         sb.setLength(0);
@@ -1448,7 +1465,7 @@
             long tcpSent = u.getTcpBytesSent(which);
             long fullWifiLockOnTime = u.getFullWifiLockTime(batteryRealtime, which);
             long scanWifiLockOnTime = u.getScanWifiLockTime(batteryRealtime, which);
-            long wifiTurnedOnTime = u.getWifiTurnedOnTime(batteryRealtime, which);
+            long uidWifiRunningTime = u.getWifiRunningTime(batteryRealtime, which);
             
             if (tcpReceived != 0 || tcpSent != 0) {
                 pw.print(prefix); pw.print("    Network: ");
@@ -1479,11 +1496,11 @@
             }
             
             if (fullWifiLockOnTime != 0 || scanWifiLockOnTime != 0
-                    || wifiTurnedOnTime != 0) {
+                    || uidWifiRunningTime != 0) {
                 sb.setLength(0);
-                sb.append(prefix); sb.append("    Turned Wifi On: "); 
-                        formatTimeMs(sb, wifiTurnedOnTime / 1000); 
-                        sb.append("("); sb.append(formatRatioLocked(wifiTurnedOnTime, 
+                sb.append(prefix); sb.append("    Wifi Running: ");
+                        formatTimeMs(sb, uidWifiRunningTime / 1000);
+                        sb.append("("); sb.append(formatRatioLocked(uidWifiRunningTime,
                                 whichBatteryRealtime)); sb.append(")\n");
                 sb.append(prefix); sb.append("    Full Wifi Lock: "); 
                         formatTimeMs(sb, fullWifiLockOnTime / 1000); 
@@ -1687,8 +1704,8 @@
      */
     @SuppressWarnings("unused")
     public void dumpLocked(PrintWriter pw) {
-        HistoryItem rec = getHistory();
-        if (rec != null) {
+        final HistoryItem rec = new HistoryItem();
+        if (startIteratingHistoryLocked()) {
             pw.println("Battery History:");
             long now = getHistoryBaseTime() + SystemClock.elapsedRealtime();
             int oldState = 0;
@@ -1697,12 +1714,14 @@
             int oldPlug = -1;
             int oldTemp = -1;
             int oldVolt = -1;
-            while (rec != null) {
+            while (getNextHistoryLocked(rec)) {
                 pw.print("  ");
                 TimeUtils.formatDuration(rec.time-now, pw, TimeUtils.HUNDRED_DAY_FIELD_LEN);
                 pw.print(" ");
                 if (rec.cmd == HistoryItem.CMD_START) {
                     pw.println(" START");
+                } else if (rec.cmd == HistoryItem.CMD_OVERFLOW) {
+                    pw.println(" *OVERFLOW*");
                 } else {
                     if (rec.batteryLevel < 10) pw.print("00");
                     else if (rec.batteryLevel < 100) pw.print("0");
@@ -1800,7 +1819,6 @@
                     pw.println();
                 }
                 oldState = rec.states;
-                rec = rec.next;
             }
             pw.println("");
         }
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 01cc408..0067e940 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -17,10 +17,13 @@
 
 package android.os;
 
+import android.os.WorkSource;
+
 /** @hide */
 interface IPowerManager
 {
-    void acquireWakeLock(int flags, IBinder lock, String tag);
+    void acquireWakeLock(int flags, IBinder lock, String tag, in WorkSource ws);
+    void updateWakeLockWorkSource(IBinder lock, in WorkSource ws);
     void goToSleep(long time);
     void goToSleepWithReason(long time, int reason);
     void releaseWakeLock(IBinder lock, int flags);
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index f4ca8bc..3876a3e 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -209,6 +209,7 @@
         int mCount = 0;
         boolean mRefCounted = true;
         boolean mHeld = false;
+        WorkSource mWorkSource;
 
         WakeLock(int flags, String tag)
         {
@@ -247,7 +248,7 @@
             synchronized (mToken) {
                 if (!mRefCounted || mCount++ == 0) {
                     try {
-                        mService.acquireWakeLock(mFlags, mToken, mTag);
+                        mService.acquireWakeLock(mFlags, mToken, mTag, mWorkSource);
                     } catch (RemoteException e) {
                     }
                     mHeld = true;
@@ -313,6 +314,32 @@
             }
         }
 
+        public void setWorkSource(WorkSource ws) {
+            synchronized (mToken) {
+                if (ws != null && ws.size() == 0) {
+                    ws = null;
+                }
+                boolean changed = true;
+                if (ws == null) {
+                    mWorkSource = null;
+                } else if (mWorkSource == null) {
+                    changed = mWorkSource != null;
+                    mWorkSource = new WorkSource(ws);
+                } else {
+                    changed = mWorkSource.diff(ws);
+                    if (changed) {
+                        mWorkSource.set(ws);
+                    }
+                }
+                if (changed && mHeld) {
+                    try {
+                        mService.updateWakeLockWorkSource(mToken, mWorkSource);
+                    } catch (RemoteException e) {
+                    }
+                }
+            }
+        }
+
         public String toString() {
             synchronized (mToken) {
                 return "WakeLock{"
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 5fea6fe..e56e257 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -307,8 +307,10 @@
      * Requires the {@link android.Manifest.permission#REBOOT} permission.
      *
      * @param context      the Context to use
-     * @param packageFile  the update package to install.  Currently
-     * must be on the /cache or /data partitions.
+     * @param packageFile  the update package to install.  Must be on
+     * a partition mountable by recovery.  (The set of partitions
+     * known to recovery may vary from device to device.  Generally,
+     * /cache and /data are safe.)
      *
      * @throws IOException  if writing the recovery command file
      * fails, or if the reboot itself fails.
@@ -316,15 +318,6 @@
     public static void installPackage(Context context, File packageFile)
         throws IOException {
         String filename = packageFile.getCanonicalPath();
-
-        if (filename.startsWith("/cache/")) {
-            filename = "CACHE:" + filename.substring(7);
-        } else if (filename.startsWith("/data/")) {
-            filename = "DATA:" + filename.substring(6);
-        } else {
-            throw new IllegalArgumentException(
-                "Must start with /cache or /data: " + filename);
-        }
         Log.w(TAG, "!!! REBOOTING TO INSTALL " + filename + " !!!");
         String arg = "--update_package=" + filename;
         bootCommand(context, arg);
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 7f7b02b..f571c42 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -201,6 +201,25 @@
     }
 
     /**
+     * Enable DropBox logging for debug phone builds.
+     *
+     * @hide
+     */
+    public static boolean conditionallyEnableDebugLogging() {
+        // For debug builds, log event loop stalls to dropbox for analysis.
+        // Similar logic also appears in ActivityThread.java for system apps.
+        if ("user".equals(Build.TYPE)) {
+            return false;
+        }
+        StrictMode.setThreadPolicy(
+            StrictMode.DISALLOW_DISK_WRITE |
+            StrictMode.DISALLOW_DISK_READ |
+            StrictMode.DISALLOW_NETWORK |
+            StrictMode.PENALTY_DROPBOX);
+        return true;
+    }
+
+    /**
      * Parses the BlockGuard policy mask out from the Exception's
      * getMessage() String value.  Kinda gross, but least
      * invasive.  :/
diff --git a/core/java/android/os/WorkSource.aidl b/core/java/android/os/WorkSource.aidl
new file mode 100644
index 0000000..1e7fabc
--- /dev/null
+++ b/core/java/android/os/WorkSource.aidl
@@ -0,0 +1,18 @@
+/* Copyright 2010, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.os;
+
+parcelable WorkSource;
diff --git a/core/java/android/os/WorkSource.java b/core/java/android/os/WorkSource.java
new file mode 100644
index 0000000..287c136
--- /dev/null
+++ b/core/java/android/os/WorkSource.java
@@ -0,0 +1,311 @@
+package android.os;
+
+/**
+ * Describes the source of some work that may be done by someone else.
+ * Currently the public representation of what a work source is is not
+ * defined; this is an opaque container.
+ */
+public class WorkSource implements Parcelable {
+    int mNum;
+    int[] mUids;
+
+    /**
+     * Internal statics to avoid object allocations in some operations.
+     * The WorkSource object itself is not thread safe, but we need to
+     * hold sTmpWorkSource lock while working with these statics.
+     */
+    static final WorkSource sTmpWorkSource = new WorkSource(0);
+    /**
+     * For returning newbie work from a modification operation.
+     */
+    static WorkSource sNewbWork;
+    /**
+     * For returning gone work form a modification operation.
+     */
+    static WorkSource sGoneWork;
+
+    /**
+     * Create an empty work source.
+     */
+    public WorkSource() {
+        mNum = 0;
+    }
+
+    /**
+     * Create a new WorkSource that is a copy of an existing one.
+     * If <var>orig</var> is null, an empty WorkSource is created.
+     */
+    public WorkSource(WorkSource orig) {
+        if (orig == null) {
+            mNum = 0;
+            return;
+        }
+        mNum = orig.mNum;
+        if (orig.mUids != null) {
+            mUids = orig.mUids.clone();
+        } else {
+            mUids = null;
+        }
+    }
+
+    /** @hide */
+    public WorkSource(int uid) {
+        mNum = 1;
+        mUids = new int[] { uid, 0 };
+    }
+
+    WorkSource(Parcel in) {
+        mNum = in.readInt();
+        mUids = in.createIntArray();
+    }
+
+    /** @hide */
+    public int size() {
+        return mNum;
+    }
+
+    /** @hide */
+    public int get(int index) {
+        return mUids[index];
+    }
+
+    /**
+     * Clear this WorkSource to be empty.
+     */
+    public void clear() {
+        mNum = 0;
+    }
+
+    /**
+     * Compare this WorkSource with another.
+     * @param other The WorkSource to compare against.
+     * @return If there is a difference, true is returned.
+     */
+    public boolean diff(WorkSource other) {
+        int N = mNum;
+        if (N != other.mNum) {
+            return true;
+        }
+        final int[] uids1 = mUids;
+        final int[] uids2 = other.mUids;
+        for (int i=0; i<N; i++) {
+            if (uids1[i] != uids2[i]) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Replace the current contents of this work source with the given
+     * work source.  If <var>other</var> is null, the current work source
+     * will be made empty.
+     */
+    public void set(WorkSource other) {
+        if (other == null) {
+            mNum = 0;
+            return;
+        }
+        mNum = other.mNum;
+        if (other.mUids != null) {
+            if (mUids != null && mUids.length >= mNum) {
+                System.arraycopy(other.mUids, 0, mUids, 0, mNum);
+            } else {
+                mUids = other.mUids.clone();
+            }
+        } else {
+            mUids = null;
+        }
+    }
+
+    /** @hide */
+    public void set(int uid) {
+        mNum = 1;
+        if (mUids == null) mUids = new int[2];
+        mUids[0] = uid;
+    }
+
+    /** @hide */
+    public WorkSource[] setReturningDiffs(WorkSource other) {
+        synchronized (sTmpWorkSource) {
+            sNewbWork = null;
+            sGoneWork = null;
+            updateLocked(other, true, true);
+            if (sNewbWork != null || sGoneWork != null) {
+                WorkSource[] diffs = new WorkSource[2];
+                diffs[0] = sNewbWork;
+                diffs[1] = sGoneWork;
+                return diffs;
+            }
+            return null;
+        }
+    }
+
+    /**
+     * Merge the contents of <var>other</var> WorkSource in to this one.
+     *
+     * @param other The other WorkSource whose contents are to be merged.
+     * @return Returns true if any new sources were added.
+     */
+    public boolean add(WorkSource other) {
+        synchronized (sTmpWorkSource) {
+            return updateLocked(other, false, false);
+        }
+    }
+
+    /** @hide */
+    public WorkSource addReturningNewbs(WorkSource other) {
+        synchronized (sTmpWorkSource) {
+            sNewbWork = null;
+            updateLocked(other, false, true);
+            return sNewbWork;
+        }
+    }
+
+    /** @hide */
+    public boolean add(int uid) {
+        synchronized (sTmpWorkSource) {
+            sTmpWorkSource.mUids[0] = uid;
+            return updateLocked(sTmpWorkSource, false, false);
+        }
+    }
+
+    /** @hide */
+    public WorkSource addReturningNewbs(int uid) {
+        synchronized (sTmpWorkSource) {
+            sNewbWork = null;
+            sTmpWorkSource.mUids[0] = uid;
+            updateLocked(sTmpWorkSource, false, true);
+            return sNewbWork;
+        }
+    }
+
+    public boolean remove(WorkSource other) {
+        int N1 = mNum;
+        final int[] uids1 = mUids;
+        final int N2 = other.mNum;
+        final int[] uids2 = other.mUids;
+        boolean changed = false;
+        int i1 = 0;
+        for (int i2=0; i2<N2 && i1<N1; i2++) {
+            if (uids2[i2] == uids1[i1]) {
+                N1--;
+                if (i1 < N1) System.arraycopy(uids1, i1+1, uids1, i1, N1-i1);
+            }
+            while (i1 < N1 && uids2[i2] > uids1[i1]) {
+                i1++;
+            }
+        }
+
+        mNum = N1;
+
+        return changed;
+    }
+
+    private boolean updateLocked(WorkSource other, boolean set, boolean returnNewbs) {
+        int N1 = mNum;
+        int[] uids1 = mUids;
+        final int N2 = other.mNum;
+        final int[] uids2 = other.mUids;
+        boolean changed = false;
+        int i1 = 0;
+        for (int i2=0; i2<N2; i2++) {
+            if (i1 >= N1 || uids2[i2] < uids1[i1]) {
+                // Need to insert a new uid.
+                changed = true;
+                if (uids1 == null) {
+                    uids1 = new int[4];
+                    uids1[0] = uids2[i2];
+                } else if (i1 >= uids1.length) {
+                    int[] newuids = new int[(uids1.length*3)/2];
+                    if (i1 > 0) System.arraycopy(uids1, 0, newuids, 0, i1);
+                    if (i1 < N1) System.arraycopy(uids1, i1, newuids, i1+1, N1-i1);
+                    uids1 = newuids;
+                    uids1[i1] = uids2[i2];
+                } else {
+                    if (i1 < N1) System.arraycopy(uids1, i1, uids1, i1+1, N1-i1);
+                    uids1[i1] = uids2[i2];
+                }
+                if (returnNewbs) {
+                    if (sNewbWork == null) {
+                        sNewbWork = new WorkSource(uids2[i2]);
+                    } else {
+                        sNewbWork.addLocked(uids2[i2]);
+                    }
+                }
+                N1++;
+                i1++;
+            } else {
+                if (!set) {
+                    // Skip uids that already exist or are not in 'other'.
+                    do {
+                        i1++;
+                    } while (i1 < N1 && uids2[i2] >= uids1[i1]);
+                } else {
+                    // Remove any uids that don't exist in 'other'.
+                    int start = i1;
+                    while (i1 < N1 && uids2[i2] > uids1[i1]) {
+                        if (sGoneWork == null) {
+                            sGoneWork = new WorkSource(uids1[i1]);
+                        } else {
+                            sGoneWork.addLocked(uids1[i1]);
+                        }
+                        i1++;
+                    }
+                    if (start < i1) {
+                        System.arraycopy(uids1, i1, uids1, start, i1-start);
+                        N1 -= i1-start;
+                        i1 = start;
+                    }
+                    // If there is a matching uid, skip it.
+                    if (i1 < N1 && uids2[i1] == uids1[i1]) {
+                        i1++;
+                    }
+                }
+            }
+        }
+
+        mNum = N1;
+        mUids = uids1;
+
+        return changed;
+    }
+
+    private void addLocked(int uid) {
+        if (mUids == null) {
+            mUids = new int[4];
+            mUids[0] = uid;
+            mNum = 1;
+            return;
+        }
+        if (mNum >= mUids.length) {
+            int[] newuids = new int[(mNum*3)/2];
+            System.arraycopy(mUids, 0, newuids, 0, mNum);
+            mUids = newuids;
+        }
+
+        mUids[mNum] = uid;
+        mNum++;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mNum);
+        dest.writeIntArray(mUids);
+    }
+
+    public static final Parcelable.Creator<WorkSource> CREATOR
+            = new Parcelable.Creator<WorkSource>() {
+        public WorkSource createFromParcel(Parcel in) {
+            return new WorkSource(in);
+        }
+        public WorkSource[] newArray(int size) {
+            return new WorkSource[size];
+        }
+    };
+}
diff --git a/core/java/android/provider/Calendar.java b/core/java/android/provider/Calendar.java
index 9a09805..6355a9c 100644
--- a/core/java/android/provider/Calendar.java
+++ b/core/java/android/provider/Calendar.java
@@ -943,6 +943,80 @@
     }
 
     /**
+     * CalendarCache stores some settings for calendar including the current
+     * time zone for the app. These settings are stored using a key/value
+     * scheme.
+     */
+    public interface CalendarCacheColumns {
+        /**
+         * The key for the setting. Keys are defined in CalendarChache in the
+         * Calendar provider.
+         * TODO Add keys to this file
+         */
+        public static final String KEY = "key";
+
+        /**
+         * The value of the given setting.
+         */
+        public static final String VALUE = "value";
+    }
+
+    public static class CalendarCache implements CalendarCacheColumns {
+        /**
+         * The URI to use for retrieving the properties from the Calendar db.
+         */
+        public static final Uri URI =
+                Uri.parse("content://" + AUTHORITY + "/properties");
+        public static final String[] POJECTION = { KEY, VALUE };
+
+        /**
+         * If updating a property, this must be provided as the selection. All
+         * other selections will fail. For queries this field can be omitted to
+         * retrieve all properties or used to query a single property. Valid
+         * keys include {@link #TIMEZONE_KEY_TYPE},
+         * {@link #TIMEZONE_KEY_INSTANCES}, and
+         * {@link #TIMEZONE_KEY_INSTANCES_PREVIOUS}, though the last one can
+         * only be read, not written.
+         */
+        public static final String WHERE = "key=?";
+
+        /**
+         * They key for updating the use of auto/home time zones in Calendar.
+         * Valid values are {@link #TIMEZONE_TYPE_AUTO} or
+         * {@link #TIMEZONE_TYPE_HOME}.
+         */
+        public static final String TIMEZONE_KEY_TYPE = "timezoneType";
+
+        /**
+         * The key for updating the time zone used by the provider when it
+         * generates the instances table. This should only be written if the
+         * type is set to {@link #TIMEZONE_TYPE_HOME}. A valid time zone id
+         * should be written to this field.
+         */
+        public static final String TIMEZONE_KEY_INSTANCES = "timezoneInstances";
+
+        /**
+         * The key for reading the last time zone set by the user. This should
+         * only be read by apps and it will be automatically updated whenever
+         * {@link #TIMEZONE_KEY_INSTANCES} is updated with
+         * {@link #TIMEZONE_TYPE_HOME} set.
+         */
+        public static final String TIMEZONE_KEY_INSTANCES_PREVIOUS = "timezoneInstancesPrevious";
+
+        /**
+         * The value to write to {@link #TIMEZONE_KEY_TYPE} if the provider
+         * should stay in sync with the device's time zone.
+         */
+        public static final String TIMEZONE_TYPE_AUTO = "auto";
+
+        /**
+         * The value to write to {@link #TIMEZONE_KEY_TYPE} if the provider
+         * should use a fixed time zone set by the user.
+         */
+        public static final String TIMEZONE_TYPE_HOME = "home";
+    }
+
+    /**
      * A few Calendar globals are needed in the CalendarProvider for expanding
      * the Instances table and these are all stored in the first (and only)
      * row of the CalendarMetaData table.
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 13cbda8..09cc3e0 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -3552,7 +3552,7 @@
          * <li>{@link #TYPE_CUSTOM}. Put the actual type in {@link #LABEL}.</li>
          * <li>{@link #TYPE_DEFAULT}</li>
          * <li>{@link #TYPE_OTHER_NAME}</li>
-         * <li>{@link #TYPE_MAINDEN_NAME}</li>
+         * <li>{@link #TYPE_MAIDEN_NAME}</li>
          * <li>{@link #TYPE_SHORT_NAME}</li>
          * <li>{@link #TYPE_INITIALS}</li>
          * </ul>
@@ -3578,6 +3578,9 @@
 
             public static final int TYPE_DEFAULT = 1;
             public static final int TYPE_OTHER_NAME = 2;
+            public static final int TYPE_MAIDEN_NAME = 3;
+            /** @deprecated Use TYPE_MAIDEN_NAME instead. */
+            @Deprecated
             public static final int TYPE_MAINDEN_NAME = 3;
             public static final int TYPE_SHORT_NAME = 4;
             public static final int TYPE_INITIALS = 5;
@@ -4882,17 +4885,30 @@
          * <td>{@link #DATA1}</td>
          * <td></td>
          * </tr>
+         * <tr>
+         * <td>int</td>
+         * <td>{@link #TYPE}</td>
+         * <td>{@link #DATA2}</td>
+         * <td>Allowed values are:
+         * <p>
+         * <ul>
+         * <li>{@link #TYPE_CUSTOM}. Put the actual type in {@link #LABEL}.</li>
+         * <li>{@link #TYPE_HOME}</li>
+         * <li>{@link #TYPE_WORK}</li>
+         * <li>{@link #TYPE_OTHER}</li>
+         * </ul>
+         * </p>
+         * </td>
+         * </tr>
+         * <tr>
+         * <td>String</td>
+         * <td>{@link #LABEL}</td>
+         * <td>{@link #DATA3}</td>
+         * <td></td>
+         * </tr>
          * </table>
          */
-        public static final class SipAddress implements DataColumnsWithJoins {
-            // TODO: Ultimately this class will probably implement
-            // CommonColumns too (in addition to DataColumnsWithJoins)
-            // since it may make sense to have multiple SIP addresses with
-            // different types+labels, just like with phone numbers.
-            //
-            // But that can be extended in the future without breaking any
-            // public API, so let's keep this class ultra-simple for now.
-
+        public static final class SipAddress implements DataColumnsWithJoins, CommonColumns {
             /**
              * This utility class cannot be instantiated
              */
@@ -4901,11 +4917,44 @@
             /** MIME type used when storing this in data table. */
             public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/sip_address";
 
+            public static final int TYPE_HOME = 1;
+            public static final int TYPE_WORK = 2;
+            public static final int TYPE_OTHER = 3;
+
             /**
              * The SIP address.
              * <P>Type: TEXT</P>
              */
             public static final String SIP_ADDRESS = DATA1;
+            // ...and TYPE and LABEL come from the CommonColumns interface.
+
+            /**
+             * Return the string resource that best describes the given
+             * {@link #TYPE}. Will always return a valid resource.
+             */
+            public static final int getTypeLabelResource(int type) {
+                switch (type) {
+                    case TYPE_HOME: return com.android.internal.R.string.sipAddressTypeHome;
+                    case TYPE_WORK: return com.android.internal.R.string.sipAddressTypeWork;
+                    case TYPE_OTHER: return com.android.internal.R.string.sipAddressTypeOther;
+                    default: return com.android.internal.R.string.sipAddressTypeCustom;
+                }
+            }
+
+            /**
+             * Return a {@link CharSequence} that best describes the given type,
+             * possibly substituting the given {@link #LABEL} value
+             * for {@link #TYPE_CUSTOM}.
+             */
+            public static final CharSequence getTypeLabel(Resources res, int type,
+                    CharSequence label) {
+                if (type == TYPE_CUSTOM && !TextUtils.isEmpty(label)) {
+                    return label;
+                } else {
+                    final int labelRes = getTypeLabelResource(type);
+                    return res.getText(labelRes);
+                }
+            }
         }
     }
 
diff --git a/core/java/android/provider/Downloads.java b/core/java/android/provider/Downloads.java
index 603e598..871a0441 100644
--- a/core/java/android/provider/Downloads.java
+++ b/core/java/android/provider/Downloads.java
@@ -60,7 +60,7 @@
      * @hide
      */
     public static final Uri CONTENT_URI =
-        Uri.parse("content://downloads/download");
+        Uri.parse("content://downloads/my_downloads");
 
     /**
      * Broadcast Action: this is sent by the download manager to the app
@@ -637,10 +637,17 @@
                 "android.permission.DOWNLOAD_WITHOUT_NOTIFICATION";
 
         /**
-         * The content:// URI for the data table in the provider
+         * The content:// URI to access downloads owned by the caller's UID.
          */
         public static final Uri CONTENT_URI =
-            Uri.parse("content://downloads/download");
+                Uri.parse("content://downloads/my_downloads");
+
+        /**
+         * The content URI for accessing all downloads across all UIDs (requires the
+         * ACCESS_ALL_DOWNLOADS permission).
+         */
+        public static final Uri ALL_DOWNLOADS_CONTENT_URI =
+                Uri.parse("content://downloads/all_downloads");
 
         /**
          * Broadcast Action: this is sent by the download manager to the app
@@ -1070,7 +1077,12 @@
         /**
          * The lowest-valued error status that is not an actual HTTP status code.
          */
-        public static final int MIN_ARTIFICIAL_ERROR_STATUS = 489;
+        public static final int MIN_ARTIFICIAL_ERROR_STATUS = 488;
+
+        /**
+         * The requested destination file already exists.
+         */
+        public static final int STATUS_FILE_ALREADY_EXISTS_ERROR = 488;
 
         /**
          * Some possibly transient error occurred, but we can't resume the download.
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index 9b28a9a..e05fe7b 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -52,22 +52,14 @@
     private final BluetoothAdapter mAdapter;
     private final Context mContext;
 
-    private static final int EVENT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 1;
-    private static final int EVENT_RESTART_BLUETOOTH = 2;
-    private static final int EVENT_PAIRING_CONSENT_DELAYED_ACCEPT = 3;
-    private static final int EVENT_AGENT_CANCEL = 4;
+    private static final int EVENT_RESTART_BLUETOOTH = 1;
+    private static final int EVENT_PAIRING_CONSENT_DELAYED_ACCEPT = 2;
+    private static final int EVENT_AGENT_CANCEL = 3;
 
     private static final int CREATE_DEVICE_ALREADY_EXISTS = 1;
     private static final int CREATE_DEVICE_SUCCESS = 0;
     private static final int CREATE_DEVICE_FAILED = -1;
 
-    // The time (in millisecs) to delay the pairing attempt after the first
-    // auto pairing attempt fails. We use an exponential delay with
-    // INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY as the initial value and
-    // MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY as the max value.
-    private static final long INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 3000;
-    private static final long MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 12000;
-
     private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
     private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
 
@@ -76,13 +68,6 @@
         public void handleMessage(Message msg) {
             String address = null;
             switch (msg.what) {
-            case EVENT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY:
-                address = (String)msg.obj;
-                if (address != null) {
-                    mBluetoothService.createBond(address);
-                    return;
-                }
-                break;
             case EVENT_RESTART_BLUETOOTH:
                 mBluetoothService.restart();
                 break;
@@ -95,8 +80,7 @@
             case EVENT_AGENT_CANCEL:
                 // Set the Bond State to BOND_NONE.
                 // We always have only 1 device in BONDING state.
-                String[] devices =
-                    mBluetoothService.getBondState().listInState(BluetoothDevice.BOND_BONDING);
+                String[] devices = mBluetoothService.listInState(BluetoothDevice.BOND_BONDING);
                 if (devices.length == 0) {
                     break;
                 } else if (devices.length > 1) {
@@ -104,7 +88,7 @@
                     break;
                 }
                 address = devices[0];
-                mBluetoothService.getBondState().setBondState(address,
+                mBluetoothService.setBondState(address,
                         BluetoothDevice.BOND_NONE,
                         BluetoothDevice.UNBOND_REASON_REMOTE_AUTH_CANCELED);
                 break;
@@ -115,7 +99,7 @@
     static { classInitNative(); }
     private static native void classInitNative();
 
-    /* pacakge */ BluetoothEventLoop(Context context, BluetoothAdapter adapter,
+    /* package */ BluetoothEventLoop(Context context, BluetoothAdapter adapter,
             BluetoothService bluetoothService) {
         mBluetoothService = bluetoothService;
         mContext = context;
@@ -209,55 +193,7 @@
 
     private void onCreatePairedDeviceResult(String address, int result) {
         address = address.toUpperCase();
-        if (result == BluetoothDevice.BOND_SUCCESS) {
-            mBluetoothService.getBondState().setBondState(address, BluetoothDevice.BOND_BONDED);
-            if (mBluetoothService.getBondState().isAutoPairingAttemptsInProgress(address)) {
-                mBluetoothService.getBondState().clearPinAttempts(address);
-            }
-        } else if (result == BluetoothDevice.UNBOND_REASON_AUTH_FAILED &&
-                mBluetoothService.getBondState().getAttempt(address) == 1) {
-            mBluetoothService.getBondState().addAutoPairingFailure(address);
-            pairingAttempt(address, result);
-        } else if (result == BluetoothDevice.UNBOND_REASON_REMOTE_DEVICE_DOWN &&
-                mBluetoothService.getBondState().isAutoPairingAttemptsInProgress(address)) {
-            pairingAttempt(address, result);
-        } else {
-            mBluetoothService.getBondState().setBondState(address,
-                                                          BluetoothDevice.BOND_NONE, result);
-            if (mBluetoothService.getBondState().isAutoPairingAttemptsInProgress(address)) {
-                mBluetoothService.getBondState().clearPinAttempts(address);
-            }
-        }
-    }
-
-    private void pairingAttempt(String address, int result) {
-        // This happens when our initial guess of "0000" as the pass key
-        // fails. Try to create the bond again and display the pin dialog
-        // to the user. Use back-off while posting the delayed
-        // message. The initial value is
-        // INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY and the max value is
-        // MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY. If the max value is
-        // reached, display an error to the user.
-        int attempt = mBluetoothService.getBondState().getAttempt(address);
-        if (attempt * INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY >
-                    MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY) {
-            mBluetoothService.getBondState().clearPinAttempts(address);
-            mBluetoothService.getBondState().setBondState(address,
-                    BluetoothDevice.BOND_NONE, result);
-            return;
-        }
-
-        Message message = mHandler.obtainMessage(EVENT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY);
-        message.obj = address;
-        boolean postResult =  mHandler.sendMessageDelayed(message,
-                                        attempt * INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY);
-        if (!postResult) {
-            mBluetoothService.getBondState().clearPinAttempts(address);
-            mBluetoothService.getBondState().setBondState(address,
-                    BluetoothDevice.BOND_NONE, result);
-            return;
-        }
-        mBluetoothService.getBondState().attempt(address);
+        mBluetoothService.onCreatePairedDeviceResult(address, result);
     }
 
     private void onDeviceCreated(String deviceObjectPath) {
@@ -275,8 +211,8 @@
     private void onDeviceRemoved(String deviceObjectPath) {
         String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath);
         if (address != null) {
-            mBluetoothService.getBondState().setBondState(address.toUpperCase(),
-                    BluetoothDevice.BOND_NONE, BluetoothDevice.UNBOND_REASON_REMOVED);
+            mBluetoothService.setBondState(address.toUpperCase(), BluetoothDevice.BOND_NONE,
+                BluetoothDevice.UNBOND_REASON_REMOVED);
             mBluetoothService.setRemoteDeviceProperty(address, "UUIDs", null);
         }
     }
@@ -407,13 +343,11 @@
                 // If locally initiated pairing, we will
                 // not go to BOND_BONDED state until we have received a
                 // successful return value in onCreatePairedDeviceResult
-                if (null == mBluetoothService.getBondState().getPendingOutgoingBonding()) {
-                    mBluetoothService.getBondState().setBondState(address,
-                            BluetoothDevice.BOND_BONDED);
+                if (null == mBluetoothService.getPendingOutgoingBonding()) {
+                    mBluetoothService.setBondState(address, BluetoothDevice.BOND_BONDED);
                 }
             } else {
-                mBluetoothService.getBondState().setBondState(address,
-                        BluetoothDevice.BOND_NONE);
+                mBluetoothService.setBondState(address, BluetoothDevice.BOND_NONE);
                 mBluetoothService.setRemoteDeviceProperty(address, "Trusted", "false");
             }
         } else if (name.equals("Trusted")) {
@@ -443,8 +377,8 @@
         // Also set it only when the state is not already Bonded, we can sometimes
         // get an authorization request from the remote end if it doesn't have the link key
         // while we still have it.
-        if (mBluetoothService.getBondState().getBondState(address) != BluetoothDevice.BOND_BONDED)
-            mBluetoothService.getBondState().setBondState(address, BluetoothDevice.BOND_BONDING);
+        if (mBluetoothService.getBondState(address) != BluetoothDevice.BOND_BONDED)
+            mBluetoothService.setBondState(address, BluetoothDevice.BOND_BONDING);
         return address;
     }
 
@@ -458,7 +392,7 @@
          * so we may get this request many times. Also if we respond immediately,
          * the other end is unable to handle it. Delay sending the message.
          */
-        if (mBluetoothService.getBondState().getBondState(address) == BluetoothDevice.BOND_BONDED) {
+        if (mBluetoothService.getBondState(address) == BluetoothDevice.BOND_BONDED) {
             Message message = mHandler.obtainMessage(EVENT_PAIRING_CONSENT_DELAYED_ACCEPT);
             message.obj = address;
             mHandler.sendMessageDelayed(message, 1500);
@@ -503,7 +437,7 @@
         if (address == null) return;
 
         String pendingOutgoingAddress =
-                mBluetoothService.getBondState().getPendingOutgoingBonding();
+                mBluetoothService.getPendingOutgoingBonding();
         if (address.equals(pendingOutgoingAddress)) {
             // we initiated the bonding
 
@@ -524,12 +458,7 @@
             case BluetoothClass.Device.AUDIO_VIDEO_PORTABLE_AUDIO:
             case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
             case BluetoothClass.Device.AUDIO_VIDEO_HIFI_AUDIO:
-                if (!mBluetoothService.getBondState().hasAutoPairingFailed(address) &&
-                    !mBluetoothService.getBondState().isAutoPairingBlacklisted(address)) {
-                    mBluetoothService.getBondState().attempt(address);
-                    mBluetoothService.setPin(address, BluetoothDevice.convertPinToBytes("0000"));
-                    return;
-                }
+                if (mBluetoothService.attemptAutoPair(address)) return;
            }
         }
         Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index d53ac80..dfe3a25 100644
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -104,6 +104,14 @@
     private static final int MESSAGE_FINISH_DISABLE = 2;
     private static final int MESSAGE_UUID_INTENT = 3;
     private static final int MESSAGE_DISCOVERABLE_TIMEOUT = 4;
+    private static final int MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 5;
+
+    // The time (in millisecs) to delay the pairing attempt after the first
+    // auto pairing attempt fails. We use an exponential delay with
+    // INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY as the initial value and
+    // MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY as the max value.
+    private static final long INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 3000;
+    private static final long MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 12000;
 
     // The timeout used to sent the UUIDs Intent
     // This timeout should be greater than the page timeout
@@ -502,6 +510,13 @@
                     setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE, -1);
                 }
                 break;
+            case MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY:
+                address = (String)msg.obj;
+                if (address != null) {
+                    createBond(address);
+                    return;
+                }
+                break;
             }
         }
     };
@@ -591,8 +606,68 @@
         Binder.restoreCallingIdentity(origCallerIdentityToken);
     }
 
-    /* package */ BondState getBondState() {
-        return mBondState;
+    /*package*/ synchronized boolean attemptAutoPair(String address) {
+        if (!mBondState.hasAutoPairingFailed(address) &&
+                !mBondState.isAutoPairingBlacklisted(address)) {
+            mBondState.attempt(address);
+            setPin(address, BluetoothDevice.convertPinToBytes("0000"));
+            return true;
+        }
+        return false;
+    }
+
+    /*package*/ synchronized void onCreatePairedDeviceResult(String address, int result) {
+        if (result == BluetoothDevice.BOND_SUCCESS) {
+            setBondState(address, BluetoothDevice.BOND_BONDED);
+            if (mBondState.isAutoPairingAttemptsInProgress(address)) {
+                mBondState.clearPinAttempts(address);
+            }
+        } else if (result == BluetoothDevice.UNBOND_REASON_AUTH_FAILED &&
+                mBondState.getAttempt(address) == 1) {
+            mBondState.addAutoPairingFailure(address);
+            pairingAttempt(address, result);
+        } else if (result == BluetoothDevice.UNBOND_REASON_REMOTE_DEVICE_DOWN &&
+              mBondState.isAutoPairingAttemptsInProgress(address)) {
+            pairingAttempt(address, result);
+        } else {
+            setBondState(address, BluetoothDevice.BOND_NONE, result);
+            if (mBondState.isAutoPairingAttemptsInProgress(address)) {
+                mBondState.clearPinAttempts(address);
+            }
+        }
+    }
+
+    /*package*/ synchronized String getPendingOutgoingBonding() {
+        return mBondState.getPendingOutgoingBonding();
+    }
+
+    private void pairingAttempt(String address, int result) {
+        // This happens when our initial guess of "0000" as the pass key
+        // fails. Try to create the bond again and display the pin dialog
+        // to the user. Use back-off while posting the delayed
+        // message. The initial value is
+        // INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY and the max value is
+        // MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY. If the max value is
+        // reached, display an error to the user.
+        int attempt = mBondState.getAttempt(address);
+        if (attempt * INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY >
+                    MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY) {
+            mBondState.clearPinAttempts(address);
+            setBondState(address, BluetoothDevice.BOND_NONE, result);
+            return;
+        }
+
+        Message message = mHandler.obtainMessage(MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY);
+        message.obj = address;
+        boolean postResult =  mHandler.sendMessageDelayed(message,
+                                        attempt * INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY);
+        if (!postResult) {
+            mBondState.clearPinAttempts(address);
+            setBondState(address,
+                    BluetoothDevice.BOND_NONE, result);
+            return;
+        }
+        mBondState.attempt(address);
     }
 
     /** local cache of bonding state.
@@ -1259,6 +1334,10 @@
         return mBondState.listInState(BluetoothDevice.BOND_BONDED);
     }
 
+    /*package*/ synchronized String[] listInState(int state) {
+      return mBondState.listInState(state);
+    }
+
     public synchronized int getBondState(String address) {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
@@ -1267,6 +1346,15 @@
         return mBondState.getBondState(address.toUpperCase());
     }
 
+    /*package*/ synchronized boolean setBondState(String address, int state) {
+        return setBondState(address, state, 0);
+    }
+
+    /*package*/ synchronized boolean setBondState(String address, int state, int reason) {
+        mBondState.setBondState(address.toUpperCase(), state);
+        return true;
+    }
+
     public synchronized boolean isBluetoothDock(String address) {
         SharedPreferences sp = mContext.getSharedPreferences(SHARED_PREFERENCES_NAME,
                 mContext.MODE_PRIVATE);
diff --git a/core/java/android/util/CalendarUtils.java b/core/java/android/util/CalendarUtils.java
new file mode 100644
index 0000000..3d340d9
--- /dev/null
+++ b/core/java/android/util/CalendarUtils.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.util;
+
+import android.content.AsyncQueryHandler;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.database.Cursor;
+import android.provider.Calendar.CalendarCache;
+import android.text.TextUtils;
+import android.text.format.DateUtils;
+import android.text.format.Time;
+
+import java.util.Formatter;
+import java.util.HashSet;
+import java.util.Locale;
+
+/**
+ * A class containing utility methods related to Calendar apps.
+ *
+ * @hide
+ */
+public class CalendarUtils {
+    private static final boolean DEBUG = false;
+    private static final String TAG = "CalendarUtils";
+
+    /**
+     * This class contains methods specific to reading and writing time zone
+     * values.
+     */
+    public static class TimeZoneUtils {
+        private static final String[] TIMEZONE_TYPE_ARGS = { CalendarCache.TIMEZONE_KEY_TYPE };
+        private static final String[] TIMEZONE_INSTANCES_ARGS =
+                { CalendarCache.TIMEZONE_KEY_INSTANCES };
+
+        private static StringBuilder mSB = new StringBuilder(50);
+        private static Formatter mF = new Formatter(mSB, Locale.getDefault());
+        private volatile static boolean mFirstTZRequest = true;
+        private volatile static boolean mTZQueryInProgress = false;
+
+        private volatile static boolean mUseHomeTZ = false;
+        private volatile static String mHomeTZ = Time.getCurrentTimezone();
+
+        private static HashSet<Runnable> mTZCallbacks = new HashSet<Runnable>();
+        private static int mToken = 1;
+        private static AsyncTZHandler mHandler;
+
+        // The name of the shared preferences file. This name must be maintained for historical
+        // reasons, as it's what PreferenceManager assigned the first time the file was created.
+        private final String mPrefsName;
+
+        /**
+         * This is the key used for writing whether or not a home time zone should
+         * be used in the Calendar app to the Calendar Preferences.
+         */
+        public static final String KEY_HOME_TZ_ENABLED = "preferences_home_tz_enabled";
+        /**
+         * This is the key used for writing the time zone that should be used if
+         * home time zones are enabled for the Calendar app.
+         */
+        public static final String KEY_HOME_TZ = "preferences_home_tz";
+
+        /**
+         * This is a helper class for handling the async queries and updates for the
+         * time zone settings in Calendar.
+         */
+        private class AsyncTZHandler extends AsyncQueryHandler {
+            public AsyncTZHandler(ContentResolver cr) {
+                super(cr);
+            }
+
+            @Override
+            protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
+                synchronized (mTZCallbacks) {
+                    boolean writePrefs = false;
+                    // Check the values in the db
+                    int keyColumn = cursor.getColumnIndexOrThrow(CalendarCache.KEY);
+                    int valueColumn = cursor.getColumnIndexOrThrow(CalendarCache.VALUE);
+                    while(cursor.moveToNext()) {
+                        String key = cursor.getString(keyColumn);
+                        String value = cursor.getString(valueColumn);
+                        if (TextUtils.equals(key, CalendarCache.TIMEZONE_KEY_TYPE)) {
+                            boolean useHomeTZ = !TextUtils.equals(
+                                    value, CalendarCache.TIMEZONE_TYPE_AUTO);
+                            if (useHomeTZ != mUseHomeTZ) {
+                                writePrefs = true;
+                                mUseHomeTZ = useHomeTZ;
+                            }
+                        } else if (TextUtils.equals(
+                                key, CalendarCache.TIMEZONE_KEY_INSTANCES_PREVIOUS)) {
+                            if (!TextUtils.isEmpty(value) && !TextUtils.equals(mHomeTZ, value)) {
+                                writePrefs = true;
+                                mHomeTZ = value;
+                            }
+                        }
+                    }
+                    cursor.close();
+                    if (writePrefs) {
+                        SharedPreferences prefs = getSharedPreferences((Context)cookie, mPrefsName);
+                        // Write the prefs
+                        setSharedPreference(prefs, KEY_HOME_TZ_ENABLED, mUseHomeTZ);
+                        setSharedPreference(prefs, KEY_HOME_TZ, mHomeTZ);
+                    }
+
+                    mTZQueryInProgress = false;
+                    for (Runnable callback : mTZCallbacks) {
+                        if (callback != null) {
+                            callback.run();
+                        }
+                    }
+                    mTZCallbacks.clear();
+                }
+            }
+        }
+
+        /**
+         * The name of the file where the shared prefs for Calendar are stored
+         * must be provided. All activities within an app should provide the
+         * same preferences name or behavior may become erratic.
+         *
+         * @param prefsName
+         */
+        public TimeZoneUtils(String prefsName) {
+            mPrefsName = prefsName;
+        }
+
+        /**
+         * Formats a date or a time range according to the local conventions.
+         *
+         * This formats a date/time range using Calendar's time zone and the
+         * local conventions for the region of the device.
+         *
+         * @param context the context is required only if the time is shown
+         * @param startMillis the start time in UTC milliseconds
+         * @param endMillis the end time in UTC milliseconds
+         * @param flags a bit mask of options See
+         * {@link DateUtils#formatDateRange(Context, Formatter, long, long, int, String) formatDateRange}
+         * @return a string containing the formatted date/time range.
+         */
+        public String formatDateRange(Context context, long startMillis,
+                long endMillis, int flags) {
+            String date;
+            synchronized (mSB) {
+                mSB.setLength(0);
+                date = DateUtils.formatDateRange(context, mF, startMillis, endMillis, flags,
+                        getTimeZone(context, null)).toString();
+            }
+            return date;
+        }
+
+        /**
+         * Writes a new home time zone to the db.
+         *
+         * Updates the home time zone in the db asynchronously and updates
+         * the local cache. Sending a time zone of
+         * {@link CalendarCache#TIMEZONE_TYPE_AUTO} will cause it to be set
+         * to the device's time zone. null or empty tz will be ignored.
+         *
+         * @param context The calling activity
+         * @param timeZone The time zone to set Calendar to, or
+         * {@link CalendarCache#TIMEZONE_TYPE_AUTO}
+         */
+        public void setTimeZone(Context context, String timeZone) {
+            if (TextUtils.isEmpty(timeZone)) {
+                if (DEBUG) {
+                    Log.d(TAG, "Empty time zone, nothing to be done.");
+                }
+                return;
+            }
+            boolean updatePrefs = false;
+            synchronized (mTZCallbacks) {
+                if (CalendarCache.TIMEZONE_TYPE_AUTO.equals(timeZone)) {
+                    if (mUseHomeTZ) {
+                        updatePrefs = true;
+                    }
+                    mUseHomeTZ = false;
+                } else {
+                    if (!mUseHomeTZ || !TextUtils.equals(mHomeTZ, timeZone)) {
+                        updatePrefs = true;
+                    }
+                    mUseHomeTZ = true;
+                    mHomeTZ = timeZone;
+                }
+            }
+            if (updatePrefs) {
+                // Write the prefs
+                SharedPreferences prefs = getSharedPreferences(context, mPrefsName);
+                setSharedPreference(prefs, KEY_HOME_TZ_ENABLED, mUseHomeTZ);
+                setSharedPreference(prefs, KEY_HOME_TZ, mHomeTZ);
+
+                // Update the db
+                ContentValues values = new ContentValues();
+                if (mHandler != null) {
+                    mHandler.cancelOperation(mToken);
+                }
+
+                mHandler = new AsyncTZHandler(context.getContentResolver());
+
+                // skip 0 so query can use it
+                if (++mToken == 0) {
+                    mToken = 1;
+                }
+
+                // Write the use home tz setting
+                values.put(CalendarCache.VALUE, mUseHomeTZ ? CalendarCache.TIMEZONE_TYPE_HOME
+                        : CalendarCache.TIMEZONE_TYPE_AUTO);
+                mHandler.startUpdate(mToken, null, CalendarCache.URI, values, CalendarCache.WHERE,
+                        TIMEZONE_TYPE_ARGS);
+
+                // If using a home tz write it to the db
+                if (mUseHomeTZ) {
+                    ContentValues values2 = new ContentValues();
+                    values2.put(CalendarCache.VALUE, mHomeTZ);
+                    mHandler.startUpdate(mToken, null, CalendarCache.URI, values2,
+                            CalendarCache.WHERE, TIMEZONE_INSTANCES_ARGS);
+                }
+            }
+        }
+
+        /**
+         * Gets the time zone that Calendar should be displayed in
+         *
+         * This is a helper method to get the appropriate time zone for Calendar. If this
+         * is the first time this method has been called it will initiate an asynchronous
+         * query to verify that the data in preferences is correct. The callback supplied
+         * will only be called if this query returns a value other than what is stored in
+         * preferences and should cause the calling activity to refresh anything that
+         * depends on calling this method.
+         *
+         * @param context The calling activity
+         * @param callback The runnable that should execute if a query returns new values
+         * @return The string value representing the time zone Calendar should display
+         */
+        public String getTimeZone(Context context, Runnable callback) {
+            synchronized (mTZCallbacks){
+                if (mFirstTZRequest) {
+                    mTZQueryInProgress = true;
+                    mFirstTZRequest = false;
+
+                    SharedPreferences prefs = getSharedPreferences(context, mPrefsName);
+                    mUseHomeTZ = prefs.getBoolean(KEY_HOME_TZ_ENABLED, false);
+                    mHomeTZ = prefs.getString(KEY_HOME_TZ, Time.getCurrentTimezone());
+
+                    // When the async query returns it should synchronize on
+                    // mTZCallbacks, update mUseHomeTZ, mHomeTZ, and the
+                    // preferences, set mTZQueryInProgress to false, and call all
+                    // the runnables in mTZCallbacks.
+                    if (mHandler == null) {
+                        mHandler = new AsyncTZHandler(context.getContentResolver());
+                    }
+                    mHandler.startQuery(0, context, CalendarCache.URI, CalendarCache.POJECTION,
+                            null, null, null);
+                }
+                if (mTZQueryInProgress) {
+                    mTZCallbacks.add(callback);
+                }
+            }
+            return mUseHomeTZ ? mHomeTZ : Time.getCurrentTimezone();
+        }
+
+        /**
+         * Forces a query of the database to check for changes to the time zone.
+         * This should be called if another app may have modified the db. If a
+         * query is already in progress the callback will be added to the list
+         * of callbacks to be called when it returns.
+         *
+         * @param context The calling activity
+         * @param callback The runnable that should execute if a query returns
+         *            new values
+         */
+        public void forceDBRequery(Context context, Runnable callback) {
+            synchronized (mTZCallbacks){
+                if (mTZQueryInProgress) {
+                    mTZCallbacks.add(callback);
+                    return;
+                }
+                mFirstTZRequest = true;
+                getTimeZone(context, callback);
+            }
+        }
+    }
+
+        /**
+         * A helper method for writing a String value to the preferences
+         * asynchronously.
+         *
+         * @param context A context with access to the correct preferences
+         * @param key The preference to write to
+         * @param value The value to write
+         */
+        public static void setSharedPreference(SharedPreferences prefs, String key, String value) {
+//            SharedPreferences prefs = getSharedPreferences(context);
+            SharedPreferences.Editor editor = prefs.edit();
+            editor.putString(key, value);
+            editor.apply();
+        }
+
+        /**
+         * A helper method for writing a boolean value to the preferences
+         * asynchronously.
+         *
+         * @param context A context with access to the correct preferences
+         * @param key The preference to write to
+         * @param value The value to write
+         */
+        public static void setSharedPreference(SharedPreferences prefs, String key, boolean value) {
+//            SharedPreferences prefs = getSharedPreferences(context, prefsName);
+            SharedPreferences.Editor editor = prefs.edit();
+            editor.putBoolean(key, value);
+            editor.apply();
+        }
+
+        /** Return a properly configured SharedPreferences instance */
+        public static SharedPreferences getSharedPreferences(Context context, String prefsName) {
+            return context.getSharedPreferences(prefsName, Context.MODE_PRIVATE);
+        }
+}
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index 7468579..dd04975 100755
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -28,8 +28,7 @@
  * keyboard may compose the capabilities of a standard keyboard together with a track pad mouse
  * or other pointing device.
  * </p><p>
- * Some input devices present multiple distinguishable sources of input.  For example, a
- * game pad may have two analog joysticks, a directional pad and a full complement of buttons.
+ * Some input devices present multiple distinguishable sources of input.
  * Applications can query the framework about the characteristics of each distinct source.
  * </p><p>
  * As a further wrinkle, different kinds of input sources uses different coordinate systems
@@ -55,7 +54,7 @@
     
     /**
      * The input source has buttons or keys.
-     * Examples: {@link #SOURCE_KEYBOARD}, {@link #SOURCE_GAMEPAD}, {@link #SOURCE_DPAD}.
+     * Examples: {@link #SOURCE_KEYBOARD}, {@link #SOURCE_DPAD}.
      * 
      * A {@link KeyEvent} should be interpreted as a button or key press.
      * 
@@ -101,18 +100,6 @@
     public static final int SOURCE_CLASS_POSITION = 0x00000008;
     
     /**
-     * The input source is a joystick.
-     * 
-     * A {@link KeyEvent} should be interpreted as a joystick button press.
-     * 
-     * A {@link MotionEvent} should be interpreted in absolute coordinates as a joystick
-     * position in normalized device-specific units nominally between -1.0 and 1.0.
-     * 
-     * Use {@link #getMotionRange} to query the range and precision of motion.
-     */
-    public static final int SOURCE_CLASS_JOYSTICK = 0x00000010;
-    
-    /**
      * The input source is unknown.
      */
     public static final int SOURCE_UNKNOWN = 0x00000000;
@@ -132,13 +119,6 @@
     public static final int SOURCE_DPAD = 0x00000200 | SOURCE_CLASS_BUTTON;
     
     /**
-     * The input source is a gamepad.
-     * 
-     * @see #SOURCE_CLASS_BUTTON
-     */
-    public static final int SOURCE_GAMEPAD = 0x00000400 | SOURCE_CLASS_BUTTON;
-    
-    /**
      * The input source is a touch screen pointing device.
      * 
      * @see #SOURCE_CLASS_POINTER
@@ -168,20 +148,6 @@
      * @see #SOURCE_CLASS_POSITION
      */
     public static final int SOURCE_TOUCHPAD = 0x00100000 | SOURCE_CLASS_POSITION;
-
-    /**
-     * The input source is a joystick mounted on the left or is a standalone joystick.
-     * 
-     * @see #SOURCE_CLASS_JOYSTICK
-     */
-    public static final int SOURCE_JOYSTICK_LEFT = 0x01000000 | SOURCE_CLASS_JOYSTICK;
-    
-    /**
-     * The input source is a joystick mounted on the right.
-     * 
-     * @see #SOURCE_CLASS_JOYSTICK
-     */
-    public static final int SOURCE_JOYSTICK_RIGHT = 0x02000000 | SOURCE_CLASS_JOYSTICK;
     
     /**
      * A special input source constant that is used when filtering input devices
@@ -411,7 +377,7 @@
         /**
          * Gets the extent of the center flat position with respect to this coordinate.
          * For example, a flat value of 8 means that the center position is between -8 and +8.
-         * This value is mainly useful for calibrating joysticks.
+         * This value is mainly useful for calibrating self-centering devices.
          * @return The extent of the center flat position.
          */
         public float getFlat() {
@@ -506,13 +472,10 @@
         description.append("  Sources:");
         appendSourceDescriptionIfApplicable(description, SOURCE_KEYBOARD, "keyboard");
         appendSourceDescriptionIfApplicable(description, SOURCE_DPAD, "dpad");
-        appendSourceDescriptionIfApplicable(description, SOURCE_GAMEPAD, "gamepad");
         appendSourceDescriptionIfApplicable(description, SOURCE_TOUCHSCREEN, "touchscreen");
         appendSourceDescriptionIfApplicable(description, SOURCE_MOUSE, "mouse");
         appendSourceDescriptionIfApplicable(description, SOURCE_TRACKBALL, "trackball");
         appendSourceDescriptionIfApplicable(description, SOURCE_TOUCHPAD, "touchpad");
-        appendSourceDescriptionIfApplicable(description, SOURCE_JOYSTICK_LEFT, "joystick_left");
-        appendSourceDescriptionIfApplicable(description, SOURCE_JOYSTICK_RIGHT, "joystick_right");
         description.append("\n");
         
         appendRangeDescriptionIfApplicable(description, MOTION_RANGE_X, "x");
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index ed10e41..9e7eedf 100755
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -24,120 +24,305 @@
 import android.view.KeyCharacterMap.KeyData;
 
 /**
- * Contains constants for key events.
+ * Object used to report key and button events.
+ * <p>
+ * Each key press is described by a sequence of key events.  A key press
+ * starts with a key event with {@link #ACTION_DOWN}.  If the key is held
+ * sufficiently long that it repeats, then the initial down is followed
+ * additional key events with {@link #ACTION_DOWN} and a non-zero value for
+ * {@link #getRepeatCount()}.  The last key event is a {@link #ACTION_UP}
+ * for the key up.  If the key press is canceled, the key up event will have the
+ * {@link #FLAG_CANCELED} flag set.
+ * </p><p>
+ * Key events are generally accompanied by a key code ({@link #getKeyCode()}),
+ * scan code ({@link #getScanCode()}) and meta state ({@link #getMetaState()}).
+ * Key code constants are defined in this class.  Scan code constants are raw
+ * device-specific codes obtained from the OS and so are not generally meaningful
+ * to applications unless interpreted using the {@link KeyCharacterMap}.
+ * Meta states describe the pressed state of key modifiers
+ * such as {@link #META_SHIFT_ON} or {@link #META_ALT_ON}.
+ * </p><p>
+ * When interacting with an IME, the framework may deliver key events
+ * with the special action {@link #ACTION_MULTIPLE} that either specifies
+ * that single repeated key code or a sequence of characters to insert.
+ * </p><p>
+ * In general, the framework makes no guarantees that the key events delivered
+ * to a view constitute a complete key press.  In particular, there is no
+ * guarantee that a view will always receive a key event with {@link #ACTION_UP}
+ * for each {@link #ACTION_DOWN} that was delivered.
+ * </p><p>
+ * Refer to {@link InputDevice} for more information about how different kinds of
+ * input devices and sources represent keys and buttons.
+ * </p>
  */
 public class KeyEvent extends InputEvent implements Parcelable {
-    // key codes
+    /** Key code constant: Unknown key code. */
     public static final int KEYCODE_UNKNOWN         = 0;
+    /** Key code constant: Soft Left key.
+     * Usually situated below the display on phones and used as a multi-function
+     * feature key for selecting a software defined function shown on the bottom left
+     * of the display. */
     public static final int KEYCODE_SOFT_LEFT       = 1;
+    /** Key code constant: Soft Right key.
+     * Usually situated below the display on phones and used as a multi-function
+     * feature key for selecting a software defined function shown on the bottom right
+     * of the display. */
     public static final int KEYCODE_SOFT_RIGHT      = 2;
+    /** Key code constant: Home key.
+     * This key is handled by the framework and is never delivered to applications. */
     public static final int KEYCODE_HOME            = 3;
+    /** Key code constant: Back key. */
     public static final int KEYCODE_BACK            = 4;
+    /** Key code constant: Call key. */
     public static final int KEYCODE_CALL            = 5;
+    /** Key code constant: End Call key. */
     public static final int KEYCODE_ENDCALL         = 6;
+    /** Key code constant: '0' key. */
     public static final int KEYCODE_0               = 7;
+    /** Key code constant: '1' key. */
     public static final int KEYCODE_1               = 8;
+    /** Key code constant: '2' key. */
     public static final int KEYCODE_2               = 9;
+    /** Key code constant: '3' key. */
     public static final int KEYCODE_3               = 10;
+    /** Key code constant: '4' key. */
     public static final int KEYCODE_4               = 11;
+    /** Key code constant: '5' key. */
     public static final int KEYCODE_5               = 12;
+    /** Key code constant: '6' key. */
     public static final int KEYCODE_6               = 13;
+    /** Key code constant: '7' key. */
     public static final int KEYCODE_7               = 14;
+    /** Key code constant: '8' key. */
     public static final int KEYCODE_8               = 15;
+    /** Key code constant: '9' key. */
     public static final int KEYCODE_9               = 16;
+    /** Key code constant: '*' key. */
     public static final int KEYCODE_STAR            = 17;
+    /** Key code constant: '#' key. */
     public static final int KEYCODE_POUND           = 18;
+    /** Key code constant: Directional Pad Up key.
+     * May also be synthesized from trackball motions. */
     public static final int KEYCODE_DPAD_UP         = 19;
+    /** Key code constant: Directional Pad Down key.
+     * May also be synthesized from trackball motions. */
     public static final int KEYCODE_DPAD_DOWN       = 20;
+    /** Key code constant: Directional Pad Left key.
+     * May also be synthesized from trackball motions. */
     public static final int KEYCODE_DPAD_LEFT       = 21;
+    /** Key code constant: Directional Pad Right key.
+     * May also be synthesized from trackball motions. */
     public static final int KEYCODE_DPAD_RIGHT      = 22;
+    /** Key code constant: Directional Pad Center key.
+     * May also be synthesized from trackball motions. */
     public static final int KEYCODE_DPAD_CENTER     = 23;
+    /** Key code constant: Volume Up key. */
     public static final int KEYCODE_VOLUME_UP       = 24;
+    /** Key code constant: Volume Down key. */
     public static final int KEYCODE_VOLUME_DOWN     = 25;
+    /** Key code constant: Power key. */
     public static final int KEYCODE_POWER           = 26;
+    /** Key code constant: Camera key.
+     * Used to launch a camera application or take pictures. */
     public static final int KEYCODE_CAMERA          = 27;
+    /** Key code constant: Clear key. */
     public static final int KEYCODE_CLEAR           = 28;
+    /** Key code constant: 'A' key. */
     public static final int KEYCODE_A               = 29;
+    /** Key code constant: 'B' key. */
     public static final int KEYCODE_B               = 30;
+    /** Key code constant: 'C' key. */
     public static final int KEYCODE_C               = 31;
+    /** Key code constant: 'D' key. */
     public static final int KEYCODE_D               = 32;
+    /** Key code constant: 'E' key. */
     public static final int KEYCODE_E               = 33;
+    /** Key code constant: 'F' key. */
     public static final int KEYCODE_F               = 34;
+    /** Key code constant: 'G' key. */
     public static final int KEYCODE_G               = 35;
+    /** Key code constant: 'H' key. */
     public static final int KEYCODE_H               = 36;
+    /** Key code constant: 'I' key. */
     public static final int KEYCODE_I               = 37;
+    /** Key code constant: 'J' key. */
     public static final int KEYCODE_J               = 38;
+    /** Key code constant: 'K' key. */
     public static final int KEYCODE_K               = 39;
+    /** Key code constant: 'L' key. */
     public static final int KEYCODE_L               = 40;
+    /** Key code constant: 'M' key. */
     public static final int KEYCODE_M               = 41;
+    /** Key code constant: 'N' key. */
     public static final int KEYCODE_N               = 42;
+    /** Key code constant: 'O' key. */
     public static final int KEYCODE_O               = 43;
+    /** Key code constant: 'P' key. */
     public static final int KEYCODE_P               = 44;
+    /** Key code constant: 'Q' key. */
     public static final int KEYCODE_Q               = 45;
+    /** Key code constant: 'R' key. */
     public static final int KEYCODE_R               = 46;
+    /** Key code constant: 'S' key. */
     public static final int KEYCODE_S               = 47;
+    /** Key code constant: 'T' key. */
     public static final int KEYCODE_T               = 48;
+    /** Key code constant: 'U' key. */
     public static final int KEYCODE_U               = 49;
+    /** Key code constant: 'V' key. */
     public static final int KEYCODE_V               = 50;
+    /** Key code constant: 'W' key. */
     public static final int KEYCODE_W               = 51;
+    /** Key code constant: 'X' key. */
     public static final int KEYCODE_X               = 52;
+    /** Key code constant: 'Y' key. */
     public static final int KEYCODE_Y               = 53;
+    /** Key code constant: 'Z' key. */
     public static final int KEYCODE_Z               = 54;
+    /** Key code constant: ',' key. */
     public static final int KEYCODE_COMMA           = 55;
+    /** Key code constant: '.' key. */
     public static final int KEYCODE_PERIOD          = 56;
+    /** Key code constant: Left Alt modifier key. */
     public static final int KEYCODE_ALT_LEFT        = 57;
+    /** Key code constant: Right Alt modifier key. */
     public static final int KEYCODE_ALT_RIGHT       = 58;
+    /** Key code constant: Left Shift modifier key. */
     public static final int KEYCODE_SHIFT_LEFT      = 59;
+    /** Key code constant: Right Shift modifier key. */
     public static final int KEYCODE_SHIFT_RIGHT     = 60;
+    /** Key code constant: Tab key. */
     public static final int KEYCODE_TAB             = 61;
+    /** Key code constant: Space key. */
     public static final int KEYCODE_SPACE           = 62;
+    /** Key code constant: Symbol modifier key. */
     public static final int KEYCODE_SYM             = 63;
+    /** Key code constant: Explorer special function key.
+     * Used to launch a browser application. */
     public static final int KEYCODE_EXPLORER        = 64;
+    /** Key code constant: Envelope special function key.
+     * Used to launch a mail application. */
     public static final int KEYCODE_ENVELOPE        = 65;
+    /** Key code constant: Enter key. */
     public static final int KEYCODE_ENTER           = 66;
+    /** Key code constant: Delete key. */
     public static final int KEYCODE_DEL             = 67;
+    /** Key code constant: '`' (backtick) key. */
     public static final int KEYCODE_GRAVE           = 68;
+    /** Key code constant: '-'. */
     public static final int KEYCODE_MINUS           = 69;
+    /** Key code constant: '=' key. */
     public static final int KEYCODE_EQUALS          = 70;
+    /** Key code constant: '[' key. */
     public static final int KEYCODE_LEFT_BRACKET    = 71;
+    /** Key code constant: ']' key. */
     public static final int KEYCODE_RIGHT_BRACKET   = 72;
+    /** Key code constant: '\' key. */
     public static final int KEYCODE_BACKSLASH       = 73;
+    /** Key code constant: ';' key. */
     public static final int KEYCODE_SEMICOLON       = 74;
+    /** Key code constant: ''' (apostrophe) key. */
     public static final int KEYCODE_APOSTROPHE      = 75;
+    /** Key code constant: '/' key. */
     public static final int KEYCODE_SLASH           = 76;
+    /** Key code constant: '@' key. */
     public static final int KEYCODE_AT              = 77;
+    /** Key code constant: Number Lock modifier key. */
     public static final int KEYCODE_NUM             = 78;
+    /** Key code constant: Headset Hook key.
+     * Used to hang up calls and stop media. */
     public static final int KEYCODE_HEADSETHOOK     = 79;
+    /** Key code constant: Camera Focus key.
+     * Used to focus the camera. */
     public static final int KEYCODE_FOCUS           = 80;   // *Camera* focus
+    /** Key code constant: '+' key. */
     public static final int KEYCODE_PLUS            = 81;
+    /** Key code constant: Menu key. */
     public static final int KEYCODE_MENU            = 82;
+    /** Key code constant: Notification key. */
     public static final int KEYCODE_NOTIFICATION    = 83;
+    /** Key code constant: Search key. */
     public static final int KEYCODE_SEARCH          = 84;
+    /** Key code constant: Play/Pause media key. */
     public static final int KEYCODE_MEDIA_PLAY_PAUSE= 85;
+    /** Key code constant: Stop media key. */
     public static final int KEYCODE_MEDIA_STOP      = 86;
+    /** Key code constant: Play Next media key. */
     public static final int KEYCODE_MEDIA_NEXT      = 87;
+    /** Key code constant: Play Previous media key. */
     public static final int KEYCODE_MEDIA_PREVIOUS  = 88;
+    /** Key code constant: Rewind media key. */
     public static final int KEYCODE_MEDIA_REWIND    = 89;
+    /** Key code constant: Fast Forward media key. */
     public static final int KEYCODE_MEDIA_FAST_FORWARD = 90;
+    /** Key code constant: Mute key. */
     public static final int KEYCODE_MUTE            = 91;
+    /** Key code constant: Page Up key. */
     public static final int KEYCODE_PAGE_UP         = 92;
+    /** Key code constant: Page Down key. */
     public static final int KEYCODE_PAGE_DOWN       = 93;
+    /** Key code constant: Picture Symbols modifier key.
+     * Used to switch symbol sets (Emoji, Kao-moji). */
     public static final int KEYCODE_PICTSYMBOLS     = 94;   // switch symbol-sets (Emoji,Kao-moji)
+    /** Key code constant: Switch Charset modifier key.
+     * Used to switch character sets (Kanji, Katakana). */
     public static final int KEYCODE_SWITCH_CHARSET  = 95;   // switch char-sets (Kanji,Katakana)
+    /** Key code constant: A Button key.
+     * On a game controller, the A button should be either the button labeled A
+     * or the first button on the upper row of controller buttons. */
     public static final int KEYCODE_BUTTON_A        = 96;
+    /** Key code constant: B Button key.
+     * On a game controller, the B button should be either the button labeled B
+     * or the second button on the upper row of controller buttons. */
     public static final int KEYCODE_BUTTON_B        = 97;
+    /** Key code constant: C Button key.
+     * On a game controller, the C button should be either the button labeled C
+     * or the third button on the upper row of controller buttons. */
     public static final int KEYCODE_BUTTON_C        = 98;
+    /** Key code constant: X Button key.
+     * On a game controller, the X button should be either the button labeled X
+     * or the first button on the lower row of controller buttons. */
     public static final int KEYCODE_BUTTON_X        = 99;
+    /** Key code constant: Y Button key.
+     * On a game controller, the Y button should be either the button labeled Y
+     * or the second button on the lower row of controller buttons. */
     public static final int KEYCODE_BUTTON_Y        = 100;
+    /** Key code constant: Z Button key.
+     * On a game controller, the Z button should be either the button labeled Z
+     * or the third button on the lower row of controller buttons. */
     public static final int KEYCODE_BUTTON_Z        = 101;
+    /** Key code constant: L1 Button key.
+     * On a game controller, the L1 button should be either the button labeled L1 (or L)
+     * or the top left trigger button. */
     public static final int KEYCODE_BUTTON_L1       = 102;
+    /** Key code constant: R1 Button key.
+     * On a game controller, the R1 button should be either the button labeled R1 (or R)
+     * or the top right trigger button. */
     public static final int KEYCODE_BUTTON_R1       = 103;
+    /** Key code constant: L2 Button key.
+     * On a game controller, the L2 button should be either the button labeled L2
+     * or the bottom left trigger button. */
     public static final int KEYCODE_BUTTON_L2       = 104;
+    /** Key code constant: R2 Button key.
+     * On a game controller, the R2 button should be either the button labeled R2
+     * or the bottom right trigger button. */
     public static final int KEYCODE_BUTTON_R2       = 105;
+    /** Key code constant: Left Thumb Button key.
+     * On a game controller, the left thumb button indicates that the left (or only)
+     * joystick is pressed. */
     public static final int KEYCODE_BUTTON_THUMBL   = 106;
+    /** Key code constant: Right Thumb Button key.
+     * On a game controller, the right thumb button indicates that the right
+     * joystick is pressed. */
     public static final int KEYCODE_BUTTON_THUMBR   = 107;
+    /** Key code constant: Start Button key.
+     * On a game controller, the button labeled Start. */
     public static final int KEYCODE_BUTTON_START    = 108;
+    /** Key code constant: Select Button key.
+     * On a game controller, the button labeled Select. */
     public static final int KEYCODE_BUTTON_SELECT   = 109;
+    /** Key code constant: Mode Button key.
+     * On a game controller, the button labeled Mode. */
     public static final int KEYCODE_BUTTON_MODE     = 110;
 
     // NOTE: If you add a new keycode here you must also add it to:
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 78b9b5d..6705596 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -24,9 +24,71 @@
  * Object used to report movement (mouse, pen, finger, trackball) events.  This
  * class may hold either absolute or relative movements, depending on what
  * it is being used for.
- * 
- * Refer to {@link InputDevice} for information about how different kinds of
+ * <p>
+ * On pointing devices such as touch screens, pointer coordinates specify absolute
+ * positions such as view X/Y coordinates.  Each complete gesture is represented
+ * by a sequence of motion events with actions that describe pointer state transitions
+ * and movements.  A gesture starts with a motion event with {@link #ACTION_DOWN}
+ * that provides the location of the first pointer down.  As each additional
+ * pointer that goes down or up, the framework will generate a motion event with
+ * {@link #ACTION_POINTER_DOWN} or {@link #ACTION_POINTER_UP} accordingly.
+ * Pointer movements are described by motion events with {@link #ACTION_MOVE}.
+ * Finally, a gesture end either when the final pointer goes up as represented
+ * by a motion event with {@link #ACTION_UP} or when gesture is canceled
+ * with {@link #ACTION_CANCEL}.
+ * </p><p>
+ * On trackballs, the pointer coordinates specify relative movements as X/Y deltas.
+ * A trackball gesture consists of a sequence of movements described by motion
+ * events with {@link #ACTION_MOVE} interspersed with occasional {@link #ACTION_DOWN}
+ * or {@link #ACTION_UP} motion events when the trackball button is pressed or released.
+ * </p><p>
+ * Motion events always report movements for all pointers at once.  The number
+ * of pointers only ever changes by one as individual pointers go up and down,
+ * except when the gesture is canceled.
+ * </p><p>
+ * The order in which individual pointers appear within a motion event can change
+ * from one event to the next. Use the {@link #getPointerId(int)} method to obtain a
+ * pointer id to track pointers across motion events in a gesture.  Then for
+ * successive motion events, use the {@link #findPointerIndex(int)} method to obtain
+ * the pointer index for a given pointer id in that motion event.
+ * </p><p>
+ * For efficiency, motion events with {@link #ACTION_MOVE} may batch together
+ * multiple movement samples within a single object.  The most current
+ * pointer coordinates are available using {@link #getX(int)} and {@link #getY(int)}.
+ * Earlier coordinates within the batch are accessed using {@link #getHistoricalX(int, int)}
+ * and {@link #getHistoricalY(int, int)}.  The coordinates are "historical" only
+ * insofar as they are older than the current coordinates in the batch; however,
+ * they are still distinct from any other coordinates reported in prior motion events.
+ * To process all coordinates in the batch in time order, first consume the historical
+ * coordinates then consume the current coordinates.
+ * </p><p>
+ * Example: Consuming all samples for all pointers in a motion event in time order.
+ * </p><p><pre><code>
+ * void printSamples(MotionEvent ev) {
+ *     final int historySize = ev.getHistorySize();
+ *     final int pointerCount = ev.getPointerCount();
+ *     for (int h = 0; h &lt; historySize; h++) {
+ *         System.out.printf("At time %d:", ev.getHistoricalEventTime(h));
+ *         for (int p = 0; p &lt; pointerCount; p++) {
+ *             System.out.printf("  pointer %d: (%f,%f)",
+ *                 ev.getPointerId(p), ev.getHistoricalX(p, h), ev.getHistoricalY(p, h));
+ *         }
+ *     }
+ *     System.out.printf("At time %d:", ev.getEventTime());
+ *     for (int p = 0; p &lt; pointerCount; p++) {
+ *         System.out.printf("  pointer %d: (%f,%f)",
+ *             ev.getPointerId(p), ev.getX(p), ev.getY(p));
+ *     }
+ * }
+ * </code></pre></p><p>
+ * In general, the framework makes no guarantees that the motion events delivered
+ * to a view constitute a complete gesture.  In particular, there is no
+ * guarantee that a view will always receive a motion event with {@link #ACTION_UP}
+ * for each {@link #ACTION_DOWN} that was delivered.
+ * </p><p>
+ * Refer to {@link InputDevice} for more information about how different kinds of
  * input devices and sources represent pointer coordinates.
+ * </p>
  */
 public final class MotionEvent extends InputEvent implements Parcelable {
     private static final long MS_PER_NS = 1000000;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index fe003a4..6e395c8 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -1551,6 +1551,12 @@
     private static final int AWAKEN_SCROLL_BARS_ON_ATTACH = 0x08000000;
 
     /**
+     * Indicates that this view has a visible/touchable overlay.
+     * @hide
+     */
+    static final int HAS_OVERLAY = 0x10000000;
+
+    /**
      * Always allow a user to overscroll this view, provided it is a
      * view that can scroll.
      *
@@ -1582,7 +1588,7 @@
      * {@link #OVERSCROLL_ALWAYS}, {@link #OVERSCROLL_IF_CONTENT_SCROLLS},
      * and {@link #OVERSCROLL_NEVER}.
      */
-    private int mOverscrollMode = OVERSCROLL_ALWAYS;
+    private int mOverscrollMode;
 
     /**
      * The parent this view is attached to.
@@ -1876,6 +1882,7 @@
         // Used for debug only
         //++sInstanceCount;
         mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
+        setOverscrollMode(OVERSCROLL_ALWAYS);
     }
 
     /**
@@ -2836,6 +2843,57 @@
         resetPressedState();
     }
 
+    /**
+     * Enable or disable drawing overlays after a full drawing pass. This enables a view to
+     * draw on a topmost overlay layer after normal drawing completes and get right of first
+     * refusal for touch events in the window.
+     * 
+     * <em>Warning:</em> Views that use this feature should take care to disable/enable overlay
+     * appropriately when they are attached/detached from their window. All overlays should be
+     * disabled when detached.
+     * 
+     * @param enabled true if overlay drawing should be enabled for this view, false otherwise
+     * 
+     * @see #onDrawOverlay(Canvas)
+     * 
+     * @hide
+     */
+    protected void setOverlayEnabled(boolean enabled) {
+        final boolean oldValue = (mPrivateFlags & HAS_OVERLAY) == HAS_OVERLAY;
+        mPrivateFlags = (mPrivateFlags & ~HAS_OVERLAY) | (enabled ? HAS_OVERLAY : 0);
+        if (enabled != oldValue) {
+            final ViewParent parent = getParent();
+            if (parent != null) {
+                try {
+                    parent.childOverlayStateChanged(this);
+                } catch (AbstractMethodError e) {
+                    Log.e(VIEW_LOG_TAG, "Could not propagate hasOverlay state", e);
+                }
+            }
+        }
+    }
+
+    /**
+     * @return true if this View has an overlay enabled.
+     * 
+     * @see #setOverlayEnabled(boolean)
+     * @see #onDrawOverlay(Canvas)
+     * 
+     * @hide
+     */
+    public boolean isOverlayEnabled() {
+        return (mPrivateFlags & HAS_OVERLAY) == HAS_OVERLAY;
+    }
+
+    /**
+     * Override this method to draw on an overlay layer above all other views in the window
+     * after the standard drawing pass is complete. This allows a view to draw outside its
+     * normal boundaries.
+     * @hide
+     */
+    public void onDrawOverlay(Canvas canvas) {
+    }
+
     private void resetPressedState() {
         if ((mViewFlags & ENABLED_MASK) == DISABLED) {
             return;
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 28bed3a..deba70c 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -228,6 +228,11 @@
     protected static final int FLAG_DISALLOW_INTERCEPT = 0x80000;
 
     /**
+     * When set, at least one child of this ViewGroup will return true from hasOverlay.
+     */
+    private static final int FLAG_CHILD_HAS_OVERLAY = 0x100000;
+
+    /**
      * Indicates which types of drawing caches are to be kept in memory.
      * This field should be made private, so it is hidden from the SDK.
      * {@hide}
@@ -854,6 +859,34 @@
                 final int scrolledYInt = (int) scrolledYFloat;
                 final View[] children = mChildren;
                 final int count = mChildrenCount;
+
+                // Check for children with overlays first. They don't rely on hit rects to determine
+                // if they can accept a new touch event.
+                if ((mGroupFlags & FLAG_CHILD_HAS_OVERLAY) == FLAG_CHILD_HAS_OVERLAY) {
+                    for (int i = count - 1; i >= 0; i--) {
+                        final View child = children[i];
+                        // Don't let children respond to events as an overlay during an animation.
+                        if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE
+                                && child.getAnimation() == null
+                                && child.isOverlayEnabled()) {
+                            // offset the event to the view's coordinate system
+                            final float xc = scrolledXFloat - child.mLeft;
+                            final float yc = scrolledYFloat - child.mTop;
+                            ev.setLocation(xc, yc);
+                            child.mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;
+                            if (child.dispatchTouchEvent(ev))  {
+                                // Event handled, we have a target now.
+                                mMotionTarget = child;
+                                return true;
+                            }
+                            // The event didn't get handled, try the next view.
+                            // Don't reset the event's location, it's not
+                            // necessary here.
+                        }
+                    }
+                }
+
+                // Now check views normally.
                 for (int i = count - 1; i >= 0; i--) {
                     final View child = children[i];
                     if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE
@@ -2312,6 +2345,8 @@
         if (clearChildFocus != null) {
             clearChildFocus(clearChildFocus);
         }
+
+        mGroupFlags &= ~FLAG_CHILD_HAS_OVERLAY;
     }
 
     /**
@@ -2534,7 +2569,8 @@
                 final int left = mLeft;
                 final int top = mTop;
 
-                if (dirty.intersect(0, 0, mRight - left, mBottom - top) ||
+                if ((mGroupFlags & FLAG_CHILD_HAS_OVERLAY) == FLAG_CHILD_HAS_OVERLAY ||
+                        dirty.intersect(0, 0, mRight - left, mBottom - top) ||
                         (mPrivateFlags & DRAW_ANIMATION) == DRAW_ANIMATION) {
                     mPrivateFlags &= ~DRAWING_CACHE_VALID;
 
@@ -3453,6 +3489,69 @@
     }
 
     /**
+     * Called when a child's overlay state changes between enabled/disabled.
+     * @param child Child view whose state has changed or null
+     * @hide
+     */
+    public void childOverlayStateChanged(View child) {
+        boolean childHasOverlay = false;
+        if (child != null) {
+            childHasOverlay = child.isOverlayEnabled();
+        } else {
+            final int childCount = getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                if (childHasOverlay |= getChildAt(i).isOverlayEnabled()) {
+                    break;
+                }
+            }
+        }
+        
+        final boolean hasChildWithOverlay = childHasOverlay ||
+                (mGroupFlags & FLAG_CHILD_HAS_OVERLAY) == FLAG_CHILD_HAS_OVERLAY;
+
+        final boolean oldValue = isOverlayEnabled();
+        mGroupFlags = (mGroupFlags & ~FLAG_CHILD_HAS_OVERLAY) |
+                (hasChildWithOverlay ? FLAG_CHILD_HAS_OVERLAY : 0);
+        if (isOverlayEnabled() != oldValue) {
+            final ViewParent parent = getParent();
+            if (parent != null) {
+                try {
+                    parent.childOverlayStateChanged(this);
+                } catch (AbstractMethodError e) {
+                    Log.e("ViewGroup", "Could not propagate hasOverlay state", e);
+                }
+            }
+        }
+    }
+
+    /**
+     * @hide
+     */
+    public boolean isOverlayEnabled() {
+        return super.isOverlayEnabled() ||
+                ((mGroupFlags & FLAG_CHILD_HAS_OVERLAY) == FLAG_CHILD_HAS_OVERLAY);
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public void onDrawOverlay(Canvas canvas) {
+        if ((mGroupFlags & FLAG_CHILD_HAS_OVERLAY) == FLAG_CHILD_HAS_OVERLAY) {
+            final int childCount = getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                final View child = getChildAt(i);
+                if (child.isOverlayEnabled()) {
+                    canvas.translate(child.mLeft - child.mScrollX, child.mTop - child.mScrollY);
+                    child.onDrawOverlay(canvas);
+                    canvas.translate(-(child.mLeft - child.mScrollX),
+                            -(child.mTop - child.mScrollY));
+                }
+            }
+        }
+    }
+
+    /**
      * LayoutParams are used by views to tell their parents how they want to be
      * laid out. See
      * {@link android.R.styleable#ViewGroup_Layout ViewGroup Layout Attributes}
diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java
index b456c5d..a0d3618 100644
--- a/core/java/android/view/ViewParent.java
+++ b/core/java/android/view/ViewParent.java
@@ -208,4 +208,11 @@
      */
     public boolean requestChildRectangleOnScreen(View child, Rect rectangle,
             boolean immediate);
+
+    /**
+     * Called when a child view's overlay state changes between enabled/disabled.
+     * @param child Child view whose state changed or null.
+     * @hide
+     */
+    public void childOverlayStateChanged(View child);
 }
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 57c9055..acec476 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -222,6 +222,8 @@
 
     private final int mDensity;
     
+    private boolean mHasOverlay;
+
     public static IWindowSession getWindowSession(Looper mainLooper) {
         synchronized (mStaticInit) {
             if (!mInitialized) {
@@ -1518,6 +1520,9 @@
                         canvas.setScreenDensity(scalingRequired
                                 ? DisplayMetrics.DENSITY_DEVICE : 0);
                         mView.draw(canvas);
+                        if (mHasOverlay) {
+                            mView.onDrawOverlay(canvas);
+                        }
                     } finally {
                         mAttachInfo.mIgnoreDirtyState = false;
                         canvas.restoreToCount(saveCount);
@@ -2914,6 +2919,19 @@
         return scrollToRectOrFocus(rectangle, immediate);
     }
 
+    /**
+     * @hide
+     */
+    public void childOverlayStateChanged(View child) {
+        final boolean oldState = mHasOverlay;
+        mHasOverlay = child.isOverlayEnabled();
+        // Invalidate the whole thing when we change overlay states just in case
+        // something left chunks of data drawn someplace it shouldn't have.
+        if (mHasOverlay != oldState) {
+            child.invalidate();
+        }
+    }
+
     class TakenSurfaceHolder extends BaseSurfaceHolder {
         @Override
         public boolean onAllowLockCanvas() {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index e97bbfb..a09b0c8 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -285,6 +285,10 @@
     }
     InputMethodState mInputMethodState;
 
+    private int mTextSelectHandleLeftRes;
+    private int mTextSelectHandleRightRes;
+    private int mTextSelectHandleRes;
+
     /*
      * Kick-start the font cache for the zygote process (to pay the cost of
      * initializing freetype for our default font only once).
@@ -705,6 +709,18 @@
                     Log.w(LOG_TAG, "Failure reading input extras", e);
                 }
                 break;
+
+            case com.android.internal.R.styleable.TextView_textSelectHandleLeft:
+                mTextSelectHandleLeftRes = a.getResourceId(attr, 0);
+                break;
+
+            case com.android.internal.R.styleable.TextView_textSelectHandleRight:
+                mTextSelectHandleRightRes = a.getResourceId(attr, 0);
+                break;
+
+            case com.android.internal.R.styleable.TextView_textSelectHandle:
+                mTextSelectHandleRes = a.getResourceId(attr, 0);
+                break;
             }
         }
         a.recycle();
@@ -3733,6 +3749,8 @@
             showError();
             mShowErrorAfterAttach = false;
         }
+        
+        updateOverlay();
     }
 
     @Override
@@ -3750,6 +3768,8 @@
         if (mError != null) {
             hideError();
         }
+        
+        setOverlayEnabled(false);
     }
 
     @Override
@@ -4100,7 +4120,13 @@
         */
 
         canvas.restore();
+    }
 
+    /**
+     * @hide
+     */
+    @Override
+    public void onDrawOverlay(Canvas canvas) {
         if (mInsertionPointCursorController != null) {
             mInsertionPointCursorController.draw(canvas);
         }
@@ -6679,10 +6705,31 @@
     public boolean onTouchEvent(MotionEvent event) {
         final int action = event.getActionMasked();
         if (action == MotionEvent.ACTION_DOWN) {
+            // Check to see if we're testing for our anchor overlay.
+            boolean handled = false;
+            final float x = event.getX();
+            final float y = event.getY();
+            if (x < 0 || x >= mRight - mLeft || y < 0 || y >= mBottom - mTop) {
+                if (mInsertionPointCursorController != null) {
+                    handled |= mInsertionPointCursorController.onTouchEvent(event);
+                }
+                if (mSelectionModifierCursorController != null) {
+                    handled |= mSelectionModifierCursorController.onTouchEvent(event);
+                }
+
+                if (!handled) {
+                    return false;
+                }
+            }
+
             // Reset this state; it will be re-set if super.onTouchEvent
             // causes focus to move to the view.
             mTouchFocusSelected = false;
             mScrolled = false;
+
+            if (handled) {
+                return true;
+            }
         }
 
         final boolean superResult = super.onTouchEvent(event);
@@ -7571,6 +7618,17 @@
         }
     }
 
+    private void updateOverlay() {
+        boolean enableOverlay = false;
+        if (mSelectionModifierCursorController != null) {
+            enableOverlay |= mSelectionModifierCursorController.isShowing();
+        }
+        if (mInsertionPointCursorController != null) {
+            enableOverlay |= mInsertionPointCursorController.isShowing();
+        }
+        setOverlayEnabled(enableOverlay);
+    }
+
     /**
      * A CursorController instance can be used to control a cursor in the text.
      *
@@ -7594,6 +7652,11 @@
         public void hide();
 
         /**
+         * @return true if the CursorController is currently visible
+         */
+        public boolean isShowing();
+
+        /**
          * Update the controller's position.
          */
         public void updatePosition(int x, int y);
@@ -7615,7 +7678,7 @@
          * a chance to become active and/or visible.
          * @param event The touch event
          */
-        public void onTouchEvent(MotionEvent event);
+        public boolean onTouchEvent(MotionEvent event);
 
         /**
          * Draws a visual representation of the controller on the canvas.
@@ -7649,10 +7712,10 @@
             final Rect bounds = sCursorControllerTempRect;
             bounds.left = (int) (mLayout.getPrimaryHorizontal(offset) - drawableWidth / 2.0)
                 + mScrollX;
-            bounds.top = (bottom ? lineBottom : lineTop) - drawableHeight / 2 + mScrollY;
+            bounds.top = (bottom ? lineBottom : lineTop) + mScrollY;
 
             mTopExtension = bottom ? 0 : drawableHeight / 2;
-            mBottomExtension = drawableHeight;
+            mBottomExtension = 0; //drawableHeight / 4;
 
             // Extend touch region up when editing the last line of text (or a single line) so that
             // it is easier to grab.
@@ -7664,8 +7727,9 @@
             bounds.bottom = bounds.top + drawableHeight;
 
             convertFromViewportToContentCoordinates(bounds);
+            invalidate();
             mDrawable.setBounds(bounds);
-            postInvalidate();
+            invalidate();
         }
 
         boolean hasFingerOn(float x, float y) {
@@ -7682,9 +7746,16 @@
             return Rect.intersects(mDrawable.getBounds(), fingerRect);
         }
 
+        void invalidate() {
+            final Rect bounds = mDrawable.getBounds();
+            TextView.this.invalidate(bounds.left, bounds.top,
+                    bounds.right, bounds.bottom);
+        }
+
         void postInvalidate() {
             final Rect bounds = mDrawable.getBounds();
-            TextView.this.postInvalidate(bounds.left, bounds.top, bounds.right, bounds.bottom);
+            TextView.this.postInvalidate(bounds.left, bounds.top,
+                    bounds.right, bounds.bottom);
         }
 
         void postInvalidateDelayed(long delay) {
@@ -7710,7 +7781,7 @@
 
         InsertionPointCursorController() {
             Resources res = mContext.getResources();
-            mHandle = new Handle(res.getDrawable(com.android.internal.R.drawable.text_select_handle));
+            mHandle = new Handle(res.getDrawable(mTextSelectHandleRes));
         }
 
         public void show() {
@@ -7718,6 +7789,7 @@
             // Has to be done after updateDrawablePosition, so that previous position invalidate
             // in only done if necessary.
             mIsVisible = true;
+            updateOverlay();
         }
 
         public void hide() {
@@ -7731,6 +7803,10 @@
             }
         }
 
+        public boolean isShowing() {
+            return mIsVisible;
+        }
+
         public void draw(Canvas canvas) {
             if (mIsVisible) {
                 int time = (int) (System.currentTimeMillis() - mFadeOutTimerStart);
@@ -7746,6 +7822,7 @@
                     } else {
                         mHandle.mDrawable.setAlpha(0);
                         mIsVisible = false;
+                        updateOverlay();
                     }
                 }
                 mHandle.mDrawable.draw(canvas);
@@ -7774,6 +7851,7 @@
                 // Should never happen, safety check.
                 Log.w(LOG_TAG, "Update cursor controller position called with no cursor");
                 mIsVisible = false;
+                updateOverlay();
                 return;
             }
 
@@ -7783,7 +7861,7 @@
             mHandle.mDrawable.setAlpha(255);
         }
 
-        public void onTouchEvent(MotionEvent event) {
+        public boolean onTouchEvent(MotionEvent event) {
             if (isFocused() && isTextEditable() && mIsVisible) {
                 switch (event.getActionMasked()) {
                     case MotionEvent.ACTION_DOWN : {
@@ -7811,8 +7889,9 @@
                             mOffsetY += viewportToContentVerticalOffset();
 
                             mOnDownTimerStart = event.getEventTime();
+                            return true;
                         }
-                        break;
+                        return false;
                     }
 
                     case MotionEvent.ACTION_UP : {
@@ -7830,6 +7909,7 @@
                     }
                 }
             }
+            return false;
         }
 
         public float getOffsetX() {
@@ -7859,8 +7939,8 @@
 
         SelectionModifierCursorController() {
             Resources res = mContext.getResources();
-            mStartHandle = new Handle(res.getDrawable(com.android.internal.R.drawable.text_select_handle));
-            mEndHandle = new Handle(res.getDrawable(com.android.internal.R.drawable.text_select_handle));
+            mStartHandle = new Handle(res.getDrawable(mTextSelectHandleLeftRes));
+            mEndHandle = new Handle(res.getDrawable(mTextSelectHandleRightRes));
         }
 
         public void show() {
@@ -7868,6 +7948,7 @@
             // Has to be done after updateDrawablePositions, so that previous position invalidate
             // in only done if necessary.
             mIsVisible = true;
+            updateOverlay();
             mFadeOutTimerStart = -1;
             hideInsertionPointCursorController();
         }
@@ -7880,8 +7961,13 @@
             }
         }
 
+        public boolean isShowing() {
+            return mIsVisible;
+        }
+
         public void cancelFadeOutAnimation() {
             mIsVisible = false;
+            updateOverlay();
             mStartHandle.postInvalidate();
             mEndHandle.postInvalidate();
         }
@@ -7900,6 +7986,7 @@
                         mStartHandle.mDrawable.setAlpha(0);
                         mEndHandle.mDrawable.setAlpha(0);
                         mIsVisible = false;
+                        updateOverlay();
                     }
                 }
                 mStartHandle.mDrawable.draw(canvas);
@@ -7957,6 +8044,7 @@
                 // Should never happen, safety check.
                 Log.w(LOG_TAG, "Update selection controller position called with no cursor");
                 mIsVisible = false;
+                updateOverlay();
                 return;
             }
 
@@ -7969,7 +8057,7 @@
             mEndHandle.mDrawable.setAlpha(255);
         }
 
-        public void onTouchEvent(MotionEvent event) {
+        public boolean onTouchEvent(MotionEvent event) {
             if (isTextEditable()) {
                 switch (event.getActionMasked()) {
                     case MotionEvent.ACTION_DOWN:
@@ -8004,6 +8092,7 @@
 
                                     mOnDownTimerStart = event.getEventTime();
                                     ((ArrowKeyMovementMethod)mMovement).setCursorController(this);
+                                    return true;
                                 }
                             }
                         }
@@ -8029,6 +8118,7 @@
                         break;
                 }
             }
+            return false;
         }
 
         /**
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 1620778..351714e 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -18,6 +18,7 @@
 
 import com.android.internal.os.BatteryStatsImpl;
 
+import android.os.WorkSource;
 import android.telephony.SignalStrength;
 
 interface IBatteryStats {
@@ -33,6 +34,9 @@
        SensorService.cpp */
     void noteStopSensor(int uid, int sensor);
 
+    void noteStartWakelockFromSource(in WorkSource ws, int pid, String name, int type);
+    void noteStopWakelockFromSource(in WorkSource ws, int pid, String name, int type);
+
     void noteStartGps(int uid);
     void noteStopGps(int uid);
     void noteScreenOn();
@@ -45,10 +49,11 @@
     void notePhoneSignalStrength(in SignalStrength signalStrength);
     void notePhoneDataConnectionState(int dataType, boolean hasData);
     void notePhoneState(int phoneState);
-    void noteWifiOn(int uid);
-    void noteWifiOff(int uid);
-    void noteWifiRunning();
-    void noteWifiStopped();
+    void noteWifiOn();
+    void noteWifiOff();
+    void noteWifiRunning(in WorkSource ws);
+    void noteWifiRunningChanged(in WorkSource oldWs, in WorkSource newWs);
+    void noteWifiStopped(in WorkSource ws);
     void noteBluetoothOn();
     void noteBluetoothOff();
     void noteFullWifiLockAcquired(int uid);
@@ -57,6 +62,12 @@
     void noteScanWifiLockReleased(int uid);
     void noteWifiMulticastEnabled(int uid);
     void noteWifiMulticastDisabled(int uid);
+    void noteFullWifiLockAcquiredFromSource(in WorkSource ws);
+    void noteFullWifiLockReleasedFromSource(in WorkSource ws);
+    void noteScanWifiLockAcquiredFromSource(in WorkSource ws);
+    void noteScanWifiLockReleasedFromSource(in WorkSource ws);
+    void noteWifiMulticastEnabledFromSource(in WorkSource ws);
+    void noteWifiMulticastDisabledFromSource(in WorkSource ws);
     void setBatteryState(int status, int health, int plugType, int level, int temp, int volt);
     long getAwakeTimeBattery();
     long getAwakeTimePlugged();
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 0ef1ea5..6e5c47f 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -29,6 +29,7 @@
 import android.os.Parcelable;
 import android.os.Process;
 import android.os.SystemClock;
+import android.os.WorkSource;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
 import android.telephony.TelephonyManager;
@@ -50,6 +51,7 @@
 import java.util.Iterator;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.ReentrantLock;
 
 /**
  * All information we are collecting about things that can happen that impact
@@ -65,15 +67,15 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS' 
 
     // Current on-disk Parcel version
-    private static final int VERSION = 50;
+    private static final int VERSION = 51;
 
     // Maximum number of items we will record in the history.
-    private static final int MAX_HISTORY_ITEMS = 1000;
+    private static final int MAX_HISTORY_ITEMS = 2000;
     
     // The maximum number of names wakelocks we will keep track of
     // per uid; once the limit is reached, we batch the remaining wakelocks
     // in to one common name.
-    private static final int MAX_WAKELOCKS_PER_UID = 20;
+    private static final int MAX_WAKELOCKS_PER_UID = 30;
     
     private static final String BATCHED_WAKELOCK_NAME = "*overflow*";
     
@@ -128,6 +130,10 @@
     final ArrayList<StopwatchTimer> mWindowTimers = new ArrayList<StopwatchTimer>();
     final SparseArray<ArrayList<StopwatchTimer>> mSensorTimers
             = new SparseArray<ArrayList<StopwatchTimer>>();
+    final ArrayList<StopwatchTimer> mWifiRunningTimers = new ArrayList<StopwatchTimer>();
+    final ArrayList<StopwatchTimer> mFullWifiLockTimers = new ArrayList<StopwatchTimer>();
+    final ArrayList<StopwatchTimer> mScanWifiLockTimers = new ArrayList<StopwatchTimer>();
+    final ArrayList<StopwatchTimer> mWifiMulticastTimers = new ArrayList<StopwatchTimer>();
 
     // Last partial timers we use for distributing CPU usage.
     final ArrayList<StopwatchTimer> mLastPartialTimers = new ArrayList<StopwatchTimer>();
@@ -193,8 +199,8 @@
     StopwatchTimer mWifiOnTimer;
     int mWifiOnUid = -1;
 
-    boolean mWifiRunning;
-    StopwatchTimer mWifiRunningTimer;
+    boolean mGlobalWifiRunning;
+    StopwatchTimer mGlobalWifiRunningTimer;
     
     boolean mBluetoothOn;
     StopwatchTimer mBluetoothOnTimer;
@@ -1171,7 +1177,7 @@
         // If the current time is basically the same as the last time,
         // just collapse into one record.
         if (mHistoryEnd != null && mHistoryEnd.cmd == HistoryItem.CMD_UPDATE
-                && (mHistoryBaseTime+curTime) < (mHistoryEnd.time+100)) {
+                && (mHistoryBaseTime+curTime) < (mHistoryEnd.time+500)) {
             // If the current is the same as the one before, then we no
             // longer need the entry.
             if (mHistoryLastEnd != null && mHistoryLastEnd.cmd == HistoryItem.CMD_UPDATE
@@ -1187,6 +1193,10 @@
             return;
         }
 
+        if (mNumHistoryItems == MAX_HISTORY_ITEMS) {
+            addHistoryRecordLocked(curTime, HistoryItem.CMD_OVERFLOW);
+        }
+
         if (mNumHistoryItems >= MAX_HISTORY_ITEMS) {
             // Once we've reached the maximum number of items, we only
             // record changes to the battery level.
@@ -1327,6 +1337,20 @@
         }
     }
 
+    public void noteStartWakeFromSourceLocked(WorkSource ws, int pid, String name, int type) {
+        int N = ws.size();
+        for (int i=0; i<N; i++) {
+            noteStartWakeLocked(ws.get(i), pid, name, type);
+        }
+    }
+
+    public void noteStopWakeFromSourceLocked(WorkSource ws, int pid, String name, int type) {
+        int N = ws.size();
+        for (int i=0; i<N; i++) {
+            noteStopWakeLocked(ws.get(i), pid, name, type);
+        }
+    }
+
     public int startAddingCpuLocked() {
         mHandler.removeMessages(MSG_UPDATE_WAKELOCKS);
 
@@ -1750,7 +1774,7 @@
         }
     }
     
-    public void noteWifiOnLocked(int uid) {
+    public void noteWifiOnLocked() {
         if (!mWifiOn) {
             mHistoryCur.states |= HistoryItem.STATE_WIFI_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI on to: "
@@ -1759,16 +1783,9 @@
             mWifiOn = true;
             mWifiOnTimer.startRunningLocked(this);
         }
-        if (mWifiOnUid != uid) {
-            if (mWifiOnUid >= 0) {
-                getUidStatsLocked(mWifiOnUid).noteWifiTurnedOffLocked();
-            }
-            mWifiOnUid = uid;
-            getUidStatsLocked(uid).noteWifiTurnedOnLocked();
-        }
     }
     
-    public void noteWifiOffLocked(int uid) {
+    public void noteWifiOffLocked() {
         if (mWifiOn) {
             mHistoryCur.states &= ~HistoryItem.STATE_WIFI_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI off to: "
@@ -1778,7 +1795,7 @@
             mWifiOnTimer.stopRunningLocked(this);
         }
         if (mWifiOnUid >= 0) {
-            getUidStatsLocked(mWifiOnUid).noteWifiTurnedOffLocked();
+            getUidStatsLocked(mWifiOnUid).noteWifiStoppedLocked();
             mWifiOnUid = -1;
         }
     }
@@ -1831,25 +1848,52 @@
         getUidStatsLocked(uid).noteVideoTurnedOffLocked();
     }
 
-    public void noteWifiRunningLocked() {
-        if (!mWifiRunning) {
+    public void noteWifiRunningLocked(WorkSource ws) {
+        if (!mGlobalWifiRunning) {
             mHistoryCur.states |= HistoryItem.STATE_WIFI_RUNNING_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI running to: "
                     + Integer.toHexString(mHistoryCur.states));
             addHistoryRecordLocked(SystemClock.elapsedRealtime());
-            mWifiRunning = true;
-            mWifiRunningTimer.startRunningLocked(this);
+            mGlobalWifiRunning = true;
+            mGlobalWifiRunningTimer.startRunningLocked(this);
+            int N = ws.size();
+            for (int i=0; i<N; i++) {
+                getUidStatsLocked(ws.get(i)).noteWifiRunningLocked();
+            }
+        } else {
+            Log.w(TAG, "noteWifiRunningLocked -- called while WIFI running");
         }
     }
 
-    public void noteWifiStoppedLocked() {
-        if (mWifiRunning) {
+    public void noteWifiRunningChangedLocked(WorkSource oldWs, WorkSource newWs) {
+        if (mGlobalWifiRunning) {
+            int N = oldWs.size();
+            for (int i=0; i<N; i++) {
+                getUidStatsLocked(oldWs.get(i)).noteWifiStoppedLocked();
+            }
+            N = newWs.size();
+            for (int i=0; i<N; i++) {
+                getUidStatsLocked(newWs.get(i)).noteWifiRunningLocked();
+            }
+        } else {
+            Log.w(TAG, "noteWifiRunningChangedLocked -- called while WIFI not running");
+        }
+    }
+
+    public void noteWifiStoppedLocked(WorkSource ws) {
+        if (mGlobalWifiRunning) {
             mHistoryCur.states &= ~HistoryItem.STATE_WIFI_RUNNING_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI stopped to: "
                     + Integer.toHexString(mHistoryCur.states));
             addHistoryRecordLocked(SystemClock.elapsedRealtime());
-            mWifiRunning = false;
-            mWifiRunningTimer.stopRunningLocked(this);
+            mGlobalWifiRunning = false;
+            mGlobalWifiRunningTimer.stopRunningLocked(this);
+            int N = ws.size();
+            for (int i=0; i<N; i++) {
+                getUidStatsLocked(ws.get(i)).noteWifiStoppedLocked();
+            }
+        } else {
+            Log.w(TAG, "noteWifiStoppedLocked -- called while WIFI not running");
         }
     }
 
@@ -1947,6 +1991,48 @@
         getUidStatsLocked(uid).noteWifiMulticastDisabledLocked();
     }
 
+    public void noteFullWifiLockAcquiredFromSourceLocked(WorkSource ws) {
+        int N = ws.size();
+        for (int i=0; i<N; i++) {
+            noteFullWifiLockAcquiredLocked(ws.get(i));
+        }
+    }
+
+    public void noteFullWifiLockReleasedFromSourceLocked(WorkSource ws) {
+        int N = ws.size();
+        for (int i=0; i<N; i++) {
+            noteFullWifiLockReleasedLocked(ws.get(i));
+        }
+    }
+
+    public void noteScanWifiLockAcquiredFromSourceLocked(WorkSource ws) {
+        int N = ws.size();
+        for (int i=0; i<N; i++) {
+            noteScanWifiLockAcquiredLocked(ws.get(i));
+        }
+    }
+
+    public void noteScanWifiLockReleasedFromSourceLocked(WorkSource ws) {
+        int N = ws.size();
+        for (int i=0; i<N; i++) {
+            noteScanWifiLockReleasedLocked(ws.get(i));
+        }
+    }
+
+    public void noteWifiMulticastEnabledFromSourceLocked(WorkSource ws) {
+        int N = ws.size();
+        for (int i=0; i<N; i++) {
+            noteWifiMulticastEnabledLocked(ws.get(i));
+        }
+    }
+
+    public void noteWifiMulticastDisabledFromSourceLocked(WorkSource ws) {
+        int N = ws.size();
+        for (int i=0; i<N; i++) {
+            noteWifiMulticastDisabledLocked(ws.get(i));
+        }
+    }
+
     @Override public long getScreenOnTime(long batteryRealtime, int which) {
         return mScreenOnTimer.getTotalTimeLocked(batteryRealtime, which);
     }
@@ -1995,8 +2081,8 @@
         return mWifiOnTimer.getTotalTimeLocked(batteryRealtime, which);
     }
     
-    @Override public long getWifiRunningTime(long batteryRealtime, int which) {
-        return mWifiRunningTimer.getTotalTimeLocked(batteryRealtime, which);
+    @Override public long getGlobalWifiRunningTime(long batteryRealtime, int which) {
+        return mGlobalWifiRunningTimer.getTotalTimeLocked(batteryRealtime, which);
     }
 
     @Override public long getBluetoothOnTime(long batteryRealtime, int which) {
@@ -2029,8 +2115,8 @@
         long mStartedTcpBytesReceived = -1;
         long mStartedTcpBytesSent = -1;
         
-        boolean mWifiTurnedOn;
-        StopwatchTimer mWifiTurnedOnTimer;
+        boolean mWifiRunning;
+        StopwatchTimer mWifiRunningTimer;
         
         boolean mFullWifiLockOut;
         StopwatchTimer mFullWifiLockTimer;
@@ -2076,14 +2162,14 @@
 
         public Uid(int uid) {
             mUid = uid;
-            mWifiTurnedOnTimer = new StopwatchTimer(Uid.this, WIFI_TURNED_ON,
-                    null, mUnpluggables);
+            mWifiRunningTimer = new StopwatchTimer(Uid.this, WIFI_RUNNING,
+                    mWifiRunningTimers, mUnpluggables);
             mFullWifiLockTimer = new StopwatchTimer(Uid.this, FULL_WIFI_LOCK,
-                    null, mUnpluggables);
+                    mFullWifiLockTimers, mUnpluggables);
             mScanWifiLockTimer = new StopwatchTimer(Uid.this, SCAN_WIFI_LOCK,
-                    null, mUnpluggables);
+                    mScanWifiLockTimers, mUnpluggables);
             mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
-                    null, mUnpluggables);
+                    mWifiMulticastTimers, mUnpluggables);
             mAudioTurnedOnTimer = new StopwatchTimer(Uid.this, AUDIO_TURNED_ON,
                     null, mUnpluggables);
             mVideoTurnedOnTimer = new StopwatchTimer(Uid.this, VIDEO_TURNED_ON,
@@ -2151,22 +2237,22 @@
         }
         
         @Override
-        public void noteWifiTurnedOnLocked() {
-            if (!mWifiTurnedOn) {
-                mWifiTurnedOn = true;
-                if (mWifiTurnedOnTimer == null) {
-                    mWifiTurnedOnTimer = new StopwatchTimer(Uid.this, WIFI_TURNED_ON,
-                            null, mUnpluggables);
+        public void noteWifiRunningLocked() {
+            if (!mWifiRunning) {
+                mWifiRunning = true;
+                if (mWifiRunningTimer == null) {
+                    mWifiRunningTimer = new StopwatchTimer(Uid.this, WIFI_RUNNING,
+                            mWifiRunningTimers, mUnpluggables);
                 }
-                mWifiTurnedOnTimer.startRunningLocked(BatteryStatsImpl.this);
+                mWifiRunningTimer.startRunningLocked(BatteryStatsImpl.this);
             }
         }
         
         @Override
-        public void noteWifiTurnedOffLocked() {
-            if (mWifiTurnedOn) {
-                mWifiTurnedOn = false;
-                mWifiTurnedOnTimer.stopRunningLocked(BatteryStatsImpl.this);
+        public void noteWifiStoppedLocked() {
+            if (mWifiRunning) {
+                mWifiRunning = false;
+                mWifiRunningTimer.stopRunningLocked(BatteryStatsImpl.this);
             }
         }
         
@@ -2176,7 +2262,7 @@
                 mFullWifiLockOut = true;
                 if (mFullWifiLockTimer == null) {
                     mFullWifiLockTimer = new StopwatchTimer(Uid.this, FULL_WIFI_LOCK,
-                            null, mUnpluggables);
+                            mFullWifiLockTimers, mUnpluggables);
                 }
                 mFullWifiLockTimer.startRunningLocked(BatteryStatsImpl.this);
             }
@@ -2196,7 +2282,7 @@
                 mScanWifiLockOut = true;
                 if (mScanWifiLockTimer == null) {
                     mScanWifiLockTimer = new StopwatchTimer(Uid.this, SCAN_WIFI_LOCK,
-                            null, mUnpluggables);
+                            mScanWifiLockTimers, mUnpluggables);
                 }
                 mScanWifiLockTimer.startRunningLocked(BatteryStatsImpl.this);
             }
@@ -2216,7 +2302,7 @@
                 mWifiMulticastEnabled = true;
                 if (mWifiMulticastTimer == null) {
                     mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
-                            null, mUnpluggables);
+                            mWifiMulticastTimers, mUnpluggables);
                 }
                 mWifiMulticastTimer.startRunningLocked(BatteryStatsImpl.this);
             }
@@ -2271,11 +2357,11 @@
         }
 
         @Override 
-        public long getWifiTurnedOnTime(long batteryRealtime, int which) {
-            if (mWifiTurnedOnTimer == null) {
+        public long getWifiRunningTime(long batteryRealtime, int which) {
+            if (mWifiRunningTimer == null) {
                 return 0;
             }
-            return mWifiTurnedOnTimer.getTotalTimeLocked(batteryRealtime, which);
+            return mWifiRunningTimer.getTotalTimeLocked(batteryRealtime, which);
         }
 
         @Override 
@@ -2361,9 +2447,9 @@
         boolean reset() {
             boolean active = false;
             
-            if (mWifiTurnedOnTimer != null) {
-                active |= !mWifiTurnedOnTimer.reset(BatteryStatsImpl.this, false);
-                active |= mWifiTurnedOn;
+            if (mWifiRunningTimer != null) {
+                active |= !mWifiRunningTimer.reset(BatteryStatsImpl.this, false);
+                active |= mWifiRunning;
             }
             if (mFullWifiLockTimer != null) {
                 active |= !mFullWifiLockTimer.reset(BatteryStatsImpl.this, false);
@@ -2456,8 +2542,8 @@
             mPids.clear();
 
             if (!active) {
-                if (mWifiTurnedOnTimer != null) {
-                    mWifiTurnedOnTimer.detach();
+                if (mWifiRunningTimer != null) {
+                    mWifiRunningTimer.detach();
                 }
                 if (mFullWifiLockTimer != null) {
                     mFullWifiLockTimer.detach();
@@ -2519,9 +2605,9 @@
             out.writeLong(computeCurrentTcpBytesSent());
             out.writeLong(mTcpBytesReceivedAtLastUnplug);
             out.writeLong(mTcpBytesSentAtLastUnplug);
-            if (mWifiTurnedOnTimer != null) {
+            if (mWifiRunningTimer != null) {
                 out.writeInt(1);
-                mWifiTurnedOnTimer.writeToParcel(out, batteryRealtime);
+                mWifiRunningTimer.writeToParcel(out, batteryRealtime);
             } else {
                 out.writeInt(0);
             }
@@ -2613,31 +2699,31 @@
             mCurrentTcpBytesSent = in.readLong();
             mTcpBytesReceivedAtLastUnplug = in.readLong();
             mTcpBytesSentAtLastUnplug = in.readLong();
-            mWifiTurnedOn = false;
+            mWifiRunning = false;
             if (in.readInt() != 0) {
-                mWifiTurnedOnTimer = new StopwatchTimer(Uid.this, WIFI_TURNED_ON,
-                        null, mUnpluggables, in);
+                mWifiRunningTimer = new StopwatchTimer(Uid.this, WIFI_RUNNING,
+                        mWifiRunningTimers, mUnpluggables, in);
             } else {
-                mWifiTurnedOnTimer = null;
+                mWifiRunningTimer = null;
             }
             mFullWifiLockOut = false;
             if (in.readInt() != 0) {
                 mFullWifiLockTimer = new StopwatchTimer(Uid.this, FULL_WIFI_LOCK,
-                        null, mUnpluggables, in);
+                        mFullWifiLockTimers, mUnpluggables, in);
             } else {
                 mFullWifiLockTimer = null;
             }
             mScanWifiLockOut = false;
             if (in.readInt() != 0) {
                 mScanWifiLockTimer = new StopwatchTimer(Uid.this, SCAN_WIFI_LOCK,
-                        null, mUnpluggables, in);
+                        mScanWifiLockTimers, mUnpluggables, in);
             } else {
                 mScanWifiLockTimer = null;
             }
             mWifiMulticastEnabled = false;
             if (in.readInt() != 0) {
                 mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
-                        null, mUnpluggables, in);
+                        mWifiMulticastTimers, mUnpluggables, in);
             } else {
                 mWifiMulticastTimer = null;
             }
@@ -3710,7 +3796,7 @@
             mPhoneDataConnectionsTimer[i] = new StopwatchTimer(null, -300-i, null, mUnpluggables);
         }
         mWifiOnTimer = new StopwatchTimer(null, -3, null, mUnpluggables);
-        mWifiRunningTimer = new StopwatchTimer(null, -4, null, mUnpluggables);
+        mGlobalWifiRunningTimer = new StopwatchTimer(null, -4, null, mUnpluggables);
         mBluetoothOnTimer = new StopwatchTimer(null, -5, null, mUnpluggables);
         mAudioOnTimer = new StopwatchTimer(null, -6, null, mUnpluggables);
         mVideoOnTimer = new StopwatchTimer(null, -7, null, mUnpluggables);
@@ -3749,6 +3835,22 @@
         }
     }
 
+    private HistoryItem mHistoryIterator;
+
+    public boolean startIteratingHistoryLocked() {
+        return (mHistoryIterator = mHistory) != null;
+    }
+
+    public boolean getNextHistoryLocked(HistoryItem out) {
+        HistoryItem cur = mHistoryIterator;
+        if (cur == null) {
+            return false;
+        }
+        out.setTo(cur);
+        mHistoryIterator = cur.next;
+        return true;
+    }
+
     @Override
     public HistoryItem getHistory() {
         return mHistory;
@@ -3800,7 +3902,7 @@
             mPhoneDataConnectionsTimer[i].reset(this, false);
         }
         mWifiOnTimer.reset(this, false);
-        mWifiRunningTimer.reset(this, false);
+        mGlobalWifiRunningTimer.reset(this, false);
         mBluetoothOnTimer.reset(this, false);
         
         for (int i=0; i<mUidStats.size(); i++) {
@@ -3875,7 +3977,7 @@
             }
             if (doWrite || (mLastWriteTime + (60 * 1000)) < mSecRealtime) {
                 if (mFile != null) {
-                    writeLocked();
+                    writeAsyncLocked();
                 }
             }
         }
@@ -4219,12 +4321,74 @@
         return u.getServiceStatsLocked(pkg, name);
     }
 
+    /**
+     * Massage data to distribute any reasonable work down to more specific
+     * owners.  Must only be called on a dead BatteryStats object!
+     */
+    public void distributeWorkLocked(int which) {
+        // Aggregate all CPU time associated with WIFI.
+        Uid wifiUid = mUidStats.get(Process.WIFI_UID);
+        if (wifiUid != null) {
+            long uSecTime = computeBatteryRealtime(SystemClock.elapsedRealtime() * 1000, which);
+            for (Uid.Proc proc : wifiUid.mProcessStats.values()) {
+                long totalRunningTime = getGlobalWifiRunningTime(uSecTime, which);
+                for (int i=0; i<mUidStats.size(); i++) {
+                    Uid uid = mUidStats.valueAt(i);
+                    if (uid.mUid != Process.WIFI_UID) {
+                        long uidRunningTime = uid.getWifiRunningTime(uSecTime, which);
+                        if (uidRunningTime > 0) {
+                            Uid.Proc uidProc = uid.getProcessStatsLocked("*wifi*");
+                            long time = proc.getUserTime(which);
+                            time = (time*uidRunningTime)/totalRunningTime;
+                            uidProc.mUserTime += time;
+                            proc.mUserTime -= time;
+                            time = proc.getSystemTime(which);
+                            time = (time*uidRunningTime)/totalRunningTime;
+                            uidProc.mSystemTime += time;
+                            proc.mSystemTime -= time;
+                            time = proc.getForegroundTime(which);
+                            time = (time*uidRunningTime)/totalRunningTime;
+                            uidProc.mForegroundTime += time;
+                            proc.mForegroundTime -= time;
+                            for (int sb=0; sb<proc.mSpeedBins.length; sb++) {
+                                SamplingCounter sc = proc.mSpeedBins[sb];
+                                if (sc != null) {
+                                    time = sc.getCountLocked(which);
+                                    time = (time*uidRunningTime)/totalRunningTime;
+                                    SamplingCounter uidSc = uidProc.mSpeedBins[sb];
+                                    if (uidSc == null) {
+                                        uidSc = new SamplingCounter(mUnpluggables);
+                                        uidProc.mSpeedBins[sb] = uidSc;
+                                    }
+                                    uidSc.mCount.addAndGet((int)time);
+                                    sc.mCount.addAndGet((int)-time);
+                                }
+                            }
+                            totalRunningTime -= uidRunningTime;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
     public void shutdownLocked() {
-        writeLocked();
+        writeSyncLocked();
         mShuttingDown = true;
     }
     
-    public void writeLocked() {
+    Parcel mPendingWrite = null;
+    final ReentrantLock mWriteLock = new ReentrantLock();
+
+    public void writeAsyncLocked() {
+        writeLocked(false);
+    }
+
+    public void writeSyncLocked() {
+        writeLocked(true);
+    }
+
+    void writeLocked(boolean sync) {
         if (mFile == null) {
             Slog.w("BatteryStats", "writeLocked: no file associated with this instance");
             return;
@@ -4234,23 +4398,51 @@
             return;
         }
         
+        Parcel out = Parcel.obtain();
+        writeSummaryToParcel(out);
+        mLastWriteTime = SystemClock.elapsedRealtime();
+
+        if (mPendingWrite != null) {
+            mPendingWrite.recycle();
+        }
+        mPendingWrite = out;
+
+        if (sync) {
+            commitPendingDataToDisk();
+        } else {
+            Thread thr = new Thread("BatteryStats-Write") {
+                @Override
+                public void run() {
+                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+                    commitPendingDataToDisk();
+                }
+            };
+            thr.start();
+        }
+    }
+
+    public void commitPendingDataToDisk() {
+        Parcel next;
+        synchronized (this) {
+            next = mPendingWrite;
+            mPendingWrite = null;
+
+            mWriteLock.lock();
+        }
+
         try {
             FileOutputStream stream = new FileOutputStream(mFile.chooseForWrite());
-            Parcel out = Parcel.obtain();
-            writeSummaryToParcel(out);
-            stream.write(out.marshall());
-            out.recycle();
-
+            stream.write(next.marshall());
             stream.flush();
             stream.close();
             mFile.commit();
-
-            mLastWriteTime = SystemClock.elapsedRealtime();
-            return;
         } catch (IOException e) {
             Slog.w("BatteryStats", "Error writing battery statistics", e);
+            mFile.rollback();
+        } finally {
+            next.recycle();
+            mWriteLock.unlock();
         }
-        mFile.rollback();
     }
 
     static byte[] readFully(FileInputStream stream) throws java.io.IOException {
@@ -4381,8 +4573,8 @@
         }
         mWifiOn = false;
         mWifiOnTimer.readSummaryFromParcelLocked(in);
-        mWifiRunning = false;
-        mWifiRunningTimer.readSummaryFromParcelLocked(in);
+        mGlobalWifiRunning = false;
+        mGlobalWifiRunningTimer.readSummaryFromParcelLocked(in);
         mBluetoothOn = false;
         mBluetoothOnTimer.readSummaryFromParcelLocked(in);
 
@@ -4410,9 +4602,9 @@
             Uid u = new Uid(uid);
             mUidStats.put(uid, u);
 
-            u.mWifiTurnedOn = false;
+            u.mWifiRunning = false;
             if (in.readInt() != 0) {
-                u.mWifiTurnedOnTimer.readSummaryFromParcelLocked(in);
+                u.mWifiRunningTimer.readSummaryFromParcelLocked(in);
             }
             u.mFullWifiLockOut = false;
             if (in.readInt() != 0) {
@@ -4486,6 +4678,14 @@
                 p.mUserTime = p.mLoadedUserTime = in.readLong();
                 p.mSystemTime = p.mLoadedSystemTime = in.readLong();
                 p.mStarts = p.mLoadedStarts = in.readInt();
+                int NSB = in.readInt();
+                p.mSpeedBins = new SamplingCounter[NSB];
+                for (int i=0; i<NSB; i++) {
+                    if (in.readInt() != 0) {
+                        p.mSpeedBins[i] = new SamplingCounter(mUnpluggables);
+                        p.mSpeedBins[i].readSummaryFromParcelLocked(in);
+                    }
+                }
                 p.readExcessiveWakeFromParcelLocked(in);
             }
 
@@ -4553,7 +4753,7 @@
             mPhoneDataConnectionsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
         }
         mWifiOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
-        mWifiRunningTimer.writeSummaryFromParcelLocked(out, NOWREAL);
+        mGlobalWifiRunningTimer.writeSummaryFromParcelLocked(out, NOWREAL);
         mBluetoothOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
 
         out.writeInt(mKernelWakelockStats.size());
@@ -4575,9 +4775,9 @@
             out.writeInt(mUidStats.keyAt(iu));
             Uid u = mUidStats.valueAt(iu);
             
-            if (u.mWifiTurnedOnTimer != null) {
+            if (u.mWifiRunningTimer != null) {
                 out.writeInt(1);
-                u.mWifiTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
+                u.mWifiRunningTimer.writeSummaryFromParcelLocked(out, NOWREAL);
             } else {
                 out.writeInt(0);
             }
@@ -4675,6 +4875,16 @@
                     out.writeLong(ps.mUserTime);
                     out.writeLong(ps.mSystemTime);
                     out.writeInt(ps.mStarts);
+                    final int N = ps.mSpeedBins.length;
+                    out.writeInt(N);
+                    for (int i=0; i<N; i++) {
+                        if (ps.mSpeedBins[i] != null) {
+                            out.writeInt(1);
+                            ps.mSpeedBins[i].writeSummaryFromParcelLocked(out);
+                        } else {
+                            out.writeInt(0);
+                        }
+                    }
                     ps.writeExcessiveWakeToParcelLocked(out);
                 }
             }
@@ -4745,8 +4955,8 @@
         }
         mWifiOn = false;
         mWifiOnTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in);
-        mWifiRunning = false;
-        mWifiRunningTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in);
+        mGlobalWifiRunning = false;
+        mGlobalWifiRunningTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in);
         mBluetoothOn = false;
         mBluetoothOnTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in);
         mUptime = in.readLong();
@@ -4798,6 +5008,10 @@
         mPartialTimers.clear();
         mFullTimers.clear();
         mWindowTimers.clear();
+        mWifiRunningTimers.clear();
+        mFullWifiLockTimers.clear();
+        mScanWifiLockTimers.clear();
+        mWifiMulticastTimers.clear();
 
         sNumSpeedSteps = in.readInt();
 
@@ -4847,7 +5061,7 @@
             mPhoneDataConnectionsTimer[i].writeToParcel(out, batteryRealtime);
         }
         mWifiOnTimer.writeToParcel(out, batteryRealtime);
-        mWifiRunningTimer.writeToParcel(out, batteryRealtime);
+        mGlobalWifiRunningTimer.writeToParcel(out, batteryRealtime);
         mBluetoothOnTimer.writeToParcel(out, batteryRealtime);
         out.writeLong(mUptime);
         out.writeLong(mUptimeStart);
@@ -4945,7 +5159,7 @@
             pr.println("*** Wifi timer:");
             mWifiOnTimer.logState(pr, "  ");
             pr.println("*** WifiRunning timer:");
-            mWifiRunningTimer.logState(pr, "  ");
+            mGlobalWifiRunningTimer.logState(pr, "  ");
             pr.println("*** Bluetooth timer:");
             mBluetoothOnTimer.logState(pr, "  ");
         }
diff --git a/core/java/com/android/internal/util/HierarchicalStateMachine.java b/core/java/com/android/internal/util/HierarchicalStateMachine.java
index c599d68..f789301 100644
--- a/core/java/com/android/internal/util/HierarchicalStateMachine.java
+++ b/core/java/com/android/internal/util/HierarchicalStateMachine.java
@@ -137,7 +137,7 @@
     }
 
     class State1 extends HierarchicalState {
-        @Override public boolean processMessage(Message message) {
+        &#64;Override public boolean processMessage(Message message) {
             Log.d(TAG, "Hello World");
             return HANDLED;
         }
@@ -257,10 +257,10 @@
     }
 
     class P1 extends HierarchicalState {
-        @Override public void enter() {
+        &#64;Override public void enter() {
             Log.d(TAG, "mP1.enter");
         }
-        @Override public boolean processMessage(Message message) {
+        &#64;Override public boolean processMessage(Message message) {
             boolean retVal;
             Log.d(TAG, "mP1.processMessage what=" + message.what);
             switch(message.what) {
@@ -278,16 +278,16 @@
             }
             return retVal;
         }
-        @Override public void exit() {
+        &#64;Override public void exit() {
             Log.d(TAG, "mP1.exit");
         }
     }
 
     class S1 extends HierarchicalState {
-        @Override public void enter() {
+        &#64;Override public void enter() {
             Log.d(TAG, "mS1.enter");
         }
-        @Override public boolean processMessage(Message message) {
+        &#64;Override public boolean processMessage(Message message) {
             Log.d(TAG, "S1.processMessage what=" + message.what);
             if (message.what == CMD_1) {
                 // Transition to ourself to show that enter/exit is called
@@ -298,16 +298,16 @@
                 return NOT_HANDLED;
             }
         }
-        @Override public void exit() {
+        &#64;Override public void exit() {
             Log.d(TAG, "mS1.exit");
         }
     }
 
     class S2 extends HierarchicalState {
-        @Override public void enter() {
+        &#64;Override public void enter() {
             Log.d(TAG, "mS2.enter");
         }
-        @Override public boolean processMessage(Message message) {
+        &#64;Override public boolean processMessage(Message message) {
             boolean retVal;
             Log.d(TAG, "mS2.processMessage what=" + message.what);
             switch(message.what) {
@@ -326,17 +326,17 @@
             }
             return retVal;
         }
-        @Override public void exit() {
+        &#64;Override public void exit() {
             Log.d(TAG, "mS2.exit");
         }
     }
 
     class P2 extends HierarchicalState {
-        @Override public void enter() {
+        &#64;Override public void enter() {
             Log.d(TAG, "mP2.enter");
             sendMessage(obtainMessage(CMD_5));
         }
-        @Override public boolean processMessage(Message message) {
+        &#64;Override public boolean processMessage(Message message) {
             Log.d(TAG, "P2.processMessage what=" + message.what);
             switch(message.what) {
             case(CMD_3):
@@ -349,12 +349,12 @@
             }
             return HANDLED;
         }
-        @Override public void exit() {
+        &#64;Override public void exit() {
             Log.d(TAG, "mP2.exit");
         }
     }
 
-    @Override
+    &#64;Override
     void halting() {
         Log.d(TAG, "halting");
         synchronized (this) {
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 2751a82..17ab46c 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -703,42 +703,6 @@
         }
     }
 
-    /* enable poisoning of memory of freed objects */
-    property_get("dalvik.vm.gc.overwritefree", propBuf, "false");
-    if (strcmp(propBuf, "true") == 0) {
-        opt.optionString = "-Xgc:overwritefree";
-        mOptions.add(opt);
-    } else if (strcmp(propBuf, "false") != 0) {
-        LOGW("dalvik.vm.gc.overwritefree should be 'true' or 'false'");
-    }
-
-    /* enable heap verification before each gc */
-    property_get("dalvik.vm.gc.preverify", propBuf, "false");
-    if (strcmp(propBuf, "true") == 0) {
-        opt.optionString = "-Xgc:preverify";
-        mOptions.add(opt);
-    } else if (strcmp(propBuf, "false") != 0) {
-        LOGW("dalvik.vm.gc.preverify should be 'true' or 'false'");
-    }
-
-    /* enable heap verification after each gc */
-    property_get("dalvik.vm.gc.postverify", propBuf, "false");
-    if (strcmp(propBuf, "true") == 0) {
-        opt.optionString = "-Xgc:postverify";
-        mOptions.add(opt);
-    } else if (strcmp(propBuf, "false") != 0) {
-        LOGW("dalvik.vm.gc.postverify should be 'true' or 'false'");
-    }
-
-    /* enable card table verification for partial gc */
-    property_get("dalvik.vm.gc.verifycardtable", propBuf, "false");
-    if (strcmp(propBuf, "true") == 0) {
-        opt.optionString = "-Xgc:verifycardtable";
-        mOptions.add(opt);
-    } else if (strcmp(propBuf, "false") != 0) {
-        LOGW("dalvik.vm.gc.verifycardtable should be 'true' or 'false'");
-    }
-
     /* enable debugging; set suspend=y to pause during VM init */
 #ifdef HAVE_ANDROID_OS
     /* use android ADB transport */
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index 2517a8a..6aa77f6 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -28,7 +28,7 @@
 #include <surfaceflinger/Surface.h>
 #include <ui/egl/android_natives.h>
 #include <ui/InputTransport.h>
-#include <utils/PollLoop.h>
+#include <utils/Looper.h>
 
 #include "JNIHelp.h"
 #include "android_os_MessageQueue.h"
@@ -128,17 +128,17 @@
 }
 
 void AInputQueue::attachLooper(ALooper* looper, int ident,
-        ALooper_callbackFunc* callback, void* data) {
-    mPollLoop = static_cast<android::PollLoop*>(looper);
-    mPollLoop->setLooperCallback(mConsumer.getChannel()->getReceivePipeFd(),
-            ident, POLLIN, callback, data);
-    mPollLoop->setLooperCallback(mDispatchKeyRead,
-            ident, POLLIN, callback, data);
+        ALooper_callbackFunc callback, void* data) {
+    mLooper = static_cast<android::Looper*>(looper);
+    mLooper->addFd(mConsumer.getChannel()->getReceivePipeFd(),
+            ident, ALOOPER_EVENT_INPUT, callback, data);
+    mLooper->addFd(mDispatchKeyRead,
+            ident, ALOOPER_EVENT_INPUT, callback, data);
 }
 
 void AInputQueue::detachLooper() {
-    mPollLoop->removeCallback(mConsumer.getChannel()->getReceivePipeFd());
-    mPollLoop->removeCallback(mDispatchKeyRead);
+    mLooper->removeFd(mConsumer.getChannel()->getReceivePipeFd());
+    mLooper->removeFd(mDispatchKeyRead);
 }
 
 int32_t AInputQueue::hasEvents() {
@@ -440,8 +440,8 @@
         if (env != NULL && clazz != NULL) {
             env->DeleteGlobalRef(clazz);
         }
-        if (pollLoop != NULL && mainWorkRead >= 0) {
-            pollLoop->removeCallback(mainWorkRead);
+        if (looper != NULL && mainWorkRead >= 0) {
+            looper->removeFd(mainWorkRead);
         }
         if (nativeInputQueue != NULL) {
             nativeInputQueue->mWorkWrite = -1;
@@ -509,7 +509,7 @@
     // These are used to wake up the main thread to process work.
     int mainWorkRead;
     int mainWorkWrite;
-    sp<PollLoop> pollLoop;
+    sp<Looper> looper;
 };
 
 void android_NativeActivity_setWindowFormat(
@@ -541,15 +541,15 @@
 /*
  * Callback for handling native events on the application's main thread.
  */
-static bool mainWorkCallback(int fd, int events, void* data) {
+static int mainWorkCallback(int fd, int events, void* data) {
     NativeCode* code = (NativeCode*)data;
     if ((events & POLLIN) == 0) {
-        return true;
+        return 1;
     }
     
     ActivityWork work;
     if (!read_work(code->mainWorkRead, &work)) {
-        return true;
+        return 1;
     }
 
     LOG_TRACE("mainWorkCallback: cmd=%d", work.cmd);
@@ -593,7 +593,7 @@
             break;
     }
     
-    return true;
+    return 1;
 }
 
 // ------------------------------------------------------------------------
@@ -621,9 +621,9 @@
             return 0;
         }
         
-        code->pollLoop = android_os_MessageQueue_getPollLoop(env, messageQueue);
-        if (code->pollLoop == NULL) {
-            LOGW("Unable to retrieve MessageQueue's PollLoop");
+        code->looper = android_os_MessageQueue_getLooper(env, messageQueue);
+        if (code->looper == NULL) {
+            LOGW("Unable to retrieve MessageQueue's Looper");
             delete code;
             return 0;
         }
@@ -642,7 +642,7 @@
         result = fcntl(code->mainWorkWrite, F_SETFL, O_NONBLOCK);
         SLOGW_IF(result != 0, "Could not make main work write pipe "
                 "non-blocking: %s", strerror(errno));
-        code->pollLoop->setCallback(code->mainWorkRead, POLLIN, mainWorkCallback, code);
+        code->looper->addFd(code->mainWorkRead, 0, ALOOPER_EVENT_INPUT, mainWorkCallback, code);
         
         code->ANativeActivity::callbacks = &code->callbacks;
         if (env->GetJavaVM(&code->vm) < 0) {
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index c784974..10fe583 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -688,8 +688,8 @@
     field fields_to_find[] = {
         { "android/hardware/Camera", "mNativeContext",   "I", &fields.context },
         { "android/view/Surface",    ANDROID_VIEW_SURFACE_JNI_ID, "I", &fields.surface },
-        { "android/hardware/Camera$CameraInfo", "mFacing",   "I", &fields.facing },
-        { "android/hardware/Camera$CameraInfo", "mOrientation",   "I", &fields.orientation },
+        { "android/hardware/Camera$CameraInfo", "facing",   "I", &fields.facing },
+        { "android/hardware/Camera$CameraInfo", "orientation",   "I", &fields.orientation },
     };
 
     if (find_fields(env, fields_to_find, NELEM(fields_to_find)) < 0)
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index e29495c..10ceb7b 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -60,7 +60,7 @@
 
     Sensor const* const* sensorList;
     size_t count = mgr.getSensorList(&sensorList);
-    if (next >= count)
+    if (size_t(next) >= count)
         return -1;
     
     Sensor const* const list = sensorList[next];
@@ -78,7 +78,7 @@
     env->SetIntField(sensor, sensorOffsets.minDelay,     list->getMinDelay());
     
     next++;
-    return next<count ? next : 0;
+    return size_t(next) < count ? next : 0;
 }
 
 //----------------------------------------------------------------------------
diff --git a/core/jni/android_os_MessageQueue.cpp b/core/jni/android_os_MessageQueue.cpp
index 847b5a5..1b203ca 100644
--- a/core/jni/android_os_MessageQueue.cpp
+++ b/core/jni/android_os_MessageQueue.cpp
@@ -18,7 +18,7 @@
 
 #include "JNIHelp.h"
 
-#include <utils/PollLoop.h>
+#include <utils/Looper.h>
 #include <utils/Log.h>
 #include "android_os_MessageQueue.h"
 
@@ -39,22 +39,22 @@
     NativeMessageQueue();
     ~NativeMessageQueue();
 
-    inline sp<PollLoop> getPollLoop() { return mPollLoop; }
+    inline sp<Looper> getLooper() { return mLooper; }
 
     bool pollOnce(int timeoutMillis);
     void wake();
 
 private:
-    sp<PollLoop> mPollLoop;
+    sp<Looper> mLooper;
 };
 
 // ----------------------------------------------------------------------------
 
 NativeMessageQueue::NativeMessageQueue() {
-    mPollLoop = PollLoop::getForThread();
-    if (mPollLoop == NULL) {
-        mPollLoop = new PollLoop(false);
-        PollLoop::setForThread(mPollLoop);
+    mLooper = Looper::getForThread();
+    if (mLooper == NULL) {
+        mLooper = new Looper(false);
+        Looper::setForThread(mLooper);
     }
 }
 
@@ -62,11 +62,11 @@
 }
 
 bool NativeMessageQueue::pollOnce(int timeoutMillis) {
-    return mPollLoop->pollOnce(timeoutMillis) != PollLoop::POLL_TIMEOUT;
+    return mLooper->pollOnce(timeoutMillis) != ALOOPER_POLL_TIMEOUT;
 }
 
 void NativeMessageQueue::wake() {
-    mPollLoop->wake();
+    mLooper->wake();
 }
 
 // ----------------------------------------------------------------------------
@@ -83,10 +83,10 @@
              reinterpret_cast<jint>(nativeMessageQueue));
 }
 
-sp<PollLoop> android_os_MessageQueue_getPollLoop(JNIEnv* env, jobject messageQueueObj) {
+sp<Looper> android_os_MessageQueue_getLooper(JNIEnv* env, jobject messageQueueObj) {
     NativeMessageQueue* nativeMessageQueue =
             android_os_MessageQueue_getNativeMessageQueue(env, messageQueueObj);
-    return nativeMessageQueue != NULL ? nativeMessageQueue->getPollLoop() : NULL;
+    return nativeMessageQueue != NULL ? nativeMessageQueue->getLooper() : NULL;
 }
 
 static void android_os_MessageQueue_nativeInit(JNIEnv* env, jobject obj) {
diff --git a/core/jni/android_os_MessageQueue.h b/core/jni/android_os_MessageQueue.h
index 5c742e2..f961d8f 100644
--- a/core/jni/android_os_MessageQueue.h
+++ b/core/jni/android_os_MessageQueue.h
@@ -21,9 +21,9 @@
 
 namespace android {
 
-class PollLoop;
+class Looper;
 
-extern sp<PollLoop> android_os_MessageQueue_getPollLoop(JNIEnv* env, jobject messageQueueObj);
+extern sp<Looper> android_os_MessageQueue_getLooper(JNIEnv* env, jobject messageQueueObj);
 
 } // namespace android
 
diff --git a/core/jni/android_view_InputQueue.cpp b/core/jni/android_view_InputQueue.cpp
index 42f35d1..282e9ed 100644
--- a/core/jni/android_view_InputQueue.cpp
+++ b/core/jni/android_view_InputQueue.cpp
@@ -29,7 +29,7 @@
 
 #include <android_runtime/AndroidRuntime.h>
 #include <utils/Log.h>
-#include <utils/PollLoop.h>
+#include <utils/Looper.h>
 #include <utils/KeyedVector.h>
 #include <utils/threads.h>
 #include <ui/InputTransport.h>
@@ -77,7 +77,7 @@
         };
 
         Connection(uint16_t id,
-                const sp<InputChannel>& inputChannel, const sp<PollLoop>& pollLoop);
+                const sp<InputChannel>& inputChannel, const sp<Looper>& looper);
 
         inline const char* getInputChannelName() const { return inputChannel->getName().string(); }
 
@@ -88,7 +88,7 @@
 
         sp<InputChannel> inputChannel;
         InputConsumer inputConsumer;
-        sp<PollLoop> pollLoop;
+        sp<Looper> looper;
         jobject inputHandlerObjGlobal;
         PreallocatedInputEventFactory inputEventFactory;
 
@@ -110,7 +110,7 @@
     static void handleInputChannelDisposed(JNIEnv* env,
             jobject inputChannelObj, const sp<InputChannel>& inputChannel, void* data);
 
-    static bool handleReceiveCallback(int receiveFd, int events, void* data);
+    static int handleReceiveCallback(int receiveFd, int events, void* data);
 
     static jlong generateFinishedToken(int32_t receiveFd,
             uint16_t connectionId, uint16_t messageSeqNum);
@@ -141,7 +141,7 @@
     LOGD("channel '%s' - Registered", inputChannel->getName().string());
 #endif
 
-    sp<PollLoop> pollLoop = android_os_MessageQueue_getPollLoop(env, messageQueueObj);
+    sp<Looper> looper = android_os_MessageQueue_getLooper(env, messageQueueObj);
 
     { // acquire lock
         AutoMutex _l(mLock);
@@ -153,7 +153,7 @@
         }
 
         uint16_t connectionId = mNextConnectionId++;
-        sp<Connection> connection = new Connection(connectionId, inputChannel, pollLoop);
+        sp<Connection> connection = new Connection(connectionId, inputChannel, looper);
         status_t result = connection->inputConsumer.initialize();
         if (result) {
             LOGW("Failed to initialize input consumer for input channel '%s', status=%d",
@@ -166,7 +166,7 @@
         int32_t receiveFd = inputChannel->getReceivePipeFd();
         mConnectionsByReceiveFd.add(receiveFd, connection);
 
-        pollLoop->setCallback(receiveFd, POLLIN, handleReceiveCallback, this);
+        looper->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
     } // release lock
 
     android_view_InputChannel_setDisposeCallback(env, inputChannelObj,
@@ -201,7 +201,7 @@
 
         connection->status = Connection::STATUS_ZOMBIE;
 
-        connection->pollLoop->removeCallback(inputChannel->getReceivePipeFd());
+        connection->looper->removeFd(inputChannel->getReceivePipeFd());
 
         env->DeleteGlobalRef(connection->inputHandlerObjGlobal);
         connection->inputHandlerObjGlobal = NULL;
@@ -293,7 +293,7 @@
     q->unregisterInputChannel(env, inputChannelObj);
 }
 
-bool NativeInputQueue::handleReceiveCallback(int receiveFd, int events, void* data) {
+int NativeInputQueue::handleReceiveCallback(int receiveFd, int events, void* data) {
     NativeInputQueue* q = static_cast<NativeInputQueue*>(data);
     JNIEnv* env = AndroidRuntime::getJNIEnv();
 
@@ -308,33 +308,33 @@
         if (connectionIndex < 0) {
             LOGE("Received spurious receive callback for unknown input channel.  "
                     "fd=%d, events=0x%x", receiveFd, events);
-            return false; // remove the callback
+            return 0; // remove the callback
         }
 
         connection = q->mConnectionsByReceiveFd.valueAt(connectionIndex);
-        if (events & (POLLERR | POLLHUP | POLLNVAL)) {
+        if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
             LOGE("channel '%s' ~ Publisher closed input channel or an error occurred.  "
                     "events=0x%x", connection->getInputChannelName(), events);
-            return false; // remove the callback
+            return 0; // remove the callback
         }
 
-        if (! (events & POLLIN)) {
+        if (! (events & ALOOPER_EVENT_INPUT)) {
             LOGW("channel '%s' ~ Received spurious callback for unhandled poll event.  "
                     "events=0x%x", connection->getInputChannelName(), events);
-            return true;
+            return 1;
         }
 
         status_t status = connection->inputConsumer.receiveDispatchSignal();
         if (status) {
             LOGE("channel '%s' ~ Failed to receive dispatch signal.  status=%d",
                     connection->getInputChannelName(), status);
-            return false; // remove the callback
+            return 0; // remove the callback
         }
 
         if (connection->messageInProgress) {
             LOGW("channel '%s' ~ Publisher sent spurious dispatch signal.",
                     connection->getInputChannelName());
-            return true;
+            return 1;
         }
 
         status = connection->inputConsumer.consume(& connection->inputEventFactory, & inputEvent);
@@ -342,7 +342,7 @@
             LOGW("channel '%s' ~ Failed to consume input event.  status=%d",
                     connection->getInputChannelName(), status);
             connection->inputConsumer.sendFinishedSignal();
-            return true;
+            return 1;
         }
 
         connection->messageInProgress = true;
@@ -394,7 +394,7 @@
                 connection->getInputChannelName());
         env->DeleteLocalRef(inputHandlerObjLocal);
         q->finished(env, finishedToken, false);
-        return true;
+        return 1;
     }
 
 #if DEBUG_DISPATCH_CYCLE
@@ -417,7 +417,7 @@
 
     env->DeleteLocalRef(inputEventObj);
     env->DeleteLocalRef(inputHandlerObjLocal);
-    return true;
+    return 1;
 }
 
 jlong NativeInputQueue::generateFinishedToken(int32_t receiveFd, uint16_t connectionId,
@@ -435,9 +435,9 @@
 // ----------------------------------------------------------------------------
 
 NativeInputQueue::Connection::Connection(uint16_t id,
-        const sp<InputChannel>& inputChannel, const sp<PollLoop>& pollLoop) :
+        const sp<InputChannel>& inputChannel, const sp<Looper>& looper) :
     id(id), status(STATUS_NORMAL), inputChannel(inputChannel), inputConsumer(inputChannel),
-    pollLoop(pollLoop), inputHandlerObjGlobal(NULL),
+    looper(looper), inputHandlerObjGlobal(NULL),
     messageSeqNum(0), messageInProgress(false) {
 }
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index a9e49713..ab0ff3f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -469,7 +469,7 @@
          Does not include placing calls. -->
     <permission android:name="android.permission.MODIFY_PHONE_STATE"
         android:permissionGroup="android.permission-group.PHONE_CALLS"
-        android:protectionLevel="dangerous"
+        android:protectionLevel="signatureOrSystem"
         android:label="@string/permlab_modifyPhoneState"
         android:description="@string/permdesc_modifyPhoneState" />
 
@@ -590,8 +590,8 @@
     <!-- Allows an application to retrieve state dump information from system
          services. -->
     <permission android:name="android.permission.DUMP"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="dangerous"
+        android:permissionGroup="android.permission-group.PERSONAL_INFO"
+        android:protectionLevel="signatureOrSystem"
         android:label="@string/permlab_dump"
         android:description="@string/permdesc_dump" />
 
@@ -840,11 +840,10 @@
         android:description="@string/permdesc_clearAppCache" />
 
     <!-- Allows an application to read the low-level system log files.
-         These can contain slightly private information about what is
-         happening on the device, but should never contain the user's
-         private information. -->
+         Log entries can contain the user's private information,
+         which is why this permission is 'dangerous'. -->
     <permission android:name="android.permission.READ_LOGS"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+        android:permissionGroup="android.permission-group.PERSONAL_INFO"
         android:protectionLevel="dangerous"
         android:label="@string/permlab_readLogs"
         android:description="@string/permdesc_readLogs" />
@@ -930,7 +929,7 @@
     <permission android:name="android.permission.UPDATE_DEVICE_STATS"
         android:label="@string/permlab_batteryStats"
         android:description="@string/permdesc_batteryStats"
-        android:protectionLevel="signature" />
+        android:protectionLevel="signatureOrSystem" />
 
     <!-- Allows an application to open windows that are for use by parts
          of the system user interface.  Not for use by third party apps. -->
diff --git a/core/res/res/drawable-hdpi/btn_check_off.png b/core/res/res/drawable-hdpi/btn_check_off.png
old mode 100644
new mode 100755
index aad9ef7..bb62e6f
--- a/core/res/res/drawable-hdpi/btn_check_off.png
+++ b/core/res/res/drawable-hdpi/btn_check_off.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_disable.png b/core/res/res/drawable-hdpi/btn_check_off_disable.png
old mode 100644
new mode 100755
index eaee9e0..b346381
--- a/core/res/res/drawable-hdpi/btn_check_off_disable.png
+++ b/core/res/res/drawable-hdpi/btn_check_off_disable.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_disable_focused.png b/core/res/res/drawable-hdpi/btn_check_off_disable_focused.png
old mode 100644
new mode 100755
index 6d2c293..8663369
--- a/core/res/res/drawable-hdpi/btn_check_off_disable_focused.png
+++ b/core/res/res/drawable-hdpi/btn_check_off_disable_focused.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_pressed.png b/core/res/res/drawable-hdpi/btn_check_off_pressed.png
old mode 100644
new mode 100755
index 1c442e9..67e49df
--- a/core/res/res/drawable-hdpi/btn_check_off_pressed.png
+++ b/core/res/res/drawable-hdpi/btn_check_off_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_selected.png b/core/res/res/drawable-hdpi/btn_check_off_selected.png
old mode 100644
new mode 100755
index b852b2c..1791d1f
--- a/core/res/res/drawable-hdpi/btn_check_off_selected.png
+++ b/core/res/res/drawable-hdpi/btn_check_off_selected.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on.png b/core/res/res/drawable-hdpi/btn_check_on.png
old mode 100644
new mode 100755
index cd5c181..15cd25e
--- a/core/res/res/drawable-hdpi/btn_check_on.png
+++ b/core/res/res/drawable-hdpi/btn_check_on.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_disable.png b/core/res/res/drawable-hdpi/btn_check_on_disable.png
old mode 100644
new mode 100755
index b4fc51a..e3fe323
--- a/core/res/res/drawable-hdpi/btn_check_on_disable.png
+++ b/core/res/res/drawable-hdpi/btn_check_on_disable.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_disable_focused.png b/core/res/res/drawable-hdpi/btn_check_on_disable_focused.png
old mode 100644
new mode 100755
index bf34647..fa41bb7
--- a/core/res/res/drawable-hdpi/btn_check_on_disable_focused.png
+++ b/core/res/res/drawable-hdpi/btn_check_on_disable_focused.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_pressed.png b/core/res/res/drawable-hdpi/btn_check_on_pressed.png
old mode 100644
new mode 100755
index fa5c7a2..906e283
--- a/core/res/res/drawable-hdpi/btn_check_on_pressed.png
+++ b/core/res/res/drawable-hdpi/btn_check_on_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_selected.png b/core/res/res/drawable-hdpi/btn_check_on_selected.png
old mode 100644
new mode 100755
index a6a21ad..eb496a8
--- a/core/res/res/drawable-hdpi/btn_check_on_selected.png
+++ b/core/res/res/drawable-hdpi/btn_check_on_selected.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_circle_disable.png b/core/res/res/drawable-hdpi/btn_circle_disable.png
old mode 100644
new mode 100755
index d829716..3f859cb
--- a/core/res/res/drawable-hdpi/btn_circle_disable.png
+++ b/core/res/res/drawable-hdpi/btn_circle_disable.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_circle_disable_focused.png b/core/res/res/drawable-hdpi/btn_circle_disable_focused.png
old mode 100644
new mode 100755
index c1b5b6e..66251b8
--- a/core/res/res/drawable-hdpi/btn_circle_disable_focused.png
+++ b/core/res/res/drawable-hdpi/btn_circle_disable_focused.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_circle_normal.png b/core/res/res/drawable-hdpi/btn_circle_normal.png
old mode 100644
new mode 100755
index bf3fb5a..6011219
--- a/core/res/res/drawable-hdpi/btn_circle_normal.png
+++ b/core/res/res/drawable-hdpi/btn_circle_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_circle_pressed.png b/core/res/res/drawable-hdpi/btn_circle_pressed.png
old mode 100644
new mode 100755
index 50e22e6..4942e50
--- a/core/res/res/drawable-hdpi/btn_circle_pressed.png
+++ b/core/res/res/drawable-hdpi/btn_circle_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_circle_selected.png b/core/res/res/drawable-hdpi/btn_circle_selected.png
old mode 100644
new mode 100755
index cfc68fb..fe49a40
--- a/core/res/res/drawable-hdpi/btn_circle_selected.png
+++ b/core/res/res/drawable-hdpi/btn_circle_selected.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_close_normal.png b/core/res/res/drawable-hdpi/btn_close_normal.png
old mode 100644
new mode 100755
index 38b49f1..47f11e5
--- a/core/res/res/drawable-hdpi/btn_close_normal.png
+++ b/core/res/res/drawable-hdpi/btn_close_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_close_pressed.png b/core/res/res/drawable-hdpi/btn_close_pressed.png
old mode 100644
new mode 100755
index aa9ea49f0..5b96b4e
--- a/core/res/res/drawable-hdpi/btn_close_pressed.png
+++ b/core/res/res/drawable-hdpi/btn_close_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_close_selected.png b/core/res/res/drawable-hdpi/btn_close_selected.png
old mode 100644
new mode 100755
index 870c670..e27d684
--- a/core/res/res/drawable-hdpi/btn_close_selected.png
+++ b/core/res/res/drawable-hdpi/btn_close_selected.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_code_lock_default.png b/core/res/res/drawable-hdpi/btn_code_lock_default.png
index df3137f..4469ce0 100644
--- a/core/res/res/drawable-hdpi/btn_code_lock_default.png
+++ b/core/res/res/drawable-hdpi/btn_code_lock_default.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_code_lock_touched.png b/core/res/res/drawable-hdpi/btn_code_lock_touched.png
index bf9e46a..b90508c 100644
--- a/core/res/res/drawable-hdpi/btn_code_lock_touched.png
+++ b/core/res/res/drawable-hdpi/btn_code_lock_touched.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_normal.9.png b/core/res/res/drawable-hdpi/btn_default_normal.9.png
old mode 100644
new mode 100755
index 329ce6e..803651b
--- a/core/res/res/drawable-hdpi/btn_default_normal.9.png
+++ b/core/res/res/drawable-hdpi/btn_default_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_normal_disable.9.png b/core/res/res/drawable-hdpi/btn_default_normal_disable.9.png
old mode 100644
new mode 100755
index a518c6b..f4f01c7
--- a/core/res/res/drawable-hdpi/btn_default_normal_disable.9.png
+++ b/core/res/res/drawable-hdpi/btn_default_normal_disable.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_normal_disable_focused.9.png b/core/res/res/drawable-hdpi/btn_default_normal_disable_focused.9.png
old mode 100644
new mode 100755
index 71a05b7..5376db2
--- a/core/res/res/drawable-hdpi/btn_default_normal_disable_focused.9.png
+++ b/core/res/res/drawable-hdpi/btn_default_normal_disable_focused.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_pressed.9.png b/core/res/res/drawable-hdpi/btn_default_pressed.9.png
old mode 100644
new mode 100755
index d9d02bf..4312c27
--- a/core/res/res/drawable-hdpi/btn_default_pressed.9.png
+++ b/core/res/res/drawable-hdpi/btn_default_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_selected.9.png b/core/res/res/drawable-hdpi/btn_default_selected.9.png
old mode 100644
new mode 100755
index ab7c612..06b7790
--- a/core/res/res/drawable-hdpi/btn_default_selected.9.png
+++ b/core/res/res/drawable-hdpi/btn_default_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_small_normal.9.png b/core/res/res/drawable-hdpi/btn_default_small_normal.9.png
old mode 100644
new mode 100755
index baafed6..11a97d0
--- a/core/res/res/drawable-hdpi/btn_default_small_normal.9.png
+++ b/core/res/res/drawable-hdpi/btn_default_small_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_small_normal_disable.9.png b/core/res/res/drawable-hdpi/btn_default_small_normal_disable.9.png
old mode 100644
new mode 100755
index 175197b..8f86e3d
--- a/core/res/res/drawable-hdpi/btn_default_small_normal_disable.9.png
+++ b/core/res/res/drawable-hdpi/btn_default_small_normal_disable.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_small_normal_disable_focused.9.png b/core/res/res/drawable-hdpi/btn_default_small_normal_disable_focused.9.png
old mode 100644
new mode 100755
index ec1feff..7c8082f
--- a/core/res/res/drawable-hdpi/btn_default_small_normal_disable_focused.9.png
+++ b/core/res/res/drawable-hdpi/btn_default_small_normal_disable_focused.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_small_pressed.9.png b/core/res/res/drawable-hdpi/btn_default_small_pressed.9.png
old mode 100644
new mode 100755
index c1f9a0f..cf03f7e
--- a/core/res/res/drawable-hdpi/btn_default_small_pressed.9.png
+++ b/core/res/res/drawable-hdpi/btn_default_small_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_small_selected.9.png b/core/res/res/drawable-hdpi/btn_default_small_selected.9.png
old mode 100644
new mode 100755
index 0ea3f40..477a666
--- a/core/res/res/drawable-hdpi/btn_default_small_selected.9.png
+++ b/core/res/res/drawable-hdpi/btn_default_small_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_dialog_disable.png b/core/res/res/drawable-hdpi/btn_dialog_disable.png
old mode 100644
new mode 100755
index 2fc5d1a..4ff634b
--- a/core/res/res/drawable-hdpi/btn_dialog_disable.png
+++ b/core/res/res/drawable-hdpi/btn_dialog_disable.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_dialog_normal.png b/core/res/res/drawable-hdpi/btn_dialog_normal.png
old mode 100644
new mode 100755
index c4a1026..e0cc339
--- a/core/res/res/drawable-hdpi/btn_dialog_normal.png
+++ b/core/res/res/drawable-hdpi/btn_dialog_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_dialog_pressed.png b/core/res/res/drawable-hdpi/btn_dialog_pressed.png
old mode 100644
new mode 100755
index 846f8bf..ed8e008
--- a/core/res/res/drawable-hdpi/btn_dialog_pressed.png
+++ b/core/res/res/drawable-hdpi/btn_dialog_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_dialog_selected.png b/core/res/res/drawable-hdpi/btn_dialog_selected.png
old mode 100644
new mode 100755
index 659c289..9b1a100
--- a/core/res/res/drawable-hdpi/btn_dialog_selected.png
+++ b/core/res/res/drawable-hdpi/btn_dialog_selected.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_dropdown_disable.9.png b/core/res/res/drawable-hdpi/btn_dropdown_disable.9.png
new file mode 100755
index 0000000..606a68e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_dropdown_disable.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_dropdown_disable_focused.9.png b/core/res/res/drawable-hdpi/btn_dropdown_disable_focused.9.png
new file mode 100755
index 0000000..d5d99cf
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_dropdown_disable_focused.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_dropdown_normal.9.png b/core/res/res/drawable-hdpi/btn_dropdown_normal.9.png
old mode 100644
new mode 100755
index 9392495..a4488b0
--- a/core/res/res/drawable-hdpi/btn_dropdown_normal.9.png
+++ b/core/res/res/drawable-hdpi/btn_dropdown_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_dropdown_pressed.9.png b/core/res/res/drawable-hdpi/btn_dropdown_pressed.9.png
old mode 100644
new mode 100755
index beaba45..bdb0077
--- a/core/res/res/drawable-hdpi/btn_dropdown_pressed.9.png
+++ b/core/res/res/drawable-hdpi/btn_dropdown_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_dropdown_selected.9.png b/core/res/res/drawable-hdpi/btn_dropdown_selected.9.png
old mode 100644
new mode 100755
index ec51fc9e..0033fdd
--- a/core/res/res/drawable-hdpi/btn_dropdown_selected.9.png
+++ b/core/res/res/drawable-hdpi/btn_dropdown_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_off.png b/core/res/res/drawable-hdpi/btn_radio_off.png
old mode 100644
new mode 100755
index c0b14aa..48ee2ba
--- a/core/res/res/drawable-hdpi/btn_radio_off.png
+++ b/core/res/res/drawable-hdpi/btn_radio_off.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_off_pressed.png b/core/res/res/drawable-hdpi/btn_radio_off_pressed.png
old mode 100644
new mode 100755
index 3189581..5a4ad89
--- a/core/res/res/drawable-hdpi/btn_radio_off_pressed.png
+++ b/core/res/res/drawable-hdpi/btn_radio_off_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_off_selected.png b/core/res/res/drawable-hdpi/btn_radio_off_selected.png
old mode 100644
new mode 100755
index f337703..7d5c676
--- a/core/res/res/drawable-hdpi/btn_radio_off_selected.png
+++ b/core/res/res/drawable-hdpi/btn_radio_off_selected.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_on.png b/core/res/res/drawable-hdpi/btn_radio_on.png
old mode 100644
new mode 100755
index c90d2eb..2472c20
--- a/core/res/res/drawable-hdpi/btn_radio_on.png
+++ b/core/res/res/drawable-hdpi/btn_radio_on.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_on_pressed.png b/core/res/res/drawable-hdpi/btn_radio_on_pressed.png
old mode 100644
new mode 100755
index d79450b8..98d74ce
--- a/core/res/res/drawable-hdpi/btn_radio_on_pressed.png
+++ b/core/res/res/drawable-hdpi/btn_radio_on_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_on_selected.png b/core/res/res/drawable-hdpi/btn_radio_on_selected.png
old mode 100644
new mode 100755
index db50c43..b6ab46c
--- a/core/res/res/drawable-hdpi/btn_radio_on_selected.png
+++ b/core/res/res/drawable-hdpi/btn_radio_on_selected.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_square_overlay_disabled.png b/core/res/res/drawable-hdpi/btn_square_overlay_disabled.png
old mode 100644
new mode 100755
index 71a037e..ff06697
--- a/core/res/res/drawable-hdpi/btn_square_overlay_disabled.png
+++ b/core/res/res/drawable-hdpi/btn_square_overlay_disabled.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_square_overlay_disabled_selected.png b/core/res/res/drawable-hdpi/btn_square_overlay_disabled_selected.png
new file mode 100755
index 0000000..6a31c71
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_square_overlay_disabled_selected.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_square_overlay_normal.png b/core/res/res/drawable-hdpi/btn_square_overlay_normal.png
old mode 100644
new mode 100755
index bf5da22..c311566
--- a/core/res/res/drawable-hdpi/btn_square_overlay_normal.png
+++ b/core/res/res/drawable-hdpi/btn_square_overlay_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_square_overlay_pressed.png b/core/res/res/drawable-hdpi/btn_square_overlay_pressed.png
old mode 100644
new mode 100755
index 52a302d..ac7fdef
--- a/core/res/res/drawable-hdpi/btn_square_overlay_pressed.png
+++ b/core/res/res/drawable-hdpi/btn_square_overlay_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_square_overlay_selected.png b/core/res/res/drawable-hdpi/btn_square_overlay_selected.png
old mode 100644
new mode 100755
index e065682..ee54149
--- a/core/res/res/drawable-hdpi/btn_square_overlay_selected.png
+++ b/core/res/res/drawable-hdpi/btn_square_overlay_selected.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/divider_horizontal_bright.9.png b/core/res/res/drawable-hdpi/divider_horizontal_bright.9.png
old mode 100644
new mode 100755
index 99a67b9..bd1cc0e
--- a/core/res/res/drawable-hdpi/divider_horizontal_bright.9.png
+++ b/core/res/res/drawable-hdpi/divider_horizontal_bright.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/divider_horizontal_bright_opaque.9.png b/core/res/res/drawable-hdpi/divider_horizontal_bright_opaque.9.png
old mode 100644
new mode 100755
index cfe258b..bd1cc0e
--- a/core/res/res/drawable-hdpi/divider_horizontal_bright_opaque.9.png
+++ b/core/res/res/drawable-hdpi/divider_horizontal_bright_opaque.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/divider_horizontal_dark.9.png b/core/res/res/drawable-hdpi/divider_horizontal_dark.9.png
index 338d840..cb62721 100644
--- a/core/res/res/drawable-hdpi/divider_horizontal_dark.9.png
+++ b/core/res/res/drawable-hdpi/divider_horizontal_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/divider_horizontal_dark_opaque.9.png b/core/res/res/drawable-hdpi/divider_horizontal_dark_opaque.9.png
old mode 100644
new mode 100755
index d21aad2..bd1cc0e
--- a/core/res/res/drawable-hdpi/divider_horizontal_dark_opaque.9.png
+++ b/core/res/res/drawable-hdpi/divider_horizontal_dark_opaque.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/divider_vertical_dark.9.png b/core/res/res/drawable-hdpi/divider_vertical_dark.9.png
index 702b878..a6c9295 100644
--- a/core/res/res/drawable-hdpi/divider_vertical_dark.9.png
+++ b/core/res/res/drawable-hdpi/divider_vertical_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/expander_ic_maximized.9.png b/core/res/res/drawable-hdpi/expander_ic_maximized.9.png
old mode 100644
new mode 100755
index 04943aa..0c19bb7
--- a/core/res/res/drawable-hdpi/expander_ic_maximized.9.png
+++ b/core/res/res/drawable-hdpi/expander_ic_maximized.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/expander_ic_minimized.9.png b/core/res/res/drawable-hdpi/expander_ic_minimized.9.png
old mode 100644
new mode 100755
index 7bddbce..2ec27af
--- a/core/res/res/drawable-hdpi/expander_ic_minimized.9.png
+++ b/core/res/res/drawable-hdpi/expander_ic_minimized.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/fasttrack_badge_normal.9.png b/core/res/res/drawable-hdpi/fasttrack_badge_normal.9.png
new file mode 100644
index 0000000..8c0381f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/fasttrack_badge_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_btn_round_more_disabled.png b/core/res/res/drawable-hdpi/ic_btn_round_more_disabled.png
old mode 100644
new mode 100755
index 0125944..3f1176f
--- a/core/res/res/drawable-hdpi/ic_btn_round_more_disabled.png
+++ b/core/res/res/drawable-hdpi/ic_btn_round_more_disabled.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_btn_round_more_normal.png b/core/res/res/drawable-hdpi/ic_btn_round_more_normal.png
old mode 100644
new mode 100755
index 33d7f89..8abda4d
--- a/core/res/res/drawable-hdpi/ic_btn_round_more_normal.png
+++ b/core/res/res/drawable-hdpi/ic_btn_round_more_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_emergency.png b/core/res/res/drawable-hdpi/ic_emergency.png
index b4465ff..89c05e3 100644
--- a/core/res/res/drawable-hdpi/ic_emergency.png
+++ b/core/res/res/drawable-hdpi/ic_emergency.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_input_add.png b/core/res/res/drawable-hdpi/ic_input_add.png
old mode 100644
new mode 100755
index d26ebac..f9ce574
--- a/core/res/res/drawable-hdpi/ic_input_add.png
+++ b/core/res/res/drawable-hdpi/ic_input_add.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_input_add_disabled.png b/core/res/res/drawable-hdpi/ic_input_add_disabled.png
new file mode 100755
index 0000000..9b3a61a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_input_add_disabled.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_input_remove.png b/core/res/res/drawable-hdpi/ic_input_remove.png
new file mode 100755
index 0000000..3b3d246
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_input_remove.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_input_remove_disabled.png b/core/res/res/drawable-hdpi/ic_input_remove_disabled.png
new file mode 100755
index 0000000..fa0ad9b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_input_remove_disabled.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_account_list.png b/core/res/res/drawable-hdpi/ic_menu_account_list.png
index f858d2c..c62261f 100644
--- a/core/res/res/drawable-hdpi/ic_menu_account_list.png
+++ b/core/res/res/drawable-hdpi/ic_menu_account_list.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_add.png b/core/res/res/drawable-hdpi/ic_menu_add.png
index 65cc01e..7b0dfc5 100644
--- a/core/res/res/drawable-hdpi/ic_menu_add.png
+++ b/core/res/res/drawable-hdpi/ic_menu_add.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_agenda.png b/core/res/res/drawable-hdpi/ic_menu_agenda.png
index 6bb5cc8..88659ae 100644
--- a/core/res/res/drawable-hdpi/ic_menu_agenda.png
+++ b/core/res/res/drawable-hdpi/ic_menu_agenda.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_allfriends.png b/core/res/res/drawable-hdpi/ic_menu_allfriends.png
index 8d11ca1..61c5f6c 100644
--- a/core/res/res/drawable-hdpi/ic_menu_allfriends.png
+++ b/core/res/res/drawable-hdpi/ic_menu_allfriends.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_always_landscape_portrait.png b/core/res/res/drawable-hdpi/ic_menu_always_landscape_portrait.png
index 7ae1760a..3acae27 100644
--- a/core/res/res/drawable-hdpi/ic_menu_always_landscape_portrait.png
+++ b/core/res/res/drawable-hdpi/ic_menu_always_landscape_portrait.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_archive.png b/core/res/res/drawable-hdpi/ic_menu_archive.png
index 9ca5c62..48fbcc4 100644
--- a/core/res/res/drawable-hdpi/ic_menu_archive.png
+++ b/core/res/res/drawable-hdpi/ic_menu_archive.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_attachment.png b/core/res/res/drawable-hdpi/ic_menu_attachment.png
index 8f11153..876377f 100644
--- a/core/res/res/drawable-hdpi/ic_menu_attachment.png
+++ b/core/res/res/drawable-hdpi/ic_menu_attachment.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_back.png b/core/res/res/drawable-hdpi/ic_menu_back.png
index a6cd712..7abf819 100644
--- a/core/res/res/drawable-hdpi/ic_menu_back.png
+++ b/core/res/res/drawable-hdpi/ic_menu_back.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_block.png b/core/res/res/drawable-hdpi/ic_menu_block.png
index e1f9c2c..7e716c4 100644
--- a/core/res/res/drawable-hdpi/ic_menu_block.png
+++ b/core/res/res/drawable-hdpi/ic_menu_block.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_blocked_user.png b/core/res/res/drawable-hdpi/ic_menu_blocked_user.png
index 3dd9a4a..b679bf31 100644
--- a/core/res/res/drawable-hdpi/ic_menu_blocked_user.png
+++ b/core/res/res/drawable-hdpi/ic_menu_blocked_user.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_call.png b/core/res/res/drawable-hdpi/ic_menu_call.png
index 2ccc087..93f97ce 100644
--- a/core/res/res/drawable-hdpi/ic_menu_call.png
+++ b/core/res/res/drawable-hdpi/ic_menu_call.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_camera.png b/core/res/res/drawable-hdpi/ic_menu_camera.png
index 5a3850f..4e10e3e 100644
--- a/core/res/res/drawable-hdpi/ic_menu_camera.png
+++ b/core/res/res/drawable-hdpi/ic_menu_camera.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_cc.png b/core/res/res/drawable-hdpi/ic_menu_cc.png
index 47905a5..62510d2 100644
--- a/core/res/res/drawable-hdpi/ic_menu_cc.png
+++ b/core/res/res/drawable-hdpi/ic_menu_cc.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_chat_dashboard.png b/core/res/res/drawable-hdpi/ic_menu_chat_dashboard.png
index dde6741..dc22e6a 100644
--- a/core/res/res/drawable-hdpi/ic_menu_chat_dashboard.png
+++ b/core/res/res/drawable-hdpi/ic_menu_chat_dashboard.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_clear_playlist.png b/core/res/res/drawable-hdpi/ic_menu_clear_playlist.png
index e6be48b..45ce7e8 100644
--- a/core/res/res/drawable-hdpi/ic_menu_clear_playlist.png
+++ b/core/res/res/drawable-hdpi/ic_menu_clear_playlist.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_close_clear_cancel.png b/core/res/res/drawable-hdpi/ic_menu_close_clear_cancel.png
index a54ea9d..4683f61 100644
--- a/core/res/res/drawable-hdpi/ic_menu_close_clear_cancel.png
+++ b/core/res/res/drawable-hdpi/ic_menu_close_clear_cancel.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_compass.png b/core/res/res/drawable-hdpi/ic_menu_compass.png
index 104270f..756bd22 100644
--- a/core/res/res/drawable-hdpi/ic_menu_compass.png
+++ b/core/res/res/drawable-hdpi/ic_menu_compass.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_compose.png b/core/res/res/drawable-hdpi/ic_menu_compose.png
index 6ad379e..bc153fa 100644
--- a/core/res/res/drawable-hdpi/ic_menu_compose.png
+++ b/core/res/res/drawable-hdpi/ic_menu_compose.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_crop.png b/core/res/res/drawable-hdpi/ic_menu_crop.png
index 0d4c9fe..82970b8 100644
--- a/core/res/res/drawable-hdpi/ic_menu_crop.png
+++ b/core/res/res/drawable-hdpi/ic_menu_crop.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_day.png b/core/res/res/drawable-hdpi/ic_menu_day.png
index 84429aa..39612e8 100644
--- a/core/res/res/drawable-hdpi/ic_menu_day.png
+++ b/core/res/res/drawable-hdpi/ic_menu_day.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_delete.png b/core/res/res/drawable-hdpi/ic_menu_delete.png
index 2aed26a..ce5ecc4 100644
--- a/core/res/res/drawable-hdpi/ic_menu_delete.png
+++ b/core/res/res/drawable-hdpi/ic_menu_delete.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_directions.png b/core/res/res/drawable-hdpi/ic_menu_directions.png
index 23f6eb3..42423b3 100644
--- a/core/res/res/drawable-hdpi/ic_menu_directions.png
+++ b/core/res/res/drawable-hdpi/ic_menu_directions.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_edit.png b/core/res/res/drawable-hdpi/ic_menu_edit.png
index 602dd10..4748cda 100644
--- a/core/res/res/drawable-hdpi/ic_menu_edit.png
+++ b/core/res/res/drawable-hdpi/ic_menu_edit.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_emoticons.png b/core/res/res/drawable-hdpi/ic_menu_emoticons.png
index 2fab515..cb520ae 100644
--- a/core/res/res/drawable-hdpi/ic_menu_emoticons.png
+++ b/core/res/res/drawable-hdpi/ic_menu_emoticons.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_end_conversation.png b/core/res/res/drawable-hdpi/ic_menu_end_conversation.png
index c05a207..e71bb36 100644
--- a/core/res/res/drawable-hdpi/ic_menu_end_conversation.png
+++ b/core/res/res/drawable-hdpi/ic_menu_end_conversation.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_forward.png b/core/res/res/drawable-hdpi/ic_menu_forward.png
index 606e6aa..6b1804f 100644
--- a/core/res/res/drawable-hdpi/ic_menu_forward.png
+++ b/core/res/res/drawable-hdpi/ic_menu_forward.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_friendslist.png b/core/res/res/drawable-hdpi/ic_menu_friendslist.png
index a90e573..ab9c552 100644
--- a/core/res/res/drawable-hdpi/ic_menu_friendslist.png
+++ b/core/res/res/drawable-hdpi/ic_menu_friendslist.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_gallery.png b/core/res/res/drawable-hdpi/ic_menu_gallery.png
index 7c528fa..ba07941 100644
--- a/core/res/res/drawable-hdpi/ic_menu_gallery.png
+++ b/core/res/res/drawable-hdpi/ic_menu_gallery.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_goto.png b/core/res/res/drawable-hdpi/ic_menu_goto.png
index a1acecb..49e68ce 100644
--- a/core/res/res/drawable-hdpi/ic_menu_goto.png
+++ b/core/res/res/drawable-hdpi/ic_menu_goto.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_help.png b/core/res/res/drawable-hdpi/ic_menu_help.png
index 4300e86..a5b4a2f 100644
--- a/core/res/res/drawable-hdpi/ic_menu_help.png
+++ b/core/res/res/drawable-hdpi/ic_menu_help.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_home.png b/core/res/res/drawable-hdpi/ic_menu_home.png
index 35cb52a..949fd04 100644
--- a/core/res/res/drawable-hdpi/ic_menu_home.png
+++ b/core/res/res/drawable-hdpi/ic_menu_home.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_info_details.png b/core/res/res/drawable-hdpi/ic_menu_info_details.png
index 7696ceb..6b3f7fd 100644
--- a/core/res/res/drawable-hdpi/ic_menu_info_details.png
+++ b/core/res/res/drawable-hdpi/ic_menu_info_details.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_invite.png b/core/res/res/drawable-hdpi/ic_menu_invite.png
index 3cb129f..f578523 100644
--- a/core/res/res/drawable-hdpi/ic_menu_invite.png
+++ b/core/res/res/drawable-hdpi/ic_menu_invite.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_login.png b/core/res/res/drawable-hdpi/ic_menu_login.png
index d23ebf0..29e2db6 100644
--- a/core/res/res/drawable-hdpi/ic_menu_login.png
+++ b/core/res/res/drawable-hdpi/ic_menu_login.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_manage.png b/core/res/res/drawable-hdpi/ic_menu_manage.png
index c7c4cbce..c08e64f 100644
--- a/core/res/res/drawable-hdpi/ic_menu_manage.png
+++ b/core/res/res/drawable-hdpi/ic_menu_manage.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_mapmode.png b/core/res/res/drawable-hdpi/ic_menu_mapmode.png
index c895ccb..80c2aa9 100644
--- a/core/res/res/drawable-hdpi/ic_menu_mapmode.png
+++ b/core/res/res/drawable-hdpi/ic_menu_mapmode.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_mark.png b/core/res/res/drawable-hdpi/ic_menu_mark.png
index 724d787..e6126fb 100644
--- a/core/res/res/drawable-hdpi/ic_menu_mark.png
+++ b/core/res/res/drawable-hdpi/ic_menu_mark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_month.png b/core/res/res/drawable-hdpi/ic_menu_month.png
index 3e55ae6..3bf3738 100644
--- a/core/res/res/drawable-hdpi/ic_menu_month.png
+++ b/core/res/res/drawable-hdpi/ic_menu_month.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_more.png b/core/res/res/drawable-hdpi/ic_menu_more.png
index ccecc1d..052f8f2 100644
--- a/core/res/res/drawable-hdpi/ic_menu_more.png
+++ b/core/res/res/drawable-hdpi/ic_menu_more.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_my_calendar.png b/core/res/res/drawable-hdpi/ic_menu_my_calendar.png
index 3d6ea1f3..afd696d 100644
--- a/core/res/res/drawable-hdpi/ic_menu_my_calendar.png
+++ b/core/res/res/drawable-hdpi/ic_menu_my_calendar.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_mylocation.png b/core/res/res/drawable-hdpi/ic_menu_mylocation.png
index 1bcb0cd..379f15c 100644
--- a/core/res/res/drawable-hdpi/ic_menu_mylocation.png
+++ b/core/res/res/drawable-hdpi/ic_menu_mylocation.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_myplaces.png b/core/res/res/drawable-hdpi/ic_menu_myplaces.png
index 5f726d8..6cb7c8b 100644
--- a/core/res/res/drawable-hdpi/ic_menu_myplaces.png
+++ b/core/res/res/drawable-hdpi/ic_menu_myplaces.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_notifications.png b/core/res/res/drawable-hdpi/ic_menu_notifications.png
index fb63937..1b1c5ed 100644
--- a/core/res/res/drawable-hdpi/ic_menu_notifications.png
+++ b/core/res/res/drawable-hdpi/ic_menu_notifications.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_play_clip.png b/core/res/res/drawable-hdpi/ic_menu_play_clip.png
index ddde03a..439890c 100644
--- a/core/res/res/drawable-hdpi/ic_menu_play_clip.png
+++ b/core/res/res/drawable-hdpi/ic_menu_play_clip.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_preferences.png b/core/res/res/drawable-hdpi/ic_menu_preferences.png
index 81bca4a..039c721 100644
--- a/core/res/res/drawable-hdpi/ic_menu_preferences.png
+++ b/core/res/res/drawable-hdpi/ic_menu_preferences.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_recent_history.png b/core/res/res/drawable-hdpi/ic_menu_recent_history.png
index 0dd1627..bbd5de3 100644
--- a/core/res/res/drawable-hdpi/ic_menu_recent_history.png
+++ b/core/res/res/drawable-hdpi/ic_menu_recent_history.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_refresh.png b/core/res/res/drawable-hdpi/ic_menu_refresh.png
index 53caccac..bbb08f1 100644
--- a/core/res/res/drawable-hdpi/ic_menu_refresh.png
+++ b/core/res/res/drawable-hdpi/ic_menu_refresh.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_report_image.png b/core/res/res/drawable-hdpi/ic_menu_report_image.png
index b6aa5d6..4db2187 100644
--- a/core/res/res/drawable-hdpi/ic_menu_report_image.png
+++ b/core/res/res/drawable-hdpi/ic_menu_report_image.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_revert.png b/core/res/res/drawable-hdpi/ic_menu_revert.png
index 11860a4..ffc67d9 100644
--- a/core/res/res/drawable-hdpi/ic_menu_revert.png
+++ b/core/res/res/drawable-hdpi/ic_menu_revert.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_rotate.png b/core/res/res/drawable-hdpi/ic_menu_rotate.png
index 85115af..835e393 100644
--- a/core/res/res/drawable-hdpi/ic_menu_rotate.png
+++ b/core/res/res/drawable-hdpi/ic_menu_rotate.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_save.png b/core/res/res/drawable-hdpi/ic_menu_save.png
index fc26c5d..62d0b9a 100644
--- a/core/res/res/drawable-hdpi/ic_menu_save.png
+++ b/core/res/res/drawable-hdpi/ic_menu_save.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_search.png b/core/res/res/drawable-hdpi/ic_menu_search.png
index f78234e..9154d6e 100644
--- a/core/res/res/drawable-hdpi/ic_menu_search.png
+++ b/core/res/res/drawable-hdpi/ic_menu_search.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_send.png b/core/res/res/drawable-hdpi/ic_menu_send.png
index 2567b58..9597731 100644
--- a/core/res/res/drawable-hdpi/ic_menu_send.png
+++ b/core/res/res/drawable-hdpi/ic_menu_send.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_set_as.png b/core/res/res/drawable-hdpi/ic_menu_set_as.png
index 7e79c15..83a87b9 100644
--- a/core/res/res/drawable-hdpi/ic_menu_set_as.png
+++ b/core/res/res/drawable-hdpi/ic_menu_set_as.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_share.png b/core/res/res/drawable-hdpi/ic_menu_share.png
index b41b348..b49d9ad7 100644
--- a/core/res/res/drawable-hdpi/ic_menu_share.png
+++ b/core/res/res/drawable-hdpi/ic_menu_share.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_slideshow.png b/core/res/res/drawable-hdpi/ic_menu_slideshow.png
index 925f4eb1..6208585 100644
--- a/core/res/res/drawable-hdpi/ic_menu_slideshow.png
+++ b/core/res/res/drawable-hdpi/ic_menu_slideshow.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_sort_alphabetically.png b/core/res/res/drawable-hdpi/ic_menu_sort_alphabetically.png
index 5d68998..94ee3be 100644
--- a/core/res/res/drawable-hdpi/ic_menu_sort_alphabetically.png
+++ b/core/res/res/drawable-hdpi/ic_menu_sort_alphabetically.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_sort_by_size.png b/core/res/res/drawable-hdpi/ic_menu_sort_by_size.png
index c9388fd..b43bc57 100644
--- a/core/res/res/drawable-hdpi/ic_menu_sort_by_size.png
+++ b/core/res/res/drawable-hdpi/ic_menu_sort_by_size.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_star.png b/core/res/res/drawable-hdpi/ic_menu_star.png
index 21a2c4b..30f6314 100644
--- a/core/res/res/drawable-hdpi/ic_menu_star.png
+++ b/core/res/res/drawable-hdpi/ic_menu_star.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_start_conversation.png b/core/res/res/drawable-hdpi/ic_menu_start_conversation.png
index d63d3a7..0dfc024 100644
--- a/core/res/res/drawable-hdpi/ic_menu_start_conversation.png
+++ b/core/res/res/drawable-hdpi/ic_menu_start_conversation.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_stop.png b/core/res/res/drawable-hdpi/ic_menu_stop.png
index 7c99ed4..310b6ca 100644
--- a/core/res/res/drawable-hdpi/ic_menu_stop.png
+++ b/core/res/res/drawable-hdpi/ic_menu_stop.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_today.png b/core/res/res/drawable-hdpi/ic_menu_today.png
index 4a9352d..653f70cd 100644
--- a/core/res/res/drawable-hdpi/ic_menu_today.png
+++ b/core/res/res/drawable-hdpi/ic_menu_today.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_upload.png b/core/res/res/drawable-hdpi/ic_menu_upload.png
index d845112..7454ba3 100644
--- a/core/res/res/drawable-hdpi/ic_menu_upload.png
+++ b/core/res/res/drawable-hdpi/ic_menu_upload.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_upload_you_tube.png b/core/res/res/drawable-hdpi/ic_menu_upload_you_tube.png
index df5fa7f..448f6c4 100644
--- a/core/res/res/drawable-hdpi/ic_menu_upload_you_tube.png
+++ b/core/res/res/drawable-hdpi/ic_menu_upload_you_tube.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_view.png b/core/res/res/drawable-hdpi/ic_menu_view.png
index 75155d4..5b9f2b9 100644
--- a/core/res/res/drawable-hdpi/ic_menu_view.png
+++ b/core/res/res/drawable-hdpi/ic_menu_view.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_week.png b/core/res/res/drawable-hdpi/ic_menu_week.png
index c216eca..c184f2e 100644
--- a/core/res/res/drawable-hdpi/ic_menu_week.png
+++ b/core/res/res/drawable-hdpi/ic_menu_week.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_zoom.png b/core/res/res/drawable-hdpi/ic_menu_zoom.png
index 9fa4d7e..c1d18d5 100644
--- a/core/res/res/drawable-hdpi/ic_menu_zoom.png
+++ b/core/res/res/drawable-hdpi/ic_menu_zoom.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_search_category_default.png b/core/res/res/drawable-hdpi/ic_search_category_default.png
index f78234e..d368c54 100644
--- a/core/res/res/drawable-hdpi/ic_search_category_default.png
+++ b/core/res/res/drawable-hdpi/ic_search_category_default.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/indicator_code_lock_drag_direction_green_up.png b/core/res/res/drawable-hdpi/indicator_code_lock_drag_direction_green_up.png
index 6560696..6f85f38 100644
--- a/core/res/res/drawable-hdpi/indicator_code_lock_drag_direction_green_up.png
+++ b/core/res/res/drawable-hdpi/indicator_code_lock_drag_direction_green_up.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/indicator_code_lock_drag_direction_red_up.png b/core/res/res/drawable-hdpi/indicator_code_lock_drag_direction_red_up.png
index 698c3ec..bec07f1 100644
--- a/core/res/res/drawable-hdpi/indicator_code_lock_drag_direction_red_up.png
+++ b/core/res/res/drawable-hdpi/indicator_code_lock_drag_direction_red_up.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/indicator_code_lock_point_area_green.png b/core/res/res/drawable-hdpi/indicator_code_lock_point_area_green.png
index 82ad8f7..9fb43b8 100644
--- a/core/res/res/drawable-hdpi/indicator_code_lock_point_area_green.png
+++ b/core/res/res/drawable-hdpi/indicator_code_lock_point_area_green.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/indicator_code_lock_point_area_red.png b/core/res/res/drawable-hdpi/indicator_code_lock_point_area_red.png
index f9d0d33..e26a083 100644
--- a/core/res/res/drawable-hdpi/indicator_code_lock_point_area_red.png
+++ b/core/res/res/drawable-hdpi/indicator_code_lock_point_area_red.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_selector_background_disabled.9.png b/core/res/res/drawable-hdpi/list_selector_background_disabled.9.png
old mode 100644
new mode 100755
index c40233e..9e1c42a
--- a/core/res/res/drawable-hdpi/list_selector_background_disabled.9.png
+++ b/core/res/res/drawable-hdpi/list_selector_background_disabled.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_selector_background_focus.9.png b/core/res/res/drawable-hdpi/list_selector_background_focus.9.png
old mode 100644
new mode 100755
index d8e16b99..5563c80
--- a/core/res/res/drawable-hdpi/list_selector_background_focus.9.png
+++ b/core/res/res/drawable-hdpi/list_selector_background_focus.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_selector_background_longpress.9.png b/core/res/res/drawable-hdpi/list_selector_background_longpress.9.png
old mode 100644
new mode 100755
index 1676ca7..72d3a08
--- a/core/res/res/drawable-hdpi/list_selector_background_longpress.9.png
+++ b/core/res/res/drawable-hdpi/list_selector_background_longpress.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_selector_background_pressed.9.png b/core/res/res/drawable-hdpi/list_selector_background_pressed.9.png
old mode 100644
new mode 100755
index ba79cf7..7568b30
--- a/core/res/res/drawable-hdpi/list_selector_background_pressed.9.png
+++ b/core/res/res/drawable-hdpi/list_selector_background_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/menu_background.9.png b/core/res/res/drawable-hdpi/menu_background.9.png
index 60f0731..1b43435 100644
--- a/core/res/res/drawable-hdpi/menu_background.9.png
+++ b/core/res/res/drawable-hdpi/menu_background.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/menu_background_fill_parent_width.9.png b/core/res/res/drawable-hdpi/menu_background_fill_parent_width.9.png
index 09eac9b..ec974d6 100644
--- a/core/res/res/drawable-hdpi/menu_background_fill_parent_width.9.png
+++ b/core/res/res/drawable-hdpi/menu_background_fill_parent_width.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/menu_submenu_background.9.png b/core/res/res/drawable-hdpi/menu_submenu_background.9.png
index cbd4400..c7056e0 100644
--- a/core/res/res/drawable-hdpi/menu_submenu_background.9.png
+++ b/core/res/res/drawable-hdpi/menu_submenu_background.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/overscroll_edge.png b/core/res/res/drawable-hdpi/overscroll_edge.png
new file mode 100644
index 0000000..f8e40ec
--- /dev/null
+++ b/core/res/res/drawable-hdpi/overscroll_edge.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/overscroll_glow.png b/core/res/res/drawable-hdpi/overscroll_glow.png
new file mode 100644
index 0000000..a8a62c4
--- /dev/null
+++ b/core/res/res/drawable-hdpi/overscroll_glow.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/picture_emergency.png b/core/res/res/drawable-hdpi/picture_emergency.png
index b0f10f9..64972c2 100644
--- a/core/res/res/drawable-hdpi/picture_emergency.png
+++ b/core/res/res/drawable-hdpi/picture_emergency.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/popup_bottom_bright.9.png b/core/res/res/drawable-hdpi/popup_bottom_bright.9.png
old mode 100644
new mode 100755
index cca47d3..f4125a8
--- a/core/res/res/drawable-hdpi/popup_bottom_bright.9.png
+++ b/core/res/res/drawable-hdpi/popup_bottom_bright.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/popup_bottom_dark.9.png b/core/res/res/drawable-hdpi/popup_bottom_dark.9.png
old mode 100644
new mode 100755
index 62a0bd0..734981a
--- a/core/res/res/drawable-hdpi/popup_bottom_dark.9.png
+++ b/core/res/res/drawable-hdpi/popup_bottom_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/popup_bottom_medium.9.png b/core/res/res/drawable-hdpi/popup_bottom_medium.9.png
old mode 100644
new mode 100755
index 6ebb4f7..26ede44
--- a/core/res/res/drawable-hdpi/popup_bottom_medium.9.png
+++ b/core/res/res/drawable-hdpi/popup_bottom_medium.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/popup_center_bright.9.png b/core/res/res/drawable-hdpi/popup_center_bright.9.png
old mode 100644
new mode 100755
index 756e9ed..102c84b
--- a/core/res/res/drawable-hdpi/popup_center_bright.9.png
+++ b/core/res/res/drawable-hdpi/popup_center_bright.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/popup_center_dark.9.png b/core/res/res/drawable-hdpi/popup_center_dark.9.png
old mode 100644
new mode 100755
index 77b4524..e2e983f
--- a/core/res/res/drawable-hdpi/popup_center_dark.9.png
+++ b/core/res/res/drawable-hdpi/popup_center_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/popup_center_medium.9.png b/core/res/res/drawable-hdpi/popup_center_medium.9.png
old mode 100644
new mode 100755
index de4be2a..1ce2a6d
--- a/core/res/res/drawable-hdpi/popup_center_medium.9.png
+++ b/core/res/res/drawable-hdpi/popup_center_medium.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/popup_full_bright.9.png b/core/res/res/drawable-hdpi/popup_full_bright.9.png
old mode 100644
new mode 100755
index 6c30bec..d98ab0c
--- a/core/res/res/drawable-hdpi/popup_full_bright.9.png
+++ b/core/res/res/drawable-hdpi/popup_full_bright.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/popup_full_dark.9.png b/core/res/res/drawable-hdpi/popup_full_dark.9.png
old mode 100644
new mode 100755
index fc8c00e..502adaf
--- a/core/res/res/drawable-hdpi/popup_full_dark.9.png
+++ b/core/res/res/drawable-hdpi/popup_full_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/popup_top_bright.9.png b/core/res/res/drawable-hdpi/popup_top_bright.9.png
old mode 100644
new mode 100755
index ddd30ab..e52a603
--- a/core/res/res/drawable-hdpi/popup_top_bright.9.png
+++ b/core/res/res/drawable-hdpi/popup_top_bright.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/popup_top_dark.9.png b/core/res/res/drawable-hdpi/popup_top_dark.9.png
old mode 100644
new mode 100755
index 144d0fc..3f7d61e9
--- a/core/res/res/drawable-hdpi/popup_top_dark.9.png
+++ b/core/res/res/drawable-hdpi/popup_top_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/scrollbar_handle_accelerated_anim2.9.png b/core/res/res/drawable-hdpi/scrollbar_handle_accelerated_anim2.9.png
index c916780..0a28223 100644
--- a/core/res/res/drawable-hdpi/scrollbar_handle_accelerated_anim2.9.png
+++ b/core/res/res/drawable-hdpi/scrollbar_handle_accelerated_anim2.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_black_16.png b/core/res/res/drawable-hdpi/spinner_black_16.png
old mode 100644
new mode 100755
index eb34867..42eb734f
--- a/core/res/res/drawable-hdpi/spinner_black_16.png
+++ b/core/res/res/drawable-hdpi/spinner_black_16.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_black_20.png b/core/res/res/drawable-hdpi/spinner_black_20.png
old mode 100644
new mode 100755
index dac06d7..c88fbc9
--- a/core/res/res/drawable-hdpi/spinner_black_20.png
+++ b/core/res/res/drawable-hdpi/spinner_black_20.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_black_48.png b/core/res/res/drawable-hdpi/spinner_black_48.png
old mode 100644
new mode 100755
index 337f72a..7f9c4f3
--- a/core/res/res/drawable-hdpi/spinner_black_48.png
+++ b/core/res/res/drawable-hdpi/spinner_black_48.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_black_76.png b/core/res/res/drawable-hdpi/spinner_black_76.png
old mode 100644
new mode 100755
index 2edc3e7..c1c177e
--- a/core/res/res/drawable-hdpi/spinner_black_76.png
+++ b/core/res/res/drawable-hdpi/spinner_black_76.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_white_16.png b/core/res/res/drawable-hdpi/spinner_white_16.png
old mode 100644
new mode 100755
index 7914a68..4e037ae
--- a/core/res/res/drawable-hdpi/spinner_white_16.png
+++ b/core/res/res/drawable-hdpi/spinner_white_16.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_white_48.png b/core/res/res/drawable-hdpi/spinner_white_48.png
old mode 100644
new mode 100755
index faee8ca..d8519f2
--- a/core/res/res/drawable-hdpi/spinner_white_48.png
+++ b/core/res/res/drawable-hdpi/spinner_white_48.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_white_76.png b/core/res/res/drawable-hdpi/spinner_white_76.png
old mode 100644
new mode 100755
index cd26379..6d6aa94
--- a/core/res/res/drawable-hdpi/spinner_white_76.png
+++ b/core/res/res/drawable-hdpi/spinner_white_76.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_alarm.png b/core/res/res/drawable-hdpi/stat_notify_alarm.png
new file mode 100755
index 0000000..2d3eb30
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_notify_alarm.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_alarm_2.png b/core/res/res/drawable-hdpi/stat_notify_alarm_2.png
new file mode 100755
index 0000000..69841ac
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_notify_alarm_2.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_bt_incoming_file.png b/core/res/res/drawable-hdpi/stat_notify_bt_incoming_file.png
new file mode 100755
index 0000000..18addce
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_notify_bt_incoming_file.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_calendar.png b/core/res/res/drawable-hdpi/stat_notify_calendar.png
new file mode 100755
index 0000000..0caab3e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_notify_calendar.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 b86d2ca..0cf5ef5 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
old mode 100644
new mode 100755
index 03499a4..60c3778
--- 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_disk_full.png b/core/res/res/drawable-hdpi/stat_notify_disk_full.png
index 6ceeda8..66e7380 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
new file mode 100755
index 0000000..78003fa
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_notify_email_generic.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
new file mode 100755
index 0000000..7356309
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_notify_gmail.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_instant_message.png b/core/res/res/drawable-hdpi/stat_notify_instant_message.png
new file mode 100755
index 0000000..9fc8262
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_notify_instant_message.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_marketplace_update.png b/core/res/res/drawable-hdpi/stat_notify_marketplace_update.png
new file mode 100755
index 0000000..c0d0284
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_notify_marketplace_update.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 192574d4e..d1173b4 100755
--- 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_mms.png b/core/res/res/drawable-hdpi/stat_notify_mms.png
new file mode 100755
index 0000000..eed8c45
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_notify_mms.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_more_notifications.png b/core/res/res/drawable-hdpi/stat_notify_more_notifications.png
new file mode 100755
index 0000000..f54b3d4
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_notify_more_notifications.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_musicplayer.png b/core/res/res/drawable-hdpi/stat_notify_musicplayer.png
new file mode 100755
index 0000000..1301f86
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_notify_musicplayer.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_myfaves.png b/core/res/res/drawable-hdpi/stat_notify_myfaves.png
new file mode 100755
index 0000000..854c745
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_notify_myfaves.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_picasa.png b/core/res/res/drawable-hdpi/stat_notify_picasa.png
new file mode 100755
index 0000000..9146185
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_notify_picasa.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
old mode 100644
new mode 100755
index d3b624b..dd947a5
--- 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_alert.png b/core/res/res/drawable-hdpi/stat_notify_sdcard_alert.png
new file mode 100755
index 0000000..fb2b26a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_notify_sdcard_alert.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
old mode 100644
new mode 100755
index a483ba2..4b9b9ca
--- 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_sim_toolkit.png b/core/res/res/drawable-hdpi/stat_notify_sim_toolkit.png
index 3b14c26..8865bda 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_sms.png b/core/res/res/drawable-hdpi/stat_notify_sms.png
new file mode 100755
index 0000000..66981ba
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_notify_sms.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_sms_failed.png b/core/res/res/drawable-hdpi/stat_notify_sms_failed.png
new file mode 100755
index 0000000..93ede20
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_notify_sms_failed.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 6f9cf84..004cfab 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_alert.png b/core/res/res/drawable-hdpi/stat_notify_sync_alert.png
new file mode 100755
index 0000000..26b2446
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_notify_sync_alert.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 6f9cf84..6973fc5 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_anim1.png b/core/res/res/drawable-hdpi/stat_notify_sync_anim1.png
new file mode 100755
index 0000000..f9d4b32
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_notify_sync_anim1.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_sync_anim2.png b/core/res/res/drawable-hdpi/stat_notify_sync_anim2.png
new file mode 100755
index 0000000..06ff588
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_notify_sync_anim2.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_sync_anim3.png b/core/res/res/drawable-hdpi/stat_notify_sync_anim3.png
new file mode 100755
index 0000000..20d1720
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_notify_sync_anim3.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_sync_anim4.png b/core/res/res/drawable-hdpi/stat_notify_sync_anim4.png
new file mode 100755
index 0000000..a217034
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_notify_sync_anim4.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_sync_anim5.png b/core/res/res/drawable-hdpi/stat_notify_sync_anim5.png
new file mode 100755
index 0000000..8d733ec
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_notify_sync_anim5.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_system_update.png b/core/res/res/drawable-hdpi/stat_notify_system_update.png
new file mode 100755
index 0000000..f4365a5
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_notify_system_update.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_usb_debugger.png b/core/res/res/drawable-hdpi/stat_notify_usb_debugger.png
new file mode 100755
index 0000000..fdf6c6c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_notify_usb_debugger.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 70b2411..5b77846 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_sys_battery_10.png b/core/res/res/drawable-hdpi/stat_sys_battery_10.png
old mode 100644
new mode 100755
index c81616b..4486553
--- a/core/res/res/drawable-hdpi/stat_sys_battery_10.png
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_10.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_100.png b/core/res/res/drawable-hdpi/stat_sys_battery_100.png
old mode 100644
new mode 100755
index e85f524..23b9e3b
--- a/core/res/res/drawable-hdpi/stat_sys_battery_100.png
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_100.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_20.png b/core/res/res/drawable-hdpi/stat_sys_battery_20.png
old mode 100644
new mode 100755
index eb5ef09..c8f9c92
--- a/core/res/res/drawable-hdpi/stat_sys_battery_20.png
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_20.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_40.png b/core/res/res/drawable-hdpi/stat_sys_battery_40.png
old mode 100644
new mode 100755
index ca70784..8d7e1d5
--- a/core/res/res/drawable-hdpi/stat_sys_battery_40.png
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_40.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_60.png b/core/res/res/drawable-hdpi/stat_sys_battery_60.png
old mode 100644
new mode 100755
index fee28db..cb674cc
--- a/core/res/res/drawable-hdpi/stat_sys_battery_60.png
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_60.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_80.png b/core/res/res/drawable-hdpi/stat_sys_battery_80.png
old mode 100644
new mode 100755
index 7f4a38f..5846df9
--- a/core/res/res/drawable-hdpi/stat_sys_battery_80.png
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_80.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim0.png b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim0.png
old mode 100644
new mode 100755
index 9a6c683..c7464f7
--- a/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim0.png
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim0.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim1.png b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim1.png
old mode 100644
new mode 100755
index c40c622..997feb3
--- a/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim1.png
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim1.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim2.png b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim2.png
old mode 100644
new mode 100755
index 2277096..bb8b022
--- a/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim2.png
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim2.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim3.png b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim3.png
old mode 100644
new mode 100755
index 7a3b19e7..212a25f
--- a/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim3.png
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim3.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim4.png b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim4.png
old mode 100644
new mode 100755
index 5c23c13..b211ed6
--- a/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim4.png
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim4.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim5.png b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim5.png
old mode 100644
new mode 100755
index 321545f..a52f81b
--- a/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim5.png
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim5.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_empty.png b/core/res/res/drawable-hdpi/stat_sys_battery_empty.png
new file mode 100755
index 0000000..82f2509
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_empty.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_unknown.png b/core/res/res/drawable-hdpi/stat_sys_battery_unknown.png
old mode 100644
new mode 100755
index 1a9abaf..dadfe8d
--- a/core/res/res/drawable-hdpi/stat_sys_battery_unknown.png
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_unknown.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_bluetooth_connected.png b/core/res/res/drawable-hdpi/stat_sys_bluetooth_connected.png
new file mode 100755
index 0000000..18c77df
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_bluetooth_connected.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_1bar_wifi.png b/core/res/res/drawable-hdpi/stat_sys_data_1bar_wifi.png
new file mode 100755
index 0000000..aea18ed
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_1bar_wifi.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_1bar_wifi_fully.png b/core/res/res/drawable-hdpi/stat_sys_data_1bar_wifi_fully.png
new file mode 100755
index 0000000..1a25a2c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_1bar_wifi_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_2bar_wifi.png b/core/res/res/drawable-hdpi/stat_sys_data_2bar_wifi.png
new file mode 100755
index 0000000..77e6ee4
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_2bar_wifi.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_2bar_wifi_fully.png b/core/res/res/drawable-hdpi/stat_sys_data_2bar_wifi_fully.png
new file mode 100755
index 0000000..00d86bf
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_2bar_wifi_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_3bar_wifi.png b/core/res/res/drawable-hdpi/stat_sys_data_3bar_wifi.png
new file mode 100755
index 0000000..c2574e1
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_3bar_wifi.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_3bar_wifi_fully.png b/core/res/res/drawable-hdpi/stat_sys_data_3bar_wifi_fully.png
new file mode 100755
index 0000000..70c030b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_3bar_wifi_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_4bar_wifi.png b/core/res/res/drawable-hdpi/stat_sys_data_4bar_wifi.png
new file mode 100755
index 0000000..55caecf
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_4bar_wifi.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_4bar_wifi_fully.png b/core/res/res/drawable-hdpi/stat_sys_data_4bar_wifi_fully.png
new file mode 100755
index 0000000..b5326d2
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_4bar_wifi_fully.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
old mode 100644
new mode 100755
index 7a8b78f..e8fbc9e
--- 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_connected_1x.png b/core/res/res/drawable-hdpi/stat_sys_data_connected_1x.png
new file mode 100755
index 0000000..bdc8c27
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_connected_1x.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_connected_1x_fully.png b/core/res/res/drawable-hdpi/stat_sys_data_connected_1x_fully.png
new file mode 100755
index 0000000..ba24082
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_connected_1x_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_connected_3g.png b/core/res/res/drawable-hdpi/stat_sys_data_connected_3g.png
new file mode 100755
index 0000000..d0d1345
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_connected_3g.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_connected_3g_fully.png b/core/res/res/drawable-hdpi/stat_sys_data_connected_3g_fully.png
new file mode 100755
index 0000000..5af2b05
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_connected_3g_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_connected_e.png b/core/res/res/drawable-hdpi/stat_sys_data_connected_e.png
new file mode 100755
index 0000000..4211b8c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_connected_e.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_connected_e_fully.png b/core/res/res/drawable-hdpi/stat_sys_data_connected_e_fully.png
new file mode 100755
index 0000000..9909b09
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_connected_e_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_connected_g.png b/core/res/res/drawable-hdpi/stat_sys_data_connected_g.png
new file mode 100755
index 0000000..d5ece7a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_connected_g.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_connected_g_fully.png b/core/res/res/drawable-hdpi/stat_sys_data_connected_g_fully.png
new file mode 100755
index 0000000..0e02b8d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_connected_g_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_connected_h.png b/core/res/res/drawable-hdpi/stat_sys_data_connected_h.png
new file mode 100755
index 0000000..6687b40
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_connected_h.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_connected_h_fully.png b/core/res/res/drawable-hdpi/stat_sys_data_connected_h_fully.png
new file mode 100755
index 0000000..f84ad32
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_connected_h_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_in_1x.png b/core/res/res/drawable-hdpi/stat_sys_data_in_1x.png
new file mode 100755
index 0000000..00a29a4
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_in_1x.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_in_1x_fully.png b/core/res/res/drawable-hdpi/stat_sys_data_in_1x_fully.png
new file mode 100755
index 0000000..d80a8ce
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_in_1x_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_in_3g.png b/core/res/res/drawable-hdpi/stat_sys_data_in_3g.png
new file mode 100755
index 0000000..11ee0f2
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_in_3g.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_in_3g_fully.png b/core/res/res/drawable-hdpi/stat_sys_data_in_3g_fully.png
new file mode 100755
index 0000000..31c976a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_in_3g_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_in_e.png b/core/res/res/drawable-hdpi/stat_sys_data_in_e.png
new file mode 100755
index 0000000..fc135fc
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_in_e.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_in_e_fully.png b/core/res/res/drawable-hdpi/stat_sys_data_in_e_fully.png
new file mode 100755
index 0000000..c299e12
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_in_e_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_in_g.png b/core/res/res/drawable-hdpi/stat_sys_data_in_g.png
new file mode 100755
index 0000000..3d33a62
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_in_g.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_in_g_fully.png b/core/res/res/drawable-hdpi/stat_sys_data_in_g_fully.png
new file mode 100755
index 0000000..a487f29
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_in_g_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_in_h.png b/core/res/res/drawable-hdpi/stat_sys_data_in_h.png
new file mode 100755
index 0000000..f36e1eb
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_in_h.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_in_h_fully.png b/core/res/res/drawable-hdpi/stat_sys_data_in_h_fully.png
new file mode 100755
index 0000000..816085b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_in_h_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_inandout_1x.png b/core/res/res/drawable-hdpi/stat_sys_data_inandout_1x.png
new file mode 100755
index 0000000..ef5dbf4
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_inandout_1x.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_inandout_1x_fully.png b/core/res/res/drawable-hdpi/stat_sys_data_inandout_1x_fully.png
new file mode 100755
index 0000000..0132019
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_inandout_1x_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_inandout_3g.png b/core/res/res/drawable-hdpi/stat_sys_data_inandout_3g.png
new file mode 100755
index 0000000..dba9675
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_inandout_3g.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_inandout_3g_fully.png b/core/res/res/drawable-hdpi/stat_sys_data_inandout_3g_fully.png
new file mode 100755
index 0000000..3903545
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_inandout_3g_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_inandout_e.png b/core/res/res/drawable-hdpi/stat_sys_data_inandout_e.png
new file mode 100755
index 0000000..2e5d82e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_inandout_e.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_inandout_e_fully.png b/core/res/res/drawable-hdpi/stat_sys_data_inandout_e_fully.png
new file mode 100755
index 0000000..ed099ff
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_inandout_e_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_inandout_g.png b/core/res/res/drawable-hdpi/stat_sys_data_inandout_g.png
new file mode 100755
index 0000000..0985a09
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_inandout_g.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_inandout_g_fully.png b/core/res/res/drawable-hdpi/stat_sys_data_inandout_g_fully.png
new file mode 100755
index 0000000..c930e4c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_inandout_g_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_inandout_h.png b/core/res/res/drawable-hdpi/stat_sys_data_inandout_h.png
new file mode 100755
index 0000000..7a32c43
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_inandout_h.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_inandout_h_fully.png b/core/res/res/drawable-hdpi/stat_sys_data_inandout_h_fully.png
new file mode 100755
index 0000000..407a06c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_inandout_h_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_nosignal_wifi.png b/core/res/res/drawable-hdpi/stat_sys_data_nosignal_wifi.png
new file mode 100755
index 0000000..98e874a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_nosignal_wifi.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_out_1x.png b/core/res/res/drawable-hdpi/stat_sys_data_out_1x.png
new file mode 100755
index 0000000..b622556
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_out_1x.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_out_1x_fully.png b/core/res/res/drawable-hdpi/stat_sys_data_out_1x_fully.png
new file mode 100755
index 0000000..6141f72
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_out_1x_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_out_3g.png b/core/res/res/drawable-hdpi/stat_sys_data_out_3g.png
new file mode 100755
index 0000000..04ec59e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_out_3g.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_out_3g_fully.png b/core/res/res/drawable-hdpi/stat_sys_data_out_3g_fully.png
new file mode 100755
index 0000000..d44a4cf
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_out_3g_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_out_e.png b/core/res/res/drawable-hdpi/stat_sys_data_out_e.png
new file mode 100755
index 0000000..a47b982
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_out_e.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_out_e_fully.png b/core/res/res/drawable-hdpi/stat_sys_data_out_e_fully.png
new file mode 100755
index 0000000..54ebd9b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_out_e_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_out_g.png b/core/res/res/drawable-hdpi/stat_sys_data_out_g.png
new file mode 100755
index 0000000..9d90e71
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_out_g.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_out_g_fully.png b/core/res/res/drawable-hdpi/stat_sys_data_out_g_fully.png
new file mode 100755
index 0000000..2fe0bbf
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_out_g_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_out_h.png b/core/res/res/drawable-hdpi/stat_sys_data_out_h.png
new file mode 100755
index 0000000..920f290
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_out_h.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_out_h_fully.png b/core/res/res/drawable-hdpi/stat_sys_data_out_h_fully.png
new file mode 100755
index 0000000..e58e019
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_out_h_fully.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 4c14c07..e916fbb 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 d9c9e4c..9df7799 100755
--- 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 4f47db0..c3defd7 100755
--- 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 e50d3c3..1302a06 100755
--- 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 6c1029c..c7f85bf 100755
--- 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 693f085..705dfd3 100755
--- 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 eabe0ef..c0bdb13 100755
--- 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_acquiring.png b/core/res/res/drawable-hdpi/stat_sys_gps_acquiring.png
new file mode 100755
index 0000000..e306ad7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_gps_acquiring.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
old mode 100644
new mode 100755
index 99a8c6c..37fb8f7
--- 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_install_complete.png b/core/res/res/drawable-hdpi/stat_sys_install_complete.png
new file mode 100755
index 0000000..c1478c40
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_install_complete.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_phone_call.png b/core/res/res/drawable-hdpi/stat_sys_phone_call.png
old mode 100644
new mode 100755
index 950713b..9b5f075
--- a/core/res/res/drawable-hdpi/stat_sys_phone_call.png
+++ b/core/res/res/drawable-hdpi/stat_sys_phone_call.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_phone_call_bluetooth.png b/core/res/res/drawable-hdpi/stat_sys_phone_call_bluetooth.png
new file mode 100755
index 0000000..fecfe6c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_phone_call_bluetooth.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_phone_call_emergency.png b/core/res/res/drawable-hdpi/stat_sys_phone_call_emergency.png
new file mode 100755
index 0000000..f69f82c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_phone_call_emergency.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_phone_call_forward.png b/core/res/res/drawable-hdpi/stat_sys_phone_call_forward.png
old mode 100644
new mode 100755
index 07a2e9d..032f8f1
--- a/core/res/res/drawable-hdpi/stat_sys_phone_call_forward.png
+++ b/core/res/res/drawable-hdpi/stat_sys_phone_call_forward.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_phone_call_on_hold.png b/core/res/res/drawable-hdpi/stat_sys_phone_call_on_hold.png
old mode 100644
new mode 100755
index 033a558..5b0a68d
--- a/core/res/res/drawable-hdpi/stat_sys_phone_call_on_hold.png
+++ b/core/res/res/drawable-hdpi/stat_sys_phone_call_on_hold.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_r_signal_3_cdma.png b/core/res/res/drawable-hdpi/stat_sys_r_signal_3_cdma.png
old mode 100644
new mode 100755
index 0a32d2e..1d2f966
--- a/core/res/res/drawable-hdpi/stat_sys_r_signal_3_cdma.png
+++ b/core/res/res/drawable-hdpi/stat_sys_r_signal_3_cdma.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_r_signal_4_cdma_fully.png b/core/res/res/drawable-hdpi/stat_sys_r_signal_4_cdma_fully.png
new file mode 100755
index 0000000..7ff8820
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_r_signal_4_cdma_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_r_signal_cdma_0.png b/core/res/res/drawable-hdpi/stat_sys_r_signal_cdma_0.png
new file mode 100755
index 0000000..d128053
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_r_signal_cdma_0.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_r_signal_cdma_1.png b/core/res/res/drawable-hdpi/stat_sys_r_signal_cdma_1.png
new file mode 100755
index 0000000..ecd46e9
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_r_signal_cdma_1.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_r_signal_cdma_1_fully.png b/core/res/res/drawable-hdpi/stat_sys_r_signal_cdma_1_fully.png
new file mode 100755
index 0000000..4462bce
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_r_signal_cdma_1_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_r_signal_cdma_2.png b/core/res/res/drawable-hdpi/stat_sys_r_signal_cdma_2.png
new file mode 100755
index 0000000..d635d8c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_r_signal_cdma_2.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_r_signal_cdma_2_fully.png b/core/res/res/drawable-hdpi/stat_sys_r_signal_cdma_2_fully.png
new file mode 100755
index 0000000..cfca5d2
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_r_signal_cdma_2_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_r_signal_cdma_3.png b/core/res/res/drawable-hdpi/stat_sys_r_signal_cdma_3.png
new file mode 100755
index 0000000..e470925
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_r_signal_cdma_3.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_r_signal_cdma_3_fully.png b/core/res/res/drawable-hdpi/stat_sys_r_signal_cdma_3_fully.png
new file mode 100755
index 0000000..d290699
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_r_signal_cdma_3_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_r_signal_cdma_4.png b/core/res/res/drawable-hdpi/stat_sys_r_signal_cdma_4.png
new file mode 100755
index 0000000..ef47408
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_r_signal_cdma_4.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_r_signal_cdma_4_fully.png b/core/res/res/drawable-hdpi/stat_sys_r_signal_cdma_4_fully.png
new file mode 100755
index 0000000..26cb22b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_r_signal_cdma_4_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_ra_signal_0_cdma.png b/core/res/res/drawable-hdpi/stat_sys_ra_signal_0_cdma.png
old mode 100644
new mode 100755
index 3333933..901058a
--- a/core/res/res/drawable-hdpi/stat_sys_ra_signal_0_cdma.png
+++ b/core/res/res/drawable-hdpi/stat_sys_ra_signal_0_cdma.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_ra_signal_1_cdma.png b/core/res/res/drawable-hdpi/stat_sys_ra_signal_1_cdma.png
old mode 100644
new mode 100755
index 6d69ed6..f5c5f98
--- a/core/res/res/drawable-hdpi/stat_sys_ra_signal_1_cdma.png
+++ b/core/res/res/drawable-hdpi/stat_sys_ra_signal_1_cdma.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_ra_signal_1_cdma_fully.png b/core/res/res/drawable-hdpi/stat_sys_ra_signal_1_cdma_fully.png
new file mode 100755
index 0000000..f71a35c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_ra_signal_1_cdma_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_ra_signal_2_cdma.png b/core/res/res/drawable-hdpi/stat_sys_ra_signal_2_cdma.png
old mode 100644
new mode 100755
index a78957d..82102b2
--- a/core/res/res/drawable-hdpi/stat_sys_ra_signal_2_cdma.png
+++ b/core/res/res/drawable-hdpi/stat_sys_ra_signal_2_cdma.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_ra_signal_2_cdma_fully.png b/core/res/res/drawable-hdpi/stat_sys_ra_signal_2_cdma_fully.png
new file mode 100755
index 0000000..6818f43
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_ra_signal_2_cdma_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_ra_signal_3_cdma_fully.png b/core/res/res/drawable-hdpi/stat_sys_ra_signal_3_cdma_fully.png
new file mode 100755
index 0000000..7d8dc5b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_ra_signal_3_cdma_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_ra_signal_4_cdma.png b/core/res/res/drawable-hdpi/stat_sys_ra_signal_4_cdma.png
old mode 100644
new mode 100755
index 44c1dca..c08cc86
--- a/core/res/res/drawable-hdpi/stat_sys_ra_signal_4_cdma.png
+++ b/core/res/res/drawable-hdpi/stat_sys_ra_signal_4_cdma.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_ringer_silent.png b/core/res/res/drawable-hdpi/stat_sys_ringer_silent.png
new file mode 100755
index 0000000..5a741bb
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_ringer_silent.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_ringer_vibrate.png b/core/res/res/drawable-hdpi/stat_sys_ringer_vibrate.png
new file mode 100755
index 0000000..7ff375a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_ringer_vibrate.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
old mode 100644
new mode 100755
index 4bae258..0889e49
--- 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_signal_0.png b/core/res/res/drawable-hdpi/stat_sys_signal_0.png
new file mode 100755
index 0000000..2f66b1d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_signal_0.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_0_cdma.png b/core/res/res/drawable-hdpi/stat_sys_signal_0_cdma.png
index 3c7db08..af43e00 100755
--- a/core/res/res/drawable-hdpi/stat_sys_signal_0_cdma.png
+++ b/core/res/res/drawable-hdpi/stat_sys_signal_0_cdma.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_1.png b/core/res/res/drawable-hdpi/stat_sys_signal_1.png
new file mode 100755
index 0000000..b91eaf5
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_signal_1.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_1_cdma.png b/core/res/res/drawable-hdpi/stat_sys_signal_1_cdma.png
index f8f40a8..4ffe421 100755
--- a/core/res/res/drawable-hdpi/stat_sys_signal_1_cdma.png
+++ b/core/res/res/drawable-hdpi/stat_sys_signal_1_cdma.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_1_cdma_fully.png b/core/res/res/drawable-hdpi/stat_sys_signal_1_cdma_fully.png
new file mode 100755
index 0000000..cd8e314
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_signal_1_cdma_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_1_fully.png b/core/res/res/drawable-hdpi/stat_sys_signal_1_fully.png
new file mode 100755
index 0000000..cb1ad97
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_signal_1_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_2.png b/core/res/res/drawable-hdpi/stat_sys_signal_2.png
new file mode 100755
index 0000000..53217e4
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_signal_2.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_2_cdma.png b/core/res/res/drawable-hdpi/stat_sys_signal_2_cdma.png
index a243195..6f27b96 100755
--- a/core/res/res/drawable-hdpi/stat_sys_signal_2_cdma.png
+++ b/core/res/res/drawable-hdpi/stat_sys_signal_2_cdma.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_2_cdma_fully.png b/core/res/res/drawable-hdpi/stat_sys_signal_2_cdma_fully.png
new file mode 100755
index 0000000..416a544
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_signal_2_cdma_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_2_fully.png b/core/res/res/drawable-hdpi/stat_sys_signal_2_fully.png
new file mode 100755
index 0000000..74ecb08
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_signal_2_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_3.png b/core/res/res/drawable-hdpi/stat_sys_signal_3.png
new file mode 100755
index 0000000..08f357f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_signal_3.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_3_cdma.png b/core/res/res/drawable-hdpi/stat_sys_signal_3_cdma.png
index 9c369e7..ddc46b0 100755
--- a/core/res/res/drawable-hdpi/stat_sys_signal_3_cdma.png
+++ b/core/res/res/drawable-hdpi/stat_sys_signal_3_cdma.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_3_cdma_fully.png b/core/res/res/drawable-hdpi/stat_sys_signal_3_cdma_fully.png
new file mode 100755
index 0000000..341116e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_signal_3_cdma_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_3_fully.png b/core/res/res/drawable-hdpi/stat_sys_signal_3_fully.png
new file mode 100755
index 0000000..929c700
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_signal_3_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_4.png b/core/res/res/drawable-hdpi/stat_sys_signal_4.png
new file mode 100755
index 0000000..b3bb321
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_signal_4.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_4_cdma.png b/core/res/res/drawable-hdpi/stat_sys_signal_4_cdma.png
index 219bbbd..fb3cfe9 100755
--- a/core/res/res/drawable-hdpi/stat_sys_signal_4_cdma.png
+++ b/core/res/res/drawable-hdpi/stat_sys_signal_4_cdma.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_4_cdma_fully.png b/core/res/res/drawable-hdpi/stat_sys_signal_4_cdma_fully.png
new file mode 100755
index 0000000..ae83e93
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_signal_4_cdma_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_4_fully.png b/core/res/res/drawable-hdpi/stat_sys_signal_4_fully.png
new file mode 100755
index 0000000..4644ac1
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_signal_4_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_evdo_0.png b/core/res/res/drawable-hdpi/stat_sys_signal_evdo_0.png
index ae18ecd..b697ca4 100755
--- a/core/res/res/drawable-hdpi/stat_sys_signal_evdo_0.png
+++ b/core/res/res/drawable-hdpi/stat_sys_signal_evdo_0.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_evdo_1.png b/core/res/res/drawable-hdpi/stat_sys_signal_evdo_1.png
index 4fed92c..a61de4d 100755
--- a/core/res/res/drawable-hdpi/stat_sys_signal_evdo_1.png
+++ b/core/res/res/drawable-hdpi/stat_sys_signal_evdo_1.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_evdo_1_fully.png b/core/res/res/drawable-hdpi/stat_sys_signal_evdo_1_fully.png
new file mode 100755
index 0000000..9fa018b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_signal_evdo_1_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_evdo_2.png b/core/res/res/drawable-hdpi/stat_sys_signal_evdo_2.png
index 96f1248..62e0393 100755
--- a/core/res/res/drawable-hdpi/stat_sys_signal_evdo_2.png
+++ b/core/res/res/drawable-hdpi/stat_sys_signal_evdo_2.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_evdo_2_fully.png b/core/res/res/drawable-hdpi/stat_sys_signal_evdo_2_fully.png
new file mode 100755
index 0000000..0324d9f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_signal_evdo_2_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_evdo_3.png b/core/res/res/drawable-hdpi/stat_sys_signal_evdo_3.png
index b0e1328..09eae9d 100755
--- a/core/res/res/drawable-hdpi/stat_sys_signal_evdo_3.png
+++ b/core/res/res/drawable-hdpi/stat_sys_signal_evdo_3.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_evdo_3_fully.png b/core/res/res/drawable-hdpi/stat_sys_signal_evdo_3_fully.png
new file mode 100755
index 0000000..1ffde3d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_signal_evdo_3_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_evdo_4.png b/core/res/res/drawable-hdpi/stat_sys_signal_evdo_4.png
index da15645..4012ac5 100755
--- a/core/res/res/drawable-hdpi/stat_sys_signal_evdo_4.png
+++ b/core/res/res/drawable-hdpi/stat_sys_signal_evdo_4.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_evdo_4_fully.png b/core/res/res/drawable-hdpi/stat_sys_signal_evdo_4_fully.png
new file mode 100755
index 0000000..22f7e42
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_signal_evdo_4_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_flightmode.png b/core/res/res/drawable-hdpi/stat_sys_signal_flightmode.png
new file mode 100755
index 0000000..01c7e2a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_signal_flightmode.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_null.png b/core/res/res/drawable-hdpi/stat_sys_signal_null.png
new file mode 100755
index 0000000..03d2147
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_signal_null.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_roaming_0.png b/core/res/res/drawable-hdpi/stat_sys_signal_roaming_0.png
new file mode 100755
index 0000000..5796a8a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_signal_roaming_0.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_roaming_1.png b/core/res/res/drawable-hdpi/stat_sys_signal_roaming_1.png
new file mode 100755
index 0000000..3dec269
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_signal_roaming_1.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_roaming_1_fully.png b/core/res/res/drawable-hdpi/stat_sys_signal_roaming_1_fully.png
new file mode 100755
index 0000000..eeb7f67
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_signal_roaming_1_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_roaming_2.png b/core/res/res/drawable-hdpi/stat_sys_signal_roaming_2.png
new file mode 100755
index 0000000..2dcff93
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_signal_roaming_2.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_roaming_2_fully.png b/core/res/res/drawable-hdpi/stat_sys_signal_roaming_2_fully.png
new file mode 100755
index 0000000..aee093a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_signal_roaming_2_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_roaming_3.png b/core/res/res/drawable-hdpi/stat_sys_signal_roaming_3.png
new file mode 100755
index 0000000..1b38450
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_signal_roaming_3.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_roaming_3_fully.png b/core/res/res/drawable-hdpi/stat_sys_signal_roaming_3_fully.png
new file mode 100755
index 0000000..a40017f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_signal_roaming_3_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_roaming_4.png b/core/res/res/drawable-hdpi/stat_sys_signal_roaming_4.png
new file mode 100755
index 0000000..33bf3b3
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_signal_roaming_4.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_roaming_4_fully.png b/core/res/res/drawable-hdpi/stat_sys_signal_roaming_4_fully.png
new file mode 100755
index 0000000..c3b44ee
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_signal_roaming_4_fully.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
old mode 100644
new mode 100755
index 51dea58..21f96c4
--- 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_tether_bluetooth.png b/core/res/res/drawable-hdpi/stat_sys_tether_bluetooth.png
index e43fbae..4ebee58 100644
--- a/core/res/res/drawable-hdpi/stat_sys_tether_bluetooth.png
+++ b/core/res/res/drawable-hdpi/stat_sys_tether_bluetooth.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_tether_general.png b/core/res/res/drawable-hdpi/stat_sys_tether_general.png
index c42b00c..e23f7f9 100644
--- a/core/res/res/drawable-hdpi/stat_sys_tether_general.png
+++ b/core/res/res/drawable-hdpi/stat_sys_tether_general.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_tether_usb.png b/core/res/res/drawable-hdpi/stat_sys_tether_usb.png
index c6c533d..d432f9a 100644
--- a/core/res/res/drawable-hdpi/stat_sys_tether_usb.png
+++ b/core/res/res/drawable-hdpi/stat_sys_tether_usb.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_tether_wifi.png b/core/res/res/drawable-hdpi/stat_sys_tether_wifi.png
index 9fcadef..74dfbba 100644
--- a/core/res/res/drawable-hdpi/stat_sys_tether_wifi.png
+++ b/core/res/res/drawable-hdpi/stat_sys_tether_wifi.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
old mode 100644
new mode 100755
index 33c0521..58eafc0
--- 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 d72afbe..cefcecc 100755
--- 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 5de2873..9d018d0 100755
--- 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 dd0b49f..38a20a6 100755
--- 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 8ac29b3..f517809 100755
--- 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 26c3e714..3ae614e 100755
--- 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 431ac6b..d0638ef 100755
--- 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_vp_phone_call.png b/core/res/res/drawable-hdpi/stat_sys_vp_phone_call.png
old mode 100644
new mode 100755
index dfb3424..83e8ead
--- a/core/res/res/drawable-hdpi/stat_sys_vp_phone_call.png
+++ b/core/res/res/drawable-hdpi/stat_sys_vp_phone_call.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_vp_phone_call_on_hold.png b/core/res/res/drawable-hdpi/stat_sys_vp_phone_call_on_hold.png
old mode 100644
new mode 100755
index 402295b..9731c46
--- a/core/res/res/drawable-hdpi/stat_sys_vp_phone_call_on_hold.png
+++ b/core/res/res/drawable-hdpi/stat_sys_vp_phone_call_on_hold.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
old mode 100644
new mode 100755
index 37c8853..cb8a3d4
--- 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/status_bar_close_on.9.png b/core/res/res/drawable-hdpi/status_bar_close_on.9.png
old mode 100644
new mode 100755
index f313ffb..87d1944
--- a/core/res/res/drawable-hdpi/status_bar_close_on.9.png
+++ b/core/res/res/drawable-hdpi/status_bar_close_on.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/status_bar_header_background.9.png b/core/res/res/drawable-hdpi/status_bar_header_background.9.png
old mode 100644
new mode 100755
index 37b5fef..79d77aa
--- a/core/res/res/drawable-hdpi/status_bar_header_background.9.png
+++ b/core/res/res/drawable-hdpi/status_bar_header_background.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/statusbar_background.9.png b/core/res/res/drawable-hdpi/statusbar_background.9.png
index a4be298..67c8b7f 100644
--- a/core/res/res/drawable-hdpi/statusbar_background.9.png
+++ b/core/res/res/drawable-hdpi/statusbar_background.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_focus.9.png b/core/res/res/drawable-hdpi/tab_focus.9.png
index 6e8a71f..7591c07 100644
--- a/core/res/res/drawable-hdpi/tab_focus.9.png
+++ b/core/res/res/drawable-hdpi/tab_focus.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_focus_bar_left.9.png b/core/res/res/drawable-hdpi/tab_focus_bar_left.9.png
old mode 100644
new mode 100755
index 51194a4..0ee8347
--- a/core/res/res/drawable-hdpi/tab_focus_bar_left.9.png
+++ b/core/res/res/drawable-hdpi/tab_focus_bar_left.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_focus_bar_right.9.png b/core/res/res/drawable-hdpi/tab_focus_bar_right.9.png
old mode 100644
new mode 100755
index 51194a4..0ee8347
--- a/core/res/res/drawable-hdpi/tab_focus_bar_right.9.png
+++ b/core/res/res/drawable-hdpi/tab_focus_bar_right.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_press.9.png b/core/res/res/drawable-hdpi/tab_press.9.png
old mode 100644
new mode 100755
index 119b2c6..01798a3
--- a/core/res/res/drawable-hdpi/tab_press.9.png
+++ b/core/res/res/drawable-hdpi/tab_press.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_press_bar_left.9.png b/core/res/res/drawable-hdpi/tab_press_bar_left.9.png
old mode 100644
new mode 100755
index dc2fbce..ee129ba
--- a/core/res/res/drawable-hdpi/tab_press_bar_left.9.png
+++ b/core/res/res/drawable-hdpi/tab_press_bar_left.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_press_bar_right.9.png b/core/res/res/drawable-hdpi/tab_press_bar_right.9.png
old mode 100644
new mode 100755
index dc2fbce..ee129ba
--- a/core/res/res/drawable-hdpi/tab_press_bar_right.9.png
+++ b/core/res/res/drawable-hdpi/tab_press_bar_right.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_selected.9.png b/core/res/res/drawable-hdpi/tab_selected.9.png
old mode 100644
new mode 100755
index f036b9a..6ee775f
--- a/core/res/res/drawable-hdpi/tab_selected.9.png
+++ b/core/res/res/drawable-hdpi/tab_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_selected_bar_left.9.png b/core/res/res/drawable-hdpi/tab_selected_bar_left.9.png
old mode 100644
new mode 100755
index aa935fe..03bcc13
--- a/core/res/res/drawable-hdpi/tab_selected_bar_left.9.png
+++ b/core/res/res/drawable-hdpi/tab_selected_bar_left.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_selected_bar_right.9.png b/core/res/res/drawable-hdpi/tab_selected_bar_right.9.png
old mode 100644
new mode 100755
index aa935fe..f228445
--- a/core/res/res/drawable-hdpi/tab_selected_bar_right.9.png
+++ b/core/res/res/drawable-hdpi/tab_selected_bar_right.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_unselected.9.png b/core/res/res/drawable-hdpi/tab_unselected.9.png
old mode 100644
new mode 100755
index c3a1f30..67561e2
--- a/core/res/res/drawable-hdpi/tab_unselected.9.png
+++ b/core/res/res/drawable-hdpi/tab_unselected.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/text_select_handle_left.png b/core/res/res/drawable-hdpi/text_select_handle_left.png
new file mode 100644
index 0000000..271a6d0
--- /dev/null
+++ b/core/res/res/drawable-hdpi/text_select_handle_left.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/text_select_handle_middle.png b/core/res/res/drawable-hdpi/text_select_handle_middle.png
new file mode 100644
index 0000000..5a83c6c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/text_select_handle_middle.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/text_select_handle_right.png b/core/res/res/drawable-hdpi/text_select_handle_right.png
new file mode 100644
index 0000000..dfdf899
--- /dev/null
+++ b/core/res/res/drawable-hdpi/text_select_handle_right.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_default.9.png b/core/res/res/drawable-hdpi/textfield_default.9.png
old mode 100644
new mode 100755
index 4c20179..f7b6e99
--- a/core/res/res/drawable-hdpi/textfield_default.9.png
+++ b/core/res/res/drawable-hdpi/textfield_default.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_disabled.9.png b/core/res/res/drawable-hdpi/textfield_disabled.9.png
old mode 100644
new mode 100755
index 81569d1..3011502
--- a/core/res/res/drawable-hdpi/textfield_disabled.9.png
+++ b/core/res/res/drawable-hdpi/textfield_disabled.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_disabled_selected.9.png b/core/res/res/drawable-hdpi/textfield_disabled_selected.9.png
old mode 100644
new mode 100755
index 2591490..e0f82eb
--- a/core/res/res/drawable-hdpi/textfield_disabled_selected.9.png
+++ b/core/res/res/drawable-hdpi/textfield_disabled_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_pressed.9.png b/core/res/res/drawable-hdpi/textfield_pressed.9.png
old mode 100644
new mode 100755
index a42d87f..296d3da
--- a/core/res/res/drawable-hdpi/textfield_pressed.9.png
+++ b/core/res/res/drawable-hdpi/textfield_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_selected.9.png b/core/res/res/drawable-hdpi/textfield_selected.9.png
old mode 100644
new mode 100755
index a36ed72..cf2cae3
--- a/core/res/res/drawable-hdpi/textfield_selected.9.png
+++ b/core/res/res/drawable-hdpi/textfield_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/title_bar_shadow.9.png b/core/res/res/drawable-hdpi/title_bar_shadow.9.png
old mode 100644
new mode 100755
index e6dab63..c3a0a23
--- a/core/res/res/drawable-hdpi/title_bar_shadow.9.png
+++ b/core/res/res/drawable-hdpi/title_bar_shadow.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_account_list.png b/core/res/res/drawable-mdpi/ic_menu_account_list.png
index f0945b2..d3af01b 100644
--- a/core/res/res/drawable-mdpi/ic_menu_account_list.png
+++ b/core/res/res/drawable-mdpi/ic_menu_account_list.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_add.png b/core/res/res/drawable-mdpi/ic_menu_add.png
old mode 100755
new mode 100644
index 6752bfd..57a4099
--- a/core/res/res/drawable-mdpi/ic_menu_add.png
+++ b/core/res/res/drawable-mdpi/ic_menu_add.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_agenda.png b/core/res/res/drawable-mdpi/ic_menu_agenda.png
old mode 100755
new mode 100644
index 9f2c1dc..3fb0031
--- a/core/res/res/drawable-mdpi/ic_menu_agenda.png
+++ b/core/res/res/drawable-mdpi/ic_menu_agenda.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_allfriends.png b/core/res/res/drawable-mdpi/ic_menu_allfriends.png
old mode 100755
new mode 100644
index a5bd331..e4e2727
--- a/core/res/res/drawable-mdpi/ic_menu_allfriends.png
+++ b/core/res/res/drawable-mdpi/ic_menu_allfriends.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_always_landscape_portrait.png b/core/res/res/drawable-mdpi/ic_menu_always_landscape_portrait.png
index 68911c4..451ccc9 100644
--- a/core/res/res/drawable-mdpi/ic_menu_always_landscape_portrait.png
+++ b/core/res/res/drawable-mdpi/ic_menu_always_landscape_portrait.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_archive.png b/core/res/res/drawable-mdpi/ic_menu_archive.png
index a4599e3..7231fbb5 100644
--- a/core/res/res/drawable-mdpi/ic_menu_archive.png
+++ b/core/res/res/drawable-mdpi/ic_menu_archive.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_attachment.png b/core/res/res/drawable-mdpi/ic_menu_attachment.png
index 89d626f..83e0687 100644
--- a/core/res/res/drawable-mdpi/ic_menu_attachment.png
+++ b/core/res/res/drawable-mdpi/ic_menu_attachment.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_back.png b/core/res/res/drawable-mdpi/ic_menu_back.png
index 5ce50eb..91fa3e7 100644
--- a/core/res/res/drawable-mdpi/ic_menu_back.png
+++ b/core/res/res/drawable-mdpi/ic_menu_back.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_block.png b/core/res/res/drawable-mdpi/ic_menu_block.png
index 422eeb1..fce9297 100644
--- a/core/res/res/drawable-mdpi/ic_menu_block.png
+++ b/core/res/res/drawable-mdpi/ic_menu_block.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_blocked_user.png b/core/res/res/drawable-mdpi/ic_menu_blocked_user.png
index 5a5619b..55322459 100644
--- a/core/res/res/drawable-mdpi/ic_menu_blocked_user.png
+++ b/core/res/res/drawable-mdpi/ic_menu_blocked_user.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_call.png b/core/res/res/drawable-mdpi/ic_menu_call.png
index a63f86b..eb05949 100644
--- a/core/res/res/drawable-mdpi/ic_menu_call.png
+++ b/core/res/res/drawable-mdpi/ic_menu_call.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_camera.png b/core/res/res/drawable-mdpi/ic_menu_camera.png
old mode 100755
new mode 100644
index cdf7ca3..7fddf7c
--- a/core/res/res/drawable-mdpi/ic_menu_camera.png
+++ b/core/res/res/drawable-mdpi/ic_menu_camera.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_cc.png b/core/res/res/drawable-mdpi/ic_menu_cc.png
index 4876021..97fb663 100644
--- a/core/res/res/drawable-mdpi/ic_menu_cc.png
+++ b/core/res/res/drawable-mdpi/ic_menu_cc.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_chat_dashboard.png b/core/res/res/drawable-mdpi/ic_menu_chat_dashboard.png
index 37fd3cbd..54e9023 100644
--- a/core/res/res/drawable-mdpi/ic_menu_chat_dashboard.png
+++ b/core/res/res/drawable-mdpi/ic_menu_chat_dashboard.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_clear_playlist.png b/core/res/res/drawable-mdpi/ic_menu_clear_playlist.png
index 750db62..52791a0 100644
--- a/core/res/res/drawable-mdpi/ic_menu_clear_playlist.png
+++ b/core/res/res/drawable-mdpi/ic_menu_clear_playlist.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_close_clear_cancel.png b/core/res/res/drawable-mdpi/ic_menu_close_clear_cancel.png
index 78222ea..04a76b5 100644
--- a/core/res/res/drawable-mdpi/ic_menu_close_clear_cancel.png
+++ b/core/res/res/drawable-mdpi/ic_menu_close_clear_cancel.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_compass.png b/core/res/res/drawable-mdpi/ic_menu_compass.png
index 7717dde..b5f885e 100644
--- a/core/res/res/drawable-mdpi/ic_menu_compass.png
+++ b/core/res/res/drawable-mdpi/ic_menu_compass.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_compose.png b/core/res/res/drawable-mdpi/ic_menu_compose.png
index 1b4733e..121228c 100644
--- a/core/res/res/drawable-mdpi/ic_menu_compose.png
+++ b/core/res/res/drawable-mdpi/ic_menu_compose.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_crop.png b/core/res/res/drawable-mdpi/ic_menu_crop.png
old mode 100755
new mode 100644
index c0df996..4892ca0
--- a/core/res/res/drawable-mdpi/ic_menu_crop.png
+++ b/core/res/res/drawable-mdpi/ic_menu_crop.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_day.png b/core/res/res/drawable-mdpi/ic_menu_day.png
old mode 100755
new mode 100644
index db5d3a4..f366c1b
--- a/core/res/res/drawable-mdpi/ic_menu_day.png
+++ b/core/res/res/drawable-mdpi/ic_menu_day.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_delete.png b/core/res/res/drawable-mdpi/ic_menu_delete.png
old mode 100755
new mode 100644
index 7d95494..bb533f7
--- a/core/res/res/drawable-mdpi/ic_menu_delete.png
+++ b/core/res/res/drawable-mdpi/ic_menu_delete.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_directions.png b/core/res/res/drawable-mdpi/ic_menu_directions.png
old mode 100755
new mode 100644
index 00a288f..fbac73d
--- a/core/res/res/drawable-mdpi/ic_menu_directions.png
+++ b/core/res/res/drawable-mdpi/ic_menu_directions.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_edit.png b/core/res/res/drawable-mdpi/ic_menu_edit.png
old mode 100755
new mode 100644
index 41a9c2e..1de85ca
--- a/core/res/res/drawable-mdpi/ic_menu_edit.png
+++ b/core/res/res/drawable-mdpi/ic_menu_edit.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_emoticons.png b/core/res/res/drawable-mdpi/ic_menu_emoticons.png
index e8c4e47..95fd566 100644
--- a/core/res/res/drawable-mdpi/ic_menu_emoticons.png
+++ b/core/res/res/drawable-mdpi/ic_menu_emoticons.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_end_conversation.png b/core/res/res/drawable-mdpi/ic_menu_end_conversation.png
index 0ea0fcb..9ddb03e 100644
--- a/core/res/res/drawable-mdpi/ic_menu_end_conversation.png
+++ b/core/res/res/drawable-mdpi/ic_menu_end_conversation.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_forward.png b/core/res/res/drawable-mdpi/ic_menu_forward.png
index 0936fac..632e4f6 100644
--- a/core/res/res/drawable-mdpi/ic_menu_forward.png
+++ b/core/res/res/drawable-mdpi/ic_menu_forward.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_friendslist.png b/core/res/res/drawable-mdpi/ic_menu_friendslist.png
index 8ec6b1a..45baa48 100644
--- a/core/res/res/drawable-mdpi/ic_menu_friendslist.png
+++ b/core/res/res/drawable-mdpi/ic_menu_friendslist.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_gallery.png b/core/res/res/drawable-mdpi/ic_menu_gallery.png
old mode 100755
new mode 100644
index a3deef1..2d74993
--- a/core/res/res/drawable-mdpi/ic_menu_gallery.png
+++ b/core/res/res/drawable-mdpi/ic_menu_gallery.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_goto.png b/core/res/res/drawable-mdpi/ic_menu_goto.png
index 40183eb..3810d54 100644
--- a/core/res/res/drawable-mdpi/ic_menu_goto.png
+++ b/core/res/res/drawable-mdpi/ic_menu_goto.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_help.png b/core/res/res/drawable-mdpi/ic_menu_help.png
index 7c55dfd..4f65a61 100644
--- a/core/res/res/drawable-mdpi/ic_menu_help.png
+++ b/core/res/res/drawable-mdpi/ic_menu_help.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_home.png b/core/res/res/drawable-mdpi/ic_menu_home.png
index 34943f6..23dcecd 100644
--- a/core/res/res/drawable-mdpi/ic_menu_home.png
+++ b/core/res/res/drawable-mdpi/ic_menu_home.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_info_details.png b/core/res/res/drawable-mdpi/ic_menu_info_details.png
old mode 100755
new mode 100644
index 1786d1e..1f8a7cd
--- a/core/res/res/drawable-mdpi/ic_menu_info_details.png
+++ b/core/res/res/drawable-mdpi/ic_menu_info_details.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_invite.png b/core/res/res/drawable-mdpi/ic_menu_invite.png
index 7577e6d..ccbf317 100644
--- a/core/res/res/drawable-mdpi/ic_menu_invite.png
+++ b/core/res/res/drawable-mdpi/ic_menu_invite.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_login.png b/core/res/res/drawable-mdpi/ic_menu_login.png
index 2b856bc..d489787 100644
--- a/core/res/res/drawable-mdpi/ic_menu_login.png
+++ b/core/res/res/drawable-mdpi/ic_menu_login.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_manage.png b/core/res/res/drawable-mdpi/ic_menu_manage.png
old mode 100755
new mode 100644
index f155bbc..a96bb0c
--- a/core/res/res/drawable-mdpi/ic_menu_manage.png
+++ b/core/res/res/drawable-mdpi/ic_menu_manage.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_mapmode.png b/core/res/res/drawable-mdpi/ic_menu_mapmode.png
index d85cab5..ef453e1 100644
--- a/core/res/res/drawable-mdpi/ic_menu_mapmode.png
+++ b/core/res/res/drawable-mdpi/ic_menu_mapmode.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_mark.png b/core/res/res/drawable-mdpi/ic_menu_mark.png
index 5e95da7..d2a0116 100644
--- a/core/res/res/drawable-mdpi/ic_menu_mark.png
+++ b/core/res/res/drawable-mdpi/ic_menu_mark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_month.png b/core/res/res/drawable-mdpi/ic_menu_month.png
old mode 100755
new mode 100644
index bf6cb89..d5285ab
--- a/core/res/res/drawable-mdpi/ic_menu_month.png
+++ b/core/res/res/drawable-mdpi/ic_menu_month.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_more.png b/core/res/res/drawable-mdpi/ic_menu_more.png
index b9fc5fa..168dcd3 100644
--- a/core/res/res/drawable-mdpi/ic_menu_more.png
+++ b/core/res/res/drawable-mdpi/ic_menu_more.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_my_calendar.png b/core/res/res/drawable-mdpi/ic_menu_my_calendar.png
old mode 100755
new mode 100644
index 0c88fd3..c1c9c20
--- a/core/res/res/drawable-mdpi/ic_menu_my_calendar.png
+++ b/core/res/res/drawable-mdpi/ic_menu_my_calendar.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_mylocation.png b/core/res/res/drawable-mdpi/ic_menu_mylocation.png
old mode 100755
new mode 100644
index fdbd5ca..9ee5024
--- a/core/res/res/drawable-mdpi/ic_menu_mylocation.png
+++ b/core/res/res/drawable-mdpi/ic_menu_mylocation.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_myplaces.png b/core/res/res/drawable-mdpi/ic_menu_myplaces.png
index 06f11ba..040f9b1 100644
--- a/core/res/res/drawable-mdpi/ic_menu_myplaces.png
+++ b/core/res/res/drawable-mdpi/ic_menu_myplaces.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_notifications.png b/core/res/res/drawable-mdpi/ic_menu_notifications.png
index 866d4e0..f361e82 100644
--- a/core/res/res/drawable-mdpi/ic_menu_notifications.png
+++ b/core/res/res/drawable-mdpi/ic_menu_notifications.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_play_clip.png b/core/res/res/drawable-mdpi/ic_menu_play_clip.png
index 4669947..8a01f70 100644
--- a/core/res/res/drawable-mdpi/ic_menu_play_clip.png
+++ b/core/res/res/drawable-mdpi/ic_menu_play_clip.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_preferences.png b/core/res/res/drawable-mdpi/ic_menu_preferences.png
index 60dbff6..2f34c76 100644
--- a/core/res/res/drawable-mdpi/ic_menu_preferences.png
+++ b/core/res/res/drawable-mdpi/ic_menu_preferences.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_recent_history.png b/core/res/res/drawable-mdpi/ic_menu_recent_history.png
index 4ccae5d..4722cbb 100644
--- a/core/res/res/drawable-mdpi/ic_menu_recent_history.png
+++ b/core/res/res/drawable-mdpi/ic_menu_recent_history.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_refresh.png b/core/res/res/drawable-mdpi/ic_menu_refresh.png
index 77d70dd..c3551bec 100644
--- a/core/res/res/drawable-mdpi/ic_menu_refresh.png
+++ b/core/res/res/drawable-mdpi/ic_menu_refresh.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_report_image.png b/core/res/res/drawable-mdpi/ic_menu_report_image.png
index 393d727..4f128d7 100644
--- a/core/res/res/drawable-mdpi/ic_menu_report_image.png
+++ b/core/res/res/drawable-mdpi/ic_menu_report_image.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_revert.png b/core/res/res/drawable-mdpi/ic_menu_revert.png
index e7e04f5..2afc8e8 100644
--- a/core/res/res/drawable-mdpi/ic_menu_revert.png
+++ b/core/res/res/drawable-mdpi/ic_menu_revert.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_rotate.png b/core/res/res/drawable-mdpi/ic_menu_rotate.png
old mode 100755
new mode 100644
index 27368b2..547d4ca
--- a/core/res/res/drawable-mdpi/ic_menu_rotate.png
+++ b/core/res/res/drawable-mdpi/ic_menu_rotate.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_save.png b/core/res/res/drawable-mdpi/ic_menu_save.png
index 36d50b3..ffd7fb7 100644
--- a/core/res/res/drawable-mdpi/ic_menu_save.png
+++ b/core/res/res/drawable-mdpi/ic_menu_save.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_search.png b/core/res/res/drawable-mdpi/ic_menu_search.png
old mode 100755
new mode 100644
index 94446db..ef949d5
--- a/core/res/res/drawable-mdpi/ic_menu_search.png
+++ b/core/res/res/drawable-mdpi/ic_menu_search.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_send.png b/core/res/res/drawable-mdpi/ic_menu_send.png
old mode 100755
new mode 100644
index 74c096d..672ab71
--- a/core/res/res/drawable-mdpi/ic_menu_send.png
+++ b/core/res/res/drawable-mdpi/ic_menu_send.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_set_as.png b/core/res/res/drawable-mdpi/ic_menu_set_as.png
old mode 100755
new mode 100644
index cb9dc49..e2c92ef
--- a/core/res/res/drawable-mdpi/ic_menu_set_as.png
+++ b/core/res/res/drawable-mdpi/ic_menu_set_as.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_share.png b/core/res/res/drawable-mdpi/ic_menu_share.png
old mode 100755
new mode 100644
index 44db9b1..b7c1c25
--- a/core/res/res/drawable-mdpi/ic_menu_share.png
+++ b/core/res/res/drawable-mdpi/ic_menu_share.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_slideshow.png b/core/res/res/drawable-mdpi/ic_menu_slideshow.png
index 04fda7f..08a40f2 100644
--- a/core/res/res/drawable-mdpi/ic_menu_slideshow.png
+++ b/core/res/res/drawable-mdpi/ic_menu_slideshow.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_sort_alphabetically.png b/core/res/res/drawable-mdpi/ic_menu_sort_alphabetically.png
old mode 100755
new mode 100644
index 2583eb8..06d5c74
--- a/core/res/res/drawable-mdpi/ic_menu_sort_alphabetically.png
+++ b/core/res/res/drawable-mdpi/ic_menu_sort_alphabetically.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_sort_by_size.png b/core/res/res/drawable-mdpi/ic_menu_sort_by_size.png
old mode 100755
new mode 100644
index 65e2786..3c39953
--- a/core/res/res/drawable-mdpi/ic_menu_sort_by_size.png
+++ b/core/res/res/drawable-mdpi/ic_menu_sort_by_size.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_star.png b/core/res/res/drawable-mdpi/ic_menu_star.png
old mode 100755
new mode 100644
index 527d74a..cf50cf9
--- a/core/res/res/drawable-mdpi/ic_menu_star.png
+++ b/core/res/res/drawable-mdpi/ic_menu_star.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_start_conversation.png b/core/res/res/drawable-mdpi/ic_menu_start_conversation.png
index aadcc2f..10ef649 100644
--- a/core/res/res/drawable-mdpi/ic_menu_start_conversation.png
+++ b/core/res/res/drawable-mdpi/ic_menu_start_conversation.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_stop.png b/core/res/res/drawable-mdpi/ic_menu_stop.png
index 4fc825c..51efa91 100644
--- a/core/res/res/drawable-mdpi/ic_menu_stop.png
+++ b/core/res/res/drawable-mdpi/ic_menu_stop.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_today.png b/core/res/res/drawable-mdpi/ic_menu_today.png
old mode 100755
new mode 100644
index c63b6af..2b15f29
--- a/core/res/res/drawable-mdpi/ic_menu_today.png
+++ b/core/res/res/drawable-mdpi/ic_menu_today.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_upload.png b/core/res/res/drawable-mdpi/ic_menu_upload.png
old mode 100755
new mode 100644
index 1c0dd3f..04f3a2c8
--- a/core/res/res/drawable-mdpi/ic_menu_upload.png
+++ b/core/res/res/drawable-mdpi/ic_menu_upload.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_upload_you_tube.png b/core/res/res/drawable-mdpi/ic_menu_upload_you_tube.png
old mode 100755
new mode 100644
index 0095564..add453b
--- a/core/res/res/drawable-mdpi/ic_menu_upload_you_tube.png
+++ b/core/res/res/drawable-mdpi/ic_menu_upload_you_tube.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_view.png b/core/res/res/drawable-mdpi/ic_menu_view.png
old mode 100755
new mode 100644
index 69828a9..6aeac7f
--- a/core/res/res/drawable-mdpi/ic_menu_view.png
+++ b/core/res/res/drawable-mdpi/ic_menu_view.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_week.png b/core/res/res/drawable-mdpi/ic_menu_week.png
old mode 100755
new mode 100644
index 62cd65e..cba437c
--- a/core/res/res/drawable-mdpi/ic_menu_week.png
+++ b/core/res/res/drawable-mdpi/ic_menu_week.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_zoom.png b/core/res/res/drawable-mdpi/ic_menu_zoom.png
index 0b8c4e8..9695c69 100644
--- a/core/res/res/drawable-mdpi/ic_menu_zoom.png
+++ b/core/res/res/drawable-mdpi/ic_menu_zoom.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_search_category_default.png b/core/res/res/drawable-mdpi/ic_search_category_default.png
old mode 100755
new mode 100644
index 94446db..9b55383
--- a/core/res/res/drawable-mdpi/ic_search_category_default.png
+++ b/core/res/res/drawable-mdpi/ic_search_category_default.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/menu_background.9.png b/core/res/res/drawable-mdpi/menu_background.9.png
index 9f16df9..ee99583 100644
--- a/core/res/res/drawable-mdpi/menu_background.9.png
+++ b/core/res/res/drawable-mdpi/menu_background.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/menu_background_fill_parent_width.9.png b/core/res/res/drawable-mdpi/menu_background_fill_parent_width.9.png
index da3011b..d368983 100644
--- a/core/res/res/drawable-mdpi/menu_background_fill_parent_width.9.png
+++ b/core/res/res/drawable-mdpi/menu_background_fill_parent_width.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/overscroll_edge.png b/core/res/res/drawable-mdpi/overscroll_edge.png
new file mode 100644
index 0000000..22f4ef8
--- /dev/null
+++ b/core/res/res/drawable-mdpi/overscroll_edge.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/overscroll_glow.png b/core/res/res/drawable-mdpi/overscroll_glow.png
new file mode 100644
index 0000000..761fb74
--- /dev/null
+++ b/core/res/res/drawable-mdpi/overscroll_glow.png
Binary files differ
diff --git a/core/res/res/drawable/overscroll_edge.png b/core/res/res/drawable/overscroll_edge.png
index 250c827..b026880 100644
--- a/core/res/res/drawable/overscroll_edge.png
+++ b/core/res/res/drawable/overscroll_edge.png
Binary files differ
diff --git a/core/res/res/drawable/overscroll_glow.png b/core/res/res/drawable/overscroll_glow.png
deleted file mode 100644
index 69b456d..0000000
--- a/core/res/res/drawable/overscroll_glow.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 13c3e7e..ac1c0dd 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -451,6 +451,21 @@
         <!-- The preference layout that has the child/tabbed effect. -->
         <attr name="preferenceLayoutChild" format="reference" />
 
+        <!-- ============================ -->
+        <!-- Text selection handle styles -->
+        <!-- ============================ -->
+        <eat-comment />
+
+        <!-- Reference to a drawable that will be used to display a text selection
+             anchor on the left side of a selection region. -->
+        <attr name="textSelectHandleLeft" format="reference" />
+        <!-- Reference to a drawable that will be used to display a text selection
+             anchor on the right side of a selection region. -->
+        <attr name="textSelectHandleRight" format="reference" />
+        <!-- Reference to a drawable that will be used to display a text selection
+             anchor for positioning the cursor within text. -->
+        <attr name="textSelectHandle" format="reference" />
+
     </declare-styleable>
 
     <!-- **************************************************************** -->
@@ -2152,6 +2167,16 @@
              EditorInfo.extras} field when the input
              method is connected. -->
         <attr name="editorExtras" format="reference" />
+
+        <!-- Reference to a drawable that will be used to display a text selection
+             anchor on the left side of a selection region. -->
+        <attr name="textSelectHandleLeft" />
+        <!-- Reference to a drawable that will be used to display a text selection
+             anchor on the right side of a selection region. -->
+        <attr name="textSelectHandleRight" />
+        <!-- Reference to a drawable that will be used to display a text selection
+             anchor for positioning the cursor within text. -->
+        <attr name="textSelectHandle" />
     </declare-styleable>
     <!-- An <code>input-extras</code> is a container for extra data to supply to
          an input method.  Contains
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index d565c68..720dc97 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -342,4 +342,6 @@
     <!-- 2 means give warning -->
     <integer name="config_datause_notification_type">2</integer>
 
+    <!-- Enables SIP on WIFI only -->
+    <bool name="config_sip_wifi_only">false</bool>
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 28a7cca..2c1e91d 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1255,6 +1255,9 @@
   <public type="attr" name="overscrollHeader" id="0x010102c2" />
   <public type="attr" name="overscrollFooter" id="0x010102c3" />
   <public type="attr" name="filterTouchesWhenObscured" id="0x010102c4" />
+  <public type="attr" name="textSelectHandleLeft" id="0x010102c5" />
+  <public type="attr" name="textSelectHandleRight" id="0x010102c6" />
+  <public type="attr" name="textSelectHandle" id="0x010102c7" />
 
   <public-padding type="attr" name="kraken_resource_pad" end="0x01010300" />
   
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 5913639..808b371 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -704,12 +704,12 @@
     <string name="permdesc_movePackage">Allows an application to move application resources from internal to external media and vice versa.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_readLogs">read system log files</string>
+    <string name="permlab_readLogs">read sensitive log data</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_readLogs">Allows an application to read from the
         system\'s various log files.  This allows it to discover general
-        information about what you are doing with the phone, but they should
-        not contain any personal or private information.</string>
+        information about what you are doing with the phone, potentially
+        including personal or private information.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_diagnostic">read/write to resources owned by diag</string>
@@ -1379,7 +1379,7 @@
     <!-- Other IM address type -->
     <string name="imTypeOther">Other</string>
 
-    <!-- Custom IM address type -->
+    <!-- Custom IM protocol type -->
     <string name="imProtocolCustom">Custom</string>
     <!-- AIM IM protocol type -->
     <string name="imProtocolAim">AIM</string>
@@ -1407,6 +1407,15 @@
     <!-- Custom organization type -->
     <string name="orgTypeCustom">Custom</string>
 
+    <!-- Custom SIP address type -->
+    <string name="sipAddressTypeCustom">Custom</string>
+    <!-- Home SIP address type -->
+    <string name="sipAddressTypeHome">Home</string>
+    <!-- Work SIP address type -->
+    <string name="sipAddressTypeWork">Work</string>
+    <!-- Other SIP address type -->
+    <string name="sipAddressTypeOther">Other</string>
+
     <!-- Attbution of a contact status update, when the time of update is unknown -->
     <string name="contact_status_update_attribution">via <xliff:g id="source" example="Google Talk">%1$s</xliff:g></string>
 
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 1c60ba0..e93b570 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -382,6 +382,9 @@
 
     <style name="Widget.TextView">
         <item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
+        <item name="android:textSelectHandleLeft">?android:attr/textSelectHandleLeft</item>
+        <item name="android:textSelectHandleRight">?android:attr/textSelectHandleRight</item>
+        <item name="android:textSelectHandle">?android:attr/textSelectHandle</item>
     </style>
     
     <style name="Widget.TextView.ListSeparator">
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 2311bdd..7d6ca06 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -136,6 +136,11 @@
         <item name="scrollbarTrackHorizontal">@null</item>
         <item name="scrollbarTrackVertical">@null</item>
 
+        <!-- Text selection handle attributes -->
+        <item name="textSelectHandleLeft">@android:drawable/text_select_handle_middle</item>
+        <item name="textSelectHandleRight">@android:drawable/text_select_handle_middle</item>
+        <item name="textSelectHandle">@android:drawable/text_select_handle_middle</item>
+
         <!-- Widget styles -->
         <item name="absListViewStyle">@android:style/Widget.AbsListView</item>
         <item name="autoCompleteTextViewStyle">@android:style/Widget.AutoCompleteTextView</item>        
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index f09421b..487a00d 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -35,6 +35,7 @@
             android:label="@string/permlab_testDenied"
             android:description="@string/permdesc_testDenied" />
 
+    <uses-permission android:name="android.permission.ACCESS_CACHE_FILESYSTEM" />
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
diff --git a/core/tests/coretests/src/android/net/DownloadManagerBaseTest.java b/core/tests/coretests/src/android/net/DownloadManagerBaseTest.java
index ee0f5f1..a7ec7d5 100644
--- a/core/tests/coretests/src/android/net/DownloadManagerBaseTest.java
+++ b/core/tests/coretests/src/android/net/DownloadManagerBaseTest.java
@@ -27,6 +27,7 @@
 import android.net.DownloadManager.Query;
 import android.net.DownloadManager.Request;
 import android.net.wifi.WifiManager;
+import android.os.Bundle;
 import android.os.Environment;
 import android.os.ParcelFileDescriptor;
 import android.os.SystemClock;
@@ -43,9 +44,12 @@
 import java.io.IOException;
 import java.net.URL;
 import java.util.concurrent.TimeoutException;
+import java.util.Collections;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Random;
+import java.util.Set;
 import java.util.Vector;
 
 import junit.framework.AssertionFailedError;
@@ -67,6 +71,7 @@
 
     protected static final String LOG_TAG = "android.net.DownloadManagerBaseTest";
     protected static final int HTTP_OK = 200;
+    protected static final int HTTP_REDIRECT = 307;
     protected static final int HTTP_PARTIAL_CONTENT = 206;
     protected static final int HTTP_NOT_FOUND = 404;
     protected static final int HTTP_SERVICE_UNAVAILABLE = 503;
@@ -119,6 +124,7 @@
 
     public static class MultipleDownloadsCompletedReceiver extends BroadcastReceiver {
         private volatile int mNumDownloadsCompleted = 0;
+        private Set<Long> downloadIds = Collections.synchronizedSet(new HashSet<Long>());
 
         /**
          * {@inheritDoc}
@@ -129,6 +135,8 @@
                 ++mNumDownloadsCompleted;
                 Log.i(LOG_TAG, "MultipleDownloadsCompletedReceiver got intent: " +
                         intent.getAction() + " --> total count: " + mNumDownloadsCompleted);
+                Bundle extras = intent.getExtras();
+                downloadIds.add(new Long(extras.getLong(DownloadManager.EXTRA_DOWNLOAD_ID)));
             }
         }
 
@@ -142,6 +150,18 @@
         public int numDownloadsCompleted() {
             return mNumDownloadsCompleted;
         }
+
+        /**
+         * Gets the list of download IDs.
+         * @return A Set<Long> with the ids of the completed downloads.
+         */
+        public Set<Long> getDownloadIds() {
+            synchronized(downloadIds) {
+                Set<Long> returnIds = new HashSet<Long>(downloadIds);
+                return returnIds;
+            }
+        }
+
     }
 
     public static class WiFiChangedReceiver extends BroadcastReceiver {
@@ -196,6 +216,17 @@
     }
 
     /**
+     * Helper to enqueue a response from the MockWebServer with no body.
+     *
+     * @param status The HTTP status code to return for this response
+     * @return Returns the mock web server response that was queued (which can be modified)
+     */
+    protected MockResponse enqueueResponse(int status) {
+        return doEnqueueResponse(status);
+
+    }
+
+    /**
      * Helper to enqueue a response from the MockWebServer.
      *
      * @param status The HTTP status code to return for this response
diff --git a/core/tests/coretests/src/android/net/DownloadManagerIntegrationTest.java b/core/tests/coretests/src/android/net/DownloadManagerIntegrationTest.java
index be3cbf7..a61f02d 100644
--- a/core/tests/coretests/src/android/net/DownloadManagerIntegrationTest.java
+++ b/core/tests/coretests/src/android/net/DownloadManagerIntegrationTest.java
@@ -21,6 +21,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.database.Cursor;
+import android.net.DownloadManager;
 import android.net.DownloadManager.Query;
 import android.net.DownloadManager.Request;
 import android.net.DownloadManagerBaseTest.DataType;
@@ -28,6 +29,7 @@
 import android.net.wifi.WifiManager;
 import android.os.Environment;
 import android.os.ParcelFileDescriptor;
+import android.os.StatFs;
 import android.os.SystemClock;
 import android.test.InstrumentationTestCase;
 import android.test.suitebuilder.annotation.LargeTest;
@@ -36,10 +38,13 @@
 import android.util.Log;
 
 import java.io.File;
+import java.io.FileOutputStream;
 import java.io.FileWriter;
 import java.io.IOException;
 import java.net.URL;
+import java.util.Iterator;
 import java.util.Random;
+import java.util.Set;
 
 import junit.framework.AssertionFailedError;
 
@@ -51,8 +56,11 @@
  */
 public class DownloadManagerIntegrationTest extends DownloadManagerBaseTest {
 
-    private static String LOG_TAG = "android.net.DownloadManagerIntegrationTest";
-    private static String PROHIBITED_DIRECTORY = "/system";
+    private final static String LOG_TAG = "android.net.DownloadManagerIntegrationTest";
+    private final static String PROHIBITED_DIRECTORY =
+            Environment.getRootDirectory().getAbsolutePath();
+    private final static String CACHE_DIR =
+            Environment.getDownloadCacheDirectory().getAbsolutePath();
     protected MultipleDownloadsCompletedReceiver mReceiver = null;
 
     /**
@@ -74,25 +82,48 @@
     public void tearDown() throws Exception {
         super.tearDown();
         setWiFiStateOn(true);
+        removeAllCurrentDownloads();
 
         if (mReceiver != null) {
             mContext.unregisterReceiver(mReceiver);
             mReceiver = null;
-            removeAllCurrentDownloads();
         }
     }
 
     /**
      * Helper that does the actual basic download verification.
      */
-    protected void doBasicDownload(byte[] blobData) throws Exception {
+    protected long doBasicDownload(byte[] blobData) throws Exception {
         long dlRequest = doStandardEnqueue(blobData);
 
         // wait for the download to complete
         waitForDownloadOrTimeout(dlRequest);
 
-        verifyAndCleanupSingleFileDownload(dlRequest, blobData);
         assertEquals(1, mReceiver.numDownloadsCompleted());
+        return dlRequest;
+    }
+
+    /**
+     * Verifies a particular error code was received from a download
+     *
+     * @param uri The uri to enqueue to the DownloadManager
+     * @param error The error code expected
+     * @throws an Exception if the test fails
+     */
+    @LargeTest
+    public void doErrorTest(Uri uri, int error) throws Exception {
+        Request request = new Request(uri);
+        request.setTitle(DEFAULT_FILENAME);
+
+        long dlRequest = mDownloadManager.enqueue(request);
+        waitForDownloadOrTimeout(dlRequest);
+
+        Cursor cursor = getCursor(dlRequest);
+        try {
+            verifyInt(cursor, DownloadManager.COLUMN_ERROR_CODE, error);
+        } finally {
+            cursor.close();
+        }
     }
 
     /**
@@ -103,7 +134,8 @@
         int fileSize = 500 * 1024;  // 500k
         byte[] blobData = generateData(fileSize, DataType.BINARY);
 
-        doBasicDownload(blobData);
+        long dlRequest = doBasicDownload(blobData);
+        verifyAndCleanupSingleFileDownload(dlRequest, blobData);
     }
 
     /**
@@ -114,7 +146,8 @@
         int fileSize = 300000;
         byte[] blobData = generateData(fileSize, DataType.TEXT);
 
-        doBasicDownload(blobData);
+        long dlRequest = doBasicDownload(blobData);
+        verifyAndCleanupSingleFileDownload(dlRequest, blobData);
     }
 
     /**
@@ -348,34 +381,209 @@
     }
 
     /**
-     * Tests trying to download two large files (50M bytes, followed by 60M bytes)
+     * Tests downloading a file to cache when there isn't enough space in the cache to hold the
+     * entire file.
      */
     @LargeTest
-    public void testInsufficientSpaceSingleFiles() throws Exception {
-        long fileSize1 = 50000000L;
-        long fileSize2 = 60000000L;
-        File largeFile1 = createFileOnSD(null, fileSize1, DataType.TEXT, null);
-        File largeFile2 = createFileOnSD(null, fileSize2, DataType.TEXT, null);
+    public void testDownloadToCache_whenFull() throws Exception {
+        int DOWNLOAD_FILE_SIZE = 500000;
+
+        StatFs fs = new StatFs(CACHE_DIR);
+        Log.i(LOG_TAG, "getAvailableBlocks: " + fs.getAvailableBlocks());
+        Log.i(LOG_TAG, "getBlockSize: " + fs.getBlockSize());
+
+        int blockSize = fs.getBlockSize();
+        int availableBlocks = fs.getAvailableBlocks();
+        int availableBytes = blockSize * availableBlocks;
+        File outFile = null;
 
         try {
-            long dlRequest = doStandardEnqueue(largeFile1);
-            waitForDownloadOrTimeout(dlRequest);
-            ParcelFileDescriptor pfd = mDownloadManager.openDownloadedFile(dlRequest);
-            verifyFileContents(pfd, largeFile1);
-            verifyFileSize(pfd, largeFile1.length());
+            // fill cache to ensure we don't have enough space - take half the size of the
+            // download size, and leave that much freespace left on the cache partition
+            if (DOWNLOAD_FILE_SIZE <= availableBytes) {
+                int writeSizeBytes = availableBytes - (DOWNLOAD_FILE_SIZE / 2);
 
-            dlRequest = doStandardEnqueue(largeFile2);
-            waitForDownloadOrTimeout(dlRequest);
-            Cursor cursor = getCursor(dlRequest);
-            try {
-                verifyInt(cursor, DownloadManager.COLUMN_ERROR_CODE,
-                        DownloadManager.ERROR_INSUFFICIENT_SPACE);
-            } finally {
-                cursor.close();
+                int writeSizeBlocks = writeSizeBytes / blockSize;
+                int remainderSizeBlocks = availableBlocks - writeSizeBlocks;
+
+                FileOutputStream fo = null;
+                try {
+                    outFile = File.createTempFile("DM_TEST", null, new File(CACHE_DIR));
+                    Log.v(LOG_TAG, "writing " + writeSizeBlocks + " blocks to file "
+                            + outFile.getAbsolutePath());
+
+                    fo = new FileOutputStream(outFile);
+
+                    byte[] buffer = new byte[blockSize];
+                    while (fs.getAvailableBlocks() >= remainderSizeBlocks) {
+                        fo.write(buffer);
+                        fs.restat(CACHE_DIR);
+                    }
+                } catch (IOException e) {
+                    Log.e(LOG_TAG, "error filling file: ", e);
+                    throw e;
+                } finally {
+                    if (fo != null) {
+                        fo.close();
+                    }
+                }
             }
+
+            assertTrue(DOWNLOAD_FILE_SIZE > (fs.getAvailableBlocks() * blockSize));
+            byte[] blobData = generateData(DOWNLOAD_FILE_SIZE, DataType.TEXT);
+            long dlRequest = doBasicDownload(blobData);
+            verifyAndCleanupSingleFileDownload(dlRequest, blobData);
+
         } finally {
-            largeFile1.delete();
-            largeFile2.delete();
+            if (outFile != null) {
+                outFile.delete();
+            }
+        }
+    }
+
+    /**
+     * Tests that files are not deleted when DOWNLOAD_CACHE_NON_PURGEABLE is set, even if we've
+     * run out of space.
+     */
+    @LargeTest
+    public void testDownloadCacheNonPurgeable() throws Exception {
+        int fileSize = 10000000;
+        byte[] blobData = generateData(fileSize, DataType.BINARY);
+        long dlRequest = -1;
+
+        // Fill up the cache partition until there's not enough room for another download.
+        // Note that we need to initiate a download first, then check for the available space. This
+        // is b/c there could be some files that are still left in the cache that can (and will be)
+        // cleared out, but not until DM gets a request for a download and reclaims that
+        // space first.
+        boolean spaceAvailable = true;
+        while (spaceAvailable) {
+            dlRequest = doStandardEnqueue(blobData);
+            waitForDownloadOrTimeout(dlRequest);
+
+            // Check if we've filled up the cache yet
+            StatFs fs = new StatFs(CACHE_DIR);
+            Log.i(LOG_TAG, "getAvailableBlocks: " + fs.getAvailableBlocks());
+            Log.i(LOG_TAG, "getBlockSize: " + fs.getBlockSize());
+            int availableBytes = fs.getBlockSize() * fs.getAvailableBlocks();
+            spaceAvailable = (availableBytes > fileSize) ? true : false;
+        }
+
+        // Now add one more download (should not fit in the space left over)
+        dlRequest = doStandardEnqueue(blobData);
+        waitForDownloadOrTimeout(dlRequest);
+
+        // For the last download we should have failed b/c there is not enough space left in cache
+        Cursor cursor = getCursor(dlRequest);
+        try {
+            verifyInt(cursor, DownloadManager.COLUMN_ERROR_CODE,
+                    DownloadManager.ERROR_INSUFFICIENT_SPACE);
+        } finally {
+            cursor.close();
+        }
+    }
+
+    /**
+     * Tests that we get the correct download ID from the download notification.
+     */
+    @LargeTest
+    public void testGetDownloadIdOnNotification() throws Exception {
+        byte[] blobData = generateData(3000, DataType.TEXT);  // file size = 3000 bytes
+
+        MockResponse response = enqueueResponse(HTTP_OK, blobData);
+        long dlRequest = doCommonStandardEnqueue();
+        waitForDownloadOrTimeout(dlRequest);
+
+        Set<Long> ids = mReceiver.getDownloadIds();
+        assertEquals(1, ids.size());
+        Iterator<Long> it = ids.iterator();
+        assertEquals("Download ID received from notification does not match initial id!",
+                dlRequest, it.next().longValue());
+    }
+
+    /**
+     * Tests the download failure error after too many redirects (>5).
+     */
+    @LargeTest
+    public void testErrorTooManyRedirects() throws Exception {
+        Uri uri = getServerUri(DEFAULT_FILENAME);
+
+        // force 6 redirects
+        for (int i = 0; i < 6; ++i) {
+            MockResponse response = enqueueResponse(HTTP_REDIRECT);
+            response.addHeader("Location", uri.toString());
+        }
+        doErrorTest(uri, DownloadManager.ERROR_TOO_MANY_REDIRECTS);
+    }
+
+    /**
+     * Tests the download failure error from an unhandled HTTP status code
+     */
+    @LargeTest
+    public void testErrorUnhandledHttpCode() throws Exception {
+        Uri uri = getServerUri(DEFAULT_FILENAME);
+        MockResponse response = enqueueResponse(HTTP_PARTIAL_CONTENT);
+
+        doErrorTest(uri, DownloadManager.ERROR_UNHANDLED_HTTP_CODE);
+    }
+
+    /**
+     * Tests the download failure error from an unhandled HTTP status code
+     */
+    @LargeTest
+    public void testErrorHttpDataError_invalidRedirect() throws Exception {
+        Uri uri = getServerUri(DEFAULT_FILENAME);
+        MockResponse response = enqueueResponse(HTTP_REDIRECT);
+        response.addHeader("Location", "://blah.blah.blah.com");
+
+        doErrorTest(uri, DownloadManager.ERROR_HTTP_DATA_ERROR);
+    }
+
+    /**
+     * Tests that we can remove a download from the download manager.
+     */
+    @LargeTest
+    public void testRemoveDownload() throws Exception {
+        int fileSize = 100 * 1024;  // 100k
+        byte[] blobData = generateData(fileSize, DataType.BINARY);
+
+        long dlRequest = doBasicDownload(blobData);
+        Cursor cursor = mDownloadManager.query(new Query().setFilterById(dlRequest));
+        try {
+            assertEquals("The count of downloads with this ID is not 1!", 1, cursor.getCount());
+            mDownloadManager.remove(dlRequest);
+            cursor.requery();
+            assertEquals("The count of downloads with this ID is not 0!", 0, cursor.getCount());
+        } finally {
+            cursor.close();
+        }
+    }
+
+    /**
+     * Tests that we can set the title of a download.
+     */
+    @LargeTest
+    public void testSetTitle() throws Exception {
+        int fileSize = 50 * 1024;  // 50k
+        byte[] blobData = generateData(fileSize, DataType.BINARY);
+        MockResponse response = enqueueResponse(HTTP_OK, blobData);
+
+        // An arbitrary unicode string title
+        final String title = "\u00a5123;\"\u0152\u017d \u054b \u0a07 \ucce0 \u6820\u03a8\u5c34" +
+                "\uf4ad\u0da9\uc0c5\uc1a8 \uf4c5 \uf4aa\u0023\'";
+
+        Uri uri = getServerUri(DEFAULT_FILENAME);
+        Request request = new Request(uri);
+        request.setTitle(title);
+
+        long dlRequest = mDownloadManager.enqueue(request);
+        waitForDownloadOrTimeout(dlRequest);
+
+        Cursor cursor = getCursor(dlRequest);
+        try {
+            verifyString(cursor, DownloadManager.COLUMN_TITLE, title);
+        } finally {
+            cursor.close();
         }
     }
 }
diff --git a/core/tests/hosttests/src/android/net/DownloadManagerHostTests.java b/core/tests/hosttests/src/android/net/DownloadManagerHostTests.java
index ed280c9..df781bf 100644
--- a/core/tests/hosttests/src/android/net/DownloadManagerHostTests.java
+++ b/core/tests/hosttests/src/android/net/DownloadManagerHostTests.java
@@ -54,8 +54,10 @@
     private static final String EXTERNAL_DOWNLOAD_URI_KEY = "external_download_uri";
     // Note: External environment variable ANDROID_TEST_EXTERNAL_URI must be set to point to the
     // external URI under which the files downloaded by the tests can be found. Note that the Uri
-    // must be accessible by the device during a test run.
-    private static String EXTERNAL_DOWNLOAD_URI_VALUE = null;
+    // must be accessible by the device during a test run. Correspondingly,
+    // ANDROID_TEST_EXTERNAL_LARGE_URI should point to the external URI of the folder containing
+    // large files.
+    private static String externalDownloadUriValue = null;
 
     Hashtable<String, String> mExtraParams = null;
 
@@ -69,8 +71,8 @@
         // ensure apk path has been set before test is run
         assertNotNull(getTestAppPath());
         mPMUtils = new PackageManagerHostTestUtils(getDevice());
-        EXTERNAL_DOWNLOAD_URI_VALUE = System.getenv("ANDROID_TEST_EXTERNAL_URI");
-        assertNotNull(EXTERNAL_DOWNLOAD_URI_VALUE);
+        externalDownloadUriValue = System.getenv("ANDROID_TEST_EXTERNAL_URI");
+        assertNotNull(externalDownloadUriValue);
         mExtraParams = getExtraParams();
     }
 
@@ -79,7 +81,7 @@
      */
     protected Hashtable<String, String> getExtraParams() {
         Hashtable<String, String> extraParams = new Hashtable<String, String>();
-        extraParams.put(EXTERNAL_DOWNLOAD_URI_KEY, EXTERNAL_DOWNLOAD_URI_VALUE);
+        extraParams.put(EXTERNAL_DOWNLOAD_URI_KEY, externalDownloadUriValue);
         return extraParams;
     }
 
@@ -198,4 +200,19 @@
                 DOWNLOAD_TEST_RUNNER_NAME, mExtraParams);
         assertTrue(testPassed);
     }
+
+    /**
+     * Spawns a device-based function to test 15 concurrent downloads of 5,000,000-byte files
+     *
+     * @throws Exception if the test failed at any point
+     */
+    public void testDownloadMultipleSimultaneously() throws Exception {
+        mPMUtils.installAppAndVerifyExistsOnDevice(String.format("%s%s%s", getTestAppPath(),
+                File.separator, FILE_DOWNLOAD_APK), FILE_DOWNLOAD_PKG, true);
+
+        boolean testPassed = mPMUtils.runDeviceTestsDidAllTestsPass(FILE_DOWNLOAD_PKG,
+                FILE_DOWNLOAD_CLASS, "runDownloadMultipleSimultaneously",
+                DOWNLOAD_TEST_RUNNER_NAME, mExtraParams);
+        assertTrue(testPassed);
+    }
 }
diff --git a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestApp.java b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestApp.java
index ef81353..0293ded 100644
--- a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestApp.java
+++ b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestApp.java
@@ -35,6 +35,7 @@
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.FileWriter;
+import java.util.HashSet;
 
 import coretestutils.http.MockResponse;
 import coretestutils.http.MockWebServer;
@@ -55,8 +56,13 @@
     protected static String DOWNLOAD_10MB_FILENAME = "External10mb.apk";
     protected static long DOWNLOAD_10MB_FILESIZE = 10258741;
 
+    private static final String FILE_CONCURRENT_DOWNLOAD_FILE_PREFIX = "file";
+    private static final String FILE_CONCURRENT_DOWNLOAD_FILE_EXTENSION = ".bin";
+    protected static long CONCURRENT_DOWNLOAD_FILESIZE = 1000000;
+
     // Values to be obtained from TestRunner
     private String externalDownloadUriValue = null;
+    private String externalLargeDownloadUriValue = null;
 
     /**
      * {@inheritDoc }
@@ -65,12 +71,24 @@
     public void setUp() throws Exception {
         super.setUp();
         DownloadManagerTestRunner mRunner = (DownloadManagerTestRunner)getInstrumentation();
-        externalDownloadUriValue = mRunner.externalDownloadUriValue;
+        externalDownloadUriValue = normalizeUri(mRunner.externalDownloadUriValue);
         assertNotNull(externalDownloadUriValue);
 
-        if (!externalDownloadUriValue.endsWith("/")) {
-            externalDownloadUriValue += "/";
+        externalLargeDownloadUriValue = normalizeUri(mRunner.externalDownloadUriValue);
+        assertNotNull(externalLargeDownloadUriValue);
+    }
+
+    /**
+     * Normalizes a uri to ensure it ends with a "/"
+     *
+     * @param uri The uri to normalize (or null)
+     * @return The normalized uri, or null if null was passed in
+     */
+    public String normalizeUri(String uri) {
+        if (uri != null && !uri.endsWith("/")) {
+            uri += "/";
         }
+        return uri;
     }
 
     /**
@@ -460,4 +478,37 @@
             downloadedFile.delete();
         }
     }
+
+    /**
+     * Tests 15 concurrent downloads of 1,000,000-byte files.
+     *
+     * @throws Exception if test failed
+     */
+    public void runDownloadMultipleSimultaneously() throws Exception {
+        final int TOTAL_DOWNLOADS = 15;
+        HashSet<Long> downloadIds = new HashSet<Long>(TOTAL_DOWNLOADS);
+        MultipleDownloadsCompletedReceiver receiver = registerNewMultipleDownloadsReceiver();
+
+        // Make sure there are no pending downloads currently going on
+        removeAllCurrentDownloads();
+
+        try {
+            for (int i = 0; i < TOTAL_DOWNLOADS; ++i) {
+                long dlRequest = -1;
+                String filename = FILE_CONCURRENT_DOWNLOAD_FILE_PREFIX + i
+                        + FILE_CONCURRENT_DOWNLOAD_FILE_EXTENSION;
+                Uri remoteUri = getExternalFileUri(filename);
+                Request request = new Request(remoteUri);
+                request.setTitle(filename);
+                dlRequest = mDownloadManager.enqueue(request);
+                assertTrue(dlRequest != -1);
+                downloadIds.add(dlRequest);
+            }
+
+            waitForDownloadsOrTimeout(DEFAULT_WAIT_POLL_TIME, 15 * 60 * 2000);  // wait 15 mins max
+            assertEquals(TOTAL_DOWNLOADS, receiver.numDownloadsCompleted());
+        } finally {
+            removeAllCurrentDownloads();
+        }
+    }
 }
diff --git a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestRunner.java b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestRunner.java
index 0f16619..27bf7e1 100644
--- a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestRunner.java
+++ b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestRunner.java
@@ -30,7 +30,7 @@
  *
  * To run the download manager tests:
  *
- * adb shell am instrument -e external_download_1mb_uri <uri> external_download_500k_uri <uri> \
+ * adb shell am instrument -e external_download_uri <uri> external_large_download_uri <uri> \
  *     -w com.android.frameworks.downloadmanagertests/.DownloadManagerTestRunner
  */
 
diff --git a/docs/html/guide/topics/resources/localization.jd b/docs/html/guide/topics/resources/localization.jd
index 3d630c9d..36e12f6 100755
--- a/docs/html/guide/topics/resources/localization.jd
+++ b/docs/html/guide/topics/resources/localization.jd
@@ -433,12 +433,12 @@
 href="{@docRoot}guide/developing/tools/emulator.html">Android Emulator</a>.</p>

 <h4>Creating and using a custom locale</h4>

 

-<p>A &quot;custom&quot; locale is a language/region combination that the

-Android system image does not explicitly support. (For a list of supported 

-locales, see the <a href="{@docRoot}sdk/android-{@sdkCurrentVersion}.html">Android

-Version Notes</a>.) You can test how your application will run in a custom

-locale by creating a custom locale in the emulator. There are two ways to do

-this:</p>

+<p>A &quot;custom&quot; locale is a language/region combination that the Android

+system image does not explicitly support. (For a list of supported locales in

+Android platforms see the Version Notes in the <a

+href="{@docRoot}sdk/index.html">SDK</a> tab). You can test

+how your application will run in a custom locale by creating a custom locale in

+the emulator. There are two ways to do this:</p>

 

 <ul>

   <li>Use the Custom Locale application, which is accessible from the

diff --git a/docs/html/sdk/adt_download.jd b/docs/html/sdk/adt_download.jd
index 126c052..5e642d7 100644
--- a/docs/html/sdk/adt_download.jd
+++ b/docs/html/sdk/adt_download.jd
@@ -24,8 +24,8 @@
   <tr>
      <td>0.9.8</td>
      <td><a href="http://dl-ssl.google.com/android/ADT-0.9.8.zip">ADT-0.9.8.zip</a></td>
-     <td><nobr>{@adtZipBytes} bytes</nobr></td>
-     <td>{@adtZipChecksum}</td>
+     <td><nobr>8703591 bytes</nobr></td>
+     <td>22070f8e52924605a3b3abf87c1ba39f</td>
      <td>Requires SDK Tools, Revision 7 <em><nobr>September 2010</nobr></em></td>
   </tr>
   <tr>
diff --git a/docs/html/sdk/android-1.5.jd b/docs/html/sdk/android-1.5.jd
index 0c16b60..9ed798c 100644
--- a/docs/html/sdk/android-1.5.jd
+++ b/docs/html/sdk/android-1.5.jd
@@ -2,8 +2,6 @@
 sdk.platform.version=1.5
 sdk.platform.apiLevel=3
 sdk.platform.majorMinor=major
-sdk.platform.releaseDate=April 2009
-sdk.platform.deployableDate=May 2009
 
 @jd:body
 
@@ -43,7 +41,7 @@
 <em>API Level:</em>&nbsp;<strong>{@sdkPlatformApiLevel}</strong></p>
 
 <p>Android {@sdkPlatformVersion} is a {@sdkPlatformMajorMinor} platform release
-deployable to Android-powered handsets starting in {@sdkPlatformDeployableDate}.
+deployable to Android-powered handsets starting in May 2009.
 The release includes new features for users and developers, as well as changes
 in the Android framework API. </p>
 
diff --git a/docs/html/sdk/android-1.6.jd b/docs/html/sdk/android-1.6.jd
index c4e08ff..a01a5f6 100644
--- a/docs/html/sdk/android-1.6.jd
+++ b/docs/html/sdk/android-1.6.jd
@@ -2,8 +2,6 @@
 sdk.platform.version=1.6
 sdk.platform.apiLevel=4
 sdk.platform.majorMinor=minor
-sdk.platform.releaseDate=December 2009
-sdk.platform.deployableDate=October 2009
 
 @jd:body
 
@@ -43,7 +41,7 @@
 <em>API Level:</em>&nbsp;<strong>{@sdkPlatformApiLevel}</strong></p>
 
 <p>Android {@sdkPlatformVersion} is a {@sdkPlatformMajorMinor} platform release
-deployable to Android-powered handsets since {@sdkPlatformDeployableDate}.
+deployable to Android-powered handsets since October 2009.
 The platform includes new features for users and developers, as well as changes
 in the Android framework API. </p>
 
diff --git a/docs/html/sdk/android-2.0.1.jd b/docs/html/sdk/android-2.0.1.jd
index cacb6bf..0c8afb6 100644
--- a/docs/html/sdk/android-2.0.1.jd
+++ b/docs/html/sdk/android-2.0.1.jd
@@ -2,8 +2,6 @@
 sdk.platform.version=2.0.1
 sdk.platform.apiLevel=6
 sdk.platform.majorMinor=minor
-sdk.platform.releaseDate=December 2009
-sdk.platform.deployableDate=December 2009
 
 @jd:body
 
@@ -44,7 +42,7 @@
 <em>API Level:</em>&nbsp;<strong>{@sdkPlatformApiLevel}</strong></p>
 
 <p>Android {@sdkPlatformVersion} is a {@sdkPlatformMajorMinor} platform release
-deployable to Android-powered handsets starting in {@sdkPlatformDeployableDate}.
+deployable to Android-powered handsets starting in December 2009.
 This release includes minor API
 changes, bug fixes and framework behavioral changes. For information on changes
 and fixes, see the <a href="#api">Framework API</a> section.</p>
diff --git a/docs/html/sdk/android-2.0.jd b/docs/html/sdk/android-2.0.jd
index a430f34..2c31923 100644
--- a/docs/html/sdk/android-2.0.jd
+++ b/docs/html/sdk/android-2.0.jd
@@ -2,8 +2,6 @@
 sdk.platform.version=2.0
 sdk.platform.apiLevel=5
 sdk.platform.majorMinor=major
-sdk.platform.releaseDate=October 2009
-sdk.platform.deployableDate=November 2009
 
 @jd:body
 
@@ -38,7 +36,7 @@
 <em>API Level:</em>&nbsp;<strong>{@sdkPlatformApiLevel}</strong></p>
 
 <p>Android {@sdkPlatformVersion} is a {@sdkPlatformMajorMinor} platform release
-deployable to Android-powered handsets starting in {@sdkPlatformDeployableDate}.
+deployable to Android-powered handsets starting in November 2009.
 The release includes new features for users and developers, as well as changes
 in the Android framework API. </p>
 
diff --git a/docs/html/sdk/android-2.1.jd b/docs/html/sdk/android-2.1.jd
index cd48a72..6eba6f09 100644
--- a/docs/html/sdk/android-2.1.jd
+++ b/docs/html/sdk/android-2.1.jd
@@ -2,7 +2,6 @@
 sdk.platform.version=2.1
 sdk.platform.apiLevel=7
 sdk.platform.majorMinor=minor
-sdk.platform.deployableDate=January 2010
 
 @jd:body
 
@@ -42,7 +41,7 @@
 <em>API Level:</em>&nbsp;<strong>{@sdkPlatformApiLevel}</strong></p>
 
 <p>Android {@sdkPlatformVersion} is a {@sdkPlatformMajorMinor} platform release
-deployable to Android-powered handsets starting in {@sdkPlatformDeployableDate}.
+deployable to Android-powered handsets starting in January 2010.
 This release includes new API
 changes and bug fixes. For information on changes, see the <a href="#api">Framework API</a>
 section.</p>
diff --git a/docs/html/sdk/eclipse-adt.jd b/docs/html/sdk/eclipse-adt.jd
index 4594bb5..a984d56 100644
--- a/docs/html/sdk/eclipse-adt.jd
+++ b/docs/html/sdk/eclipse-adt.jd
@@ -1,5 +1,9 @@
 page.title=ADT Plugin for Eclipse
 sdk.preview=0
+adt.zip.version=0.9.8
+adt.zip.download=ADT-0.9.8.zip
+adt.zip.bytes=8703591
+adt.zip.checksum=22070f8e52924605a3b3abf87c1ba39f
 
 @jd:body
 
@@ -428,7 +432,7 @@
 
 <h3 id="preparing">Configuring the ADT Plugin</h3>
 
-<p>Once you've successfully downnloaded ADT as described above, the next step
+<p>Once you've successfully downloaded ADT as described above, the next step
 is to modify your ADT preferences in Eclipse to point to the Android SDK directory:</p>
 
 <ol>
diff --git a/docs/knowntags.txt b/docs/knowntags.txt
new file mode 100644
index 0000000..5bebabb
--- /dev/null
+++ b/docs/knowntags.txt
@@ -0,0 +1,38 @@
+# 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.
+
+#
+# The grandfathered list.  We should get rid of these if possible.
+#
+@ToBeFixed
+@stable
+@com.intel.drl.spec_ref
+@ar.org.fitc.spec_ref
+
+# Something about CTS?
+@cts
+
+# Auto-generated info about the SDK
+@sdkCurrent
+@sdkCurrentVersion
+@sdkCurrentRelId
+@sdkPlatformVersion
+@sdkPlatformApiLevel
+@sdkPlatformMajorMinor
+@sdkPlatformReleaseDate
+@sdkPlatformDeployableDate
+@adtZipVersion
+@adtZipDownload
+@adtZipBytes
+@adtZipChecksum
diff --git a/include/android_runtime/android_app_NativeActivity.h b/include/android_runtime/android_app_NativeActivity.h
index fdceb84..b49e02a 100644
--- a/include/android_runtime/android_app_NativeActivity.h
+++ b/include/android_runtime/android_app_NativeActivity.h
@@ -18,6 +18,7 @@
 #define _ANDROID_APP_NATIVEACTIVITY_H
 
 #include <ui/InputTransport.h>
+#include <utils/Looper.h>
 
 #include <android/native_activity.h>
 
@@ -69,7 +70,7 @@
     /* Destroys the consumer and releases its input channel. */
     ~AInputQueue();
 
-    void attachLooper(ALooper* looper, int ident, ALooper_callbackFunc* callback, void* data);
+    void attachLooper(ALooper* looper, int ident, ALooper_callbackFunc callback, void* data);
 
     void detachLooper();
 
@@ -103,7 +104,7 @@
     void wakeupDispatch();
 
     android::InputConsumer mConsumer;
-    android::sp<android::PollLoop> mPollLoop;
+    android::sp<android::Looper> mLooper;
 
     int mDispatchKeyRead;
     int mDispatchKeyWrite;
diff --git a/include/camera/CameraParameters.h b/include/camera/CameraParameters.h
index 7c5371a..53039a0 100644
--- a/include/camera/CameraParameters.h
+++ b/include/camera/CameraParameters.h
@@ -380,12 +380,14 @@
     // continuously. Applications should not call
     // CameraHardwareInterface.autoFocus in this mode.
     static const char FOCUS_MODE_EDOF[];
-    // Continuous auto focus mode. The camera continuously tries to focus. This
-    // is ideal for shooting video or shooting photo of moving object. Auto
-    // focus starts when the parameter is set. Applications should not call
-    // CameraHardwareInterface.autoFocus in this mode.  To stop continuous
-    // focus, applications should change the focus mode to other modes.
-    static const char FOCUS_MODE_CONTINUOUS[];
+    // Continuous auto focus mode intended for video recording. The camera
+    // continuously tries to focus. This is ideal for shooting video.
+    // Applications still can call CameraHardwareInterface.takePicture in this
+    // mode but the subject may not be in focus. Auto focus starts when the
+    // parameter is set. Applications should not call
+    // CameraHardwareInterface.autoFocus in this mode. To stop continuous focus,
+    // applications should change the focus mode to other modes.
+    static const char FOCUS_MODE_CONTINUOUS_VIDEO[];
 
 private:
     DefaultKeyedVector<String8,String8>    mMap;
diff --git a/include/gui/SensorEventQueue.h b/include/gui/SensorEventQueue.h
index 6581ae3..97dd391 100644
--- a/include/gui/SensorEventQueue.h
+++ b/include/gui/SensorEventQueue.h
@@ -42,7 +42,7 @@
 
 class ISensorEventConnection;
 class Sensor;
-class PollLoop;
+class Looper;
 
 // ----------------------------------------------------------------------------
 
@@ -69,11 +69,11 @@
     status_t disableSensor(int32_t handle) const;
 
 private:
-    sp<PollLoop> getPollLoop() const;
+    sp<Looper> getLooper() const;
     sp<ISensorEventConnection> mSensorEventConnection;
     sp<SensorChannel> mSensorChannel;
     mutable Mutex mLock;
-    mutable sp<PollLoop> mPollLoop;
+    mutable sp<Looper> mLooper;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/ui/EventHub.h b/include/ui/EventHub.h
index 25d5afb..d6b09dc 100644
--- a/include/ui/EventHub.h
+++ b/include/ui/EventHub.h
@@ -111,10 +111,10 @@
     /* The input device is a multi-touch touchscreen. */
     INPUT_DEVICE_CLASS_TOUCHSCREEN_MT= 0x00000010,
 
-    /* The input device is a directional pad. */
+    /* The input device is a directional pad (implies keyboard, has DPAD keys). */
     INPUT_DEVICE_CLASS_DPAD          = 0x00000020,
 
-    /* The input device is a gamepad (implies keyboard). */
+    /* The input device is a gamepad (implies keyboard, has BUTTON keys). */
     INPUT_DEVICE_CLASS_GAMEPAD       = 0x00000040,
 
     /* The input device has switches. */
diff --git a/include/ui/FramebufferNativeWindow.h b/include/ui/FramebufferNativeWindow.h
index 0f4594f..c913355 100644
--- a/include/ui/FramebufferNativeWindow.h
+++ b/include/ui/FramebufferNativeWindow.h
@@ -56,6 +56,9 @@
     status_t setUpdateRectangle(const Rect& updateRect);
     status_t compositionComplete();
     
+    // for debugging only
+    int getCurrentBufferIndex() const;
+
 private:
     friend class LightRefBase<FramebufferNativeWindow>;    
     ~FramebufferNativeWindow(); // this class cannot be overloaded
@@ -77,6 +80,7 @@
     int32_t mNumBuffers;
     int32_t mNumFreeBuffers;
     int32_t mBufferHead;
+    int32_t mCurrentBufferIndex;
     bool mUpdateOnDemand;
 };
     
diff --git a/include/ui/GraphicLog.h b/include/ui/GraphicLog.h
new file mode 100644
index 0000000..ee1b09a
--- /dev/null
+++ b/include/ui/GraphicLog.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _UI_GRAPHIC_LOG_H
+#define _UI_GRAPHIC_LOG_H
+
+#include <utils/Singleton.h>
+#include <cutils/compiler.h>
+
+namespace android {
+
+class GraphicLog : public Singleton<GraphicLog>
+{
+    int32_t mEnabled;
+    static void logImpl(int32_t tag, int32_t buffer);
+    static void logImpl(int32_t tag, int32_t identity, int32_t buffer);
+
+public:
+    enum {
+        SF_APP_DEQUEUE_BEFORE   = 60100,
+        SF_APP_DEQUEUE_AFTER    = 60101,
+        SF_APP_LOCK_BEFORE      = 60102,
+        SF_APP_LOCK_AFTER       = 60103,
+        SF_APP_QUEUE            = 60104,
+
+        SF_REPAINT              = 60105,
+        SF_COMPOSITION_COMPLETE = 60106,
+        SF_UNLOCK_CLIENTS       = 60107,
+        SF_SWAP_BUFFERS         = 60108,
+        SF_REPAINT_DONE         = 60109,
+
+        SF_FB_POST_BEFORE       = 60110,
+        SF_FB_POST_AFTER        = 60111,
+        SF_FB_DEQUEUE_BEFORE    = 60112,
+        SF_FB_DEQUEUE_AFTER     = 60113,
+        SF_FB_LOCK_BEFORE       = 60114,
+        SF_FB_LOCK_AFTER        = 60115,
+    };
+
+    inline void log(int32_t tag, int32_t buffer) {
+        if (CC_UNLIKELY(mEnabled))
+            logImpl(tag, buffer);
+    }
+    inline void log(int32_t tag, int32_t identity, int32_t buffer) {
+        if (CC_UNLIKELY(mEnabled))
+            logImpl(tag, identity, buffer);
+    }
+
+    GraphicLog();
+
+    void setEnabled(bool enable);
+};
+
+}
+
+#endif // _UI_GRAPHIC_LOG_H
+
diff --git a/include/ui/InputDispatcher.h b/include/ui/InputDispatcher.h
index a06208a..96b4faed 100644
--- a/include/ui/InputDispatcher.h
+++ b/include/ui/InputDispatcher.h
@@ -25,7 +25,7 @@
 #include <utils/Timers.h>
 #include <utils/RefBase.h>
 #include <utils/String8.h>
-#include <utils/PollLoop.h>
+#include <utils/Looper.h>
 #include <utils/Pool.h>
 
 #include <stddef.h>
@@ -81,9 +81,8 @@
  */
 struct InputTarget {
     enum {
-        /* This flag indicates that subsequent event delivery should be held until the
-         * current event is delivered to this target or a timeout occurs. */
-        FLAG_SYNC = 0x01,
+        /* This flag indicates that the event is being delivered to a foreground application. */
+        FLAG_FOREGROUND = 0x01,
 
         /* This flag indicates that a MotionEvent with AMOTION_EVENT_ACTION_DOWN falls outside
          * of the area of this target and so should instead be delivered as an
@@ -109,12 +108,6 @@
     // Flags for the input target.
     int32_t flags;
 
-    // The timeout for event delivery to this target in nanoseconds, or -1 to wait indefinitely.
-    nsecs_t timeout;
-
-    // The time already spent waiting for this target in nanoseconds, or 0 if none.
-    nsecs_t timeSpentWaitingForApplication;
-
     // The x and y offset to add to a MotionEvent as it is delivered.
     // (ignored for KeyEvents)
     float xOffset, yOffset;
@@ -190,6 +183,7 @@
     };
 
     sp<InputChannel> inputChannel;
+    String8 name;
     int32_t layoutParamsFlags;
     int32_t layoutParamsType;
     nsecs_t dispatchingTimeout;
@@ -206,9 +200,11 @@
     int32_t touchableAreaRight;
     int32_t touchableAreaBottom;
     bool visible;
+    bool canReceiveKeys;
     bool hasFocus;
     bool hasWallpaper;
     bool paused;
+    int32_t layer;
     int32_t ownerPid;
     int32_t ownerUid;
 
@@ -257,18 +253,12 @@
 
     /* Notifies the system that an application is not responding.
      * Returns a new timeout to continue waiting, or 0 to abort dispatch. */
-    virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle) = 0;
+    virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
+            const sp<InputChannel>& inputChannel) = 0;
 
     /* Notifies the system that an input channel is unrecoverably broken. */
     virtual void notifyInputChannelBroken(const sp<InputChannel>& inputChannel) = 0;
 
-    /* Notifies the system that an input channel is not responding.
-     * Returns a new timeout to continue waiting, or 0 to abort dispatch. */
-    virtual nsecs_t notifyInputChannelANR(const sp<InputChannel>& inputChannel) = 0;
-
-    /* Notifies the system that an input channel recovered from ANR. */
-    virtual void notifyInputChannelRecoveredFromANR(const sp<InputChannel>& inputChannel) = 0;
-
     /* Gets the key repeat initial timeout or -1 if automatic key repeating is disabled. */
     virtual nsecs_t getKeyRepeatTimeout() = 0;
 
@@ -361,16 +351,6 @@
      */
     virtual void setInputDispatchMode(bool enabled, bool frozen) = 0;
 
-    /* Preempts input dispatch in progress by making pending synchronous
-     * dispatches asynchronous instead.  This method is generally called during a focus
-     * transition from one application to the next so as to enable the new application
-     * to start receiving input as soon as possible without having to wait for the
-     * old application to finish up.
-     *
-     * This method may be called on any thread (usually by the input manager).
-     */
-    virtual void preemptInputDispatch() = 0;
-
     /* Registers or unregister input channels that may be used as targets for input events.
      * If monitor is true, the channel will receive a copy of all input events.
      *
@@ -424,7 +404,6 @@
     virtual void setInputWindows(const Vector<InputWindow>& inputWindows);
     virtual void setFocusedApplication(const InputApplication* inputApplication);
     virtual void setInputDispatchMode(bool enabled, bool frozen);
-    virtual void preemptInputDispatch();
 
     virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel, bool monitor);
     virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel);
@@ -454,7 +433,7 @@
         int32_t injectorUid;      // -1 if not injected
 
         bool dispatchInProgress; // initially false, set to true while dispatching
-        int32_t pendingSyncDispatches; // the number of synchronous dispatches in progress
+        int32_t pendingForegroundDispatches; // the number of foreground dispatches in progress
 
         inline bool isInjected() { return injectorPid >= 0; }
 
@@ -522,7 +501,6 @@
         int32_t targetFlags;
         float xOffset;
         float yOffset;
-        nsecs_t timeout;
 
         // True if dispatch has started.
         bool inProgress;
@@ -540,12 +518,8 @@
         //   will be set to NULL.
         MotionSample* tailMotionSample;
 
-        inline bool isSyncTarget() const {
-            return targetFlags & InputTarget::FLAG_SYNC;
-        }
-
-        inline void preemptSyncTarget() {
-            targetFlags &= ~ InputTarget::FLAG_SYNC;
+        inline bool hasForegroundTarget() const {
+            return targetFlags & InputTarget::FLAG_FOREGROUND;
         }
     };
 
@@ -628,6 +602,8 @@
             dequeue(first);
             return first;
         }
+
+        uint32_t count() const;
     };
 
     /* Allocates queue entries and performs reference counting as needed. */
@@ -647,7 +623,7 @@
                 nsecs_t downTime, uint32_t pointerCount,
                 const int32_t* pointerIds, const PointerCoords* pointerCoords);
         DispatchEntry* obtainDispatchEntry(EventEntry* eventEntry,
-                int32_t targetFlags, float xOffset, float yOffset, nsecs_t timeout);
+                int32_t targetFlags, float xOffset, float yOffset);
         CommandEntry* obtainCommandEntry(Command command);
 
         void releaseEventEntry(EventEntry* entry);
@@ -761,8 +737,6 @@
             STATUS_NORMAL,
             // An unrecoverable communication error has occurred.
             STATUS_BROKEN,
-            // The client is not responding.
-            STATUS_NOT_RESPONDING,
             // The input channel has been unregistered.
             STATUS_ZOMBIE
         };
@@ -772,11 +746,9 @@
         InputPublisher inputPublisher;
         InputState inputState;
         Queue<DispatchEntry> outboundQueue;
-        nsecs_t nextTimeoutTime; // next timeout time (LONG_LONG_MAX if none)
 
         nsecs_t lastEventTime; // the time when the event was originally captured
         nsecs_t lastDispatchTime; // the time when the last event was dispatched
-        nsecs_t lastANRTime; // the time when the last ANR was recorded
 
         explicit Connection(const sp<InputChannel>& inputChannel);
 
@@ -788,18 +760,6 @@
         // Returns NULL if not found.
         DispatchEntry* findQueuedDispatchEntryForEvent(const EventEntry* eventEntry) const;
 
-        // Determine whether this connection has a pending synchronous dispatch target.
-        // Since there can only ever be at most one such target at a time, if there is one,
-        // it must be at the tail because nothing else can be enqueued after it.
-        inline bool hasPendingSyncTarget() const {
-            return ! outboundQueue.isEmpty() && outboundQueue.tailSentinel.prev->isSyncTarget();
-        }
-
-        // Assuming there is a pending sync target, make it async.
-        inline void preemptSyncTarget() {
-            outboundQueue.tailSentinel.prev->preemptSyncTarget();
-        }
-
         // Gets the time since the current event was originally obtained from the input driver.
         inline double getEventLatencyMillis(nsecs_t currentTime) const {
             return (currentTime - lastEventTime) / 1000000.0;
@@ -810,15 +770,7 @@
             return (currentTime - lastDispatchTime) / 1000000.0;
         }
 
-        // Gets the time since the current event ANR was declared, if applicable.
-        inline double getANRLatencyMillis(nsecs_t currentTime) const {
-            return (currentTime - lastANRTime) / 1000000.0;
-        }
-
         status_t initialize();
-
-        void setNextTimeoutTime(nsecs_t currentTime, nsecs_t timeout);
-        void resetTimeout(nsecs_t currentTime);
     };
 
     sp<InputDispatcherPolicyInterface> mPolicy;
@@ -826,7 +778,7 @@
     Mutex mLock;
 
     Allocator mAllocator;
-    sp<PollLoop> mPollLoop;
+    sp<Looper> mLooper;
 
     EventEntry* mPendingEvent;
     Queue<EventEntry> mInboundQueue;
@@ -837,7 +789,7 @@
     void dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout, nsecs_t keyRepeatDelay,
             nsecs_t* nextWakeupTime);
 
-    // Enqueues an inbound event.  Returns true if mPollLoop->wake() should be called.
+    // Enqueues an inbound event.  Returns true if mLooper->wake() should be called.
     bool enqueueInboundEventLocked(EventEntry* entry);
 
     // App switch latency optimization.
@@ -851,7 +803,7 @@
     // All registered connections mapped by receive pipe file descriptor.
     KeyedVector<int, sp<Connection> > mConnectionsByReceiveFd;
 
-    ssize_t getConnectionIndex(const sp<InputChannel>& inputChannel);
+    ssize_t getConnectionIndexLocked(const sp<InputChannel>& inputChannel);
 
     // Active connections are connections that have a non-empty outbound queue.
     // We don't use a ref-counted pointer here because we explicitly abort connections
@@ -859,12 +811,6 @@
     // and the connection itself to be deactivated.
     Vector<Connection*> mActiveConnections;
 
-    // List of connections that have timed out.  Only used by dispatchOnce()
-    // We don't use a ref-counted pointer here because it is not possible for a connection
-    // to be unregistered while processing timed out connections since we hold the lock for
-    // the duration.
-    Vector<Connection*> mTimedOutConnections;
-
     // Input channels that will receive a copy of all input events.
     Vector<sp<InputChannel> > mMonitoringChannels;
 
@@ -877,7 +823,7 @@
     void setInjectionResultLocked(EventEntry* entry, int32_t injectionResult);
 
     Condition mInjectionSyncFinishedCondition;
-    void decrementPendingSyncDispatchesLocked(EventEntry* entry);
+    void decrementPendingForegroundDispatchesLocked(EventEntry* entry);
 
     // Throttling state.
     struct ThrottleState {
@@ -905,8 +851,8 @@
 
     // Inbound event processing.
     void drainInboundQueueLocked();
-    void releasePendingEventLocked(bool wasDropped);
-    void releaseInboundEventLocked(EventEntry* entry, bool wasDropped);
+    void releasePendingEventLocked();
+    void releaseInboundEventLocked(EventEntry* entry);
     bool isEventFromReliableSourceLocked(EventEntry* entry);
 
     // Dispatch state.
@@ -940,10 +886,10 @@
             nsecs_t currentTime, ConfigurationChangedEntry* entry);
     bool dispatchKeyLocked(
             nsecs_t currentTime, KeyEntry* entry, nsecs_t keyRepeatTimeout,
-            nsecs_t* nextWakeupTime);
+            bool dropEvent, nsecs_t* nextWakeupTime);
     bool dispatchMotionLocked(
             nsecs_t currentTime, MotionEntry* entry,
-            nsecs_t* nextWakeupTime);
+            bool dropEvent, nsecs_t* nextWakeupTime);
     void dispatchEventToCurrentInputTargetsLocked(
             nsecs_t currentTime, EventEntry* entry, bool resumeWithAppendedMotionSample);
 
@@ -951,8 +897,6 @@
     void logOutboundMotionDetailsLocked(const char* prefix, const MotionEntry* entry);
 
     // The input targets that were most recently identified for dispatch.
-    // If there is a synchronous event dispatch in progress, the current input targets will
-    // remain unchanged until the dispatch has completed or been aborted.
     bool mCurrentInputTargetsValid; // false while targets are being recomputed
     Vector<InputTarget> mCurrentInputTargets;
     int32_t mCurrentInputWindowType;
@@ -970,13 +914,14 @@
     bool mInputTargetWaitTimeoutExpired;
 
     // Finding targets for input events.
-    void startFindingTargetsLocked();
-    void finishFindingTargetsLocked(const InputWindow* window);
+    void resetTargetsLocked();
+    void commitTargetsLocked(const InputWindow* window);
     int32_t handleTargetsNotReadyLocked(nsecs_t currentTime, const EventEntry* entry,
             const InputApplication* application, const InputWindow* window,
             nsecs_t* nextWakeupTime);
-    void resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout);
-    nsecs_t getTimeSpentWaitingForApplicationWhileFindingTargetsLocked(nsecs_t currentTime);
+    void resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout,
+            const sp<InputChannel>& inputChannel);
+    nsecs_t getTimeSpentWaitingForApplicationLocked(nsecs_t currentTime);
     void resetANRTimeoutsLocked();
 
     int32_t findFocusedWindowLocked(nsecs_t currentTime, const EventEntry* entry,
@@ -984,14 +929,16 @@
     int32_t findTouchedWindowLocked(nsecs_t currentTime, const MotionEntry* entry,
             nsecs_t* nextWakeupTime, InputWindow** outWindow);
 
-    void addWindowTargetLocked(const InputWindow* window, int32_t targetFlags,
-            nsecs_t timeSpentWaitingForApplication);
+    void addWindowTargetLocked(const InputWindow* window, int32_t targetFlags);
     void addMonitoringTargetsLocked();
     void pokeUserActivityLocked(nsecs_t eventTime, int32_t windowType, int32_t eventType);
     bool checkInjectionPermission(const InputWindow* window,
             int32_t injectorPid, int32_t injectorUid);
     bool isWindowObscuredLocked(const InputWindow* window);
+    bool isWindowFinishedWithPreviousInputLocked(const InputWindow* window);
     void releaseTouchedWindowLocked();
+    String8 getApplicationWindowLabelLocked(const InputApplication* application,
+            const InputWindow* window);
 
     // Manage the dispatch cycle for a single connection.
     // These methods are deliberately not Interruptible because doing all of the work
@@ -1000,20 +947,13 @@
     void prepareDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
             EventEntry* eventEntry, const InputTarget* inputTarget,
             bool resumeWithAppendedMotionSample);
-    void startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
-            nsecs_t timeSpentWaitingForApplication);
+    void startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
     void finishDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
     void startNextDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
-    void timeoutDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
-    void resumeAfterTimeoutDispatchCycleLocked(nsecs_t currentTime,
-            const sp<Connection>& connection, nsecs_t newTimeout);
     void abortDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
             bool broken);
-    void drainOutboundQueueLocked(Connection* connection, DispatchEntry* firstDispatchEntryToDrain);
-    static bool handleReceiveCallback(int receiveFd, int events, void* data);
-
-    // Preempting input dispatch.
-    bool preemptInputDispatchInnerLocked();
+    void drainOutboundQueueLocked(Connection* connection);
+    static int handleReceiveCallback(int receiveFd, int events, void* data);
 
     // Dump state.
     void dumpDispatchStateLocked(String8& dump);
@@ -1027,20 +967,23 @@
     void onDispatchCycleStartedLocked(
             nsecs_t currentTime, const sp<Connection>& connection);
     void onDispatchCycleFinishedLocked(
-            nsecs_t currentTime, const sp<Connection>& connection, bool recoveredFromANR);
-    void onDispatchCycleANRLocked(
             nsecs_t currentTime, const sp<Connection>& connection);
     void onDispatchCycleBrokenLocked(
             nsecs_t currentTime, const sp<Connection>& connection);
+    void onANRLocked(
+            nsecs_t currentTime, const InputApplication* application, const InputWindow* window,
+            nsecs_t eventTime, nsecs_t waitStartTime);
 
     // Outbound policy interactions.
     void doNotifyConfigurationChangedInterruptible(CommandEntry* commandEntry);
     void doNotifyInputChannelBrokenLockedInterruptible(CommandEntry* commandEntry);
-    void doNotifyInputChannelANRLockedInterruptible(CommandEntry* commandEntry);
-    void doNotifyInputChannelRecoveredFromANRLockedInterruptible(CommandEntry* commandEntry);
+    void doNotifyANRLockedInterruptible(CommandEntry* commandEntry);
     void doInterceptKeyBeforeDispatchingLockedInterruptible(CommandEntry* commandEntry);
     void doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry);
-    void doTargetsNotReadyTimeoutLockedInterruptible(CommandEntry* commandEntry);
+
+    // Statistics gathering.
+    void updateDispatchStatisticsLocked(nsecs_t currentTime, const EventEntry* entry,
+            int32_t injectionResult, nsecs_t timeSpentWaitingForApplication);
 };
 
 /* Enqueues and dispatches input events, endlessly. */
diff --git a/include/ui/InputTransport.h b/include/ui/InputTransport.h
index 82831e29..dc9e27a 100644
--- a/include/ui/InputTransport.h
+++ b/include/ui/InputTransport.h
@@ -33,7 +33,6 @@
 #include <semaphore.h>
 #include <ui/Input.h>
 #include <utils/Errors.h>
-#include <utils/PollLoop.h>
 #include <utils/Timers.h>
 #include <utils/RefBase.h>
 #include <utils/String8.h>
diff --git a/include/utils/Looper.h b/include/utils/Looper.h
new file mode 100644
index 0000000..7d90866
--- /dev/null
+++ b/include/utils/Looper.h
@@ -0,0 +1,213 @@
+/*
+ * 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 UTILS_LOOPER_H
+#define UTILS_LOOPER_H
+
+#include <utils/threads.h>
+#include <utils/RefBase.h>
+#include <utils/KeyedVector.h>
+
+#include <android/looper.h>
+
+/*
+ * Declare a concrete type for the NDK's looper forward declaration.
+ */
+struct ALooper {
+};
+
+namespace android {
+
+/**
+ * A polling loop that supports monitoring file descriptor events, optionally
+ * using callbacks.  The implementation uses epoll() internally.
+ *
+ * A looper can be associated with a thread although there is no requirement that it must be.
+ */
+class Looper : public ALooper, public RefBase {
+protected:
+    virtual ~Looper();
+
+public:
+    /**
+     * Creates a looper.
+     *
+     * If allowNonCallbaks is true, the looper will allow file descriptors to be
+     * registered without associated callbacks.  This assumes that the caller of
+     * pollOnce() is prepared to handle callback-less events itself.
+     */
+    Looper(bool allowNonCallbacks);
+
+    /**
+     * Returns whether this looper instance allows the registration of file descriptors
+     * using identifiers instead of callbacks.
+     */
+    bool getAllowNonCallbacks() const;
+
+    /**
+     * Waits for events to be available, with optional timeout in milliseconds.
+     * Invokes callbacks for all file descriptors on which an event occurred.
+     *
+     * If the timeout is zero, returns immediately without blocking.
+     * If the timeout is negative, waits indefinitely until an event appears.
+     *
+     * Returns ALOOPER_POLL_WAKE if the poll was awoken using wake() before
+     * the timeout expired and no callbacks were invoked and no other file
+     * descriptors were ready.
+     *
+     * Returns ALOOPER_POLL_CALLBACK if one or more callbacks were invoked.
+     *
+     * Returns ALOOPER_POLL_TIMEOUT if there was no data before the given
+     * timeout expired.
+     *
+     * Returns ALOOPER_POLL_ERROR if an error occurred.
+     *
+     * Returns a value >= 0 containing an identifier if its file descriptor has data
+     * and it has no callback function (requiring the caller here to handle it).
+     * In this (and only this) case outFd, outEvents and outData will contain the poll
+     * events and data associated with the fd, otherwise they will be set to NULL.
+     *
+     * This method does not return until it has finished invoking the appropriate callbacks
+     * for all file descriptors that were signalled.
+     */
+    int pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData);
+    inline int pollOnce(int timeoutMillis) {
+        return pollOnce(timeoutMillis, NULL, NULL, NULL);
+    }
+
+    /**
+     * Like pollOnce(), but performs all pending callbacks until all
+     * data has been consumed or a file descriptor is available with no callback.
+     * This function will never return ALOOPER_POLL_CALLBACK.
+     */
+    int pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData);
+    inline int pollAll(int timeoutMillis) {
+        return pollAll(timeoutMillis, NULL, NULL, NULL);
+    }
+
+    /**
+     * Wakes the poll asynchronously.
+     *
+     * This method can be called on any thread.
+     * This method returns immediately.
+     */
+    void wake();
+
+    /**
+     * Adds a new file descriptor to be polled by the looper.
+     * If the same file descriptor was previously added, it is replaced.
+     *
+     * "fd" is the file descriptor to be added.
+     * "ident" is an identifier for this event, which is returned from ALooper_pollOnce().
+     * The identifier must be >= 0, or ALOOPER_POLL_CALLBACK if providing a non-NULL callback.
+     * "events" are the poll events to wake up on.  Typically this is ALOOPER_EVENT_INPUT.
+     * "callback" is the function to call when there is an event on the file descriptor.
+     * "data" is a private data pointer to supply to the callback.
+     *
+     * There are two main uses of this function:
+     *
+     * (1) If "callback" is non-NULL, then this function will be called when there is
+     * data on the file descriptor.  It should execute any events it has pending,
+     * appropriately reading from the file descriptor.  The 'ident' is ignored in this case.
+     *
+     * (2) If "callback" is NULL, the 'ident' will be returned by ALooper_pollOnce
+     * when its file descriptor has data available, requiring the caller to take
+     * care of processing it.
+     *
+     * Returns 1 if the file descriptor was added, 0 if the arguments were invalid.
+     *
+     * This method can be called on any thread.
+     * This method may block briefly if it needs to wake the poll.
+     */
+    int addFd(int fd, int ident, int events, ALooper_callbackFunc callback, void* data);
+
+    /**
+     * Removes a previously added file descriptor from the looper.
+     *
+     * When this method returns, it is safe to close the file descriptor since the looper
+     * will no longer have a reference to it.  However, it is possible for the callback to
+     * already be running or for it to run one last time if the file descriptor was already
+     * signalled.  Calling code is responsible for ensuring that this case is safely handled.
+     * For example, if the callback takes care of removing itself during its own execution either
+     * by returning 0 or by calling this method, then it can be guaranteed to not be invoked
+     * again at any later time unless registered anew.
+     *
+     * Returns 1 if the file descriptor was removed, 0 if none was previously registered.
+     *
+     * This method can be called on any thread.
+     * This method may block briefly if it needs to wake the poll.
+     */
+    int removeFd(int fd);
+
+    /**
+     * Prepares a looper associated with the calling thread, and returns it.
+     * If the thread already has a looper, it is returned.  Otherwise, a new
+     * one is created, associated with the thread, and returned.
+     *
+     * The opts may be ALOOPER_PREPARE_ALLOW_NON_CALLBACKS or 0.
+     */
+    static sp<Looper> prepare(int opts);
+
+    /**
+     * Sets the given looper to be associated with the calling thread.
+     * If another looper is already associated with the thread, it is replaced.
+     *
+     * If "looper" is NULL, removes the currently associated looper.
+     */
+    static void setForThread(const sp<Looper>& looper);
+
+    /**
+     * Returns the looper associated with the calling thread, or NULL if
+     * there is not one.
+     */
+    static sp<Looper> getForThread();
+
+private:
+    struct Request {
+        int fd;
+        int ident;
+        ALooper_callbackFunc callback;
+        void* data;
+    };
+
+    struct Response {
+        int events;
+        Request request;
+    };
+
+    const bool mAllowNonCallbacks; // immutable
+
+    int mEpollFd; // immutable
+    int mWakeReadPipeFd;  // immutable
+    int mWakeWritePipeFd; // immutable
+
+    // Locked list of file descriptor monitoring requests.
+    Mutex mLock;
+    KeyedVector<int, Request> mRequests;
+
+    // This state is only used privately by pollOnce and does not require a lock since
+    // it runs on a single thread.
+    Vector<Response> mResponses;
+    size_t mResponseIndex;
+
+    int pollInner(int timeoutMillis);
+
+    static void threadDestructor(void *st);
+};
+
+} // namespace android
+
+#endif // UTILS_LOOPER_H
diff --git a/include/utils/PollLoop.h b/include/utils/PollLoop.h
deleted file mode 100644
index c2dfe5d..0000000
--- a/include/utils/PollLoop.h
+++ /dev/null
@@ -1,219 +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 UTILS_POLL_LOOP_H
-#define UTILS_POLL_LOOP_H
-
-#include <utils/Vector.h>
-#include <utils/threads.h>
-
-#include <sys/poll.h>
-
-#include <android/looper.h>
-
-struct ALooper : public android::RefBase {
-protected:
-    virtual ~ALooper() { }
-
-public:
-    ALooper() { }
-};
-
-namespace android {
-
-/**
- * A basic file descriptor polling loop based on poll() with callbacks.
- */
-class PollLoop : public ALooper {
-protected:
-    virtual ~PollLoop();
-
-public:
-    PollLoop(bool allowNonCallbacks);
-
-    /**
-     * A callback that it to be invoked when an event occurs on a file descriptor.
-     * Specifies the events that were triggered and the user data provided when the
-     * callback was set.
-     *
-     * Returns true if the callback should be kept, false if it should be removed automatically
-     * after the callback returns.
-     */
-    typedef bool (*Callback)(int fd, int events, void* data);
-
-    enum {
-        POLL_CALLBACK = ALOOPER_POLL_CALLBACK,
-        POLL_TIMEOUT = ALOOPER_POLL_TIMEOUT,
-        POLL_ERROR = ALOOPER_POLL_ERROR,
-    };
-    
-    /**
-     * Performs a single call to poll() with optional timeout in milliseconds.
-     * Invokes callbacks for all file descriptors on which an event occurred.
-     *
-     * If the timeout is zero, returns immediately without blocking.
-     * If the timeout is negative, waits indefinitely until awoken.
-     *
-     * Returns ALOOPER_POLL_CALLBACK if a callback was invoked.
-     *
-     * Returns ALOOPER_POLL_TIMEOUT if there was no data before the given
-     * timeout expired.
-     *
-     * Returns ALOPER_POLL_ERROR if an error occurred.
-     *
-     * Returns a value >= 0 containing a file descriptor if it has data
-     * and it has no callback function (requiring the caller here to handle it).
-     * In this (and only this) case outEvents and outData will contain the poll
-     * events and data associated with the fd.
-     *
-     * This method must only be called on the thread owning the PollLoop.
-     * This method blocks until either a file descriptor is signalled, a timeout occurs,
-     * or wake() is called.
-     * This method does not return until it has finished invoking the appropriate callbacks
-     * for all file descriptors that were signalled.
-     */
-    int32_t pollOnce(int timeoutMillis, int* outEvents = NULL, void** outData = NULL);
-
-    /**
-     * Wakes the loop asynchronously.
-     *
-     * This method can be called on any thread.
-     * This method returns immediately.
-     */
-    void wake();
-
-    /**
-     * Control whether this PollLoop instance allows using IDs instead
-     * of callbacks.
-     */
-    bool getAllowNonCallbacks() const;
-    
-    /**
-     * Sets the callback for a file descriptor, replacing the existing one, if any.
-     * It is an error to call this method with events == 0 or callback == NULL.
-     *
-     * Note that a callback can be invoked with the POLLERR, POLLHUP or POLLNVAL events
-     * even if it is not explicitly requested when registered.
-     *
-     * This method can be called on any thread.
-     * This method may block briefly if it needs to wake the poll loop.
-     */
-    void setCallback(int fd, int ident, int events, Callback callback, void* data = NULL);
-
-    /**
-     * Convenience for above setCallback when ident is not used.  In this case
-     * the ident is set to POLL_CALLBACK.
-     */
-    void setCallback(int fd, int events, Callback callback, void* data = NULL);
-    
-    /**
-     * Like setCallback(), but for the NDK callback function.
-     */
-    void setLooperCallback(int fd, int ident, int events, ALooper_callbackFunc* callback,
-            void* data);
-    
-    /**
-     * Removes the callback for a file descriptor, if one exists.
-     *
-     * When this method returns, it is safe to close the file descriptor since the poll loop
-     * will no longer have a reference to it.  However, it is possible for the callback to
-     * already be running or for it to run one last time if the file descriptor was already
-     * signalled.  Calling code is responsible for ensuring that this case is safely handled.
-     * For example, if the callback takes care of removing itself during its own execution either
-     * by returning false or calling this method, then it can be guaranteed to not be invoked
-     * again at any later time unless registered anew.
-     *
-     * This method can be called on any thread.
-     * This method may block briefly if it needs to wake the poll loop.
-     *
-     * Returns true if a callback was actually removed, false if none was registered.
-     */
-    bool removeCallback(int fd);
-
-    /**
-     * Set the given PollLoop to be associated with the
-     * calling thread.  There must be a 1:1 relationship between
-     * PollLoop and thread.
-     */
-    static void setForThread(const sp<PollLoop>& pollLoop);
-    
-    /**
-     * Return the PollLoop associated with the calling thread.
-     */
-    static sp<PollLoop> getForThread();
-    
-private:
-    struct RequestedCallback {
-        Callback callback;
-        ALooper_callbackFunc* looperCallback;
-        int ident;
-        void* data;
-    };
-
-    struct PendingCallback {
-        int fd;
-        int ident;
-        int events;
-        Callback callback;
-        ALooper_callbackFunc* looperCallback;
-        void* data;
-    };
-    
-    const bool mAllowNonCallbacks; // immutable
-
-    int mWakeReadPipeFd;  // immutable
-    int mWakeWritePipeFd; // immutable
-
-    // The lock guards state used to track whether there is a poll() in progress and whether
-    // there are any other threads waiting in wakeAndLock().  The condition variables
-    // are used to transfer control among these threads such that all waiters are
-    // serviced before a new poll can begin.
-    // The wakeAndLock() method increments mWaiters, wakes the poll, blocks on mAwake
-    // until mPolling becomes false, then decrements mWaiters again.
-    // The poll() method blocks on mResume until mWaiters becomes 0, then sets
-    // mPolling to true, blocks until the poll completes, then resets mPolling to false
-    // and signals mResume if there are waiters.
-    Mutex mLock;
-    bool mPolling;      // guarded by mLock
-    uint32_t mWaiters;  // guarded by mLock
-    Condition mAwake;   // guarded by mLock
-    Condition mResume;  // guarded by mLock
-
-    // The next two vectors are only mutated when mPolling is false since they must
-    // not be changed while the poll() system call is in progress.  To mutate these
-    // vectors, the poll() must first be awoken then the lock acquired.
-    Vector<struct pollfd> mRequestedFds;
-    Vector<RequestedCallback> mRequestedCallbacks;
-
-    // This state is only used privately by pollOnce and does not require a lock since
-    // it runs on a single thread.
-    Vector<PendingCallback> mPendingCallbacks;
-    Vector<PendingCallback> mPendingFds;
-    size_t mPendingFdsPos;
-    
-    void openWakePipe();
-    void closeWakePipe();
-
-    void setCallbackCommon(int fd, int ident, int events, Callback callback,
-            ALooper_callbackFunc* looperCallback, void* data);
-    ssize_t getRequestIndexLocked(int fd);
-    void wakeAndLock();
-    static void threadDestructor(void *st);
-};
-
-} // namespace android
-
-#endif // UTILS_POLL_LOOP_H
diff --git a/libs/camera/CameraParameters.cpp b/libs/camera/CameraParameters.cpp
index 362d9ee..83e5e57f 100644
--- a/libs/camera/CameraParameters.cpp
+++ b/libs/camera/CameraParameters.cpp
@@ -142,7 +142,7 @@
 const char CameraParameters::FOCUS_MODE_MACRO[] = "macro";
 const char CameraParameters::FOCUS_MODE_FIXED[] = "fixed";
 const char CameraParameters::FOCUS_MODE_EDOF[] = "edof";
-const char CameraParameters::FOCUS_MODE_CONTINUOUS[] = "continuous";
+const char CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO[] = "continuous-video";
 
 CameraParameters::CameraParameters()
                 : mMap()
diff --git a/libs/gui/SensorEventQueue.cpp b/libs/gui/SensorEventQueue.cpp
index 7eb6da5..f935524 100644
--- a/libs/gui/SensorEventQueue.cpp
+++ b/libs/gui/SensorEventQueue.cpp
@@ -21,7 +21,7 @@
 
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
-#include <utils/PollLoop.h>
+#include <utils/Looper.h>
 
 #include <gui/Sensor.h>
 #include <gui/SensorChannel.h>
@@ -70,9 +70,13 @@
 ssize_t SensorEventQueue::read(ASensorEvent* events, size_t numEvents)
 {
     ssize_t size = mSensorChannel->read(events, numEvents*sizeof(events[0]));
+    LOGE_IF(size<0 && size!=-EAGAIN,
+            "SensorChannel::read error (%s)", strerror(-size));
     if (size >= 0) {
         if (size % sizeof(events[0])) {
             // partial read!!! should never happen.
+            LOGE("SensorEventQueue partial read (event-size=%u, read=%d)",
+                    sizeof(events[0]), int(size));
             return -EINVAL;
         }
         // returns number of events read
@@ -81,28 +85,38 @@
     return size;
 }
 
-sp<PollLoop> SensorEventQueue::getPollLoop() const
+sp<Looper> SensorEventQueue::getLooper() const
 {
     Mutex::Autolock _l(mLock);
-    if (mPollLoop == 0) {
-        mPollLoop = new PollLoop(true);
-        mPollLoop->setCallback(getFd(), getFd(), POLLIN, NULL, NULL);
+    if (mLooper == 0) {
+        mLooper = new Looper(true);
+        mLooper->addFd(getFd(), getFd(), ALOOPER_EVENT_INPUT, NULL, NULL);
     }
-    return mPollLoop;
+    return mLooper;
 }
 
 status_t SensorEventQueue::waitForEvent() const
 {
     const int fd = getFd();
-    sp<PollLoop> pollLoop(getPollLoop());
-    int32_t result = pollLoop->pollOnce(-1, NULL, NULL);
-    return (result == fd) ? NO_ERROR : -1;
+    sp<Looper> looper(getLooper());
+
+    int32_t result;
+    do {
+        result = looper->pollOnce(-1);
+        if (result == ALOOPER_EVENT_ERROR) {
+            LOGE("SensorChannel::waitForEvent error (errno=%d)", errno);
+            result = -EPIPE; // unknown error, so we make up one
+            break;
+        }
+    } while (result != fd);
+
+    return  (result == fd) ? status_t(NO_ERROR) : result;
 }
 
 status_t SensorEventQueue::wake() const
 {
-    sp<PollLoop> pollLoop(getPollLoop());
-    pollLoop->wake();
+    sp<Looper> looper(getLooper());
+    looper->wake();
     return NO_ERROR;
 }
 
diff --git a/libs/surfaceflinger_client/Surface.cpp b/libs/surfaceflinger_client/Surface.cpp
index cb76091..560ea67 100644
--- a/libs/surfaceflinger_client/Surface.cpp
+++ b/libs/surfaceflinger_client/Surface.cpp
@@ -32,6 +32,7 @@
 #include <ui/DisplayInfo.h>
 #include <ui/GraphicBuffer.h>
 #include <ui/GraphicBufferMapper.h>
+#include <ui/GraphicLog.h>
 #include <ui/Rect.h>
 
 #include <surfaceflinger/Surface.h>
@@ -568,7 +569,13 @@
     if (err != NO_ERROR)
         return err;
 
+    GraphicLog& logger(GraphicLog::getInstance());
+    logger.log(GraphicLog::SF_APP_DEQUEUE_BEFORE, mIdentity, -1);
+
     ssize_t bufIdx = mSharedBufferClient->dequeue();
+
+    logger.log(GraphicLog::SF_APP_DEQUEUE_AFTER, mIdentity, bufIdx);
+
     if (bufIdx < 0) {
         LOGE("error dequeuing a buffer (%s)", strerror(bufIdx));
         return bufIdx;
@@ -617,13 +624,20 @@
         return err;
 
     int32_t bufIdx = getBufferIndex(GraphicBuffer::getSelf(buffer));
+
+    GraphicLog& logger(GraphicLog::getInstance());
+    logger.log(GraphicLog::SF_APP_LOCK_BEFORE, mIdentity, bufIdx);
+
     err = mSharedBufferClient->lock(bufIdx);
+
+    logger.log(GraphicLog::SF_APP_LOCK_AFTER, mIdentity, bufIdx);
+
     LOGE_IF(err, "error locking buffer %d (%s)", bufIdx, strerror(-err));
     return err;
 }
 
 int Surface::queueBuffer(android_native_buffer_t* buffer)
-{   
+{
     status_t err = validate();
     if (err != NO_ERROR)
         return err;
@@ -633,6 +647,9 @@
     }
     
     int32_t bufIdx = getBufferIndex(GraphicBuffer::getSelf(buffer));
+
+    GraphicLog::getInstance().log(GraphicLog::SF_APP_QUEUE, mIdentity, bufIdx);
+
     mSharedBufferClient->setTransform(bufIdx, mNextBufferTransform);
     mSharedBufferClient->setCrop(bufIdx, mNextBufferCrop);
     mSharedBufferClient->setDirtyRegion(bufIdx, mDirtyRegion);
diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk
index 9f49348..c4a09d6 100644
--- a/libs/ui/Android.mk
+++ b/libs/ui/Android.mk
@@ -9,6 +9,7 @@
 	GraphicBuffer.cpp \
 	GraphicBufferAllocator.cpp \
 	GraphicBufferMapper.cpp \
+	GraphicLog.cpp \
 	KeyLayoutMap.cpp \
 	KeyCharacterMap.cpp \
 	Input.cpp \
diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp
index 6f8948d..a36d555 100644
--- a/libs/ui/FramebufferNativeWindow.cpp
+++ b/libs/ui/FramebufferNativeWindow.cpp
@@ -29,6 +29,7 @@
 
 #include <ui/Rect.h>
 #include <ui/FramebufferNativeWindow.h>
+#include <ui/GraphicLog.h>
 
 #include <EGL/egl.h>
 
@@ -174,6 +175,14 @@
     return fb->setSwapInterval(fb, interval);
 }
 
+// only for debugging / logging
+int FramebufferNativeWindow::getCurrentBufferIndex() const
+{
+    Mutex::Autolock _l(mutex);
+    const int index = mCurrentBufferIndex;
+    return index;
+}
+
 int FramebufferNativeWindow::dequeueBuffer(ANativeWindow* window, 
         android_native_buffer_t** buffer)
 {
@@ -181,18 +190,24 @@
     Mutex::Autolock _l(self->mutex);
     framebuffer_device_t* fb = self->fbDev;
 
+    int index = self->mBufferHead++;
+    if (self->mBufferHead >= self->mNumBuffers)
+        self->mBufferHead = 0;
+
+    GraphicLog& logger(GraphicLog::getInstance());
+    logger.log(GraphicLog::SF_FB_DEQUEUE_BEFORE, index);
+
     // wait for a free buffer
     while (!self->mNumFreeBuffers) {
         self->mCondition.wait(self->mutex);
     }
     // get this buffer
     self->mNumFreeBuffers--;
-    int index = self->mBufferHead++;
-    if (self->mBufferHead >= self->mNumBuffers)
-        self->mBufferHead = 0;
+    self->mCurrentBufferIndex = index;
 
     *buffer = self->buffers[index].get();
 
+    logger.log(GraphicLog::SF_FB_DEQUEUE_AFTER, index);
     return 0;
 }
 
@@ -202,11 +217,17 @@
     FramebufferNativeWindow* self = getSelf(window);
     Mutex::Autolock _l(self->mutex);
 
+    const int index = self->mCurrentBufferIndex;
+    GraphicLog& logger(GraphicLog::getInstance());
+    logger.log(GraphicLog::SF_FB_LOCK_BEFORE, index);
+
     // wait that the buffer we're locking is not front anymore
     while (self->front == buffer) {
         self->mCondition.wait(self->mutex);
     }
 
+    logger.log(GraphicLog::SF_FB_LOCK_AFTER, index);
+
     return NO_ERROR;
 }
 
@@ -217,7 +238,15 @@
     Mutex::Autolock _l(self->mutex);
     framebuffer_device_t* fb = self->fbDev;
     buffer_handle_t handle = static_cast<NativeBuffer*>(buffer)->handle;
+
+    const int index = self->mCurrentBufferIndex;
+    GraphicLog& logger(GraphicLog::getInstance());
+    logger.log(GraphicLog::SF_FB_POST_BEFORE, index);
+
     int res = fb->post(fb, handle);
+
+    logger.log(GraphicLog::SF_FB_POST_AFTER, index);
+
     self->front = static_cast<NativeBuffer*>(buffer);
     self->mNumFreeBuffers++;
     self->mCondition.broadcast();
diff --git a/libs/ui/GraphicLog.cpp b/libs/ui/GraphicLog.cpp
new file mode 100644
index 0000000..7ba2779
--- /dev/null
+++ b/libs/ui/GraphicLog.cpp
@@ -0,0 +1,92 @@
+/*
+ * 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 <stdlib.h>
+#include <unistd.h>
+#include <cutils/log.h>
+#include <cutils/properties.h>
+#include <utils/Endian.h>
+#include <utils/Timers.h>
+
+#include <ui/GraphicLog.h>
+
+namespace android {
+
+ANDROID_SINGLETON_STATIC_INSTANCE(GraphicLog)
+
+static inline
+void writeInt32(uint8_t* base, size_t& pos, int32_t value) {
+#ifdef HAVE_LITTLE_ENDIAN
+    int32_t v = value;
+#else
+    int32_t v = htole32(value);
+#endif
+    base[pos] = EVENT_TYPE_INT;
+    memcpy(&base[pos+1], &v, sizeof(int32_t));
+    pos += 1+sizeof(int32_t);
+}
+
+static inline
+void writeInt64(uint8_t* base,  size_t& pos, int64_t value) {
+#ifdef HAVE_LITTLE_ENDIAN
+    int64_t v = value;
+#else
+    int64_t v = htole64(value);
+#endif
+    base[pos] = EVENT_TYPE_LONG;
+    memcpy(&base[pos+1], &v, sizeof(int64_t));
+    pos += 1+sizeof(int64_t);
+}
+
+void GraphicLog::logImpl(int32_t tag, int32_t buffer)
+{
+    uint8_t scratch[2 + 2 + sizeof(int32_t) + sizeof(int64_t)];
+    size_t pos = 0;
+    scratch[pos++] = EVENT_TYPE_LIST;
+    scratch[pos++] = 2;
+    writeInt32(scratch, pos, buffer);
+    writeInt64(scratch, pos, ns2ms( systemTime( SYSTEM_TIME_MONOTONIC ) ));
+    android_bWriteLog(tag, scratch, sizeof(scratch));
+}
+
+void GraphicLog::logImpl(int32_t tag, int32_t identity, int32_t buffer)
+{
+    uint8_t scratch[2 + 3 + sizeof(int32_t) + sizeof(int32_t) + sizeof(int64_t)];
+    size_t pos = 0;
+    scratch[pos++] = EVENT_TYPE_LIST;
+    scratch[pos++] = 3;
+    writeInt32(scratch, pos, buffer);
+    writeInt32(scratch, pos, identity);
+    writeInt64(scratch, pos, ns2ms( systemTime( SYSTEM_TIME_MONOTONIC ) ));
+    android_bWriteLog(tag, scratch, sizeof(scratch));
+}
+
+GraphicLog::GraphicLog()
+    : mEnabled(0)
+{
+    char property[PROPERTY_VALUE_MAX];
+    if (property_get("debug.graphic_log", property, NULL) > 0) {
+        mEnabled = atoi(property);
+    }
+}
+
+void GraphicLog::setEnabled(bool enable)
+{
+    mEnabled = enable;
+}
+
+}
diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp
index b8a26b0..1cf7592 100644
--- a/libs/ui/InputDispatcher.cpp
+++ b/libs/ui/InputDispatcher.cpp
@@ -95,7 +95,7 @@
     mFocusedApplication(NULL),
     mCurrentInputTargetsValid(false),
     mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) {
-    mPollLoop = new PollLoop(false);
+    mLooper = new Looper(false);
 
     mInboundQueue.headSentinel.refCount = -1;
     mInboundQueue.headSentinel.type = EventEntry::TYPE_SENTINEL;
@@ -122,7 +122,7 @@
         AutoMutex _l(mLock);
 
         resetKeyRepeatLocked();
-        releasePendingEventLocked(true);
+        releasePendingEventLocked();
         drainInboundQueueLocked();
     }
 
@@ -156,7 +156,7 @@
         timeoutMillis = 0;
     }
 
-    mPollLoop->pollOnce(timeoutMillis);
+    mLooper->pollOnce(timeoutMillis);
 }
 
 void InputDispatcher::dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout,
@@ -174,7 +174,7 @@
     if (! mDispatchEnabled) {
         if (mPendingEvent || ! mInboundQueue.isEmpty()) {
             LOGI("Dropping pending events because input dispatch is disabled.");
-            releasePendingEventLocked(true);
+            releasePendingEventLocked();
             drainInboundQueueLocked();
         }
         return;
@@ -196,42 +196,6 @@
         *nextWakeupTime = mAppSwitchDueTime;
     }
 
-    // Detect and process timeouts for all connections and determine if there are any
-    // synchronous event dispatches pending.  This step is entirely non-interruptible.
-    bool havePendingSyncTarget = false;
-    size_t activeConnectionCount = mActiveConnections.size();
-    for (size_t i = 0; i < activeConnectionCount; i++) {
-        Connection* connection = mActiveConnections.itemAt(i);
-
-        if (connection->hasPendingSyncTarget()) {
-            if (isAppSwitchDue) {
-                connection->preemptSyncTarget();
-            } else {
-                havePendingSyncTarget = true;
-            }
-        }
-
-        nsecs_t connectionTimeoutTime  = connection->nextTimeoutTime;
-        if (connectionTimeoutTime <= currentTime) {
-            mTimedOutConnections.add(connection);
-        } else if (connectionTimeoutTime < *nextWakeupTime) {
-            *nextWakeupTime = connectionTimeoutTime;
-        }
-    }
-
-    size_t timedOutConnectionCount = mTimedOutConnections.size();
-    for (size_t i = 0; i < timedOutConnectionCount; i++) {
-        Connection* connection = mTimedOutConnections.itemAt(i);
-        timeoutDispatchCycleLocked(currentTime, connection);
-        *nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately
-    }
-    mTimedOutConnections.clear();
-
-    // If we have a pending synchronous target, skip dispatch.
-    if (havePendingSyncTarget) {
-        return;
-    }
-
     // Ready to start a new event.
     // If we don't already have a pending event, go grab one.
     if (! mPendingEvent) {
@@ -317,51 +281,50 @@
 
     // Now we have an event to dispatch.
     assert(mPendingEvent != NULL);
-    bool wasDispatched = false;
-    bool wasDropped = false;
+    bool done = false;
     switch (mPendingEvent->type) {
     case EventEntry::TYPE_CONFIGURATION_CHANGED: {
         ConfigurationChangedEntry* typedEntry =
                 static_cast<ConfigurationChangedEntry*>(mPendingEvent);
-        wasDispatched = dispatchConfigurationChangedLocked(currentTime, typedEntry);
+        done = dispatchConfigurationChangedLocked(currentTime, typedEntry);
         break;
     }
 
     case EventEntry::TYPE_KEY: {
         KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent);
-        if (isAppSwitchPendingLocked()) {
-            if (isAppSwitchKey(typedEntry->keyCode)) {
+        bool appSwitchKey = isAppSwitchKey(typedEntry->keyCode);
+        bool dropEvent = isAppSwitchDue && ! appSwitchKey;
+        done = dispatchKeyLocked(currentTime, typedEntry, keyRepeatTimeout, dropEvent,
+                nextWakeupTime);
+        if (done) {
+            if (dropEvent) {
+                LOGI("Dropped key because of pending overdue app switch.");
+            } else if (appSwitchKey) {
                 resetPendingAppSwitchLocked(true);
-            } else if (isAppSwitchDue) {
-                LOGI("Dropping key because of pending overdue app switch.");
-                wasDropped = true;
-                break;
             }
         }
-        wasDispatched = dispatchKeyLocked(currentTime, typedEntry, keyRepeatTimeout,
-                nextWakeupTime);
         break;
     }
 
     case EventEntry::TYPE_MOTION: {
         MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);
-        if (isAppSwitchDue) {
-            LOGI("Dropping motion because of pending overdue app switch.");
-            wasDropped = true;
-            break;
+        bool dropEvent = isAppSwitchDue;
+        done = dispatchMotionLocked(currentTime, typedEntry, dropEvent, nextWakeupTime);
+        if (done) {
+            if (dropEvent) {
+                LOGI("Dropped motion because of pending overdue app switch.");
+            }
         }
-        wasDispatched = dispatchMotionLocked(currentTime, typedEntry, nextWakeupTime);
         break;
     }
 
     default:
         assert(false);
-        wasDropped = true;
         break;
     }
 
-    if (wasDispatched || wasDropped) {
-        releasePendingEventLocked(wasDropped);
+    if (done) {
+        releasePendingEventLocked();
         *nextWakeupTime = LONG_LONG_MIN;  // force next poll to wake up immediately
     }
 }
@@ -439,21 +402,21 @@
 void InputDispatcher::drainInboundQueueLocked() {
     while (! mInboundQueue.isEmpty()) {
         EventEntry* entry = mInboundQueue.dequeueAtHead();
-        releaseInboundEventLocked(entry, true /*wasDropped*/);
+        releaseInboundEventLocked(entry);
     }
 }
 
-void InputDispatcher::releasePendingEventLocked(bool wasDropped) {
+void InputDispatcher::releasePendingEventLocked() {
     if (mPendingEvent) {
-        releaseInboundEventLocked(mPendingEvent, wasDropped);
+        releaseInboundEventLocked(mPendingEvent);
         mPendingEvent = NULL;
     }
 }
 
-void InputDispatcher::releaseInboundEventLocked(EventEntry* entry, bool wasDropped) {
-    if (wasDropped) {
+void InputDispatcher::releaseInboundEventLocked(EventEntry* entry) {
+    if (entry->injectionResult == INPUT_EVENT_INJECTION_PENDING) {
 #if DEBUG_DISPATCH_CYCLE
-        LOGD("Pending event was dropped.");
+        LOGD("Inbound event was dropped.  Setting injection result to failed.");
 #endif
         setInjectionResultLocked(entry, INPUT_EVENT_INJECTION_FAILED);
     }
@@ -528,7 +491,41 @@
 
 bool InputDispatcher::dispatchKeyLocked(
         nsecs_t currentTime, KeyEntry* entry, nsecs_t keyRepeatTimeout,
-        nsecs_t* nextWakeupTime) {
+        bool dropEvent, nsecs_t* nextWakeupTime) {
+    // Give the policy a chance to intercept the key.
+    if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) {
+        bool trusted;
+        if (! dropEvent && mFocusedWindow) {
+            trusted = checkInjectionPermission(mFocusedWindow,
+                    entry->injectorPid, entry->injectorUid);
+        } else {
+            trusted = isEventFromReliableSourceLocked(entry);
+        }
+        if (trusted) {
+            CommandEntry* commandEntry = postCommandLocked(
+                    & InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);
+            if (! dropEvent && mFocusedWindow) {
+                commandEntry->inputChannel = mFocusedWindow->inputChannel;
+            }
+            commandEntry->keyEntry = entry;
+            entry->refCount += 1;
+            return false; // wait for the command to run
+        } else {
+            entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;
+        }
+    } else if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_SKIP) {
+        resetTargetsLocked();
+        setInjectionResultLocked(entry, INPUT_EVENT_INJECTION_SUCCEEDED);
+        return true;
+    }
+
+    // Clean up if dropping the event.
+    if (dropEvent) {
+        resetTargetsLocked();
+        setInjectionResultLocked(entry, INPUT_EVENT_INJECTION_FAILED);
+        return true;
+    }
+
     // Preprocessing.
     if (! entry->dispatchInProgress) {
         logOutboundKeyDetailsLocked("dispatchKey - ", entry);
@@ -557,7 +554,7 @@
         }
 
         entry->dispatchInProgress = true;
-        startFindingTargetsLocked();
+        resetTargetsLocked();
     }
 
     // Identify targets.
@@ -575,20 +572,7 @@
         }
 
         addMonitoringTargetsLocked();
-        finishFindingTargetsLocked(window);
-    }
-
-    // Give the policy a chance to intercept the key.
-    if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) {
-        CommandEntry* commandEntry = postCommandLocked(
-                & InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);
-        commandEntry->inputChannel = mCurrentInputChannel;
-        commandEntry->keyEntry = entry;
-        entry->refCount += 1;
-        return false; // wait for the command to run
-    }
-    if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_SKIP) {
-        return true;
+        commitTargetsLocked(window);
     }
 
     // Dispatch the key.
@@ -612,13 +596,20 @@
 }
 
 bool InputDispatcher::dispatchMotionLocked(
-        nsecs_t currentTime, MotionEntry* entry, nsecs_t* nextWakeupTime) {
+        nsecs_t currentTime, MotionEntry* entry, bool dropEvent, nsecs_t* nextWakeupTime) {
+    // Clean up if dropping the event.
+    if (dropEvent) {
+        resetTargetsLocked();
+        setInjectionResultLocked(entry, INPUT_EVENT_INJECTION_FAILED);
+        return true;
+    }
+
     // Preprocessing.
     if (! entry->dispatchInProgress) {
         logOutboundMotionDetailsLocked("dispatchMotion - ", entry);
 
         entry->dispatchInProgress = true;
-        startFindingTargetsLocked();
+        resetTargetsLocked();
     }
 
     bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER;
@@ -646,7 +637,7 @@
         }
 
         addMonitoringTargetsLocked();
-        finishFindingTargetsLocked(window);
+        commitTargetsLocked(window);
     }
 
     // Dispatch the motion.
@@ -728,7 +719,7 @@
     for (size_t i = 0; i < mCurrentInputTargets.size(); i++) {
         const InputTarget& inputTarget = mCurrentInputTargets.itemAt(i);
 
-        ssize_t connectionIndex = getConnectionIndex(inputTarget.inputChannel);
+        ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
         if (connectionIndex >= 0) {
             sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
             prepareDispatchCycleLocked(currentTime, connection, eventEntry, & inputTarget,
@@ -741,14 +732,14 @@
     }
 }
 
-void InputDispatcher::startFindingTargetsLocked() {
+void InputDispatcher::resetTargetsLocked() {
     mCurrentInputTargetsValid = false;
     mCurrentInputTargets.clear();
     mCurrentInputChannel.clear();
     mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_NONE;
 }
 
-void InputDispatcher::finishFindingTargetsLocked(const InputWindow* window) {
+void InputDispatcher::commitTargetsLocked(const InputWindow* window) {
     mCurrentInputWindowType = window->layoutParamsType;
     mCurrentInputChannel = window->inputChannel;
     mCurrentInputTargetsValid = true;
@@ -770,9 +761,8 @@
     } else {
         if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) {
 #if DEBUG_FOCUS
-            LOGD("Waiting for application to become ready for input: name=%s, window=%s",
-                    application ? application->name.string() : "<unknown>",
-                    window ? window->inputChannel->getName().string() : "<unknown>");
+            LOGD("Waiting for application to become ready for input: %s",
+                    getApplicationWindowLabelLocked(application, window).string());
 #endif
             nsecs_t timeout = window ? window->dispatchingTimeout :
                 application ? application->dispatchingTimeout : DEFAULT_INPUT_DISPATCHING_TIMEOUT;
@@ -789,21 +779,7 @@
     }
 
     if (currentTime >= mInputTargetWaitTimeoutTime) {
-        LOGI("Application is not ready for input: name=%s, window=%s,"
-                "%01.1fms since event, %01.1fms since wait started",
-                application ? application->name.string() : "<unknown>",
-                window ? window->inputChannel->getName().string() : "<unknown>",
-                (currentTime - entry->eventTime) / 1000000.0,
-                (currentTime - mInputTargetWaitStartTime) / 1000000.0);
-
-        CommandEntry* commandEntry = postCommandLocked(
-                & InputDispatcher::doTargetsNotReadyTimeoutLockedInterruptible);
-        if (application) {
-            commandEntry->inputApplicationHandle = application->handle;
-        }
-        if (window) {
-            commandEntry->inputChannel = window->inputChannel;
-        }
+        onANRLocked(currentTime, application, window, entry->eventTime, mInputTargetWaitStartTime);
 
         // Force poll loop to wake up immediately on next iteration once we get the
         // ANR response back from the policy.
@@ -818,17 +794,30 @@
     }
 }
 
-void InputDispatcher::resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout) {
+void InputDispatcher::resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout,
+        const sp<InputChannel>& inputChannel) {
     if (newTimeout > 0) {
         // Extend the timeout.
         mInputTargetWaitTimeoutTime = now() + newTimeout;
     } else {
         // Give up.
         mInputTargetWaitTimeoutExpired = true;
+
+        // Release the touch target.
+        releaseTouchedWindowLocked();
+
+        // Input state will not be realistic.  Mark it out of sync.
+        if (inputChannel.get()) {
+            ssize_t connectionIndex = getConnectionIndexLocked(inputChannel);
+            if (connectionIndex >= 0) {
+                sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
+                connection->inputState.setOutOfSync();
+            }
+        }
     }
 }
 
-nsecs_t InputDispatcher::getTimeSpentWaitingForApplicationWhileFindingTargetsLocked(
+nsecs_t InputDispatcher::getTimeSpentWaitingForApplicationLocked(
         nsecs_t currentTime) {
     if (mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) {
         return currentTime - mInputTargetWaitStartTime;
@@ -841,13 +830,6 @@
         LOGD("Resetting ANR timeouts.");
 #endif
 
-    // Reset timeouts for all active connections.
-    nsecs_t currentTime = now();
-    for (size_t i = 0; i < mActiveConnections.size(); i++) {
-        Connection* connection = mActiveConnections[i];
-        connection->resetTimeout(currentTime);
-    }
-
     // Reset input target wait timeout.
     mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_NONE;
 }
@@ -865,8 +847,8 @@
         if (mFocusedApplication) {
 #if DEBUG_FOCUS
             LOGD("Waiting because there is no focused window but there is a "
-                    "focused application that may eventually add a window: '%s'.",
-                    mFocusedApplication->name.string());
+                    "focused application that may eventually add a window: %s.",
+                    getApplicationWindowLabelLocked(mFocusedApplication, NULL).string());
 #endif
             injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
                     mFocusedApplication, NULL, nextWakeupTime);
@@ -894,19 +876,31 @@
         goto Unresponsive;
     }
 
+    // If the currently focused window is still working on previous events then keep waiting.
+    if (! isWindowFinishedWithPreviousInputLocked(mFocusedWindow)) {
+#if DEBUG_FOCUS
+        LOGD("Waiting because focused window still processing previous input.");
+#endif
+        injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
+                mFocusedApplication, mFocusedWindow, nextWakeupTime);
+        goto Unresponsive;
+    }
+
     // Success!  Output targets.
     injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
     *outWindow = mFocusedWindow;
-    addWindowTargetLocked(mFocusedWindow, InputTarget::FLAG_SYNC,
-            getTimeSpentWaitingForApplicationWhileFindingTargetsLocked(currentTime));
+    addWindowTargetLocked(mFocusedWindow, InputTarget::FLAG_FOREGROUND);
 
     // Done.
 Failed:
 Unresponsive:
+    nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime);
+    updateDispatchStatisticsLocked(currentTime, entry,
+            injectionResult, timeSpentWaitingForApplication);
 #if DEBUG_FOCUS
-    LOGD("findFocusedWindow finished: injectionResult=%d",
-            injectionResult);
-    logDispatchStateLocked();
+    LOGD("findFocusedWindow finished: injectionResult=%d, "
+            "timeSpendWaitingForApplication=%0.1fms",
+            injectionResult, timeSpentWaitingForApplication / 1000000.0);
 #endif
     return injectionResult;
 }
@@ -1018,8 +1012,8 @@
             if (mFocusedApplication) {
 #if DEBUG_FOCUS
                 LOGD("Waiting because there is no touched window but there is a "
-                        "focused application that may eventually add a new window: '%s'.",
-                        mFocusedApplication->name.string());
+                        "focused application that may eventually add a new window: %s.",
+                        getApplicationWindowLabelLocked(mFocusedApplication, NULL).string());
 #endif
                 injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
                         mFocusedApplication, NULL, nextWakeupTime);
@@ -1051,6 +1045,17 @@
             goto Unresponsive;
         }
 
+        // If the touched window is still working on previous events then keep waiting.
+        if (! isWindowFinishedWithPreviousInputLocked(newTouchedWindow)) {
+#if DEBUG_FOCUS
+            LOGD("Waiting because touched window still processing previous input.");
+#endif
+            injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
+                    NULL, newTouchedWindow, nextWakeupTime);
+            injectionPermission = INJECTION_PERMISSION_GRANTED;
+            goto Unresponsive;
+        }
+
         // Success!  Update the touch dispatch state for real.
         releaseTouchedWindowLocked();
 
@@ -1098,6 +1103,17 @@
             injectionPermission = INJECTION_PERMISSION_GRANTED;
             goto Unresponsive;
         }
+
+        // If the touched window is still working on previous events then keep waiting.
+        if (! isWindowFinishedWithPreviousInputLocked(mTouchedWindow)) {
+#if DEBUG_FOCUS
+            LOGD("Waiting because touched window still processing previous input.");
+#endif
+            injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
+                    NULL, mTouchedWindow, nextWakeupTime);
+            injectionPermission = INJECTION_PERMISSION_GRANTED;
+            goto Unresponsive;
+        }
     }
 
     // Success!  Output targets.
@@ -1108,7 +1124,7 @@
         size_t numWallpaperWindows = mTouchedWallpaperWindows.size();
         for (size_t i = 0; i < numWallpaperWindows; i++) {
             addWindowTargetLocked(mTouchedWallpaperWindows[i],
-                    InputTarget::FLAG_WINDOW_IS_OBSCURED, 0);
+                    InputTarget::FLAG_WINDOW_IS_OBSCURED);
         }
 
         size_t numOutsideTargets = mTempTouchedOutsideTargets.size();
@@ -1118,16 +1134,15 @@
             if (outsideTarget.obscured) {
                 outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
             }
-            addWindowTargetLocked(outsideTarget.window, outsideTargetFlags, 0);
+            addWindowTargetLocked(outsideTarget.window, outsideTargetFlags);
         }
         mTempTouchedOutsideTargets.clear();
 
-        int32_t targetFlags = InputTarget::FLAG_SYNC;
+        int32_t targetFlags = InputTarget::FLAG_FOREGROUND;
         if (mTouchedWindowIsObscured) {
             targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
         }
-        addWindowTargetLocked(mTouchedWindow, targetFlags,
-                getTimeSpentWaitingForApplicationWhileFindingTargetsLocked(currentTime));
+        addWindowTargetLocked(mTouchedWindow, targetFlags);
         *outWindow = mTouchedWindow;
     }
 
@@ -1166,10 +1181,13 @@
     }
 
 Unresponsive:
+    nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime);
+    updateDispatchStatisticsLocked(currentTime, entry,
+            injectionResult, timeSpentWaitingForApplication);
 #if DEBUG_FOCUS
-    LOGD("findTouchedWindow finished: injectionResult=%d, injectionPermission=%d",
-            injectionResult, injectionPermission);
-    logDispatchStateLocked();
+    LOGD("findTouchedWindow finished: injectionResult=%d, injectionPermission=%d,"
+            "timeSpendWaitingForApplication=%0.1fms",
+            injectionResult, injectionPermission, timeSpentWaitingForApplication / 1000000.0);
 #endif
     return injectionResult;
 }
@@ -1180,15 +1198,12 @@
     mTouchedWallpaperWindows.clear();
 }
 
-void InputDispatcher::addWindowTargetLocked(const InputWindow* window, int32_t targetFlags,
-        nsecs_t timeSpentWaitingForApplication) {
+void InputDispatcher::addWindowTargetLocked(const InputWindow* window, int32_t targetFlags) {
     mCurrentInputTargets.push();
 
     InputTarget& target = mCurrentInputTargets.editTop();
     target.inputChannel = window->inputChannel;
     target.flags = targetFlags;
-    target.timeout = window->dispatchingTimeout;
-    target.timeSpentWaitingForApplication = timeSpentWaitingForApplication;
     target.xOffset = - window->frameLeft;
     target.yOffset = - window->frameTop;
 }
@@ -1200,8 +1215,6 @@
         InputTarget& target = mCurrentInputTargets.editTop();
         target.inputChannel = mMonitoringChannels[i];
         target.flags = 0;
-        target.timeout = -1;
-        target.timeSpentWaitingForApplication = 0;
         target.xOffset = 0;
         target.yOffset = 0;
     }
@@ -1241,6 +1254,34 @@
     return false;
 }
 
+bool InputDispatcher::isWindowFinishedWithPreviousInputLocked(const InputWindow* window) {
+    ssize_t connectionIndex = getConnectionIndexLocked(window->inputChannel);
+    if (connectionIndex >= 0) {
+        sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
+        return connection->outboundQueue.isEmpty();
+    } else {
+        return true;
+    }
+}
+
+String8 InputDispatcher::getApplicationWindowLabelLocked(const InputApplication* application,
+        const InputWindow* window) {
+    if (application) {
+        if (window) {
+            String8 label(application->name);
+            label.append(" - ");
+            label.append(window->name);
+            return label;
+        } else {
+            return application->name;
+        }
+    } else if (window) {
+        return window->name;
+    } else {
+        return String8("<unknown application or window>");
+    }
+}
+
 void InputDispatcher::pokeUserActivityLocked(nsecs_t eventTime,
         int32_t windowType, int32_t eventType) {
     CommandEntry* commandEntry = postCommandLocked(
@@ -1254,25 +1295,18 @@
         const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget,
         bool resumeWithAppendedMotionSample) {
 #if DEBUG_DISPATCH_CYCLE
-    LOGD("channel '%s' ~ prepareDispatchCycle - flags=%d, timeout=%lldns, "
+    LOGD("channel '%s' ~ prepareDispatchCycle - flags=%d, "
             "xOffset=%f, yOffset=%f, resumeWithAppendedMotionSample=%s",
-            connection->getInputChannelName(), inputTarget->flags, inputTarget->timeout,
+            connection->getInputChannelName(), inputTarget->flags,
             inputTarget->xOffset, inputTarget->yOffset,
             toString(resumeWithAppendedMotionSample));
 #endif
 
     // Skip this event if the connection status is not normal.
-    // We don't want to enqueue additional outbound events if the connection is broken or
-    // not responding.
+    // We don't want to enqueue additional outbound events if the connection is broken.
     if (connection->status != Connection::STATUS_NORMAL) {
         LOGW("channel '%s' ~ Dropping event because the channel status is %s",
                 connection->getInputChannelName(), connection->getStatusLabel());
-
-        // If the connection is not responding but the user is poking the application anyways,
-        // retrigger the original timeout.
-        if (connection->status == Connection::STATUS_NOT_RESPONDING) {
-            timeoutDispatchCycleLocked(currentTime, connection);
-        }
         return;
     }
 
@@ -1379,7 +1413,7 @@
 
                 DispatchEntry* cancelationDispatchEntry =
                         mAllocator.obtainDispatchEntry(cancelationEventEntry,
-                        0, inputTarget->xOffset, inputTarget->yOffset, inputTarget->timeout);
+                        0, inputTarget->xOffset, inputTarget->yOffset); // increments ref
                 connection->outboundQueue.enqueueAtTail(cancelationDispatchEntry);
 
                 mAllocator.releaseEventEntry(cancelationEventEntry);
@@ -1390,10 +1424,9 @@
     // This is a new event.
     // Enqueue a new dispatch entry onto the outbound queue for this connection.
     DispatchEntry* dispatchEntry = mAllocator.obtainDispatchEntry(eventEntry, // increments ref
-            inputTarget->flags, inputTarget->xOffset, inputTarget->yOffset,
-            inputTarget->timeout);
-    if (dispatchEntry->isSyncTarget()) {
-        eventEntry->pendingSyncDispatches += 1;
+            inputTarget->flags, inputTarget->xOffset, inputTarget->yOffset);
+    if (dispatchEntry->hasForegroundTarget()) {
+        eventEntry->pendingForegroundDispatches += 1;
     }
 
     // Handle the case where we could not stream a new motion sample because the consumer has
@@ -1416,13 +1449,12 @@
     // If the outbound queue was previously empty, start the dispatch cycle going.
     if (wasEmpty) {
         activateConnectionLocked(connection.get());
-        startDispatchCycleLocked(currentTime, connection,
-                inputTarget->timeSpentWaitingForApplication);
+        startDispatchCycleLocked(currentTime, connection);
     }
 }
 
 void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
-        const sp<Connection>& connection, nsecs_t timeSpentWaitingForApplication) {
+        const sp<Connection>& connection) {
 #if DEBUG_DISPATCH_CYCLE
     LOGD("channel '%s' ~ startDispatchCycle",
             connection->getInputChannelName());
@@ -1588,9 +1620,6 @@
     connection->lastEventTime = dispatchEntry->eventEntry->eventTime;
     connection->lastDispatchTime = currentTime;
 
-    nsecs_t timeout = dispatchEntry->timeout - timeSpentWaitingForApplication;
-    connection->setNextTimeoutTime(currentTime, timeout);
-
     // Notify other system components.
     onDispatchCycleStartedLocked(currentTime, connection);
 }
@@ -1610,21 +1639,8 @@
         return;
     }
 
-    // Clear the pending timeout.
-    connection->nextTimeoutTime = LONG_LONG_MAX;
-
-    if (connection->status == Connection::STATUS_NOT_RESPONDING) {
-        // Recovering from an ANR.
-        connection->status = Connection::STATUS_NORMAL;
-
-        // Notify other system components.
-        onDispatchCycleFinishedLocked(currentTime, connection, true /*recoveredFromANR*/);
-    } else {
-        // Normal finish.  Not much to do here.
-
-        // Notify other system components.
-        onDispatchCycleFinishedLocked(currentTime, connection, false /*recoveredFromANR*/);
-    }
+    // Notify other system components.
+    onDispatchCycleFinishedLocked(currentTime, connection);
 
     // Reset the publisher since the event has been consumed.
     // We do this now so that the publisher can release some of its internal resources
@@ -1653,20 +1669,20 @@
                 dispatchEntry->inProgress = false;
                 dispatchEntry->headMotionSample = dispatchEntry->tailMotionSample;
                 dispatchEntry->tailMotionSample = NULL;
-                startDispatchCycleLocked(currentTime, connection, 0);
+                startDispatchCycleLocked(currentTime, connection);
                 return;
             }
             // Finished.
             connection->outboundQueue.dequeueAtHead();
-            if (dispatchEntry->isSyncTarget()) {
-                decrementPendingSyncDispatchesLocked(dispatchEntry->eventEntry);
+            if (dispatchEntry->hasForegroundTarget()) {
+                decrementPendingForegroundDispatchesLocked(dispatchEntry->eventEntry);
             }
             mAllocator.releaseDispatchEntry(dispatchEntry);
         } else {
             // If the head is not in progress, then we must have already dequeued the in
-            // progress event, which means we actually aborted it (due to ANR).
+            // progress event, which means we actually aborted it.
             // So just start the next event for this connection.
-            startDispatchCycleLocked(currentTime, connection, 0);
+            startDispatchCycleLocked(currentTime, connection);
             return;
         }
     }
@@ -1675,66 +1691,6 @@
     deactivateConnectionLocked(connection.get());
 }
 
-void InputDispatcher::timeoutDispatchCycleLocked(nsecs_t currentTime,
-        const sp<Connection>& connection) {
-#if DEBUG_DISPATCH_CYCLE
-    LOGD("channel '%s' ~ timeoutDispatchCycle",
-            connection->getInputChannelName());
-#endif
-
-    if (connection->status == Connection::STATUS_NORMAL) {
-        // Enter the not responding state.
-        connection->status = Connection::STATUS_NOT_RESPONDING;
-        connection->lastANRTime = currentTime;
-    } else if (connection->status != Connection::STATUS_NOT_RESPONDING) {
-        // Connection is broken or dead.
-        return;
-    }
-
-    // Notify other system components.
-    // This enqueues a command which will eventually call resumeAfterTimeoutDispatchCycleLocked.
-    onDispatchCycleANRLocked(currentTime, connection);
-}
-
-void InputDispatcher::resumeAfterTimeoutDispatchCycleLocked(nsecs_t currentTime,
-        const sp<Connection>& connection, nsecs_t newTimeout) {
-#if DEBUG_DISPATCH_CYCLE
-    LOGD("channel '%s' ~ resumeAfterTimeoutDispatchCycleLocked - newTimeout=%lld",
-            connection->getInputChannelName(), newTimeout);
-#endif
-
-    if (connection->status != Connection::STATUS_NOT_RESPONDING) {
-        return;
-    }
-
-    if (newTimeout > 0) {
-        // The system has decided to give the application some more time.
-        // Keep waiting synchronously and resume normal dispatch.
-        connection->status = Connection::STATUS_NORMAL;
-        connection->setNextTimeoutTime(currentTime, newTimeout);
-    } else {
-        // The system is about to throw up an ANR dialog and has requested that we abort dispatch.
-        // Reset the timeout.
-        connection->nextTimeoutTime = LONG_LONG_MAX;
-
-        // Input state will no longer be realistic.
-        connection->inputState.setOutOfSync();
-
-        if (! connection->outboundQueue.isEmpty()) {
-            // Make the current pending dispatch asynchronous (if it isn't already) so that
-            // subsequent events can be delivered to the ANR dialog or to another application.
-            DispatchEntry* currentDispatchEntry = connection->outboundQueue.headSentinel.next;
-            currentDispatchEntry->preemptSyncTarget();
-
-            // Drain all but the first entry in the outbound queue.  We keep the first entry
-            // since that is the one that dispatch is stuck on.  We throw away the others
-            // so that we don't spam the application with stale messages if it eventually
-            // wakes up and recovers from the ANR.
-            drainOutboundQueueLocked(connection.get(), currentDispatchEntry->next);
-        }
-    }
-}
-
 void InputDispatcher::abortDispatchCycleLocked(nsecs_t currentTime,
         const sp<Connection>& connection, bool broken) {
 #if DEBUG_DISPATCH_CYCLE
@@ -1742,20 +1698,16 @@
             connection->getInputChannelName(), toString(broken));
 #endif
 
-    // Clear the pending timeout.
-    connection->nextTimeoutTime = LONG_LONG_MAX;
-
     // Input state will no longer be realistic.
     connection->inputState.setOutOfSync();
 
     // Clear the outbound queue.
-    drainOutboundQueueLocked(connection.get(), connection->outboundQueue.headSentinel.next);
+    drainOutboundQueueLocked(connection.get());
 
     // Handle the case where the connection appears to be unrecoverably broken.
     // Ignore already broken or zombie connections.
     if (broken) {
-        if (connection->status == Connection::STATUS_NORMAL
-                || connection->status == Connection::STATUS_NOT_RESPONDING) {
+        if (connection->status == Connection::STATUS_NORMAL) {
             connection->status = Connection::STATUS_BROKEN;
 
             // Notify other system components.
@@ -1764,27 +1716,19 @@
     }
 }
 
-void InputDispatcher::drainOutboundQueueLocked(Connection* connection,
-        DispatchEntry* firstDispatchEntryToDrain) {
-    for (DispatchEntry* dispatchEntry = firstDispatchEntryToDrain;
-            dispatchEntry != & connection->outboundQueue.tailSentinel;) {
-        DispatchEntry* next = dispatchEntry->next;
-        connection->outboundQueue.dequeue(dispatchEntry);
-
-        if (dispatchEntry->isSyncTarget()) {
-            decrementPendingSyncDispatchesLocked(dispatchEntry->eventEntry);
+void InputDispatcher::drainOutboundQueueLocked(Connection* connection) {
+    while (! connection->outboundQueue.isEmpty()) {
+        DispatchEntry* dispatchEntry = connection->outboundQueue.dequeueAtHead();
+        if (dispatchEntry->hasForegroundTarget()) {
+            decrementPendingForegroundDispatchesLocked(dispatchEntry->eventEntry);
         }
         mAllocator.releaseDispatchEntry(dispatchEntry);
-
-        dispatchEntry = next;
     }
 
-    if (connection->outboundQueue.isEmpty()) {
-        deactivateConnectionLocked(connection);
-    }
+    deactivateConnectionLocked(connection);
 }
 
-bool InputDispatcher::handleReceiveCallback(int receiveFd, int events, void* data) {
+int InputDispatcher::handleReceiveCallback(int receiveFd, int events, void* data) {
     InputDispatcher* d = static_cast<InputDispatcher*>(data);
 
     { // acquire lock
@@ -1794,24 +1738,24 @@
         if (connectionIndex < 0) {
             LOGE("Received spurious receive callback for unknown input channel.  "
                     "fd=%d, events=0x%x", receiveFd, events);
-            return false; // remove the callback
+            return 0; // remove the callback
         }
 
         nsecs_t currentTime = now();
 
         sp<Connection> connection = d->mConnectionsByReceiveFd.valueAt(connectionIndex);
-        if (events & (POLLERR | POLLHUP | POLLNVAL)) {
+        if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
             LOGE("channel '%s' ~ Consumer closed input channel or an error occurred.  "
                     "events=0x%x", connection->getInputChannelName(), events);
             d->abortDispatchCycleLocked(currentTime, connection, true /*broken*/);
             d->runCommandsLockedInterruptible();
-            return false; // remove the callback
+            return 0; // remove the callback
         }
 
-        if (! (events & POLLIN)) {
+        if (! (events & ALOOPER_EVENT_INPUT)) {
             LOGW("channel '%s' ~ Received spurious callback for unhandled poll event.  "
                     "events=0x%x", connection->getInputChannelName(), events);
-            return true;
+            return 1;
         }
 
         status_t status = connection->inputPublisher.receiveFinishedSignal();
@@ -1820,12 +1764,12 @@
                     connection->getInputChannelName(), status);
             d->abortDispatchCycleLocked(currentTime, connection, true /*broken*/);
             d->runCommandsLockedInterruptible();
-            return false; // remove the callback
+            return 0; // remove the callback
         }
 
         d->finishDispatchCycleLocked(currentTime, connection);
         d->runCommandsLockedInterruptible();
-        return true;
+        return 1;
     } // release lock
 }
 
@@ -1843,7 +1787,7 @@
     } // release lock
 
     if (needWake) {
-        mPollLoop->wake();
+        mLooper->wake();
     }
 }
 
@@ -1870,7 +1814,7 @@
     } // release lock
 
     if (needWake) {
-        mPollLoop->wake();
+        mLooper->wake();
     }
 }
 
@@ -1941,56 +1885,63 @@
             // STREAMING CASE
             //
             // There is no pending motion event (of any kind) for this device in the inbound queue.
-            // Search the outbound queues for a synchronously dispatched motion event for this
-            // device.  If found, then we append the new sample to that event and then try to
-            // push it out to all current targets.  It is possible that some targets will already
-            // have consumed the motion event.  This case is automatically handled by the
-            // logic in prepareDispatchCycleLocked by tracking where resumption takes place.
-            //
-            // The reason we look for a synchronously dispatched motion event is because we
-            // want to be sure that no other motion events have been dispatched since the move.
-            // It's also convenient because it means that the input targets are still valid.
-            // This code could be improved to support streaming of asynchronously dispatched
-            // motion events (which might be significantly more efficient) but it may become
-            // a little more complicated as a result.
-            //
-            // Note: This code crucially depends on the invariant that an outbound queue always
-            //       contains at most one synchronous event and it is always last (but it might
-            //       not be first!).
+            // Search the outbound queue for the current foreground targets to find a dispatched
+            // motion event that is still in progress.  If found, then, appen the new sample to
+            // that event and push it out to all current targets.  The logic in
+            // prepareDispatchCycleLocked takes care of the case where some targets may
+            // already have consumed the motion event by starting a new dispatch cycle if needed.
             if (mCurrentInputTargetsValid) {
-                for (size_t i = 0; i < mActiveConnections.size(); i++) {
-                    Connection* connection = mActiveConnections.itemAt(i);
-                    if (! connection->outboundQueue.isEmpty()) {
-                        DispatchEntry* dispatchEntry = connection->outboundQueue.tailSentinel.prev;
-                        if (dispatchEntry->isSyncTarget()) {
-                            if (dispatchEntry->eventEntry->type != EventEntry::TYPE_MOTION) {
-                                goto NoBatchingOrStreaming;
-                            }
-
-                            MotionEntry* syncedMotionEntry = static_cast<MotionEntry*>(
-                                    dispatchEntry->eventEntry);
-                            if (syncedMotionEntry->action != AMOTION_EVENT_ACTION_MOVE
-                                    || syncedMotionEntry->deviceId != deviceId
-                                    || syncedMotionEntry->pointerCount != pointerCount
-                                    || syncedMotionEntry->isInjected()) {
-                                goto NoBatchingOrStreaming;
-                            }
-
-                            // Found synced move entry.  Append sample and resume dispatch.
-                            mAllocator.appendMotionSample(syncedMotionEntry, eventTime,
-                                    pointerCoords);
-    #if DEBUG_BATCHING
-                            LOGD("Appended motion sample onto batch for most recent synchronously "
-                                    "dispatched motion event for this device in the outbound queues.");
-    #endif
-                            nsecs_t currentTime = now();
-                            dispatchEventToCurrentInputTargetsLocked(currentTime, syncedMotionEntry,
-                                    true /*resumeWithAppendedMotionSample*/);
-
-                            runCommandsLockedInterruptible();
-                            return; // done!
-                        }
+                for (size_t i = 0; i < mCurrentInputTargets.size(); i++) {
+                    const InputTarget& inputTarget = mCurrentInputTargets[i];
+                    if ((inputTarget.flags & InputTarget::FLAG_FOREGROUND) == 0) {
+                        // Skip non-foreground targets.  We only want to stream if there is at
+                        // least one foreground target whose dispatch is still in progress.
+                        continue;
                     }
+
+                    ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
+                    if (connectionIndex < 0) {
+                        // Connection must no longer be valid.
+                        continue;
+                    }
+
+                    sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
+                    if (connection->outboundQueue.isEmpty()) {
+                        // This foreground target has an empty outbound queue.
+                        continue;
+                    }
+
+                    DispatchEntry* dispatchEntry = connection->outboundQueue.headSentinel.next;
+                    if (! dispatchEntry->inProgress
+                            || dispatchEntry->eventEntry->type != EventEntry::TYPE_MOTION) {
+                        // No motion event is being dispatched.
+                        continue;
+                    }
+
+                    MotionEntry* motionEntry = static_cast<MotionEntry*>(
+                            dispatchEntry->eventEntry);
+                    if (motionEntry->action != AMOTION_EVENT_ACTION_MOVE
+                            || motionEntry->deviceId != deviceId
+                            || motionEntry->pointerCount != pointerCount
+                            || motionEntry->isInjected()) {
+                        // The motion event is not compatible with this move.
+                        continue;
+                    }
+
+                    // Hurray!  This foreground target is currently dispatching a move event
+                    // that we can stream onto.  Append the motion sample and resume dispatch.
+                    mAllocator.appendMotionSample(motionEntry, eventTime, pointerCoords);
+#if DEBUG_BATCHING
+                    LOGD("Appended motion sample onto batch for most recently dispatched "
+                            "motion event for this device in the outbound queues.  "
+                            "Attempting to stream the motion sample.");
+#endif
+                    nsecs_t currentTime = now();
+                    dispatchEventToCurrentInputTargetsLocked(currentTime, motionEntry,
+                            true /*resumeWithAppendedMotionSample*/);
+
+                    runCommandsLockedInterruptible();
+                    return; // done!
                 }
             }
 
@@ -2007,7 +1958,7 @@
     } // release lock
 
     if (needWake) {
-        mPollLoop->wake();
+        mLooper->wake();
     }
 }
 
@@ -2043,7 +1994,7 @@
     } // release lock
 
     if (needWake) {
-        mPollLoop->wake();
+        mLooper->wake();
     }
 
     int32_t injectionResult;
@@ -2074,15 +2025,15 @@
 
             if (injectionResult == INPUT_EVENT_INJECTION_SUCCEEDED
                     && syncMode == INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISHED) {
-                while (injectedEntry->pendingSyncDispatches != 0) {
+                while (injectedEntry->pendingForegroundDispatches != 0) {
 #if DEBUG_INJECTION
-                    LOGD("injectInputEvent - Waiting for %d pending synchronous dispatches.",
-                            injectedEntry->pendingSyncDispatches);
+                    LOGD("injectInputEvent - Waiting for %d pending foreground dispatches.",
+                            injectedEntry->pendingForegroundDispatches);
 #endif
                     nsecs_t remainingTimeout = endTime - now();
                     if (remainingTimeout <= 0) {
 #if DEBUG_INJECTION
-                    LOGD("injectInputEvent - Timed out waiting for pending synchronous "
+                    LOGD("injectInputEvent - Timed out waiting for pending foreground "
                             "dispatches to finish.");
 #endif
                         injectionResult = INPUT_EVENT_INJECTION_TIMED_OUT;
@@ -2137,10 +2088,10 @@
     }
 }
 
-void InputDispatcher::decrementPendingSyncDispatchesLocked(EventEntry* entry) {
-    entry->pendingSyncDispatches -= 1;
+void InputDispatcher::decrementPendingForegroundDispatchesLocked(EventEntry* entry) {
+    entry->pendingForegroundDispatches -= 1;
 
-    if (entry->isInjected() && entry->pendingSyncDispatches == 0) {
+    if (entry->isInjected() && entry->pendingForegroundDispatches == 0) {
         mInjectionSyncFinishedCondition.broadcast();
     }
 }
@@ -2238,6 +2189,9 @@
     { // acquire lock
         AutoMutex _l(mLock);
 
+        // Clear old window pointers but remember their associated channels.
+        mFocusedWindow = NULL;
+
         sp<InputChannel> touchedWindowChannel;
         if (mTouchedWindow) {
             touchedWindowChannel = mTouchedWindow->inputChannel;
@@ -2250,13 +2204,11 @@
             }
             mTouchedWallpaperWindows.clear();
         }
-
-        bool hadFocusedWindow = mFocusedWindow != NULL;
-
-        mFocusedWindow = NULL;
         mWallpaperWindows.clear();
-
         mWindows.clear();
+
+        // Loop over new windows and rebuild the necessary window pointers for
+        // tracking focus and touch.
         mWindows.appendVector(inputWindows);
 
         size_t numWindows = mWindows.size();
@@ -2280,21 +2232,15 @@
                 mTouchedWindow = window;
             }
         }
-
         mTempTouchedWallpaperChannels.clear();
 
-        if ((hadFocusedWindow && ! mFocusedWindow)
-                || (mFocusedWindow && ! mFocusedWindow->visible)) {
-            preemptInputDispatchInnerLocked();
-        }
-
 #if DEBUG_FOCUS
         logDispatchStateLocked();
 #endif
     } // release lock
 
     // Wake up poll loop since it may need to make new input dispatching choices.
-    mPollLoop->wake();
+    mLooper->wake();
 }
 
 void InputDispatcher::setFocusedApplication(const InputApplication* inputApplication) {
@@ -2317,7 +2263,7 @@
     } // release lock
 
     // Wake up poll loop since it may need to make new input dispatching choices.
-    mPollLoop->wake();
+    mLooper->wake();
 }
 
 void InputDispatcher::releaseFocusedApplicationLocked() {
@@ -2355,47 +2301,24 @@
 
     if (changed) {
         // Wake up poll loop since it may need to make new input dispatching choices.
-        mPollLoop->wake();
+        mLooper->wake();
     }
 }
 
-void InputDispatcher::preemptInputDispatch() {
-#if DEBUG_FOCUS
-    LOGD("preemptInputDispatch");
-#endif
-
-    bool preemptedOne;
-    { // acquire lock
-        AutoMutex _l(mLock);
-        preemptedOne = preemptInputDispatchInnerLocked();
-    } // release lock
-
-    if (preemptedOne) {
-        // Wake up the poll loop so it can get a head start dispatching the next event.
-        mPollLoop->wake();
-    }
-}
-
-bool InputDispatcher::preemptInputDispatchInnerLocked() {
-    bool preemptedOne = false;
-    for (size_t i = 0; i < mActiveConnections.size(); i++) {
-        Connection* connection = mActiveConnections[i];
-        if (connection->hasPendingSyncTarget()) {
-#if DEBUG_DISPATCH_CYCLE
-            LOGD("channel '%s' ~ Preempted pending synchronous dispatch",
-                    connection->getInputChannelName());
-#endif
-            connection->preemptSyncTarget();
-            preemptedOne = true;
-        }
-    }
-    return preemptedOne;
-}
-
 void InputDispatcher::logDispatchStateLocked() {
     String8 dump;
     dumpDispatchStateLocked(dump);
-    LOGD("%s", dump.string());
+
+    char* text = dump.lockBuffer(dump.size());
+    char* start = text;
+    while (*start != '\0') {
+        char* end = strchr(start, '\n');
+        if (*end == '\n') {
+            *(end++) = '\0';
+        }
+        LOGD("%s", start);
+        start = end;
+    }
 }
 
 void InputDispatcher::dumpDispatchStateLocked(String8& dump) {
@@ -2409,28 +2332,30 @@
     } else {
         dump.append("  focusedApplication: <null>\n");
     }
-    dump.appendFormat("  focusedWindow: '%s'\n",
-            mFocusedWindow != NULL ? mFocusedWindow->inputChannel->getName().string() : "<null>");
-    dump.appendFormat("  touchedWindow: '%s', touchDown=%d\n",
-            mTouchedWindow != NULL ? mTouchedWindow->inputChannel->getName().string() : "<null>",
+    dump.appendFormat("  focusedWindow: name='%s'\n",
+            mFocusedWindow != NULL ? mFocusedWindow->name.string() : "<null>");
+    dump.appendFormat("  touchedWindow: name='%s', touchDown=%d\n",
+            mTouchedWindow != NULL ? mTouchedWindow->name.string() : "<null>",
             mTouchDown);
     for (size_t i = 0; i < mTouchedWallpaperWindows.size(); i++) {
-        dump.appendFormat("  touchedWallpaperWindows[%d]: '%s'\n",
-                i, mTouchedWallpaperWindows[i]->inputChannel->getName().string());
+        dump.appendFormat("  touchedWallpaperWindows[%d]: name='%s'\n",
+                i, mTouchedWallpaperWindows[i]->name.string());
     }
     for (size_t i = 0; i < mWindows.size(); i++) {
-        dump.appendFormat("  windows[%d]: '%s', paused=%s, hasFocus=%s, hasWallpaper=%s, "
-                "visible=%s, flags=0x%08x, type=0x%08x, "
+        dump.appendFormat("  windows[%d]: name='%s', paused=%s, hasFocus=%s, hasWallpaper=%s, "
+                "visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, "
                 "frame=[%d,%d][%d,%d], "
                 "visibleFrame=[%d,%d][%d,%d], "
                 "touchableArea=[%d,%d][%d,%d], "
                 "ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n",
-                i, mWindows[i].inputChannel->getName().string(),
+                i, mWindows[i].name.string(),
                 toString(mWindows[i].paused),
                 toString(mWindows[i].hasFocus),
                 toString(mWindows[i].hasWallpaper),
                 toString(mWindows[i].visible),
+                toString(mWindows[i].canReceiveKeys),
                 mWindows[i].layoutParamsFlags, mWindows[i].layoutParamsType,
+                mWindows[i].layer,
                 mWindows[i].frameLeft, mWindows[i].frameTop,
                 mWindows[i].frameRight, mWindows[i].frameBottom,
                 mWindows[i].visibleFrameLeft, mWindows[i].visibleFrameTop,
@@ -2447,12 +2372,14 @@
                 i, channel->getName().string());
     }
 
+    dump.appendFormat("  inboundQueue: length=%u", mInboundQueue.count());
+
     for (size_t i = 0; i < mActiveConnections.size(); i++) {
         const Connection* connection = mActiveConnections[i];
-        dump.appendFormat("  activeConnection[%d]: '%s', status=%s, hasPendingSyncTarget=%s, "
+        dump.appendFormat("  activeConnection[%d]: '%s', status=%s, outboundQueueLength=%u"
                 "inputState.isNeutral=%s, inputState.isOutOfSync=%s\n",
                 i, connection->getInputChannelName(), connection->getStatusLabel(),
-                toString(connection->hasPendingSyncTarget()),
+                connection->outboundQueue.count(),
                 toString(connection->inputState.isNeutral()),
                 toString(connection->inputState.isOutOfSync()));
     }
@@ -2474,7 +2401,7 @@
     { // acquire lock
         AutoMutex _l(mLock);
 
-        if (getConnectionIndex(inputChannel) >= 0) {
+        if (getConnectionIndexLocked(inputChannel) >= 0) {
             LOGW("Attempted to register already registered input channel '%s'",
                     inputChannel->getName().string());
             return BAD_VALUE;
@@ -2495,7 +2422,7 @@
             mMonitoringChannels.push(inputChannel);
         }
 
-        mPollLoop->setCallback(receiveFd, POLLIN, handleReceiveCallback, this);
+        mLooper->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
 
         runCommandsLockedInterruptible();
     } // release lock
@@ -2510,7 +2437,7 @@
     { // acquire lock
         AutoMutex _l(mLock);
 
-        ssize_t connectionIndex = getConnectionIndex(inputChannel);
+        ssize_t connectionIndex = getConnectionIndexLocked(inputChannel);
         if (connectionIndex < 0) {
             LOGW("Attempted to unregister already unregistered input channel '%s'",
                     inputChannel->getName().string());
@@ -2529,7 +2456,7 @@
             }
         }
 
-        mPollLoop->removeCallback(inputChannel->getReceivePipeFd());
+        mLooper->removeFd(inputChannel->getReceivePipeFd());
 
         nsecs_t currentTime = now();
         abortDispatchCycleLocked(currentTime, connection, true /*broken*/);
@@ -2539,11 +2466,11 @@
 
     // Wake the poll loop because removing the connection may have changed the current
     // synchronization state.
-    mPollLoop->wake();
+    mLooper->wake();
     return OK;
 }
 
-ssize_t InputDispatcher::getConnectionIndex(const sp<InputChannel>& inputChannel) {
+ssize_t InputDispatcher::getConnectionIndexLocked(const sp<InputChannel>& inputChannel) {
     ssize_t connectionIndex = mConnectionsByReceiveFd.indexOfKey(inputChannel->getReceivePipeFd());
     if (connectionIndex >= 0) {
         sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
@@ -2578,31 +2505,7 @@
 }
 
 void InputDispatcher::onDispatchCycleFinishedLocked(
-        nsecs_t currentTime, const sp<Connection>& connection, bool recoveredFromANR) {
-    if (recoveredFromANR) {
-        LOGI("channel '%s' ~ Recovered from ANR.  %01.1fms since event, "
-                "%01.1fms since dispatch, %01.1fms since ANR",
-                connection->getInputChannelName(),
-                connection->getEventLatencyMillis(currentTime),
-                connection->getDispatchLatencyMillis(currentTime),
-                connection->getANRLatencyMillis(currentTime));
-
-        CommandEntry* commandEntry = postCommandLocked(
-                & InputDispatcher::doNotifyInputChannelRecoveredFromANRLockedInterruptible);
-        commandEntry->connection = connection;
-    }
-}
-
-void InputDispatcher::onDispatchCycleANRLocked(
         nsecs_t currentTime, const sp<Connection>& connection) {
-    LOGI("channel '%s' ~ Not responding!  %01.1fms since event, %01.1fms since dispatch",
-            connection->getInputChannelName(),
-            connection->getEventLatencyMillis(currentTime),
-            connection->getDispatchLatencyMillis(currentTime));
-
-    CommandEntry* commandEntry = postCommandLocked(
-            & InputDispatcher::doNotifyInputChannelANRLockedInterruptible);
-    commandEntry->connection = connection;
 }
 
 void InputDispatcher::onDispatchCycleBrokenLocked(
@@ -2615,6 +2518,25 @@
     commandEntry->connection = connection;
 }
 
+void InputDispatcher::onANRLocked(
+        nsecs_t currentTime, const InputApplication* application, const InputWindow* window,
+        nsecs_t eventTime, nsecs_t waitStartTime) {
+    LOGI("Application is not responding: %s.  "
+            "%01.1fms since event, %01.1fms since wait started",
+            getApplicationWindowLabelLocked(application, window).string(),
+            (currentTime - eventTime) / 1000000.0,
+            (currentTime - waitStartTime) / 1000000.0);
+
+    CommandEntry* commandEntry = postCommandLocked(
+            & InputDispatcher::doNotifyANRLockedInterruptible);
+    if (application) {
+        commandEntry->inputApplicationHandle = application->handle;
+    }
+    if (window) {
+        commandEntry->inputChannel = window->inputChannel;
+    }
+}
+
 void InputDispatcher::doNotifyConfigurationChangedInterruptible(
         CommandEntry* commandEntry) {
     mLock.unlock();
@@ -2637,33 +2559,16 @@
     }
 }
 
-void InputDispatcher::doNotifyInputChannelANRLockedInterruptible(
+void InputDispatcher::doNotifyANRLockedInterruptible(
         CommandEntry* commandEntry) {
-    sp<Connection> connection = commandEntry->connection;
+    mLock.unlock();
 
-    if (connection->status != Connection::STATUS_ZOMBIE) {
-        mLock.unlock();
+    nsecs_t newTimeout = mPolicy->notifyANR(
+            commandEntry->inputApplicationHandle, commandEntry->inputChannel);
 
-        nsecs_t newTimeout = mPolicy->notifyInputChannelANR(connection->inputChannel);
+    mLock.lock();
 
-        mLock.lock();
-
-        nsecs_t currentTime = now();
-        resumeAfterTimeoutDispatchCycleLocked(currentTime, connection, newTimeout);
-    }
-}
-
-void InputDispatcher::doNotifyInputChannelRecoveredFromANRLockedInterruptible(
-        CommandEntry* commandEntry) {
-    sp<Connection> connection = commandEntry->connection;
-
-    if (connection->status != Connection::STATUS_ZOMBIE) {
-        mLock.unlock();
-
-        mPolicy->notifyInputChannelRecoveredFromANR(connection->inputChannel);
-
-        mLock.lock();
-    }
+    resumeAfterTargetsNotReadyTimeoutLocked(newTimeout, commandEntry->inputChannel);
 }
 
 void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible(
@@ -2695,22 +2600,9 @@
     mLock.lock();
 }
 
-void InputDispatcher::doTargetsNotReadyTimeoutLockedInterruptible(
-        CommandEntry* commandEntry) {
-    mLock.unlock();
-
-    nsecs_t newTimeout;
-    if (commandEntry->inputChannel.get()) {
-        newTimeout = mPolicy->notifyInputChannelANR(commandEntry->inputChannel);
-    } else if (commandEntry->inputApplicationHandle.get()) {
-        newTimeout = mPolicy->notifyANR(commandEntry->inputApplicationHandle);
-    } else {
-        newTimeout = 0;
-    }
-
-    mLock.lock();
-
-    resumeAfterTargetsNotReadyTimeoutLocked(newTimeout);
+void InputDispatcher::updateDispatchStatisticsLocked(nsecs_t currentTime, const EventEntry* entry,
+        int32_t injectionResult, nsecs_t timeSpentWaitingForApplication) {
+    // TODO Write some statistics about how long we spend waiting.
 }
 
 void InputDispatcher::dump(String8& dump) {
@@ -2718,6 +2610,18 @@
 }
 
 
+// --- InputDispatcher::Queue ---
+
+template <typename T>
+uint32_t InputDispatcher::Queue<T>::count() const {
+    uint32_t result = 0;
+    for (const T* entry = headSentinel.next; entry != & tailSentinel; entry = entry->next) {
+        result += 1;
+    }
+    return result;
+}
+
+
 // --- InputDispatcher::Allocator ---
 
 InputDispatcher::Allocator::Allocator() {
@@ -2733,7 +2637,7 @@
     entry->injectionIsAsync = false;
     entry->injectorPid = -1;
     entry->injectorUid = -1;
-    entry->pendingSyncDispatches = 0;
+    entry->pendingForegroundDispatches = 0;
 }
 
 InputDispatcher::ConfigurationChangedEntry*
@@ -2797,14 +2701,13 @@
 
 InputDispatcher::DispatchEntry* InputDispatcher::Allocator::obtainDispatchEntry(
         EventEntry* eventEntry,
-        int32_t targetFlags, float xOffset, float yOffset, nsecs_t timeout) {
+        int32_t targetFlags, float xOffset, float yOffset) {
     DispatchEntry* entry = mDispatchEntryPool.alloc();
     entry->eventEntry = eventEntry;
     eventEntry->refCount += 1;
     entry->targetFlags = targetFlags;
     entry->xOffset = xOffset;
     entry->yOffset = yOffset;
-    entry->timeout = timeout;
     entry->inProgress = false;
     entry->headMotionSample = NULL;
     entry->tailMotionSample = NULL;
@@ -2896,7 +2799,7 @@
 void InputDispatcher::EventEntry::recycle() {
     injectionResult = INPUT_EVENT_INJECTION_PENDING;
     dispatchInProgress = false;
-    pendingSyncDispatches = 0;
+    pendingForegroundDispatches = 0;
 }
 
 
@@ -3106,9 +3009,7 @@
 
 InputDispatcher::Connection::Connection(const sp<InputChannel>& inputChannel) :
         status(STATUS_NORMAL), inputChannel(inputChannel), inputPublisher(inputChannel),
-        nextTimeoutTime(LONG_LONG_MAX),
-        lastEventTime(LONG_LONG_MAX), lastDispatchTime(LONG_LONG_MAX),
-        lastANRTime(LONG_LONG_MAX) {
+        lastEventTime(LONG_LONG_MAX), lastDispatchTime(LONG_LONG_MAX) {
 }
 
 InputDispatcher::Connection::~Connection() {
@@ -3118,18 +3019,6 @@
     return inputPublisher.initialize();
 }
 
-void InputDispatcher::Connection::setNextTimeoutTime(nsecs_t currentTime, nsecs_t timeout) {
-    nextTimeoutTime = (timeout >= 0) ? currentTime + timeout : LONG_LONG_MAX;
-}
-
-void InputDispatcher::Connection::resetTimeout(nsecs_t currentTime) {
-    if (outboundQueue.isEmpty()) {
-        nextTimeoutTime = LONG_LONG_MAX;
-    } else {
-        setNextTimeoutTime(currentTime, outboundQueue.headSentinel.next->timeout);
-    }
-}
-
 const char* InputDispatcher::Connection::getStatusLabel() const {
     switch (status) {
     case STATUS_NORMAL:
@@ -3138,9 +3027,6 @@
     case STATUS_BROKEN:
         return "BROKEN";
 
-    case STATUS_NOT_RESPONDING:
-        return "NOT_RESPONDING";
-
     case STATUS_ZOMBIE:
         return "ZOMBIE";
 
diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp
index 88084c0..783cbc4 100644
--- a/libs/ui/InputReader.cpp
+++ b/libs/ui/InputReader.cpp
@@ -325,9 +325,6 @@
     if (classes & INPUT_DEVICE_CLASS_DPAD) {
         keyboardSources |= AINPUT_SOURCE_DPAD;
     }
-    if (classes & INPUT_DEVICE_CLASS_GAMEPAD) {
-        keyboardSources |= AINPUT_SOURCE_GAMEPAD;
-    }
 
     if (keyboardSources != 0) {
         device->addMapper(new KeyboardInputMapper(device,
diff --git a/libs/ui/InputTransport.cpp b/libs/ui/InputTransport.cpp
index 4c402dc..2c6346e 100644
--- a/libs/ui/InputTransport.cpp
+++ b/libs/ui/InputTransport.cpp
@@ -131,7 +131,10 @@
 }
 
 status_t InputChannel::sendSignal(char signal) {
-    ssize_t nWrite = ::write(mSendPipeFd, & signal, 1);
+    ssize_t nWrite;
+    do {
+        nWrite = ::write(mSendPipeFd, & signal, 1);
+    } while (nWrite == -1 && errno == EINTR);
 
     if (nWrite == 1) {
 #if DEBUG_CHANNEL_SIGNALS
@@ -147,7 +150,11 @@
 }
 
 status_t InputChannel::receiveSignal(char* outSignal) {
-    ssize_t nRead = ::read(mReceivePipeFd, outSignal, 1);
+    ssize_t nRead;
+    do {
+        nRead = ::read(mReceivePipeFd, outSignal, 1);
+    } while (nRead == -1 && errno == EINTR);
+
     if (nRead == 1) {
 #if DEBUG_CHANNEL_SIGNALS
         LOGD("channel '%s' ~ received signal '%c'", mName.string(), *outSignal);
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk
index 2e20268..eb75ed8 100644
--- a/libs/utils/Android.mk
+++ b/libs/utils/Android.mk
@@ -86,7 +86,7 @@
 	$(commonSources) \
 	BackupData.cpp \
 	BackupHelpers.cpp \
-	PollLoop.cpp
+	Looper.cpp
 
 ifeq ($(TARGET_OS),linux)
 LOCAL_LDLIBS += -lrt -ldl
diff --git a/libs/utils/Looper.cpp b/libs/utils/Looper.cpp
new file mode 100644
index 0000000..b46279e
--- /dev/null
+++ b/libs/utils/Looper.cpp
@@ -0,0 +1,380 @@
+//
+// Copyright 2010 The Android Open Source Project
+//
+// A looper implementation based on epoll().
+//
+#define LOG_TAG "Looper"
+
+//#define LOG_NDEBUG 0
+
+// Debugs poll and wake interactions.
+#define DEBUG_POLL_AND_WAKE 0
+
+// Debugs callback registration and invocation.
+#define DEBUG_CALLBACKS 0
+
+#include <cutils/log.h>
+#include <utils/Looper.h>
+#include <utils/Timers.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/epoll.h>
+
+
+namespace android {
+
+static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER;
+static bool gHaveTLS = false;
+static pthread_key_t gTLS = 0;
+
+// Hint for number of file descriptors to be associated with the epoll instance.
+static const int EPOLL_SIZE_HINT = 8;
+
+// Maximum number of file descriptors for which to retrieve poll events each iteration.
+static const int EPOLL_MAX_EVENTS = 16;
+
+Looper::Looper(bool allowNonCallbacks) :
+        mAllowNonCallbacks(allowNonCallbacks),
+        mResponseIndex(0) {
+    mEpollFd = epoll_create(EPOLL_SIZE_HINT);
+    LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance.  errno=%d", errno);
+
+    int wakeFds[2];
+    int result = pipe(wakeFds);
+    LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe.  errno=%d", errno);
+
+    mWakeReadPipeFd = wakeFds[0];
+    mWakeWritePipeFd = wakeFds[1];
+
+    result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
+    LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking.  errno=%d",
+            errno);
+
+    result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
+    LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking.  errno=%d",
+            errno);
+
+    struct epoll_event eventItem;
+    eventItem.events = EPOLLIN;
+    eventItem.data.fd = mWakeReadPipeFd;
+    result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, & eventItem);
+    LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance.  errno=%d",
+            errno);
+}
+
+Looper::~Looper() {
+    close(mWakeReadPipeFd);
+    close(mWakeWritePipeFd);
+    close(mEpollFd);
+}
+
+void Looper::threadDestructor(void *st) {
+    Looper* const self = static_cast<Looper*>(st);
+    if (self != NULL) {
+        self->decStrong((void*)threadDestructor);
+    }
+}
+
+void Looper::setForThread(const sp<Looper>& looper) {
+    sp<Looper> old = getForThread(); // also has side-effect of initializing TLS
+
+    if (looper != NULL) {
+        looper->incStrong((void*)threadDestructor);
+    }
+
+    pthread_setspecific(gTLS, looper.get());
+
+    if (old != NULL) {
+        old->decStrong((void*)threadDestructor);
+    }
+}
+
+sp<Looper> Looper::getForThread() {
+    if (!gHaveTLS) {
+        pthread_mutex_lock(&gTLSMutex);
+        if (pthread_key_create(&gTLS, threadDestructor) != 0) {
+            pthread_mutex_unlock(&gTLSMutex);
+            return NULL;
+        }
+        gHaveTLS = true;
+        pthread_mutex_unlock(&gTLSMutex);
+    }
+
+    return (Looper*)pthread_getspecific(gTLS);
+}
+
+sp<Looper> Looper::prepare(int opts) {
+    bool allowNonCallbacks = opts & ALOOPER_PREPARE_ALLOW_NON_CALLBACKS;
+    sp<Looper> looper = Looper::getForThread();
+    if (looper == NULL) {
+        looper = new Looper(allowNonCallbacks);
+        Looper::setForThread(looper);
+    }
+    if (looper->getAllowNonCallbacks() != allowNonCallbacks) {
+        LOGW("Looper already prepared for this thread with a different value for the "
+                "ALOOPER_PREPARE_ALLOW_NON_CALLBACKS option.");
+    }
+    return looper;
+}
+
+bool Looper::getAllowNonCallbacks() const {
+    return mAllowNonCallbacks;
+}
+
+int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
+    int result = 0;
+    for (;;) {
+        while (mResponseIndex < mResponses.size()) {
+            const Response& response = mResponses.itemAt(mResponseIndex++);
+            if (! response.request.callback) {
+#if DEBUG_POLL_AND_WAKE
+                LOGD("%p ~ pollOnce - returning signalled identifier %d: "
+                        "fd=%d, events=0x%x, data=%p", this,
+                        response.request.ident, response.request.fd,
+                        response.events, response.request.data);
+#endif
+                if (outFd != NULL) *outFd = response.request.fd;
+                if (outEvents != NULL) *outEvents = response.events;
+                if (outData != NULL) *outData = response.request.data;
+                return response.request.ident;
+            }
+        }
+
+        if (result != 0) {
+#if DEBUG_POLL_AND_WAKE
+            LOGD("%p ~ pollOnce - returning result %d", this, result);
+#endif
+            if (outFd != NULL) *outFd = 0;
+            if (outEvents != NULL) *outEvents = NULL;
+            if (outData != NULL) *outData = NULL;
+            return result;
+        }
+
+        result = pollInner(timeoutMillis);
+    }
+}
+
+int Looper::pollInner(int timeoutMillis) {
+#if DEBUG_POLL_AND_WAKE
+    LOGD("%p ~ pollOnce - waiting: timeoutMillis=%d", this, timeoutMillis);
+#endif
+    struct epoll_event eventItems[EPOLL_MAX_EVENTS];
+    int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
+    if (eventCount < 0) {
+        if (errno == EINTR) {
+            return ALOOPER_POLL_WAKE;
+        }
+
+        LOGW("Poll failed with an unexpected error, errno=%d", errno);
+        return ALOOPER_POLL_ERROR;
+    }
+
+    if (eventCount == 0) {
+#if DEBUG_POLL_AND_WAKE
+        LOGD("%p ~ pollOnce - timeout", this);
+#endif
+        return ALOOPER_POLL_TIMEOUT;
+    }
+
+    int result = ALOOPER_POLL_WAKE;
+    mResponses.clear();
+    mResponseIndex = 0;
+
+#if DEBUG_POLL_AND_WAKE
+    LOGD("%p ~ pollOnce - handling events from %d fds", this, eventCount);
+#endif
+    bool acquiredLock = false;
+    for (int i = 0; i < eventCount; i++) {
+        int fd = eventItems[i].data.fd;
+        uint32_t epollEvents = eventItems[i].events;
+        if (fd == mWakeReadPipeFd) {
+            if (epollEvents & EPOLLIN) {
+#if DEBUG_POLL_AND_WAKE
+                LOGD("%p ~ pollOnce - awoken", this);
+#endif
+                char buffer[16];
+                ssize_t nRead;
+                do {
+                    nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
+                } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer));
+            } else {
+                LOGW("Ignoring unexpected epoll events 0x%x on wake read pipe.", epollEvents);
+            }
+        } else {
+            if (! acquiredLock) {
+                mLock.lock();
+                acquiredLock = true;
+            }
+
+            ssize_t requestIndex = mRequests.indexOfKey(fd);
+            if (requestIndex >= 0) {
+                int events = 0;
+                if (epollEvents & EPOLLIN) events |= ALOOPER_EVENT_INPUT;
+                if (epollEvents & EPOLLOUT) events |= ALOOPER_EVENT_OUTPUT;
+                if (epollEvents & EPOLLERR) events |= ALOOPER_EVENT_ERROR;
+                if (epollEvents & EPOLLHUP) events |= ALOOPER_EVENT_HANGUP;
+
+                Response response;
+                response.events = events;
+                response.request = mRequests.valueAt(requestIndex);
+                mResponses.push(response);
+            } else {
+                LOGW("Ignoring unexpected epoll events 0x%x on fd %d that is "
+                        "no longer registered.", epollEvents, fd);
+            }
+        }
+    }
+    if (acquiredLock) {
+        mLock.unlock();
+    }
+
+    for (size_t i = 0; i < mResponses.size(); i++) {
+        const Response& response = mResponses.itemAt(i);
+        if (response.request.callback) {
+#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
+            LOGD("%p ~ pollOnce - invoking callback: fd=%d, events=0x%x, data=%p", this,
+                    response.request.fd, response.events, response.request.data);
+#endif
+            int callbackResult = response.request.callback(
+                    response.request.fd, response.events, response.request.data);
+            if (callbackResult == 0) {
+                removeFd(response.request.fd);
+            }
+
+            result = ALOOPER_POLL_CALLBACK;
+        }
+    }
+    return result;
+}
+
+int Looper::pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
+    if (timeoutMillis <= 0) {
+        int result;
+        do {
+            result = pollOnce(timeoutMillis, outFd, outEvents, outData);
+        } while (result == ALOOPER_POLL_CALLBACK);
+        return result;
+    } else {
+        nsecs_t endTime = systemTime(SYSTEM_TIME_MONOTONIC)
+                + milliseconds_to_nanoseconds(timeoutMillis);
+
+        for (;;) {
+            int result = pollOnce(timeoutMillis, outFd, outEvents, outData);
+            if (result != ALOOPER_POLL_CALLBACK) {
+                return result;
+            }
+
+            nsecs_t timeoutNanos = endTime - systemTime(SYSTEM_TIME_MONOTONIC);
+            if (timeoutNanos <= 0) {
+                return ALOOPER_POLL_TIMEOUT;
+            }
+
+            timeoutMillis = int(nanoseconds_to_milliseconds(timeoutNanos + 999999LL));
+        }
+    }
+}
+
+void Looper::wake() {
+#if DEBUG_POLL_AND_WAKE
+    LOGD("%p ~ wake", this);
+#endif
+
+    ssize_t nWrite;
+    do {
+        nWrite = write(mWakeWritePipeFd, "W", 1);
+    } while (nWrite == -1 && errno == EINTR);
+
+    if (nWrite != 1) {
+        if (errno != EAGAIN) {
+            LOGW("Could not write wake signal, errno=%d", errno);
+        }
+    }
+}
+
+int Looper::addFd(int fd, int ident, int events, ALooper_callbackFunc callback, void* data) {
+#if DEBUG_CALLBACKS
+    LOGD("%p ~ addFd - fd=%d, ident=%d, events=0x%x, callback=%p, data=%p", this, fd, ident,
+            events, callback, data);
+#endif
+
+    int epollEvents = 0;
+    if (events & ALOOPER_EVENT_INPUT) epollEvents |= EPOLLIN;
+    if (events & ALOOPER_EVENT_OUTPUT) epollEvents |= EPOLLOUT;
+    if (events & ALOOPER_EVENT_ERROR) epollEvents |= EPOLLERR;
+    if (events & ALOOPER_EVENT_HANGUP) epollEvents |= EPOLLHUP;
+
+    if (epollEvents == 0) {
+        LOGE("Invalid attempt to set a callback with no selected poll events.");
+        return -1;
+    }
+
+    if (! callback) {
+        if (! mAllowNonCallbacks) {
+            LOGE("Invalid attempt to set NULL callback but not allowed for this looper.");
+            return -1;
+        }
+
+        if (ident < 0) {
+            LOGE("Invalid attempt to set NULL callback with ident <= 0.");
+            return -1;
+        }
+    }
+
+    { // acquire lock
+        AutoMutex _l(mLock);
+
+        Request request;
+        request.fd = fd;
+        request.ident = ident;
+        request.callback = callback;
+        request.data = data;
+
+        struct epoll_event eventItem;
+        eventItem.events = epollEvents;
+        eventItem.data.fd = fd;
+
+        ssize_t requestIndex = mRequests.indexOfKey(fd);
+        if (requestIndex < 0) {
+            int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem);
+            if (epollResult < 0) {
+                LOGE("Error adding epoll events for fd %d, errno=%d", fd, errno);
+                return -1;
+            }
+            mRequests.add(fd, request);
+        } else {
+            int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_MOD, fd, & eventItem);
+            if (epollResult < 0) {
+                LOGE("Error modifying epoll events for fd %d, errno=%d", fd, errno);
+                return -1;
+            }
+            mRequests.replaceValueAt(requestIndex, request);
+        }
+    } // release lock
+    return 1;
+}
+
+int Looper::removeFd(int fd) {
+#if DEBUG_CALLBACKS
+    LOGD("%p ~ removeFd - fd=%d", this, fd);
+#endif
+
+    { // acquire lock
+        AutoMutex _l(mLock);
+        ssize_t requestIndex = mRequests.indexOfKey(fd);
+        if (requestIndex < 0) {
+            return 0;
+        }
+
+        int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_DEL, fd, NULL);
+        if (epollResult < 0) {
+            LOGE("Error removing epoll events for fd %d, errno=%d", fd, errno);
+            return -1;
+        }
+
+        mRequests.removeItemsAt(requestIndex);
+    } // request lock
+    return 1;
+}
+
+} // namespace android
diff --git a/libs/utils/PollLoop.cpp b/libs/utils/PollLoop.cpp
deleted file mode 100644
index fe76cd0..0000000
--- a/libs/utils/PollLoop.cpp
+++ /dev/null
@@ -1,377 +0,0 @@
-//
-// Copyright 2010 The Android Open Source Project
-//
-// A select loop implementation.
-//
-#define LOG_TAG "PollLoop"
-
-//#define LOG_NDEBUG 0
-
-// Debugs poll and wake interactions.
-#define DEBUG_POLL_AND_WAKE 0
-
-// Debugs callback registration and invocation.
-#define DEBUG_CALLBACKS 0
-
-#include <cutils/log.h>
-#include <utils/PollLoop.h>
-
-#include <unistd.h>
-#include <fcntl.h>
-
-namespace android {
-
-static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER;
-static bool gHaveTLS = false;
-static pthread_key_t gTLS = 0;
-
-PollLoop::PollLoop(bool allowNonCallbacks) :
-        mAllowNonCallbacks(allowNonCallbacks), mPolling(false),
-        mWaiters(0), mPendingFdsPos(0) {
-    openWakePipe();
-}
-
-PollLoop::~PollLoop() {
-    closeWakePipe();
-}
-
-void PollLoop::threadDestructor(void *st) {
-    PollLoop* const self = static_cast<PollLoop*>(st);
-    if (self != NULL) {
-        self->decStrong((void*)threadDestructor);
-    }
-}
-
-void PollLoop::setForThread(const sp<PollLoop>& pollLoop) {
-    sp<PollLoop> old = getForThread();
-    
-    if (pollLoop != NULL) {
-        pollLoop->incStrong((void*)threadDestructor);
-    }
-    
-    pthread_setspecific(gTLS, pollLoop.get());
-    
-    if (old != NULL) {
-        old->decStrong((void*)threadDestructor);
-    }
-}
-    
-sp<PollLoop> PollLoop::getForThread() {
-    if (!gHaveTLS) {
-        pthread_mutex_lock(&gTLSMutex);
-        if (pthread_key_create(&gTLS, threadDestructor) != 0) {
-            pthread_mutex_unlock(&gTLSMutex);
-            return NULL;
-        }
-        gHaveTLS = true;
-        pthread_mutex_unlock(&gTLSMutex);
-    }
-    
-    return (PollLoop*)pthread_getspecific(gTLS);
-}
-
-void PollLoop::openWakePipe() {
-    int wakeFds[2];
-    int result = pipe(wakeFds);
-    LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe.  errno=%d", errno);
-
-    mWakeReadPipeFd = wakeFds[0];
-    mWakeWritePipeFd = wakeFds[1];
-
-    result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
-    LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking.  errno=%d",
-            errno);
-
-    result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
-    LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking.  errno=%d",
-            errno);
-
-    // Add the wake pipe to the head of the request list with a null callback.
-    struct pollfd requestedFd;
-    requestedFd.fd = mWakeReadPipeFd;
-    requestedFd.events = POLLIN;
-    mRequestedFds.insertAt(requestedFd, 0);
-
-    RequestedCallback requestedCallback;
-    requestedCallback.callback = NULL;
-    requestedCallback.looperCallback = NULL;
-    requestedCallback.ident = 0;
-    requestedCallback.data = NULL;
-    mRequestedCallbacks.insertAt(requestedCallback, 0);
-}
-
-void PollLoop::closeWakePipe() {
-    close(mWakeReadPipeFd);
-    close(mWakeWritePipeFd);
-
-    // Note: We don't need to remove the poll structure or callback entry because this
-    //       method is currently only called by the destructor.
-}
-
-int32_t PollLoop::pollOnce(int timeoutMillis, int* outEvents, void** outData) {
-    // If there are still pending fds from the last call, dispatch those
-    // first, to avoid an earlier fd from starving later ones.
-    const size_t pendingFdsCount = mPendingFds.size();
-    if (mPendingFdsPos < pendingFdsCount) {
-        const PendingCallback& pending = mPendingFds.itemAt(mPendingFdsPos);
-        mPendingFdsPos++;
-        if (outEvents != NULL) *outEvents = pending.events;
-        if (outData != NULL) *outData = pending.data;
-        return pending.ident;
-    }
-
-    // Wait for wakeAndLock() waiters to run then set mPolling to true.
-    mLock.lock();
-    while (mWaiters != 0) {
-        mResume.wait(mLock);
-    }
-    mPolling = true;
-    mLock.unlock();
-
-    // Poll.
-    int32_t result;
-    size_t requestedCount = mRequestedFds.size();
-
-#if DEBUG_POLL_AND_WAKE
-    LOGD("%p ~ pollOnce - waiting on %d fds", this, requestedCount);
-    for (size_t i = 0; i < requestedCount; i++) {
-        LOGD("  fd %d - events %d", mRequestedFds[i].fd, mRequestedFds[i].events);
-    }
-#endif
-
-    int respondedCount = poll(mRequestedFds.editArray(), requestedCount, timeoutMillis);
-
-    if (respondedCount == 0) {
-        // Timeout
-#if DEBUG_POLL_AND_WAKE
-        LOGD("%p ~ pollOnce - timeout", this);
-#endif
-        result = POLL_TIMEOUT;
-        goto Done;
-    }
-
-    if (respondedCount < 0) {
-        // Error
-#if DEBUG_POLL_AND_WAKE
-        LOGD("%p ~ pollOnce - error, errno=%d", this, errno);
-#endif
-        if (errno != EINTR) {
-            LOGW("Poll failed with an unexpected error, errno=%d", errno);
-        }
-        result = POLL_ERROR;
-        goto Done;
-    }
-
-#if DEBUG_POLL_AND_WAKE
-    LOGD("%p ~ pollOnce - handling responses from %d fds", this, respondedCount);
-    for (size_t i = 0; i < requestedCount; i++) {
-        LOGD("  fd %d - events %d, revents %d", mRequestedFds[i].fd, mRequestedFds[i].events,
-                mRequestedFds[i].revents);
-    }
-#endif
-
-    // Process the poll results.
-    mPendingCallbacks.clear();
-    mPendingFds.clear();
-    mPendingFdsPos = 0;
-    if (outEvents != NULL) *outEvents = 0;
-    if (outData != NULL) *outData = NULL;
-    
-    result = POLL_CALLBACK;
-    for (size_t i = 0; i < requestedCount; i++) {
-        const struct pollfd& requestedFd = mRequestedFds.itemAt(i);
-
-        short revents = requestedFd.revents;
-        if (revents) {
-            const RequestedCallback& requestedCallback = mRequestedCallbacks.itemAt(i);
-            PendingCallback pending;
-            pending.fd = requestedFd.fd;
-            pending.ident = requestedCallback.ident;
-            pending.events = revents;
-            pending.callback = requestedCallback.callback;
-            pending.looperCallback = requestedCallback.looperCallback;
-            pending.data = requestedCallback.data;
-
-            if (pending.callback || pending.looperCallback) {
-                mPendingCallbacks.push(pending);
-            } else if (pending.fd != mWakeReadPipeFd) {
-                if (result == POLL_CALLBACK) {
-                    result = pending.ident;
-                    if (outEvents != NULL) *outEvents = pending.events;
-                    if (outData != NULL) *outData = pending.data;
-                } else {
-                    mPendingFds.push(pending);
-                }
-            } else {
-#if DEBUG_POLL_AND_WAKE
-                LOGD("%p ~ pollOnce - awoken", this);
-#endif
-                char buffer[16];
-                ssize_t nRead;
-                do {
-                    nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
-                } while (nRead == sizeof(buffer));
-            }
-
-            respondedCount -= 1;
-            if (respondedCount == 0) {
-                break;
-            }
-        }
-    }
-
-Done:
-    // Set mPolling to false and wake up the wakeAndLock() waiters.
-    mLock.lock();
-    mPolling = false;
-    if (mWaiters != 0) {
-        mAwake.broadcast();
-    }
-    mLock.unlock();
-
-    if (result == POLL_CALLBACK || result >= 0) {
-        size_t pendingCount = mPendingCallbacks.size();
-        for (size_t i = 0; i < pendingCount; i++) {
-            const PendingCallback& pendingCallback = mPendingCallbacks.itemAt(i);
-#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
-            LOGD("%p ~ pollOnce - invoking callback for fd %d", this, pendingCallback.fd);
-#endif
-
-            bool keep = true;
-            if (pendingCallback.callback != NULL) {
-                keep = pendingCallback.callback(pendingCallback.fd, pendingCallback.events,
-                        pendingCallback.data);
-            } else {
-                keep = pendingCallback.looperCallback(pendingCallback.fd, pendingCallback.events,
-                        pendingCallback.data) != 0;
-            }
-            if (! keep) {
-                removeCallback(pendingCallback.fd);
-            }
-        }
-    }
-
-#if DEBUG_POLL_AND_WAKE
-    LOGD("%p ~ pollOnce - done", this);
-#endif
-    return result;
-}
-
-void PollLoop::wake() {
-#if DEBUG_POLL_AND_WAKE
-    LOGD("%p ~ wake", this);
-#endif
-
-    ssize_t nWrite = write(mWakeWritePipeFd, "W", 1);
-    if (nWrite != 1) {
-        if (errno != EAGAIN) {
-            LOGW("Could not write wake signal, errno=%d", errno);
-        }
-    }
-}
-
-bool PollLoop::getAllowNonCallbacks() const {
-    return mAllowNonCallbacks;
-}
-
-void PollLoop::setCallback(int fd, int ident, int events, Callback callback, void* data) {
-    setCallbackCommon(fd, ident, events, callback, NULL, data);
-}
-
-void PollLoop::setCallback(int fd, int events, Callback callback, void* data) {
-    setCallbackCommon(fd, POLL_CALLBACK, events, callback, NULL, data);
-}
-
-void PollLoop::setLooperCallback(int fd, int ident, int events, ALooper_callbackFunc* callback,
-        void* data) {
-    setCallbackCommon(fd, ident, events, NULL, callback, data);
-}
-
-void PollLoop::setCallbackCommon(int fd, int ident, int events, Callback callback,
-        ALooper_callbackFunc* looperCallback, void* data) {
-
-#if DEBUG_CALLBACKS
-    LOGD("%p ~ setCallback - fd=%d, events=%d", this, fd, events);
-#endif
-
-    if (! events) {
-        LOGE("Invalid attempt to set a callback with no selected poll events.");
-        removeCallback(fd);
-        return;
-    }
-
-    if (! callback && ! looperCallback && ! mAllowNonCallbacks) {
-        LOGE("Invalid attempt to set NULL callback but not allowed.");
-        removeCallback(fd);
-        return;
-    }
-    
-    wakeAndLock();
-
-    struct pollfd requestedFd;
-    requestedFd.fd = fd;
-    requestedFd.events = events;
-
-    RequestedCallback requestedCallback;
-    requestedCallback.callback = callback;
-    requestedCallback.looperCallback = looperCallback;
-    requestedCallback.ident = ident;
-    requestedCallback.data = data;
-
-    ssize_t index = getRequestIndexLocked(fd);
-    if (index < 0) {
-        mRequestedFds.push(requestedFd);
-        mRequestedCallbacks.push(requestedCallback);
-    } else {
-        mRequestedFds.replaceAt(requestedFd, size_t(index));
-        mRequestedCallbacks.replaceAt(requestedCallback, size_t(index));
-    }
-
-    mLock.unlock();
-}
-
-bool PollLoop::removeCallback(int fd) {
-#if DEBUG_CALLBACKS
-    LOGD("%p ~ removeCallback - fd=%d", this, fd);
-#endif
-
-    wakeAndLock();
-
-    ssize_t index = getRequestIndexLocked(fd);
-    if (index >= 0) {
-        mRequestedFds.removeAt(size_t(index));
-        mRequestedCallbacks.removeAt(size_t(index));
-    }
-
-    mLock.unlock();
-    return index >= 0;
-}
-
-ssize_t PollLoop::getRequestIndexLocked(int fd) {
-    size_t requestCount = mRequestedFds.size();
-
-    for (size_t i = 0; i < requestCount; i++) {
-        if (mRequestedFds.itemAt(i).fd == fd) {
-            return i;
-        }
-    }
-
-    return -1;
-}
-
-void PollLoop::wakeAndLock() {
-    mLock.lock();
-
-    mWaiters += 1;
-    while (mPolling) {
-        wake();
-        mAwake.wait(mLock);
-    }
-
-    mWaiters -= 1;
-    if (mWaiters == 0) {
-        mResume.signal();
-    }
-}
-
-} // namespace android
diff --git a/libs/utils/tests/Android.mk b/libs/utils/tests/Android.mk
index 725de9c..00077ee 100644
--- a/libs/utils/tests/Android.mk
+++ b/libs/utils/tests/Android.mk
@@ -7,7 +7,7 @@
 # Build the unit tests.
 test_src_files := \
 	ObbFile_test.cpp \
-	PollLoop_test.cpp \
+	Looper_test.cpp \
 	String8_test.cpp
 
 shared_libraries := \
diff --git a/libs/utils/tests/Looper_test.cpp b/libs/utils/tests/Looper_test.cpp
new file mode 100644
index 0000000..afc92f8
--- /dev/null
+++ b/libs/utils/tests/Looper_test.cpp
@@ -0,0 +1,433 @@
+//
+// Copyright 2010 The Android Open Source Project
+//
+
+#include <utils/Looper.h>
+#include <utils/Timers.h>
+#include <utils/StopWatch.h>
+#include <gtest/gtest.h>
+#include <unistd.h>
+#include <time.h>
+
+#include "TestHelpers.h"
+
+// # of milliseconds to fudge stopwatch measurements
+#define TIMING_TOLERANCE_MS 25
+
+namespace android {
+
+class DelayedWake : public DelayedTask {
+    sp<Looper> mLooper;
+
+public:
+    DelayedWake(int delayMillis, const sp<Looper> looper) :
+        DelayedTask(delayMillis), mLooper(looper) {
+    }
+
+protected:
+    virtual void doTask() {
+        mLooper->wake();
+    }
+};
+
+class DelayedWriteSignal : public DelayedTask {
+    Pipe* mPipe;
+
+public:
+    DelayedWriteSignal(int delayMillis, Pipe* pipe) :
+        DelayedTask(delayMillis), mPipe(pipe) {
+    }
+
+protected:
+    virtual void doTask() {
+        mPipe->writeSignal();
+    }
+};
+
+class CallbackHandler {
+public:
+    void setCallback(const sp<Looper>& looper, int fd, int events) {
+        looper->addFd(fd, 0, events, staticHandler, this);
+    }
+
+protected:
+    virtual ~CallbackHandler() { }
+
+    virtual int handler(int fd, int events) = 0;
+
+private:
+    static int staticHandler(int fd, int events, void* data) {
+        return static_cast<CallbackHandler*>(data)->handler(fd, events);
+    }
+};
+
+class StubCallbackHandler : public CallbackHandler {
+public:
+    int nextResult;
+    int callbackCount;
+
+    int fd;
+    int events;
+
+    StubCallbackHandler(int nextResult) : nextResult(nextResult),
+            callbackCount(0), fd(-1), events(-1) {
+    }
+
+protected:
+    virtual int handler(int fd, int events) {
+        callbackCount += 1;
+        this->fd = fd;
+        this->events = events;
+        return nextResult;
+    }
+};
+
+class LooperTest : public testing::Test {
+protected:
+    sp<Looper> mLooper;
+
+    virtual void SetUp() {
+        mLooper = new Looper(true);
+    }
+
+    virtual void TearDown() {
+        mLooper.clear();
+    }
+};
+
+
+TEST_F(LooperTest, PollOnce_WhenNonZeroTimeoutAndNotAwoken_WaitsForTimeout) {
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(100);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should approx. equal timeout";
+    EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result)
+            << "pollOnce result should be ALOOPER_POLL_TIMEOUT";
+}
+
+TEST_F(LooperTest, PollOnce_WhenNonZeroTimeoutAndAwokenBeforeWaiting_ImmediatelyReturns) {
+    mLooper->wake();
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(1000);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should approx. zero because wake() was called before waiting";
+    EXPECT_EQ(ALOOPER_POLL_WAKE, result)
+            << "pollOnce result should be ALOOPER_POLL_CALLBACK because loop was awoken";
+}
+
+TEST_F(LooperTest, PollOnce_WhenNonZeroTimeoutAndAwokenWhileWaiting_PromptlyReturns) {
+    sp<DelayedWake> delayedWake = new DelayedWake(100, mLooper);
+    delayedWake->run();
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(1000);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should approx. equal wake delay";
+    EXPECT_EQ(ALOOPER_POLL_WAKE, result)
+            << "pollOnce result should be ALOOPER_POLL_CALLBACK because loop was awoken";
+}
+
+TEST_F(LooperTest, PollOnce_WhenZeroTimeoutAndNoRegisteredFDs_ImmediatelyReturns) {
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(0);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should be approx. zero";
+    EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result)
+            << "pollOnce result should be ALOOPER_POLL_TIMEOUT";
+}
+
+TEST_F(LooperTest, PollOnce_WhenZeroTimeoutAndNoSignalledFDs_ImmediatelyReturns) {
+    Pipe pipe;
+    StubCallbackHandler handler(true);
+
+    handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(0);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should be approx. zero";
+    EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result)
+            << "pollOnce result should be ALOOPER_POLL_TIMEOUT";
+    EXPECT_EQ(0, handler.callbackCount)
+            << "callback should not have been invoked because FD was not signalled";
+}
+
+TEST_F(LooperTest, PollOnce_WhenZeroTimeoutAndSignalledFD_ImmediatelyInvokesCallbackAndReturns) {
+    Pipe pipe;
+    StubCallbackHandler handler(true);
+
+    ASSERT_EQ(OK, pipe.writeSignal());
+    handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(0);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should be approx. zero";
+    EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
+            << "pollOnce result should be ALOOPER_POLL_CALLBACK because FD was signalled";
+    EXPECT_EQ(1, handler.callbackCount)
+            << "callback should be invoked exactly once";
+    EXPECT_EQ(pipe.receiveFd, handler.fd)
+            << "callback should have received pipe fd as parameter";
+    EXPECT_EQ(ALOOPER_EVENT_INPUT, handler.events)
+            << "callback should have received ALOOPER_EVENT_INPUT as events";
+}
+
+TEST_F(LooperTest, PollOnce_WhenNonZeroTimeoutAndNoSignalledFDs_WaitsForTimeoutAndReturns) {
+    Pipe pipe;
+    StubCallbackHandler handler(true);
+
+    handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(100);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should approx. equal timeout";
+    EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result)
+            << "pollOnce result should be ALOOPER_POLL_TIMEOUT";
+    EXPECT_EQ(0, handler.callbackCount)
+            << "callback should not have been invoked because FD was not signalled";
+}
+
+TEST_F(LooperTest, PollOnce_WhenNonZeroTimeoutAndSignalledFDBeforeWaiting_ImmediatelyInvokesCallbackAndReturns) {
+    Pipe pipe;
+    StubCallbackHandler handler(true);
+
+    pipe.writeSignal();
+    handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(100);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    ASSERT_EQ(OK, pipe.readSignal())
+            << "signal should actually have been written";
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should be approx. zero";
+    EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
+            << "pollOnce result should be ALOOPER_POLL_CALLBACK because FD was signalled";
+    EXPECT_EQ(1, handler.callbackCount)
+            << "callback should be invoked exactly once";
+    EXPECT_EQ(pipe.receiveFd, handler.fd)
+            << "callback should have received pipe fd as parameter";
+    EXPECT_EQ(ALOOPER_EVENT_INPUT, handler.events)
+            << "callback should have received ALOOPER_EVENT_INPUT as events";
+}
+
+TEST_F(LooperTest, PollOnce_WhenNonZeroTimeoutAndSignalledFDWhileWaiting_PromptlyInvokesCallbackAndReturns) {
+    Pipe pipe;
+    StubCallbackHandler handler(true);
+    sp<DelayedWriteSignal> delayedWriteSignal = new DelayedWriteSignal(100, & pipe);
+
+    handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
+    delayedWriteSignal->run();
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(1000);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    ASSERT_EQ(OK, pipe.readSignal())
+            << "signal should actually have been written";
+    EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should approx. equal signal delay";
+    EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
+            << "pollOnce result should be ALOOPER_POLL_CALLBACK because FD was signalled";
+    EXPECT_EQ(1, handler.callbackCount)
+            << "callback should be invoked exactly once";
+    EXPECT_EQ(pipe.receiveFd, handler.fd)
+            << "callback should have received pipe fd as parameter";
+    EXPECT_EQ(ALOOPER_EVENT_INPUT, handler.events)
+            << "callback should have received ALOOPER_EVENT_INPUT as events";
+}
+
+TEST_F(LooperTest, PollOnce_WhenCallbackAddedThenRemoved_CallbackShouldNotBeInvoked) {
+    Pipe pipe;
+    StubCallbackHandler handler(true);
+
+    handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
+    pipe.writeSignal(); // would cause FD to be considered signalled
+    mLooper->removeFd(pipe.receiveFd);
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(100);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    ASSERT_EQ(OK, pipe.readSignal())
+            << "signal should actually have been written";
+    EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should approx. equal timeout because FD was no longer registered";
+    EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result)
+            << "pollOnce result should be ALOOPER_POLL_TIMEOUT";
+    EXPECT_EQ(0, handler.callbackCount)
+            << "callback should not be invoked";
+}
+
+TEST_F(LooperTest, PollOnce_WhenCallbackReturnsFalse_CallbackShouldNotBeInvokedAgainLater) {
+    Pipe pipe;
+    StubCallbackHandler handler(false);
+
+    handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
+
+    // First loop: Callback is registered and FD is signalled.
+    pipe.writeSignal();
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(0);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    ASSERT_EQ(OK, pipe.readSignal())
+            << "signal should actually have been written";
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should approx. equal zero because FD was already signalled";
+    EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
+            << "pollOnce result should be ALOOPER_POLL_CALLBACK because FD was signalled";
+    EXPECT_EQ(1, handler.callbackCount)
+            << "callback should be invoked";
+
+    // Second loop: Callback is no longer registered and FD is signalled.
+    pipe.writeSignal();
+
+    stopWatch.reset();
+    result = mLooper->pollOnce(0);
+    elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    ASSERT_EQ(OK, pipe.readSignal())
+            << "signal should actually have been written";
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should approx. equal zero because timeout was zero";
+    EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result)
+            << "pollOnce result should be ALOOPER_POLL_TIMEOUT";
+    EXPECT_EQ(1, handler.callbackCount)
+            << "callback should not be invoked this time";
+}
+
+TEST_F(LooperTest, PollOnce_WhenNonCallbackFdIsSignalled_ReturnsIdent) {
+    const int expectedIdent = 5;
+    void* expectedData = this;
+
+    Pipe pipe;
+
+    pipe.writeSignal();
+    mLooper->addFd(pipe.receiveFd, expectedIdent, ALOOPER_EVENT_INPUT, NULL, expectedData);
+
+    StopWatch stopWatch("pollOnce");
+    int fd;
+    int events;
+    void* data;
+    int result = mLooper->pollOnce(100, &fd, &events, &data);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    ASSERT_EQ(OK, pipe.readSignal())
+            << "signal should actually have been written";
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should be approx. zero";
+    EXPECT_EQ(expectedIdent, result)
+            << "pollOnce result should be the ident of the FD that was signalled";
+    EXPECT_EQ(pipe.receiveFd, fd)
+            << "pollOnce should have returned the received pipe fd";
+    EXPECT_EQ(ALOOPER_EVENT_INPUT, events)
+            << "pollOnce should have returned ALOOPER_EVENT_INPUT as events";
+    EXPECT_EQ(expectedData, data)
+            << "pollOnce should have returned the data";
+}
+
+TEST_F(LooperTest, AddFd_WhenCallbackAdded_ReturnsOne) {
+    Pipe pipe;
+    int result = mLooper->addFd(pipe.receiveFd, 0, ALOOPER_EVENT_INPUT, NULL, NULL);
+
+    EXPECT_EQ(1, result)
+            << "addFd should return 1 because FD was added";
+}
+
+TEST_F(LooperTest, AddFd_WhenEventsIsZero_ReturnsError) {
+    Pipe pipe;
+    int result = mLooper->addFd(pipe.receiveFd, 0, 0, NULL, NULL);
+
+    EXPECT_EQ(-1, result)
+            << "addFd should return -1 because arguments were invalid";
+}
+
+TEST_F(LooperTest, AddFd_WhenIdentIsNegativeAndCallbackIsNull_ReturnsError) {
+    Pipe pipe;
+    int result = mLooper->addFd(pipe.receiveFd, -1, ALOOPER_EVENT_INPUT, NULL, NULL);
+
+    EXPECT_EQ(-1, result)
+            << "addFd should return -1 because arguments were invalid";
+}
+
+TEST_F(LooperTest, AddFd_WhenNoCallbackAndAllowNonCallbacksIsFalse_ReturnsError) {
+    Pipe pipe;
+    sp<Looper> looper = new Looper(false /*allowNonCallbacks*/);
+    int result = looper->addFd(pipe.receiveFd, 0, 0, NULL, NULL);
+
+    EXPECT_EQ(-1, result)
+            << "addFd should return -1 because arguments were invalid";
+}
+
+TEST_F(LooperTest, RemoveFd_WhenCallbackNotAdded_ReturnsZero) {
+    int result = mLooper->removeFd(1);
+
+    EXPECT_EQ(0, result)
+            << "removeFd should return 0 because FD not registered";
+}
+
+TEST_F(LooperTest, RemoveFd_WhenCallbackAddedThenRemovedTwice_ReturnsOnceFirstTimeAndReturnsZeroSecondTime) {
+    Pipe pipe;
+    StubCallbackHandler handler(false);
+    handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
+
+    // First time.
+    int result = mLooper->removeFd(pipe.receiveFd);
+
+    EXPECT_EQ(1, result)
+            << "removeFd should return 1 first time because FD was registered";
+
+    // Second time.
+    result = mLooper->removeFd(pipe.receiveFd);
+
+    EXPECT_EQ(0, result)
+            << "removeFd should return 0 second time because FD was no longer registered";
+}
+
+TEST_F(LooperTest, PollOnce_WhenCallbackAddedTwice_OnlySecondCallbackShouldBeInvoked) {
+    Pipe pipe;
+    StubCallbackHandler handler1(true);
+    StubCallbackHandler handler2(true);
+
+    handler1.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
+    handler2.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT); // replace it
+    pipe.writeSignal(); // would cause FD to be considered signalled
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(100);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    ASSERT_EQ(OK, pipe.readSignal())
+            << "signal should actually have been written";
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should approx. zero because FD was already signalled";
+    EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
+            << "pollOnce result should be ALOOPER_POLL_CALLBACK because FD was signalled";
+    EXPECT_EQ(0, handler1.callbackCount)
+            << "original handler callback should not be invoked because it was replaced";
+    EXPECT_EQ(1, handler2.callbackCount)
+            << "replacement handler callback should be invoked";
+}
+
+
+} // namespace android
diff --git a/libs/utils/tests/PollLoop_test.cpp b/libs/utils/tests/PollLoop_test.cpp
deleted file mode 100644
index 02f1808..0000000
--- a/libs/utils/tests/PollLoop_test.cpp
+++ /dev/null
@@ -1,370 +0,0 @@
-//
-// Copyright 2010 The Android Open Source Project
-//
-
-#include <utils/PollLoop.h>
-#include <utils/Timers.h>
-#include <utils/StopWatch.h>
-#include <gtest/gtest.h>
-#include <unistd.h>
-#include <time.h>
-
-#include "TestHelpers.h"
-
-// # of milliseconds to fudge stopwatch measurements
-#define TIMING_TOLERANCE_MS 25
-
-namespace android {
-
-class DelayedWake : public DelayedTask {
-    sp<PollLoop> mPollLoop;
-
-public:
-    DelayedWake(int delayMillis, const sp<PollLoop> pollLoop) :
-        DelayedTask(delayMillis), mPollLoop(pollLoop) {
-    }
-
-protected:
-    virtual void doTask() {
-        mPollLoop->wake();
-    }
-};
-
-class DelayedWriteSignal : public DelayedTask {
-    Pipe* mPipe;
-
-public:
-    DelayedWriteSignal(int delayMillis, Pipe* pipe) :
-        DelayedTask(delayMillis), mPipe(pipe) {
-    }
-
-protected:
-    virtual void doTask() {
-        mPipe->writeSignal();
-    }
-};
-
-class CallbackHandler {
-public:
-    void setCallback(const sp<PollLoop>& pollLoop, int fd, int events) {
-        pollLoop->setCallback(fd, events, staticHandler, this);
-    }
-
-protected:
-    virtual ~CallbackHandler() { }
-
-    virtual bool handler(int fd, int events) = 0;
-
-private:
-    static bool staticHandler(int fd, int events, void* data) {
-        return static_cast<CallbackHandler*>(data)->handler(fd, events);
-    }
-};
-
-class StubCallbackHandler : public CallbackHandler {
-public:
-    bool nextResult;
-    int callbackCount;
-
-    int fd;
-    int events;
-
-    StubCallbackHandler(bool nextResult) : nextResult(nextResult),
-            callbackCount(0), fd(-1), events(-1) {
-    }
-
-protected:
-    virtual bool handler(int fd, int events) {
-        callbackCount += 1;
-        this->fd = fd;
-        this->events = events;
-        return nextResult;
-    }
-};
-
-class PollLoopTest : public testing::Test {
-protected:
-    sp<PollLoop> mPollLoop;
-
-    virtual void SetUp() {
-        mPollLoop = new PollLoop(false);
-    }
-
-    virtual void TearDown() {
-        mPollLoop.clear();
-    }
-};
-
-
-TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndNotAwoken_WaitsForTimeoutAndReturnsFalse) {
-    StopWatch stopWatch("pollOnce");
-    int32_t result = mPollLoop->pollOnce(100);
-    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
-
-    EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
-            << "elapsed time should approx. equal timeout";
-    EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
-            << "pollOnce result should be POLL_TIMEOUT";
-}
-
-TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndAwokenBeforeWaiting_ImmediatelyReturnsTrue) {
-    mPollLoop->wake();
-
-    StopWatch stopWatch("pollOnce");
-    int32_t result = mPollLoop->pollOnce(1000);
-    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
-
-    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
-            << "elapsed time should approx. zero because wake() was called before waiting";
-    EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
-            << "pollOnce result should be POLL_CALLBACK because loop was awoken";
-}
-
-TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndAwokenWhileWaiting_PromptlyReturnsTrue) {
-    sp<DelayedWake> delayedWake = new DelayedWake(100, mPollLoop);
-    delayedWake->run();
-
-    StopWatch stopWatch("pollOnce");
-    int32_t result = mPollLoop->pollOnce(1000);
-    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
-
-    EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
-            << "elapsed time should approx. equal wake delay";
-    EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
-            << "pollOnce result should be POLL_CALLBACK because loop was awoken";
-}
-
-TEST_F(PollLoopTest, PollOnce_WhenZeroTimeoutAndNoRegisteredFDs_ImmediatelyReturnsFalse) {
-    StopWatch stopWatch("pollOnce");
-    int32_t result = mPollLoop->pollOnce(0);
-    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
-
-    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
-            << "elapsed time should be approx. zero";
-    EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
-            << "pollOnce result should be POLL_TIMEOUT";
-}
-
-TEST_F(PollLoopTest, PollOnce_WhenZeroTimeoutAndNoSignalledFDs_ImmediatelyReturnsFalse) {
-    Pipe pipe;
-    StubCallbackHandler handler(true);
-
-    handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
-
-    StopWatch stopWatch("pollOnce");
-    int32_t result = mPollLoop->pollOnce(0);
-    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
-
-    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
-            << "elapsed time should be approx. zero";
-    EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
-            << "pollOnce result should be POLL_TIMEOUT";
-    EXPECT_EQ(0, handler.callbackCount)
-            << "callback should not have been invoked because FD was not signalled";
-}
-
-TEST_F(PollLoopTest, PollOnce_WhenZeroTimeoutAndSignalledFD_ImmediatelyInvokesCallbackAndReturnsTrue) {
-    Pipe pipe;
-    StubCallbackHandler handler(true);
-
-    ASSERT_EQ(OK, pipe.writeSignal());
-    handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
-
-    StopWatch stopWatch("pollOnce");
-    int32_t result = mPollLoop->pollOnce(0);
-    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
-
-    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
-            << "elapsed time should be approx. zero";
-    EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
-            << "pollOnce result should be POLL_CALLBACK because FD was signalled";
-    EXPECT_EQ(1, handler.callbackCount)
-            << "callback should be invoked exactly once";
-    EXPECT_EQ(pipe.receiveFd, handler.fd)
-            << "callback should have received pipe fd as parameter";
-    EXPECT_EQ(POLL_IN, handler.events)
-            << "callback should have received POLL_IN as events";
-}
-
-TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndNoSignalledFDs_WaitsForTimeoutAndReturnsFalse) {
-    Pipe pipe;
-    StubCallbackHandler handler(true);
-
-    handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
-
-    StopWatch stopWatch("pollOnce");
-    int32_t result = mPollLoop->pollOnce(100);
-    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
-
-    EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
-            << "elapsed time should approx. equal timeout";
-    EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
-            << "pollOnce result should be POLL_TIMEOUT";
-    EXPECT_EQ(0, handler.callbackCount)
-            << "callback should not have been invoked because FD was not signalled";
-}
-
-TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndSignalledFDBeforeWaiting_ImmediatelyInvokesCallbackAndReturnsTrue) {
-    Pipe pipe;
-    StubCallbackHandler handler(true);
-
-    pipe.writeSignal();
-    handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
-
-    StopWatch stopWatch("pollOnce");
-    int32_t result = mPollLoop->pollOnce(100);
-    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
-
-    ASSERT_EQ(OK, pipe.readSignal())
-            << "signal should actually have been written";
-    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
-            << "elapsed time should be approx. zero";
-    EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
-            << "pollOnce result should be POLL_CALLBACK because FD was signalled";
-    EXPECT_EQ(1, handler.callbackCount)
-            << "callback should be invoked exactly once";
-    EXPECT_EQ(pipe.receiveFd, handler.fd)
-            << "callback should have received pipe fd as parameter";
-    EXPECT_EQ(POLL_IN, handler.events)
-            << "callback should have received POLL_IN as events";
-}
-
-TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndSignalledFDWhileWaiting_PromptlyInvokesCallbackAndReturnsTrue) {
-    Pipe pipe;
-    StubCallbackHandler handler(true);
-    sp<DelayedWriteSignal> delayedWriteSignal = new DelayedWriteSignal(100, & pipe);
-
-    handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
-    delayedWriteSignal->run();
-
-    StopWatch stopWatch("pollOnce");
-    int32_t result = mPollLoop->pollOnce(1000);
-    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
-
-    ASSERT_EQ(OK, pipe.readSignal())
-            << "signal should actually have been written";
-    EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
-            << "elapsed time should approx. equal signal delay";
-    EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
-            << "pollOnce result should be POLL_CALLBACK because FD was signalled";
-    EXPECT_EQ(1, handler.callbackCount)
-            << "callback should be invoked exactly once";
-    EXPECT_EQ(pipe.receiveFd, handler.fd)
-            << "callback should have received pipe fd as parameter";
-    EXPECT_EQ(POLL_IN, handler.events)
-            << "callback should have received POLL_IN as events";
-}
-
-TEST_F(PollLoopTest, PollOnce_WhenCallbackAddedThenRemoved_CallbackShouldNotBeInvoked) {
-    Pipe pipe;
-    StubCallbackHandler handler(true);
-
-    handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
-    pipe.writeSignal(); // would cause FD to be considered signalled
-    mPollLoop->removeCallback(pipe.receiveFd);
-
-    StopWatch stopWatch("pollOnce");
-    int32_t result = mPollLoop->pollOnce(100);
-    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
-
-    ASSERT_EQ(OK, pipe.readSignal())
-            << "signal should actually have been written";
-    EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
-            << "elapsed time should approx. equal timeout because FD was no longer registered";
-    EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
-            << "pollOnce result should be POLL_TIMEOUT";
-    EXPECT_EQ(0, handler.callbackCount)
-            << "callback should not be invoked";
-}
-
-TEST_F(PollLoopTest, PollOnce_WhenCallbackReturnsFalse_CallbackShouldNotBeInvokedAgainLater) {
-    Pipe pipe;
-    StubCallbackHandler handler(false);
-
-    handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
-
-    // First loop: Callback is registered and FD is signalled.
-    pipe.writeSignal();
-
-    StopWatch stopWatch("pollOnce");
-    int32_t result = mPollLoop->pollOnce(0);
-    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
-
-    ASSERT_EQ(OK, pipe.readSignal())
-            << "signal should actually have been written";
-    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
-            << "elapsed time should approx. equal zero because FD was already signalled";
-    EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
-            << "pollOnce result should be POLL_CALLBACK because FD was signalled";
-    EXPECT_EQ(1, handler.callbackCount)
-            << "callback should be invoked";
-
-    // Second loop: Callback is no longer registered and FD is signalled.
-    pipe.writeSignal();
-
-    stopWatch.reset();
-    result = mPollLoop->pollOnce(0);
-    elapsedMillis = ns2ms(stopWatch.elapsedTime());
-
-    ASSERT_EQ(OK, pipe.readSignal())
-            << "signal should actually have been written";
-    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
-            << "elapsed time should approx. equal zero because timeout was zero";
-    EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
-            << "pollOnce result should be POLL_TIMEOUT";
-    EXPECT_EQ(1, handler.callbackCount)
-            << "callback should not be invoked this time";
-}
-
-TEST_F(PollLoopTest, RemoveCallback_WhenCallbackNotAdded_ReturnsFalse) {
-    bool result = mPollLoop->removeCallback(1);
-
-    EXPECT_FALSE(result)
-            << "removeCallback should return false because FD not registered";
-}
-
-TEST_F(PollLoopTest, RemoveCallback_WhenCallbackAddedThenRemovedTwice_ReturnsTrueFirstTimeAndReturnsFalseSecondTime) {
-    Pipe pipe;
-    StubCallbackHandler handler(false);
-    handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
-
-    // First time.
-    bool result = mPollLoop->removeCallback(pipe.receiveFd);
-
-    EXPECT_TRUE(result)
-            << "removeCallback should return true first time because FD was registered";
-
-    // Second time.
-    result = mPollLoop->removeCallback(pipe.receiveFd);
-
-    EXPECT_FALSE(result)
-            << "removeCallback should return false second time because FD was no longer registered";
-}
-
-TEST_F(PollLoopTest, PollOnce_WhenCallbackAddedTwice_OnlySecondCallbackShouldBeInvoked) {
-    Pipe pipe;
-    StubCallbackHandler handler1(true);
-    StubCallbackHandler handler2(true);
-
-    handler1.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
-    handler2.setCallback(mPollLoop, pipe.receiveFd, POLL_IN); // replace it
-    pipe.writeSignal(); // would cause FD to be considered signalled
-
-    StopWatch stopWatch("pollOnce");
-    int32_t result = mPollLoop->pollOnce(100);
-    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
-
-    ASSERT_EQ(OK, pipe.readSignal())
-            << "signal should actually have been written";
-    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
-            << "elapsed time should approx. zero because FD was already signalled";
-    EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
-            << "pollOnce result should be POLL_CALLBACK because FD was signalled";
-    EXPECT_EQ(0, handler1.callbackCount)
-            << "original handler callback should not be invoked because it was replaced";
-    EXPECT_EQ(1, handler2.callbackCount)
-            << "replacement handler callback should be invoked";
-}
-
-
-} // namespace android
diff --git a/location/java/android/location/Geocoder.java b/location/java/android/location/Geocoder.java
index 546bb9d..ac7eb8b 100644
--- a/location/java/android/location/Geocoder.java
+++ b/location/java/android/location/Geocoder.java
@@ -41,7 +41,7 @@
  * The Geocoder class requires a backend service that is not included in
  * the core android framework.  The Geocoder query methods will return an
  * empty list if there no backend service in the platform.  Use the
- * isImplemented() method to determine whether a Geocoder implementation
+ * isPresent() method to determine whether a Geocoder implementation
  * exists.
  */
 public final class Geocoder {
@@ -56,13 +56,13 @@
      * connectivity may still cause these methods to return null or
      * empty lists.
      */
-    public static Boolean isImplemented() {
+    public static boolean isPresent() {
         IBinder b = ServiceManager.getService(Context.LOCATION_SERVICE);
         ILocationManager lm = ILocationManager.Stub.asInterface(b);
         try {
-            return lm.geocoderIsImplemented();
+            return lm.geocoderIsPresent();
         } catch (RemoteException e) {
-            Log.e(TAG, "isImplemented: got RemoteException", e);
+            Log.e(TAG, "isPresent: got RemoteException", e);
             return false;
         }
     }
diff --git a/location/java/android/location/GeocoderParams.java b/location/java/android/location/GeocoderParams.java
index 8b8e63b..174fe3e 100644
--- a/location/java/android/location/GeocoderParams.java
+++ b/location/java/android/location/GeocoderParams.java
@@ -29,6 +29,8 @@
  * as well as the Geocoder client's package name for geocoder server
  * logging.  This information is kept in a separate class to allow for
  * future expansion of the IGeocodeProvider interface.
+ *
+ * @hide
  */
 public class GeocoderParams implements Parcelable {
     private Locale mLocale;
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index 32d4b27..2255bf2 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -67,7 +67,7 @@
     // it need not be shared with other providers.
     void reportLocation(in Location location, boolean passive);
 
-    boolean geocoderIsImplemented();
+    boolean geocoderIsPresent();
     String getFromLocation(double latitude, double longitude, int maxResults,
         in GeocoderParams params, out List<Address> addrs);
     String getFromLocationName(String locationName,
diff --git a/location/java/android/location/ILocationProvider.aidl b/location/java/android/location/ILocationProvider.aidl
index 2b9782a..ecf6789 100644
--- a/location/java/android/location/ILocationProvider.aidl
+++ b/location/java/android/location/ILocationProvider.aidl
@@ -20,6 +20,7 @@
 import android.location.Location;
 import android.net.NetworkInfo;
 import android.os.Bundle;
+import android.os.WorkSource;
 
 /**
  * Binder interface for services that implement location providers.
@@ -43,7 +44,7 @@
     long getStatusUpdateTime();
     String getInternalState();
     void enableLocationTracking(boolean enable);
-    void setMinTime(long minTime);
+    void setMinTime(long minTime, in WorkSource ws);
     void updateNetworkState(int state, in NetworkInfo info);
     void updateLocation(in Location location);
     boolean sendExtraCommand(String command, inout Bundle extras);
diff --git a/location/java/android/location/provider/GeocodeProvider.java b/location/java/android/location/provider/GeocodeProvider.java
index 9a58763..493c631 100644
--- a/location/java/android/location/provider/GeocodeProvider.java
+++ b/location/java/android/location/provider/GeocodeProvider.java
@@ -29,6 +29,8 @@
  * outside of the core android platform.
  * Geocode providers can be implemented as services and return the result of
  * {@link GeocodeProvider#getBinder()} in its getBinder() method.
+ *
+ * @hide
  */
 public abstract class GeocodeProvider {
 
diff --git a/location/java/android/location/provider/LocationProvider.java b/location/java/android/location/provider/LocationProvider.java
index cf939de..14dea14 100644
--- a/location/java/android/location/provider/LocationProvider.java
+++ b/location/java/android/location/provider/LocationProvider.java
@@ -26,6 +26,7 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.WorkSource;
 import android.util.Log;
 
 /**
@@ -33,6 +34,8 @@
  * outside of the core android platform.
  * Location providers can be implemented as services and return the result of
  * {@link LocationProvider#getBinder()} in its getBinder() method.
+ *
+ * @hide
  */
 public abstract class LocationProvider {
 
@@ -106,8 +109,8 @@
             LocationProvider.this.onEnableLocationTracking(enable);
         }
 
-        public void setMinTime(long minTime) {
-            LocationProvider.this.onSetMinTime(minTime);
+        public void setMinTime(long minTime, WorkSource ws) {
+            LocationProvider.this.onSetMinTime(minTime, ws);
         }
 
         public void updateNetworkState(int state, NetworkInfo info) {
@@ -123,11 +126,11 @@
         }
 
         public void addListener(int uid) {
-            LocationProvider.this.onAddListener(uid);
+            LocationProvider.this.onAddListener(uid, new WorkSource(uid));
         }
 
         public void removeListener(int uid) {
-            LocationProvider.this.onRemoveListener(uid);
+            LocationProvider.this.onRemoveListener(uid, new WorkSource(uid));
         }
     };
 
@@ -303,8 +306,9 @@
      * the frequency of updates to match the requested frequency.
      *
      * @param minTime the smallest minTime value over all listeners for this provider.
+     * @param ws the source this work is coming from.
      */
-    public abstract void onSetMinTime(long minTime);
+    public abstract void onSetMinTime(long minTime, WorkSource ws);
 
     /**
      * Updates the network state for the given provider. This function must
@@ -340,14 +344,16 @@
      * Notifies the location provider when a new client is listening for locations.
      *
      * @param uid user ID of the new client.
+     * @param ws a WorkSource representation of the client.
      */
-    public abstract void onAddListener(int uid);
+    public abstract void onAddListener(int uid, WorkSource ws);
 
     /**
      * Notifies the location provider when a client is no longer listening for locations.
      *
      * @param uid user ID of the client no longer listening.
+     * @param ws a WorkSource representation of the client.
      */
-    public abstract void onRemoveListener(int uid);
+    public abstract void onRemoveListener(int uid, WorkSource ws);
 }
 
diff --git a/media/java/android/media/AudioEffect.java b/media/java/android/media/AudioEffect.java
index 35038fa..ed7601e 100644
--- a/media/java/android/media/AudioEffect.java
+++ b/media/java/android/media/AudioEffect.java
@@ -16,12 +16,14 @@
 
 package android.media;
 
-import android.util.Log;
-import java.lang.ref.WeakReference;
-import java.io.IOException;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.util.Log;
+import java.io.IOException;
+import java.lang.ref.WeakReference;
 import java.nio.ByteOrder;
 import java.nio.ByteBuffer;
 import java.util.UUID;
@@ -839,6 +841,126 @@
                 byte[] value);
     }
 
+
+    // -------------------------------------------------------------------------
+    // Audio Effect Control panel intents
+    // -------------------------------------------------------------------------
+
+    /**
+     *  Intent to launch an audio effect control panel UI.
+     *  <p>The goal of this intent is to enable separate implementations of music/media player
+     *  applications and audio effect control application or services.
+     *  This will allow platform vendors to offer more advanced control options for standard effects
+     *  or control for platform specific effects.
+     *  <p>The intent carries a number of extras used by the player application to communicate
+     *  necessary pieces of information to the control panel application.
+     *  <p>The calling application must use the
+     *  {@link android.app.Activity#startActivityForResult(Intent, int)} method to launch the
+     *  control panel so that its package name is indicated and used by the control panel
+     *  application to keep track of changes for this particular application.
+     *  <p>The {@link #EXTRA_AUDIO_SESSION} extra will indicate an audio session to which the
+     *  audio effects should be applied. If no audio session is specified, either one of the
+     *  follownig will happen:
+     *  <p>- If an audio session was previously opened by the calling application with
+     *  {@link #ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION} intent, the effect changes will
+     *  be applied to that session.
+     *  <p>- If no audio session is opened, the changes will be stored in the package specific
+     *  storage area and applied whenever a new audio session is opened by this application.
+     *  <p>The {@link #EXTRA_CONTENT_TYPE} extra will help the control panel application
+     *  customize both the UI layout and the default audio effect settings if none are already
+     *  stored for the calling application.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL =
+        "android.media.action.DISPLAY_AUDIO_EFFECT_CONTROL_PANEL";
+
+    /**
+     *  Intent to signal to the effect control application or service that a new audio session
+     *  is opened and requires audio effects to be applied.
+     *  <p>This is different from {@link #ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL} in that no
+     *  UI should be displayed in this case. Music player applications can broadcast this intent
+     *  before starting playback to make sure that any audio effect settings previously selected
+     *  by the user are applied.
+     *  <p>The effect control application receiving this intent will look for previously stored
+     *  settings for the calling application, create all required audio effects and apply the
+     *  effect settings to the specified audio session.
+     *  <p>The calling package name is indicated by the {@link #EXTRA_PACKAGE_NAME} extra and the
+     *  audio session ID by the {@link #EXTRA_AUDIO_SESSION} extra. Both extras are mandatory.
+     *  <p>If no stored settings are found for the calling application, default settings for the
+     *  content type indicated by {@link #EXTRA_CONTENT_TYPE} will be applied. The default settings
+     *  for a given content type are platform specific.
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION =
+        "android.media.action.OPEN_AUDIO_EFFECT_CONTROL_SESSION";
+
+    /**
+     *  Intent to signal to the effect control application or service that an audio session
+     *  is closed and that effects should not be applied anymore.
+     *  <p>The effect control application receiving this intent will delete all effects on
+     *  this session and store current settings in package specific storage.
+     *  <p>The calling package name is indicated by the {@link #EXTRA_PACKAGE_NAME} extra and the
+     *  audio session ID by the {@link #EXTRA_AUDIO_SESSION} extra. Both extras are mandatory.
+     *  <p>It is good practice for applications to broadcast this intent when music playback stops
+     *  and/or when exiting to free system resources consumed by audio effect engines.
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION =
+        "android.media.action.CLOSE_AUDIO_EFFECT_CONTROL_SESSION";
+
+    /**
+     * Contains the ID of the audio session the effects should be applied to.
+     * <p>This extra is for use with {@link #ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL},
+     * {@link #ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION} and
+     * {@link #ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION} intents.
+     * <p>The extra value is of type int and is the audio session ID.
+     *
+     *  @see android.media.MediaPlayer#setAudioSessionId(int)
+     */
+     public static final String EXTRA_AUDIO_SESSION = "android.media.extra.AUDIO_SESSION";
+
+    /**
+     * Contains the package name of the calling application.
+     * <p>This extra is for use with {@link #ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION} and
+     * {@link #ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION} intents.
+     * <p>The extra value is a string containing the full package name.
+     */
+    public static final String EXTRA_PACKAGE_NAME = "android.media.extra.PACKAGE_NAME";
+
+    /**
+     * Indicates which type of content is played by the application.
+     * <p>This extra is for use with {@link #ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL} and
+     * {@link #ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION} intents.
+     * <p>This information is used by the effect control application to customize UI and select
+     * appropriate default effect settings. The content type is one of the following:
+     * <ul>
+     *   <li>{@link #CONTENT_TYPE_MUSIC}</li>
+     *   <li>{@link #CONTENT_TYPE_MOVIE}</li>
+     *   <li>{@link #CONTENT_TYPE_GAME}</li>
+     *   <li>{@link #CONTENT_TYPE_VOICE}</li>
+     * </ul>
+     * If omitted, the content type defaults to {@link #CONTENT_TYPE_MUSIC}.
+     */
+    public static final String EXTRA_CONTENT_TYPE = "android.media.extra.CONTENT_TYPE";
+
+    /**
+     * Value for {@link #EXTRA_CONTENT_TYPE} when the type of content played is music
+     */
+    public static final int  CONTENT_TYPE_MUSIC = 0;
+    /**
+     * Value for {@link #EXTRA_CONTENT_TYPE} when the type of content played is video or movie
+     */
+    public static final int  CONTENT_TYPE_MOVIE = 1;
+    /**
+     * Value for {@link #EXTRA_CONTENT_TYPE} when the type of content played is game audio
+     */
+    public static final int  CONTENT_TYPE_GAME = 2;
+    /**
+     * Value for {@link #EXTRA_CONTENT_TYPE} when the type of content played is voice audio
+     */
+    public static final int  CONTENT_TYPE_VOICE = 3;
+
+
     // ---------------------------------------------------------
     // Inner classes
     // --------------------
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index b8403e1..280def9 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1210,7 +1210,6 @@
      * effect which can be applied on any sound source that directs a certain amount of its
      * energy to this effect. This amount is defined by setAuxEffectSendLevel().
      * {@see #setAuxEffectSendLevel(float)}.
-     // TODO when AudioEffect is unhidden
      * <p>After creating an auxiliary effect (e.g. {@link android.media.EnvironmentalReverb}),
      * retrieve its ID with {@link android.media.AudioEffect#getId()} and use it when calling
      * this method to attach the player to the effect.
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index 90756d0..8f40130 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -145,6 +145,7 @@
                                 void          *pParam,
                                 size_t        *pValueSize,
                                 void          *pValue);
+int Effect_setEnabled(EffectContext *pContext, bool enabled);
 
 /* Effect Library Interface Implementation */
 extern "C" int EffectQueryNumberEffects(uint32_t *pNumEffects){
@@ -303,32 +304,34 @@
     }
     LOGV("\tEffectCreate - pBundledContext is %p", pContext->pBundledContext);
 
+    SessionContext *pSessionContext = &GlobalSessionMemory[pContext->pBundledContext->SessionNo];
+
     // Create each Effect
     if (memcmp(uuid, &gBassBoostDescriptor.uuid, sizeof(effect_uuid_t)) == 0){
         // Create Bass Boost
         LOGV("\tEffectCreate - Effect to be created is LVM_BASS_BOOST");
-        GlobalSessionMemory[pContext->pBundledContext->SessionNo].bBassInstantiated = LVM_TRUE;
+        pSessionContext->bBassInstantiated = LVM_TRUE;
 
         pContext->itfe       = &gLvmEffectInterface;
         pContext->EffectType = LVM_BASS_BOOST;
     } else if (memcmp(uuid, &gVirtualizerDescriptor.uuid, sizeof(effect_uuid_t)) == 0){
         // Create Virtualizer
         LOGV("\tEffectCreate - Effect to be created is LVM_VIRTUALIZER");
-        GlobalSessionMemory[pContext->pBundledContext->SessionNo].bVirtualizerInstantiated=LVM_TRUE;
+        pSessionContext->bVirtualizerInstantiated=LVM_TRUE;
 
         pContext->itfe       = &gLvmEffectInterface;
         pContext->EffectType = LVM_VIRTUALIZER;
     } else if (memcmp(uuid, &gEqualizerDescriptor.uuid, sizeof(effect_uuid_t)) == 0){
         // Create Equalizer
         LOGV("\tEffectCreate - Effect to be created is LVM_EQUALIZER");
-        GlobalSessionMemory[pContext->pBundledContext->SessionNo].bEqualizerInstantiated = LVM_TRUE;
+        pSessionContext->bEqualizerInstantiated = LVM_TRUE;
 
         pContext->itfe       = &gLvmEffectInterface;
         pContext->EffectType = LVM_EQUALIZER;
     } else if (memcmp(uuid, &gVolumeDescriptor.uuid, sizeof(effect_uuid_t)) == 0){
         // Create Volume
         LOGV("\tEffectCreate - Effect to be created is LVM_VOLUME");
-        GlobalSessionMemory[pContext->pBundledContext->SessionNo].bVolumeInstantiated = LVM_TRUE;
+        pSessionContext->bVolumeInstantiated = LVM_TRUE;
 
         pContext->itfe       = &gLvmEffectInterface;
         pContext->EffectType = LVM_VOLUME;
@@ -353,29 +356,33 @@
         return -EINVAL;
     }
 
+
+    Effect_setEnabled(pContext, LVM_FALSE);
+
+    SessionContext *pSessionContext = &GlobalSessionMemory[pContext->pBundledContext->SessionNo];
+
     // Clear the instantiated flag for the effect
     if(pContext->EffectType == LVM_BASS_BOOST) {
         LOGV("\tEffectRelease LVM_BASS_BOOST Clearing global intstantiated flag");
-        GlobalSessionMemory[pContext->pBundledContext->SessionNo].bBassInstantiated = LVM_FALSE;
+        pSessionContext->bBassInstantiated = LVM_FALSE;
     } else if(pContext->EffectType == LVM_VIRTUALIZER) {
         LOGV("\tEffectRelease LVM_VIRTUALIZER Clearing global intstantiated flag");
-        GlobalSessionMemory[pContext->pBundledContext->SessionNo].bVirtualizerInstantiated
-            = LVM_FALSE;
+        pSessionContext->bVirtualizerInstantiated = LVM_FALSE;
     } else if(pContext->EffectType == LVM_EQUALIZER) {
         LOGV("\tEffectRelease LVM_EQUALIZER Clearing global intstantiated flag");
-        GlobalSessionMemory[pContext->pBundledContext->SessionNo].bEqualizerInstantiated =LVM_FALSE;
+        pSessionContext->bEqualizerInstantiated =LVM_FALSE;
     } else if(pContext->EffectType == LVM_VOLUME) {
         LOGV("\tEffectRelease LVM_VOLUME Clearing global intstantiated flag");
-        GlobalSessionMemory[pContext->pBundledContext->SessionNo].bVolumeInstantiated = LVM_FALSE;
+        pSessionContext->bVolumeInstantiated = LVM_FALSE;
     } else {
         LOGV("\tLVM_ERROR : EffectRelease : Unsupported effect\n\n\n\n\n\n\n");
     }
 
     // if all effects are no longer instantiaed free the lvm memory and delete BundledEffectContext
-    if((GlobalSessionMemory[pContext->pBundledContext->SessionNo].bBassInstantiated == LVM_FALSE)&&
-    (GlobalSessionMemory[pContext->pBundledContext->SessionNo].bVolumeInstantiated == LVM_FALSE)&&
-    (GlobalSessionMemory[pContext->pBundledContext->SessionNo].bEqualizerInstantiated ==LVM_FALSE)&&
-    (GlobalSessionMemory[pContext->pBundledContext->SessionNo].bVirtualizerInstantiated==LVM_FALSE))
+    if ((pSessionContext->bBassInstantiated == LVM_FALSE) &&
+            (pSessionContext->bVolumeInstantiated == LVM_FALSE) &&
+            (pSessionContext->bEqualizerInstantiated ==LVM_FALSE) &&
+            (pSessionContext->bVirtualizerInstantiated==LVM_FALSE))
     {
         #ifdef LVM_PCM
         if (pContext->pBundledContext->PcmInPtr != NULL) {
@@ -402,8 +409,8 @@
         }
 
         LOGV("\tEffectRelease: All effects are no longer instantiated\n");
-        GlobalSessionMemory[pContext->pBundledContext->SessionNo].bBundledEffectsEnabled =LVM_FALSE;
-        GlobalSessionMemory[pContext->pBundledContext->SessionNo].pBundledContext = LVM_NULL;
+        pSessionContext->bBundledEffectsEnabled =LVM_FALSE;
+        pSessionContext->pBundledContext = LVM_NULL;
         LOGV("\tEffectRelease: Freeing LVM Bundle memory\n");
         LvmEffect_free(pContext);
         LOGV("\tEffectRelease: Deleting LVM Bundle context %p\n", pContext->pBundledContext);
@@ -2377,6 +2384,107 @@
     return db_fix;
 }
 
+//----------------------------------------------------------------------------
+// Effect_setEnabled()
+//----------------------------------------------------------------------------
+// Purpose:
+// Enable or disable effect
+//
+// Inputs:
+//  pContext      - pointer to effect context
+//  enabled       - true if enabling the effect, false otherwise
+//
+// Outputs:
+//
+//----------------------------------------------------------------------------
+
+int Effect_setEnabled(EffectContext *pContext, bool enabled)
+{
+    LOGV("\tEffect_setEnabled() type %d, enabled %d", pContext->EffectType, enabled);
+
+    if (enabled) {
+        switch (pContext->EffectType) {
+            case LVM_BASS_BOOST:
+                if (pContext->pBundledContext->bBassEnabled == LVM_TRUE) {
+                     LOGV("\tLVM_ERROR : Effect_setEnabled() LVM_BASS_BOOST is already enabled");
+                     return -EINVAL;
+                }
+                pContext->pBundledContext->SamplesToExitCountBb =
+                     (LVM_INT32)(pContext->pBundledContext->SamplesPerSecond*0.1);
+                pContext->pBundledContext->bBassEnabled = LVM_TRUE;
+                break;
+            case LVM_EQUALIZER:
+                if (pContext->pBundledContext->bEqualizerEnabled == LVM_TRUE) {
+                    LOGV("\tLVM_ERROR : Effect_setEnabled() LVM_EQUALIZER is already enabled");
+                    return -EINVAL;
+                }
+                pContext->pBundledContext->SamplesToExitCountEq =
+                     (LVM_INT32)(pContext->pBundledContext->SamplesPerSecond*0.1);
+                pContext->pBundledContext->bEqualizerEnabled = LVM_TRUE;
+                break;
+            case LVM_VIRTUALIZER:
+                if (pContext->pBundledContext->bVirtualizerEnabled == LVM_TRUE) {
+                    LOGV("\tLVM_ERROR : Effect_setEnabled() LVM_VIRTUALIZER is already enabled");
+                    return -EINVAL;
+                }
+                pContext->pBundledContext->SamplesToExitCountVirt =
+                     (LVM_INT32)(pContext->pBundledContext->SamplesPerSecond*0.1);
+                pContext->pBundledContext->bVirtualizerEnabled = LVM_TRUE;
+                break;
+            case LVM_VOLUME:
+                if (pContext->pBundledContext->bVolumeEnabled == LVM_TRUE) {
+                    LOGV("\tLVM_ERROR : Effect_setEnabled() LVM_VOLUME is already enabled");
+                    return -EINVAL;
+                }
+                pContext->pBundledContext->bVolumeEnabled = LVM_TRUE;
+                break;
+            default:
+                LOGV("\tLVM_ERROR : Effect_setEnabled() invalid effect type");
+                return -EINVAL;
+        }
+        pContext->pBundledContext->NumberEffectsEnabled++;
+        LvmEffect_enable(pContext);
+    } else {
+        switch (pContext->EffectType) {
+            case LVM_BASS_BOOST:
+                if (pContext->pBundledContext->bBassEnabled == LVM_FALSE) {
+                    LOGV("\tLVM_ERROR : Effect_setEnabled() LVM_BASS_BOOST is already disabled");
+                    return -EINVAL;
+                }
+                pContext->pBundledContext->bBassEnabled = LVM_FALSE;
+                break;
+            case LVM_EQUALIZER:
+                if (pContext->pBundledContext->bEqualizerEnabled == LVM_FALSE) {
+                    LOGV("\tLVM_ERROR : Effect_setEnabled() LVM_EQUALIZER is already disabled");
+                    return -EINVAL;
+                }
+                pContext->pBundledContext->bEqualizerEnabled = LVM_FALSE;
+                break;
+            case LVM_VIRTUALIZER:
+                if (pContext->pBundledContext->bVirtualizerEnabled == LVM_FALSE) {
+                    LOGV("\tLVM_ERROR : Effect_setEnabled() LVM_VIRTUALIZER is already disabled");
+                    return -EINVAL;
+                }
+                pContext->pBundledContext->bVirtualizerEnabled = LVM_FALSE;
+                break;
+            case LVM_VOLUME:
+                if (pContext->pBundledContext->bVolumeEnabled == LVM_FALSE) {
+                    LOGV("\tLVM_ERROR : Effect_setEnabled() LVM_VOLUME is already disabled");
+                    return -EINVAL;
+                }
+                pContext->pBundledContext->bVolumeEnabled = LVM_FALSE;
+                break;
+            default:
+                LOGV("\tLVM_ERROR : Effect_setEnabled() invalid effect type");
+                return -EINVAL;
+        }
+        pContext->pBundledContext->NumberEffectsEnabled--;
+        LvmEffect_disable(pContext);
+    }
+
+    return 0;
+}
+
 } // namespace
 } // namespace
 
@@ -2426,7 +2534,7 @@
             //LOGV("\tEffect_process: Waiting to turn off BASS_BOOST, %d samples left",
             //    pContext->pBundledContext->SamplesToExitCountBb);
         } else {
-        status = -ENODATA;
+            status = -ENODATA;
         }
     }
     if ((pContext->pBundledContext->bVolumeEnabled == LVM_FALSE)&&
@@ -2843,62 +2951,8 @@
                 LOGV("\tLVM_ERROR : Effect_command cmdCode Case: EFFECT_CMD_ENABLE: ERROR");
                 return -EINVAL;
             }
-            switch (pContext->EffectType){
-                case LVM_BASS_BOOST:
-                    if(pContext->pBundledContext->bBassEnabled == LVM_TRUE){
-                         LOGV("\tLVM_ERROR : BassBoost_command cmdCode Case: "
-                                 "EFFECT_CMD_ENABLE: ERROR-Effect is already enabled");
-                         return -EINVAL;
-                    }
-                    pContext->pBundledContext->bBassEnabled = LVM_TRUE;
-                    //LOGV("\tEffect_command cmdCode Case:EFFECT_CMD_ENABLE LVM_BASS_BOOSTenabled");
-                    break;
-                case LVM_EQUALIZER:
-                    if(pContext->pBundledContext->bEqualizerEnabled == LVM_TRUE){
-                         LOGV("\tLVM_ERROR : Equalizer_command cmdCode Case: "
-                                 "EFFECT_CMD_ENABLE: ERROR-Effect is already enabled");
-                         return -EINVAL;
-                    }
-                    pContext->pBundledContext->bEqualizerEnabled = LVM_TRUE;
-                    //LOGV("\tEffect_command cmdCode Case:EFFECT_CMD_ENABLE LVM_EQUALIZER enabled");
-                    break;
-                case LVM_VIRTUALIZER:
-                    if(pContext->pBundledContext->bVirtualizerEnabled == LVM_TRUE){
-                         LOGV("\tLVM_ERROR : Virtualizer_command cmdCode Case: "
-                                 "EFFECT_CMD_ENABLE: ERROR-Effect is already enabled");
-                         return -EINVAL;
-                    }
-                    pContext->pBundledContext->bVirtualizerEnabled = LVM_TRUE;
-                    //LOGV("\tEffect_command cmdCode :EFFECT_CMD_ENABLE LVM_VIRTUALIZER enabled");
-                    break;
-                case LVM_VOLUME:
-                    if(pContext->pBundledContext->bVolumeEnabled == LVM_TRUE){
-                         LOGV("\tLVM_ERROR : Volume_command cmdCode Case: "
-                                 "EFFECT_CMD_ENABLE: ERROR-Effect is already enabled");
-                         return -EINVAL;
-                    }
-                    pContext->pBundledContext->bVolumeEnabled = LVM_TRUE;
-                    LOGV("\tEffect_command cmdCode Case: EFFECT_CMD_ENABLE LVM_VOLUME enabled");
-                    break;
-                default:
-                    LOGV("\tLVM_ERROR : Effect_command cmdCode Case: "
-                        "EFFECT_CMD_ENABLE: ERROR, invalid Effect Type");
-                    return -EINVAL;
-            }
-            *(int *)pReplyData = 0;
-            pContext->pBundledContext->NumberEffectsEnabled++;
-            android::LvmEffect_enable(pContext);
-            pContext->pBundledContext->SamplesToExitCountEq =
-                 (LVM_INT32)(pContext->pBundledContext->SamplesPerSecond*0.1); // 0.1 secs Stereo
-            pContext->pBundledContext->SamplesToExitCountBb =
-                 (LVM_INT32)(pContext->pBundledContext->SamplesPerSecond*0.1); // 0.1 secs Stereo
-            pContext->pBundledContext->SamplesToExitCountVirt =
-                 (LVM_INT32)(pContext->pBundledContext->SamplesPerSecond*0.1); // 0.1 secs Stereo
-            LOGV("\tEffect_command cmdCode Case: EFFECT_CMD_ENABLE Samples to Exit = %d",
-                pContext->pBundledContext->SamplesToExitCountBb);
-            //LOGV("\tEffect_command cmdCode Case: EFFECT_CMD_ENABLE NumberEffectsEnabled = %d",
-            //        pContext->pBundledContext->NumberEffectsEnabled);
-            //LOGV("\tEffect_command cmdCode Case: EFFECT_CMD_ENABLE end");
+
+            *(int *)pReplyData = android::Effect_setEnabled(pContext, LVM_TRUE);
             break;
 
         case EFFECT_CMD_DISABLE:
@@ -2907,57 +2961,7 @@
                 LOGV("\tLVM_ERROR : Effect_command cmdCode Case: EFFECT_CMD_DISABLE: ERROR");
                 return -EINVAL;
             }
-            switch (pContext->EffectType){
-                case LVM_BASS_BOOST:
-                    if(pContext->pBundledContext->bBassEnabled == LVM_FALSE){
-                         LOGV("\tLVM_ERROR : BassBoost_command cmdCode Case: "
-                                 "EFFECT_CMD_DISABLE: ERROR-Effect is not yet enabled");
-                         return -EINVAL;
-                    }
-                    pContext->pBundledContext->bBassEnabled      = LVM_FALSE;
-                    //LOGV("\tEffect_command cmdCode Case: "
-                    //       "EFFECT_CMD_DISABLE LVM_BASS_BOOST disabled");
-                    break;
-                case LVM_EQUALIZER:
-                    if(pContext->pBundledContext->bEqualizerEnabled == LVM_FALSE){
-                         LOGV("\tLVM_ERROR : Equalizer_command cmdCode Case: "
-                                 "EFFECT_CMD_DISABLE: ERROR-Effect is not yet enabled");
-                         return -EINVAL;
-                    }
-                    pContext->pBundledContext->bEqualizerEnabled = LVM_FALSE;
-                    //LOGV("\tEffect_command cmdCode Case: "
-                    //       "EFFECT_CMD_DISABLE LVM_EQUALIZER disabled");
-                    break;
-                case LVM_VIRTUALIZER:
-                    if(pContext->pBundledContext->bVirtualizerEnabled == LVM_FALSE){
-                         LOGV("\tLVM_ERROR : Virtualizer_command cmdCode Case: "
-                                 "EFFECT_CMD_DISABLE: ERROR-Effect is not yet enabled");
-                         return -EINVAL;
-                    }
-                    pContext->pBundledContext->bVirtualizerEnabled = LVM_FALSE;
-                    //LOGV("\tEffect_command cmdCode Case: "
-                    //     "EFFECT_CMD_DISABLE LVM_VIRTUALIZER disabled");
-                    break;
-                case LVM_VOLUME:
-                    if(pContext->pBundledContext->bVolumeEnabled == LVM_FALSE){
-                         LOGV("\tLVM_ERROR : Volume_command cmdCode Case: "
-                                 "EFFECT_CMD_DISABLE: ERROR-Effect is not yet enabled");
-                         return -EINVAL;
-                    }
-                    pContext->pBundledContext->bVolumeEnabled = LVM_FALSE;
-                    //LOGV("\tEffect_command cmdCode Case: EFFECT_CMD_DISABLE LVM_VOLUME disabled");
-                    break;
-                default:
-                    LOGV("\tLVM_ERROR : Effect_command cmdCode Case: "
-                        "EFFECT_CMD_DISABLE: ERROR, invalid Effect Type");
-                    return -EINVAL;
-            }
-            *(int *)pReplyData = 0;
-            pContext->pBundledContext->NumberEffectsEnabled--;
-            android::LvmEffect_disable(pContext);
-            //LOGV("\tEffect_command cmdCode Case: EFFECT_CMD_DISABLE NumberEffectsEnabled = %d",
-            //        pContext->pBundledContext->NumberEffectsEnabled);
-            //LOGV("\tEffect_command cmdCode Case: EFFECT_CMD_DISABLE end");
+            *(int *)pReplyData = android::Effect_setEnabled(pContext, LVM_FALSE);
             break;
 
         case EFFECT_CMD_SET_DEVICE:
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index f3229c0..c6b2efb 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -590,6 +590,9 @@
         break;
     case MEDIA_PLAYBACK_COMPLETE:
         LOGV("playback complete");
+        if (mCurrentState == MEDIA_PLAYER_IDLE) {
+            LOGE("playback complete in idle state");
+        }
         if (!mLoop) {
             mCurrentState = MEDIA_PLAYER_PLAYBACK_COMPLETE;
         }
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 86fa668..e0321a5 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -34,6 +34,7 @@
         ShoutcastSource.cpp               \
         StagefrightMediaScanner.cpp       \
         StagefrightMetadataRetriever.cpp  \
+        ThreadedSource.cpp                \
         ThrottledSource.cpp               \
         TimeSource.cpp                    \
         TimedEventQueue.cpp               \
diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp
index 8d7ada3..29f16d8 100644
--- a/media/libstagefright/AudioSource.cpp
+++ b/media/libstagefright/AudioSource.cpp
@@ -256,6 +256,8 @@
             if (numLostBytes > kMaxBufferSize) {
                 mPrevLostBytes = numLostBytes - kMaxBufferSize;
                 numLostBytes = kMaxBufferSize;
+            } else {
+                mPrevLostBytes = 0;
             }
 
             CHECK_EQ(numLostBytes & 1, 0);
@@ -275,8 +277,9 @@
             memset(buffer->data(), 0, numLostBytes);
             buffer->set_range(0, numLostBytes);
             if (numFramesRecorded == 0) {
-                buffer->meta_data()->setInt64(kKeyTime, mStartTimeUs);
+                buffer->meta_data()->setInt64(kKeyAnchorTime, mStartTimeUs);
             }
+            buffer->meta_data()->setInt64(kKeyTime, mStartTimeUs + mPrevSampleTimeUs);
             buffer->meta_data()->setInt64(kKeyDriftTime, readTimeUs - mInitialReadTimeUs);
             mPrevSampleTimeUs = timestampUs;
             *out = buffer;
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index 3e31d61..89cb135 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -93,6 +93,9 @@
        return OMX_COLOR_Format16bitRGB565;
     }
 
+    LOGE("Uknown color format (%s), please add it to "
+         "CameraSource::getColorFormat", colorFormat);
+
     CHECK_EQ(0, "Unknown color format");
 }
 
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index de4233d..f0d8943 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -1675,9 +1675,9 @@
 
     }
 
-    if (mSampleSizes.empty()) {
-        err = ERROR_MALFORMED;
-    } else if (OK != checkCodecSpecificData()) {
+    if (mSampleSizes.empty() ||                      // no samples written
+        (!mIsAudio && mNumStssTableEntries == 0) ||  // no sync frames for video
+        (OK != checkCodecSpecificData())) {          // no codec specific data
         err = ERROR_MALFORMED;
     }
     mOwner->trackProgressStatus(this, -1, err);
@@ -1794,13 +1794,13 @@
         !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
         if (!mCodecSpecificData ||
             mCodecSpecificDataSize <= 0) {
-            // Missing codec specific data
+            LOGE("Missing codec specific data");
             return ERROR_MALFORMED;
         }
     } else {
         if (mCodecSpecificData ||
             mCodecSpecificDataSize > 0) {
-            // Unexepected codec specific data found
+            LOGE("Unexepected codec specific data found");
             return ERROR_MALFORMED;
         }
     }
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 165cec9..523b79c 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -52,6 +52,8 @@
 #include <OMX_Audio.h>
 #include <OMX_Component.h>
 
+#include "include/ThreadedSource.h"
+
 namespace android {
 
 static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
@@ -134,6 +136,10 @@
     for (size_t i = 0;
          i < sizeof(kFactoryInfo) / sizeof(kFactoryInfo[0]); ++i) {
         if (!strcmp(name, kFactoryInfo[i].name)) {
+            if (!strcmp(name, "VPXDecoder")) {
+                return new ThreadedSource(
+                        (*kFactoryInfo[i].CreateFunc)(source));
+            }
             return (*kFactoryInfo[i].CreateFunc)(source);
         }
     }
@@ -163,15 +169,18 @@
     { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.7x30.video.decoder.mpeg4" },
     { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.video.decoder.mpeg4" },
     { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.Video.Decoder" },
+    { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.SEC.MPEG4.Decoder" },
     { MEDIA_MIMETYPE_VIDEO_MPEG4, "M4vH263Decoder" },
 //    { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.PV.mpeg4dec" },
     { MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.7x30.video.decoder.h263" },
     { MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.video.decoder.h263" },
+    { MEDIA_MIMETYPE_VIDEO_H263, "OMX.SEC.H263.Decoder" },
     { MEDIA_MIMETYPE_VIDEO_H263, "M4vH263Decoder" },
 //    { MEDIA_MIMETYPE_VIDEO_H263, "OMX.PV.h263dec" },
     { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.7x30.video.decoder.avc" },
     { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.video.decoder.avc" },
     { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.Video.Decoder" },
+    { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.SEC.AVC.Decoder" },
     { MEDIA_MIMETYPE_VIDEO_AVC, "AVCDecoder" },
 //    { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.PV.avcdec" },
     { MEDIA_MIMETYPE_AUDIO_VORBIS, "VorbisDecoder" },
@@ -189,16 +198,19 @@
     { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.7x30.video.encoder.mpeg4" },
     { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.video.encoder.mpeg4" },
     { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.Video.encoder" },
+    { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.SEC.MPEG4.Encoder" },
     { MEDIA_MIMETYPE_VIDEO_MPEG4, "M4vH263Encoder" },
 //    { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.PV.mpeg4enc" },
     { MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.7x30.video.encoder.h263" },
     { MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.video.encoder.h263" },
     { MEDIA_MIMETYPE_VIDEO_H263, "OMX.TI.Video.encoder" },
+    { MEDIA_MIMETYPE_VIDEO_H263, "OMX.SEC.H263.Encoder" },
     { MEDIA_MIMETYPE_VIDEO_H263, "M4vH263Encoder" },
 //    { MEDIA_MIMETYPE_VIDEO_H263, "OMX.PV.h263enc" },
     { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.7x30.video.encoder.avc" },
     { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.video.encoder.avc" },
     { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.Video.encoder" },
+    { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.SEC.AVC.Encoder" },
     { MEDIA_MIMETYPE_VIDEO_AVC, "AVCEncoder" },
 //    { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.PV.avcenc" },
 };
@@ -811,8 +823,7 @@
         if (OMX_ErrorNone != mOMX->getParameter(
                 mNode, OMX_IndexParamVideoPortFormat,
                 &portFormat, sizeof(portFormat))) {
-
-            return UNKNOWN_ERROR;
+            break;
         }
         // Make sure that omx component does not overwrite
         // the incremented index (bug 2897413).
@@ -832,6 +843,8 @@
             break;
         }
     }
+
+    LOGE("color format %d is not supported", colorFormat);
     return UNKNOWN_ERROR;
 }
 
@@ -1028,7 +1041,7 @@
                 mNode, OMX_IndexParamVideoProfileLevelQuerySupported,
                 &param, sizeof(param));
 
-        if (err != OK) return err;
+        if (err != OK) break;
 
         int32_t supportedProfile = static_cast<int32_t>(param.eProfile);
         int32_t supportedLevel = static_cast<int32_t>(param.eLevel);
@@ -1036,7 +1049,10 @@
             supportedProfile, supportedLevel);
 
         if (profile == supportedProfile &&
-            level == supportedLevel) {
+            level <= supportedLevel) {
+            // We can further check whether the level is a valid
+            // value; but we will leave that to the omx encoder component
+            // via OMX_SetParameter call.
             profileLevel.mProfile = profile;
             profileLevel.mLevel = level;
             return OK;
@@ -1427,6 +1443,8 @@
 }
 
 OMXCodec::~OMXCodec() {
+    mSource.clear();
+
     CHECK(mState == LOADED || mState == ERROR);
 
     status_t err = mOMX->freeNode(mNode);
diff --git a/media/libstagefright/ThreadedSource.cpp b/media/libstagefright/ThreadedSource.cpp
new file mode 100644
index 0000000..5add2a5
--- /dev/null
+++ b/media/libstagefright/ThreadedSource.cpp
@@ -0,0 +1,209 @@
+/*
+ * 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 "include/ThreadedSource.h"
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MetaData.h>
+
+namespace android {
+
+static const size_t kMaxQueueSize = 2;
+
+ThreadedSource::ThreadedSource(const sp<MediaSource> &source)
+    : mSource(source),
+      mReflector(new AHandlerReflector<ThreadedSource>(this)),
+      mLooper(new ALooper),
+      mStarted(false) {
+    mLooper->registerHandler(mReflector);
+}
+
+ThreadedSource::~ThreadedSource() {
+    if (mStarted) {
+        stop();
+    }
+}
+
+status_t ThreadedSource::start(MetaData *params) {
+    CHECK(!mStarted);
+
+    status_t err = mSource->start(params);
+
+    if (err != OK) {
+        return err;
+    }
+
+    mFinalResult = OK;
+    mSeekTimeUs = -1;
+    mDecodePending = false;
+
+    Mutex::Autolock autoLock(mLock);
+    postDecodeMore_l();
+
+    CHECK_EQ(mLooper->start(), (status_t)OK);
+
+    mStarted = true;
+
+    return OK;
+}
+
+status_t ThreadedSource::stop() {
+    CHECK(mStarted);
+
+    CHECK_EQ(mLooper->stop(), (status_t)OK);
+
+    Mutex::Autolock autoLock(mLock);
+    clearQueue_l();
+
+    status_t err = mSource->stop();
+
+    mStarted = false;
+
+    return err;
+}
+
+sp<MetaData> ThreadedSource::getFormat() {
+    return mSource->getFormat();
+}
+
+status_t ThreadedSource::read(
+        MediaBuffer **buffer, const ReadOptions *options) {
+    *buffer = NULL;
+
+    Mutex::Autolock autoLock(mLock);
+
+    int64_t seekTimeUs;
+    ReadOptions::SeekMode seekMode;
+    if (options && options->getSeekTo(&seekTimeUs, &seekMode)) {
+        int32_t seekComplete = 0;
+
+        sp<AMessage> msg = new AMessage(kWhatSeek, mReflector->id());
+        msg->setInt64("timeUs", seekTimeUs);
+        msg->setInt32("mode", seekMode);
+        msg->setPointer("complete", &seekComplete);
+        msg->post();
+
+        while (!seekComplete) {
+            mCondition.wait(mLock);
+        }
+    }
+
+    while (mQueue.empty() && mFinalResult == OK) {
+        mCondition.wait(mLock);
+    }
+
+    if (!mQueue.empty()) {
+        *buffer = *mQueue.begin();
+        mQueue.erase(mQueue.begin());
+
+        if (mFinalResult == OK) {
+            postDecodeMore_l();
+        }
+
+        return OK;
+    }
+
+    return mFinalResult;
+}
+
+void ThreadedSource::onMessageReceived(const sp<AMessage> &msg) {
+    switch (msg->what()) {
+        case kWhatSeek:
+        {
+            CHECK(msg->findInt64("timeUs", &mSeekTimeUs));
+            CHECK_GE(mSeekTimeUs, 0ll);
+
+            int32_t x;
+            CHECK(msg->findInt32("mode", &x));
+            mSeekMode = (ReadOptions::SeekMode)x;
+
+            int32_t *seekComplete;
+            CHECK(msg->findPointer("complete", (void **)&seekComplete));
+
+            Mutex::Autolock autoLock(mLock);
+            clearQueue_l();
+            mFinalResult = OK;
+
+            *seekComplete = 1;
+            mCondition.signal();
+
+            postDecodeMore_l();
+            break;
+        }
+
+        case kWhatDecodeMore:
+        {
+            {
+                Mutex::Autolock autoLock(mLock);
+                mDecodePending = false;
+
+                if (mQueue.size() == kMaxQueueSize) {
+                    break;
+                }
+            }
+
+            MediaBuffer *buffer;
+            ReadOptions options;
+            if (mSeekTimeUs >= 0) {
+                options.setSeekTo(mSeekTimeUs, mSeekMode);
+                mSeekTimeUs = -1ll;
+            }
+            status_t err = mSource->read(&buffer, &options);
+
+            Mutex::Autolock autoLock(mLock);
+
+            if (err != OK) {
+                mFinalResult = err;
+            } else {
+                mQueue.push_back(buffer);
+
+                if (mQueue.size() < kMaxQueueSize) {
+                    postDecodeMore_l();
+                }
+            }
+
+            mCondition.signal();
+            break;
+        }
+
+        default:
+            TRESPASS();
+            break;
+    }
+}
+
+void ThreadedSource::postDecodeMore_l() {
+    if (mDecodePending) {
+        return;
+    }
+
+    mDecodePending = true;
+    (new AMessage(kWhatDecodeMore, mReflector->id()))->post();
+}
+
+void ThreadedSource::clearQueue_l() {
+    while (!mQueue.empty()) {
+        MediaBuffer *buffer = *mQueue.begin();
+        mQueue.erase(mQueue.begin());
+
+        buffer->release();
+        buffer = NULL;
+    }
+}
+
+}  // namespace android
diff --git a/media/libstagefright/WAVExtractor.cpp b/media/libstagefright/WAVExtractor.cpp
index 57c1075..aff06bc 100644
--- a/media/libstagefright/WAVExtractor.cpp
+++ b/media/libstagefright/WAVExtractor.cpp
@@ -331,9 +331,20 @@
         return err;
     }
 
+    size_t maxBytesToRead =
+        mBitsPerSample == 8 ? kMaxFrameSize / 2 : kMaxFrameSize;
+
+    size_t maxBytesAvailable =
+        (mCurrentPos - mOffset >= (off_t)mSize)
+            ? 0 : mSize - (mCurrentPos - mOffset);
+
+    if (maxBytesToRead > maxBytesAvailable) {
+        maxBytesToRead = maxBytesAvailable;
+    }
+
     ssize_t n = mDataSource->readAt(
             mCurrentPos, buffer->data(),
-            mBitsPerSample == 8 ? kMaxFrameSize / 2 : kMaxFrameSize);
+            maxBytesToRead);
 
     if (n <= 0) {
         buffer->release();
diff --git a/media/libstagefright/codecs/aacdec/AACDecoder.cpp b/media/libstagefright/codecs/aacdec/AACDecoder.cpp
index c5b51c0..e4ed5e6 100644
--- a/media/libstagefright/codecs/aacdec/AACDecoder.cpp
+++ b/media/libstagefright/codecs/aacdec/AACDecoder.cpp
@@ -123,6 +123,8 @@
     mAnchorTimeUs = 0;
     mNumSamplesOutput = 0;
     mStarted = true;
+    mNumDecodedBuffers = 0;
+    mUpsamplingFactor = 2;
 
     return OK;
 }
@@ -207,22 +209,65 @@
 
     Int decoderErr = PVMP4AudioDecodeFrame(mConfig, mDecoderBuf);
 
-    // Check on the sampling rate to see whether it is changed.
-    int32_t sampleRate;
-    CHECK(mMeta->findInt32(kKeySampleRate, &sampleRate));
-    if (mConfig->samplingRate != sampleRate) {
-        mMeta->setInt32(kKeySampleRate, mConfig->samplingRate);
-        LOGW("Sample rate was %d, but now is %d",
-                sampleRate, mConfig->samplingRate);
-        buffer->release();
-        mInputBuffer->release();
-        mInputBuffer = NULL;
-        return INFO_FORMAT_CHANGED;
+    /*
+     * AAC+/eAAC+ streams can be signalled in two ways: either explicitly
+     * or implicitly, according to MPEG4 spec. AAC+/eAAC+ is a dual
+     * rate system and the sampling rate in the final output is actually
+     * doubled compared with the core AAC decoder sampling rate.
+     *
+     * Explicit signalling is done by explicitly defining SBR audio object
+     * type in the bitstream. Implicit signalling is done by embedding
+     * SBR content in AAC extension payload specific to SBR, and hence
+     * requires an AAC decoder to perform pre-checks on actual audio frames.
+     *
+     * Thus, we could not say for sure whether a stream is
+     * AAC+/eAAC+ until the first data frame is decoded.
+     */
+    if (++mNumDecodedBuffers <= 2) {
+        LOGV("audio/extended audio object type: %d + %d",
+            mConfig->audioObjectType, mConfig->extendedAudioObjectType);
+        LOGV("aac+ upsampling factor: %d desired channels: %d",
+            mConfig->aacPlusUpsamplingFactor, mConfig->desiredChannels);
+
+        CHECK(mNumDecodedBuffers > 0);
+        if (mNumDecodedBuffers == 1) {
+            mUpsamplingFactor = mConfig->aacPlusUpsamplingFactor;
+            // Check on the sampling rate to see whether it is changed.
+            int32_t sampleRate;
+            CHECK(mMeta->findInt32(kKeySampleRate, &sampleRate));
+            if (mConfig->samplingRate != sampleRate) {
+                mMeta->setInt32(kKeySampleRate, mConfig->samplingRate);
+                LOGW("Sample rate was %d Hz, but now is %d Hz",
+                        sampleRate, mConfig->samplingRate);
+                buffer->release();
+                mInputBuffer->release();
+                mInputBuffer = NULL;
+                return INFO_FORMAT_CHANGED;
+            }
+        } else {  // mNumDecodedBuffers == 2
+            if (mConfig->extendedAudioObjectType == MP4AUDIO_AAC_LC ||
+                mConfig->extendedAudioObjectType == MP4AUDIO_LTP) {
+                if (mUpsamplingFactor == 2) {
+                    // The stream turns out to be not aacPlus mode anyway
+                    LOGW("Disable AAC+/eAAC+ since extended audio object type is %d",
+                        mConfig->extendedAudioObjectType);
+                    mConfig->aacPlusEnabled = 0;
+                }
+            } else {
+                if (mUpsamplingFactor == 1) {
+                    // aacPlus mode does not buy us anything, but to cause
+                    // 1. CPU load to increase, and
+                    // 2. a half speed of decoding
+                    LOGW("Disable AAC+/eAAC+ since upsampling factor is 1");
+                    mConfig->aacPlusEnabled = 0;
+                }
+            }
+        }
     }
 
     size_t numOutBytes =
         mConfig->frameLength * sizeof(int16_t) * mConfig->desiredChannels;
-    if (mConfig->aacPlusUpsamplingFactor == 2) {
+    if (mUpsamplingFactor == 2) {
         if (mConfig->desiredChannels == 1) {
             memcpy(&mConfig->pOutputBuffer[1024], &mConfig->pOutputBuffer[2048], numOutBytes * 2);
         }
diff --git a/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp b/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp
index 7154ba5..7483d60 100644
--- a/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp
+++ b/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp
@@ -317,7 +317,7 @@
                 &nalType, &nalRefIdc);
 
     if (res != AVCDEC_SUCCESS) {
-        LOGE("cannot determine nal type");
+        LOGV("cannot determine nal type");
     } else if (nalType == AVC_NALTYPE_SPS || nalType == AVC_NALTYPE_PPS
                 || (mSPSSeen && mPPSSeen)) {
         switch (nalType) {
@@ -330,6 +330,7 @@
                         fragSize);
 
                 if (res != AVCDEC_SUCCESS) {
+                    LOGV("PVAVCDecSeqParamSet returned error %d", res);
                     break;
                 }
 
@@ -396,6 +397,7 @@
                         fragSize);
 
                 if (res != AVCDEC_SUCCESS) {
+                    LOGV("PVAVCDecPicParamSet returned error %d", res);
                     break;
                 }
 
@@ -418,8 +420,13 @@
                     AVCFrameIO Output;
                     Output.YCbCr[0] = Output.YCbCr[1] = Output.YCbCr[2] = NULL;
 
-                    CHECK_EQ(PVAVCDecGetOutput(mHandle, &index, &Release, &Output),
-                             AVCDEC_SUCCESS);
+                    AVCDec_Status status =
+                        PVAVCDecGetOutput(mHandle, &index, &Release, &Output);
+
+                    if (status != AVCDEC_SUCCESS) {
+                        LOGV("PVAVCDecGetOutput returned error %d", status);
+                        break;
+                    }
 
                     CHECK(index >= 0);
                     CHECK(index < (int32_t)mFrames.size());
@@ -466,7 +473,7 @@
 
                     err = OK;
                 } else {
-                    LOGV("failed to decode frame (res = %d)", res);
+                    LOGV("PVAVCDecodeSlice returned error %d", res);
                 }
                 break;
             }
diff --git a/media/libstagefright/codecs/on2/dec/VPXDecoder.cpp b/media/libstagefright/codecs/on2/dec/VPXDecoder.cpp
index fbc97f4..9433178 100644
--- a/media/libstagefright/codecs/on2/dec/VPXDecoder.cpp
+++ b/media/libstagefright/codecs/on2/dec/VPXDecoder.cpp
@@ -29,8 +29,9 @@
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/Utils.h>
 
-#include "vpx_codec/vpx_decoder.h"
-#include "vp8/vp8dx.h"
+#include "vpx/vpx_decoder.h"
+#include "vpx/vpx_codec.h"
+#include "vpx/vp8dx.h"
 
 namespace android {
 
@@ -82,9 +83,10 @@
     }
 
     mCtx = new vpx_codec_ctx_t;
-    if (vpx_codec_dec_init(
-                (vpx_codec_ctx_t *)mCtx, &vpx_codec_vp8_dx_algo, NULL, 0)) {
-        LOGE("on2 decoder failed to initialize.");
+    vpx_codec_err_t vpx_err;
+    if ((vpx_err = vpx_codec_dec_init(
+                (vpx_codec_ctx_t *)mCtx, &vpx_codec_vp8_dx_algo, NULL, 0))) {
+        LOGE("on2 decoder failed to initialize. (%d)", vpx_err);
 
         mSource->stop();
 
diff --git a/media/libstagefright/include/AACDecoder.h b/media/libstagefright/include/AACDecoder.h
index 200f93c..886a3b7 100644
--- a/media/libstagefright/include/AACDecoder.h
+++ b/media/libstagefright/include/AACDecoder.h
@@ -53,6 +53,8 @@
     int64_t mAnchorTimeUs;
     int64_t mNumSamplesOutput;
     status_t mInitCheck;
+    int64_t  mNumDecodedBuffers;
+    int32_t  mUpsamplingFactor;
 
     MediaBuffer *mInputBuffer;
 
diff --git a/media/libstagefright/include/ThreadedSource.h b/media/libstagefright/include/ThreadedSource.h
new file mode 100644
index 0000000..c67295c
--- /dev/null
+++ b/media/libstagefright/include/ThreadedSource.h
@@ -0,0 +1,73 @@
+/*
+ * 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 THREADED_SOURCE_H_
+
+#define THREADED_SOURCE_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/foundation/AHandlerReflector.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/MediaSource.h>
+#include <utils/threads.h>
+
+namespace android {
+
+struct ThreadedSource : public MediaSource {
+    ThreadedSource(const sp<MediaSource> &source);
+
+    virtual status_t start(MetaData *params);
+    virtual status_t stop();
+
+    virtual sp<MetaData> getFormat();
+
+    virtual status_t read(
+            MediaBuffer **buffer, const ReadOptions *options);
+
+    virtual void onMessageReceived(const sp<AMessage> &msg);
+
+protected:
+    virtual ~ThreadedSource();
+
+private:
+    enum {
+        kWhatDecodeMore = 'deco',
+        kWhatSeek       = 'seek',
+    };
+
+    sp<MediaSource> mSource;
+    sp<AHandlerReflector<ThreadedSource> > mReflector;
+    sp<ALooper> mLooper;
+
+    Mutex mLock;
+    Condition mCondition;
+    List<MediaBuffer *> mQueue;
+    status_t mFinalResult;
+    bool mDecodePending;
+    bool mStarted;
+
+    int64_t mSeekTimeUs;
+    ReadOptions::SeekMode mSeekMode;
+
+    void postDecodeMore_l();
+    void clearQueue_l();
+
+    DISALLOW_EVIL_CONSTRUCTORS(ThreadedSource);
+};
+
+}  // namespace android
+
+#endif  // THREADED_SOURCE_H_
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index 6de761f..c927da1 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -245,13 +245,15 @@
     CHECK(index >= 0);
     mLiveNodes.removeItemsAt(index);
 
+    instance->observer()->asBinder()->unlinkToDeath(this);
+
+    status_t err = instance->freeNode(mMaster);
+
     index = mDispatchers.indexOfKey(node);
     CHECK(index >= 0);
     mDispatchers.removeItemsAt(index);
 
-    instance->observer()->asBinder()->unlinkToDeath(this);
-
-    return instance->freeNode(mMaster);
+    return err;
 }
 
 status_t OMX::sendCommand(
diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp
index b63798f..b3e86eb 100644
--- a/media/libstagefright/rtsp/APacketSource.cpp
+++ b/media/libstagefright/rtsp/APacketSource.cpp
@@ -764,7 +764,11 @@
     int64_t lastTimeUs;
     CHECK(last->meta()->findInt64("timeUs", &lastTimeUs));
 
-    CHECK_GE(lastTimeUs, firstTimeUs);
+    if (lastTimeUs < firstTimeUs) {
+        LOG(ERROR) << "Huh? Time moving backwards? "
+                   << firstTimeUs << " > " << lastTimeUs;
+        return 0;
+    }
 
     return lastTimeUs - firstTimeUs;
 }
diff --git a/media/libstagefright/rtsp/ARTSPConnection.cpp b/media/libstagefright/rtsp/ARTSPConnection.cpp
index cbd4836..da4a73a 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTSPConnection.cpp
@@ -175,19 +175,38 @@
 
     mState = CONNECTING;
 
-    mSocket = socket(AF_INET, SOCK_STREAM, 0);
-
-    MakeSocketBlocking(mSocket, false);
-
     AString url;
     CHECK(msg->findString("url", &url));
 
+    sp<AMessage> reply;
+    CHECK(msg->findMessage("reply", &reply));
+
     AString host, path;
     unsigned port;
-    CHECK(ParseURL(url.c_str(), &host, &port, &path));
+    if (!ParseURL(url.c_str(), &host, &port, &path)) {
+        LOG(ERROR) << "Malformed rtsp url " << url;
+
+        reply->setInt32("result", ERROR_MALFORMED);
+        reply->post();
+
+        mState = DISCONNECTED;
+        return;
+    }
 
     struct hostent *ent = gethostbyname(host.c_str());
-    CHECK(ent != NULL);
+    if (ent == NULL) {
+        LOG(ERROR) << "Unknown host " << host;
+
+        reply->setInt32("result", -ENOENT);
+        reply->post();
+
+        mState = DISCONNECTED;
+        return;
+    }
+
+    mSocket = socket(AF_INET, SOCK_STREAM, 0);
+
+    MakeSocketBlocking(mSocket, false);
 
     struct sockaddr_in remote;
     memset(remote.sin_zero, 0, sizeof(remote.sin_zero));
@@ -198,9 +217,6 @@
     int err = ::connect(
             mSocket, (const struct sockaddr *)&remote, sizeof(remote));
 
-    sp<AMessage> reply;
-    CHECK(msg->findMessage("reply", &reply));
-
     reply->setInt32("server-ip", ntohl(remote.sin_addr.s_addr));
 
     if (err < 0) {
@@ -337,13 +353,20 @@
 
         if (n == 0) {
             // Server closed the connection.
-            TRESPASS();
+            LOG(ERROR) << "Server unexpectedly closed the connection.";
+
+            reply->setInt32("result", ERROR_IO);
+            reply->post();
+            return;
         } else if (n < 0) {
             if (errno == EINTR) {
                 continue;
             }
 
-            TRESPASS();
+            LOG(ERROR) << "Error sending rtsp request.";
+            reply->setInt32("result", -errno);
+            reply->post();
+            return;
         }
 
         numBytesSent += (size_t)n;
@@ -415,13 +438,15 @@
         ssize_t n = recv(mSocket, (uint8_t *)data + offset, size - offset, 0);
         if (n == 0) {
             // Server closed the connection.
+            LOG(ERROR) << "Server unexpectedly closed the connection.";
             return ERROR_IO;
         } else if (n < 0) {
             if (errno == EINTR) {
                 continue;
             }
 
-            TRESPASS();
+            LOG(ERROR) << "Error reading rtsp response.";
+            return -errno;
         }
 
         offset += (size_t)n;
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index b849117..526bef3 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -209,22 +209,24 @@
                                 response->mContent->data(),
                                 response->mContent->size());
 
-                        CHECK(mSessionDesc->isValid());
-
-                        ssize_t i = response->mHeaders.indexOfKey("content-base");
-                        if (i >= 0) {
-                            mBaseURL = response->mHeaders.valueAt(i);
+                        if (!mSessionDesc->isValid()) {
+                            result = ERROR_MALFORMED;
                         } else {
-                            i = response->mHeaders.indexOfKey("content-location");
+                            ssize_t i = response->mHeaders.indexOfKey("content-base");
                             if (i >= 0) {
                                 mBaseURL = response->mHeaders.valueAt(i);
                             } else {
-                                mBaseURL = mSessionURL;
+                                i = response->mHeaders.indexOfKey("content-location");
+                                if (i >= 0) {
+                                    mBaseURL = response->mHeaders.valueAt(i);
+                                } else {
+                                    mBaseURL = mSessionURL;
+                                }
                             }
-                        }
 
-                        CHECK_GT(mSessionDesc->countTracks(), 1u);
-                        setupTrack(1);
+                            CHECK_GT(mSessionDesc->countTracks(), 1u);
+                            setupTrack(1);
+                        }
                     }
                 }
 
@@ -333,13 +335,17 @@
                     sp<ARTSPResponse> response =
                         static_cast<ARTSPResponse *>(obj.get());
 
-                    CHECK_EQ(response->mStatusCode, 200u);
+                    if (response->mStatusCode != 200) {
+                        result = UNKNOWN_ERROR;
+                    } else {
+                        parsePlayResponse(response);
 
-                    parsePlayResponse(response);
+                        sp<AMessage> timeout = new AMessage('tiou', id());
+                        timeout->post(kStartupTimeoutUs);
+                    }
+                }
 
-                    sp<AMessage> timeout = new AMessage('tiou', id());
-                    timeout->post(kStartupTimeoutUs);
-                } else {
+                if (result != OK) {
                     sp<AMessage> reply = new AMessage('disc', id());
                     mConn->disconnect(reply);
                 }
@@ -477,6 +483,11 @@
 
                 uint32_t seqNum = (uint32_t)accessUnit->int32Data();
 
+                if (mSeekPending) {
+                    LOG(INFO) << "we're seeking, dropping stale packet.";
+                    break;
+                }
+
                 if (seqNum < track->mFirstSeqNumInSegment) {
                     LOG(INFO) << "dropping stale access-unit "
                               << "(" << seqNum << " < "
@@ -600,18 +611,26 @@
                 LOG(INFO) << "PLAY completed with result "
                      << result << " (" << strerror(-result) << ")";
 
-                CHECK_EQ(result, (status_t)OK);
+                if (result == OK) {
+                    sp<RefBase> obj;
+                    CHECK(msg->findObject("response", &obj));
+                    sp<ARTSPResponse> response =
+                        static_cast<ARTSPResponse *>(obj.get());
 
-                sp<RefBase> obj;
-                CHECK(msg->findObject("response", &obj));
-                sp<ARTSPResponse> response =
-                    static_cast<ARTSPResponse *>(obj.get());
+                    if (response->mStatusCode != 200) {
+                        result = UNKNOWN_ERROR;
+                    } else {
+                        parsePlayResponse(response);
 
-                CHECK_EQ(response->mStatusCode, 200u);
+                        LOG(INFO) << "seek completed.";
+                    }
+                }
 
-                parsePlayResponse(response);
+                if (result != OK) {
+                    LOG(ERROR) << "seek failed, aborting.";
+                    (new AMessage('abor', id()))->post();
+                }
 
-                LOG(INFO) << "seek completed.";
                 mSeekPending = false;
                 break;
             }
diff --git a/native/android/input.cpp b/native/android/input.cpp
index 57f0072..c753aa5 100644
--- a/native/android/input.cpp
+++ b/native/android/input.cpp
@@ -20,7 +20,7 @@
 #include <android/input.h>
 #include <ui/Input.h>
 #include <ui/InputTransport.h>
-#include <utils/PollLoop.h>
+#include <utils/Looper.h>
 #include <utils/RefBase.h>
 #include <utils/Vector.h>
 
@@ -250,7 +250,7 @@
 
 
 void AInputQueue_attachLooper(AInputQueue* queue, ALooper* looper,
-        int ident, ALooper_callbackFunc* callback, void* data) {
+        int ident, ALooper_callbackFunc callback, void* data) {
     queue->attachLooper(looper, ident, callback, data);
 }
 
diff --git a/native/android/looper.cpp b/native/android/looper.cpp
index 0aeed77..9f5cda9 100644
--- a/native/android/looper.cpp
+++ b/native/android/looper.cpp
@@ -18,65 +18,56 @@
 #include <utils/Log.h>
 
 #include <android/looper.h>
-#include <utils/PollLoop.h>
+#include <utils/Looper.h>
 
-using android::PollLoop;
+using android::Looper;
 using android::sp;
 
 ALooper* ALooper_forThread() {
-    return PollLoop::getForThread().get();
+    return Looper::getForThread().get();
 }
 
-ALooper* ALooper_prepare(int32_t opts) {
-    bool allowFds = (opts&ALOOPER_PREPARE_ALLOW_NON_CALLBACKS) != 0;
-    sp<PollLoop> loop = PollLoop::getForThread();
-    if (loop == NULL) {
-        loop = new PollLoop(allowFds);
-        PollLoop::setForThread(loop);
-    }
-    if (loop->getAllowNonCallbacks() != allowFds) {
-        LOGW("ALooper_prepare again with different ALOOPER_PREPARE_ALLOW_NON_CALLBACKS");
-    }
-    return loop.get();
-}
-
-int32_t ALooper_pollOnce(int timeoutMillis, int* outEvents, void** outData) {
-    sp<PollLoop> loop = PollLoop::getForThread();
-    if (loop == NULL) {
-        LOGW("ALooper_pollOnce: No looper for this thread!");
-        return -1;
-    }
-    return loop->pollOnce(timeoutMillis, outEvents, outData);
-}
-
-int32_t ALooper_pollAll(int timeoutMillis, int* outEvents, void** outData) {
-    sp<PollLoop> loop = PollLoop::getForThread();
-    if (loop == NULL) {
-        LOGW("ALooper_pollOnce: No looper for this thread!");
-        return -1;
-    }
-    
-    int32_t result;
-    while ((result = loop->pollOnce(timeoutMillis, outEvents, outData)) == ALOOPER_POLL_CALLBACK) {
-        ;
-    }
-    
-    return result;
+ALooper* ALooper_prepare(int opts) {
+    return Looper::prepare(opts).get();
 }
 
 void ALooper_acquire(ALooper* looper) {
-    static_cast<PollLoop*>(looper)->incStrong((void*)ALooper_acquire);
+    static_cast<Looper*>(looper)->incStrong((void*)ALooper_acquire);
 }
 
 void ALooper_release(ALooper* looper) {
-    static_cast<PollLoop*>(looper)->decStrong((void*)ALooper_acquire);
+    static_cast<Looper*>(looper)->decStrong((void*)ALooper_acquire);
 }
 
-void ALooper_addFd(ALooper* looper, int fd, int ident, int events,
-        ALooper_callbackFunc* callback, void* data) {
-    static_cast<PollLoop*>(looper)->setLooperCallback(fd, ident, events, callback, data);
+int ALooper_pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
+    sp<Looper> looper = Looper::getForThread();
+    if (looper == NULL) {
+        LOGE("ALooper_pollOnce: No looper for this thread!");
+        return ALOOPER_POLL_ERROR;
+    }
+
+    return looper->pollOnce(timeoutMillis, outFd, outEvents, outData);
 }
 
-int32_t ALooper_removeFd(ALooper* looper, int fd) {
-    return static_cast<PollLoop*>(looper)->removeCallback(fd) ? 1 : 0;
+int ALooper_pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
+    sp<Looper> looper = Looper::getForThread();
+    if (looper == NULL) {
+        LOGE("ALooper_pollAll: No looper for this thread!");
+        return ALOOPER_POLL_ERROR;
+    }
+    
+    return looper->pollAll(timeoutMillis, outFd, outEvents, outData);
+}
+
+void ALooper_wake(ALooper* looper) {
+    static_cast<Looper*>(looper)->wake();
+}
+
+int ALooper_addFd(ALooper* looper, int fd, int ident, int events,
+        ALooper_callbackFunc callback, void* data) {
+    return static_cast<Looper*>(looper)->addFd(fd, ident, events, callback, data);
+}
+
+int ALooper_removeFd(ALooper* looper, int fd) {
+    return static_cast<Looper*>(looper)->removeFd(fd);
 }
diff --git a/native/android/sensor.cpp b/native/android/sensor.cpp
index cf7635d..76c6eda 100644
--- a/native/android/sensor.cpp
+++ b/native/android/sensor.cpp
@@ -21,7 +21,7 @@
 #include <android/sensor.h>
 
 #include <utils/RefBase.h>
-#include <utils/PollLoop.h>
+#include <utils/Looper.h>
 #include <utils/Timers.h>
 
 #include <gui/Sensor.h>
@@ -60,12 +60,12 @@
 }
 
 ASensorEventQueue* ASensorManager_createEventQueue(ASensorManager* manager,
-        ALooper* looper, int ident, ALooper_callbackFunc* callback, void* data)
+        ALooper* looper, int ident, ALooper_callbackFunc callback, void* data)
 {
     sp<SensorEventQueue> queue =
             static_cast<SensorManager*>(manager)->createEventQueue();
     if (queue != 0) {
-        ALooper_addFd(looper, queue->getFd(), ident, POLLIN, callback, data);
+        ALooper_addFd(looper, queue->getFd(), ident, ALOOPER_EVENT_INPUT, callback, data);
         queue->looper = looper;
         queue->incStrong(manager);
     }
diff --git a/native/include/android/input.h b/native/include/android/input.h
index 9da122b..5580700 100644
--- a/native/include/android/input.h
+++ b/native/include/android/input.h
@@ -295,7 +295,6 @@
     AINPUT_SOURCE_CLASS_POINTER = 0x00000002,
     AINPUT_SOURCE_CLASS_NAVIGATION = 0x00000004,
     AINPUT_SOURCE_CLASS_POSITION = 0x00000008,
-    AINPUT_SOURCE_CLASS_JOYSTICK = 0x00000010,
 };
 
 enum {
@@ -303,13 +302,10 @@
 
     AINPUT_SOURCE_KEYBOARD = 0x00000100 | AINPUT_SOURCE_CLASS_BUTTON,
     AINPUT_SOURCE_DPAD = 0x00000200 | AINPUT_SOURCE_CLASS_BUTTON,
-    AINPUT_SOURCE_GAMEPAD = 0x00000400 | AINPUT_SOURCE_CLASS_BUTTON,
     AINPUT_SOURCE_TOUCHSCREEN = 0x00001000 | AINPUT_SOURCE_CLASS_POINTER,
     AINPUT_SOURCE_MOUSE = 0x00002000 | AINPUT_SOURCE_CLASS_POINTER,
     AINPUT_SOURCE_TRACKBALL = 0x00010000 | AINPUT_SOURCE_CLASS_NAVIGATION,
     AINPUT_SOURCE_TOUCHPAD = 0x00100000 | AINPUT_SOURCE_CLASS_POSITION,
-    AINPUT_SOURCE_JOYSTICK_LEFT = 0x01000000 | AINPUT_SOURCE_CLASS_JOYSTICK,
-    AINPUT_SOURCE_JOYSTICK_RIGHT = 0x02000000 | AINPUT_SOURCE_CLASS_JOYSTICK,
 };
 
 /*
@@ -645,7 +641,7 @@
  * ALooper_addFd() for information on the ident, callback, and data params.
  */
 void AInputQueue_attachLooper(AInputQueue* queue, ALooper* looper,
-        int ident, ALooper_callbackFunc* callback, void* data);
+        int ident, ALooper_callbackFunc callback, void* data);
 
 /*
  * Remove the input queue from the looper it is currently attached to.
diff --git a/native/include/android/looper.h b/native/include/android/looper.h
index 287bcd5..a63b744 100644
--- a/native/include/android/looper.h
+++ b/native/include/android/looper.h
@@ -18,8 +18,6 @@
 #ifndef ANDROID_LOOPER_H
 #define ANDROID_LOOPER_H
 
-#include <poll.h>
-
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -41,25 +39,14 @@
 typedef struct ALooper ALooper;
 
 /**
- * For callback-based event loops, this is the prototype of the function
- * that is called.  It is given the file descriptor it is associated with,
- * a bitmask of the poll events that were triggered (typically POLLIN), and
- * the data pointer that was originally supplied.
- *
- * Implementations should return 1 to continue receiving callbacks, or 0
- * to have this file descriptor and callback unregistered from the looper.
- */
-typedef int ALooper_callbackFunc(int fd, int events, void* data);
-
-/**
- * Return the ALooper associated with the calling thread, or NULL if
+ * Returns the looper associated with the calling thread, or NULL if
  * there is not one.
  */
 ALooper* ALooper_forThread();
 
 enum {
     /**
-     * Option for ALooper_prepare: this ALooper will accept calls to
+     * Option for ALooper_prepare: this looper will accept calls to
      * ALooper_addFd() that do not have a callback (that is provide NULL
      * for the callback).  In this case the caller of ALooper_pollOnce()
      * or ALooper_pollAll() MUST check the return from these functions to
@@ -69,66 +56,42 @@
 };
 
 /**
- * Prepare an ALooper associated with the calling thread, and return it.
- * If the thread already has an ALooper, it is returned.  Otherwise, a new
+ * Prepares a looper associated with the calling thread, and returns it.
+ * If the thread already has a looper, it is returned.  Otherwise, a new
  * one is created, associated with the thread, and returned.
  *
  * The opts may be ALOOPER_PREPARE_ALLOW_NON_CALLBACKS or 0.
  */
-ALooper* ALooper_prepare(int32_t opts);
+ALooper* ALooper_prepare(int opts);
 
 enum {
     /**
-     * Result from ALooper_pollOnce() and ALooper_pollAll(): one or
-     * more callbacks were executed.
+     * Result from ALooper_pollOnce() and ALooper_pollAll():
+     * The poll was awoken using wake() before the timeout expired
+     * and no callbacks were executed and no other file descriptors were ready.
      */
-    ALOOPER_POLL_CALLBACK = -1,
-    
+    ALOOPER_POLL_WAKE = -1,
+
     /**
-     * Result from ALooper_pollOnce() and ALooper_pollAll(): the
-     * timeout expired.
+     * Result from ALooper_pollOnce() and ALooper_pollAll():
+     * One or more callbacks were executed.
      */
-    ALOOPER_POLL_TIMEOUT = -2,
-    
+    ALOOPER_POLL_CALLBACK = -2,
+
     /**
-     * Result from ALooper_pollOnce() and ALooper_pollAll(): an error
-     * occurred.
+     * Result from ALooper_pollOnce() and ALooper_pollAll():
+     * The timeout expired.
      */
-    ALOOPER_POLL_ERROR = -3,
+    ALOOPER_POLL_TIMEOUT = -3,
+
+    /**
+     * Result from ALooper_pollOnce() and ALooper_pollAll():
+     * An error occurred.
+     */
+    ALOOPER_POLL_ERROR = -4,
 };
 
 /**
- * Wait for events to be available, with optional timeout in milliseconds.
- * Invokes callbacks for all file descriptors on which an event occurred.
- *
- * If the timeout is zero, returns immediately without blocking.
- * If the timeout is negative, waits indefinitely until an event appears.
- *
- * Returns ALOOPER_POLL_CALLBACK if a callback was invoked.
- *
- * Returns ALOOPER_POLL_TIMEOUT if there was no data before the given
- * timeout expired.
- *
- * Returns ALOPER_POLL_ERROR if an error occurred.
- *
- * Returns a value >= 0 containing an identifier if its file descriptor has data
- * and it has no callback function (requiring the caller here to handle it).
- * In this (and only this) case outEvents and outData will contain the poll
- * events and data associated with the fd.
- *
- * This method does not return until it has finished invoking the appropriate callbacks
- * for all file descriptors that were signalled.
- */
-int32_t ALooper_pollOnce(int timeoutMillis, int* outEvents, void** outData);
-
-/**
- * Like ALooper_pollOnce(), but performs all pending callbacks until all
- * data has been consumed or a file descriptor is available with no callback.
- * This function will never return ALOOPER_POLL_CALLBACK.
- */
-int32_t ALooper_pollAll(int timeoutMillis, int* outEvents, void** outData);
-
-/**
  * Acquire a reference on the given ALooper object.  This prevents the object
  * from being deleted until the reference is removed.  This is only needed
  * to safely hand an ALooper from one thread to another.
@@ -141,36 +104,140 @@
 void ALooper_release(ALooper* looper);
 
 /**
- * Add a new file descriptor to be polled by the looper.  If the same file
- * descriptor was previously added, it is replaced.
+ * Flags for file descriptor events that a looper can monitor.
+ *
+ * These flag bits can be combined to monitor multiple events at once.
+ */
+enum {
+    /**
+     * The file descriptor is available for read operations.
+     */
+    ALOOPER_EVENT_INPUT = 1 << 0,
+
+    /**
+     * The file descriptor is available for write operations.
+     */
+    ALOOPER_EVENT_OUTPUT = 1 << 1,
+
+    /**
+     * The file descriptor has encountered an error condition.
+     *
+     * The looper always sends notifications about errors; it is not necessary
+     * to specify this event flag in the requested event set.
+     */
+    ALOOPER_EVENT_ERROR = 1 << 2,
+
+    /**
+     * The file descriptor was hung up.
+     * For example, indicates that the remote end of a pipe or socket was closed.
+     *
+     * The looper always sends notifications about hangups; it is not necessary
+     * to specify this event flag in the requested event set.
+     */
+    ALOOPER_EVENT_HANGUP = 1 << 3,
+};
+
+/**
+ * For callback-based event loops, this is the prototype of the function
+ * that is called.  It is given the file descriptor it is associated with,
+ * a bitmask of the poll events that were triggered (typically ALOOPER_EVENT_INPUT),
+ * and the data pointer that was originally supplied.
+ *
+ * Implementations should return 1 to continue receiving callbacks, or 0
+ * to have this file descriptor and callback unregistered from the looper.
+ */
+typedef int (*ALooper_callbackFunc)(int fd, int events, void* data);
+
+/**
+ * Waits for events to be available, with optional timeout in milliseconds.
+ * Invokes callbacks for all file descriptors on which an event occurred.
+ *
+ * If the timeout is zero, returns immediately without blocking.
+ * If the timeout is negative, waits indefinitely until an event appears.
+ *
+ * Returns ALOOPER_POLL_WAKE if the poll was awoken using wake() before
+ * the timeout expired and no callbacks were invoked and no other file
+ * descriptors were ready.
+ *
+ * Returns ALOOPER_POLL_CALLBACK if one or more callbacks were invoked.
+ *
+ * Returns ALOOPER_POLL_TIMEOUT if there was no data before the given
+ * timeout expired.
+ *
+ * Returns ALOOPER_POLL_ERROR if an error occurred.
+ *
+ * Returns a value >= 0 containing an identifier if its file descriptor has data
+ * and it has no callback function (requiring the caller here to handle it).
+ * In this (and only this) case outFd, outEvents and outData will contain the poll
+ * events and data associated with the fd, otherwise they will be set to NULL.
+ *
+ * This method does not return until it has finished invoking the appropriate callbacks
+ * for all file descriptors that were signalled.
+ */
+int ALooper_pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData);
+
+/**
+ * Like ALooper_pollOnce(), but performs all pending callbacks until all
+ * data has been consumed or a file descriptor is available with no callback.
+ * This function will never return ALOOPER_POLL_CALLBACK.
+ */
+int ALooper_pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData);
+
+/**
+ * Wakes the poll asynchronously.
+ *
+ * This method can be called on any thread.
+ * This method returns immediately.
+ */
+void ALooper_wake(ALooper* looper);
+
+/**
+ * Adds a new file descriptor to be polled by the looper.
+ * If the same file descriptor was previously added, it is replaced.
  *
  * "fd" is the file descriptor to be added.
- * "ident" is an identifier for this event, which is returned from
- * ALooper_pollOnce().  Must be >= 0, or ALOOPER_POLL_CALLBACK if
- * providing a non-NULL callback.
- * "events" are the poll events to wake up on.  Typically this is POLLIN.
- * "callback" is the function to call when there is an event on the file
- * descriptor.
+ * "ident" is an identifier for this event, which is returned from ALooper_pollOnce().
+ * The identifier must be >= 0, or ALOOPER_POLL_CALLBACK if providing a non-NULL callback.
+ * "events" are the poll events to wake up on.  Typically this is ALOOPER_EVENT_INPUT.
+ * "callback" is the function to call when there is an event on the file descriptor.
  * "data" is a private data pointer to supply to the callback.
  *
  * There are two main uses of this function:
  *
- * (1) If "callback" is non-NULL, then
- * this function will be called when there is data on the file descriptor.  It
- * should execute any events it has pending, appropriately reading from the
- * file descriptor.  The 'ident' is ignored in this case.
+ * (1) If "callback" is non-NULL, then this function will be called when there is
+ * data on the file descriptor.  It should execute any events it has pending,
+ * appropriately reading from the file descriptor.  The 'ident' is ignored in this case.
  *
  * (2) If "callback" is NULL, the 'ident' will be returned by ALooper_pollOnce
  * when its file descriptor has data available, requiring the caller to take
  * care of processing it.
+ *
+ * Returns 1 if the file descriptor was added or -1 if an error occurred.
+ *
+ * This method can be called on any thread.
+ * This method may block briefly if it needs to wake the poll.
  */
-void ALooper_addFd(ALooper* looper, int fd, int ident, int events,
-        ALooper_callbackFunc* callback, void* data);
+int ALooper_addFd(ALooper* looper, int fd, int ident, int events,
+        ALooper_callbackFunc callback, void* data);
 
 /**
- * Remove a previously added file descriptor from the looper.
+ * Removes a previously added file descriptor from the looper.
+ *
+ * When this method returns, it is safe to close the file descriptor since the looper
+ * will no longer have a reference to it.  However, it is possible for the callback to
+ * already be running or for it to run one last time if the file descriptor was already
+ * signalled.  Calling code is responsible for ensuring that this case is safely handled.
+ * For example, if the callback takes care of removing itself during its own execution either
+ * by returning 0 or by calling this method, then it can be guaranteed to not be invoked
+ * again at any later time unless registered anew.
+ *
+ * Returns 1 if the file descriptor was removed, 0 if none was previously registered
+ * or -1 if an error occurred.
+ *
+ * This method can be called on any thread.
+ * This method may block briefly if it needs to wake the poll.
  */
-int32_t ALooper_removeFd(ALooper* looper, int fd);
+int ALooper_removeFd(ALooper* looper, int fd);
 
 #ifdef __cplusplus
 };
diff --git a/native/include/android/sensor.h b/native/include/android/sensor.h
index a102d43..f163f18 100644
--- a/native/include/android/sensor.h
+++ b/native/include/android/sensor.h
@@ -166,7 +166,7 @@
  * Creates a new sensor event queue and associate it with a looper.
  */
 ASensorEventQueue* ASensorManager_createEventQueue(ASensorManager* manager,
-        ALooper* looper, int ident, ALooper_callbackFunc* callback, void* data);
+        ALooper* looper, int ident, ALooper_callbackFunc callback, void* data);
 
 /*
  * Destroys the event queue and free all resources associated to it.
diff --git a/opengl/include/GLES/glext.h b/opengl/include/GLES/glext.h
index a5b3ead..65ab5e4 100644
--- a/opengl/include/GLES/glext.h
+++ b/opengl/include/GLES/glext.h
@@ -211,9 +211,12 @@
 #define GL_VERTEX_ARRAY_BINDING_OES                             0x85B5
 #endif
 
-/* GL_OES_texture_external */
-#ifndef GL_TEXTURE_EXTERNAL_OES
+/* GL_OES_EGL_image_external */
+#ifndef GL_OES_EGL_image_external
 #define GL_TEXTURE_EXTERNAL_OES                                 0x8D65
+#define GL_SAMPLER_EXTERNAL_OES                                 0x8D66
+#define GL_TEXTURE_BINDING_EXTERNAL_OES                         0x8D67
+#define GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES                     0x8D68
 #endif
 
 /*------------------------------------------------------------------------*
@@ -782,9 +785,9 @@
 typedef GLboolean (GL_APIENTRYP PFNGLISVERTEXARRAYOESPROC) (GLuint array);
 #endif
 
-/* GL_OES_texture_external */
-#ifndef GL_OES_texture_external
-#define GL_OES_texture_external 1
+/* GL_OES_EGL_image_external */
+#ifndef GL_OES_EGL_image_external
+#define GL_OES_EGL_image_external 1
 #endif
 
 /*------------------------------------------------------------------------*
diff --git a/opengl/include/GLES2/gl2ext.h b/opengl/include/GLES2/gl2ext.h
index de5d65a..9db4e252c 100644
--- a/opengl/include/GLES2/gl2ext.h
+++ b/opengl/include/GLES2/gl2ext.h
@@ -146,9 +146,12 @@
 #define GL_INT_10_10_10_2_OES                                   0x8DF7
 #endif
 
-/* GL_OES_texture_external */
-#ifndef GL_TEXTURE_EXTERNAL_OES
+/* GL_OES_EGL_image_external */
+#ifndef GL_OES_EGL_image_external
 #define GL_TEXTURE_EXTERNAL_OES                                 0x8D65
+#define GL_SAMPLER_EXTERNAL_OES                                 0x8D66
+#define GL_TEXTURE_BINDING_EXTERNAL_OES                         0x8D67
+#define GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES                     0x8D68
 #endif
 
 /*------------------------------------------------------------------------*
@@ -546,9 +549,9 @@
 #define GL_OES_vertex_type_10_10_10_2 1
 #endif
 
-/* GL_OES_texture_external */
-#ifndef GL_OES_texture_external
-#define GL_OES_texture_external 1
+/* GL_OES_EGL_image_external */
+#ifndef GL_OES_EGL_image_external
+#define GL_OES_EGL_image_external 1
 #endif
 
 /*------------------------------------------------------------------------*
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 5d6ac26..747c829 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -136,30 +136,24 @@
      */
     
     void* dso;
-    char path[PATH_MAX];
     int index = int(display);
     driver_t* hnd = 0;
-    const char* const format = "/system/lib/egl/lib%s_%s.so";
     
     char const* tag = getTag(index, impl);
     if (tag) {
-        snprintf(path, PATH_MAX, format, "GLES", tag);
-        dso = load_driver(path, cnx, EGL | GLESv1_CM | GLESv2);
+        dso = load_driver("GLES", tag, cnx, EGL | GLESv1_CM | GLESv2);
         if (dso) {
             hnd = new driver_t(dso);
         } else {
             // Always load EGL first
-            snprintf(path, PATH_MAX, format, "EGL", tag);
-            dso = load_driver(path, cnx, EGL);
+            dso = load_driver("EGL", tag, cnx, EGL);
             if (dso) {
                 hnd = new driver_t(dso);
 
                 // TODO: make this more automated
-                snprintf(path, PATH_MAX, format, "GLESv1_CM", tag);
-                hnd->set( load_driver(path, cnx, GLESv1_CM), GLESv1_CM );
+                hnd->set( load_driver("GLESv1_CM", tag, cnx, GLESv1_CM), GLESv1_CM );
 
-                snprintf(path, PATH_MAX, format, "GLESv2", tag);
-                hnd->set( load_driver(path, cnx, GLESv2), GLESv2 );
+                hnd->set( load_driver("GLESv2", tag, cnx, GLESv2), GLESv2 );
             }
         }
     }
@@ -222,12 +216,20 @@
     }
 }
 
-void *Loader::load_driver(const char* driver_absolute_path,
+void *Loader::load_driver(const char* kind, const char *tag,
         egl_connection_t* cnx, uint32_t mask)
 {
+    char driver_absolute_path[PATH_MAX];
+    const char* const search1 = "/vendor/lib/egl/lib%s_%s.so";
+    const char* const search2 = "/system/lib/egl/lib%s_%s.so";
+
+    snprintf(driver_absolute_path, PATH_MAX, search1, kind, tag);
     if (access(driver_absolute_path, R_OK)) {
-        // this happens often, we don't want to log an error
-        return 0;
+        snprintf(driver_absolute_path, PATH_MAX, search2, kind, tag);
+        if (access(driver_absolute_path, R_OK)) {
+            // this happens often, we don't want to log an error
+            return 0;
+        }
     }
 
     void* dso = dlopen(driver_absolute_path, RTLD_NOW | RTLD_LOCAL);
diff --git a/opengl/libs/EGL/Loader.h b/opengl/libs/EGL/Loader.h
index 8659b0b..580d6e4 100644
--- a/opengl/libs/EGL/Loader.h
+++ b/opengl/libs/EGL/Loader.h
@@ -74,7 +74,7 @@
     
 private:
     Loader();
-    void *load_driver(const char* driver, egl_connection_t* cnx, uint32_t mask);
+    void *load_driver(const char* kind, const char *tag, egl_connection_t* cnx, uint32_t mask);
 
     static __attribute__((noinline))
     void init_api(void* dso, 
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_alarm.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_alarm.png
index 89daee1..2d3eb30 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_alarm_2.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_alarm_2.png
new file mode 100644
index 0000000..69841ac
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_notify_alarm_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_bt_incoming_file.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_bt_incoming_file.png
new file mode 100644
index 0000000..18addce
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_notify_bt_incoming_file.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_calendar.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_calendar.png
new file mode 100644
index 0000000..0caab3e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_notify_calendar.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_call_mute.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_call_mute.png
new file mode 100644
index 0000000..0cf5ef5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_notify_call_mute.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_car_mode.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_car_mode.png
new file mode 100644
index 0000000..60c3778
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_notify_car_mode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_disk_full.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_disk_full.png
new file mode 100644
index 0000000..66e7380
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_notify_disk_full.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_email_generic.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_email_generic.png
new file mode 100644
index 0000000..78003fa
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_notify_email_generic.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_gmail.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_gmail.png
new file mode 100644
index 0000000..7356309
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_notify_gmail.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_instant_message.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_instant_message.png
new file mode 100644
index 0000000..9fc8262
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_notify_instant_message.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_marketplace_update.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_marketplace_update.png
new file mode 100644
index 0000000..c0d0284
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_notify_marketplace_update.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_missed_call.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_missed_call.png
new file mode 100644
index 0000000..d1173b4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_notify_missed_call.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_mms.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_mms.png
new file mode 100644
index 0000000..eed8c45
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_notify_mms.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_more_notifications.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_more_notifications.png
new file mode 100644
index 0000000..f54b3d4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_notify_more_notifications.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_musicplayer.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_musicplayer.png
new file mode 100644
index 0000000..1301f86
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_notify_musicplayer.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_myfaves.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_myfaves.png
new file mode 100644
index 0000000..854c745
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_notify_myfaves.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_picasa.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_picasa.png
new file mode 100644
index 0000000..9146185
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_notify_picasa.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_sdcard.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_sdcard.png
new file mode 100644
index 0000000..dd947a5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_notify_sdcard.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_sdcard_alert.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_sdcard_alert.png
new file mode 100644
index 0000000..fb2b26a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_notify_sdcard_alert.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_sdcard_prepare.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_sdcard_prepare.png
new file mode 100644
index 0000000..4b9b9ca
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_notify_sdcard_prepare.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_sim_toolkit.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_sim_toolkit.png
new file mode 100644
index 0000000..8865bda
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_notify_sim_toolkit.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_sms.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_sms.png
new file mode 100644
index 0000000..66981ba
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_notify_sms.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_sms_failed.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_sms_failed.png
new file mode 100644
index 0000000..93ede20
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_notify_sms_failed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_sync.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_sync.png
new file mode 100644
index 0000000..004cfab
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_notify_sync.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_sync_alert.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_sync_alert.png
new file mode 100644
index 0000000..26b2446
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_notify_sync_alert.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_sync_anim0.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_sync_anim0.png
new file mode 100644
index 0000000..6973fc5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_notify_sync_anim0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_sync_anim1.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_sync_anim1.png
new file mode 100644
index 0000000..f9d4b32
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_notify_sync_anim1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_sync_anim2.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_sync_anim2.png
new file mode 100644
index 0000000..06ff588
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_notify_sync_anim2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_sync_anim3.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_sync_anim3.png
new file mode 100644
index 0000000..20d1720
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_notify_sync_anim3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_sync_anim4.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_sync_anim4.png
new file mode 100644
index 0000000..a217034
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_notify_sync_anim4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_sync_anim5.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_sync_anim5.png
new file mode 100644
index 0000000..8d733ec
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_notify_sync_anim5.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_system_update.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_system_update.png
new file mode 100644
index 0000000..f4365a5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_notify_system_update.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_usb_debugger.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_usb_debugger.png
new file mode 100644
index 0000000..fdf6c6c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_notify_usb_debugger.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_voicemail.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_voicemail.png
new file mode 100644
index 0000000..5b77846
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_notify_voicemail.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_10.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_10.png
new file mode 100644
index 0000000..4486553
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_10.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_100.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_100.png
new file mode 100644
index 0000000..23b9e3b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_100.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_20.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_20.png
new file mode 100644
index 0000000..c8f9c92
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_20.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_40.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_40.png
new file mode 100644
index 0000000..8d7e1d5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_40.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_60.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_60.png
new file mode 100644
index 0000000..cb674cc
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_60.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_80.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_80.png
new file mode 100644
index 0000000..5846df9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_80.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim0.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim0.png
new file mode 100644
index 0000000..c7464f7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim1.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim1.png
new file mode 100644
index 0000000..997feb3
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim2.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim2.png
new file mode 100644
index 0000000..bb8b022
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim3.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim3.png
new file mode 100644
index 0000000..212a25f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim4.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim4.png
new file mode 100644
index 0000000..b211ed6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim5.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim5.png
new file mode 100644
index 0000000..a52f81b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_charge_anim5.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_empty.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_empty.png
new file mode 100644
index 0000000..82f2509
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_empty.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_unknown.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_unknown.png
new file mode 100644
index 0000000..dadfe8d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_unknown.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_bluetooth_connected.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_bluetooth_connected.png
new file mode 100644
index 0000000..18c77df
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_bluetooth_connected.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_1bar_wifi.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_1bar_wifi.png
new file mode 100644
index 0000000..aea18ed
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_1bar_wifi.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_1bar_wifi_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_1bar_wifi_fully.png
new file mode 100644
index 0000000..1a25a2c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_1bar_wifi_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_2bar_wifi.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_2bar_wifi.png
new file mode 100644
index 0000000..77e6ee4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_2bar_wifi.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_2bar_wifi_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_2bar_wifi_fully.png
new file mode 100644
index 0000000..00d86bf
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_2bar_wifi_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_3bar_wifi.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_3bar_wifi.png
new file mode 100644
index 0000000..c2574e1
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_3bar_wifi.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_3bar_wifi_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_3bar_wifi_fully.png
new file mode 100644
index 0000000..70c030b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_3bar_wifi_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_4bar_wifi.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_4bar_wifi.png
new file mode 100644
index 0000000..55caecf
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_4bar_wifi.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_4bar_wifi_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_4bar_wifi_fully.png
new file mode 100644
index 0000000..b5326d2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_4bar_wifi_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_bluetooth.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_bluetooth.png
index 96dc085..e8fbc9e 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_bluetooth.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_bluetooth.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_1x_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_1x_fully.png
new file mode 100644
index 0000000..ba24082
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_1x_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_3g_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_3g_fully.png
new file mode 100644
index 0000000..5af2b05
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_3g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_e_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_e_fully.png
new file mode 100644
index 0000000..9909b09
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_e_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_g_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_g_fully.png
new file mode 100644
index 0000000..0e02b8d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_h_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_h_fully.png
new file mode 100644
index 0000000..f84ad32
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_h_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_1x_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_1x_fully.png
new file mode 100644
index 0000000..d80a8ce
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_1x_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_3g_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_3g_fully.png
new file mode 100644
index 0000000..31c976a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_3g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_e_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_e_fully.png
new file mode 100644
index 0000000..c299e12
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_e_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_g_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_g_fully.png
new file mode 100644
index 0000000..a487f29
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_h_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_h_fully.png
new file mode 100644
index 0000000..816085b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_h_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_1x_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_1x_fully.png
new file mode 100644
index 0000000..0132019
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_1x_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_3g_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_3g_fully.png
new file mode 100644
index 0000000..3903545
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_3g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_e_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_e_fully.png
new file mode 100644
index 0000000..ed099ff
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_e_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_g_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_g_fully.png
new file mode 100644
index 0000000..c930e4c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_h_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_h_fully.png
new file mode 100644
index 0000000..407a06c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_h_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_nosignal_wifi.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_nosignal_wifi.png
new file mode 100644
index 0000000..98e874a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_nosignal_wifi.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_1x_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_1x_fully.png
new file mode 100644
index 0000000..6141f72
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_1x_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_3g_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_3g_fully.png
new file mode 100644
index 0000000..d44a4cf
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_3g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_e_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_e_fully.png
new file mode 100644
index 0000000..54ebd9b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_e_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_g_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_g_fully.png
new file mode 100644
index 0000000..2fe0bbf
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_g_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_h_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_h_fully.png
new file mode 100644
index 0000000..e58e019
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_h_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_usb.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_usb.png
new file mode 100644
index 0000000..e916fbb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_usb.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_download_anim0.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_download_anim0.png
new file mode 100644
index 0000000..9df7799
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_download_anim0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_download_anim1.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_download_anim1.png
new file mode 100644
index 0000000..c3defd7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_download_anim1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_download_anim2.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_download_anim2.png
new file mode 100644
index 0000000..1302a06
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_download_anim2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_download_anim3.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_download_anim3.png
new file mode 100644
index 0000000..c7f85bf
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_download_anim3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_download_anim4.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_download_anim4.png
new file mode 100644
index 0000000..705dfd3
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_download_anim4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_download_anim5.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_download_anim5.png
new file mode 100644
index 0000000..c0bdb13
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_download_anim5.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 9003d67..e306ad7 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_gps_on.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_gps_on.png
new file mode 100644
index 0000000..37fb8f7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_gps_on.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_install_complete.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_install_complete.png
new file mode 100644
index 0000000..c1478c40
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_install_complete.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_phone_call.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_phone_call.png
new file mode 100644
index 0000000..9b5f075
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_phone_call.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_phone_call_bluetooth.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_phone_call_bluetooth.png
new file mode 100644
index 0000000..fecfe6c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_phone_call_bluetooth.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_phone_call_emergency.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_phone_call_emergency.png
new file mode 100644
index 0000000..f69f82c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_phone_call_emergency.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_phone_call_forward.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_phone_call_forward.png
new file mode 100644
index 0000000..032f8f1
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_phone_call_forward.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_phone_call_on_hold.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_phone_call_on_hold.png
new file mode 100644
index 0000000..5b0a68d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_phone_call_on_hold.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0_fully.png
new file mode 100644
index 0000000..95ba181
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1_fully.png
new file mode 100644
index 0000000..adf668d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2_fully.png
new file mode 100644
index 0000000..7bf6b51
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3_cdma.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3_cdma.png
new file mode 100644
index 0000000..1d2f966
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3_cdma.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3_fully.png
new file mode 100644
index 0000000..78738ac
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4_cdma_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4_cdma_fully.png
new file mode 100644
index 0000000..7ff8820
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4_cdma_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4_fully.png
new file mode 100644
index 0000000..ac88143
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_cdma_0.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_cdma_0.png
new file mode 100644
index 0000000..d128053
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_cdma_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_cdma_1.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_cdma_1.png
new file mode 100644
index 0000000..ecd46e9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_cdma_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_cdma_1_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_cdma_1_fully.png
new file mode 100644
index 0000000..4462bce
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_cdma_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_cdma_2.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_cdma_2.png
new file mode 100644
index 0000000..d635d8c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_cdma_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_cdma_2_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_cdma_2_fully.png
new file mode 100644
index 0000000..cfca5d2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_cdma_2_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_cdma_3.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_cdma_3.png
new file mode 100644
index 0000000..e470925
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_cdma_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_cdma_3_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_cdma_3_fully.png
new file mode 100644
index 0000000..d290699
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_cdma_3_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_cdma_4.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_cdma_4.png
new file mode 100644
index 0000000..ef47408
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_cdma_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_cdma_4_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_cdma_4_fully.png
new file mode 100644
index 0000000..26cb22b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_cdma_4_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_ra_signal_0_cdma.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_ra_signal_0_cdma.png
new file mode 100644
index 0000000..901058a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_ra_signal_0_cdma.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_ra_signal_1_cdma.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_ra_signal_1_cdma.png
new file mode 100644
index 0000000..f5c5f98
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_ra_signal_1_cdma.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_ra_signal_1_cdma_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_ra_signal_1_cdma_fully.png
new file mode 100644
index 0000000..f71a35c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_ra_signal_1_cdma_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_ra_signal_2_cdma.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_ra_signal_2_cdma.png
new file mode 100644
index 0000000..82102b2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_ra_signal_2_cdma.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_ra_signal_2_cdma_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_ra_signal_2_cdma_fully.png
new file mode 100644
index 0000000..6818f43
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_ra_signal_2_cdma_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_ra_signal_3_cdma_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_ra_signal_3_cdma_fully.png
new file mode 100644
index 0000000..7d8dc5b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_ra_signal_3_cdma_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_ra_signal_4_cdma.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_ra_signal_4_cdma.png
new file mode 100644
index 0000000..c08cc86
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_ra_signal_4_cdma.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_silent.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_silent.png
index bdd37e1..5a741bb 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_silent.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_silent.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_vibrate.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_vibrate.png
index 21c1c08..7ff375a 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_vibrate.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_vibrate.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_secure.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_secure.png
new file mode 100644
index 0000000..0889e49
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_secure.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 3e317dd..2f66b1d 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_0_cdma.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_cdma.png
new file mode 100644
index 0000000..af43e00
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_cdma.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_fully.png
new file mode 100644
index 0000000..3e317dd
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_fully.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 72329f8..b91eaf5 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_cdma.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_cdma.png
new file mode 100644
index 0000000..4ffe421
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_cdma.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_cdma_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_cdma_fully.png
new file mode 100644
index 0000000..cd8e314
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_cdma_fully.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
new file mode 100644
index 0000000..cb1ad97
--- /dev/null
+++ 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 558c49c..53217e4 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_cdma.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_cdma.png
new file mode 100644
index 0000000..6f27b96
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_cdma.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_cdma_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_cdma_fully.png
new file mode 100644
index 0000000..416a544
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_cdma_fully.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
new file mode 100644
index 0000000..74ecb08
--- /dev/null
+++ 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 6440bdd..08f357f 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_cdma.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_cdma.png
new file mode 100644
index 0000000..ddc46b0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_cdma.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_cdma_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_cdma_fully.png
new file mode 100644
index 0000000..341116e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_cdma_fully.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
new file mode 100644
index 0000000..929c700
--- /dev/null
+++ 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 fe20423..b3bb321 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_cdma.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_cdma.png
new file mode 100644
index 0000000..fb3cfe9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_cdma.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_cdma_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_cdma_fully.png
new file mode 100644
index 0000000..ae83e93
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_cdma_fully.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
new file mode 100644
index 0000000..4644ac1
--- /dev/null
+++ 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_evdo_0.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_evdo_0.png
new file mode 100644
index 0000000..b697ca4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_evdo_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_evdo_1.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_evdo_1.png
new file mode 100644
index 0000000..a61de4d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_evdo_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_evdo_1_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_evdo_1_fully.png
new file mode 100644
index 0000000..9fa018b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_evdo_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_evdo_2.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_evdo_2.png
new file mode 100644
index 0000000..62e0393
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_evdo_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_evdo_2_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_evdo_2_fully.png
new file mode 100644
index 0000000..0324d9f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_evdo_2_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_evdo_3.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_evdo_3.png
new file mode 100644
index 0000000..09eae9d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_evdo_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_evdo_3_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_evdo_3_fully.png
new file mode 100644
index 0000000..1ffde3d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_evdo_3_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_evdo_4.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_evdo_4.png
new file mode 100644
index 0000000..4012ac5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_evdo_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_evdo_4_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_evdo_4_fully.png
new file mode 100644
index 0000000..22f7e42
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_evdo_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 7a419f1..01c7e2a 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_null.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_null.png
index 1adc05a..03d2147 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_null.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_null.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_roaming_0.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_roaming_0.png
new file mode 100644
index 0000000..5796a8a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_roaming_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_roaming_1.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_roaming_1.png
new file mode 100644
index 0000000..3dec269
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_roaming_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_roaming_1_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_roaming_1_fully.png
new file mode 100644
index 0000000..eeb7f67
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_roaming_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_roaming_2.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_roaming_2.png
new file mode 100644
index 0000000..2dcff93
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_roaming_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_roaming_2_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_roaming_2_fully.png
new file mode 100644
index 0000000..aee093a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_roaming_2_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_roaming_3.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_roaming_3.png
new file mode 100644
index 0000000..1b38450
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_roaming_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_roaming_3_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_roaming_3_fully.png
new file mode 100644
index 0000000..a40017f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_roaming_3_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_roaming_4.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_roaming_4.png
new file mode 100644
index 0000000..33bf3b3
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_roaming_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_roaming_4_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_roaming_4_fully.png
new file mode 100644
index 0000000..c3b44ee
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_roaming_4_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_speakerphone.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_speakerphone.png
new file mode 100644
index 0000000..21f96c4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_speakerphone.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_tether_bluetooth.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_tether_bluetooth.png
new file mode 100644
index 0000000..4ebee58
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_tether_bluetooth.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_tether_general.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_tether_general.png
new file mode 100644
index 0000000..e23f7f9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_tether_general.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_tether_usb.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_tether_usb.png
new file mode 100644
index 0000000..d432f9a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_tether_usb.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_tether_wifi.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_tether_wifi.png
new file mode 100644
index 0000000..74dfbba
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_tether_wifi.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_throttled.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_throttled.png
new file mode 100644
index 0000000..58eafc0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_throttled.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_upload_anim0.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_upload_anim0.png
new file mode 100644
index 0000000..cefcecc
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_upload_anim0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_upload_anim1.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_upload_anim1.png
new file mode 100644
index 0000000..9d018d0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_upload_anim1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_upload_anim2.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_upload_anim2.png
new file mode 100644
index 0000000..38a20a6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_upload_anim2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_upload_anim3.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_upload_anim3.png
new file mode 100644
index 0000000..f517809
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_upload_anim3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_upload_anim4.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_upload_anim4.png
new file mode 100644
index 0000000..3ae614e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_upload_anim4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_upload_anim5.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_upload_anim5.png
new file mode 100644
index 0000000..d0638ef
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_upload_anim5.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_vp_phone_call.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_vp_phone_call.png
new file mode 100644
index 0000000..83e8ead
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_vp_phone_call.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_vp_phone_call_on_hold.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_vp_phone_call_on_hold.png
new file mode 100644
index 0000000..9731c46
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_vp_phone_call_on_hold.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_warning.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_warning.png
new file mode 100644
index 0000000..cb8a3d4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_warning.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 98e874a..55a2ad8 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 aea18ed..d16b3e8 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_2.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_2.png
index 77e6ee4..2511083 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_3.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_3.png
index c2574e1..e0799a5 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_4.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_4.png
index 55caecf..2385c3a 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/status_bar_close_on.9.png b/packages/SystemUI/res/drawable-hdpi/status_bar_close_on.9.png
new file mode 100644
index 0000000..87d1944
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/status_bar_close_on.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_header_background.9.png b/packages/SystemUI/res/drawable-hdpi/status_bar_header_background.9.png
new file mode 100644
index 0000000..79d77aa
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/status_bar_header_background.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/statusbar_background.9.png b/packages/SystemUI/res/drawable-hdpi/statusbar_background.9.png
new file mode 100644
index 0000000..67c8b7f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/statusbar_background.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_1x.png
new file mode 100644
index 0000000..130724f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_3g.png
new file mode 100644
index 0000000..a109280
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_e.png
new file mode 100644
index 0000000..c552644
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_g.png
new file mode 100644
index 0000000..f7edb49
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_h.png
new file mode 100644
index 0000000..7d5413a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_1x.png
new file mode 100644
index 0000000..3155e632
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_3g.png
new file mode 100644
index 0000000..01b003c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_e.png
new file mode 100644
index 0000000..bffa0eb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_g.png
new file mode 100644
index 0000000..8884b48
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_h.png
new file mode 100644
index 0000000..695b80c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_1x.png
new file mode 100644
index 0000000..1017e3b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_3g.png
new file mode 100644
index 0000000..3651300
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_e.png
new file mode 100644
index 0000000..99533e0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_g.png
new file mode 100644
index 0000000..f4e5a12
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_h.png
new file mode 100644
index 0000000..467acd1
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_1x.png
new file mode 100644
index 0000000..5418791
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_3g.png
new file mode 100644
index 0000000..f7f0f89
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_e.png
new file mode 100644
index 0000000..c915426
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_g.png
new file mode 100644
index 0000000..5d36035
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_h.png
new file mode 100644
index 0000000..da50305
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_h.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
new file mode 100644
index 0000000..8ee3421
--- /dev/null
+++ 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
new file mode 100644
index 0000000..184fa36
--- /dev/null
+++ 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_2.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_2.png
new file mode 100644
index 0000000..79935bb
--- /dev/null
+++ 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_3.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_3.png
new file mode 100644
index 0000000..d2099e6
--- /dev/null
+++ 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_4.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_4.png
new file mode 100644
index 0000000..2062aad
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_4.png
Binary files differ
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java
index b4e0d3a..0fc092e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java
@@ -120,19 +120,29 @@
 
     //***** Signal strength icons
     //GSM/UMTS
-    private static final int[] sSignalImages = new int[] {
-        R.drawable.stat_sys_signal_0,
-        R.drawable.stat_sys_signal_1,
-        R.drawable.stat_sys_signal_2,
-        R.drawable.stat_sys_signal_3,
-        R.drawable.stat_sys_signal_4
+    private static final int[][] sSignalImages = {
+        { R.drawable.stat_sys_signal_0,
+          R.drawable.stat_sys_signal_1,
+          R.drawable.stat_sys_signal_2,
+          R.drawable.stat_sys_signal_3,
+          R.drawable.stat_sys_signal_4 },
+        { R.drawable.stat_sys_signal_0_fully,
+          R.drawable.stat_sys_signal_1_fully,
+          R.drawable.stat_sys_signal_2_fully,
+          R.drawable.stat_sys_signal_3_fully,
+          R.drawable.stat_sys_signal_4_fully }
     };
-    private static final int[] sSignalImages_r = new int[] {
-        R.drawable.stat_sys_r_signal_0,
-        R.drawable.stat_sys_r_signal_1,
-        R.drawable.stat_sys_r_signal_2,
-        R.drawable.stat_sys_r_signal_3,
-        R.drawable.stat_sys_r_signal_4
+    private static final int[][] sSignalImages_r = {
+        { R.drawable.stat_sys_r_signal_0,
+          R.drawable.stat_sys_r_signal_1,
+          R.drawable.stat_sys_r_signal_2,
+          R.drawable.stat_sys_r_signal_3,
+          R.drawable.stat_sys_r_signal_4 },
+        { R.drawable.stat_sys_r_signal_0_fully,
+          R.drawable.stat_sys_r_signal_1_fully,
+          R.drawable.stat_sys_r_signal_2_fully,
+          R.drawable.stat_sys_r_signal_3_fully,
+          R.drawable.stat_sys_r_signal_4_fully }
     };
     private static final int[] sRoamingIndicatorImages_cdma = new int[] {
         R.drawable.stat_sys_roaming_cdma_0, //Standard Roaming Indicator
@@ -330,7 +340,9 @@
 
     private int mLastWifiSignalLevel = -1;
     private boolean mIsWifiConnected = false;
-    private int mLastWifiInetConnectivityState = 0;
+
+    // state of inet connection - 0 not connected, 100 connected
+    private int mInetCondition = 0;
 
     // sync state
     // If sync is active the SyncActive icon is displayed. If sync is not active but
@@ -381,7 +393,8 @@
             else if (action.equals(TtyIntent.TTY_ENABLED_CHANGE_ACTION)) {
                 updateTTY(intent);
             }
-            else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
+            else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION) ||
+                     action.equals(ConnectivityManager.INET_CONDITION_ACTION)) {
                 // TODO - stop using other means to get wifi/mobile info
                 updateConnectivity(intent);
             }
@@ -489,6 +502,7 @@
         filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
         filter.addAction(TtyIntent.TTY_ENABLED_CHANGE_ACTION);
         filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+        filter.addAction(ConnectivityManager.INET_CONDITION_ACTION);
         mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);
 
         // load config to determine if to distinguish Hspa data icon
@@ -697,41 +711,39 @@
                 ConnectivityManager.EXTRA_NETWORK_INFO));
         int connectionStatus = intent.getIntExtra(ConnectivityManager.EXTRA_INET_CONDITION, 0);
         Slog.d(TAG, "got CONNECTIVITY_ACTION - info=" + info + ", status = " + connectionStatus);
-        if (info.isConnected() == false) return;
+
+        int inetCondition = (connectionStatus > INET_CONDITION_THRESHOLD ? 1 : 0);
 
         switch (info.getType()) {
         case ConnectivityManager.TYPE_MOBILE:
-            if (info.isConnected()) {
-                updateDataNetType(info.getSubtype(), connectionStatus);
-                updateDataIcon();
-            }
+            mInetCondition = inetCondition;
+            updateDataNetType(info.getSubtype());
+            updateDataIcon();
+            updateSignalStrength(); // apply any change in connectionStatus
             break;
         case ConnectivityManager.TYPE_WIFI:
+            mInetCondition = inetCondition;
             if (info.isConnected()) {
                 mIsWifiConnected = true;
-                mLastWifiInetConnectivityState =
-                        (connectionStatus > INET_CONDITION_THRESHOLD ? 1 : 0);
                 int iconId;
                 if (mLastWifiSignalLevel == -1) {
-                    iconId = sWifiSignalImages[mLastWifiInetConnectivityState][0];
+                    iconId = sWifiSignalImages[mInetCondition][0];
                 } else {
-                    iconId = sWifiSignalImages[mLastWifiInetConnectivityState]
-                            [mLastWifiSignalLevel];
+                    iconId = sWifiSignalImages[mInetCondition][mLastWifiSignalLevel];
                 }
-
                 mService.setIcon("wifi", iconId, 0);
                 // Show the icon since wi-fi is connected
                 mService.setIconVisibility("wifi", true);
             } else {
                 mLastWifiSignalLevel = -1;
                 mIsWifiConnected = false;
-                mLastWifiInetConnectivityState = 0;
                 int iconId = sWifiSignalImages[0][0];
 
                 mService.setIcon("wifi", iconId, 0);
                 // Hide the icon since we're not connected
                 mService.setIconVisibility("wifi", false);
             }
+            updateSignalStrength(); // apply any change in mInetCondition
             break;
         }
     }
@@ -763,7 +775,7 @@
         @Override
         public void onDataConnectionStateChanged(int state, int networkType) {
             mDataState = state;
-            updateDataNetType(networkType, 0);
+            updateDataNetType(networkType);
             updateDataIcon();
         }
 
@@ -859,12 +871,12 @@
 
             // Though mPhone is a Manager, this call is not an IPC
             if (mPhone.isNetworkRoaming()) {
-                iconList = sSignalImages_r;
+                iconList = sSignalImages_r[mInetCondition];
             } else {
-                iconList = sSignalImages;
+                iconList = sSignalImages[mInetCondition];
             }
         } else {
-            iconList = this.sSignalImages;
+            iconList = sSignalImages[mInetCondition];
 
             // If 3G(EV) and 1x network are available than 3G should be
             // displayed, displayed RSSI should be from the EV side.
@@ -925,38 +937,37 @@
         return (levelEvdoDbm < levelEvdoSnr) ? levelEvdoDbm : levelEvdoSnr;
     }
 
-    private final void updateDataNetType(int net, int inetCondition) {
-        int connected = (inetCondition > INET_CONDITION_THRESHOLD ? 1 : 0);
+    private final void updateDataNetType(int net) {
         switch (net) {
         case TelephonyManager.NETWORK_TYPE_EDGE:
-            mDataIconList = sDataNetType_e[connected];
+            mDataIconList = sDataNetType_e[mInetCondition];
             break;
         case TelephonyManager.NETWORK_TYPE_UMTS:
-            mDataIconList = sDataNetType_3g[connected];
+            mDataIconList = sDataNetType_3g[mInetCondition];
             break;
         case TelephonyManager.NETWORK_TYPE_HSDPA:
         case TelephonyManager.NETWORK_TYPE_HSUPA:
         case TelephonyManager.NETWORK_TYPE_HSPA:
             if (mHspaDataDistinguishable) {
-                mDataIconList = sDataNetType_h[connected];
+                mDataIconList = sDataNetType_h[mInetCondition];
             } else {
-                mDataIconList = sDataNetType_3g[connected];
+                mDataIconList = sDataNetType_3g[mInetCondition];
             }
             break;
         case TelephonyManager.NETWORK_TYPE_CDMA:
             // display 1xRTT for IS95A/B
-            mDataIconList = sDataNetType_1x[connected];
+            mDataIconList = sDataNetType_1x[mInetCondition];
             break;
         case TelephonyManager.NETWORK_TYPE_1xRTT:
-            mDataIconList = sDataNetType_1x[connected];
+            mDataIconList = sDataNetType_1x[mInetCondition];
             break;
         case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through
         case TelephonyManager.NETWORK_TYPE_EVDO_A:
         case TelephonyManager.NETWORK_TYPE_EVDO_B:
-            mDataIconList = sDataNetType_3g[connected];
+            mDataIconList = sDataNetType_3g[mInetCondition];
             break;
         default:
-            mDataIconList = sDataNetType_g[connected];
+            mDataIconList = sDataNetType_g[mInetCondition];
         break;
         }
     }
@@ -1101,11 +1112,11 @@
             int iconId;
             final int newRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200);
             int newSignalLevel = WifiManager.calculateSignalLevel(newRssi,
-                                                                  sWifiSignalImages.length);
+                                                                  sWifiSignalImages[0].length);
             if (newSignalLevel != mLastWifiSignalLevel) {
                 mLastWifiSignalLevel = newSignalLevel;
                 if (mIsWifiConnected) {
-                    iconId = sWifiSignalImages[mLastWifiInetConnectivityState][newSignalLevel];
+                    iconId = sWifiSignalImages[mInetCondition][newSignalLevel];
                 } else {
                     iconId = sWifiTemporarilyNotConnectedImage;
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java
index af736aa..b555277 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java
@@ -82,7 +82,7 @@
 
 public class StatusBarService extends Service implements CommandQueue.Callbacks {
     static final String TAG = "StatusBarService";
-    static final boolean SPEW = false;
+    static final boolean SPEW = true;
 
     public static final String ACTION_STATUSBAR_START
             = "com.android.internal.policy.statusbar.START";
@@ -1534,4 +1534,3 @@
         }
     };
 }
-
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbStorageActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbStorageActivity.java
index 55d31ec..29df28e 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbStorageActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbStorageActivity.java
@@ -30,6 +30,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.hardware.Usb;
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.Handler;
@@ -70,11 +71,11 @@
     static final boolean localLOGV = false;
 
     /** Used to detect when the USB cable is unplugged, so we can call finish() */
-    private BroadcastReceiver mBatteryReceiver = new BroadcastReceiver() {
+    private BroadcastReceiver mUsbStateReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            if (intent.getAction() == Intent.ACTION_BATTERY_CHANGED) {
-                handleBatteryChanged(intent);
+            if (intent.getAction().equals(Usb.ACTION_USB_STATE)) {
+                handleUsbStateChanged(intent);
             }
         }
     };
@@ -139,7 +140,7 @@
         super.onResume();
 
         mStorageManager.registerListener(mStorageListener);
-        registerReceiver(mBatteryReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
+        registerReceiver(mUsbStateReceiver, new IntentFilter(Usb.ACTION_USB_STATE));
         try {
             switchDisplay(mStorageManager.isUsbMassStorageEnabled());
         } catch (Exception ex) {
@@ -151,15 +152,15 @@
     protected void onPause() {
         super.onPause();
         
-        unregisterReceiver(mBatteryReceiver);
+        unregisterReceiver(mUsbStateReceiver);
         if (mStorageManager == null && mStorageListener != null) {
             mStorageManager.unregisterListener(mStorageListener);
         }
     }
 
-    private void handleBatteryChanged(Intent intent) {
-        int pluggedType = intent.getIntExtra("plugged", 0);
-        if (pluggedType == 0) {
+    private void handleUsbStateChanged(Intent intent) {
+        boolean connected = intent.getExtras().getBoolean(Usb.USB_CONNECTED);
+        if (!connected) {
             // It was disconnected from the plug, so finish
             finish();
         }
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index e454c08..aa87f29 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -54,6 +54,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
+import android.os.WorkSource;
 import android.provider.Settings;
 import android.util.EventLog;
 import android.util.Slog;
@@ -504,7 +505,7 @@
         parseLeftoverJournals();
 
         // Power management
-        mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "backup");
+        mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*");
 
         // Start the backup passes going
         setBackupEnabled(areEnabled);
@@ -1363,6 +1364,7 @@
                         ? IApplicationThread.BACKUP_MODE_FULL
                         : IApplicationThread.BACKUP_MODE_INCREMENTAL;
                 try {
+                    mWakelock.setWorkSource(new WorkSource(request.appInfo.uid));
                     agent = bindToAgentSynchronous(request.appInfo, mode);
                     if (agent != null) {
                         int result = processOneBackup(request, agent, transport);
@@ -1378,6 +1380,8 @@
                 }
             }
 
+            mWakelock.setWorkSource(null);
+
             return BackupConstants.TRANSPORT_OK;
         }
 
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 9784d96..f38748b 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -48,6 +48,7 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.GregorianCalendar;
 import java.util.List;
 
 /**
@@ -109,6 +110,10 @@
     private boolean mSystemReady;
     private Intent mInitialBroadcast;
 
+    // used in DBG mode to track inet condition reports
+    private static final int INET_CONDITION_LOG_MAX_SIZE = 15;
+    private ArrayList mInetLog;
+
     private static class NetworkAttributes {
         /**
          * Class for holding settings read from resources.
@@ -329,6 +334,9 @@
                                   mTethering.getTetherableWifiRegexs().length != 0) &&
                                  mTethering.getUpstreamIfaceRegexs().length != 0);
 
+        if (DBG) {
+            mInetLog = new ArrayList();
+        }
     }
 
 
@@ -912,11 +920,19 @@
             newNet = tryFailover(prevNetType);
             if (newNet != null) {
                 NetworkInfo switchTo = newNet.getNetworkInfo();
+                if (!switchTo.isConnected()) {
+                    // if the other net is connected they've already reset this and perhaps even gotten
+                    // a positive report we don't want to overwrite, but if not we need to clear this now
+                    // to turn our cellular sig strength white
+                    mDefaultInetConditionPublished = 0;
+                }
                 intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
             } else {
+                mDefaultInetConditionPublished = 0; // we're not connected anymore
                 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
             }
         }
+        intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
         // do this before we broadcast the change
         handleConnectivityChange(prevNetType);
 
@@ -1008,7 +1024,15 @@
     }
 
     private void sendConnectedBroadcast(NetworkInfo info) {
-        Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
+        sendGeneralBroadcast(info, ConnectivityManager.CONNECTIVITY_ACTION);
+    }
+
+    private void sendInetConditionBroadcast(NetworkInfo info) {
+        sendGeneralBroadcast(info, ConnectivityManager.INET_CONDITION_ACTION);
+    }
+
+    private void sendGeneralBroadcast(NetworkInfo info, String bcastType) {
+        Intent intent = new Intent(bcastType);
         intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
         if (info.isFailover()) {
             intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
@@ -1067,12 +1091,20 @@
             newNet = tryFailover(info.getType());
             if (newNet != null) {
                 NetworkInfo switchTo = newNet.getNetworkInfo();
+                if (!switchTo.isConnected()) {
+                    // if the other net is connected they've already reset this and perhaps even gotten
+                    // a positive report we don't want to overwrite, but if not we need to clear this now
+                    // to turn our cellular sig strength white
+                    mDefaultInetConditionPublished = 0;
+                }
                 intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
             } else {
+                mDefaultInetConditionPublished = 0;
                 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
             }
         }
 
+        intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
         sendStickyBroadcast(intent);
         /*
          * If the failover network is already connected, then immediately send
@@ -1357,6 +1389,14 @@
         pw.println();
 
         mTethering.dump(fd, pw, args);
+
+        if (mInetLog != null) {
+            pw.println();
+            pw.println("Inet condition reports:");
+            for(int i = 0; i < mInetLog.size(); i++) {
+                pw.println(mInetLog.get(i));
+            }
+        }
     }
 
     // must be stateless - things change under us.
@@ -1512,7 +1552,7 @@
                         break;
                     }
                     mDefaultInetConditionPublished = mDefaultInetCondition;
-                    sendConnectedBroadcast(networkInfo);
+                    sendInetConditionBroadcast(networkInfo);
                     break;
             }
         }
@@ -1605,6 +1645,17 @@
                 android.Manifest.permission.STATUS_BAR,
                 "ConnectivityService");
 
+        if (DBG) {
+            int pid = getCallingPid();
+            int uid = getCallingUid();
+            String s = pid + "(" + uid + ") reports inet is " +
+                (percentage > 50 ? "connected" : "disconnected") + " (" + percentage + ") on " +
+                "network Type " + networkType + " at " + GregorianCalendar.getInstance().getTime();
+            mInetLog.add(s);
+            while(mInetLog.size() > INET_CONDITION_LOG_MAX_SIZE) {
+                mInetLog.remove(0);
+            }
+        }
         mHandler.sendMessage(mHandler.obtainMessage(
             NetworkStateTracker.EVENT_INET_CONDITION_CHANGE, networkType, percentage));
     }
diff --git a/services/java/com/android/server/InputManager.java b/services/java/com/android/server/InputManager.java
index 90d036a..024aec5 100644
--- a/services/java/com/android/server/InputManager.java
+++ b/services/java/com/android/server/InputManager.java
@@ -24,18 +24,13 @@
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.os.Environment;
-import android.os.LocalPowerManager;
-import android.os.PowerManager;
 import android.os.SystemProperties;
 import android.util.Slog;
 import android.util.Xml;
 import android.view.InputChannel;
 import android.view.InputDevice;
 import android.view.InputEvent;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
 import android.view.Surface;
-import android.view.WindowManagerPolicy;
 
 import java.io.BufferedReader;
 import java.io.File;
@@ -83,7 +78,6 @@
     private static native void nativeSetInputWindows(InputWindow[] windows);
     private static native void nativeSetInputDispatchMode(boolean enabled, boolean frozen);
     private static native void nativeSetFocusedApplication(InputApplication application);
-    private static native void nativePreemptInputDispatch();
     private static native InputDevice nativeGetInputDevice(int deviceId);
     private static native int[] nativeGetInputDeviceIds();
     private static native String nativeDump();
@@ -331,10 +325,6 @@
         nativeSetFocusedApplication(application);
     }
     
-    public void preemptInputDispatch() {
-        nativePreemptInputDispatch();
-    }
-    
     public void setInputDispatchMode(boolean enabled, boolean frozen) {
         nativeSetInputDispatchMode(enabled, frozen);
     }
@@ -395,20 +385,10 @@
         public void notifyInputChannelBroken(InputChannel inputChannel) {
             mWindowManagerService.mInputMonitor.notifyInputChannelBroken(inputChannel);
         }
-
-        @SuppressWarnings("unused")
-        public long notifyInputChannelANR(InputChannel inputChannel) {
-            return mWindowManagerService.mInputMonitor.notifyInputChannelANR(inputChannel);
-        }
-
-        @SuppressWarnings("unused")
-        public void notifyInputChannelRecoveredFromANR(InputChannel inputChannel) {
-            mWindowManagerService.mInputMonitor.notifyInputChannelRecoveredFromANR(inputChannel);
-        }
         
         @SuppressWarnings("unused")
-        public long notifyANR(Object token) {
-            return mWindowManagerService.mInputMonitor.notifyANR(token);
+        public long notifyANR(Object token, InputChannel inputChannel) {
+            return mWindowManagerService.mInputMonitor.notifyANR(token, inputChannel);
         }
         
         @SuppressWarnings("unused")
diff --git a/services/java/com/android/server/InputWindow.java b/services/java/com/android/server/InputWindow.java
index dbc59ef..befc770 100644
--- a/services/java/com/android/server/InputWindow.java
+++ b/services/java/com/android/server/InputWindow.java
@@ -27,6 +27,9 @@
     // The input channel associated with the window.
     public InputChannel inputChannel;
     
+    // The window name.
+    public String name;
+    
     // Window layout params attributes.  (WindowManager.LayoutParams)
     public int layoutParamsFlags;
     public int layoutParamsType;
@@ -55,6 +58,9 @@
     // Window is visible.
     public boolean visible;
     
+    // Window can receive keys.
+    public boolean canReceiveKeys;
+    
     // Window has focus.
     public boolean hasFocus;
     
@@ -64,6 +70,9 @@
     // Input event dispatching is paused.
     public boolean paused;
     
+    // Window layer.
+    public int layer;
+    
     // Id of process and user that owns the window.
     public int ownerPid;
     public int ownerUid;
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index a38970f..643b2f5 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -52,6 +52,7 @@
 import android.os.PowerManager;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.WorkSource;
 import android.provider.Settings;
 import android.util.Log;
 import android.util.Slog;
@@ -157,6 +158,12 @@
     private final HashMap<String,ArrayList<UpdateRecord>> mRecordsByProvider =
         new HashMap<String,ArrayList<UpdateRecord>>();
 
+    /**
+     * Temporary filled in when computing min time for a provider.  Access is
+     * protected by global lock mLock.
+     */
+    private final WorkSource mTmpWorkSource = new WorkSource();
+
     // Proximity listeners
     private Receiver mProximityReceiver = null;
     private ILocationListener mProximityListener = null;
@@ -912,7 +919,7 @@
         if (enabled) {
             p.enable();
             if (listeners > 0) {
-                p.setMinTime(getMinTimeLocked(provider));
+                p.setMinTime(getMinTimeLocked(provider), mTmpWorkSource);
                 p.enableLocationTracking(true);
             }
         } else {
@@ -924,9 +931,21 @@
     private long getMinTimeLocked(String provider) {
         long minTime = Long.MAX_VALUE;
         ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
+        mTmpWorkSource.clear();
         if (records != null) {
             for (int i=records.size()-1; i>=0; i--) {
-                minTime = Math.min(minTime, records.get(i).mMinTime);
+                UpdateRecord ur = records.get(i);
+                long curTime = ur.mMinTime;
+                if (curTime < minTime) {
+                    minTime = curTime;
+                }
+            }
+            long inclTime = (minTime*3)/2;
+            for (int i=records.size()-1; i>=0; i--) {
+                UpdateRecord ur = records.get(i);
+                if (ur.mMinTime <= inclTime) {
+                    mTmpWorkSource.add(ur.mUid);
+                }
             }
         }
         return minTime;
@@ -1124,7 +1143,7 @@
             boolean isProviderEnabled = isAllowedBySettingsLocked(provider);
             if (isProviderEnabled) {
                 long minTimeForProvider = getMinTimeLocked(provider);
-                p.setMinTime(minTimeForProvider);
+                p.setMinTime(minTimeForProvider, mTmpWorkSource);
                 // try requesting single shot if singleShot is true, and fall back to
                 // regular location tracking if requestSingleShotFix() is not supported
                 if (!singleShot || !p.requestSingleShotFix()) {
@@ -1222,7 +1241,7 @@
                 LocationProviderInterface p = mProvidersByName.get(provider);
                 if (p != null) {
                     if (hasOtherListener) {
-                        p.setMinTime(getMinTimeLocked(provider));
+                        p.setMinTime(getMinTimeLocked(provider), mTmpWorkSource);
                     } else {
                         p.enableLocationTracking(false);
                     }
@@ -1940,7 +1959,7 @@
 
     // Geocoder
 
-    public boolean geocoderIsImplemented() {
+    public boolean geocoderIsPresent() {
         return mGeocodeProvider != null;
     }
 
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 6e8b42e..cfba07a 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -826,6 +826,15 @@
         if (!getVolumeState(path).equals(Environment.MEDIA_MOUNTED)) {
             return VoldResponseCode.OpFailedVolNotMounted;
         }
+
+        /*
+         * Force a GC to make sure AssetManagers in other threads of the
+         * system_server are cleaned up. We have to do this since AssetManager
+         * instances are kept as a WeakReference and it's possible we have files
+         * open on the external storage.
+         */
+        Runtime.getRuntime().gc();
+
         // Redundant probably. But no harm in updating state again.
         mPms.updateExternalMediaStatus(false, false);
         try {
@@ -1277,6 +1286,14 @@
         waitForReady();
         warnOnNotMounted();
 
+        /*
+         * Force a GC to make sure AssetManagers in other threads of the
+         * system_server are cleaned up. We have to do this since AssetManager
+         * instances are kept as a WeakReference and it's possible we have files
+         * open on the external storage.
+         */
+        Runtime.getRuntime().gc();
+
         int rc = StorageResultCode.OperationSucceeded;
         try {
             mConnector.doCommand(String.format("asec destroy %s%s", id, (force ? " force" : "")));
@@ -1341,6 +1358,14 @@
             }
          }
 
+        /*
+         * Force a GC to make sure AssetManagers in other threads of the
+         * system_server are cleaned up. We have to do this since AssetManager
+         * instances are kept as a WeakReference and it's possible we have files
+         * open on the external storage.
+         */
+        Runtime.getRuntime().gc();
+
         int rc = StorageResultCode.OperationSucceeded;
         String cmd = String.format("asec unmount %s%s", id, (force ? " force" : ""));
         try {
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 685bee4..4c15c94 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -222,6 +222,9 @@
     // This is the object monitoring the system app dir.
     final FileObserver mSystemInstallObserver;
 
+    // This is the object monitoring the system app dir.
+    final FileObserver mVendorInstallObserver;
+
     // This is the object monitoring mAppInstallDir.
     final FileObserver mAppInstallObserver;
 
@@ -234,6 +237,7 @@
 
     final File mFrameworkDir;
     final File mSystemAppDir;
+    final File mVendorAppDir;
     final File mAppInstallDir;
     final File mDalvikCacheDir;
 
@@ -927,6 +931,14 @@
             scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM
                     | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode);
             
+            // Collect all vendor packages.
+            mVendorAppDir = new File("/vendor/app");
+            mVendorInstallObserver = new AppDirObserver(
+                mVendorAppDir.getPath(), OBSERVER_EVENTS, true);
+            mVendorInstallObserver.startWatching();
+            scanDirLI(mVendorAppDir, PackageParser.PARSE_IS_SYSTEM
+                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode);
+
             if (mInstaller != null) {
                 if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands");
                 mInstaller.moveFiles();
@@ -2493,9 +2505,13 @@
     }
 
     private void scanDirLI(File dir, int flags, int scanMode) {
-        Log.d(TAG, "Scanning app dir " + dir);
-
         String[] files = dir.list();
+        if (files == null) {
+            Log.d(TAG, "No files in app dir " + dir);
+            return;
+        }
+
+        Log.d(TAG, "Scanning app dir " + dir);
 
         int i;
         for (i=0; i<files.length; i++) {
@@ -2546,7 +2562,7 @@
         if (GET_CERTIFICATES) {
             if (ps != null
                     && ps.codePath.equals(srcFile)
-                    && ps.getTimeStamp() == srcFile.lastModified()) {
+                    && ps.timeStamp == srcFile.lastModified()) {
                 if (ps.signatures.mSignatures != null
                         && ps.signatures.mSignatures.length != 0) {
                     // Optimization: reuse the existing cached certificates
@@ -3139,7 +3155,7 @@
         
         long scanFileTime = scanFile.lastModified();
         final boolean forceDex = (scanMode&SCAN_FORCE_DEX) != 0;
-        final boolean scanFileNewer = forceDex || scanFileTime != pkgSetting.getTimeStamp();
+        final boolean scanFileNewer = forceDex || scanFileTime != pkgSetting.timeStamp;
         pkg.applicationInfo.processName = fixProcessName(
                 pkg.applicationInfo.packageName,
                 pkg.applicationInfo.processName,
@@ -7007,7 +7023,7 @@
                         }
                     }
                     pw.println("]");
-                    pw.print("    timeStamp="); pw.println(ps.getTimeStampStr());
+                    pw.print("    timeStamp="); pw.println(String.valueOf(ps.timeStamp));
                     pw.print("    signatures="); pw.println(ps.signatures);
                     pw.print("    permissionsFixed="); pw.print(ps.permissionsFixed);
                             pw.print(" haveGids="); pw.println(ps.haveGids);
@@ -7532,8 +7548,7 @@
         String resourcePathString;
         String nativeLibraryPathString;
         String obbPathString;
-        private long timeStamp;
-        private String timeStampString = "0";
+        long timeStamp;
         int versionCode;
 
         boolean uidError;
@@ -7590,23 +7605,7 @@
         }
 
         public void setTimeStamp(long newStamp) {
-            if (newStamp != timeStamp) {
-                timeStamp = newStamp;
-                timeStampString = Long.toString(newStamp);
-            }
-        }
-
-        public void setTimeStamp(long newStamp, String newStampStr) {
             timeStamp = newStamp;
-            timeStampString = newStampStr;
-        }
-
-        public long getTimeStamp() {
-            return timeStamp;
-        }
-
-        public String getTimeStampStr() {
-            return timeStampString;
         }
 
         public void copyFrom(PackageSettingBase base) {
@@ -7614,7 +7613,6 @@
             gids = base.gids;
 
             timeStamp = base.timeStamp;
-            timeStampString = base.timeStampString;
             signatures = base.signatures;
             permissionsFixed = base.permissionsFixed;
             haveGids = base.haveGids;
@@ -8476,7 +8474,7 @@
                 serializer.attribute(null, "realName", pkg.realName);
             }
             serializer.attribute(null, "codePath", pkg.codePathString);
-            serializer.attribute(null, "ts", pkg.getTimeStampStr());
+            serializer.attribute(null, "ts", String.valueOf(pkg.timeStamp));
             serializer.attribute(null, "version", String.valueOf(pkg.versionCode));
             if (!pkg.resourcePathString.equals(pkg.codePathString)) {
                 serializer.attribute(null, "resourcePath", pkg.resourcePathString);
@@ -8528,7 +8526,7 @@
             }
             serializer.attribute(null, "flags",
                     Integer.toString(pkg.pkgFlags));
-            serializer.attribute(null, "ts", pkg.getTimeStampStr());
+            serializer.attribute(null, "ts", String.valueOf(pkg.timeStamp));
             serializer.attribute(null, "version", String.valueOf(pkg.versionCode));
             if (pkg.sharedUser == null) {
                 serializer.attribute(null, "userId",
@@ -8888,7 +8886,7 @@
             if (timeStampStr != null) {
                 try {
                     long timeStamp = Long.parseLong(timeStampStr);
-                    ps.setTimeStamp(timeStamp, timeStampStr);
+                    ps.setTimeStamp(timeStamp);
                 } catch (NumberFormatException e) {
                 }
             }
@@ -8936,7 +8934,6 @@
             String installerPackageName = null;
             String uidError = null;
             int pkgFlags = 0;
-            String timeStampStr;
             long timeStamp = 0;
             PackageSettingBase packageSetting = null;
             String version = null;
@@ -8977,7 +8974,7 @@
                         pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
                     }
                 }
-                timeStampStr = parser.getAttributeValue(null, "ts");
+                final String timeStampStr = parser.getAttributeValue(null, "ts");
                 if (timeStampStr != null) {
                     try {
                         timeStamp = Long.parseLong(timeStampStr);
@@ -9013,7 +9010,7 @@
                                 + " while parsing settings at "
                                 + parser.getPositionDescription());
                     } else {
-                        packageSetting.setTimeStamp(timeStamp, timeStampStr);
+                        packageSetting.setTimeStamp(timeStamp);
                     }
                 } else if (sharedIdStr != null) {
                     userId = sharedIdStr != null
@@ -9022,7 +9019,7 @@
                         packageSetting = new PendingPackage(name.intern(), realName,
                                 new File(codePathStr), new File(resourcePathStr),
                                 nativeLibraryPathStr, userId, versionCode, pkgFlags);
-                        packageSetting.setTimeStamp(timeStamp, timeStampStr);
+                        packageSetting.setTimeStamp(timeStamp);
                         mPendingPackages.add((PendingPackage) packageSetting);
                         if (DEBUG_SETTINGS) Log.i(TAG, "Reading package " + name
                                 + ": sharedUserId=" + userId + " pkg="
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index 16f3f10..8ab1bb8 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -50,6 +50,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
+import android.os.WorkSource;
 import android.provider.Settings.SettingNotFoundException;
 import android.provider.Settings;
 import android.util.EventLog;
@@ -310,7 +311,7 @@
                 long ident = Binder.clearCallingIdentity();
                 try {
                     PowerManagerService.this.acquireWakeLockLocked(mFlags, mToken,
-                            MY_UID, MY_PID, mTag);
+                            MY_UID, MY_PID, mTag, null);
                     mHeld = true;
                 } finally {
                     Binder.restoreCallingIdentity(ident);
@@ -607,6 +608,7 @@
         final int uid;
         final int pid;
         final int monitorType;
+        WorkSource ws;
         boolean activated = true;
         int minState;
     }
@@ -630,35 +632,84 @@
                 || n == PowerManager.SCREEN_DIM_WAKE_LOCK;
     }
 
-    public void acquireWakeLock(int flags, IBinder lock, String tag) {
+    void enforceWakeSourcePermission(int uid, int pid) {
+        if (uid == Process.myUid()) {
+            return;
+        }
+        mContext.enforcePermission(android.Manifest.permission.UPDATE_DEVICE_STATS,
+                pid, uid, null);
+    }
+
+    public void acquireWakeLock(int flags, IBinder lock, String tag, WorkSource ws) {
         int uid = Binder.getCallingUid();
         int pid = Binder.getCallingPid();
         if (uid != Process.myUid()) {
             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
         }
+        if (ws != null) {
+            enforceWakeSourcePermission(uid, pid);
+        }
         long ident = Binder.clearCallingIdentity();
         try {
             synchronized (mLocks) {
-                acquireWakeLockLocked(flags, lock, uid, pid, tag);
+                acquireWakeLockLocked(flags, lock, uid, pid, tag, ws);
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
     }
 
-    public void acquireWakeLockLocked(int flags, IBinder lock, int uid, int pid, String tag) {
-        int acquireUid = -1;
-        int acquirePid = -1;
-        String acquireName = null;
-        int acquireType = -1;
+    void noteStartWakeLocked(WakeLock wl, WorkSource ws) {
+        if (wl.monitorType >= 0) {
+            long origId = Binder.clearCallingIdentity();
+            try {
+                if (ws != null) {
+                    mBatteryStats.noteStartWakelockFromSource(ws, wl.pid, wl.tag,
+                            wl.monitorType);
+                } else {
+                    mBatteryStats.noteStartWakelock(wl.uid, wl.pid, wl.tag, wl.monitorType);
+                }
+            } catch (RemoteException e) {
+                // Ignore
+            } finally {
+                Binder.restoreCallingIdentity(origId);
+            }
+        }
+    }
 
+    void noteStopWakeLocked(WakeLock wl, WorkSource ws) {
+        if (wl.monitorType >= 0) {
+            long origId = Binder.clearCallingIdentity();
+            try {
+                if (ws != null) {
+                    mBatteryStats.noteStopWakelockFromSource(ws, wl.pid, wl.tag,
+                            wl.monitorType);
+                } else {
+                    mBatteryStats.noteStopWakelock(wl.uid, wl.pid, wl.tag, wl.monitorType);
+                }
+            } catch (RemoteException e) {
+                // Ignore
+            } finally {
+                Binder.restoreCallingIdentity(origId);
+            }
+        }
+    }
+
+    public void acquireWakeLockLocked(int flags, IBinder lock, int uid, int pid, String tag,
+            WorkSource ws) {
         if (mSpew) {
             Slog.d(TAG, "acquireWakeLock flags=0x" + Integer.toHexString(flags) + " tag=" + tag);
         }
 
+        if (ws != null && ws.size() == 0) {
+            ws = null;
+        }
+
         int index = mLocks.getIndex(lock);
         WakeLock wl;
         boolean newlock;
+        boolean diffsource;
+        WorkSource oldsource;
         if (index < 0) {
             wl = new WakeLock(flags, lock, tag, uid, pid);
             switch (wl.flags & LOCK_MASK)
@@ -687,10 +738,31 @@
                     return;
             }
             mLocks.addLock(wl);
+            if (ws != null) {
+                wl.ws = new WorkSource(ws);
+            }
             newlock = true;
+            diffsource = false;
+            oldsource = null;
         } else {
             wl = mLocks.get(index);
             newlock = false;
+            oldsource = wl.ws;
+            if (oldsource != null) {
+                if (ws == null) {
+                    wl.ws = null;
+                    diffsource = true;
+                } else {
+                    diffsource = oldsource.diff(ws);
+                }
+            } else if (ws != null) {
+                diffsource = true;
+            } else {
+                diffsource = false;
+            }
+            if (diffsource) {
+                wl.ws = new WorkSource(ws);
+            }
         }
         if (isScreenLock(flags)) {
             // if this causes a wakeup, we reactivate all of the locks and
@@ -731,19 +803,36 @@
                 enableProximityLockLocked();
             }
         }
-        if (newlock) {
-            acquireUid = wl.uid;
-            acquirePid = wl.pid;
-            acquireName = wl.tag;
-            acquireType = wl.monitorType;
-        }
 
-        if (acquireType >= 0) {
-            try {
-                mBatteryStats.noteStartWakelock(acquireUid, acquirePid, acquireName, acquireType);
-            } catch (RemoteException e) {
-                // Ignore
+        if (diffsource) {
+            // If the lock sources have changed, need to first release the
+            // old ones.
+            noteStopWakeLocked(wl, oldsource);
+        }
+        if (newlock || diffsource) {
+            noteStartWakeLocked(wl, ws);
+        }
+    }
+
+    public void updateWakeLockWorkSource(IBinder lock, WorkSource ws) {
+        int uid = Binder.getCallingUid();
+        int pid = Binder.getCallingPid();
+        if (ws != null && ws.size() == 0) {
+            ws = null;
+        }
+        if (ws != null) {
+            enforceWakeSourcePermission(uid, pid);
+        }
+        synchronized (mLocks) {
+            int index = mLocks.getIndex(lock);
+            if (index < 0) {
+                throw new IllegalArgumentException("Wake lock not active");
             }
+            WakeLock wl = mLocks.get(index);
+            WorkSource oldsource = wl.ws;
+            wl.ws = ws != null ? new WorkSource(ws) : null;
+            noteStopWakeLocked(wl, oldsource);
+            noteStartWakeLocked(wl, ws);
         }
     }
 
@@ -759,11 +848,6 @@
     }
 
     private void releaseWakeLockLocked(IBinder lock, int flags, boolean death) {
-        int releaseUid;
-        int releasePid;
-        String releaseName;
-        int releaseType;
-
         WakeLock wl = mLocks.removeLock(lock);
         if (wl == null) {
             return;
@@ -804,21 +888,8 @@
         }
         // Unlink the lock from the binder.
         wl.binder.unlinkToDeath(wl, 0);
-        releaseUid = wl.uid;
-        releasePid = wl.pid;
-        releaseName = wl.tag;
-        releaseType = wl.monitorType;
 
-        if (releaseType >= 0) {
-            long origId = Binder.clearCallingIdentity();
-            try {
-                mBatteryStats.noteStopWakelock(releaseUid, releasePid, releaseName, releaseType);
-            } catch (RemoteException e) {
-                // Ignore
-            } finally {
-                Binder.restoreCallingIdentity(origId);
-            }
-        }
+        noteStopWakeLocked(wl, wl.ws);
     }
 
     private class PokeLock implements IBinder.DeathRecipient
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 4a9c9e9..859de46 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -518,14 +518,8 @@
         });
 
         // For debug builds, log event loop stalls to dropbox for analysis.
-        // Similar logic also appears in ActivityThread.java for system apps.
-        if (!"user".equals(Build.TYPE)) {
-            Slog.i(TAG, "Enabling StrictMode for system server.");
-            StrictMode.setThreadPolicy(
-                StrictMode.DISALLOW_DISK_WRITE |
-                StrictMode.DISALLOW_DISK_READ |
-                StrictMode.DISALLOW_NETWORK |
-                StrictMode.PENALTY_DROPBOX);
+        if (StrictMode.conditionallyEnableDebugLogging()) {
+            Slog.i(TAG, "Enabled StrictMode for system server main thread.");
         }
 
         Looper.loop();
diff --git a/services/java/com/android/server/VibratorService.java b/services/java/com/android/server/VibratorService.java
index 2e7e3e1..f0b5955 100755
--- a/services/java/com/android/server/VibratorService.java
+++ b/services/java/com/android/server/VibratorService.java
@@ -29,6 +29,7 @@
 import android.os.IBinder;
 import android.os.Binder;
 import android.os.SystemClock;
+import android.os.WorkSource;
 import android.util.Slog;
 
 import java.util.LinkedList;
@@ -39,6 +40,7 @@
 
     private final LinkedList<Vibration> mVibrations;
     private Vibration mCurrentVibration;
+    private final WorkSource mTmpWorkSource = new WorkSource();
 
     private class Vibration implements IBinder.DeathRecipient {
         private final IBinder mToken;
@@ -46,22 +48,24 @@
         private final long    mStartTime;
         private final long[]  mPattern;
         private final int     mRepeat;
+        private final int     mUid;
 
-        Vibration(IBinder token, long millis) {
-            this(token, millis, null, 0);
+        Vibration(IBinder token, long millis, int uid) {
+            this(token, millis, null, 0, uid);
         }
 
-        Vibration(IBinder token, long[] pattern, int repeat) {
-            this(token, 0, pattern, repeat);
+        Vibration(IBinder token, long[] pattern, int repeat, int uid) {
+            this(token, 0, pattern, repeat, uid);
         }
 
         private Vibration(IBinder token, long millis, long[] pattern,
-                int repeat) {
+                int repeat, int uid) {
             mToken = token;
             mTimeout = millis;
             mStartTime = SystemClock.uptimeMillis();
             mPattern = pattern;
             mRepeat = repeat;
+            mUid = uid;
         }
 
         public void binderDied() {
@@ -98,7 +102,7 @@
         mContext = context;
         PowerManager pm = (PowerManager)context.getSystemService(
                 Context.POWER_SERVICE);
-        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*vibrator*");
         mWakeLock.setReferenceCounted(true);
 
         mVibrations = new LinkedList<Vibration>();
@@ -113,6 +117,7 @@
                 != PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException("Requires VIBRATE permission");
         }
+        int uid = Binder.getCallingUid();
         // We're running in the system server so we cannot crash. Check for a
         // timeout of 0 or negative. This will ensure that a vibration has
         // either a timeout of > 0 or a non-null pattern.
@@ -122,7 +127,7 @@
             // longer than milliseconds.
             return;
         }
-        Vibration vib = new Vibration(token, milliseconds);
+        Vibration vib = new Vibration(token, milliseconds, uid);
         synchronized (mVibrations) {
             removeVibrationLocked(token);
             doCancelVibrateLocked();
@@ -146,6 +151,7 @@
                 != PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException("Requires VIBRATE permission");
         }
+        int uid = Binder.getCallingUid();
         // so wakelock calls will succeed
         long identity = Binder.clearCallingIdentity();
         try {
@@ -165,7 +171,7 @@
                 return;
             }
 
-            Vibration vib = new Vibration(token, pattern, repeat);
+            Vibration vib = new Vibration(token, pattern, repeat, uid);
             try {
                 token.linkToDeath(vib, 0);
             } catch (RemoteException e) {
@@ -280,6 +286,8 @@
 
         VibrateThread(Vibration vib) {
             mVibration = vib;
+            mTmpWorkSource.set(vib.mUid);
+            mWakeLock.setWorkSource(mTmpWorkSource);
             mWakeLock.acquire();
         }
 
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
index 124da4e..c837a3a 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -727,9 +727,10 @@
         }
     }
 
+    // Called by SystemBackupAgent after files are restored to disk.
     void settingsRestored() {
         if (DEBUG) Slog.v(TAG, "settingsRestored");
-        
+
         boolean success = false;
         synchronized (mLock) {
             loadSettingsLocked();
@@ -766,7 +767,10 @@
             mName = "";
             WALLPAPER_FILE.delete();
         }
-        saveSettingsLocked();
+
+        synchronized (mLock) {
+            saveSettingsLocked();
+        }
     }
 
     boolean restoreNamedResourceLocked() {
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 0eca082..87329e3 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -63,6 +63,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.WorkSource;
 import android.provider.Settings;
 import android.util.Slog;
 import android.text.TextUtils;
@@ -144,7 +145,7 @@
      */
     private static final long DEFAULT_IDLE_MILLIS = 15 * 60 * 1000; /* 15 minutes */
 
-    private static final String WAKELOCK_TAG = "WifiService";
+    private static final String WAKELOCK_TAG = "*wifi*";
 
     /**
      * The maximum amount of time to hold the wake lock after a disconnect
@@ -188,6 +189,12 @@
     private static final int SCAN_RESULT_BUFFER_SIZE = 512;
     private boolean mNeedReconfig;
 
+    /**
+     * Temporary for computing UIDS that are responsible for starting WIFI.
+     * Protected by mWifiStateTracker lock.
+     */
+    private final WorkSource mTmpWorkSource = new WorkSource();
+
     /*
      * Last UID that asked to enable WIFI.
      */
@@ -528,9 +535,9 @@
         long ident = Binder.clearCallingIdentity();
         try {
             if (wifiState == WIFI_STATE_ENABLED) {
-                mBatteryStats.noteWifiOn(uid);
+                mBatteryStats.noteWifiOn();
             } else if (wifiState == WIFI_STATE_DISABLED) {
-                mBatteryStats.noteWifiOff(uid);
+                mBatteryStats.noteWifiOff();
             }
         } catch (RemoteException e) {
         } finally {
@@ -787,9 +794,9 @@
         long ident = Binder.clearCallingIdentity();
         try {
             if (wifiAPState == WIFI_AP_STATE_ENABLED) {
-                mBatteryStats.noteWifiOn(uid);
+                mBatteryStats.noteWifiOn();
             } else if (wifiAPState == WIFI_AP_STATE_DISABLED) {
-                mBatteryStats.noteWifiOff(uid);
+                mBatteryStats.noteWifiOff();
             }
         } catch (RemoteException e) {
         } finally {
@@ -1663,6 +1670,9 @@
                 mAlarmManager.cancel(mIdleIntent);
                 mDeviceIdle = false;
                 mScreenOff = false;
+                // Once the screen is on, we are not keeping WIFI running
+                // because of any locks so clear that tracking immediately.
+                reportStartWorkSource();
                 mWifiStateTracker.enableRssiPolling(true);
                 /* DHCP or other temporary failures in the past can prevent
                  * a disabled network from being connected to, enable on screen on
@@ -1704,6 +1714,7 @@
             } else if (action.equals(ACTION_DEVICE_IDLE)) {
                 Slog.d(TAG, "got ACTION_DEVICE_IDLE");
                 mDeviceIdle = true;
+                reportStartWorkSource();
             } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
                 /*
                  * Set a timer to put Wi-Fi to sleep, but only if the screen is off
@@ -1805,6 +1816,19 @@
         Message.obtain(mWifiHandler, MESSAGE_ENABLE_NETWORKS).sendToTarget();
     }
 
+    private void reportStartWorkSource() {
+        synchronized (mWifiStateTracker) {
+            mTmpWorkSource.clear();
+            if (mDeviceIdle) {
+                for (int i=0; i<mLocks.mList.size(); i++) {
+                    mTmpWorkSource.add(mLocks.mList.get(i).mWorkSource);
+                }
+            }
+            mWifiStateTracker.updateBatteryWorkSourceLocked(mTmpWorkSource);
+            sWakeLock.setWorkSource(mTmpWorkSource);
+        }
+    }
+
     private void updateWifiState() {
         // send a message so it's all serialized
         Message.obtain(mWifiHandler, MESSAGE_UPDATE_STATE, 0, 0).sendToTarget();
@@ -1813,7 +1837,12 @@
     private void doUpdateWifiState() {
         boolean wifiEnabled = getPersistedWifiEnabled();
         boolean airplaneMode = isAirplaneModeOn() && !mAirplaneModeOverwridden;
-        boolean lockHeld = mLocks.hasLocks();
+
+        boolean lockHeld;
+        synchronized (mLocks) {
+            lockHeld = mLocks.hasLocks();
+        }
+
         int strongestLockMode = WifiManager.WIFI_MODE_FULL;
         boolean wifiShouldBeEnabled = wifiEnabled && !airplaneMode;
         boolean wifiShouldBeStarted = !mDeviceIdle || lockHeld;
@@ -1921,6 +1950,7 @@
                     break;
 
                 case MESSAGE_START_WIFI:
+                    reportStartWorkSource();
                     mWifiStateTracker.setScanOnlyMode(msg.arg1 == WifiManager.WIFI_MODE_SCAN_ONLY);
                     mWifiStateTracker.restart();
                     mWifiStateTracker.setHighPerfMode(msg.arg1 ==
@@ -2036,8 +2066,8 @@
     }
 
     private class WifiLock extends DeathRecipient {
-        WifiLock(int lockMode, String tag, IBinder binder) {
-            super(lockMode, tag, binder);
+        WifiLock(int lockMode, String tag, IBinder binder, WorkSource ws) {
+            super(lockMode, tag, binder, ws);
         }
 
         public void binderDied() {
@@ -2111,7 +2141,15 @@
         }
     }
 
-    public boolean acquireWifiLock(IBinder binder, int lockMode, String tag) {
+    void enforceWakeSourcePermission(int uid, int pid) {
+        if (uid == Process.myUid()) {
+            return;
+        }
+        mContext.enforcePermission(android.Manifest.permission.UPDATE_DEVICE_STATS,
+                pid, uid, null);
+    }
+
+    public boolean acquireWifiLock(IBinder binder, int lockMode, String tag, WorkSource ws) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
         if (lockMode != WifiManager.WIFI_MODE_FULL &&
                 lockMode != WifiManager.WIFI_MODE_SCAN_ONLY &&
@@ -2120,34 +2158,68 @@
             if (DBG) throw new IllegalArgumentException("lockMode=" + lockMode);
             return false;
         }
-        WifiLock wifiLock = new WifiLock(lockMode, tag, binder);
+        if (ws != null) {
+            enforceWakeSourcePermission(Binder.getCallingUid(), Binder.getCallingPid());
+        }
+        if (ws != null && ws.size() == 0) {
+            ws = null;
+        }
+        if (ws == null) {
+            ws = new WorkSource(Binder.getCallingUid());
+        }
+        WifiLock wifiLock = new WifiLock(lockMode, tag, binder, ws);
         synchronized (mLocks) {
             return acquireWifiLockLocked(wifiLock);
         }
     }
 
+    private void noteAcquireWifiLock(WifiLock wifiLock) throws RemoteException {
+        switch(wifiLock.mMode) {
+            case WifiManager.WIFI_MODE_FULL:
+                mBatteryStats.noteFullWifiLockAcquiredFromSource(wifiLock.mWorkSource);
+                break;
+            case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
+                /* Treat high power as a full lock for battery stats */
+                mBatteryStats.noteFullWifiLockAcquiredFromSource(wifiLock.mWorkSource);
+                break;
+            case WifiManager.WIFI_MODE_SCAN_ONLY:
+                mBatteryStats.noteScanWifiLockAcquiredFromSource(wifiLock.mWorkSource);
+                break;
+        }
+    }
+
+    private void noteReleaseWifiLock(WifiLock wifiLock) throws RemoteException {
+        switch(wifiLock.mMode) {
+            case WifiManager.WIFI_MODE_FULL:
+                mBatteryStats.noteFullWifiLockReleasedFromSource(wifiLock.mWorkSource);
+                break;
+            case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
+                /* Treat high power as a full lock for battery stats */
+                mBatteryStats.noteFullWifiLockReleasedFromSource(wifiLock.mWorkSource);
+                break;
+            case WifiManager.WIFI_MODE_SCAN_ONLY:
+                mBatteryStats.noteScanWifiLockReleasedFromSource(wifiLock.mWorkSource);
+                break;
+        }
+    }
+
     private boolean acquireWifiLockLocked(WifiLock wifiLock) {
         Slog.d(TAG, "acquireWifiLockLocked: " + wifiLock);
 
         mLocks.addLock(wifiLock);
 
-        int uid = Binder.getCallingUid();
         long ident = Binder.clearCallingIdentity();
         try {
+            noteAcquireWifiLock(wifiLock);
             switch(wifiLock.mMode) {
             case WifiManager.WIFI_MODE_FULL:
                 ++mFullLocksAcquired;
-                mBatteryStats.noteFullWifiLockAcquired(uid);
                 break;
             case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
                 ++mFullHighPerfLocksAcquired;
-                /* Treat high power as a full lock for battery stats */
-                mBatteryStats.noteFullWifiLockAcquired(uid);
                 break;
-
             case WifiManager.WIFI_MODE_SCAN_ONLY:
                 ++mScanLocksAcquired;
-                mBatteryStats.noteScanWifiLockAcquired(uid);
                 break;
             }
         } catch (RemoteException e) {
@@ -2155,10 +2227,41 @@
             Binder.restoreCallingIdentity(ident);
         }
 
+        // Be aggressive about adding new locks into the accounted state...
+        // we want to over-report rather than under-report.
+        reportStartWorkSource();
+
         updateWifiState();
         return true;
     }
 
+    public void updateWifiLockWorkSource(IBinder lock, WorkSource ws) {
+        int uid = Binder.getCallingUid();
+        int pid = Binder.getCallingPid();
+        if (ws != null && ws.size() == 0) {
+            ws = null;
+        }
+        if (ws != null) {
+            enforceWakeSourcePermission(uid, pid);
+        }
+        long ident = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLocks) {
+                int index = mLocks.findLockByBinder(lock);
+                if (index < 0) {
+                    throw new IllegalArgumentException("Wifi lock not active");
+                }
+                WifiLock wl = mLocks.mList.get(index);
+                noteReleaseWifiLock(wl);
+                wl.mWorkSource = ws != null ? new WorkSource(ws) : new WorkSource(uid);
+                noteAcquireWifiLock(wl);
+            }
+        } catch (RemoteException e) {
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
     public boolean releaseWifiLock(IBinder lock) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
         synchronized (mLocks) {
@@ -2176,21 +2279,18 @@
         hadLock = (wifiLock != null);
 
         if (hadLock) {
-            int uid = Binder.getCallingUid();
             long ident = Binder.clearCallingIdentity();
             try {
+                noteAcquireWifiLock(wifiLock);
                 switch(wifiLock.mMode) {
                     case WifiManager.WIFI_MODE_FULL:
                         ++mFullLocksReleased;
-                        mBatteryStats.noteFullWifiLockReleased(uid);
                         break;
                     case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
                         ++mFullHighPerfLocksReleased;
-                        mBatteryStats.noteFullWifiLockReleased(uid);
                         break;
                     case WifiManager.WIFI_MODE_SCAN_ONLY:
                         ++mScanLocksReleased;
-                        mBatteryStats.noteScanWifiLockReleased(uid);
                         break;
                 }
             } catch (RemoteException e) {
@@ -2208,12 +2308,14 @@
         String mTag;
         int mMode;
         IBinder mBinder;
+        WorkSource mWorkSource;
 
-        DeathRecipient(int mode, String tag, IBinder binder) {
+        DeathRecipient(int mode, String tag, IBinder binder, WorkSource ws) {
             super();
             mTag = tag;
             mMode = mode;
             mBinder = binder;
+            mWorkSource = ws;
             try {
                 mBinder.linkToDeath(this, 0);
             } catch (RemoteException e) {
@@ -2228,7 +2330,7 @@
 
     private class Multicaster extends DeathRecipient {
         Multicaster(String tag, IBinder binder) {
-            super(Binder.getCallingUid(), tag, binder);
+            super(Binder.getCallingUid(), tag, binder, null);
         }
 
         public void binderDied() {
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 27d875e..d7a1ac25 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -5096,61 +5096,39 @@
             }
         }
         
-        /* Notifies the window manager about an input channel that is not responding.
+        /* Notifies the window manager about an application that is not responding.
          * Returns a new timeout to continue waiting in nanoseconds, or 0 to abort dispatch.
          * 
          * Called by the InputManager.
          */
-        public long notifyInputChannelANR(InputChannel inputChannel) {
-            AppWindowToken token;
-            synchronized (mWindowMap) {
-                WindowState windowState = getWindowStateForInputChannelLocked(inputChannel);
-                if (windowState == null) {
-                    return 0; // window is unknown, abort dispatching
+        public long notifyANR(Object token, InputChannel inputChannel) {
+            AppWindowToken appWindowToken = null;
+            if (inputChannel != null) {
+                synchronized (mWindowMap) {
+                    WindowState windowState = getWindowStateForInputChannelLocked(inputChannel);
+                    if (windowState != null) {
+                        Slog.i(TAG, "Input event dispatching timed out sending to "
+                                + windowState.mAttrs.getTitle());
+                        appWindowToken = windowState.mAppToken;
+                    }
                 }
-                
-                Slog.i(TAG, "Input event dispatching timed out sending to "
-                        + windowState.mAttrs.getTitle());
-                token = windowState.mAppToken;
             }
             
-            return notifyANRInternal(token);
-        }
-    
-        /* Notifies the window manager about an input channel spontaneously recovering from ANR
-         * by successfully delivering the event that originally timed out.
-         * 
-         * Called by the InputManager.
-         */
-        public void notifyInputChannelRecoveredFromANR(InputChannel inputChannel) {
-            // Nothing to do just now.
-            // Just wait for the user to dismiss the ANR dialog.
-        }
-        
-        /* Notifies the window manager about an application that is not responding
-         * in general rather than with respect to a particular input channel.
-         * Returns a new timeout to continue waiting in nanoseconds, or 0 to abort dispatch.
-         * 
-         * Called by the InputManager.
-         */
-        public long notifyANR(Object token) {
-            AppWindowToken appWindowToken = (AppWindowToken) token;
+            if (appWindowToken == null && token != null) {
+                appWindowToken = (AppWindowToken) token;
+                Slog.i(TAG, "Input event dispatching timed out sending to application "
+                        + appWindowToken.stringName);
+            }
 
-            Slog.i(TAG, "Input event dispatching timed out sending to application "
-                    + appWindowToken.stringName);
-            return notifyANRInternal(appWindowToken);
-        }
-        
-        private long notifyANRInternal(AppWindowToken token) {
-            if (token != null && token.appToken != null) {
+            if (appWindowToken != null && appWindowToken.appToken != null) {
                 try {
                     // Notify the activity manager about the timeout and let it decide whether
                     // to abort dispatching or keep waiting.
-                    boolean abort = token.appToken.keyDispatchingTimedOut();
+                    boolean abort = appWindowToken.appToken.keyDispatchingTimedOut();
                     if (! abort) {
                         // The activity manager declined to abort dispatching.
                         // Wait a bit longer and timeout again later.
-                        return token.inputDispatchingTimeoutNanos;
+                        return appWindowToken.inputDispatchingTimeoutNanos;
                     }
                 } catch (RemoteException ex) {
                 }
@@ -5203,13 +5181,16 @@
                 // Add a window to our list of input windows.
                 final InputWindow inputWindow = mTempInputWindows.add();
                 inputWindow.inputChannel = child.mInputChannel;
+                inputWindow.name = child.toString();
                 inputWindow.layoutParamsFlags = flags;
                 inputWindow.layoutParamsType = type;
                 inputWindow.dispatchingTimeoutNanos = child.getInputDispatchingTimeoutNanos();
                 inputWindow.visible = isVisible;
+                inputWindow.canReceiveKeys = child.canReceiveKeys();
                 inputWindow.hasFocus = hasFocus;
                 inputWindow.hasWallpaper = hasWallpaper;
                 inputWindow.paused = child.mAppToken != null ? child.mAppToken.paused : false;
+                inputWindow.layer = child.mLayer;
                 inputWindow.ownerPid = child.mSession.mPid;
                 inputWindow.ownerUid = child.mSession.mUid;
                 
@@ -5302,23 +5283,6 @@
 
             if (newWindow != mInputFocus) {
                 if (newWindow != null && newWindow.canReceiveKeys()) {
-                    // If the new input focus is an error window or appears above the current
-                    // input focus, preempt any pending synchronous dispatch so that we can
-                    // start delivering events to the new input focus as soon as possible.
-                    if ((newWindow.mAttrs.flags & FLAG_SYSTEM_ERROR) != 0) {
-                        if (DEBUG_INPUT) {
-                            Slog.v(TAG, "New SYSTEM_ERROR window; resetting state");
-                        }
-                        preemptInputDispatchLw();
-                    } else if (mInputFocus != null && newWindow.mLayer > mInputFocus.mLayer) {
-                        if (DEBUG_INPUT) {
-                            Slog.v(TAG, "Transferring focus to new window at higher layer: "
-                                    + "old win layer=" + mInputFocus.mLayer
-                                    + ", new win layer=" + newWindow.mLayer);
-                        }
-                        preemptInputDispatchLw();
-                    }
-                    
                     // Displaying a window implicitly causes dispatching to be unpaused.
                     // This is to protect against bugs if someone pauses dispatching but
                     // forgets to resume.
@@ -5330,14 +5294,6 @@
             }
         }
         
-        /* Tells the dispatcher to stop waiting for its current synchronous event targets.
-         * Essentially, just makes those dispatches asynchronous so a new dispatch cycle
-         * can begin.
-         */
-        private void preemptInputDispatchLw() {
-            mInputManager.preemptInputDispatch();
-        }
-        
         public void setFocusedAppLw(AppWindowToken newApp) {
             // Focused app has changed.
             if (newApp == null) {
@@ -8360,6 +8316,11 @@
             return;
         }
         
+        if (mDisplay == null) {
+            // Not yet initialized, nothing to do.
+            return;
+        }
+
         boolean recoveringMemory = false;
         if (mForceRemoves != null) {
             recoveringMemory = true;
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 2cdf31e..4f0d2d5 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -561,6 +561,11 @@
     BroadcastRecord mPendingBroadcast = null;
 
     /**
+     * The receiver index that is pending, to restart the broadcast if needed.
+     */
+    int mPendingBroadcastRecvIndex;
+
+    /**
      * Keeps track of all IIntentReceivers that have been registered for
      * broadcasts.  Hash keys are the receiver IBinder, hash value is
      * a ReceiverList.
@@ -747,6 +752,7 @@
     ComponentName mTopComponent;
     String mTopAction;
     String mTopData;
+    boolean mProcessesReady = false;
     boolean mSystemReady = false;
     boolean mBooting = false;
     boolean mWaitingUpdate = false;
@@ -964,7 +970,11 @@
                         return;
                     }
                     
-                    broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
+                    Intent intent = new Intent("android.intent.action.ANR");
+                    if (!mProcessesReady) {
+                        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+                    }
+                    broadcastIntentLocked(null, null, intent,
                             null, null, 0, null, null, null,
                             false, false, MY_PID, Process.SYSTEM_UID);
 
@@ -1051,7 +1061,7 @@
                 // Only process broadcast timeouts if the system is ready. That way
                 // PRE_BOOT_COMPLETED broadcasts can't timeout as they are intended
                 // to do heavy lifting for system up
-                if (mSystemReady) {
+                if (mProcessesReady) {
                     broadcastTimeout();
                 }
             } break;
@@ -1383,7 +1393,7 @@
         mBatteryStatsService = new BatteryStatsService(new File(
                 systemDir, "batterystats.bin").toString());
         mBatteryStatsService.getActiveStatistics().readLocked();
-        mBatteryStatsService.getActiveStatistics().writeLocked();
+        mBatteryStatsService.getActiveStatistics().writeAsyncLocked();
         mOnBattery = mBatteryStatsService.getActiveStatistics().getIsOnBattery();
         mBatteryStatsService.getActiveStatistics().setCallback(this);
         
@@ -1536,7 +1546,7 @@
 
                 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
                     mLastWriteTime = now;
-                    mBatteryStatsService.getActiveStatistics().writeLocked();
+                    mBatteryStatsService.getActiveStatistics().writeAsyncLocked();
                 }
             }
         }
@@ -1717,10 +1727,12 @@
             if (!knownToBeDead || app.thread == null) {
                 // We already have the app running, or are waiting for it to
                 // come up (we have a pid but not yet its thread), so keep it.
+                if (DEBUG_PROCESSES) Slog.v(TAG, "App already running: " + app);
                 return app;
             } else {
                 // An application record is attached to a previous process,
                 // clean it up now.
+                if (DEBUG_PROCESSES) Slog.v(TAG, "App died: " + app);
                 handleAppDiedLocked(app, true);
             }
         }
@@ -1732,6 +1744,8 @@
             // If we are in the background, then check to see if this process
             // is bad.  If so, we will just silently fail.
             if (mBadProcesses.get(info.processName, info.uid) != null) {
+                if (DEBUG_PROCESSES) Slog.v(TAG, "Bad process: " + info.uid
+                        + "/" + info.processName);
                 return null;
             }
         } else {
@@ -1739,6 +1753,8 @@
             // crash count so that we won't make it bad until they see at
             // least one crash dialog again, and make the process good again
             // if it had been bad.
+            if (DEBUG_PROCESSES) Slog.v(TAG, "Clearing bad process: " + info.uid
+                    + "/" + info.processName);
             mProcessCrashTimes.remove(info.processName, info.uid);
             if (mBadProcesses.get(info.processName, info.uid) != null) {
                 EventLog.writeEvent(EventLogTags.AM_PROC_GOOD, info.uid,
@@ -1760,12 +1776,13 @@
 
         // If the system is not ready yet, then hold off on starting this
         // process until it is.
-        if (!mSystemReady
+        if (!mProcessesReady
                 && !isAllowedWhileBooting(info)
                 && !allowWhileBooting) {
             if (!mProcessesOnHold.contains(app)) {
                 mProcessesOnHold.add(app);
             }
+            if (DEBUG_PROCESSES) Slog.v(TAG, "System not ready, putting on hold: " + app);
             return app;
         }
 
@@ -1787,6 +1804,8 @@
             app.pid = 0;
         }
 
+        if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG,
+                "startProcessLocked removing on hold: " + app);
         mProcessesOnHold.remove(app);
 
         updateCpuStats();
@@ -3040,11 +3059,8 @@
                 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
                         Uri.fromParts("package", packageName, null));
                 intent.putExtra(Intent.EXTRA_UID, pkgUid);
-                synchronized (this) {
-                    broadcastIntentLocked(null, null, intent,
-                            null, null, 0, null, null, null,
-                            false, false, MY_PID, Process.SYSTEM_UID);
-                }
+                broadcastIntentInPackage("android", Process.SYSTEM_UID, intent,
+                        null, null, 0, null, null, null, false, false);
             } catch (RemoteException e) {
             }
         } finally {
@@ -3148,6 +3164,7 @@
 
     public void closeSystemDialogs(String reason) {
         Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
         if (reason != null) {
             intent.putExtra("reason", reason);
         }
@@ -3225,6 +3242,9 @@
         forceStopPackageLocked(packageName, uid, false, false, true);
         Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
                 Uri.fromParts("package", packageName, null));
+        if (!mProcessesReady) {
+            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+        }
         intent.putExtra(Intent.EXTRA_UID, uid);
         broadcastIntentLocked(null, null, intent,
                 null, null, 0, null, null, null,
@@ -3427,6 +3447,8 @@
             }
             if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
                 Slog.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
+                mPendingBroadcast.state = BroadcastRecord.IDLE;
+                mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;
                 mPendingBroadcast = null;
                 scheduleBroadcastsLocked();
             }
@@ -3502,7 +3524,7 @@
 
         mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
 
-        boolean normalMode = mSystemReady || isAllowedWhileBooting(app.info);
+        boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
         List providers = normalMode ? generateApplicationProvidersLocked(app) : null;
 
         if (!normalMode) {
@@ -3561,6 +3583,8 @@
 
         // Remove this record from the list of starting applications.
         mPersistentStartingProcesses.remove(app);
+        if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG,
+                "Attach application locked removing on hold: " + app);
         mProcessesOnHold.remove(app);
 
         boolean badApp = false;
@@ -3702,7 +3726,9 @@
                 ArrayList<ProcessRecord> procs =
                     new ArrayList<ProcessRecord>(mProcessesOnHold);
                 for (int ip=0; ip<NP; ip++) {
-                    this.startProcessLocked(procs.get(ip), "on-hold", null);
+                    if (DEBUG_PROCESSES) Slog.v(TAG, "Starting process on hold: "
+                            + procs.get(ip));
+                    startProcessLocked(procs.get(ip), "on-hold", null);
                 }
             }
             
@@ -5253,7 +5279,7 @@
                     throw new SecurityException(msg);
                 }
 
-                if (!mSystemReady && !mDidUpdate && !mWaitingUpdate
+                if (!mProcessesReady && !mDidUpdate && !mWaitingUpdate
                         && !cpi.processName.equals("system")) {
                     // If this content provider does not run in the system
                     // process, and the system is not yet ready to run other
@@ -5985,12 +6011,18 @@
                             finisher = new IIntentReceiver.Stub() {
                                 public void performReceive(Intent intent, int resultCode,
                                         String data, Bundle extras, boolean ordered,
-                                        boolean sticky)
-                                        throws RemoteException {
-                                    synchronized (ActivityManagerService.this) {
-                                        mDidUpdate = true;
-                                    }
-                                    systemReady(goingCallback);
+                                        boolean sticky) {
+                                    // The raw IIntentReceiver interface is called
+                                    // with the AM lock held, so redispatch to
+                                    // execute our code without the lock.
+                                    mHandler.post(new Runnable() {
+                                        public void run() {
+                                            synchronized (ActivityManagerService.this) {
+                                                mDidUpdate = true;
+                                            }
+                                            systemReady(goingCallback);
+                                        }
+                                    });
                                 }
                             };
                         }
@@ -6034,6 +6066,11 @@
                     Slog.i(TAG, "Removing system update proc: " + proc);
                     removeProcessLocked(proc, true);
                 }
+
+                // Now that we have cleaned up any update processes, we
+                // are ready to start launching real processes and know that
+                // we won't trample on them any more.
+                mProcessesReady = true;
             }
         }
         
@@ -7277,8 +7314,9 @@
         if (dumpAll) {
             pw.println("  Total persistent processes: " + numPers);
             pw.println("  mStartRunning=" + mStartRunning
-                    + " mSystemReady=" + mSystemReady
-                    + " mBooting=" + mBooting
+                    + " mProcessesReady=" + mProcessesReady
+                    + " mSystemReady=" + mSystemReady);
+            pw.println("  mBooting=" + mBooting
                     + " mBooted=" + mBooted
                     + " mFactoryTest=" + mFactoryTest);
             pw.println("  mGoingToSleep=" + mMainStack.mGoingToSleep);
@@ -8092,6 +8130,8 @@
                 restart = true;
             }
         }
+        if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG,
+                "Clean-up removing on hold: " + app);
         mProcessesOnHold.remove(app);
 
         if (app == mHomeProcess) {
@@ -10112,7 +10152,7 @@
             }
             boolean replaced = false;
             if (replacePending) {
-                for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
+                for (int i=mOrderedBroadcasts.size()-1; i>0; i--) {
                     if (intent.filterEquals(mOrderedBroadcasts.get(i).intent)) {
                         if (DEBUG_BROADCAST) Slog.v(TAG,
                                 "***** DROPPING ORDERED: " + intent);
@@ -10131,35 +10171,41 @@
         return BROADCAST_SUCCESS;
     }
 
-    public final int broadcastIntent(IApplicationThread caller,
-            Intent intent, String resolvedType, IIntentReceiver resultTo,
-            int resultCode, String resultData, Bundle map,
-            String requiredPermission, boolean serialized, boolean sticky) {
+    final Intent verifyBroadcastLocked(Intent intent) {
         // Refuse possible leaked file descriptors
         if (intent != null && intent.hasFileDescriptors() == true) {
             throw new IllegalArgumentException("File descriptors passed in Intent");
         }
 
+        int flags = intent.getFlags();
+
+        if (!mProcessesReady) {
+            // if the caller really truly claims to know what they're doing, go
+            // ahead and allow the broadcast without launching any receivers
+            if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
+                intent = new Intent(intent);
+                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+            } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
+                Slog.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
+                        + " before boot completion");
+                throw new IllegalStateException("Cannot broadcast before boot completed");
+            }
+        }
+
+        if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
+            throw new IllegalArgumentException(
+                    "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
+        }
+
+        return intent;
+    }
+
+    public final int broadcastIntent(IApplicationThread caller,
+            Intent intent, String resolvedType, IIntentReceiver resultTo,
+            int resultCode, String resultData, Bundle map,
+            String requiredPermission, boolean serialized, boolean sticky) {
         synchronized(this) {
-            int flags = intent.getFlags();
-            
-            if (!mSystemReady) {
-                // if the caller really truly claims to know what they're doing, go
-                // ahead and allow the broadcast without launching any receivers
-                if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
-                    intent = new Intent(intent);
-                    intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-                } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
-                    Slog.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
-                            + " before boot completion");
-                    throw new IllegalStateException("Cannot broadcast before boot completed");
-                }
-            }
-            
-            if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
-                throw new IllegalArgumentException(
-                        "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
-            }
+            intent = verifyBroadcastLocked(intent);
             
             final ProcessRecord callerApp = getRecordForAppLocked(caller);
             final int callingPid = Binder.getCallingPid();
@@ -10180,6 +10226,8 @@
             int resultCode, String resultData, Bundle map,
             String requiredPermission, boolean serialized, boolean sticky) {
         synchronized(this) {
+            intent = verifyBroadcastLocked(intent);
+
             final long origId = Binder.clearCallingIdentity();
             int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
                     resultTo, resultCode, resultData, map, requiredPermission,
@@ -10393,6 +10441,8 @@
 
     private final void processCurBroadcastLocked(BroadcastRecord r,
             ProcessRecord app) throws RemoteException {
+        if (DEBUG_BROADCAST)  Slog.v(TAG,
+                "Process cur broadcast " + r + " for app " + app);
         if (app.thread == null) {
             throw new RemoteException();
         }
@@ -10412,9 +10462,13 @@
             ensurePackageDexOpt(r.intent.getComponent().getPackageName());
             app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
                     r.resultCode, r.resultData, r.resultExtras, r.ordered);
+            if (DEBUG_BROADCAST)  Slog.v(TAG,
+                    "Process cur broadcast " + r + " DELIVERED for app " + app);
             started = true;
         } finally {
             if (!started) {
+                if (DEBUG_BROADCAST)  Slog.v(TAG,
+                        "Process cur broadcast " + r + ": NOT STARTED!");
                 r.receiver = null;
                 r.curApp = null;
                 app.curReceiver = null;
@@ -10579,6 +10633,8 @@
                 } else {
                     Slog.w(TAG, "pending app " + mPendingBroadcast.curApp
                             + " died before responding to broadcast");
+                    mPendingBroadcast.state = BroadcastRecord.IDLE;
+                    mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;
                     mPendingBroadcast = null;
                 }
             }
@@ -10609,7 +10665,7 @@
                 // one time heavy lifting after system upgrades and can take
                 // significant amounts of time.
                 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
-                if (mSystemReady && r.dispatchTime > 0) {
+                if (mProcessesReady && r.dispatchTime > 0) {
                     long now = SystemClock.uptimeMillis();
                     if ((numReceivers > 0) &&
                             (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
@@ -10680,7 +10736,7 @@
                 if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing ordered broadcast "
                         + r);
                 if (DEBUG_BROADCAST) Slog.v(TAG,
-                        "Submitting BROADCAST_TIMEOUT_MSG for "
+                        "Submitting BROADCAST_TIMEOUT_MSG for " + r + " at "
                         + (r.receiverTime + BROADCAST_TIMEOUT));
                 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
                 mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT);
@@ -10748,10 +10804,15 @@
             }
             if (r.curApp != null && r.curApp.crashing) {
                 // If the target process is crashing, just skip it.
+                if (DEBUG_BROADCAST)  Slog.v(TAG,
+                        "Skipping deliver ordered " + r + " to " + r.curApp
+                        + ": process crashing");
                 skip = true;
             }
 
             if (skip) {
+                if (DEBUG_BROADCAST)  Slog.v(TAG,
+                        "Skipping delivery of ordered " + r + " for whatever reason");
                 r.receiver = null;
                 r.curFilter = null;
                 r.state = BroadcastRecord.IDLE;
@@ -10783,6 +10844,8 @@
             }
 
             // Not running -- get it started, to be executed when the app comes up.
+            if (DEBUG_BROADCAST)  Slog.v(TAG,
+                    "Need to start app " + targetProcess + " for broadcast " + r);
             if ((r.curApp=startProcessLocked(targetProcess,
                     info.activityInfo.applicationInfo, true,
                     r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
@@ -10804,6 +10867,7 @@
             }
 
             mPendingBroadcast = r;
+            mPendingBroadcastRecvIndex = recIdx;
         }
     }
 
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index a0c21dd..a4497d6 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -1104,26 +1104,30 @@
         // Okay we are now going to start a switch, to 'next'.  We may first
         // have to pause the current activity, but this is an important point
         // where we have decided to go to 'next' so keep track of that.
-        if (mLastStartedActivity != null) {
-            long now = SystemClock.uptimeMillis();
-            final boolean inTime = mLastStartedActivity.startTime != 0
-                    && (mLastStartedActivity.startTime + START_WARN_TIME) >= now;
-            final int lastUid = mLastStartedActivity.info.applicationInfo.uid;
-            final int nextUid = next.info.applicationInfo.uid;
-            if (inTime && lastUid != nextUid
-                    && lastUid != next.launchedFromUid
-                    && mService.checkPermission(
-                            android.Manifest.permission.STOP_APP_SWITCHES,
-                            -1, next.launchedFromUid)
-                    != PackageManager.PERMISSION_GRANTED) {
-                mService.showLaunchWarningLocked(mLastStartedActivity, next);
+        // XXX "App Redirected" dialog is getting too many false positives
+        // at this point, so turn off for now.
+        if (false) {
+            if (mLastStartedActivity != null && !mLastStartedActivity.finishing) {
+                long now = SystemClock.uptimeMillis();
+                final boolean inTime = mLastStartedActivity.startTime != 0
+                        && (mLastStartedActivity.startTime + START_WARN_TIME) >= now;
+                final int lastUid = mLastStartedActivity.info.applicationInfo.uid;
+                final int nextUid = next.info.applicationInfo.uid;
+                if (inTime && lastUid != nextUid
+                        && lastUid != next.launchedFromUid
+                        && mService.checkPermission(
+                                android.Manifest.permission.STOP_APP_SWITCHES,
+                                -1, next.launchedFromUid)
+                        != PackageManager.PERMISSION_GRANTED) {
+                    mService.showLaunchWarningLocked(mLastStartedActivity, next);
+                } else {
+                    next.startTime = now;
+                    mLastStartedActivity = next;
+                }
             } else {
-                next.startTime = now;
+                next.startTime = SystemClock.uptimeMillis();
                 mLastStartedActivity = next;
             }
-        } else {
-            next.startTime = SystemClock.uptimeMillis();
-            mLastStartedActivity = next;
         }
         
         // We need to start pausing the current activity so the top one
diff --git a/services/java/com/android/server/am/BatteryStatsService.java b/services/java/com/android/server/am/BatteryStatsService.java
index 7314e04..73a5435 100644
--- a/services/java/com/android/server/am/BatteryStatsService.java
+++ b/services/java/com/android/server/am/BatteryStatsService.java
@@ -23,6 +23,7 @@
 import android.os.Parcel;
 import android.os.Process;
 import android.os.ServiceManager;
+import android.os.WorkSource;
 import android.telephony.SignalStrength;
 import android.util.Slog;
 
@@ -107,6 +108,20 @@
         }
     }
 
+    public void noteStartWakelockFromSource(WorkSource ws, int pid, String name, int type) {
+        enforceCallingPermission();
+        synchronized (mStats) {
+            mStats.noteStartWakeFromSourceLocked(ws, pid, name, type);
+        }
+    }
+
+    public void noteStopWakelockFromSource(WorkSource ws, int pid, String name, int type) {
+        enforceCallingPermission();
+        synchronized (mStats) {
+            mStats.noteStopWakeFromSourceLocked(ws, pid, name, type);
+        }
+    }
+
     public void noteStartSensor(int uid, int sensor) {
         enforceCallingPermission();
         synchronized (mStats) {
@@ -203,17 +218,17 @@
         }
     }
 
-    public void noteWifiOn(int uid) {
+    public void noteWifiOn() {
         enforceCallingPermission();
         synchronized (mStats) {
-            mStats.noteWifiOnLocked(uid);
+            mStats.noteWifiOnLocked();
         }
     }
     
-    public void noteWifiOff(int uid) {
+    public void noteWifiOff() {
         enforceCallingPermission();
         synchronized (mStats) {
-            mStats.noteWifiOffLocked(uid);
+            mStats.noteWifiOffLocked();
         }
     }
 
@@ -245,17 +260,24 @@
         }
     }
 
-    public void noteWifiRunning() {
+    public void noteWifiRunning(WorkSource ws) {
         enforceCallingPermission();
         synchronized (mStats) {
-            mStats.noteWifiRunningLocked();
+            mStats.noteWifiRunningLocked(ws);
         }
     }
 
-    public void noteWifiStopped() {
+    public void noteWifiRunningChanged(WorkSource oldWs, WorkSource newWs) {
         enforceCallingPermission();
         synchronized (mStats) {
-            mStats.noteWifiStoppedLocked();
+            mStats.noteWifiRunningChangedLocked(oldWs, newWs);
+        }
+    }
+
+    public void noteWifiStopped(WorkSource ws) {
+        enforceCallingPermission();
+        synchronized (mStats) {
+            mStats.noteWifiStoppedLocked(ws);
         }
     }
 
@@ -317,6 +339,48 @@
         }
     }
 
+    public void noteFullWifiLockAcquiredFromSource(WorkSource ws) {
+        enforceCallingPermission();
+        synchronized (mStats) {
+            mStats.noteFullWifiLockAcquiredFromSourceLocked(ws);
+        }
+    }
+
+    public void noteFullWifiLockReleasedFromSource(WorkSource ws) {
+        enforceCallingPermission();
+        synchronized (mStats) {
+            mStats.noteFullWifiLockReleasedFromSourceLocked(ws);
+        }
+    }
+
+    public void noteScanWifiLockAcquiredFromSource(WorkSource ws) {
+        enforceCallingPermission();
+        synchronized (mStats) {
+            mStats.noteScanWifiLockAcquiredFromSourceLocked(ws);
+        }
+    }
+
+    public void noteScanWifiLockReleasedFromSource(WorkSource ws) {
+        enforceCallingPermission();
+        synchronized (mStats) {
+            mStats.noteScanWifiLockReleasedFromSourceLocked(ws);
+        }
+    }
+
+    public void noteWifiMulticastEnabledFromSource(WorkSource ws) {
+        enforceCallingPermission();
+        synchronized (mStats) {
+            mStats.noteWifiMulticastEnabledFromSourceLocked(ws);
+        }
+    }
+
+    public void noteWifiMulticastDisabledFromSource(WorkSource ws) {
+        enforceCallingPermission();
+        synchronized (mStats) {
+            mStats.noteWifiMulticastDisabledFromSourceLocked(ws);
+        }
+    }
+
     public boolean isOnBattery() {
         return mStats.isOnBattery();
     }
diff --git a/services/java/com/android/server/am/UriPermission.java b/services/java/com/android/server/am/UriPermission.java
index c95546e..0cb6943 100644
--- a/services/java/com/android/server/am/UriPermission.java
+++ b/services/java/com/android/server/am/UriPermission.java
@@ -45,8 +45,8 @@
         uri = _uri;
     }
     
-    void clearModes(int modeFlags) {
-        if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
+    void clearModes(int modeFlagsToClear) {
+        if ((modeFlagsToClear&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
             globalModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
             modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
             if (readOwners.size() > 0) {
@@ -56,7 +56,7 @@
                 readOwners.clear();
             }
         }
-        if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
+        if ((modeFlagsToClear&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
             globalModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
             modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
             if (readOwners.size() > 0) {
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
index eb0a8a9..1bc5e4b 100644
--- a/services/java/com/android/server/connectivity/Tethering.java
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -35,6 +35,7 @@
 import android.net.NetworkUtils;
 import android.os.Binder;
 import android.os.Environment;
+import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.INetworkManagementService;
@@ -110,6 +111,14 @@
     private boolean mUsbMassStorageOff;  // track the status of USB Mass Storage
     private boolean mUsbConnected;       // track the status of USB connection
 
+    // mUsbHandler message
+    static final int USB_STATE_CHANGE = 1;
+    static final int USB_DISCONNECTED = 0;
+    static final int USB_CONNECTED = 1;
+
+    // Time to delay before processing USB disconnect events
+    static final long USB_DISCONNECT_DELAY = 1000;
+
     public Tethering(Context context, Looper looper) {
         Log.d(TAG, "Tethering starting");
         mContext = context;
@@ -421,12 +430,25 @@
         }
     }
 
+    private Handler mUsbHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            mUsbConnected = (msg.arg1 == USB_CONNECTED);
+            updateUsbStatus();
+        }
+    };
+
     private class StateReceiver extends BroadcastReceiver {
         public void onReceive(Context content, Intent intent) {
             String action = intent.getAction();
             if (action.equals(Usb.ACTION_USB_STATE)) {
-                mUsbConnected = intent.getExtras().getBoolean(Usb.USB_CONNECTED);
-                updateUsbStatus();
+                // process connect events immediately, but delay handling disconnects
+                // to debounce USB configuration changes
+                boolean connected = intent.getExtras().getBoolean(Usb.USB_CONNECTED);
+                Message msg = Message.obtain(mUsbHandler, USB_STATE_CHANGE,
+                        (connected ? USB_CONNECTED : USB_DISCONNECTED), 0);
+                mUsbHandler.removeMessages(USB_STATE_CHANGE);
+                mUsbHandler.sendMessageDelayed(msg, connected ? 0 : USB_DISCONNECT_DELAY);
             } else if (action.equals(Intent.ACTION_MEDIA_SHARED)) {
                 mUsbMassStorageOff = false;
                 updateUsbStatus();
diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.java
index c1165c7..3bf6ee4 100755
--- a/services/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/java/com/android/server/location/GpsLocationProvider.java
@@ -44,6 +44,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
+import android.os.WorkSource;
 import android.provider.Settings;
 import android.util.Log;
 import android.util.SparseIntArray;
@@ -736,7 +737,7 @@
         startNavigating(true);
     }
 
-    public void setMinTime(long minTime) {
+    public void setMinTime(long minTime, WorkSource ws) {
         if (DEBUG) Log.d(TAG, "setMinTime " + minTime);
         
         if (minTime >= 0) {
@@ -779,7 +780,7 @@
     public void addListener(int uid) {
         synchronized (mWakeLock) {
             mPendingListenerMessages++;
-           mWakeLock.acquire();
+            mWakeLock.acquire();
             Message m = Message.obtain(mHandler, ADD_LISTENER);
             m.arg1 = uid;
             mHandler.sendMessage(m);
diff --git a/services/java/com/android/server/location/LocationProviderInterface.java b/services/java/com/android/server/location/LocationProviderInterface.java
index 084ab81..858a582 100644
--- a/services/java/com/android/server/location/LocationProviderInterface.java
+++ b/services/java/com/android/server/location/LocationProviderInterface.java
@@ -20,6 +20,7 @@
 import android.location.Location;
 import android.net.NetworkInfo;
 import android.os.Bundle;
+import android.os.WorkSource;
 
 /**
  * Location Manager's interface for location providers.
@@ -47,7 +48,7 @@
     /* returns false if single shot is not supported */
     boolean requestSingleShotFix();
     String getInternalState();
-    void setMinTime(long minTime);
+    void setMinTime(long minTime, WorkSource ws);
     void updateNetworkState(int state, NetworkInfo info);
     void updateLocation(Location location);
     boolean sendExtraCommand(String command, Bundle extras);
diff --git a/services/java/com/android/server/location/LocationProviderProxy.java b/services/java/com/android/server/location/LocationProviderProxy.java
index 24d7737..7dc9920 100644
--- a/services/java/com/android/server/location/LocationProviderProxy.java
+++ b/services/java/com/android/server/location/LocationProviderProxy.java
@@ -29,6 +29,7 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.SystemClock;
+import android.os.WorkSource;
 import android.util.Log;
 
 import com.android.internal.location.DummyLocationProvider;
@@ -52,6 +53,7 @@
     private boolean mLocationTracking = false;
     private boolean mEnabled = false;
     private long mMinTime = -1;
+    private WorkSource mMinTimeSource = new WorkSource();
     private int mNetworkState;
     private NetworkInfo mNetworkInfo;
 
@@ -122,7 +124,7 @@
                     provider.enableLocationTracking(true);
                 }
                 if (mMinTime >= 0) {
-                    provider.setMinTime(mMinTime);
+                    provider.setMinTime(mMinTime, mMinTimeSource);
                 }
                 if (mNetworkInfo != null) {
                     provider.updateNetworkState(mNetworkState, mNetworkInfo);
@@ -318,6 +320,7 @@
         mLocationTracking = enable;
         if (!enable) {
             mMinTime = -1;
+            mMinTimeSource.clear();
         }
         ILocationProvider provider;
         synchronized (mServiceConnection) {
@@ -339,15 +342,16 @@
         return mMinTime;
     }
 
-    public void setMinTime(long minTime) {
-       mMinTime = minTime;
+    public void setMinTime(long minTime, WorkSource ws) {
+        mMinTime = minTime;
+        mMinTimeSource.set(ws);
         ILocationProvider provider;
         synchronized (mServiceConnection) {
             provider = mProvider;
         }
         if (provider != null) {
             try {
-                provider.setMinTime(minTime);
+                provider.setMinTime(minTime, ws);
             } catch (RemoteException e) {
             }
         }
diff --git a/services/java/com/android/server/location/MockProvider.java b/services/java/com/android/server/location/MockProvider.java
index 01b34b7..09d799f 100644
--- a/services/java/com/android/server/location/MockProvider.java
+++ b/services/java/com/android/server/location/MockProvider.java
@@ -23,6 +23,7 @@
 import android.net.NetworkInfo;
 import android.os.Bundle;
 import android.os.RemoteException;
+import android.os.WorkSource;
 import android.util.Log;
 import android.util.PrintWriterPrinter;
 
@@ -201,7 +202,7 @@
         return false;
     }
 
-    public void setMinTime(long minTime) {
+    public void setMinTime(long minTime, WorkSource ws) {
     }
 
     public void updateNetworkState(int state, NetworkInfo info) {
diff --git a/services/java/com/android/server/location/PassiveProvider.java b/services/java/com/android/server/location/PassiveProvider.java
index 7fc93f8..ea0d1b0 100644
--- a/services/java/com/android/server/location/PassiveProvider.java
+++ b/services/java/com/android/server/location/PassiveProvider.java
@@ -24,6 +24,7 @@
 import android.net.NetworkInfo;
 import android.os.Bundle;
 import android.os.RemoteException;
+import android.os.WorkSource;
 import android.util.Log;
 
 /**
@@ -123,7 +124,7 @@
         return false;
     }
 
-    public void setMinTime(long minTime) {
+    public void setMinTime(long minTime, WorkSource ws) {
     }
 
     public void updateNetworkState(int state, NetworkInfo info) {
diff --git a/services/java/com/android/server/sip/SipHelper.java b/services/java/com/android/server/sip/SipHelper.java
index d9a1bbf..050eddc 100644
--- a/services/java/com/android/server/sip/SipHelper.java
+++ b/services/java/com/android/server/sip/SipHelper.java
@@ -68,6 +68,7 @@
  */
 class SipHelper {
     private static final String TAG = SipHelper.class.getSimpleName();
+    private static final boolean DEBUG = true;
 
     private SipStack mSipStack;
     private SipProvider mSipProvider;
@@ -264,6 +265,7 @@
 
             ClientTransaction clientTransaction =
                     mSipProvider.getNewClientTransaction(request);
+            if (DEBUG) Log.d(TAG, "send INVITE: " + request);
             clientTransaction.sendRequest();
             return clientTransaction;
         } catch (ParseException e) {
@@ -281,6 +283,7 @@
 
             ClientTransaction clientTransaction =
                     mSipProvider.getNewClientTransaction(request);
+            if (DEBUG) Log.d(TAG, "send RE-INVITE: " + request);
             dialog.sendRequest(clientTransaction);
             return clientTransaction;
         } catch (ParseException e) {
@@ -314,6 +317,7 @@
             ToHeader toHeader = (ToHeader) response.getHeader(ToHeader.NAME);
             toHeader.setTag(tag);
             response.addHeader(toHeader);
+            if (DEBUG) Log.d(TAG, "send RINGING: " + response);
             transaction.sendResponse(response);
             return transaction;
         } catch (ParseException e) {
@@ -340,7 +344,9 @@
             if (inviteTransaction == null) {
                 inviteTransaction = getServerTransaction(event);
             }
+
             if (inviteTransaction.getState() != TransactionState.COMPLETED) {
+                if (DEBUG) Log.d(TAG, "send OK: " + response);
                 inviteTransaction.sendResponse(response);
             }
 
@@ -358,6 +364,7 @@
                     Response.BUSY_HERE, request);
 
             if (inviteTransaction.getState() != TransactionState.COMPLETED) {
+                if (DEBUG) Log.d(TAG, "send BUSY HERE: " + response);
                 inviteTransaction.sendResponse(response);
             }
         } catch (ParseException e) {
@@ -373,27 +380,31 @@
         Response response = event.getResponse();
         long cseq = ((CSeqHeader) response.getHeader(CSeqHeader.NAME))
                 .getSeqNumber();
-        dialog.sendAck(dialog.createAck(cseq));
+        Request ack = dialog.createAck(cseq);
+        if (DEBUG) Log.d(TAG, "send ACK: " + ack);
+        dialog.sendAck(ack);
     }
 
     public void sendBye(Dialog dialog) throws SipException {
         Request byeRequest = dialog.createRequest(Request.BYE);
-        Log.d(TAG, "send BYE: " + byeRequest);
+        if (DEBUG) Log.d(TAG, "send BYE: " + byeRequest);
         dialog.sendRequest(mSipProvider.getNewClientTransaction(byeRequest));
     }
 
     public void sendCancel(ClientTransaction inviteTransaction)
             throws SipException {
         Request cancelRequest = inviteTransaction.createCancel();
+        if (DEBUG) Log.d(TAG, "send CANCEL: " + cancelRequest);
         mSipProvider.getNewClientTransaction(cancelRequest).sendRequest();
     }
 
     public void sendResponse(RequestEvent event, int responseCode)
             throws SipException {
         try {
-            getServerTransaction(event).sendResponse(
-                    mMessageFactory.createResponse(
-                            responseCode, event.getRequest()));
+            Response response = mMessageFactory.createResponse(
+                    responseCode, event.getRequest());
+            if (DEBUG) Log.d(TAG, "send response: " + response);
+            getServerTransaction(event).sendResponse(response);
         } catch (ParseException e) {
             throw new SipException("sendResponse()", e);
         }
@@ -402,8 +413,10 @@
     public void sendInviteRequestTerminated(Request inviteRequest,
             ServerTransaction inviteTransaction) throws SipException {
         try {
-            inviteTransaction.sendResponse(mMessageFactory.createResponse(
-                    Response.REQUEST_TERMINATED, inviteRequest));
+            Response response = mMessageFactory.createResponse(
+                    Response.REQUEST_TERMINATED, inviteRequest);
+            if (DEBUG) Log.d(TAG, "send response: " + response);
+            inviteTransaction.sendResponse(response);
         } catch (ParseException e) {
             throw new SipException("sendInviteRequestTerminated()", e);
         }
diff --git a/services/java/com/android/server/sip/SipService.java b/services/java/com/android/server/sip/SipService.java
index c3786f5..a2ebc69 100644
--- a/services/java/com/android/server/sip/SipService.java
+++ b/services/java/com/android/server/sip/SipService.java
@@ -35,6 +35,10 @@
 import android.net.wifi.WifiManager;
 import android.os.Binder;
 import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.text.TextUtils;
@@ -59,6 +63,8 @@
  */
 public final class SipService extends ISipService.Stub {
     private static final String TAG = "SipService";
+    private static final boolean DEBUG = true;
+    private static final boolean DEBUG_TIMER = DEBUG && false;
     private static final int EXPIRY_TIME = 3600;
     private static final int SHORT_EXPIRY_TIME = 10;
     private static final int MIN_EXPIRY_TIME = 60;
@@ -69,6 +75,9 @@
     private boolean mConnected;
     private WakeupTimer mTimer;
     private WifiManager.WifiLock mWifiLock;
+    private boolean mWifiOnly;
+
+    private MyExecutor mExecutor;
 
     // SipProfile URI --> group
     private Map<String, SipSessionGroupExt> mSipGroups =
@@ -90,13 +99,20 @@
     }
 
     private SipService(Context context) {
-        Log.v(TAG, " service started!");
+        if (DEBUG) Log.d(TAG, " service started!");
         mContext = context;
         mConnectivityReceiver = new ConnectivityReceiver();
         context.registerReceiver(mConnectivityReceiver,
                 new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
 
         mTimer = new WakeupTimer(context);
+        mWifiOnly = SipManager.isSipWifiOnly(context);
+    }
+
+    private MyExecutor getExecutor() {
+        // create mExecutor lazily
+        if (mExecutor == null) mExecutor = new MyExecutor();
+        return mExecutor;
     }
 
     public synchronized SipProfile[] getListOfProfiles() {
@@ -137,7 +153,7 @@
             throw new RuntimeException(
                     "empty broadcast action for incoming call");
         }
-        Log.v(TAG, "open3: " + localProfile.getUriString() + ": "
+        if (DEBUG) Log.d(TAG, "open3: " + localProfile.getUriString() + ": "
                 + incomingCallBroadcastAction + ": " + listener);
         try {
             SipSessionGroupExt group = createGroup(localProfile,
@@ -238,14 +254,14 @@
     }
 
     private void notifyProfileAdded(SipProfile localProfile) {
-        Log.d(TAG, "notify: profile added: " + localProfile);
+        if (DEBUG) Log.d(TAG, "notify: profile added: " + localProfile);
         Intent intent = new Intent(SipManager.SIP_ADD_PHONE_ACTION);
         intent.putExtra(SipManager.LOCAL_URI_KEY, localProfile.getUriString());
         mContext.sendBroadcast(intent);
     }
 
     private void notifyProfileRemoved(SipProfile localProfile) {
-        Log.d(TAG, "notify: profile removed: " + localProfile);
+        if (DEBUG) Log.d(TAG, "notify: profile removed: " + localProfile);
         Intent intent = new Intent(SipManager.SIP_REMOVE_PHONE_ACTION);
         intent.putExtra(SipManager.LOCAL_URI_KEY, localProfile.getUriString());
         mContext.sendBroadcast(intent);
@@ -260,7 +276,7 @@
 
     private void grabWifiLock() {
         if (mWifiLock == null) {
-            Log.v(TAG, "acquire wifi lock");
+            if (DEBUG) Log.d(TAG, "acquire wifi lock");
             mWifiLock = ((WifiManager)
                     mContext.getSystemService(Context.WIFI_SERVICE))
                     .createWifiLock(WifiManager.WIFI_MODE_FULL, TAG);
@@ -270,7 +286,7 @@
 
     private void releaseWifiLock() {
         if (mWifiLock != null) {
-            Log.v(TAG, "release wifi lock");
+            if (DEBUG) Log.d(TAG, "release wifi lock");
             mWifiLock.release();
             mWifiLock = null;
         }
@@ -283,7 +299,7 @@
 
     private synchronized void onConnectivityChanged(
             String type, boolean connected) {
-        Log.v(TAG, "onConnectivityChanged(): "
+        if (DEBUG) Log.d(TAG, "onConnectivityChanged(): "
                 + mNetworkType + (mConnected? " CONNECTED" : " DISCONNECTED")
                 + " --> " + type + (connected? " CONNECTED" : " DISCONNECTED"));
 
@@ -398,19 +414,20 @@
                 mSipGroup.openToReceiveCalls(this);
                 mAutoRegistration.start(mSipGroup);
             }
-            Log.v(TAG, "  openToReceiveCalls: " + getUri() + ": "
+            if (DEBUG) Log.d(TAG, "  openToReceiveCalls: " + getUri() + ": "
                     + mIncomingCallBroadcastAction);
         }
 
         public void onConnectivityChanged(boolean connected)
                 throws SipException {
+            mSipGroup.onConnectivityChanged();
             if (connected) {
                 resetGroup(mLocalIp);
                 if (mOpened) openToReceiveCalls();
             } else {
                 // close mSipGroup but remember mOpened
-                Log.v(TAG, "  close auto reg temporarily: " + getUri() + ": "
-                        + mIncomingCallBroadcastAction);
+                if (DEBUG) Log.d(TAG, "  close auto reg temporarily: "
+                        + getUri() + ": " + mIncomingCallBroadcastAction);
                 mSipGroup.close();
                 mAutoRegistration.stop();
             }
@@ -436,7 +453,7 @@
             mOpened = false;
             mSipGroup.closeToNotReceiveCalls();
             mAutoRegistration.stop();
-            Log.v(TAG, "   close: " + getUri() + ": "
+            if (DEBUG) Log.d(TAG, "   close: " + getUri() + ": "
                     + mIncomingCallBroadcastAction);
         }
 
@@ -455,13 +472,13 @@
                     }
 
                     // send out incoming call broadcast
-                    Log.d(TAG, " ringing~~ " + getUri() + ": " + caller.getUri()
-                            + ": " + session.getCallId());
                     addPendingSession(session);
                     Intent intent = SipManager.createIncomingCallBroadcast(
                             mIncomingCallBroadcastAction, session.getCallId(),
                             sessionDescription);
-                    Log.d(TAG, "   send out intent: " + intent);
+                    if (DEBUG) Log.d(TAG, " ringing~~ " + getUri() + ": "
+                            + caller.getUri() + ": " + session.getCallId()
+                            + " " + mIncomingCallBroadcastAction);
                     mContext.sendBroadcast(intent);
                 } catch (RemoteException e) {
                     // should never happen with a local call
@@ -471,9 +488,10 @@
         }
 
         @Override
-        public void onError(ISipSession session, String errorClass,
+        public void onError(ISipSession session, int errorCode,
                 String message) {
-            Log.v(TAG, "sip session error: " + errorClass + ": " + message);
+            if (DEBUG) Log.d(TAG, "sip session error: "
+                    + SipErrorCode.toString(errorCode) + ": " + message);
         }
 
         public boolean isOpened() {
@@ -503,9 +521,18 @@
         }
 
         public void run() {
+            // delegate to mExecutor
+            getExecutor().addTask(new Runnable() {
+                public void run() {
+                    realRun();
+                }
+            });
+        }
+
+        private void realRun() {
             synchronized (SipService.this) {
                 SipSessionGroup.SipSessionImpl session = mSession.duplicate();
-                Log.d(TAG, "  ~~~ keepalive");
+                if (DEBUG) Log.d(TAG, "~~~ keepalive");
                 mTimer.cancel(this);
                 session.sendKeepAlive();
                 if (session.isReRegisterRequired()) {
@@ -529,7 +556,7 @@
         private int mBackoff = 1;
         private boolean mRegistered;
         private long mExpiryTime;
-        private SipErrorCode mErrorCode;
+        private int mErrorCode;
         private String mErrorMessage;
 
         private String getAction() {
@@ -548,7 +575,7 @@
                 // TODO: when rfc5626 is deployed, use reg-id and sip.instance
                 // in registration to avoid adding duplicate entries to server
                 mSession.unregister();
-                Log.v(TAG, "start AutoRegistrationProcess for "
+                if (DEBUG) Log.d(TAG, "start AutoRegistrationProcess for "
                         + mSession.getLocalProfile().getUriString());
             }
         }
@@ -580,16 +607,14 @@
         }
 
         public void setListener(ISipSessionListener listener) {
-            Log.v(TAG, "setListener(): " + listener);
             synchronized (SipService.this) {
                 mProxy.setListener(listener);
                 if (mSession == null) return;
 
                 try {
-                    SipSessionState state = (mSession == null)
+                    int state = (mSession == null)
                             ? SipSessionState.READY_TO_CALL
-                            : Enum.valueOf(
-                                    SipSessionState.class, mSession.getState());
+                            : mSession.getState();
                     if ((state == SipSessionState.REGISTERING)
                             || (state == SipSessionState.DEREGISTERING)) {
                         mProxy.onRegistering(mSession);
@@ -597,12 +622,12 @@
                         int duration = (int)
                                 (mExpiryTime - SystemClock.elapsedRealtime());
                         mProxy.onRegistrationDone(mSession, duration);
-                    } else if (mErrorCode != null) {
+                    } else if (mErrorCode != SipErrorCode.NO_ERROR) {
                         if (mErrorCode == SipErrorCode.TIME_OUT) {
                             mProxy.onRegistrationTimeout(mSession);
                         } else {
-                            mProxy.onRegistrationFailed(mSession,
-                                    mErrorCode.toString(), mErrorMessage);
+                            mProxy.onRegistrationFailed(mSession, mErrorCode,
+                                    mErrorMessage);
                         }
                     }
                 } catch (Throwable t) {
@@ -616,9 +641,18 @@
         }
 
         public void run() {
-            mErrorCode = null;
+            // delegate to mExecutor
+            getExecutor().addTask(new Runnable() {
+                public void run() {
+                    realRun();
+                }
+            });
+        }
+
+        private void realRun() {
+            mErrorCode = SipErrorCode.NO_ERROR;
             mErrorMessage = null;
-            Log.v(TAG, "  ~~~ registering");
+            if (DEBUG) Log.d(TAG, "~~~ registering");
             synchronized (SipService.this) {
                 if (mConnected && !isStopped()) mSession.register(EXPIRY_TIME);
             }
@@ -641,7 +675,7 @@
         }
 
         private void restart(int duration) {
-            Log.v(TAG, "Refresh registration " + duration + "s later.");
+            if (DEBUG) Log.d(TAG, "Refresh registration " + duration + "s later.");
             mTimer.cancel(this);
             mTimer.set(duration * 1000, this);
         }
@@ -658,7 +692,7 @@
 
         @Override
         public void onRegistering(ISipSession session) {
-            Log.v(TAG, "onRegistering(): " + session + ": " + mSession);
+            if (DEBUG) Log.d(TAG, "onRegistering(): " + session);
             synchronized (SipService.this) {
                 if (!isStopped() && (session != mSession)) return;
                 mRegistered = false;
@@ -668,7 +702,7 @@
 
         @Override
         public void onRegistrationDone(ISipSession session, int duration) {
-            Log.v(TAG, "onRegistrationDone(): " + session + ": " + mSession);
+            if (DEBUG) Log.d(TAG, "onRegistrationDone(): " + session);
             synchronized (SipService.this) {
                 if (!isStopped() && (session != mSession)) return;
 
@@ -702,28 +736,25 @@
                 } else {
                     mRegistered = false;
                     mExpiryTime = -1L;
-                    Log.v(TAG, "Refresh registration immediately");
+                    if (DEBUG) Log.d(TAG, "Refresh registration immediately");
                     run();
                 }
             }
         }
 
         @Override
-        public void onRegistrationFailed(ISipSession session,
-                String errorCodeString, String message) {
-            SipErrorCode errorCode =
-                    Enum.valueOf(SipErrorCode.class, errorCodeString);
-            Log.v(TAG, "onRegistrationFailed(): " + session + ": " + mSession
-                    + ": " + errorCode + ": " + message);
+        public void onRegistrationFailed(ISipSession session, int errorCode,
+                String message) {
+            if (DEBUG) Log.d(TAG, "onRegistrationFailed(): " + session + ": "
+                    + SipErrorCode.toString(errorCode) + ": " + message);
             synchronized (SipService.this) {
                 if (!isStopped() && (session != mSession)) return;
                 mErrorCode = errorCode;
                 mErrorMessage = message;
-                mProxy.onRegistrationFailed(session, errorCode.toString(),
-                        message);
+                mProxy.onRegistrationFailed(session, errorCode, message);
 
                 if (errorCode == SipErrorCode.INVALID_CREDENTIALS) {
-                    Log.d(TAG, "   pause auto-registration");
+                    if (DEBUG) Log.d(TAG, "   pause auto-registration");
                     stopButKeepStates();
                 } else if (!isStopped()) {
                     onError();
@@ -733,7 +764,7 @@
 
         @Override
         public void onRegistrationTimeout(ISipSession session) {
-            Log.v(TAG, "onRegistrationTimeout(): " + session + ": " + mSession);
+            if (DEBUG) Log.d(TAG, "onRegistrationTimeout(): " + session);
             synchronized (SipService.this) {
                 if (!isStopped() && (session != mSession)) return;
                 mErrorCode = SipErrorCode.TIME_OUT;
@@ -770,20 +801,55 @@
                             b.get(ConnectivityManager.EXTRA_NETWORK_INFO);
                     String type = netInfo.getTypeName();
                     NetworkInfo.State state = netInfo.getState();
+
+                    if (mWifiOnly && (netInfo.getType() !=
+                            ConnectivityManager.TYPE_WIFI)) {
+                        if (DEBUG) {
+                            Log.d(TAG, "Wifi only, other connectivity ignored: "
+                                    + type);
+                        }
+                        return;
+                    }
+
+                    NetworkInfo activeNetInfo = getActiveNetworkInfo();
+                    if (DEBUG) {
+                        if (activeNetInfo != null) {
+                            Log.d(TAG, "active network: "
+                                    + activeNetInfo.getTypeName()
+                                    + ((activeNetInfo.getState() == NetworkInfo.State.CONNECTED)
+                                            ? " CONNECTED" : " DISCONNECTED"));
+                        } else {
+                            Log.d(TAG, "active network: null");
+                        }
+                    }
+                    if ((state == NetworkInfo.State.CONNECTED)
+                            && (activeNetInfo != null)
+                            && (activeNetInfo.getType() != netInfo.getType())) {
+                        if (DEBUG) Log.d(TAG, "ignore connect event: " + type
+                                + ", active: " + activeNetInfo.getTypeName());
+                        return;
+                    }
+
                     if (state == NetworkInfo.State.CONNECTED) {
-                        Log.v(TAG, "Connectivity alert: CONNECTED " + type);
+                        if (DEBUG) Log.d(TAG, "Connectivity alert: CONNECTED " + type);
                         onChanged(type, true);
                     } else if (state == NetworkInfo.State.DISCONNECTED) {
-                        Log.v(TAG, "Connectivity alert: DISCONNECTED " + type);
+                        if (DEBUG) Log.d(TAG, "Connectivity alert: DISCONNECTED " + type);
                         onChanged(type, false);
                     } else {
-                        Log.d(TAG, "Connectivity alert not processed: " + state
-                                + " " + type);
+                        if (DEBUG) Log.d(TAG, "Connectivity alert not processed: "
+                                + state + " " + type);
                     }
                 }
             }
         }
 
+        private NetworkInfo getActiveNetworkInfo() {
+            ConnectivityManager cm = (ConnectivityManager)
+                    mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+            return cm.getActiveNetworkInfo();
+        }
+
         private void onChanged(String type, boolean connected) {
             synchronized (SipService.this) {
                 // When turning on WIFI, it needs some time for network
@@ -793,7 +859,7 @@
                 if (connected) {
                     if (mTask != null) mTask.cancel();
                     mTask = new MyTimerTask(type, connected);
-                    mTimer.schedule(mTask, 3 * 1000L);
+                    mTimer.schedule(mTask, 2 * 1000L);
                     // TODO: hold wakup lock so that we can finish change before
                     // the device goes to sleep
                 } else {
@@ -816,6 +882,15 @@
 
             @Override
             public void run() {
+                // delegate to mExecutor
+                getExecutor().addTask(new Runnable() {
+                    public void run() {
+                        realRun();
+                    }
+                });
+            }
+
+            private void realRun() {
                 synchronized (SipService.this) {
                     if (mTask != this) {
                         Log.w(TAG, "  unexpected task: " + mNetworkType
@@ -823,7 +898,7 @@
                         return;
                     }
                     mTask = null;
-                    Log.v(TAG, " deliver change for " + mNetworkType
+                    if (DEBUG) Log.d(TAG, " deliver change for " + mNetworkType
                             + (mConnected ? " CONNECTED" : "DISCONNECTED"));
                     onConnectivityChanged(mNetworkType, mConnected);
                 }
@@ -905,8 +980,10 @@
             newQueue.addAll((Collection<MyEvent>) mEventQueue);
             mEventQueue.clear();
             mEventQueue = newQueue;
-            Log.v(TAG, "queue re-calculated");
-            printQueue();
+            if (DEBUG_TIMER) {
+                Log.d(TAG, "queue re-calculated");
+                printQueue();
+            }
         }
 
         // Determines the period and the trigger time of the new event and insert it
@@ -960,10 +1037,12 @@
             }
 
             long triggerTime = event.mTriggerTime;
-            Log.v(TAG, " add event " + event + " scheduled at "
-                    + showTime(triggerTime) + " at " + showTime(now)
-                    + ", #events=" + mEventQueue.size());
-            printQueue();
+            if (DEBUG_TIMER) {
+                Log.d(TAG, " add event " + event + " scheduled at "
+                        + showTime(triggerTime) + " at " + showTime(now)
+                        + ", #events=" + mEventQueue.size());
+                printQueue();
+            }
         }
 
         /**
@@ -973,7 +1052,7 @@
          */
         public synchronized void cancel(Runnable callback) {
             if (stopped() || mEventQueue.isEmpty()) return;
-            Log.d(TAG, "cancel:" + callback);
+            if (DEBUG_TIMER) Log.d(TAG, "cancel:" + callback);
 
             MyEvent firstEvent = mEventQueue.first();
             for (Iterator<MyEvent> iter = mEventQueue.iterator();
@@ -981,7 +1060,7 @@
                 MyEvent event = iter.next();
                 if (event.mCallback == callback) {
                     iter.remove();
-                    Log.d(TAG, "    cancel found:" + event);
+                    if (DEBUG_TIMER) Log.d(TAG, "    cancel found:" + event);
                 }
             }
             if (mEventQueue.isEmpty()) {
@@ -995,8 +1074,10 @@
                 recalculatePeriods();
                 scheduleNext();
             }
-            Log.d(TAG, "after cancel:");
-            printQueue();
+            if (DEBUG_TIMER) {
+                Log.d(TAG, "after cancel:");
+                printQueue();
+            }
         }
 
         private void scheduleNext() {
@@ -1045,13 +1126,13 @@
         }
 
         private void execute(long triggerTime) {
-            Log.d(TAG, "time's up, triggerTime = " + showTime(triggerTime) + ": "
-                    + mEventQueue.size());
+            if (DEBUG_TIMER) Log.d(TAG, "time's up, triggerTime = "
+                    + showTime(triggerTime) + ": " + mEventQueue.size());
             if (stopped() || mEventQueue.isEmpty()) return;
 
             for (MyEvent event : mEventQueue) {
                 if (event.mTriggerTime != triggerTime) break;
-                Log.d(TAG, "execute " + event);
+                if (DEBUG_TIMER) Log.d(TAG, "execute " + event);
 
                 event.mLastTriggerTime = event.mTriggerTime;
                 event.mTriggerTime += event.mPeriod;
@@ -1059,8 +1140,10 @@
                 // run the callback in a new thread to prevent deadlock
                 new Thread(event.mCallback).start();
             }
-            Log.d(TAG, "after timeout execution");
-            printQueue();
+            if (DEBUG_TIMER) {
+                Log.d(TAG, "after timeout execution");
+                printQueue();
+            }
             scheduleNext();
         }
 
@@ -1118,4 +1201,30 @@
             return (this == that);
         }
     }
+
+    // Single-threaded executor
+    private static class MyExecutor extends Handler {
+        MyExecutor() {
+            super(createLooper());
+        }
+
+        private static Looper createLooper() {
+            HandlerThread thread = new HandlerThread("SipService");
+            thread.start();
+            return thread.getLooper();
+        }
+
+        void addTask(Runnable task) {
+            Message.obtain(this, 0/* don't care */, task).sendToTarget();
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            if (msg.obj instanceof Runnable) {
+                ((Runnable) msg.obj).run();
+            } else {
+                Log.w(TAG, "can't handle msg: " + msg);
+            }
+        }
+    }
 }
diff --git a/services/java/com/android/server/sip/SipSessionGroup.java b/services/java/com/android/server/sip/SipSessionGroup.java
index da8e9b8..b4c2241 100644
--- a/services/java/com/android/server/sip/SipSessionGroup.java
+++ b/services/java/com/android/server/sip/SipSessionGroup.java
@@ -19,6 +19,7 @@
 import gov.nist.javax.sip.clientauthutils.AccountManager;
 import gov.nist.javax.sip.clientauthutils.UserCredentials;
 import gov.nist.javax.sip.header.SIPHeaderNames;
+import gov.nist.javax.sip.header.ProxyAuthenticate;
 import gov.nist.javax.sip.header.WWWAuthenticate;
 import gov.nist.javax.sip.message.SIPMessage;
 
@@ -79,9 +80,12 @@
  */
 class SipSessionGroup implements SipListener {
     private static final String TAG = "SipSession";
+    private static final boolean DEBUG = true;
+    private static final boolean DEBUG_PING = DEBUG && false;
     private static final String ANONYMOUS = "anonymous";
     private static final String SERVER_ERROR_PREFIX = "Response: ";
-    private static final int EXPIRY_TIME = 3600;
+    private static final int EXPIRY_TIME = 3600; // in seconds
+    private static final int CANCEL_CALL_TIMER = 5; // in seconds
 
     private static final EventObject DEREGISTER = new EventObject("Deregister");
     private static final EventObject END_CALL = new EventObject("End call");
@@ -153,6 +157,13 @@
         mSessionMap.clear();
     }
 
+    synchronized void onConnectivityChanged() {
+        for (SipSessionImpl s : mSessionMap.values()) {
+            s.onError(SipErrorCode.DATA_CONNECTION_LOST,
+                    "data connection lost");
+        }
+    }
+
     public SipProfile getLocalProfile() {
         return mLocalProfile;
     }
@@ -210,22 +221,26 @@
 
     private synchronized SipSessionImpl getSipSession(EventObject event) {
         String key = SipHelper.getCallId(event);
-        Log.d(TAG, " sesssion key from event: " + key);
-        Log.d(TAG, " active sessions:");
-        for (String k : mSessionMap.keySet()) {
-            Log.d(TAG, "   .....  '" + k + "': " + mSessionMap.get(k));
-        }
         SipSessionImpl session = mSessionMap.get(key);
+        if ((session != null) && isLoggable(session)) {
+            Log.d(TAG, "session key from event: " + key);
+            Log.d(TAG, "active sessions:");
+            for (String k : mSessionMap.keySet()) {
+                Log.d(TAG, " ..." + k + ": " + mSessionMap.get(k));
+            }
+        }
         return ((session != null) ? session : mCallReceiverSession);
     }
 
     private synchronized void addSipSession(SipSessionImpl newSession) {
         removeSipSession(newSession);
         String key = newSession.getCallId();
-        Log.d(TAG, " +++++  add a session with key:  '" + key + "'");
         mSessionMap.put(key, newSession);
-        for (String k : mSessionMap.keySet()) {
-            Log.d(TAG, "   .....  " + k + ": " + mSessionMap.get(k));
+        if (isLoggable(newSession)) {
+            Log.d(TAG, "+++  add a session with key:  '" + key + "'");
+            for (String k : mSessionMap.keySet()) {
+                Log.d(TAG, "  " + k + ": " + mSessionMap.get(k));
+            }
         }
     }
 
@@ -246,10 +261,12 @@
                 }
             }
         }
-        Log.d(TAG, "   remove session " + session + " with key '" + key + "'");
 
-        for (String k : mSessionMap.keySet()) {
-            Log.d(TAG, "   .....  " + k + ": " + mSessionMap.get(k));
+        if ((s != null) && isLoggable(s)) {
+            Log.d(TAG, "remove session " + session + " @key '" + key + "'");
+            for (String k : mSessionMap.keySet()) {
+                Log.d(TAG, "  " + k + ": " + mSessionMap.get(k));
+            }
         }
     }
 
@@ -280,10 +297,11 @@
     private synchronized void process(EventObject event) {
         SipSessionImpl session = getSipSession(event);
         try {
-            if ((session != null) && session.process(event)) {
-                Log.d(TAG, " ~~~~~   new state: " + session.mState);
-            } else {
-                Log.d(TAG, "event not processed: " + event);
+            boolean isLoggable = isLoggable(session, event);
+            boolean processed = (session != null) && session.process(event);
+            if (isLoggable && processed) {
+                Log.d(TAG, "new state after: "
+                        + SipSessionState.toString(session.mState));
             }
         } catch (Throwable e) {
             Log.w(TAG, "event process error: " + event, e);
@@ -313,7 +331,8 @@
         }
 
         public boolean process(EventObject evt) throws SipException {
-            Log.d(TAG, " ~~~~~   " + this + ": " + mState + ": processing "
+            if (isLoggable(this, evt)) Log.d(TAG, " ~~~~~   " + this + ": "
+                    + SipSessionState.toString(mState) + ": processing "
                     + log(evt));
             if (isRequestEvent(Request.INVITE, evt)) {
                 RequestEvent event = (RequestEvent) evt;
@@ -339,7 +358,7 @@
     class SipSessionImpl extends ISipSession.Stub {
         SipProfile mPeerProfile;
         SipSessionListenerProxy mProxy = new SipSessionListenerProxy();
-        SipSessionState mState = SipSessionState.READY_TO_CALL;
+        int mState = SipSessionState.READY_TO_CALL;
         RequestEvent mInviteReceived;
         Dialog mDialog;
         ServerTransaction mServerTransaction;
@@ -347,6 +366,40 @@
         String mPeerSessionDescription;
         boolean mInCall;
         boolean mReRegisterFlag = false;
+        SessionTimer mTimer;
+
+        // lightweight timer
+        class SessionTimer {
+            private boolean mRunning = true;
+
+            void start(final int timeout) {
+                new Thread(new Runnable() {
+                    public void run() {
+                        sleep(timeout);
+                        if (mRunning) timeout();
+                    }
+                }).start();
+            }
+
+            synchronized void cancel() {
+                mRunning = false;
+                this.notify();
+            }
+
+            private void timeout() {
+                synchronized (SipSessionGroup.this) {
+                    onError(SipErrorCode.TIME_OUT, "Session timed out!");
+                }
+            }
+
+            private synchronized void sleep(int timeout) {
+                try {
+                    this.wait(timeout * 1000);
+                } catch (InterruptedException e) {
+                    Log.e(TAG, "session timer interrupted!");
+                }
+            }
+        }
 
         public SipSessionImpl(ISipSessionListener listener) {
             setListener(listener);
@@ -366,6 +419,8 @@
             mServerTransaction = null;
             mClientTransaction = null;
             mPeerSessionDescription = null;
+
+            cancelSessionTimer();
         }
 
         public boolean isInCall() {
@@ -394,8 +449,8 @@
             return null;
         }
 
-        public String getState() {
-            return mState.toString();
+        public int getState() {
+            return mState;
         }
 
         public void setListener(ISipSessionListener listener) {
@@ -418,16 +473,16 @@
             }).start();
         }
 
-        public void makeCall(SipProfile peerProfile,
-                String sessionDescription) {
-            doCommandAsync(
-                    new MakeCallCommand(peerProfile, sessionDescription));
+        public void makeCall(SipProfile peerProfile, String sessionDescription,
+                int timeout) {
+            doCommandAsync(new MakeCallCommand(peerProfile, sessionDescription,
+                    timeout));
         }
 
-        public void answerCall(String sessionDescription) {
+        public void answerCall(String sessionDescription, int timeout) {
             try {
-                processCommand(
-                        new MakeCallCommand(mPeerProfile, sessionDescription));
+                processCommand(new MakeCallCommand(mPeerProfile,
+                        sessionDescription, timeout));
             } catch (SipException e) {
                 onError(e);
             }
@@ -437,9 +492,15 @@
             doCommandAsync(END_CALL);
         }
 
-        public void changeCall(String sessionDescription) {
-            doCommandAsync(
-                    new MakeCallCommand(mPeerProfile, sessionDescription));
+        public void changeCall(String sessionDescription, int timeout) {
+            doCommandAsync(new MakeCallCommand(mPeerProfile, sessionDescription,
+                    timeout));
+        }
+
+        public void changeCallWithTimeout(
+                String sessionDescription, int timeout) {
+            doCommandAsync(new MakeCallCommand(mPeerProfile, sessionDescription,
+                    timeout));
         }
 
         public void register(int duration) {
@@ -462,7 +523,7 @@
             mState = SipSessionState.PINGING;
             try {
                 processCommand(new OptionsCommand());
-                while (SipSessionState.PINGING.equals(mState)) {
+                while (SipSessionState.PINGING == mState) {
                     Thread.sleep(1000);
                 }
             } catch (SipException e) {
@@ -488,14 +549,16 @@
         public String toString() {
             try {
                 String s = super.toString();
-                return s.substring(s.indexOf("@")) + ":" + mState;
+                return s.substring(s.indexOf("@")) + ":"
+                        + SipSessionState.toString(mState);
             } catch (Throwable e) {
                 return super.toString();
             }
         }
 
         public boolean process(EventObject evt) throws SipException {
-            Log.d(TAG, " ~~~~~   " + this + ": " + mState + ": processing "
+            if (isLoggable(this, evt)) Log.d(TAG, " ~~~~~   " + this + ": "
+                    + SipSessionState.toString(mState) + ": processing "
                     + log(evt));
             synchronized (SipSessionGroup.this) {
                 if (isClosed()) return false;
@@ -511,30 +574,30 @@
                 boolean processed;
 
                 switch (mState) {
-                case REGISTERING:
-                case DEREGISTERING:
+                case SipSessionState.REGISTERING:
+                case SipSessionState.DEREGISTERING:
                     processed = registeringToReady(evt);
                     break;
-                case PINGING:
+                case SipSessionState.PINGING:
                     processed = keepAliveProcess(evt);
                     break;
-                case READY_TO_CALL:
+                case SipSessionState.READY_TO_CALL:
                     processed = readyForCall(evt);
                     break;
-                case INCOMING_CALL:
+                case SipSessionState.INCOMING_CALL:
                     processed = incomingCall(evt);
                     break;
-                case INCOMING_CALL_ANSWERING:
+                case SipSessionState.INCOMING_CALL_ANSWERING:
                     processed = incomingCallToInCall(evt);
                     break;
-                case OUTGOING_CALL:
-                case OUTGOING_CALL_RING_BACK:
+                case SipSessionState.OUTGOING_CALL:
+                case SipSessionState.OUTGOING_CALL_RING_BACK:
                     processed = outgoingCall(evt);
                     break;
-                case OUTGOING_CALL_CANCELING:
+                case SipSessionState.OUTGOING_CALL_CANCELING:
                     processed = outgoingCallToReady(evt);
                     break;
-                case IN_CALL:
+                case SipSessionState.IN_CALL:
                     processed = inCall(evt);
                     break;
                 default:
@@ -581,8 +644,8 @@
         private void processTransactionTerminated(
                 TransactionTerminatedEvent event) {
             switch (mState) {
-                case IN_CALL:
-                case READY_TO_CALL:
+                case SipSessionState.IN_CALL:
+                case SipSessionState.READY_TO_CALL:
                     Log.d(TAG, "Transaction terminated; do nothing");
                     break;
                 default:
@@ -607,18 +670,18 @@
                 return;
             }
             switch (mState) {
-                case REGISTERING:
-                case DEREGISTERING:
+                case SipSessionState.REGISTERING:
+                case SipSessionState.DEREGISTERING:
                     reset();
                     mProxy.onRegistrationTimeout(this);
                     break;
-                case INCOMING_CALL:
-                case INCOMING_CALL_ANSWERING:
-                case OUTGOING_CALL:
-                case OUTGOING_CALL_CANCELING:
+                case SipSessionState.INCOMING_CALL:
+                case SipSessionState.INCOMING_CALL_ANSWERING:
+                case SipSessionState.OUTGOING_CALL:
+                case SipSessionState.OUTGOING_CALL_CANCELING:
                     onError(SipErrorCode.TIME_OUT, event.toString());
                     break;
-                case PINGING:
+                case SipSessionState.PINGING:
                     reset();
                     mReRegisterFlag = true;
                     mState = SipSessionState.READY_TO_CALL;
@@ -664,14 +727,14 @@
                     if (mRPort == 0) mRPort = rPort;
                     if (mRPort != rPort) {
                         mReRegisterFlag = true;
-                        Log.w(TAG, String.format("rport is changed: %d <> %d",
-                                mRPort, rPort));
+                        if (DEBUG) Log.w(TAG, String.format(
+                                "rport is changed: %d <> %d", mRPort, rPort));
                         mRPort = rPort;
                     } else {
-                        Log.w(TAG, "rport is the same: " + rPort);
+                        if (DEBUG_PING) Log.w(TAG, "rport is the same: " + rPort);
                     }
                 } else {
-                    Log.w(TAG, "peer did not respect our rport request");
+                    if (DEBUG) Log.w(TAG, "peer did not respond rport");
                 }
                 reset();
                 return true;
@@ -694,7 +757,7 @@
                 int statusCode = response.getStatusCode();
                 switch (statusCode) {
                 case Response.OK:
-                    SipSessionState state = mState;
+                    int state = mState;
                     onRegistrationDone((state == SipSessionState.REGISTERING)
                             ? getExpiryTime(((ResponseEvent) evt).getResponse())
                             : -1);
@@ -704,9 +767,15 @@
                 case Response.UNAUTHORIZED:
                 case Response.PROXY_AUTHENTICATION_REQUIRED:
                     if (!handleAuthentication(event)) {
-                        Log.v(TAG, "Incorrect username/password");
-                        onRegistrationFailed(SipErrorCode.INVALID_CREDENTIALS,
-                                "incorrect username or password");
+                        if (mLastNonce == null) {
+                            onRegistrationFailed(SipErrorCode.SERVER_ERROR,
+                                    "server does not provide challenge");
+                        } else {
+                            Log.v(TAG, "Incorrect username/password");
+                            onRegistrationFailed(
+                                    SipErrorCode.INVALID_CREDENTIALS,
+                                    "incorrect username or password");
+                        }
                     }
                     return true;
                 default:
@@ -724,7 +793,8 @@
             Response response = event.getResponse();
             String nonce = getNonceFromResponse(response);
             if (((nonce != null) && nonce.equals(mLastNonce)) ||
-                    (nonce == mLastNonce)) {
+                    (nonce == null)) {
+                mLastNonce = nonce;
                 return false;
             } else {
                 mClientTransaction = mSipHelper.handleChallenge(
@@ -757,9 +827,12 @@
         }
 
         private String getNonceFromResponse(Response response) {
-            WWWAuthenticate authHeader = (WWWAuthenticate)(response.getHeader(
-                    SIPHeaderNames.WWW_AUTHENTICATE));
-            return (authHeader == null) ? null : authHeader.getNonce();
+            WWWAuthenticate wwwAuth = (WWWAuthenticate)response.getHeader(
+                    SIPHeaderNames.WWW_AUTHENTICATE);
+            if (wwwAuth != null) return wwwAuth.getNonce();
+            ProxyAuthenticate proxyAuth = (ProxyAuthenticate)response.getHeader(
+                    SIPHeaderNames.PROXY_AUTHENTICATE);
+            return (proxyAuth == null) ? null : proxyAuth.getNonce();
         }
 
         private boolean readyForCall(EventObject evt) throws SipException {
@@ -774,6 +847,7 @@
                 addSipSession(this);
                 mState = SipSessionState.OUTGOING_CALL;
                 mProxy.onCalling(this);
+                startSessionTimer(cmd.getTimeout());
                 return true;
             } else if (evt instanceof RegisterCommand) {
                 int duration = ((RegisterCommand) evt).getDuration();
@@ -805,6 +879,7 @@
                         ((MakeCallCommand) evt).getSessionDescription(),
                         mServerTransaction);
                 mState = SipSessionState.INCOMING_CALL_ANSWERING;
+                startSessionTimer(((MakeCallCommand) evt).getTimeout());
                 return true;
             } else if (END_CALL == evt) {
                 mSipHelper.sendInviteBusyHere(mInviteReceived,
@@ -847,6 +922,7 @@
                     if (mState == SipSessionState.OUTGOING_CALL) {
                         mState = SipSessionState.OUTGOING_CALL_RING_BACK;
                         mProxy.onRingingBack(this);
+                        cancelSessionTimer();
                     }
                     return true;
                 case Response.OK:
@@ -854,11 +930,15 @@
                     mPeerSessionDescription = extractContent(response);
                     establishCall();
                     return true;
+                case Response.UNAUTHORIZED:
                 case Response.PROXY_AUTHENTICATION_REQUIRED:
                     if (handleAuthentication(event)) {
                         addSipSession(this);
+                    } else if (mLastNonce == null) {
+                        onError(SipErrorCode.SERVER_ERROR,
+                                "server does not provide challenge");
                     } else {
-                        endCallOnError(SipErrorCode.INVALID_CREDENTIALS,
+                        onError(SipErrorCode.INVALID_CREDENTIALS,
                                 "incorrect username or password");
                     }
                     return true;
@@ -884,6 +964,7 @@
                 // response.
                 mSipHelper.sendCancel(mClientTransaction);
                 mState = SipSessionState.OUTGOING_CALL_CANCELING;
+                startSessionTimer(CANCEL_CALL_TIMER);
                 return true;
             }
             return false;
@@ -896,9 +977,13 @@
                 Response response = event.getResponse();
                 int statusCode = response.getStatusCode();
                 if (expectResponse(Request.CANCEL, evt)) {
-                    if (statusCode == Response.OK) {
-                        // do nothing; wait for REQUEST_TERMINATED
-                        return true;
+                    switch (statusCode) {
+                        case Response.OK:
+                            // do nothing; wait for REQUEST_TERMINATED
+                            return true;
+                        case Response.REQUEST_TERMINATED:
+                            endCallNormally();
+                            return true;
                     }
                 } else if (expectResponse(Request.INVITE, evt)) {
                     if (statusCode == Response.OK) {
@@ -948,11 +1033,27 @@
                 mClientTransaction = mSipHelper.sendReinvite(mDialog,
                         ((MakeCallCommand) evt).getSessionDescription());
                 mState = SipSessionState.OUTGOING_CALL;
+                startSessionTimer(((MakeCallCommand) evt).getTimeout());
                 return true;
             }
             return false;
         }
 
+        // timeout in seconds
+        private void startSessionTimer(int timeout) {
+            if (timeout > 0) {
+                mTimer = new SessionTimer();
+                mTimer.start(timeout);
+            }
+        }
+
+        private void cancelSessionTimer() {
+            if (mTimer != null) {
+                mTimer.cancel();
+                mTimer = null;
+            }
+        }
+
         private String createErrorMessage(Response response) {
             return String.format(SERVER_ERROR_PREFIX + "%s (%d)",
                     response.getReasonPhrase(), response.getStatusCode());
@@ -961,19 +1062,13 @@
         private void establishCall() {
             mState = SipSessionState.IN_CALL;
             mInCall = true;
+            cancelSessionTimer();
             mProxy.onCallEstablished(this, mPeerSessionDescription);
         }
 
-        private void fallbackToPreviousInCall(Throwable exception) {
-            exception = getRootCause(exception);
-            fallbackToPreviousInCall(getErrorCode(exception),
-                    exception.toString());
-        }
-
-        private void fallbackToPreviousInCall(SipErrorCode errorCode,
-                String message) {
+        private void fallbackToPreviousInCall(int errorCode, String message) {
             mState = SipSessionState.IN_CALL;
-            mProxy.onCallChangeFailed(this, errorCode.toString(), message);
+            mProxy.onCallChangeFailed(this, errorCode, message);
         }
 
         private void endCallNormally() {
@@ -981,9 +1076,9 @@
             mProxy.onCallEnded(this);
         }
 
-        private void endCallOnError(SipErrorCode errorCode, String message) {
+        private void endCallOnError(int errorCode, String message) {
             reset();
-            mProxy.onError(this, errorCode.toString(), message);
+            mProxy.onError(this, errorCode, message);
         }
 
         private void endCallOnBusy() {
@@ -991,14 +1086,16 @@
             mProxy.onCallBusy(this);
         }
 
-        private void onError(SipErrorCode errorCode, String message) {
+        private void onError(int errorCode, String message) {
+            cancelSessionTimer();
             switch (mState) {
-                case REGISTERING:
-                case DEREGISTERING:
+                case SipSessionState.REGISTERING:
+                case SipSessionState.DEREGISTERING:
                     onRegistrationFailed(errorCode, message);
                     break;
                 default:
-                    if (mInCall) {
+                    if ((errorCode != SipErrorCode.DATA_CONNECTION_LOST)
+                            && mInCall) {
                         fallbackToPreviousInCall(errorCode, message);
                     } else {
                         endCallOnError(errorCode, message);
@@ -1014,21 +1111,31 @@
 
         private void onError(Response response) {
             int statusCode = response.getStatusCode();
-            if (!mInCall && ((statusCode == Response.TEMPORARILY_UNAVAILABLE)
-                    || (statusCode == Response.BUSY_HERE))) {
+            if (!mInCall && (statusCode == Response.BUSY_HERE)) {
                 endCallOnBusy();
             } else {
                 onError(getErrorCode(statusCode), createErrorMessage(response));
             }
         }
 
-        private SipErrorCode getErrorCode(int responseStatusCode) {
+        private int getErrorCode(int responseStatusCode) {
             switch (responseStatusCode) {
+                case Response.TEMPORARILY_UNAVAILABLE:
+                case Response.FORBIDDEN:
+                case Response.GONE:
                 case Response.NOT_FOUND:
+                case Response.NOT_ACCEPTABLE:
+                case Response.NOT_ACCEPTABLE_HERE:
+                    return SipErrorCode.PEER_NOT_REACHABLE;
+
+                case Response.REQUEST_URI_TOO_LONG:
                 case Response.ADDRESS_INCOMPLETE:
+                case Response.AMBIGUOUS:
                     return SipErrorCode.INVALID_REMOTE_URI;
+
                 case Response.REQUEST_TIMEOUT:
                     return SipErrorCode.TIME_OUT;
+
                 default:
                     if (responseStatusCode < 500) {
                         return SipErrorCode.CLIENT_ERROR;
@@ -1047,7 +1154,7 @@
             return exception;
         }
 
-        private SipErrorCode getErrorCode(Throwable exception) {
+        private int getErrorCode(Throwable exception) {
             String message = exception.getMessage();
             if (exception instanceof UnknownHostException) {
                 return SipErrorCode.INVALID_REMOTE_URI;
@@ -1065,10 +1172,9 @@
             mProxy.onRegistrationDone(this, duration);
         }
 
-        private void onRegistrationFailed(SipErrorCode errorCode,
-                String message) {
+        private void onRegistrationFailed(int errorCode, String message) {
             reset();
-            mProxy.onRegistrationFailed(this, errorCode.toString(), message);
+            mProxy.onRegistrationFailed(this, errorCode, message);
         }
 
         private void onRegistrationFailed(Throwable exception) {
@@ -1148,13 +1254,41 @@
                     .setPort(uri.getPort())
                     .setDisplayName(address.getDisplayName())
                     .build();
-        } catch (InvalidArgumentException e) {
+        } catch (IllegalArgumentException e) {
             throw new SipException("createPeerProfile()", e);
         } catch (ParseException e) {
             throw new SipException("createPeerProfile()", e);
         }
     }
 
+    private static boolean isLoggable(SipSessionImpl s) {
+        if (s != null) {
+            switch (s.mState) {
+                case SipSessionState.PINGING:
+                    return DEBUG_PING;
+            }
+        }
+        return DEBUG;
+    }
+
+    private static boolean isLoggable(SipSessionImpl s, EventObject evt) {
+        if (!isLoggable(s)) return false;
+        if (evt == null) return false;
+
+        if (evt instanceof OptionsCommand) {
+            return DEBUG_PING;
+        } else if (evt instanceof ResponseEvent) {
+            Response response = ((ResponseEvent) evt).getResponse();
+            if (Request.OPTIONS.equals(response.getHeader(CSeqHeader.NAME))) {
+                return DEBUG_PING;
+            }
+            return DEBUG;
+        } else if (evt instanceof RequestEvent) {
+            return DEBUG;
+        }
+        return false;
+    }
+
     private static String log(EventObject evt) {
         if (evt instanceof RequestEvent) {
             return ((RequestEvent) evt).getRequest().toString();
@@ -1186,11 +1320,18 @@
 
     private class MakeCallCommand extends EventObject {
         private String mSessionDescription;
+        private int mTimeout; // in seconds
 
         public MakeCallCommand(SipProfile peerProfile,
                 String sessionDescription) {
+            this(peerProfile, sessionDescription, -1);
+        }
+
+        public MakeCallCommand(SipProfile peerProfile,
+                String sessionDescription, int timeout) {
             super(peerProfile);
             mSessionDescription = sessionDescription;
+            mTimeout = timeout;
         }
 
         public SipProfile getPeerProfile() {
@@ -1200,6 +1341,9 @@
         public String getSessionDescription() {
             return mSessionDescription;
         }
-    }
 
+        public int getTimeout() {
+            return mTimeout;
+        }
+    }
 }
diff --git a/services/java/com/android/server/sip/SipSessionListenerProxy.java b/services/java/com/android/server/sip/SipSessionListenerProxy.java
index 747d79f..a4cd102 100644
--- a/services/java/com/android/server/sip/SipSessionListenerProxy.java
+++ b/services/java/com/android/server/sip/SipSessionListenerProxy.java
@@ -124,7 +124,7 @@
     }
 
     public void onCallChangeFailed(final ISipSession session,
-            final String errorCode, final String message) {
+            final int errorCode, final String message) {
         if (mListener == null) return;
         proxy(new Runnable() {
             public void run() {
@@ -137,7 +137,7 @@
         });
     }
 
-    public void onError(final ISipSession session, final String errorCode,
+    public void onError(final ISipSession session, final int errorCode,
             final String message) {
         if (mListener == null) return;
         proxy(new Runnable() {
@@ -179,7 +179,7 @@
     }
 
     public void onRegistrationFailed(final ISipSession session,
-            final String errorCode, final String message) {
+            final int errorCode, final String message) {
         if (mListener == null) return;
         proxy(new Runnable() {
             public void run() {
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index 6dd619c5..d27c2c6 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -49,8 +49,6 @@
     jmethodID notifyConfigurationChanged;
     jmethodID notifyLidSwitchChanged;
     jmethodID notifyInputChannelBroken;
-    jmethodID notifyInputChannelANR;
-    jmethodID notifyInputChannelRecoveredFromANR;
     jmethodID notifyANR;
     jmethodID virtualKeyDownFeedback;
     jmethodID interceptKeyBeforeQueueing;
@@ -85,6 +83,7 @@
     jclass clazz;
 
     jfieldID inputChannel;
+    jfieldID name;
     jfieldID layoutParamsFlags;
     jfieldID layoutParamsType;
     jfieldID dispatchingTimeoutNanos;
@@ -101,9 +100,11 @@
     jfieldID touchableAreaRight;
     jfieldID touchableAreaBottom;
     jfieldID visible;
+    jfieldID canReceiveKeys;
     jfieldID hasFocus;
     jfieldID hasWallpaper;
     jfieldID paused;
+    jfieldID layer;
     jfieldID ownerPid;
     jfieldID ownerUid;
 } gInputWindowClassInfo;
@@ -168,7 +169,6 @@
     void setInputWindows(JNIEnv* env, jobjectArray windowObjArray);
     void setFocusedApplication(JNIEnv* env, jobject applicationObj);
     void setInputDispatchMode(bool enabled, bool frozen);
-    void preemptInputDispatch();
 
     /* --- InputReaderPolicyInterface implementation --- */
 
@@ -191,10 +191,9 @@
     /* --- InputDispatcherPolicyInterface implementation --- */
 
     virtual void notifyConfigurationChanged(nsecs_t when);
-    virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle);
+    virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
+            const sp<InputChannel>& inputChannel);
     virtual void notifyInputChannelBroken(const sp<InputChannel>& inputChannel);
-    virtual nsecs_t notifyInputChannelANR(const sp<InputChannel>& inputChannel);
-    virtual void notifyInputChannelRecoveredFromANR(const sp<InputChannel>& inputChannel);
     virtual nsecs_t getKeyRepeatTimeout();
     virtual nsecs_t getKeyRepeatDelay();
     virtual int32_t getMaxEventsPerSecond();
@@ -409,10 +408,15 @@
 
 jobject NativeInputManager::getInputChannelObjLocal(JNIEnv* env,
         const sp<InputChannel>& inputChannel) {
+    InputChannel* inputChannelPtr = inputChannel.get();
+    if (! inputChannelPtr) {
+        return NULL;
+    }
+
     {
         AutoMutex _l(mInputChannelRegistryLock);
 
-        ssize_t index = mInputChannelObjWeakTable.indexOfKey(inputChannel.get());
+        ssize_t index = mInputChannelObjWeakTable.indexOfKey(inputChannelPtr);
         if (index < 0) {
             return NULL;
         }
@@ -702,32 +706,34 @@
     checkAndClearExceptionFromCallback(env, "notifyConfigurationChanged");
 }
 
-nsecs_t NativeInputManager::notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle) {
+nsecs_t NativeInputManager::notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
+        const sp<InputChannel>& inputChannel) {
 #if DEBUG_INPUT_DISPATCHER_POLICY
     LOGD("notifyANR");
 #endif
 
     JNIEnv* env = jniEnv();
 
-    ApplicationToken* token = static_cast<ApplicationToken*>(inputApplicationHandle.get());
-    jweak tokenObjWeak = token->getTokenObj();
-
-    jlong newTimeout;
-    jobject tokenObjLocal = env->NewLocalRef(tokenObjWeak);
-    if (tokenObjLocal) {
-        newTimeout = env->CallLongMethod(mCallbacksObj,
-                gCallbacksClassInfo.notifyANR, tokenObjLocal);
-        if (checkAndClearExceptionFromCallback(env, "notifyANR")) {
-            newTimeout = 0; // abort dispatch
-        } else {
-            assert(newTimeout >= 0);
-        }
-
-        env->DeleteLocalRef(tokenObjLocal);
+    jobject tokenObjLocal;
+    if (inputApplicationHandle.get()) {
+        ApplicationToken* token = static_cast<ApplicationToken*>(inputApplicationHandle.get());
+        jweak tokenObjWeak = token->getTokenObj();
+        tokenObjLocal = env->NewLocalRef(tokenObjWeak);
     } else {
-        newTimeout = 0; // abort dispatch
+        tokenObjLocal = NULL;
     }
 
+    jobject inputChannelObjLocal = getInputChannelObjLocal(env, inputChannel);
+    jlong newTimeout = env->CallLongMethod(mCallbacksObj,
+                gCallbacksClassInfo.notifyANR, tokenObjLocal, inputChannelObjLocal);
+    if (checkAndClearExceptionFromCallback(env, "notifyANR")) {
+        newTimeout = 0; // abort dispatch
+    } else {
+        assert(newTimeout >= 0);
+    }
+
+    env->DeleteLocalRef(tokenObjLocal);
+    env->DeleteLocalRef(inputChannelObjLocal);
     return newTimeout;
 }
 
@@ -748,51 +754,6 @@
     }
 }
 
-nsecs_t NativeInputManager::notifyInputChannelANR(const sp<InputChannel>& inputChannel) {
-#if DEBUG_INPUT_DISPATCHER_POLICY
-    LOGD("notifyInputChannelANR - inputChannel='%s'",
-            inputChannel->getName().string());
-#endif
-
-    JNIEnv* env = jniEnv();
-
-    jlong newTimeout;
-    jobject inputChannelObjLocal = getInputChannelObjLocal(env, inputChannel);
-    if (inputChannelObjLocal) {
-        newTimeout = env->CallLongMethod(mCallbacksObj,
-                gCallbacksClassInfo.notifyInputChannelANR, inputChannelObjLocal);
-        if (checkAndClearExceptionFromCallback(env, "notifyInputChannelANR")) {
-            newTimeout = 0; // abort dispatch
-        } else {
-            assert(newTimeout >= 0);
-        }
-
-        env->DeleteLocalRef(inputChannelObjLocal);
-    } else {
-        newTimeout = 0; // abort dispatch
-    }
-
-    return newTimeout;
-}
-
-void NativeInputManager::notifyInputChannelRecoveredFromANR(const sp<InputChannel>& inputChannel) {
-#if DEBUG_INPUT_DISPATCHER_POLICY
-    LOGD("notifyInputChannelRecoveredFromANR - inputChannel='%s'",
-            inputChannel->getName().string());
-#endif
-
-    JNIEnv* env = jniEnv();
-
-    jobject inputChannelObjLocal = getInputChannelObjLocal(env, inputChannel);
-    if (inputChannelObjLocal) {
-        env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.notifyInputChannelRecoveredFromANR,
-                inputChannelObjLocal);
-        checkAndClearExceptionFromCallback(env, "notifyInputChannelRecoveredFromANR");
-
-        env->DeleteLocalRef(inputChannelObjLocal);
-    }
-}
-
 nsecs_t NativeInputManager::getKeyRepeatTimeout() {
     if (! isScreenOn()) {
         // Disable key repeat when the screen is off.
@@ -855,6 +816,8 @@
         sp<InputChannel> inputChannel =
                 android_view_InputChannel_getInputChannel(env, inputChannelObj);
         if (inputChannel != NULL) {
+            jstring name = jstring(env->GetObjectField(windowObj,
+                    gInputWindowClassInfo.name));
             jint layoutParamsFlags = env->GetIntField(windowObj,
                     gInputWindowClassInfo.layoutParamsFlags);
             jint layoutParamsType = env->GetIntField(windowObj,
@@ -887,18 +850,25 @@
                     gInputWindowClassInfo.touchableAreaBottom);
             jboolean visible = env->GetBooleanField(windowObj,
                     gInputWindowClassInfo.visible);
+            jboolean canReceiveKeys = env->GetBooleanField(windowObj,
+                    gInputWindowClassInfo.canReceiveKeys);
             jboolean hasFocus = env->GetBooleanField(windowObj,
                     gInputWindowClassInfo.hasFocus);
             jboolean hasWallpaper = env->GetBooleanField(windowObj,
                     gInputWindowClassInfo.hasWallpaper);
             jboolean paused = env->GetBooleanField(windowObj,
                     gInputWindowClassInfo.paused);
+            jint layer = env->GetIntField(windowObj,
+                    gInputWindowClassInfo.layer);
             jint ownerPid = env->GetIntField(windowObj,
                     gInputWindowClassInfo.ownerPid);
             jint ownerUid = env->GetIntField(windowObj,
                     gInputWindowClassInfo.ownerUid);
 
+            const char* nameStr = env->GetStringUTFChars(name, NULL);
+
             outWindow.inputChannel = inputChannel;
+            outWindow.name.setTo(nameStr);
             outWindow.layoutParamsFlags = layoutParamsFlags;
             outWindow.layoutParamsType = layoutParamsType;
             outWindow.dispatchingTimeout = dispatchingTimeoutNanos;
@@ -915,11 +885,15 @@
             outWindow.touchableAreaRight = touchableAreaRight;
             outWindow.touchableAreaBottom = touchableAreaBottom;
             outWindow.visible = visible;
+            outWindow.canReceiveKeys = canReceiveKeys;
             outWindow.hasFocus = hasFocus;
             outWindow.hasWallpaper = hasWallpaper;
             outWindow.paused = paused;
+            outWindow.layer = layer;
             outWindow.ownerPid = ownerPid;
             outWindow.ownerUid = ownerUid;
+
+            env->ReleaseStringUTFChars(name, nameStr);
             valid = true;
         } else {
             LOGW("Dropping input target because its input channel is not initialized.");
@@ -973,10 +947,6 @@
     mInputManager->getDispatcher()->setInputDispatchMode(enabled, frozen);
 }
 
-void NativeInputManager::preemptInputDispatch() {
-    mInputManager->getDispatcher()->preemptInputDispatch();
-}
-
 bool NativeInputManager::interceptKeyBeforeDispatching(const sp<InputChannel>& inputChannel,
         const KeyEvent* keyEvent, uint32_t policyFlags) {
     bool isScreenOn = this->isScreenOn();
@@ -986,23 +956,17 @@
 
     JNIEnv* env = jniEnv();
 
+    // Note: inputChannel may be null.
     jobject inputChannelObj = getInputChannelObjLocal(env, inputChannel);
-    if (inputChannelObj) {
-        jboolean consumed = env->CallBooleanMethod(mCallbacksObj,
-                gCallbacksClassInfo.interceptKeyBeforeDispatching,
-                inputChannelObj, keyEvent->getAction(), keyEvent->getFlags(),
-                keyEvent->getKeyCode(), keyEvent->getMetaState(),
-                keyEvent->getRepeatCount(), policyFlags);
-        bool error = checkAndClearExceptionFromCallback(env, "interceptKeyBeforeDispatching");
+    jboolean consumed = env->CallBooleanMethod(mCallbacksObj,
+            gCallbacksClassInfo.interceptKeyBeforeDispatching,
+            inputChannelObj, keyEvent->getAction(), keyEvent->getFlags(),
+            keyEvent->getKeyCode(), keyEvent->getMetaState(),
+            keyEvent->getRepeatCount(), policyFlags);
+    bool error = checkAndClearExceptionFromCallback(env, "interceptKeyBeforeDispatching");
 
-        env->DeleteLocalRef(inputChannelObj);
-
-        return consumed && ! error;
-    } else {
-        LOGW("Could not apply key dispatch policy because input channel '%s' is "
-                "no longer valid.", inputChannel->getName().string());
-        return false;
-    }
+    env->DeleteLocalRef(inputChannelObj);
+    return consumed && ! error;
 }
 
 void NativeInputManager::pokeUserActivity(nsecs_t eventTime, int32_t windowType, int32_t eventType) {
@@ -1246,15 +1210,6 @@
     gNativeInputManager->setInputDispatchMode(enabled, frozen);
 }
 
-static void android_server_InputManager_nativePreemptInputDispatch(JNIEnv* env,
-        jclass clazz) {
-    if (checkInputManagerUnitialized(env)) {
-        return;
-    }
-
-    gNativeInputManager->preemptInputDispatch();
-}
-
 static jobject android_server_InputManager_nativeGetInputDevice(JNIEnv* env,
         jclass clazz, jint deviceId) {
     if (checkInputManagerUnitialized(env)) {
@@ -1357,8 +1312,6 @@
             (void*) android_server_InputManager_nativeSetFocusedApplication },
     { "nativeSetInputDispatchMode", "(ZZ)V",
             (void*) android_server_InputManager_nativeSetInputDispatchMode },
-    { "nativePreemptInputDispatch", "()V",
-            (void*) android_server_InputManager_nativePreemptInputDispatch },
     { "nativeGetInputDevice", "(I)Landroid/view/InputDevice;",
             (void*) android_server_InputManager_nativeGetInputDevice },
     { "nativeGetInputDeviceIds", "()[I",
@@ -1398,14 +1351,8 @@
     GET_METHOD_ID(gCallbacksClassInfo.notifyInputChannelBroken, gCallbacksClassInfo.clazz,
             "notifyInputChannelBroken", "(Landroid/view/InputChannel;)V");
 
-    GET_METHOD_ID(gCallbacksClassInfo.notifyInputChannelANR, gCallbacksClassInfo.clazz,
-            "notifyInputChannelANR", "(Landroid/view/InputChannel;)J");
-
-    GET_METHOD_ID(gCallbacksClassInfo.notifyInputChannelRecoveredFromANR, gCallbacksClassInfo.clazz,
-            "notifyInputChannelRecoveredFromANR", "(Landroid/view/InputChannel;)V");
-
     GET_METHOD_ID(gCallbacksClassInfo.notifyANR, gCallbacksClassInfo.clazz,
-            "notifyANR", "(Ljava/lang/Object;)J");
+            "notifyANR", "(Ljava/lang/Object;Landroid/view/InputChannel;)J");
 
     GET_METHOD_ID(gCallbacksClassInfo.virtualKeyDownFeedback, gCallbacksClassInfo.clazz,
             "virtualKeyDownFeedback", "()V");
@@ -1477,6 +1424,9 @@
     GET_FIELD_ID(gInputWindowClassInfo.inputChannel, gInputWindowClassInfo.clazz,
             "inputChannel", "Landroid/view/InputChannel;");
 
+    GET_FIELD_ID(gInputWindowClassInfo.name, gInputWindowClassInfo.clazz,
+            "name", "Ljava/lang/String;");
+
     GET_FIELD_ID(gInputWindowClassInfo.layoutParamsFlags, gInputWindowClassInfo.clazz,
             "layoutParamsFlags", "I");
 
@@ -1525,6 +1475,9 @@
     GET_FIELD_ID(gInputWindowClassInfo.visible, gInputWindowClassInfo.clazz,
             "visible", "Z");
 
+    GET_FIELD_ID(gInputWindowClassInfo.canReceiveKeys, gInputWindowClassInfo.clazz,
+            "canReceiveKeys", "Z");
+
     GET_FIELD_ID(gInputWindowClassInfo.hasFocus, gInputWindowClassInfo.clazz,
             "hasFocus", "Z");
 
@@ -1534,6 +1487,9 @@
     GET_FIELD_ID(gInputWindowClassInfo.paused, gInputWindowClassInfo.clazz,
             "paused", "Z");
 
+    GET_FIELD_ID(gInputWindowClassInfo.layer, gInputWindowClassInfo.clazz,
+            "layer", "I");
+
     GET_FIELD_ID(gInputWindowClassInfo.ownerPid, gInputWindowClassInfo.clazz,
             "ownerPid", "I");
 
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 3025f77..e204e04 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -529,7 +529,7 @@
     LOGE_IF(size<0, "dropping %d events on the floor (%s)",
             count, strerror(-size));
 
-    return size < 0 ? size : NO_ERROR;
+    return size < 0 ? status_t(size) : status_t(NO_ERROR);
 }
 
 sp<SensorChannel> SensorService::SensorEventConnection::getSensorChannel() const
diff --git a/services/sensorservice/tests/sensorservicetest.cpp b/services/sensorservice/tests/sensorservicetest.cpp
index e464713..42bf983 100644
--- a/services/sensorservice/tests/sensorservicetest.cpp
+++ b/services/sensorservice/tests/sensorservicetest.cpp
@@ -18,11 +18,11 @@
 #include <gui/Sensor.h>
 #include <gui/SensorManager.h>
 #include <gui/SensorEventQueue.h>
-#include <utils/PollLoop.h>
+#include <utils/Looper.h>
 
 using namespace android;
 
-bool receiver(int fd, int events, void* data)
+int receiver(int fd, int events, void* data)
 {
     sp<SensorEventQueue> q((SensorEventQueue*)data);
     ssize_t n;
@@ -41,7 +41,7 @@
     if (n<0 && n != -EAGAIN) {
         printf("error reading events (%s)\n", strerror(-n));
     }
-    return true;
+    return 1;
 }
 
 
@@ -51,7 +51,7 @@
 
     Sensor const* const* list;
     ssize_t count = mgr.getSensorList(&list);
-    printf("numSensors=%d\n", count);
+    printf("numSensors=%d\n", int(count));
 
     sp<SensorEventQueue> q = mgr.createEventQueue();
     printf("queue=%p\n", q.get());
@@ -63,13 +63,16 @@
 
     q->setEventRate(accelerometer, ms2ns(10));
 
-    sp<PollLoop> loop = new PollLoop(false);
-    loop->setCallback(q->getFd(), POLLIN, receiver, q.get());
+    sp<Looper> loop = new Looper(false);
+    loop->addFd(q->getFd(), 0, ALOOPER_EVENT_INPUT, receiver, q.get());
 
     do {
         //printf("about to poll...\n");
-        int32_t ret = loop->pollOnce(-1, 0, 0);
+        int32_t ret = loop->pollOnce(-1);
         switch (ret) {
+            case ALOOPER_POLL_WAKE:
+                //("ALOOPER_POLL_WAKE\n");
+                break;
             case ALOOPER_POLL_CALLBACK:
                 //("ALOOPER_POLL_CALLBACK\n");
                 break;
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index 2eac0a8..0515110 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -296,6 +296,10 @@
     return mNativeWindow->compositionComplete();
 }
 
+int DisplayHardware::getCurrentBufferIndex() const {
+    return mNativeWindow->getCurrentBufferIndex();
+}
+
 void DisplayHardware::flip(const Region& dirty) const
 {
     checkGLErrors();
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.h b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
index 66bf521..2d7900c 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
@@ -87,6 +87,9 @@
         return Rect(mWidth, mHeight);
     }
 
+    // only for debugging
+    int getCurrentBufferIndex() const;
+
 private:
     void init(uint32_t displayIndex) __attribute__((noinline));
     void fini() __attribute__((noinline));
diff --git a/services/surfaceflinger/GLExtensions.cpp b/services/surfaceflinger/GLExtensions.cpp
index 7f4f9fc..850866a 100644
--- a/services/surfaceflinger/GLExtensions.cpp
+++ b/services/surfaceflinger/GLExtensions.cpp
@@ -86,7 +86,7 @@
         mHaveNpot = true;
     }
 
-    if (hasExtension("GL_OES_texture_external")) {
+    if (hasExtension("GL_OES_EGL_image_external")) {
         mHaveTextureExternal = true;
     } else if (strstr(mRenderer.string(), "Adreno")) {
         // hack for Adreno 200
diff --git a/services/surfaceflinger/LayerBlur.cpp b/services/surfaceflinger/LayerBlur.cpp
index 2ee21b9..4cfcfe3 100644
--- a/services/surfaceflinger/LayerBlur.cpp
+++ b/services/surfaceflinger/LayerBlur.cpp
@@ -146,7 +146,7 @@
     Region::const_iterator it = clip.begin();
     Region::const_iterator const end = clip.end();
     if (it != end) {
-#if defined(GL_OES_texture_external)
+#if defined(GL_OES_EGL_image_external)
         if (GLExtensions::getInstance().haveTextureExternal()) {
             glDisable(GL_TEXTURE_EXTERNAL_OES);
         }
diff --git a/services/surfaceflinger/LayerDim.cpp b/services/surfaceflinger/LayerDim.cpp
index a1f339e..80cc52c 100644
--- a/services/surfaceflinger/LayerDim.cpp
+++ b/services/surfaceflinger/LayerDim.cpp
@@ -71,7 +71,7 @@
         glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
         glColor4f(0, 0, 0, alpha);
 
-#if defined(GL_OES_texture_external)
+#if defined(GL_OES_EGL_image_external)
         if (GLExtensions::getInstance().haveTextureExternal()) {
             glDisable(GL_TEXTURE_EXTERNAL_OES);
         }
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 637ae48..dc241d4e 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -38,6 +38,7 @@
 #include <utils/StopWatch.h>
 
 #include <ui/GraphicBufferAllocator.h>
+#include <ui/GraphicLog.h>
 #include <ui/PixelFormat.h>
 
 #include <pixelflinger/pixelflinger.h>
@@ -371,15 +372,25 @@
     const DisplayHardware& hw(graphicPlane(0).displayHardware());
     if (LIKELY(hw.canDraw() && !isFrozen())) {
         // repaint the framebuffer (if needed)
+
+        const int index = hw.getCurrentBufferIndex();
+        GraphicLog& logger(GraphicLog::getInstance());
+
+        logger.log(GraphicLog::SF_REPAINT, index);
         handleRepaint();
 
         // inform the h/w that we're done compositing
+        logger.log(GraphicLog::SF_COMPOSITION_COMPLETE, index);
         hw.compositionComplete();
 
         // release the clients before we flip ('cause flip might block)
+        logger.log(GraphicLog::SF_UNLOCK_CLIENTS, index);
         unlockClients();
 
+        logger.log(GraphicLog::SF_SWAP_BUFFERS, index);
         postFramebuffer();
+
+        logger.log(GraphicLog::SF_REPAINT_DONE, index);
     } else {
         // pretend we did the post
         unlockClients();
@@ -906,7 +917,7 @@
         glVertexPointer(2, GL_SHORT, 0, vertices);
         glTexCoordPointer(2, GL_SHORT, 0, tcoords);
         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-#if defined(GL_OES_texture_external)
+#if defined(GL_OES_EGL_image_external)
         if (GLExtensions::getInstance().haveTextureExternal()) {
             glDisable(GL_TEXTURE_EXTERNAL_OES);
         }
@@ -1470,8 +1481,7 @@
         int n;
         switch (code) {
             case 1000: // SHOW_CPU, NOT SUPPORTED ANYMORE
-                return NO_ERROR;
-            case 1001:  // SHOW_FPS, NOT SUPPORTED ANYMORE
+            case 1001: // SHOW_FPS, NOT SUPPORTED ANYMORE
                 return NO_ERROR;
             case 1002:  // SHOW_UPDATES
                 n = data.readInt32();
@@ -1492,6 +1502,11 @@
                 setTransactionFlags(eTransactionNeeded|eTraversalNeeded);
                 return NO_ERROR;
             }
+            case 1006:{ // enable/disable GraphicLog
+                int enabled = data.readInt32();
+                GraphicLog::getInstance().setEnabled(enabled);
+                return NO_ERROR;
+            }
             case 1007: // set mFreezeCount
                 mFreezeCount = data.readInt32();
                 mFreezeDisplayTime = 0;
diff --git a/services/surfaceflinger/TextureManager.cpp b/services/surfaceflinger/TextureManager.cpp
index 76f6159..c9a15f5 100644
--- a/services/surfaceflinger/TextureManager.cpp
+++ b/services/surfaceflinger/TextureManager.cpp
@@ -43,7 +43,7 @@
 }
 
 GLenum TextureManager::getTextureTarget(const Image* image) {
-#if defined(GL_OES_texture_external)
+#if defined(GL_OES_EGL_image_external)
     switch (image->target) {
         case Texture::TEXTURE_EXTERNAL:
             return GL_TEXTURE_EXTERNAL_OES;
@@ -85,7 +85,7 @@
     pImage->height = 0;
 
     GLenum target = GL_TEXTURE_2D;
-#if defined(GL_OES_texture_external)
+#if defined(GL_OES_EGL_image_external)
     if (GLExtensions::getInstance().haveTextureExternal()) {
         if (format && isYuvFormat(format)) {
             target = GL_TEXTURE_EXTERNAL_OES;
@@ -306,7 +306,7 @@
     if (target == GL_TEXTURE_2D) {
         glBindTexture(GL_TEXTURE_2D, texture.name);
         glEnable(GL_TEXTURE_2D);
-#if defined(GL_OES_texture_external)
+#if defined(GL_OES_EGL_image_external)
         if (GLExtensions::getInstance().haveTextureExternal()) {
             glDisable(GL_TEXTURE_EXTERNAL_OES);
         }
@@ -329,7 +329,7 @@
 void TextureManager::deactivateTextures()
 {
     glDisable(GL_TEXTURE_2D);
-#if defined(GL_OES_texture_external)
+#if defined(GL_OES_EGL_image_external)
     if (GLExtensions::getInstance().haveTextureExternal()) {
         glDisable(GL_TEXTURE_EXTERNAL_OES);
     }
diff --git a/telephony/java/android/telephony/gsm/GsmCellLocation.java b/telephony/java/android/telephony/gsm/GsmCellLocation.java
index c4204fa..313bc82 100644
--- a/telephony/java/android/telephony/gsm/GsmCellLocation.java
+++ b/telephony/java/android/telephony/gsm/GsmCellLocation.java
@@ -60,8 +60,10 @@
     }
 
     /**
+     * On a UMTS network, returns the primary scrambling code of the serving
+     * cell.
+     *
      * @return primary scrambling code for UMTS, -1 if unknown or GSM
-     * @hide
      */
     public int getPsc() {
         return mPsc;
diff --git a/telephony/java/com/android/internal/telephony/CallManager.java b/telephony/java/com/android/internal/telephony/CallManager.java
index 4bf3282..23cb42a 100644
--- a/telephony/java/com/android/internal/telephony/CallManager.java
+++ b/telephony/java/com/android/internal/telephony/CallManager.java
@@ -24,6 +24,7 @@
 import android.os.Handler;
 import android.os.Message;
 import android.os.RegistrantList;
+import android.os.Registrant;
 import android.telephony.PhoneStateListener;
 import android.telephony.ServiceState;
 import android.util.Log;
@@ -54,7 +55,8 @@
 public final class CallManager {
 
     private static final String LOG_TAG ="Phone";
-    private static final boolean LOCAL_DEBUG = true;
+    private static final boolean DBG = true;
+    private static final boolean VDBG = false;
 
     private static final int EVENT_DISCONNECT = 100;
     private static final int EVENT_PRECISE_CALL_STATE_CHANGED = 101;
@@ -75,11 +77,12 @@
     private static final int EVENT_SUBSCRIPTION_INFO_READY = 116;
     private static final int EVENT_SUPP_SERVICE_FAILED = 117;
     private static final int EVENT_SERVICE_STATE_CHANGED = 118;
+    private static final int EVENT_POST_DIAL_CHARACTER = 119;
 
     // Singleton instance
     private static final CallManager INSTANCE = new CallManager();
 
-    // list of registered phones
+    // list of registered phones, which are PhoneBase objs
     private final ArrayList<Phone> mPhones;
 
     // list of supported ringing calls
@@ -94,7 +97,7 @@
     // empty connection list
     private final ArrayList<Connection> emptyConnections = new ArrayList<Connection>();
 
-    // default phone as the first phone registered
+    // default phone as the first phone registered, which is PhoneBase obj
     private Phone mDefaultPhone;
 
     // state registrants
@@ -158,6 +161,9 @@
     protected final RegistrantList mServiceStateChangedRegistrants
     = new RegistrantList();
 
+    protected final RegistrantList mPostDialCharacterRegistrants
+    = new RegistrantList();
+
     private CallManager() {
         mPhones = new ArrayList<Phone>();
         mRingingCalls = new ArrayList<Call>();
@@ -175,6 +181,46 @@
     }
 
     /**
+     * Get the corresponding PhoneBase obj
+     *
+     * @param phone a Phone object
+     * @return the corresponding PhoneBase obj in Phone if Phone
+     * is a PhoneProxy obj
+     * or the Phone itself if Phone is not a PhoneProxy obj
+     */
+    private static Phone getPhoneBase(Phone phone) {
+        if (phone instanceof PhoneProxy) {
+            return phone.getForegroundCall().getPhone();
+        }
+        return phone;
+    }
+
+    /**
+     * Check if two phones refer to the same PhoneBase obj
+     *
+     * Note: PhoneBase, not PhoneProxy, is to be used inside of CallManager
+     *
+     * Both PhoneBase and PhoneProxy implement Phone interface, so
+     * they have same phone APIs, such as dial(). The real implementation, for
+     * example in GSM,  is in GSMPhone as extend from PhoneBase, so that
+     * foregroundCall.getPhone() returns GSMPhone obj. On the other hand,
+     * PhoneFactory.getDefaultPhone() returns PhoneProxy obj, which has a class
+     * member of GSMPhone.
+     *
+     * So for phone returned by PhoneFacotry, which is used by PhoneApp,
+     *        phone.getForegroundCall().getPhone() != phone
+     * but
+     *        isSamePhone(phone, phone.getForegroundCall().getPhone()) == true
+     *
+     * @param p1 is the first Phone obj
+     * @param p2 is the second Phone obj
+     * @return true if p1 and p2 refer to the same phone
+     */
+    public static boolean isSamePhone(Phone p1, Phone p2) {
+        return (getPhoneBase(p1) == getPhoneBase(p2));
+    }
+
+    /**
      * Returns all the registered phone objects.
      * @return all the registered phone objects.
      */
@@ -193,9 +239,9 @@
 
         for (Phone phone : mPhones) {
             if (phone.getState() == Phone.State.RINGING) {
-                return Phone.State.RINGING;
+                s = Phone.State.RINGING;
             } else if (phone.getState() == Phone.State.OFFHOOK) {
-                s = Phone.State.OFFHOOK;
+                if (s == Phone.State.IDLE) s = Phone.State.OFFHOOK;
             }
         }
         return s;
@@ -238,25 +284,50 @@
 
     /**
      * Register phone to CallManager
-     * @param phone
+     * @param phone to be registered
      * @return true if register successfully
      */
     public boolean registerPhone(Phone phone) {
-        if (phone != null && !mPhones.contains(phone)) {
+        Phone basePhone = getPhoneBase(phone);
+
+        if (basePhone != null && !mPhones.contains(basePhone)) {
             if (mPhones.isEmpty()) {
-                mDefaultPhone = phone;
+                mDefaultPhone = basePhone;
             }
-            mPhones.add(phone);
-            mRingingCalls.add(phone.getRingingCall());
-            mBackgroundCalls.add(phone.getBackgroundCall());
-            mForegroundCalls.add(phone.getForegroundCall());
-            registerForPhoneStates(phone);
+            mPhones.add(basePhone);
+            mRingingCalls.add(basePhone.getRingingCall());
+            mBackgroundCalls.add(basePhone.getBackgroundCall());
+            mForegroundCalls.add(basePhone.getForegroundCall());
+            registerForPhoneStates(basePhone);
             return true;
         }
         return false;
     }
 
     /**
+     * unregister phone from CallManager
+     * @param phone to be unregistered
+     */
+    public void unregisterPhone(Phone phone) {
+        Phone basePhone = getPhoneBase(phone);
+
+        if (basePhone != null && mPhones.contains(basePhone)) {
+            mPhones.remove(basePhone);
+            mRingingCalls.remove(basePhone.getRingingCall());
+            mBackgroundCalls.remove(basePhone.getBackgroundCall());
+            mForegroundCalls.remove(basePhone.getForegroundCall());
+            unregisterForPhoneStates(basePhone);
+            if (basePhone == mDefaultPhone) {
+                if (mPhones.isEmpty()) {
+                    mDefaultPhone = null;
+                } else {
+                    mDefaultPhone = mPhones.get(0);
+                }
+            }
+        }
+    }
+
+    /**
      * return the default phone or null if no phone available
      */
     public Phone getDefaultPhone() {
@@ -284,27 +355,6 @@
         return getFirstActiveRingingCall().getPhone();
     }
 
-    /**
-     * unregister phone from CallManager
-     * @param phone
-     */
-    public void unregisterPhone(Phone phone) {
-        if (phone != null && mPhones.contains(phone)) {
-            mPhones.remove(phone);
-            mRingingCalls.remove(phone.getRingingCall());
-            mBackgroundCalls.remove(phone.getBackgroundCall());
-            mForegroundCalls.remove(phone.getForegroundCall());
-            unregisterForPhoneStates(phone);
-            if (phone == mDefaultPhone) {
-                if (mPhones.isEmpty()) {
-                    mDefaultPhone = null;
-                } else {
-                    mDefaultPhone = mPhones.get(0);
-                }
-            }
-        }
-    }
-
     public void setAudioMode() {
         Context context = getContext();
         if (context == null) return;
@@ -334,6 +384,7 @@
     }
 
     private void registerForPhoneStates(Phone phone) {
+        // for common events supported by all phones
         phone.registerForPreciseCallStateChanged(mHandler, EVENT_PRECISE_CALL_STATE_CHANGED, null);
         phone.registerForDisconnect(mHandler, EVENT_DISCONNECT, null);
         phone.registerForNewRingingConnection(mHandler, EVENT_NEW_RINGING_CONNECTION, null);
@@ -342,20 +393,31 @@
         phone.registerForRingbackTone(mHandler, EVENT_RINGBACK_TONE, null);
         phone.registerForInCallVoicePrivacyOn(mHandler, EVENT_IN_CALL_VOICE_PRIVACY_ON, null);
         phone.registerForInCallVoicePrivacyOff(mHandler, EVENT_IN_CALL_VOICE_PRIVACY_OFF, null);
-        phone.registerForCallWaiting(mHandler, EVENT_CALL_WAITING, null);
         phone.registerForDisplayInfo(mHandler, EVENT_DISPLAY_INFO, null);
         phone.registerForSignalInfo(mHandler, EVENT_SIGNAL_INFO, null);
-        phone.registerForCdmaOtaStatusChange(mHandler, EVENT_CDMA_OTA_STATUS_CHANGE, null);
         phone.registerForResendIncallMute(mHandler, EVENT_RESEND_INCALL_MUTE, null);
         phone.registerForMmiInitiate(mHandler, EVENT_MMI_INITIATE, null);
         phone.registerForMmiComplete(mHandler, EVENT_MMI_COMPLETE, null);
-        phone.registerForEcmTimerReset(mHandler, EVENT_ECM_TIMER_RESET, null);
-        phone.registerForSubscriptionInfoReady(mHandler, EVENT_SUBSCRIPTION_INFO_READY, null);
         phone.registerForSuppServiceFailed(mHandler, EVENT_SUPP_SERVICE_FAILED, null);
         phone.registerForServiceStateChanged(mHandler, EVENT_SERVICE_STATE_CHANGED, null);
+
+        // for events supported only by GSM and CDMA phone
+        if (phone.getPhoneType() == Phone.PHONE_TYPE_GSM ||
+                phone.getPhoneType() == Phone.PHONE_TYPE_CDMA) {
+            phone.setOnPostDialCharacter(mHandler, EVENT_POST_DIAL_CHARACTER, null);
+        }
+
+        // for events supported only by CDMA phone
+        if (phone.getPhoneType() == Phone.PHONE_TYPE_CDMA ){
+            phone.registerForCdmaOtaStatusChange(mHandler, EVENT_CDMA_OTA_STATUS_CHANGE, null);
+            phone.registerForSubscriptionInfoReady(mHandler, EVENT_SUBSCRIPTION_INFO_READY, null);
+            phone.registerForCallWaiting(mHandler, EVENT_CALL_WAITING, null);
+            phone.registerForEcmTimerReset(mHandler, EVENT_ECM_TIMER_RESET, null);
+        }
     }
 
     private void unregisterForPhoneStates(Phone phone) {
+        //  for common events supported by all phones
         phone.unregisterForPreciseCallStateChanged(mHandler);
         phone.unregisterForDisconnect(mHandler);
         phone.unregisterForNewRingingConnection(mHandler);
@@ -364,17 +426,27 @@
         phone.unregisterForRingbackTone(mHandler);
         phone.unregisterForInCallVoicePrivacyOn(mHandler);
         phone.unregisterForInCallVoicePrivacyOff(mHandler);
-        phone.unregisterForCallWaiting(mHandler);
         phone.unregisterForDisplayInfo(mHandler);
         phone.unregisterForSignalInfo(mHandler);
-        phone.unregisterForCdmaOtaStatusChange(mHandler);
         phone.unregisterForResendIncallMute(mHandler);
         phone.unregisterForMmiInitiate(mHandler);
         phone.unregisterForMmiComplete(mHandler);
-        phone.unregisterForEcmTimerReset(mHandler);
-        phone.unregisterForSubscriptionInfoReady(mHandler);
         phone.unregisterForSuppServiceFailed(mHandler);
         phone.unregisterForServiceStateChanged(mHandler);
+
+        // for events supported only by GSM and CDMA phone
+        if (phone.getPhoneType() == Phone.PHONE_TYPE_GSM ||
+                phone.getPhoneType() == Phone.PHONE_TYPE_CDMA) {
+            phone.setOnPostDialCharacter(null, EVENT_POST_DIAL_CHARACTER, null);
+        }
+
+        // for events supported only by CDMA phone
+        if (phone.getPhoneType() == Phone.PHONE_TYPE_CDMA ){
+            phone.unregisterForCdmaOtaStatusChange(mHandler);
+            phone.unregisterForSubscriptionInfoReady(mHandler);
+            phone.unregisterForCallWaiting(mHandler);
+            phone.unregisterForEcmTimerReset(mHandler);
+        }
     }
 
     /**
@@ -393,12 +465,16 @@
     public void acceptCall(Call ringingCall) throws CallStateException {
         Phone ringingPhone = ringingCall.getPhone();
 
+        if (VDBG) {
+            Log.d(LOG_TAG, "CallManager.acceptCall " + this);
+        }
+
         if ( hasActiveFgCall() ) {
             Phone activePhone = getActiveFgCall().getPhone();
             boolean hasBgCall = ! (activePhone.getBackgroundCall().isIdle());
             boolean sameChannel = (activePhone == ringingPhone);
 
-            if (LOCAL_DEBUG) {
+            if (DBG) {
                 Log.d(LOG_TAG, "hasBgCall: "+ hasBgCall + "sameChannel:" + sameChannel);
             }
 
@@ -546,15 +622,20 @@
      * handled asynchronously.
      */
     public Connection dial(Phone phone, String dialString) throws CallStateException {
+        Phone basePhone = getPhoneBase(phone);
+        if (VDBG) {
+            Log.d(LOG_TAG, "CallManager.dial( phone=" + basePhone + ", dialString="+ dialString + ")");
+            Log.d(LOG_TAG, this.toString());
+        }
         if ( hasActiveFgCall() ) {
             Phone activePhone = getActiveFgCall().getPhone();
             boolean hasBgCall = !(activePhone.getBackgroundCall().isIdle());
 
-            if (LOCAL_DEBUG) {
-                Log.d(LOG_TAG, "hasBgCall: "+ hasBgCall + "sameChannel:" + (activePhone != phone));
+            if (DBG) {
+                Log.d(LOG_TAG, "hasBgCall: "+ hasBgCall + " sameChannel:" + (activePhone == basePhone));
             }
 
-            if (activePhone != phone) {
+            if (activePhone != basePhone) {
                 if (hasBgCall) {
                     Log.d(LOG_TAG, "Hangup");
                     getActiveFgCall().hangup();
@@ -564,7 +645,7 @@
                 }
             }
         }
-        return phone.dial(dialString);
+        return basePhone.dial(dialString);
     }
 
     /**
@@ -1132,6 +1213,46 @@
         mSubscriptionInfoReadyRegistrants.remove(h);
     }
 
+    /**
+     * Sets an event to be fired when the telephony system processes
+     * a post-dial character on an outgoing call.<p>
+     *
+     * Messages of type <code>what</code> will be sent to <code>h</code>.
+     * The <code>obj</code> field of these Message's will be instances of
+     * <code>AsyncResult</code>. <code>Message.obj.result</code> will be
+     * a Connection object.<p>
+     *
+     * Message.arg1 will be the post dial character being processed,
+     * or 0 ('\0') if end of string.<p>
+     *
+     * If Connection.getPostDialState() == WAIT,
+     * the application must call
+     * {@link com.android.internal.telephony.Connection#proceedAfterWaitChar()
+     * Connection.proceedAfterWaitChar()} or
+     * {@link com.android.internal.telephony.Connection#cancelPostDial()
+     * Connection.cancelPostDial()}
+     * for the telephony system to continue playing the post-dial
+     * DTMF sequence.<p>
+     *
+     * If Connection.getPostDialState() == WILD,
+     * the application must call
+     * {@link com.android.internal.telephony.Connection#proceedAfterWildChar
+     * Connection.proceedAfterWildChar()}
+     * or
+     * {@link com.android.internal.telephony.Connection#cancelPostDial()
+     * Connection.cancelPostDial()}
+     * for the telephony system to continue playing the
+     * post-dial DTMF sequence.<p>
+     *
+     */
+    public void registerForPostDialCharacter(Handler h, int what, Object obj){
+        mPostDialCharacterRegistrants.addUnique(h, what, obj);
+    }
+
+    public void unregisterForPostDialCharacter(Handler h){
+        mPostDialCharacterRegistrants.remove(h);
+    }
+
     /* APIs to access foregroudCalls, backgroudCalls, and ringingCalls
      * 1. APIs to access list of calls
      * 2. APIs to check if any active call, which has connection other than
@@ -1144,22 +1265,22 @@
     /**
      * @return list of all ringing calls
      */
-    public ArrayList<Call> getRingingCalls() {
-        return mRingingCalls;
+    public List<Call> getRingingCalls() {
+        return Collections.unmodifiableList(mRingingCalls);
     }
 
     /**
      * @return list of all foreground calls
      */
-    public ArrayList<Call> getForegroundCalls() {
-        return mForegroundCalls;
+    public List<Call> getForegroundCalls() {
+        return Collections.unmodifiableList(mForegroundCalls);
     }
 
     /**
      * @return list of all background calls
      */
-    public ArrayList<Call> getBackgroundCalls() {
-        return mBackgroundCalls;
+    public List<Call> getBackgroundCalls() {
+        return Collections.unmodifiableList(mBackgroundCalls);
     }
 
     /**
@@ -1222,7 +1343,7 @@
      */
     public Call getFirstActiveBgCall() {
         for (Call call : mBackgroundCalls) {
-            if (!call.isIdle()) {
+            if (call.getState() != Call.State.IDLE) {
                 return call;
             }
         }
@@ -1269,7 +1390,7 @@
 
     /**
      * @return the connections of active foreground call
-     * return null if there is no active foreground call
+     * return empty list if there is no active foreground call
      */
     public List<Connection> getFgCallConnections() {
         Call fgCall = getActiveFgCall();
@@ -1284,7 +1405,7 @@
      * return empty list if there is no active background call
      */
     public List<Connection> getBgCallConnections() {
-        Call bgCall = getActiveFgCall();
+        Call bgCall = getFirstActiveBgCall();
         if ( bgCall != null) {
             return bgCall.getConnections();
         }
@@ -1408,7 +1529,61 @@
                     break;
                 case EVENT_SERVICE_STATE_CHANGED:
                     mServiceStateChangedRegistrants.notifyRegistrants((AsyncResult) msg.obj);
+                    break;
+                case EVENT_POST_DIAL_CHARACTER:
+                    // we need send the character that is being processed in msg.arg1
+                    // so can't use notifyRegistrants()
+                    for(int i=0; i < mPostDialCharacterRegistrants.size(); i++) {
+                        Message notifyMsg;
+                        notifyMsg = ((Registrant)mPostDialCharacterRegistrants.get(i)).messageForRegistrant();
+                        notifyMsg.obj = msg.obj;
+                        notifyMsg.arg1 = msg.arg1;
+                        notifyMsg.sendToTarget();
+                    }
+                    break;
             }
         }
     };
+
+    @Override
+    public String toString() {
+        Call call;
+        StringBuilder b = new StringBuilder();
+
+        b.append("########### Dump CallManager ############");
+        b.append("\nCM state = " + getState());
+        call = getActiveFgCall();
+        b.append("\n   - FG call: " + getActiveFgCallState());
+        b.append(" from " + call.getPhone());
+        b.append("\n     Conn: ").append(getFgCallConnections());
+        call = getFirstActiveBgCall();
+        b.append("\n   - BG call: " + call.getState());
+        b.append(" from " + call.getPhone());
+        b.append("\n     Conn: ").append(getBgCallConnections());
+        call = getFirstActiveRingingCall();
+        b.append("\n   - RINGING call: " +call.getState());
+        b.append(" from " + call.getPhone());
+
+        b.append("\n");
+        for (Phone phone : getAllPhones()) {
+            if (phone != null) {
+                b.append("\n Phone: " + phone + ", name = " + phone.getPhoneName()
+                        + ", state = " + phone.getState());
+                call = phone.getForegroundCall();
+                b.append("\n   - FG call: ").append(call);
+                b.append("  State: ").append(call.getState());
+                b.append("\n     Conn: ").append(call.getConnections());
+                call = phone.getBackgroundCall();
+                b.append("\n   - BG call: ").append(call);
+                b.append("  State: ").append(call.getState());
+                b.append("\n     Conn: ").append(call.getConnections());
+                call = phone.getRingingCall();
+                b.append("\n   - RINGING call: ").append(call);
+                b.append( "  State: ").append(call.getState());
+                b.append("\n     Conn: ").append(call.getConnections());
+            }
+        }
+        b.append("\n########## End Dump CallManager ##########");
+        return b.toString();
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/Connection.java b/telephony/java/com/android/internal/telephony/Connection.java
index c20c200..72c50fc 100644
--- a/telephony/java/com/android/internal/telephony/Connection.java
+++ b/telephony/java/com/android/internal/telephony/Connection.java
@@ -39,6 +39,7 @@
         CONGESTION,                     /* outgoing call to congested network */
         MMI,                            /* not presently used; dial() returns null */
         INVALID_NUMBER,                 /* invalid dial string */
+        NUMBER_UNREACHABLE,             /* cannot reach the peer */
         INVALID_CREDENTIALS,            /* invalid credentials */
         TIMED_OUT,                      /* client timed out */
         LOST_SIGNAL,
diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhone.java b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
index 2c99145..35aa3b3 100755
--- a/telephony/java/com/android/internal/telephony/sip/SipPhone.java
+++ b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
@@ -74,6 +74,7 @@
 public class SipPhone extends SipPhoneBase {
     private static final String LOG_TAG = "SipPhone";
     private static final boolean LOCAL_DEBUG = true;
+    private static final int SESSION_TIMEOUT = 8; // in seconds
 
     // A call that is ringing or (call) waiting
     private SipCall ringingCall = new SipCall();
@@ -142,19 +143,12 @@
             // in case the active/holding call disappeared and this
             // is no longer call waiting
 
-            if (ringingCall.getState() == Call.State.INCOMING) {
+            if ((ringingCall.getState() == Call.State.INCOMING) ||
+                    (ringingCall.getState() == Call.State.WAITING)) {
                 Log.v(LOG_TAG, "acceptCall");
                 // Always unmute when answering a new call
                 setMute(false);
-                // make ringingCall foreground
-                foregroundCall.switchWith(ringingCall);
-                foregroundCall.acceptCall();
-            } else if (ringingCall.getState() == Call.State.WAITING) {
-                setMute(false);
-                switchHoldingAndActive();
-                // make ringingCall foreground
-                foregroundCall.switchWith(ringingCall);
-                foregroundCall.acceptCall();
+                ringingCall.acceptCall();
             } else {
                 throw new CallStateException("phone not ringing");
             }
@@ -392,25 +386,45 @@
             }
         }
 
-        private CallerInfo getCallerInfo(String number) {
+        private CallerInfo createCallerInfo(String number, SipProfile callee) {
+            SipProfile p = callee;
+            String name = p.getDisplayName();
+            if (TextUtils.isEmpty(name)) name = p.getUserName();
+            CallerInfo info = new CallerInfo();
+            info.name = name;
+            info.phoneNumber = number;
+            Log.v(LOG_TAG, "create caller info from scratch:");
+            Log.v(LOG_TAG, "     name: " + info.name);
+            Log.v(LOG_TAG, "     numb: " + info.phoneNumber);
+            return info;
+        }
+
+        // from contacts
+        private CallerInfo findCallerInfo(String number) {
             CallerInfo info = CallerInfo.getCallerInfo(mContext, number);
             if ((info == null) || (info.name == null)) return null;
-            Log.v(LOG_TAG, "++******++ got info from contact:");
+            Log.v(LOG_TAG, "got caller info from contact:");
             Log.v(LOG_TAG, "     name: " + info.name);
             Log.v(LOG_TAG, "     numb: " + info.phoneNumber);
             Log.v(LOG_TAG, "     pres: " + info.numberPresentation);
             return info;
         }
 
-        Connection dial(String calleeSipUri) throws SipException {
-            CallerInfo info = getCallerInfo(calleeSipUri);
+        private CallerInfo getCallerInfo(String number, SipProfile callee) {
+            CallerInfo info = findCallerInfo(number);
+            if (info == null) info = createCallerInfo(number, callee);
+            return info;
+        }
+
+        Connection dial(String originalNumber) throws SipException {
+            String calleeSipUri = originalNumber;
             if (!calleeSipUri.contains("@")) {
                 calleeSipUri += "@" + getSipDomain(mProfile);
-                if (info != null) info.phoneNumber = calleeSipUri;
             }
             try {
                 SipProfile callee =
                         new SipProfile.Builder(calleeSipUri).build();
+                CallerInfo info = getCallerInfo(originalNumber, callee);
                 SipConnection c = new SipConnection(this, callee, info);
                 connections.add(c);
                 c.dial();
@@ -442,9 +456,9 @@
 
         void initIncomingCall(SipAudioCall sipAudioCall, boolean makeCallWait) {
             SipProfile callee = sipAudioCall.getPeerProfile();
-            CallerInfo info = getCallerInfo(getUriString(callee));
-            if (info == null) info = getCallerInfo(callee.getUserName());
-            if (info == null) info = getCallerInfo(callee.getDisplayName());
+            CallerInfo info = findCallerInfo(getUriString(callee));
+            if (info == null) info = findCallerInfo(callee.getUserName());
+            if (info == null) info = findCallerInfo(callee.getDisplayName());
             SipConnection c = new SipConnection(this, callee, info);
             connections.add(c);
 
@@ -460,8 +474,8 @@
         }
 
         void acceptCall() throws CallStateException {
-            if (this != foregroundCall) {
-                throw new CallStateException("acceptCall() in a non-fg call");
+            if (this != ringingCall) {
+                throw new CallStateException("acceptCall() in a non-ringing call");
             }
             if (connections.size() != 1) {
                 throw new CallStateException("acceptCall() in a conf call");
@@ -606,6 +620,7 @@
                 }
                 synchronized (SipPhone.class) {
                     setState(Call.State.DISCONNECTED);
+                    mSipAudioCall.close();
                     mOwner.onConnectionEnded(SipConnection.this);
                     Log.v(LOG_TAG, "-------- connection ended: "
                             + mPeer.getUriString() + ": "
@@ -623,6 +638,19 @@
                     if (newState == Call.State.INCOMING) {
                         setState(mOwner.getState()); // INCOMING or WAITING
                     } else {
+                        if (mOwner == ringingCall) {
+                            if (ringingCall.getState() == Call.State.WAITING) {
+                                try {
+                                    switchHoldingAndActive();
+                                } catch (CallStateException e) {
+                                    // disconnect the call.
+                                    onCallEnded(DisconnectCause.LOCAL);
+                                    return;
+                                }
+                            }
+                            foregroundCall.switchWith(ringingCall);
+                        }
+                        if (newState == Call.State.ACTIVE) call.startAudio();
                         setState(newState);
                     }
                     mOwner.onConnectionStateChanged(SipConnection.this);
@@ -635,9 +663,9 @@
             @Override
             protected void onError(DisconnectCause cause) {
                 Log.w(LOG_TAG, "SIP error: " + cause);
-                if (mSipAudioCall.isInCall()) {
-                    // Don't end the call when in call.
-                    // TODO: how to deliver the error to PhoneApp
+                if (mSipAudioCall.isInCall()
+                        && (cause != DisconnectCause.LOST_SIGNAL)) {
+                    // Don't end the call when in a call.
                     return;
                 }
 
@@ -650,20 +678,9 @@
             super(getUriString(callee));
             mOwner = owner;
             mPeer = callee;
-            if (info == null) info = createCallerInfo();
             setUserData(info);
         }
 
-        private CallerInfo createCallerInfo() {
-            SipProfile p = mPeer;
-            String name = p.getDisplayName();
-            if (TextUtils.isEmpty(name)) name = p.getUserName();
-            CallerInfo info = new CallerInfo();
-            info.name = name;
-            info.phoneNumber = getUriString(p);
-            return info;
-        }
-
         void initIncomingCall(SipAudioCall sipAudioCall, Call.State newState) {
             setState(newState);
             mSipAudioCall = sipAudioCall;
@@ -673,7 +690,7 @@
 
         void acceptCall() throws CallStateException {
             try {
-                mSipAudioCall.answerCall();
+                mSipAudioCall.answerCall(SESSION_TIMEOUT);
             } catch (SipException e) {
                 throw new CallStateException("acceptCall(): " + e);
             }
@@ -691,7 +708,7 @@
         void dial() throws SipException {
             setState(Call.State.DIALING);
             mSipAudioCall = mSipManager.makeAudioCall(mContext, mProfile,
-                    mPeer, null);
+                    mPeer, null, SESSION_TIMEOUT);
             mSipAudioCall.setRingbackToneEnabled(false);
             mSipAudioCall.setListener(mAdapter);
         }
@@ -699,7 +716,7 @@
         void hold() throws CallStateException {
             setState(Call.State.HOLDING);
             try {
-                mSipAudioCall.holdCall();
+                mSipAudioCall.holdCall(SESSION_TIMEOUT);
             } catch (SipException e) {
                 throw new CallStateException("hold(): " + e);
             }
@@ -709,7 +726,7 @@
             mSipAudioCall.setAudioGroup(audioGroup);
             setState(Call.State.ACTIVE);
             try {
-                mSipAudioCall.continueCall();
+                mSipAudioCall.continueCall(SESSION_TIMEOUT);
             } catch (SipException e) {
                 throw new CallStateException("unhold(): " + e);
             }
@@ -753,7 +770,7 @@
                 Log.v(LOG_TAG, "hangup conn: " + mPeer.getUriString() + ": "
                         + ": on phone " + getPhone().getPhoneName());
                 try {
-                    mSipAudioCall.endCall();
+                    if (mSipAudioCall != null) mSipAudioCall.endCall();
                     setState(Call.State.DISCONNECTING);
                     setDisconnectCause(DisconnectCause.LOCAL);
                 } catch (SipException e) {
@@ -789,15 +806,15 @@
 
     private static Call.State getCallStateFrom(SipAudioCall sipAudioCall) {
         if (sipAudioCall.isOnHold()) return Call.State.HOLDING;
-        SipSessionState sessionState = sipAudioCall.getState();
+        int sessionState = sipAudioCall.getState();
         switch (sessionState) {
-            case READY_TO_CALL:            return Call.State.IDLE;
-            case INCOMING_CALL:
-            case INCOMING_CALL_ANSWERING:  return Call.State.INCOMING;
-            case OUTGOING_CALL:            return Call.State.DIALING;
-            case OUTGOING_CALL_RING_BACK:  return Call.State.ALERTING;
-            case OUTGOING_CALL_CANCELING:  return Call.State.DISCONNECTING;
-            case IN_CALL:                  return Call.State.ACTIVE;
+            case SipSessionState.READY_TO_CALL:            return Call.State.IDLE;
+            case SipSessionState.INCOMING_CALL:
+            case SipSessionState.INCOMING_CALL_ANSWERING:  return Call.State.INCOMING;
+            case SipSessionState.OUTGOING_CALL:            return Call.State.DIALING;
+            case SipSessionState.OUTGOING_CALL_RING_BACK:  return Call.State.ALERTING;
+            case SipSessionState.OUTGOING_CALL_CANCELING:  return Call.State.DISCONNECTING;
+            case SipSessionState.IN_CALL:                  return Call.State.ACTIVE;
             default:
                 Log.w(LOG_TAG, "illegal connection state: " + sessionState);
                 return Call.State.DISCONNECTED;
@@ -810,7 +827,9 @@
 
         @Override
         public void onCallEnded(SipAudioCall call) {
-            onCallEnded(Connection.DisconnectCause.NORMAL);
+            onCallEnded(call.isInCall()
+                    ? Connection.DisconnectCause.NORMAL
+                    : Connection.DisconnectCause.INCOMING_MISSED);
         }
 
         @Override
@@ -819,23 +838,31 @@
         }
 
         @Override
-        public void onError(SipAudioCall call, String errorCode,
+        public void onError(SipAudioCall call, int errorCode,
                 String errorMessage) {
-            switch (Enum.valueOf(SipErrorCode.class, errorCode)) {
-                case INVALID_REMOTE_URI:
+            switch (errorCode) {
+                case SipErrorCode.PEER_NOT_REACHABLE:
+                    onError(Connection.DisconnectCause.NUMBER_UNREACHABLE);
+                    break;
+                case SipErrorCode.INVALID_REMOTE_URI:
                     onError(Connection.DisconnectCause.INVALID_NUMBER);
                     break;
-                case TIME_OUT:
-                case TRANSACTION_TERMINTED:
+                case SipErrorCode.TIME_OUT:
+                case SipErrorCode.TRANSACTION_TERMINTED:
                     onError(Connection.DisconnectCause.TIMED_OUT);
                     break;
-                case INVALID_CREDENTIALS:
+                case SipErrorCode.DATA_CONNECTION_LOST:
+                    onError(Connection.DisconnectCause.LOST_SIGNAL);
+                    break;
+                case SipErrorCode.INVALID_CREDENTIALS:
                     onError(Connection.DisconnectCause.INVALID_CREDENTIALS);
                     break;
-                case SOCKET_ERROR:
-                case SERVER_ERROR:
-                case CLIENT_ERROR:
+                case SipErrorCode.SOCKET_ERROR:
+                case SipErrorCode.SERVER_ERROR:
+                case SipErrorCode.CLIENT_ERROR:
                 default:
+                    Log.w(LOG_TAG, "error: " + SipErrorCode.toString(errorCode)
+                            + ": " + errorMessage);
                     onError(Connection.DisconnectCause.ERROR_UNSPECIFIED);
             }
         }
diff --git a/tests/CoreTests/android/core/SSLPerformanceTest.java b/tests/CoreTests/android/core/SSLPerformanceTest.java
index fd87e89..5b5be0a 100644
--- a/tests/CoreTests/android/core/SSLPerformanceTest.java
+++ b/tests/CoreTests/android/core/SSLPerformanceTest.java
@@ -211,17 +211,17 @@
         deleteDirectory();
 
         OpenSSLContextImpl sslContext = new OpenSSLContextImpl();
-        sslContext.engineInit(null, null, null,
-                FileClientSessionCache.usingDirectory(getCacheDirectory()),
-                null);
+        sslContext.engineInit(null, null, null);
+        sslContext.engineGetClientSessionContext().setPersistentCache(
+                FileClientSessionCache.usingDirectory(getCacheDirectory()));
 
         // Make sure www.google.com is in the cache.
         getVerisignDotCom(sslContext);
 
         // Re-initialize so we hit the file cache.
-        sslContext.engineInit(null, null, null,
-                FileClientSessionCache.usingDirectory(getCacheDirectory()),
-                null);
+        sslContext.engineInit(null, null, null);
+        sslContext.engineGetClientSessionContext().setPersistentCache(
+                FileClientSessionCache.usingDirectory(getCacheDirectory()));
 
         Stopwatch stopwatch = new Stopwatch();
 
diff --git a/tests/CoreTests/android/core/SSLSocketTest.java b/tests/CoreTests/android/core/SSLSocketTest.java
index 021df80..03905e1 100644
--- a/tests/CoreTests/android/core/SSLSocketTest.java
+++ b/tests/CoreTests/android/core/SSLSocketTest.java
@@ -911,7 +911,8 @@
 
         // Cache size = 2.
         FakeClientSessionCache fakeCache = new FakeClientSessionCache();
-        context.engineInit(null, null, null, fakeCache, null);
+        context.engineInit(null, null, null);
+        context.engineGetClientSessionContext().setPersistentCache(fakeCache);
         SSLSocketFactory socketFactory = context.engineGetSocketFactory();
         context.engineGetClientSessionContext().setSessionCacheSize(2);
         makeRequests(socketFactory);
@@ -933,7 +934,8 @@
 
         // Cache size = 3.
         fakeCache = new FakeClientSessionCache();
-        context.engineInit(null, null, null, fakeCache, null);
+        context.engineInit(null, null, null);
+        context.engineGetClientSessionContext().setPersistentCache(fakeCache);
         socketFactory = context.engineGetSocketFactory();
         context.engineGetClientSessionContext().setSessionCacheSize(3);
         makeRequests(socketFactory);
@@ -952,7 +954,8 @@
 
         // Cache size = 4.
         fakeCache = new FakeClientSessionCache();
-        context.engineInit(null, null, null, fakeCache, null);
+        context.engineInit(null, null, null);
+        context.engineGetClientSessionContext().setPersistentCache(fakeCache);
         socketFactory = context.engineGetSocketFactory();
         context.engineGetClientSessionContext().setSessionCacheSize(4);
         makeRequests(socketFactory);
@@ -1010,7 +1013,8 @@
         try {
             ClientSessionCacheProxy cacheProxy
                     = new ClientSessionCacheProxy(fileCache);
-            context.engineInit(null, null, null, cacheProxy, null);
+            context.engineInit(null, null, null);
+            context.engineGetClientSessionContext().setPersistentCache(cacheProxy);
             SSLSocketFactory socketFactory = context.engineGetSocketFactory();
             context.engineGetClientSessionContext().setSessionCacheSize(1);
             makeRequests(socketFactory);
@@ -1033,7 +1037,8 @@
             // Try again now that file-based cache is populated.
             fileCache = FileClientSessionCache.usingDirectory(cacheDir);
             cacheProxy = new ClientSessionCacheProxy(fileCache);
-            context.engineInit(null, null, null, cacheProxy, null);
+            context.engineInit(null, null, null);
+            context.engineGetClientSessionContext().setPersistentCache(cacheProxy);
             socketFactory = context.engineGetSocketFactory();
             context.engineGetClientSessionContext().setSessionCacheSize(1);
             makeRequests(socketFactory);
diff --git a/voip/java/android/net/sip/ISipSession.aidl b/voip/java/android/net/sip/ISipSession.aidl
index 1a23527..2d515db 100644
--- a/voip/java/android/net/sip/ISipSession.aidl
+++ b/voip/java/android/net/sip/ISipSession.aidl
@@ -17,12 +17,11 @@
 package android.net.sip;
 
 import android.net.sip.ISipSessionListener;
-import android.net.sip.SessionDescription;
 import android.net.sip.SipProfile;
 
 /**
- * A SIP session that is associated with a SIP dialog or a transaction
- * (e.g., registration) not within a dialog.
+ * A SIP session that is associated with a SIP dialog or a transaction that is
+ * not within a dialog.
  * @hide
  */
 interface ISipSession {
@@ -50,14 +49,11 @@
 
     /**
      * Gets the session state. The value returned must be one of the states in
-     * {@link SipSessionState}. One may convert it to {@link SipSessionState} by
-     * <code>
-     *      Enum.valueOf(SipSessionState.class, session.getState());
-     * </code>
+     * {@link SipSessionState}.
      *
      * @return the session state
      */
-    String getState();
+    int getState();
 
     /**
      * Checks if the session is in a call.
@@ -113,9 +109,11 @@
      *
      * @param callee the SIP profile to make the call to
      * @param sessionDescription the session description of this call
+     * @param timeout the session will be timed out if the call is not
+     *        established within {@code timeout} seconds
      * @see ISipSessionListener
      */
-    void makeCall(in SipProfile callee, String sessionDescription);
+    void makeCall(in SipProfile callee, String sessionDescription, int timeout);
 
     /**
      * Answers an incoming call with the specified session description. The
@@ -123,8 +121,10 @@
      * {@link SipSessionState#INCOMING_CALL}.
      *
      * @param sessionDescription the session description to answer this call
+     * @param timeout the session will be timed out if the call is not
+     *        established within {@code timeout} seconds
      */
-    void answerCall(String sessionDescription);
+    void answerCall(String sessionDescription, int timeout);
 
     /**
      * Ends an established call, terminates an outgoing call or rejects an
@@ -141,6 +141,8 @@
      * to call when the session state is in {@link SipSessionState#IN_CALL}.
      *
      * @param sessionDescription the new session description
+     * @param timeout the session will be timed out if the call is not
+     *        established within {@code timeout} seconds
      */
-    void changeCall(String sessionDescription);
+    void changeCall(String sessionDescription, int timeout);
 }
diff --git a/voip/java/android/net/sip/ISipSessionListener.aidl b/voip/java/android/net/sip/ISipSessionListener.aidl
index 0a6220b..5920bca 100644
--- a/voip/java/android/net/sip/ISipSessionListener.aidl
+++ b/voip/java/android/net/sip/ISipSessionListener.aidl
@@ -79,8 +79,7 @@
      * @param errorCode error code defined in {@link SipErrorCode}
      * @param errorMessage error message
      */
-    void onError(in ISipSession session, String errorCode,
-            String errorMessage);
+    void onError(in ISipSession session, int errorCode, String errorMessage);
 
     /**
      * Called when an error occurs during session modification negotiation.
@@ -89,7 +88,7 @@
      * @param errorCode error code defined in {@link SipErrorCode}
      * @param errorMessage error message
      */
-    void onCallChangeFailed(in ISipSession session, String errorCode,
+    void onCallChangeFailed(in ISipSession session, int errorCode,
             String errorMessage);
 
     /**
@@ -114,7 +113,7 @@
      * @param errorCode error code defined in {@link SipErrorCode}
      * @param errorMessage error message
      */
-    void onRegistrationFailed(in ISipSession session, String errorCode,
+    void onRegistrationFailed(in ISipSession session, int errorCode,
             String errorMessage);
 
     /**
diff --git a/voip/java/android/net/sip/SipAudioCall.java b/voip/java/android/net/sip/SipAudioCall.java
index 39083a5..0069fe0 100644
--- a/voip/java/android/net/sip/SipAudioCall.java
+++ b/voip/java/android/net/sip/SipAudioCall.java
@@ -88,15 +88,16 @@
          * Called when an error occurs.
          *
          * @param call the call object that carries out the audio call
-         * @param errorCode error code defined in {@link SipErrorCode}
+         * @param errorCode error code of this error
          * @param errorMessage error message
+         * @see SipErrorCode
          */
-        void onError(SipAudioCall call, String errorCode, String errorMessage);
+        void onError(SipAudioCall call, int errorCode, String errorMessage);
     }
 
     /**
-     * The adapter class for {@link SipAudioCall#Listener}. The default
-     * implementation of all callback methods is no-op.
+     * The adapter class for {@link Listener}. The default implementation of
+     * all callback methods is no-op.
      */
     public class Adapter implements Listener {
         protected void onChanged(SipAudioCall call) {
@@ -125,7 +126,7 @@
         public void onCallHeld(SipAudioCall call) {
             onChanged(call);
         }
-        public void onError(SipAudioCall call, String errorCode,
+        public void onError(SipAudioCall call, int errorCode,
                 String errorMessage) {
             onChanged(call);
         }
@@ -133,7 +134,7 @@
 
     /**
      * Sets the listener to listen to the audio call events. The method calls
-     * {@link #setListener(Listener, false)}.
+     * {@code setListener(listener, false)}.
      *
      * @param listener to listen to the audio call events of this object
      * @see #setListener(Listener, boolean)
@@ -152,17 +153,29 @@
     void setListener(Listener listener, boolean callbackImmediately);
 
     /**
-     * Closes this object. The object is not usable after being closed.
+     * Closes this object. This object is not usable after being closed.
      */
     void close();
 
     /**
-     * Initiates an audio call to the specified profile.
+     * Initiates an audio call to the specified profile. The attempt will be
+     * timed out if the call is not established within {@code timeout} seconds
+     * and {@code Listener.onError(SipAudioCall, SipErrorCode.TIME_OUT, String)}
+     * will be called.
      *
      * @param callee the SIP profile to make the call to
      * @param sipManager the {@link SipManager} object to help make call with
+     * @param timeout the timeout value in seconds
+     * @see Listener.onError
      */
-    void makeCall(SipProfile callee, SipManager sipManager) throws SipException;
+    void makeCall(SipProfile callee, SipManager sipManager, int timeout)
+            throws SipException;
+
+    /**
+     * Starts the audio for the established call. This method should be called
+     * after {@link Listener#onCallEstablished} is called.
+     */
+    void startAudio();
 
     /**
      * Attaches an incoming call to this call object.
@@ -177,19 +190,39 @@
     void endCall() throws SipException;
 
     /**
-     * Puts a call on hold.  When succeeds,
-     * {@link #Listener#onCallHeld(SipAudioCall)} is called.
+     * Puts a call on hold.  When succeeds, {@link Listener#onCallHeld} is
+     * called. The attempt will be timed out if the call is not established
+     * within {@code timeout} seconds and
+     * {@code Listener.onError(SipAudioCall, SipErrorCode.TIME_OUT, String)}
+     * will be called.
+     *
+     * @param timeout the timeout value in seconds
+     * @see Listener.onError
      */
-    void holdCall() throws SipException;
+    void holdCall(int timeout) throws SipException;
 
-    /** Answers a call. */
-    void answerCall() throws SipException;
+    /**
+     * Answers a call. The attempt will be timed out if the call is not
+     * established within {@code timeout} seconds and
+     * {@code Listener.onError(SipAudioCall, SipErrorCode.TIME_OUT, String)}
+     * will be called.
+     *
+     * @param timeout the timeout value in seconds
+     * @see Listener.onError
+     */
+    void answerCall(int timeout) throws SipException;
 
     /**
      * Continues a call that's on hold. When succeeds,
-     * {@link #Listener#onCallEstablished(SipAudioCall)} is called.
+     * {@link Listener#onCallEstablished} is called. The attempt will be timed
+     * out if the call is not established within {@code timeout} seconds and
+     * {@code Listener.onError(SipAudioCall, SipErrorCode.TIME_OUT, String)}
+     * will be called.
+     *
+     * @param timeout the timeout value in seconds
+     * @see Listener.onError
      */
-    void continueCall() throws SipException;
+    void continueCall(int timeout) throws SipException;
 
     /** Puts the device to speaker mode. */
     void setSpeakerMode(boolean speakerMode);
@@ -285,10 +318,11 @@
 
     /**
      * Gets the state of the {@link ISipSession} that carries this call.
+     * The value returned must be one of the states in {@link SipSessionState}.
      *
      * @return the session state
      */
-    SipSessionState getState();
+    int getState();
 
     /**
      * Gets the {@link ISipSession} that carries this call.
diff --git a/voip/java/android/net/sip/SipAudioCallImpl.java b/voip/java/android/net/sip/SipAudioCallImpl.java
index 67ba97f..ccf4d15 100644
--- a/voip/java/android/net/sip/SipAudioCallImpl.java
+++ b/voip/java/android/net/sip/SipAudioCallImpl.java
@@ -37,6 +37,7 @@
 
 import java.io.IOException;
 import java.net.InetAddress;
+import java.net.UnknownHostException;
 import java.text.ParseException;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -55,6 +56,7 @@
     private static final boolean DONT_RELEASE_SOCKET = false;
     private static final String AUDIO = "audio";
     private static final int DTMF = 101;
+    private static final int SESSION_TIMEOUT = 5; // in seconds
 
     private Context mContext;
     private SipProfile mLocalProfile;
@@ -79,6 +81,9 @@
     private WifiManager mWm;
     private WifiManager.WifiLock mWifiHighPerfLock;
 
+    private int mErrorCode = SipErrorCode.NO_ERROR;
+    private String mErrorMessage;
+
     public SipAudioCallImpl(Context context, SipProfile localProfile) {
         mContext = context;
         mLocalProfile = localProfile;
@@ -92,23 +97,33 @@
     public void setListener(SipAudioCall.Listener listener,
             boolean callbackImmediately) {
         mListener = listener;
-        if ((listener == null) || !callbackImmediately) return;
         try {
-            SipSessionState state = getState();
-            switch (state) {
-            case READY_TO_CALL:
-                listener.onReadyToCall(this);
-                break;
-            case INCOMING_CALL:
-                listener.onRinging(this, getPeerProfile(mSipSession));
-                startRinging();
-                break;
-            case OUTGOING_CALL:
-                listener.onCalling(this);
-                break;
-            default:
-                listener.onError(this, SipErrorCode.CLIENT_ERROR.toString(),
-                        "wrong state to attach call: " + state);
+            if ((listener == null) || !callbackImmediately) {
+                // do nothing
+            } else if (mErrorCode != SipErrorCode.NO_ERROR) {
+                listener.onError(this, mErrorCode, mErrorMessage);
+            } else if (mInCall) {
+                if (mHold) {
+                    listener.onCallHeld(this);
+                } else {
+                    listener.onCallEstablished(this);
+                }
+            } else {
+                int state = getState();
+                switch (state) {
+                    case SipSessionState.READY_TO_CALL:
+                        listener.onReadyToCall(this);
+                        break;
+                    case SipSessionState.INCOMING_CALL:
+                        listener.onRinging(this, getPeerProfile(mSipSession));
+                        break;
+                    case SipSessionState.OUTGOING_CALL:
+                        listener.onCalling(this);
+                        break;
+                    case SipSessionState.OUTGOING_CALL_RING_BACK:
+                        listener.onRingingBack(this);
+                        break;
+                }
             }
         } catch (Throwable t) {
             Log.e(TAG, "setListener()", t);
@@ -131,10 +146,21 @@
         if (closeRtp) stopCall(RELEASE_SOCKET);
         stopRingbackTone();
         stopRinging();
-        mSipSession = null;
+
         mInCall = false;
         mHold = false;
         mSessionId = -1L;
+        mErrorCode = SipErrorCode.NO_ERROR;
+        mErrorMessage = null;
+
+        if (mSipSession != null) {
+            try {
+                mSipSession.setListener(null);
+            } catch (RemoteException e) {
+                // don't care
+            }
+            mSipSession = null;
+        }
     }
 
     public synchronized SipProfile getLocalProfile() {
@@ -149,10 +175,10 @@
         }
     }
 
-    public synchronized SipSessionState getState() {
+    public synchronized int getState() {
         if (mSipSession == null) return SipSessionState.READY_TO_CALL;
         try {
-            return Enum.valueOf(SipSessionState.class, mSipSession.getState());
+            return mSipSession.getState();
         } catch (RemoteException e) {
             return SipSessionState.REMOTE_ERROR;
         }
@@ -169,7 +195,7 @@
         Listener listener = mListener;
         if (listener != null) {
             try {
-                listener.onCalling(SipAudioCallImpl.this);
+                listener.onCalling(this);
             } catch (Throwable t) {
                 Log.e(TAG, "onCalling()", t);
             }
@@ -183,7 +209,7 @@
         Listener listener = mListener;
         if (listener != null) {
             try {
-                listener.onRingingBack(SipAudioCallImpl.this);
+                listener.onRingingBack(this);
             } catch (Throwable t) {
                 Log.e(TAG, "onRingingBack()", t);
             }
@@ -204,7 +230,7 @@
             // session changing request
             try {
                 mPeerSd = new SdpSessionDescription(sessionDescription);
-                answerCall();
+                answerCall(SESSION_TIMEOUT);
             } catch (Throwable e) {
                 Log.e(TAG, "onRinging()", e);
                 session.endCall();
@@ -214,31 +240,25 @@
         }
     }
 
-    private synchronized void establishCall(String sessionDescription) {
-        stopRingbackTone();
-        stopRinging();
-        try {
-            SdpSessionDescription sd =
-                    new SdpSessionDescription(sessionDescription);
-            Log.d(TAG, "sip call established: " + sd);
-            startCall(sd);
-            mInCall = true;
-        } catch (SdpException e) {
-            Log.e(TAG, "createSessionDescription()", e);
-        }
-    }
-
     @Override
     public void onCallEstablished(ISipSession session,
             String sessionDescription) {
-        establishCall(sessionDescription);
+        stopRingbackTone();
+        stopRinging();
+        try {
+            mPeerSd = new SdpSessionDescription(sessionDescription);
+            Log.d(TAG, "sip call established: " + mPeerSd);
+        } catch (SdpException e) {
+            Log.e(TAG, "createSessionDescription()", e);
+        }
+
         Listener listener = mListener;
         if (listener != null) {
             try {
                 if (mHold) {
-                    listener.onCallHeld(SipAudioCallImpl.this);
+                    listener.onCallHeld(this);
                 } else {
-                    listener.onCallEstablished(SipAudioCallImpl.this);
+                    listener.onCallEstablished(this);
                 }
             } catch (Throwable t) {
                 Log.e(TAG, "onCallEstablished()", t);
@@ -249,39 +269,41 @@
     @Override
     public void onCallEnded(ISipSession session) {
         Log.d(TAG, "sip call ended: " + session);
-        close();
         Listener listener = mListener;
         if (listener != null) {
             try {
-                listener.onCallEnded(SipAudioCallImpl.this);
+                listener.onCallEnded(this);
             } catch (Throwable t) {
                 Log.e(TAG, "onCallEnded()", t);
             }
         }
+        close();
     }
 
     @Override
     public void onCallBusy(ISipSession session) {
         Log.d(TAG, "sip call busy: " + session);
-        close(false);
         Listener listener = mListener;
         if (listener != null) {
             try {
-                listener.onCallBusy(SipAudioCallImpl.this);
+                listener.onCallBusy(this);
             } catch (Throwable t) {
                 Log.e(TAG, "onCallBusy()", t);
             }
         }
+        close(false);
     }
 
     @Override
-    public void onCallChangeFailed(ISipSession session, String errorCode,
+    public void onCallChangeFailed(ISipSession session, int errorCode,
             String message) {
         Log.d(TAG, "sip call change failed: " + message);
+        mErrorCode = errorCode;
+        mErrorMessage = message;
         Listener listener = mListener;
         if (listener != null) {
             try {
-                listener.onError(SipAudioCallImpl.this, errorCode, message);
+                listener.onError(this, mErrorCode, message);
             } catch (Throwable t) {
                 Log.e(TAG, "onCallBusy()", t);
             }
@@ -289,20 +311,25 @@
     }
 
     @Override
-    public void onError(ISipSession session, String errorCode,
-            String message) {
-        Log.d(TAG, "sip session error: " + errorCode + ": " + message);
-        synchronized (this) {
-            if (!isInCall()) close(true);
-        }
+    public void onError(ISipSession session, int errorCode, String message) {
+        Log.d(TAG, "sip session error: " + SipErrorCode.toString(errorCode)
+                + ": " + message);
+        mErrorCode = errorCode;
+        mErrorMessage = message;
         Listener listener = mListener;
         if (listener != null) {
             try {
-                listener.onError(SipAudioCallImpl.this, errorCode, message);
+                listener.onError(this, errorCode, message);
             } catch (Throwable t) {
                 Log.e(TAG, "onError()", t);
             }
         }
+        synchronized (this) {
+            if ((errorCode == SipErrorCode.DATA_CONNECTION_LOST)
+                    || !isInCall()) {
+                close(true);
+            }
+        }
     }
 
     public synchronized void attachCall(ISipSession session,
@@ -311,6 +338,8 @@
         try {
             mPeerSd = new SdpSessionDescription(sessionDescription);
             session.setListener(this);
+
+            if (getState() == SipSessionState.INCOMING_CALL) startRinging();
         } catch (Throwable e) {
             Log.e(TAG, "attachCall()", e);
             throwSipException(e);
@@ -318,14 +347,15 @@
     }
 
     public synchronized void makeCall(SipProfile peerProfile,
-            SipManager sipManager) throws SipException {
+            SipManager sipManager, int timeout) throws SipException {
         try {
             mSipSession = sipManager.createSipSession(mLocalProfile, this);
             if (mSipSession == null) {
                 throw new SipException(
                         "Failed to create SipSession; network available?");
             }
-            mSipSession.makeCall(peerProfile, createOfferSessionDescription());
+            mSipSession.makeCall(peerProfile, createOfferSessionDescription(),
+                    timeout);
         } catch (Throwable e) {
             if (e instanceof SipException) {
                 throw (SipException) e;
@@ -348,10 +378,10 @@
         }
     }
 
-    public synchronized void holdCall() throws SipException {
+    public synchronized void holdCall(int timeout) throws SipException {
         if (mHold) return;
         try {
-            mSipSession.changeCall(createHoldSessionDescription());
+            mSipSession.changeCall(createHoldSessionDescription(), timeout);
             mHold = true;
         } catch (Throwable e) {
             throwSipException(e);
@@ -361,21 +391,21 @@
         if (audioGroup != null) audioGroup.setMode(AudioGroup.MODE_ON_HOLD);
     }
 
-    public synchronized void answerCall() throws SipException {
+    public synchronized void answerCall(int timeout) throws SipException {
         try {
             stopRinging();
-            mSipSession.answerCall(createAnswerSessionDescription());
+            mSipSession.answerCall(createAnswerSessionDescription(), timeout);
         } catch (Throwable e) {
             Log.e(TAG, "answerCall()", e);
             throwSipException(e);
         }
     }
 
-    public synchronized void continueCall() throws SipException {
+    public synchronized void continueCall(int timeout) throws SipException {
         if (!mHold) return;
         try {
             mHold = false;
-            mSipSession.changeCall(createContinueSessionDescription());
+            mSipSession.changeCall(createContinueSessionDescription(), timeout);
         } catch (Throwable e) {
             throwSipException(e);
         }
@@ -570,10 +600,23 @@
         return copies;
     }
 
-    private void startCall(SdpSessionDescription peerSd) {
+    public void startAudio() {
+        try {
+            startAudioInternal();
+        } catch (UnknownHostException e) {
+            onError(mSipSession, SipErrorCode.PEER_NOT_REACHABLE,
+                    e.getMessage());
+        } catch (Throwable e) {
+            onError(mSipSession, SipErrorCode.CLIENT_ERROR,
+                    e.getMessage());
+        }
+    }
+
+    private synchronized void startAudioInternal() throws UnknownHostException {
         stopCall(DONT_RELEASE_SOCKET);
+        mInCall = true;
+        SdpSessionDescription peerSd = mPeerSd;
         if (isWifiOn()) grabWifiHighPerfLock();
-        mPeerSd = peerSd;
         String peerMediaAddress = peerSd.getPeerMediaAddress(AUDIO);
         // TODO: handle multiple media fields
         int peerMediaPort = peerSd.getPeerMediaPort(AUDIO);
@@ -582,58 +625,55 @@
         int localPort = getLocalMediaPort();
         int sampleRate = 8000;
         int frameSize = sampleRate / 50; // 160
-        try {
-            // TODO: get sample rate from sdp
-            mCodec = getCodec(peerSd);
 
-            AudioStream audioStream = mAudioStream;
-            audioStream.associate(InetAddress.getByName(peerMediaAddress),
-                    peerMediaPort);
-            audioStream.setCodec(convert(mCodec), mCodec.payloadType);
-            audioStream.setDtmfType(DTMF);
-            Log.d(TAG, "start media: localPort=" + localPort + ", peer="
-                    + peerMediaAddress + ":" + peerMediaPort);
+        // TODO: get sample rate from sdp
+        mCodec = getCodec(peerSd);
 
-            audioStream.setMode(RtpStream.MODE_NORMAL);
-            if (!mHold) {
-                // FIXME: won't work if peer is not sending nor receiving
-                if (!peerSd.isSending(AUDIO)) {
-                    Log.d(TAG, "   not receiving");
-                    audioStream.setMode(RtpStream.MODE_SEND_ONLY);
-                }
-                if (!peerSd.isReceiving(AUDIO)) {
-                    Log.d(TAG, "   not sending");
-                    audioStream.setMode(RtpStream.MODE_RECEIVE_ONLY);
-                }
+        AudioStream audioStream = mAudioStream;
+        audioStream.associate(InetAddress.getByName(peerMediaAddress),
+                peerMediaPort);
+        audioStream.setCodec(convert(mCodec), mCodec.payloadType);
+        audioStream.setDtmfType(DTMF);
+        Log.d(TAG, "start media: localPort=" + localPort + ", peer="
+                + peerMediaAddress + ":" + peerMediaPort);
 
-                /* The recorder volume will be very low if the device is in
-                 * IN_CALL mode. Therefore, we have to set the mode to NORMAL
-                 * in order to have the normal microphone level.
-                 */
-                ((AudioManager) mContext.getSystemService
-                        (Context.AUDIO_SERVICE))
-                        .setMode(AudioManager.MODE_NORMAL);
+        audioStream.setMode(RtpStream.MODE_NORMAL);
+        if (!mHold) {
+            // FIXME: won't work if peer is not sending nor receiving
+            if (!peerSd.isSending(AUDIO)) {
+                Log.d(TAG, "   not receiving");
+                audioStream.setMode(RtpStream.MODE_SEND_ONLY);
+            }
+            if (!peerSd.isReceiving(AUDIO)) {
+                Log.d(TAG, "   not sending");
+                audioStream.setMode(RtpStream.MODE_RECEIVE_ONLY);
             }
 
-            // AudioGroup logic:
-            AudioGroup audioGroup = getAudioGroup();
-            if (mHold) {
-                if (audioGroup != null) {
-                    audioGroup.setMode(AudioGroup.MODE_ON_HOLD);
-                }
-                // don't create an AudioGroup here; doing so will fail if
-                // there's another AudioGroup out there that's active
+            /* The recorder volume will be very low if the device is in
+             * IN_CALL mode. Therefore, we have to set the mode to NORMAL
+             * in order to have the normal microphone level.
+             */
+            ((AudioManager) mContext.getSystemService
+                    (Context.AUDIO_SERVICE))
+                    .setMode(AudioManager.MODE_NORMAL);
+        }
+
+        // AudioGroup logic:
+        AudioGroup audioGroup = getAudioGroup();
+        if (mHold) {
+            if (audioGroup != null) {
+                audioGroup.setMode(AudioGroup.MODE_ON_HOLD);
+            }
+            // don't create an AudioGroup here; doing so will fail if
+            // there's another AudioGroup out there that's active
+        } else {
+            if (audioGroup == null) audioGroup = new AudioGroup();
+            audioStream.join(audioGroup);
+            if (mMuted) {
+                audioGroup.setMode(AudioGroup.MODE_MUTED);
             } else {
-                if (audioGroup == null) audioGroup = new AudioGroup();
-                audioStream.join(audioGroup);
-                if (mMuted) {
-                    audioGroup.setMode(AudioGroup.MODE_MUTED);
-                } else {
-                    audioGroup.setMode(AudioGroup.MODE_NORMAL);
-                }
+                audioGroup.setMode(AudioGroup.MODE_NORMAL);
             }
-        } catch (Exception e) {
-            Log.e(TAG, "call()", e);
         }
     }
 
diff --git a/voip/java/android/net/sip/SipErrorCode.java b/voip/java/android/net/sip/SipErrorCode.java
index 8624811..7496d28 100644
--- a/voip/java/android/net/sip/SipErrorCode.java
+++ b/voip/java/android/net/sip/SipErrorCode.java
@@ -18,34 +18,75 @@
 
 /**
  * Defines error code returned in
- * {@link SipRegistrationListener#onRegistrationFailed(String, String, String)},
- * {@link ISipSessionListener#onError(ISipSession, String, String)},
- * {@link ISipSessionListener#onCallChangeFailed(ISipSession, String, String)} and
- * {@link ISipSessionListener#onRegistrationFailed(ISipSession, String, String)}.
+ * {@link SipRegistrationListener#onRegistrationFailed},
+ * {@link ISipSessionListener#onError},
+ * {@link ISipSessionListener#onCallChangeFailed} and
+ * {@link ISipSessionListener#onRegistrationFailed}.
  * @hide
  */
-public enum SipErrorCode {
+public class SipErrorCode {
+    /** Not an error. */
+    public static final int NO_ERROR = 0;
+
     /** When some socket error occurs. */
-    SOCKET_ERROR,
+    public static final int SOCKET_ERROR = -1;
 
     /** When server responds with an error. */
-    SERVER_ERROR,
+    public static final int SERVER_ERROR = -2;
 
     /** When transaction is terminated unexpectedly. */
-    TRANSACTION_TERMINTED,
+    public static final int TRANSACTION_TERMINTED = -3;
 
     /** When some error occurs on the device, possibly due to a bug. */
-    CLIENT_ERROR,
+    public static final int CLIENT_ERROR = -4;
 
     /** When the transaction gets timed out. */
-    TIME_OUT,
+    public static final int TIME_OUT = -5;
 
     /** When the remote URI is not valid. */
-    INVALID_REMOTE_URI,
+    public static final int INVALID_REMOTE_URI = -6;
+
+    /** When the peer is not reachable. */
+    public static final int PEER_NOT_REACHABLE = -7;
 
     /** When invalid credentials are provided. */
-    INVALID_CREDENTIALS,
+    public static final int INVALID_CREDENTIALS = -8;
 
     /** The client is in a transaction and cannot initiate a new one. */
-    IN_PROGRESS;
+    public static final int IN_PROGRESS = -9;
+
+    /** When data connection is lost. */
+    public static final int DATA_CONNECTION_LOST = -10;
+
+    public static String toString(int errorCode) {
+        switch (errorCode) {
+            case NO_ERROR:
+                return "NO_ERROR";
+            case SOCKET_ERROR:
+                return "SOCKET_ERROR";
+            case SERVER_ERROR:
+                return "SERVER_ERROR";
+            case TRANSACTION_TERMINTED:
+                return "TRANSACTION_TERMINTED";
+            case CLIENT_ERROR:
+                return "CLIENT_ERROR";
+            case TIME_OUT:
+                return "TIME_OUT";
+            case INVALID_REMOTE_URI:
+                return "INVALID_REMOTE_URI";
+            case PEER_NOT_REACHABLE:
+                return "PEER_NOT_REACHABLE";
+            case INVALID_CREDENTIALS:
+                return "INVALID_CREDENTIALS";
+            case IN_PROGRESS:
+                return "IN_PROGRESS";
+            case DATA_CONNECTION_LOST:
+                return "DATA_CONNECTION_LOST";
+            default:
+                return "UNKNOWN";
+        }
+    }
+
+    private SipErrorCode() {
+    }
 }
diff --git a/voip/java/android/net/sip/SipException.java b/voip/java/android/net/sip/SipException.java
index d615342..f0d846b 100644
--- a/voip/java/android/net/sip/SipException.java
+++ b/voip/java/android/net/sip/SipException.java
@@ -17,6 +17,7 @@
 package android.net.sip;
 
 /**
+ * General SIP-related exception class.
  * @hide
  */
 public class SipException extends Exception {
diff --git a/voip/java/android/net/sip/SipManager.java b/voip/java/android/net/sip/SipManager.java
index ccae7f9..31768d7 100644
--- a/voip/java/android/net/sip/SipManager.java
+++ b/voip/java/android/net/sip/SipManager.java
@@ -28,25 +28,22 @@
 
 /**
  * The class provides API for various SIP related tasks. Specifically, the API
- * allows the application to:
+ * allows an application to:
  * <ul>
  * <li>register a {@link SipProfile} to have the background SIP service listen
  *      to incoming calls and broadcast them with registered command string. See
  *      {@link #open(SipProfile, String, SipRegistrationListener)},
- *      {@link #open(SipProfile)}, {@link #close(String)},
- *      {@link #isOpened(String)} and {@link isRegistered(String)}. It also
- *      facilitates handling of the incoming call broadcast intent. See
- *      {@link #isIncomingCallIntent(Intent)}, {@link #getCallId(Intent)},
- *      {@link #getOfferSessionDescription(Intent)} and
- *      {@link #takeAudioCall(Context, Intent, SipAudioCall.Listener)}.</li>
+ *      {@link #open(SipProfile)}, {@link #close}, {@link #isOpened} and
+ *      {@link #isRegistered}. It also facilitates handling of the incoming call
+ *      broadcast intent. See
+ *      {@link #isIncomingCallIntent}, {@link #getCallId},
+ *      {@link #getOfferSessionDescription} and {@link #takeAudioCall}.</li>
  * <li>make/take SIP-based audio calls. See
- *      {@link #makeAudioCall(Context, SipProfile, SipProfile, SipAudioCall.Listener)}
- *      and {@link #takeAudioCall(Context, Intent, SipAudioCall.Listener}.</li>
+ *      {@link #makeAudioCall} and {@link #takeAudioCall}.</li>
  * <li>register/unregister with a SIP service provider. See
- *      {@link #register(SipProfile, int, ISipSessionListener)} and
- *      {@link #unregister(SipProfile, ISipSessionListener)}.</li>
+ *      {@link #register} and {@link #unregister}.</li>
  * <li>process SIP events directly with a {@link ISipSession} created by
- *      {@link createSipSession(SipProfile, ISipSessionListener)}.</li>
+ *      {@link #createSipSession}.</li>
  * </ul>
  * @hide
  */
@@ -100,6 +97,14 @@
          */
     }
 
+    /**
+     * Returns true if SIP is only available on WIFI.
+     */
+    public static boolean isSipWifiOnly(Context context) {
+        return context.getResources().getBoolean(
+                com.android.internal.R.bool.config_sip_wifi_only);
+    }
+
     private SipManager() {
         createSipService();
     }
@@ -113,8 +118,7 @@
     /**
      * Opens the profile for making calls and/or receiving calls. Subsequent
      * SIP calls can be made through the default phone UI. The caller may also
-     * make subsequent calls through
-     * {@link #makeAudioCall(Context, String, String, SipAudioCall.Listener)}.
+     * make subsequent calls through {@link #makeAudioCall}.
      * If the receiving-call option is enabled in the profile, the SIP service
      * will register the profile to the corresponding server periodically in
      * order to receive calls from the server.
@@ -134,8 +138,7 @@
     /**
      * Opens the profile for making calls and/or receiving calls. Subsequent
      * SIP calls can be made through the default phone UI. The caller may also
-     * make subsequent calls through
-     * {@link #makeAudioCall(Context, String, String, SipAudioCall.Listener)}.
+     * make subsequent calls through {@link #makeAudioCall}.
      * If the receiving-call option is enabled in the profile, the SIP service
      * will register the profile to the corresponding server periodically in
      * order to receive calls from the server.
@@ -160,9 +163,7 @@
 
     /**
      * Sets the listener to listen to registration events. No effect if the
-     * profile has not been opened to receive calls
-     * (see {@link #open(SipProfile, String, SipRegistrationListener)} and
-     * {@link #open(SipProfile)}).
+     * profile has not been opened to receive calls (see {@link #open}).
      *
      * @param localProfileUri the URI of the profile
      * @param listener to listen to registration events; can be null
@@ -225,44 +226,55 @@
     }
 
     /**
-     * Creates a {@link SipAudioCall} to make a call.
+     * Creates a {@link SipAudioCall} to make a call. The attempt will be timed
+     * out if the call is not established within {@code timeout} seconds and
+     * {@code SipAudioCall.Listener.onError(SipAudioCall, SipErrorCode.TIME_OUT, String)}
+     * will be called.
      *
      * @param context context to create a {@link SipAudioCall} object
      * @param localProfile the SIP profile to make the call from
      * @param peerProfile the SIP profile to make the call to
      * @param listener to listen to the call events from {@link SipAudioCall};
      *      can be null
+     * @param timeout the timeout value in seconds
      * @return a {@link SipAudioCall} object
      * @throws SipException if calling the SIP service results in an error
+     * @see SipAudioCall.Listener.onError
      */
     public SipAudioCall makeAudioCall(Context context, SipProfile localProfile,
-            SipProfile peerProfile, SipAudioCall.Listener listener)
+            SipProfile peerProfile, SipAudioCall.Listener listener, int timeout)
             throws SipException {
         SipAudioCall call = new SipAudioCallImpl(context, localProfile);
         call.setListener(listener);
-        call.makeCall(peerProfile, this);
+        call.makeCall(peerProfile, this, timeout);
         return call;
     }
 
     /**
      * Creates a {@link SipAudioCall} to make a call. To use this method, one
-     * must call {@link #open(SipProfile)} first.
+     * must call {@link #open(SipProfile)} first. The attempt will be timed out
+     * if the call is not established within {@code timeout} seconds and
+     * {@code SipAudioCall.Listener.onError(SipAudioCall, SipErrorCode.TIME_OUT, String)}
+     * will be called.
      *
      * @param context context to create a {@link SipAudioCall} object
      * @param localProfileUri URI of the SIP profile to make the call from
      * @param peerProfileUri URI of the SIP profile to make the call to
      * @param listener to listen to the call events from {@link SipAudioCall};
      *      can be null
+     * @param timeout the timeout value in seconds
      * @return a {@link SipAudioCall} object
      * @throws SipException if calling the SIP service results in an error
+     * @see SipAudioCall.Listener.onError
      */
     public SipAudioCall makeAudioCall(Context context, String localProfileUri,
-            String peerProfileUri, SipAudioCall.Listener listener)
+            String peerProfileUri, SipAudioCall.Listener listener, int timeout)
             throws SipException {
         try {
             return makeAudioCall(context,
                     new SipProfile.Builder(localProfileUri).build(),
-                    new SipProfile.Builder(peerProfileUri).build(), listener);
+                    new SipProfile.Builder(peerProfileUri).build(), listener,
+                    timeout);
         } catch (ParseException e) {
             throw new SipException("build SipProfile", e);
         }
@@ -283,7 +295,7 @@
     /**
      * Creates a {@link SipAudioCall} to take an incoming call. Before the call
      * is returned, the listener will receive a
-     * {@link SipAudioCall#Listener.onRinging(SipAudioCall, SipProfile)}
+     * {@link SipAudioCall.Listener#onRinging}
      * callback.
      *
      * @param context context to create a {@link SipAudioCall} object
@@ -377,12 +389,11 @@
 
     /**
      * Registers the profile to the corresponding server for receiving calls.
-     * {@link #open(SipProfile, String, SipRegistrationListener)} is still
-     * needed to be called at least once in order for the SIP service to
-     * broadcast an intent when an incoming call is received.
+     * {@link #open} is still needed to be called at least once in order for
+     * the SIP service to broadcast an intent when an incoming call is received.
      *
      * @param localProfile the SIP profile to register with
-     * @param expiryTime registration expiration time (in second)
+     * @param expiryTime registration expiration time (in seconds)
      * @param listener to listen to the registration events
      * @throws SipException if calling the SIP service results in an error
      */
@@ -419,9 +430,9 @@
     /**
      * Gets the {@link ISipSession} that handles the incoming call. For audio
      * calls, consider to use {@link SipAudioCall} to handle the incoming call.
-     * See {@link #takeAudioCall(Context, Intent, SipAudioCall.Listener)}.
-     * Note that the method may be called only once for the same intent. For
-     * subsequent calls on the same intent, the method returns null.
+     * See {@link #takeAudioCall}. Note that the method may be called only once
+     * for the same intent. For subsequent calls on the same intent, the method
+     * returns null.
      *
      * @param incomingCallIntent the incoming call broadcast intent
      * @return the session object that handles the incoming call
@@ -500,7 +511,7 @@
         }
 
         @Override
-        public void onRegistrationFailed(ISipSession session, String errorCode,
+        public void onRegistrationFailed(ISipSession session, int errorCode,
                 String message) {
             mListener.onRegistrationFailed(getUri(session), errorCode, message);
         }
@@ -508,7 +519,7 @@
         @Override
         public void onRegistrationTimeout(ISipSession session) {
             mListener.onRegistrationFailed(getUri(session),
-                    SipErrorCode.TIME_OUT.toString(), "registration timed out");
+                    SipErrorCode.TIME_OUT, "registration timed out");
         }
     }
 }
diff --git a/voip/java/android/net/sip/SipProfile.java b/voip/java/android/net/sip/SipProfile.java
index aa2da75..88bfba9 100644
--- a/voip/java/android/net/sip/SipProfile.java
+++ b/voip/java/android/net/sip/SipProfile.java
@@ -61,7 +61,7 @@
             };
 
     /**
-     * Class to help create a {@link SipProfile}.
+     * Class to help create a {@code SipProfile}.
      */
     public static class Builder {
         private AddressFactory mAddressFactory;
@@ -120,8 +120,8 @@
          *
          * @param username username of the SIP account
          * @param serverDomain the SIP server domain; if the network address
-         *      is different from the domain, use
-         *      {@link #setOutboundProxy(String)} to set server address
+         *      is different from the domain, use {@link #setOutboundProxy} to
+         *      set server address
          * @throws ParseException if the parameters are not valid
          */
         public Builder(String username, String serverDomain)
@@ -167,11 +167,15 @@
          *
          * @param port port number of the server
          * @return this builder object
-         * @throws InvalidArgumentException if the port number is out of range
+         * @throws IllegalArgumentException if the port number is out of range
          */
-        public Builder setPort(int port) throws InvalidArgumentException {
-            mUri.setPort(port);
-            return this;
+        public Builder setPort(int port) throws IllegalArgumentException {
+            try {
+                mUri.setPort(port);
+                return this;
+            } catch (InvalidArgumentException e) {
+                throw new IllegalArgumentException(e);
+            }
         }
 
         /**
@@ -180,16 +184,16 @@
          *
          * @param protocol the protocol string
          * @return this builder object
-         * @throws InvalidArgumentException if the protocol is not recognized
+         * @throws IllegalArgumentException if the protocol is not recognized
          */
         public Builder setProtocol(String protocol)
-                throws InvalidArgumentException {
+                throws IllegalArgumentException {
             if (protocol == null) {
                 throw new NullPointerException("protocol cannot be null");
             }
             protocol = protocol.toUpperCase();
             if (!protocol.equals("UDP") && !protocol.equals("TCP")) {
-                throw new InvalidArgumentException(
+                throw new IllegalArgumentException(
                         "unsupported protocol: " + protocol);
             }
             mProfile.mProtocol = protocol;
@@ -305,6 +309,7 @@
      * Gets the SIP URI of this profile.
      *
      * @return the SIP URI of this profile
+     * @hide
      */
     public SipURI getUri() {
         return (SipURI) mAddress.getURI();
@@ -323,6 +328,7 @@
      * Gets the SIP address of this profile.
      *
      * @return the SIP address of this profile
+     * @hide
      */
     public Address getSipAddress() {
         return mAddress;
diff --git a/voip/java/android/net/sip/SipRegistrationListener.java b/voip/java/android/net/sip/SipRegistrationListener.java
index 22488d7..37c9ce2 100644
--- a/voip/java/android/net/sip/SipRegistrationListener.java
+++ b/voip/java/android/net/sip/SipRegistrationListener.java
@@ -29,20 +29,21 @@
     void onRegistering(String localProfileUri);
 
     /**
-     * Called when registration is successfully done.
+     * Called when the registration succeeded.
      *
      * @param localProfileUri the URI string of the SIP profile to register with
-     * @param expiryTime duration in second before the registration expires
+     * @param expiryTime duration in seconds before the registration expires
      */
     void onRegistrationDone(String localProfileUri, long expiryTime);
 
     /**
-     * Called when the registration fails.
+     * Called when the registration failed.
      *
      * @param localProfileUri the URI string of the SIP profile to register with
-     * @param errorCode error code defined in {@link SipErrorCode}
+     * @param errorCode error code of this error
      * @param errorMessage error message
+     * @see SipErrorCode
      */
-    void onRegistrationFailed(String localProfileUri, String errorCode,
+    void onRegistrationFailed(String localProfileUri, int errorCode,
             String errorMessage);
 }
diff --git a/voip/java/android/net/sip/SipSessionAdapter.java b/voip/java/android/net/sip/SipSessionAdapter.java
index 6020f2c..86aca37 100644
--- a/voip/java/android/net/sip/SipSessionAdapter.java
+++ b/voip/java/android/net/sip/SipSessionAdapter.java
@@ -42,11 +42,11 @@
     public void onCallBusy(ISipSession session) {
     }
 
-    public void onCallChangeFailed(ISipSession session, String errorCode,
+    public void onCallChangeFailed(ISipSession session, int errorCode,
             String message) {
     }
 
-    public void onError(ISipSession session, String errorCode, String message) {
+    public void onError(ISipSession session, int errorCode, String message) {
     }
 
     public void onRegistering(ISipSession session) {
@@ -55,7 +55,7 @@
     public void onRegistrationDone(ISipSession session, int duration) {
     }
 
-    public void onRegistrationFailed(ISipSession session, String errorCode,
+    public void onRegistrationFailed(ISipSession session, int errorCode,
             String message) {
     }
 
diff --git a/voip/java/android/net/sip/SipSessionState.java b/voip/java/android/net/sip/SipSessionState.java
index 5bab112..31e9d3f 100644
--- a/voip/java/android/net/sip/SipSessionState.java
+++ b/voip/java/android/net/sip/SipSessionState.java
@@ -20,47 +20,75 @@
  * Defines {@link ISipSession} states.
  * @hide
  */
-public enum SipSessionState {
+public class SipSessionState {
     /** When session is ready to initiate a call or transaction. */
-    READY_TO_CALL,
+    public static final int READY_TO_CALL = 0;
 
     /** When the registration request is sent out. */
-    REGISTERING,
+    public static final int REGISTERING = 1;
 
     /** When the unregistration request is sent out. */
-    DEREGISTERING,
+    public static final int DEREGISTERING = 2;
 
     /** When an INVITE request is received. */
-    INCOMING_CALL,
+    public static final int INCOMING_CALL = 3;
 
     /** When an OK response is sent for the INVITE request received. */
-    INCOMING_CALL_ANSWERING,
+    public static final int INCOMING_CALL_ANSWERING = 4;
 
     /** When an INVITE request is sent. */
-    OUTGOING_CALL,
+    public static final int OUTGOING_CALL = 5;
 
     /** When a RINGING response is received for the INVITE request sent. */
-    OUTGOING_CALL_RING_BACK,
+    public static final int OUTGOING_CALL_RING_BACK = 6;
 
     /** When a CANCEL request is sent for the INVITE request sent. */
-    OUTGOING_CALL_CANCELING,
+    public static final int OUTGOING_CALL_CANCELING = 7;
 
     /** When a call is established. */
-    IN_CALL,
+    public static final int IN_CALL = 8;
 
     /** Some error occurs when making a remote call to {@link ISipSession}. */
-    REMOTE_ERROR,
+    public static final int REMOTE_ERROR = 9;
 
     /** When an OPTIONS request is sent. */
-    PINGING;
+    public static final int PINGING = 10;
+
+    /** Not defined. */
+    public static final int NOT_DEFINED = 101;
 
     /**
-     * Checks if the specified string represents the same state as this object.
-     *
-     * @return true if the specified string represents the same state as this
-     *      object
+     * Converts the state to string.
      */
-    public boolean equals(String state) {
-        return toString().equals(state);
+    public static String toString(int state) {
+        switch (state) {
+            case READY_TO_CALL:
+                return "READY_TO_CALL";
+            case REGISTERING:
+                return "REGISTERING";
+            case DEREGISTERING:
+                return "DEREGISTERING";
+            case INCOMING_CALL:
+                return "INCOMING_CALL";
+            case INCOMING_CALL_ANSWERING:
+                return "INCOMING_CALL_ANSWERING";
+            case OUTGOING_CALL:
+                return "OUTGOING_CALL";
+            case OUTGOING_CALL_RING_BACK:
+                return "OUTGOING_CALL_RING_BACK";
+            case OUTGOING_CALL_CANCELING:
+                return "OUTGOING_CALL_CANCELING";
+            case IN_CALL:
+                return "IN_CALL";
+            case REMOTE_ERROR:
+                return "REMOTE_ERROR";
+            case PINGING:
+                return "PINGING";
+            default:
+                return "NOT_DEFINED";
+        }
+    }
+
+    private SipSessionState() {
     }
 }
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 6e0bc9d..0ee559e 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -21,6 +21,8 @@
 import android.net.wifi.ScanResult;
 import android.net.DhcpInfo;
 
+import android.os.WorkSource;
+
 /**
  * Interface that allows controlling and querying Wi-Fi connectivity.
  *
@@ -66,7 +68,9 @@
 
     DhcpInfo getDhcpInfo();
 
-    boolean acquireWifiLock(IBinder lock, int lockType, String tag);
+    boolean acquireWifiLock(IBinder lock, int lockType, String tag, in WorkSource ws);
+
+    void updateWifiLockWorkSource(IBinder lock, in WorkSource ws);
 
     boolean releaseWifiLock(IBinder lock);
 
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 9d21521..dd162f2 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -23,6 +23,7 @@
 import android.os.IBinder;
 import android.os.Handler;
 import android.os.RemoteException;
+import android.os.WorkSource;
 
 import java.util.List;
 
@@ -872,6 +873,7 @@
         int mLockType;
         private boolean mRefCounted;
         private boolean mHeld;
+        private WorkSource mWorkSource;
 
         private WifiLock(int lockType, String tag) {
             mTag = tag;
@@ -897,7 +899,7 @@
             synchronized (mBinder) {
                 if (mRefCounted ? (++mRefCount > 0) : (!mHeld)) {
                     try {
-                        mService.acquireWifiLock(mBinder, mLockType, mTag);
+                        mService.acquireWifiLock(mBinder, mLockType, mTag, mWorkSource);
                         synchronized (WifiManager.this) {
                             if (mActiveLockCount >= MAX_ACTIVE_LOCKS) {
                                 mService.releaseWifiLock(mBinder);
@@ -969,6 +971,32 @@
             }
         }
 
+        public void setWorkSource(WorkSource ws) {
+            synchronized (mBinder) {
+                if (ws != null && ws.size() == 0) {
+                    ws = null;
+                }
+                boolean changed = true;
+                if (ws == null) {
+                    mWorkSource = null;
+                } else if (mWorkSource == null) {
+                    changed = mWorkSource != null;
+                    mWorkSource = new WorkSource(ws);
+                } else {
+                    changed = mWorkSource.diff(ws);
+                    if (changed) {
+                        mWorkSource.set(ws);
+                    }
+                }
+                if (changed && mHeld) {
+                    try {
+                        mService.updateWifiLockWorkSource(mBinder, mWorkSource);
+                    } catch (RemoteException e) {
+                    }
+                }
+            }
+        }
+
         public String toString() {
             String s1, s2, s3;
             synchronized (mBinder) {
diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java
index 22dbda3..9d27bde 100644
--- a/wifi/java/android/net/wifi/WifiStateTracker.java
+++ b/wifi/java/android/net/wifi/WifiStateTracker.java
@@ -38,6 +38,7 @@
 import android.os.Looper;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.WorkSource;
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.EventLog;
@@ -323,6 +324,21 @@
     private static String[] sDnsPropNames;
 
     /**
+     * Keep track of whether we last told the battery stats we had started.
+     */
+    private boolean mReportedRunning = false;
+
+    /**
+     * Most recently set source of starting WIFI.
+     */
+    private final WorkSource mRunningWifiUids = new WorkSource();
+
+    /**
+     * The last reported UIDs that were responsible for starting WIFI.
+     */
+    private final WorkSource mLastRunningWifiUids = new WorkSource();
+
+    /**
      * A structure for supplying information about a supplicant state
      * change in the STATE_CHANGE event message that comes from the
      * WifiMonitor
@@ -632,12 +648,35 @@
         return mRunState == RUN_STATE_STOPPED || mRunState == RUN_STATE_STOPPING;
     }
 
-    private void noteRunState() {
+    public void updateBatteryWorkSourceLocked(WorkSource newSource) {
         try {
+            if (newSource != null) {
+                mRunningWifiUids.set(newSource);
+            }
             if (mRunState == RUN_STATE_RUNNING) {
-                mBatteryStats.noteWifiRunning();
+                if (mReportedRunning) {
+                    // If the work source has changed since last time, need
+                    // to remove old work from battery stats.
+                    if (mLastRunningWifiUids.diff(mRunningWifiUids)) {
+                        mBatteryStats.noteWifiRunningChanged(mLastRunningWifiUids,
+                                mRunningWifiUids);
+                        mLastRunningWifiUids.set(mRunningWifiUids);
+                    }
+                } else {
+                    // Now being started, report it.
+                    mBatteryStats.noteWifiRunning(mRunningWifiUids);
+                    mLastRunningWifiUids.set(mRunningWifiUids);
+                    mReportedRunning = true;
+                }
             } else if (mRunState == RUN_STATE_STOPPED) {
-                mBatteryStats.noteWifiStopped();
+                if (mReportedRunning) {
+                    // Last reported we were running, time to stop.
+                    mBatteryStats.noteWifiStopped(mLastRunningWifiUids);
+                    mLastRunningWifiUids.clear();
+                    mReportedRunning = false;
+                }
+            } else {
+                // State in transition -- nothing to update yet.
             }
         } catch (RemoteException ignore) {
         }
@@ -801,7 +840,9 @@
         switch (msg.what) {
             case EVENT_SUPPLICANT_CONNECTION:
                 mRunState = RUN_STATE_RUNNING;
-                noteRunState();
+                synchronized (this) {
+                    updateBatteryWorkSourceLocked(null);
+                }
                 checkUseStaticIp();
                 /* Reset notification state on new connection */
                 resetNotificationTimer();
@@ -875,7 +916,9 @@
 
             case EVENT_SUPPLICANT_DISCONNECT:
                 mRunState = RUN_STATE_STOPPED;
-                noteRunState();
+                synchronized (this) {
+                    updateBatteryWorkSourceLocked(null);
+                }
                 boolean died = mWifiState.get() != WIFI_STATE_DISABLED &&
                                mWifiState.get() != WIFI_STATE_DISABLING;
                 if (died) {
@@ -1267,7 +1310,9 @@
                     mWM.setWifiEnabled(true);
                     break;
                 }
-                noteRunState();
+                synchronized (this) {
+                    updateBatteryWorkSourceLocked(null);
+                }
                 break;
 
             case EVENT_PASSWORD_KEY_MAY_BE_INCORRECT: