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=""continuous""
+ value=""continuous-video""
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<android.location.Address>">
-</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<android.location.Address>">
-</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=""android.media.action.CLOSE_AUDIO_EFFECT_CONTROL_SESSION""
+ 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=""android.media.action.DISPLAY_AUDIO_EFFECT_CONTROL_PANEL""
+ 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=""android.media.action.OPEN_AUDIO_EFFECT_CONTROL_SESSION""
+ 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=""android.media.extra.AUDIO_SESSION""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_CONTENT_TYPE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.media.extra.CONTENT_TYPE""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_PACKAGE_NAME"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.media.extra.PACKAGE_NAME""
+ 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 < historySize; h++) {
+ * System.out.printf("At time %d:", ev.getHistoricalEventTime(h));
+ * for (int p = 0; p < 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 < 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) {
+ @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() {
+ @Override public void enter() {
Log.d(TAG, "mP1.enter");
}
- @Override public boolean processMessage(Message message) {
+ @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() {
+ @Override public void exit() {
Log.d(TAG, "mP1.exit");
}
}
class S1 extends HierarchicalState {
- @Override public void enter() {
+ @Override public void enter() {
Log.d(TAG, "mS1.enter");
}
- @Override public boolean processMessage(Message message) {
+ @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() {
+ @Override public void exit() {
Log.d(TAG, "mS1.exit");
}
}
class S2 extends HierarchicalState {
- @Override public void enter() {
+ @Override public void enter() {
Log.d(TAG, "mS2.enter");
}
- @Override public boolean processMessage(Message message) {
+ @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() {
+ @Override public void exit() {
Log.d(TAG, "mS2.exit");
}
}
class P2 extends HierarchicalState {
- @Override public void enter() {
+ @Override public void enter() {
Log.d(TAG, "mP2.enter");
sendMessage(obtainMessage(CMD_5));
}
- @Override public boolean processMessage(Message message) {
+ @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() {
+ @Override public void exit() {
Log.d(TAG, "mP2.exit");
}
}
- @Override
+ @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 "custom" 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 "custom" 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> <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> <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> <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> <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> <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,
¶m, 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: