am 7e8566a6: am d7f659e8: Merge "Fail gracefully if the user fails to supply necessary args to bmgr" into kraken
diff --git a/Android.mk b/Android.mk
index 3041065..a43e8c8 100644
--- a/Android.mk
+++ b/Android.mk
@@ -194,7 +194,7 @@
$(framework-res-source-path)/com/android/internal/R.java
LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core ext
+LOCAL_JAVA_LIBRARIES := core core-junit ext
LOCAL_MODULE := framework
LOCAL_MODULE_CLASS := JAVA_LIBRARIES
@@ -302,34 +302,14 @@
# Intentionally not included from libcore:
# icu openssl suncompat support
libcore_to_document := \
- annotation/src/main/java/java \
- archive/src/main/java/java \
- auth/src/main/java/javax \
- awt-kernel/src/main/java/java \
- concurrent/src/main/java \
- crypto/src/main/java/javax \
dalvik/src/main/java/dalvik \
json/src/main/java \
junit/src/main/java \
- logging/src/main/java/java \
luni/src/main/java/java \
- luni-kernel/src/main/java/java \
- math/src/main/java/java \
- nio/src/main/java/java \
- nio_char/src/main/java/java \
- prefs/src/main/java/java \
- regex/src/main/java/java \
- security/src/main/java/java \
- security/src/main/java/javax \
- security-kernel/src/main/java/java \
- sql/src/main/java/java \
- sql/src/main/java/javax \
- text/src/main/java/java \
- x-net/src/main/java/javax \
- xml/src/main/java/javax \
- xml/src/main/java/org/xml/sax \
+ luni/src/main/java/javax \
+ luni/src/main/java/org/xml/sax \
+ luni/src/main/java/org/w3c \
xml/src/main/java/org/xmlpull/v1 \
- xml/src/main/java/org/w3c
non_base_dirs := \
../../external/apache-http/src/org/apache/http
@@ -486,7 +466,8 @@
include $(BUILD_DROIDDOC)
-$(full_target): $(framework_built)
+# $(gen), i.e. framework.aidl, is also needed while building against the current stub.
+$(full_target): $(framework_built) $(gen)
$(INTERNAL_PLATFORM_API_FILE): $(full_target)
$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_API_FILE))
diff --git a/api/9.xml b/api/9.xml
index b7596bd..20397df 100644
--- a/api/9.xml
+++ b/api/9.xml
@@ -147782,17 +147782,6 @@
visibility="public"
>
</constructor>
-<method name="abortUpdates"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
<method name="close"
return="void"
abstract="false"
@@ -147804,30 +147793,6 @@
visibility="public"
>
</method>
-<method name="commitUpdates"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="commitUpdates"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="values" type="java.util.Map<? extends java.lang.Long, ? extends java.util.Map<java.lang.String, java.lang.Object>>">
-</parameter>
-</method>
<method name="copyStringToBuffer"
return="void"
abstract="false"
@@ -147854,17 +147819,6 @@
visibility="public"
>
</method>
-<method name="deleteRow"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
<method name="getBlob"
return="byte[]"
abstract="false"
@@ -148061,17 +148015,6 @@
visibility="public"
>
</method>
-<method name="hasUpdates"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
<method name="isAfterLast"
return="boolean"
abstract="false"
@@ -148275,17 +148218,6 @@
<parameter name="uri" type="android.net.Uri">
</parameter>
</method>
-<method name="supportsUpdates"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
<method name="unregisterContentObserver"
return="void"
abstract="false"
@@ -148312,124 +148244,6 @@
<parameter name="observer" type="android.database.DataSetObserver">
</parameter>
</method>
-<method name="updateBlob"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="columnIndex" type="int">
-</parameter>
-<parameter name="value" type="byte[]">
-</parameter>
-</method>
-<method name="updateDouble"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="columnIndex" type="int">
-</parameter>
-<parameter name="value" type="double">
-</parameter>
-</method>
-<method name="updateFloat"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="columnIndex" type="int">
-</parameter>
-<parameter name="value" type="float">
-</parameter>
-</method>
-<method name="updateInt"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="columnIndex" type="int">
-</parameter>
-<parameter name="value" type="int">
-</parameter>
-</method>
-<method name="updateLong"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="columnIndex" type="int">
-</parameter>
-<parameter name="value" type="long">
-</parameter>
-</method>
-<method name="updateShort"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="columnIndex" type="int">
-</parameter>
-<parameter name="value" type="short">
-</parameter>
-</method>
-<method name="updateString"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="columnIndex" type="int">
-</parameter>
-<parameter name="value" type="java.lang.String">
-</parameter>
-</method>
-<method name="updateToNull"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="columnIndex" type="int">
-</parameter>
-</method>
</class>
<class name="MockDialogInterface"
extends="java.lang.Object"
@@ -164696,7 +164510,7 @@
type="java.lang.String"
transient="false"
volatile="false"
- value=""((aero|arpa|asia|a[cdefgilmnoqrstuwxz])|(biz|b[abdefghijmnorstvwyz])|(cat|com|coop|c[acdfghiklmnoruvxyz])|d[ejkmoz]|(edu|e[cegrstu])|f[ijkmor]|(gov|g[abdefghilmnpqrstuwy])|h[kmnrtu]|(info|int|i[delmnoqrst])|(jobs|j[emop])|k[eghimnprwyz]|l[abcikrstuvy]|(mil|mobi|museum|m[acdeghklmnopqrstuvwxyz])|(name|net|n[acefgilopruz])|(org|om)|(pro|p[aefghklmnrstwy])|qa|r[eosuw]|s[abcdeghijklmnortuvyz]|(tel|travel|t[cdfghjklmnoprtvwz])|u[agksyz]|v[aceginu]|w[fs]|(xn\\-\\-0zwm56d|xn\\-\\-11b5bs3a9aj6g|xn\\-\\-80akhbyknj4f|xn\\-\\-9t4b11yi5a|xn\\-\\-deba0ad|xn\\-\\-g6w251d|xn\\-\\-hgbk6aj7f53bba|xn\\-\\-hlcj6aya9esc7a|xn\\-\\-jxalpdlp|xn\\-\\-kgbechtv|xn\\-\\-zckzah)|y[etu]|z[amw])""
+ value=""((aero|arpa|asia|a[cdefgilmnoqrstuwxz])|(biz|b[abdefghijmnorstvwyz])|(cat|com|coop|c[acdfghiklmnoruvxyz])|d[ejkmoz]|(edu|e[cegrstu])|f[ijkmor]|(gov|g[abdefghilmnpqrstuwy])|h[kmnrtu]|(info|int|i[delmnoqrst])|(jobs|j[emop])|k[eghimnprwyz]|l[abcikrstuvy]|(mil|mobi|museum|m[acdeghklmnopqrstuvwxyz])|(name|net|n[acefgilopruz])|(org|om)|(pro|p[aefghklmnrstwy])|qa|r[eosuw]|s[abcdeghijklmnortuvyz]|(tel|travel|t[cdfghjklmnoprtvwz])|u[agksyz]|v[aceginu]|w[fs]|(xn\\-\\-0zwm56d|xn\\-\\-11b5bs3a9aj6g|xn\\-\\-80akhbyknj4f|xn\\-\\-9t4b11yi5a|xn\\-\\-deba0ad|xn\\-\\-g6w251d|xn\\-\\-hgbk6aj7f53bba|xn\\-\\-hlcj6aya9esc7a|xn\\-\\-jxalpdlp|xn\\-\\-kgbechtv|xn\\-\\-mgbaam7a8h|xn\\-\\-mgberp4a5d4ar|xn\\-\\-wgbh1c|xn\\-\\-zckzah)|y[et]|z[amw])""
static="true"
final="true"
deprecated="not deprecated"
@@ -164707,7 +164521,7 @@
type="java.lang.String"
transient="false"
volatile="false"
- value=""(?:(?:aero|arpa|asia|a[cdefgilmnoqrstuwxz])|(?:biz|b[abdefghijmnorstvwyz])|(?:cat|com|coop|c[acdfghiklmnoruvxyz])|d[ejkmoz]|(?:edu|e[cegrstu])|f[ijkmor]|(?:gov|g[abdefghilmnpqrstuwy])|h[kmnrtu]|(?:info|int|i[delmnoqrst])|(?:jobs|j[emop])|k[eghimnprwyz]|l[abcikrstuvy]|(?:mil|mobi|museum|m[acdeghklmnopqrstuvwxyz])|(?:name|net|n[acefgilopruz])|(?:org|om)|(?:pro|p[aefghklmnrstwy])|qa|r[eosuw]|s[abcdeghijklmnortuvyz]|(?:tel|travel|t[cdfghjklmnoprtvwz])|u[agksyz]|v[aceginu]|w[fs]|(?:xn\\-\\-0zwm56d|xn\\-\\-11b5bs3a9aj6g|xn\\-\\-80akhbyknj4f|xn\\-\\-9t4b11yi5a|xn\\-\\-deba0ad|xn\\-\\-g6w251d|xn\\-\\-hgbk6aj7f53bba|xn\\-\\-hlcj6aya9esc7a|xn\\-\\-jxalpdlp|xn\\-\\-kgbechtv|xn\\-\\-zckzah)|y[etu]|z[amw]))""
+ value=""(?:(?:aero|arpa|asia|a[cdefgilmnoqrstuwxz])|(?:biz|b[abdefghijmnorstvwyz])|(?:cat|com|coop|c[acdfghiklmnoruvxyz])|d[ejkmoz]|(?:edu|e[cegrstu])|f[ijkmor]|(?:gov|g[abdefghilmnpqrstuwy])|h[kmnrtu]|(?:info|int|i[delmnoqrst])|(?:jobs|j[emop])|k[eghimnprwyz]|l[abcikrstuvy]|(?:mil|mobi|museum|m[acdeghklmnopqrstuvwxyz])|(?:name|net|n[acefgilopruz])|(?:org|om)|(?:pro|p[aefghklmnrstwy])|qa|r[eosuw]|s[abcdeghijklmnortuvyz]|(?:tel|travel|t[cdfghjklmnoprtvwz])|u[agksyz]|v[aceginu]|w[fs]|(?:xn\\-\\-0zwm56d|xn\\-\\-11b5bs3a9aj6g|xn\\-\\-80akhbyknj4f|xn\\-\\-9t4b11yi5a|xn\\-\\-deba0ad|xn\\-\\-g6w251d|xn\\-\\-hgbk6aj7f53bba|xn\\-\\-hlcj6aya9esc7a|xn\\-\\-jxalpdlp|xn\\-\\-kgbechtv|xn\\-\\-mgbaam7a8h|xn\\-\\-mgberp4a5d4ar|xn\\-\\-wgbh1c|xn\\-\\-zckzah)|y[et]|z[amw]))""
static="true"
final="true"
deprecated="not deprecated"
@@ -216572,33 +216386,6 @@
</package>
<package name="dalvik.system"
>
-<class name="AllocationLimitError"
- extends="java.lang.VirtualMachineError"
- abstract="false"
- static="false"
- final="false"
- deprecated="deprecated"
- visibility="public"
->
-<constructor name="AllocationLimitError"
- type="dalvik.system.AllocationLimitError"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</constructor>
-<constructor name="AllocationLimitError"
- type="dalvik.system.AllocationLimitError"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="detailMessage" type="java.lang.String">
-</parameter>
-</constructor>
-</class>
<class name="DexClassLoader"
extends="java.lang.ClassLoader"
abstract="false"
@@ -216778,1010 +216565,6 @@
</parameter>
</constructor>
</class>
-<class name="PotentialDeadlockError"
- extends="java.lang.VirtualMachineError"
- abstract="false"
- static="false"
- final="false"
- deprecated="deprecated"
- visibility="public"
->
-<constructor name="PotentialDeadlockError"
- type="dalvik.system.PotentialDeadlockError"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</constructor>
-<constructor name="PotentialDeadlockError"
- type="dalvik.system.PotentialDeadlockError"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="detailMessage" type="java.lang.String">
-</parameter>
-</constructor>
-</class>
-<class name="StaleDexCacheError"
- extends="java.lang.VirtualMachineError"
- abstract="false"
- static="false"
- final="false"
- deprecated="deprecated"
- visibility="public"
->
-<constructor name="StaleDexCacheError"
- type="dalvik.system.StaleDexCacheError"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</constructor>
-<constructor name="StaleDexCacheError"
- type="dalvik.system.StaleDexCacheError"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="detailMessage" type="java.lang.String">
-</parameter>
-</constructor>
-</class>
-<class name="TemporaryDirectory"
- extends="java.lang.Object"
- abstract="false"
- static="false"
- final="false"
- deprecated="deprecated"
- visibility="public"
->
-<constructor name="TemporaryDirectory"
- type="dalvik.system.TemporaryDirectory"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</constructor>
-<method name="setUpDirectory"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="baseDir" type="java.lang.String">
-</parameter>
-</method>
-<method name="setUpDirectory"
- return="void"
- abstract="false"
- native="false"
- synchronized="true"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="baseDir" type="java.io.File">
-</parameter>
-</method>
-</class>
-<class name="TouchDex"
- extends="java.lang.Object"
- abstract="false"
- static="false"
- final="false"
- deprecated="deprecated"
- visibility="public"
->
-<constructor name="TouchDex"
- type="dalvik.system.TouchDex"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</constructor>
-<method name="main"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="args" type="java.lang.String[]">
-</parameter>
-</method>
-<method name="start"
- return="int"
- abstract="false"
- native="false"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="dexFiles" type="java.lang.String">
-</parameter>
-</method>
-</class>
-<class name="VMDebug"
- extends="java.lang.Object"
- abstract="false"
- static="false"
- final="true"
- deprecated="deprecated"
- visibility="public"
->
-<method name="dumpHprofData"
- return="void"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="fileName" type="java.lang.String">
-</parameter>
-<exception name="IOException" type="java.io.IOException">
-</exception>
-</method>
-<method name="getAllocCount"
- return="int"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="kind" type="int">
-</parameter>
-</method>
-<method name="getInstructionCount"
- return="void"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="counts" type="int[]">
-</parameter>
-</method>
-<method name="getLoadedClassCount"
- return="int"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="isDebuggerConnected"
- return="boolean"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="isDebuggingEnabled"
- return="boolean"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="lastDebuggerActivity"
- return="long"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="printLoadedClasses"
- return="void"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="flags" type="int">
-</parameter>
-</method>
-<method name="resetAllocCount"
- return="void"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="kinds" type="int">
-</parameter>
-</method>
-<method name="resetInstructionCount"
- return="void"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="setAllocationLimit"
- return="int"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="limit" type="int">
-</parameter>
-</method>
-<method name="setGlobalAllocationLimit"
- return="int"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="limit" type="int">
-</parameter>
-</method>
-<method name="startAllocCounting"
- return="void"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="startEmulatorTracing"
- return="void"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="startInstructionCounting"
- return="void"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="startMethodTracing"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="true"
- final="false"
- deprecated="deprecated"
- visibility="public"
->
-</method>
-<method name="startMethodTracing"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="traceFileName" type="java.lang.String">
-</parameter>
-<parameter name="bufferSize" type="int">
-</parameter>
-<parameter name="flags" type="int">
-</parameter>
-</method>
-<method name="stopAllocCounting"
- return="void"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="stopEmulatorTracing"
- return="void"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="stopInstructionCounting"
- return="void"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="stopMethodTracing"
- return="void"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="threadCpuTimeNanos"
- return="long"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<field name="DEFAULT_METHOD_TRACE_FILE_NAME"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value=""/sdcard/dmtrace.trace""
- static="true"
- final="true"
- deprecated="deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_ALL_COUNTS"
- type="int"
- transient="false"
- volatile="false"
- value="-1"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_GLOBAL_ALLOCATED_BYTES"
- type="int"
- transient="false"
- volatile="false"
- value="2"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_GLOBAL_ALLOCATED_OBJECTS"
- type="int"
- transient="false"
- volatile="false"
- value="1"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_GLOBAL_CLASS_INIT_COUNT"
- type="int"
- transient="false"
- volatile="false"
- value="32"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_GLOBAL_CLASS_INIT_TIME"
- type="int"
- transient="false"
- volatile="false"
- value="64"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_GLOBAL_EXT_ALLOCATED_BYTES"
- type="int"
- transient="false"
- volatile="false"
- value="8192"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_GLOBAL_EXT_ALLOCATED_OBJECTS"
- type="int"
- transient="false"
- volatile="false"
- value="4096"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_GLOBAL_EXT_FREED_BYTES"
- type="int"
- transient="false"
- volatile="false"
- value="32768"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_GLOBAL_EXT_FREED_OBJECTS"
- type="int"
- transient="false"
- volatile="false"
- value="16384"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_GLOBAL_FREED_BYTES"
- type="int"
- transient="false"
- volatile="false"
- value="8"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_GLOBAL_FREED_OBJECTS"
- type="int"
- transient="false"
- volatile="false"
- value="4"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_GLOBAL_GC_INVOCATIONS"
- type="int"
- transient="false"
- volatile="false"
- value="16"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_THREAD_ALLOCATED_BYTES"
- type="int"
- transient="false"
- volatile="false"
- value="131072"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_THREAD_ALLOCATED_OBJECTS"
- type="int"
- transient="false"
- volatile="false"
- value="65536"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_THREAD_CLASS_INIT_COUNT"
- type="int"
- transient="false"
- volatile="false"
- value="2097152"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_THREAD_CLASS_INIT_TIME"
- type="int"
- transient="false"
- volatile="false"
- value="4194304"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_THREAD_EXT_ALLOCATED_BYTES"
- type="int"
- transient="false"
- volatile="false"
- value="536870912"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_THREAD_EXT_ALLOCATED_OBJECTS"
- type="int"
- transient="false"
- volatile="false"
- value="268435456"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_THREAD_EXT_FREED_BYTES"
- type="int"
- transient="false"
- volatile="false"
- value="-2147483648"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_THREAD_EXT_FREED_OBJECTS"
- type="int"
- transient="false"
- volatile="false"
- value="1073741824"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_THREAD_FREED_BYTES"
- type="int"
- transient="false"
- volatile="false"
- value="524288"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_THREAD_FREED_OBJECTS"
- type="int"
- transient="false"
- volatile="false"
- value="262144"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_THREAD_GC_INVOCATIONS"
- type="int"
- transient="false"
- volatile="false"
- value="1048576"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="TRACE_COUNT_ALLOCS"
- type="int"
- transient="false"
- volatile="false"
- value="1"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-</class>
-<class name="VMRuntime"
- extends="java.lang.Object"
- abstract="false"
- static="false"
- final="true"
- deprecated="deprecated"
- visibility="public"
->
-<method name="gcSoftReferences"
- return="void"
- abstract="false"
- native="true"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="getExternalBytesAllocated"
- return="long"
- abstract="false"
- native="true"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="getMinimumHeapSize"
- return="long"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="getRuntime"
- return="dalvik.system.VMRuntime"
- abstract="false"
- native="false"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="getTargetHeapUtilization"
- return="float"
- abstract="false"
- native="true"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="runFinalizationSync"
- return="void"
- abstract="false"
- native="true"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="setMinimumHeapSize"
- return="long"
- abstract="false"
- native="false"
- synchronized="true"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="size" type="long">
-</parameter>
-</method>
-<method name="setTargetHeapUtilization"
- return="float"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="newTarget" type="float">
-</parameter>
-</method>
-</class>
-<class name="VMStack"
- extends="java.lang.Object"
- abstract="false"
- static="false"
- final="true"
- deprecated="deprecated"
- visibility="public"
->
-<constructor name="VMStack"
- type="dalvik.system.VMStack"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</constructor>
-<method name="getCallingClassLoader"
- return="java.lang.ClassLoader"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="getCallingClassLoader2"
- return="java.lang.ClassLoader"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="getClasses"
- return="java.lang.Class<?>[]"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="maxDepth" type="int">
-</parameter>
-<parameter name="stopAtPrivileged" type="boolean">
-</parameter>
-</method>
-<method name="getThreadStackTrace"
- return="java.lang.StackTraceElement[]"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="t" type="java.lang.Thread">
-</parameter>
-</method>
-</class>
-<class name="Zygote"
- extends="java.lang.Object"
- abstract="false"
- static="false"
- final="false"
- deprecated="deprecated"
- visibility="public"
->
-<method name="fork"
- return="int"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="forkAndSpecialize"
- return="int"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="uid" type="int">
-</parameter>
-<parameter name="gid" type="int">
-</parameter>
-<parameter name="gids" type="int[]">
-</parameter>
-<parameter name="debugFlags" type="int">
-</parameter>
-<parameter name="rlimits" type="int[][]">
-</parameter>
-</method>
-<method name="forkAndSpecialize"
- return="int"
- abstract="false"
- native="false"
- synchronized="false"
- static="true"
- final="false"
- deprecated="deprecated"
- visibility="public"
->
-<parameter name="uid" type="int">
-</parameter>
-<parameter name="gid" type="int">
-</parameter>
-<parameter name="gids" type="int[]">
-</parameter>
-<parameter name="enableDebugger" type="boolean">
-</parameter>
-<parameter name="rlimits" type="int[][]">
-</parameter>
-</method>
-<method name="forkSystemServer"
- return="int"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="uid" type="int">
-</parameter>
-<parameter name="gid" type="int">
-</parameter>
-<parameter name="gids" type="int[]">
-</parameter>
-<parameter name="debugFlags" type="int">
-</parameter>
-<parameter name="rlimits" type="int[][]">
-</parameter>
-</method>
-<method name="forkSystemServer"
- return="int"
- abstract="false"
- native="false"
- synchronized="false"
- static="true"
- final="false"
- deprecated="deprecated"
- visibility="public"
->
-<parameter name="uid" type="int">
-</parameter>
-<parameter name="gid" type="int">
-</parameter>
-<parameter name="gids" type="int[]">
-</parameter>
-<parameter name="enableDebugger" type="boolean">
-</parameter>
-<parameter name="rlimits" type="int[][]">
-</parameter>
-</method>
-<field name="DEBUG_ENABLE_ASSERT"
- type="int"
- transient="false"
- volatile="false"
- value="4"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="DEBUG_ENABLE_CHECKJNI"
- type="int"
- transient="false"
- volatile="false"
- value="2"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="DEBUG_ENABLE_DEBUGGER"
- type="int"
- transient="false"
- volatile="false"
- value="1"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="DEBUG_ENABLE_SAFEMODE"
- type="int"
- transient="false"
- volatile="false"
- value="8"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-</class>
</package>
<package name="java.awt.font"
>
@@ -288545,21 +287328,6 @@
<parameter name="where" type="java.util.Locale">
</parameter>
</method>
-<method name="getInt"
- return="int"
- abstract="false"
- native="false"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="protected"
->
-<parameter name="buf" type="byte[]">
-</parameter>
-<parameter name="offset" type="int">
-</parameter>
-</method>
<method name="getLineInstance"
return="java.text.BreakIterator"
abstract="false"
@@ -288584,21 +287352,6 @@
<parameter name="where" type="java.util.Locale">
</parameter>
</method>
-<method name="getLong"
- return="long"
- abstract="false"
- native="false"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="protected"
->
-<parameter name="buf" type="byte[]">
-</parameter>
-<parameter name="offset" type="int">
-</parameter>
-</method>
<method name="getSentenceInstance"
return="java.text.BreakIterator"
abstract="false"
@@ -288623,21 +287376,6 @@
<parameter name="where" type="java.util.Locale">
</parameter>
</method>
-<method name="getShort"
- return="short"
- abstract="false"
- native="false"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="protected"
->
-<parameter name="buf" type="byte[]">
-</parameter>
-<parameter name="offset" type="int">
-</parameter>
-</method>
<method name="getText"
return="java.text.CharacterIterator"
abstract="true"
@@ -289255,9 +287993,9 @@
</class>
<class name="CollationKey"
extends="java.lang.Object"
- abstract="false"
+ abstract="true"
static="false"
- final="true"
+ final="false"
deprecated="not deprecated"
visibility="public"
>
@@ -289265,7 +288003,7 @@
</implements>
<method name="compareTo"
return="int"
- abstract="false"
+ abstract="true"
native="false"
synchronized="false"
static="false"
@@ -289289,7 +288027,7 @@
</method>
<method name="toByteArray"
return="byte[]"
- abstract="false"
+ abstract="true"
native="false"
synchronized="false"
static="false"
@@ -291013,7 +289751,7 @@
extends="java.lang.Object"
abstract="false"
static="false"
- final="true"
+ final="false"
deprecated="not deprecated"
visibility="public"
>
@@ -291515,7 +290253,7 @@
static="false"
final="false"
deprecated="not deprecated"
- visibility="public"
+ visibility="protected"
>
</constructor>
<method name="clone"
@@ -291915,7 +290653,7 @@
static="false"
final="false"
deprecated="not deprecated"
- visibility="public"
+ visibility="protected"
>
</constructor>
<method name="format"
@@ -305629,7 +304367,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="tasks" type="java.util.Collection<java.util.concurrent.Callable<T>>">
+<parameter name="tasks" type="java.util.Collection<? extends java.util.concurrent.Callable<T>>">
</parameter>
<exception name="InterruptedException" type="java.lang.InterruptedException">
</exception>
@@ -305644,7 +304382,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="tasks" type="java.util.Collection<java.util.concurrent.Callable<T>>">
+<parameter name="tasks" type="java.util.Collection<? extends java.util.concurrent.Callable<T>>">
</parameter>
<parameter name="timeout" type="long">
</parameter>
@@ -305663,7 +304401,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="tasks" type="java.util.Collection<java.util.concurrent.Callable<T>>">
+<parameter name="tasks" type="java.util.Collection<? extends java.util.concurrent.Callable<T>>">
</parameter>
<exception name="ExecutionException" type="java.util.concurrent.ExecutionException">
</exception>
@@ -305680,7 +304418,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="tasks" type="java.util.Collection<java.util.concurrent.Callable<T>>">
+<parameter name="tasks" type="java.util.Collection<? extends java.util.concurrent.Callable<T>>">
</parameter>
<parameter name="timeout" type="long">
</parameter>
@@ -307693,7 +306431,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="tasks" type="java.util.Collection<java.util.concurrent.Callable<T>>">
+<parameter name="tasks" type="java.util.Collection<? extends java.util.concurrent.Callable<T>>">
</parameter>
<exception name="InterruptedException" type="java.lang.InterruptedException">
</exception>
@@ -307708,7 +306446,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="tasks" type="java.util.Collection<java.util.concurrent.Callable<T>>">
+<parameter name="tasks" type="java.util.Collection<? extends java.util.concurrent.Callable<T>>">
</parameter>
<parameter name="timeout" type="long">
</parameter>
@@ -307727,7 +306465,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="tasks" type="java.util.Collection<java.util.concurrent.Callable<T>>">
+<parameter name="tasks" type="java.util.Collection<? extends java.util.concurrent.Callable<T>>">
</parameter>
<exception name="ExecutionException" type="java.util.concurrent.ExecutionException">
</exception>
@@ -307744,7 +306482,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="tasks" type="java.util.Collection<java.util.concurrent.Callable<T>>">
+<parameter name="tasks" type="java.util.Collection<? extends java.util.concurrent.Callable<T>>">
</parameter>
<parameter name="timeout" type="long">
</parameter>
@@ -307889,7 +306627,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="action" type="java.security.PrivilegedAction">
+<parameter name="action" type="java.security.PrivilegedAction<?>">
</parameter>
</method>
<method name="callable"
@@ -307902,7 +306640,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="action" type="java.security.PrivilegedExceptionAction">
+<parameter name="action" type="java.security.PrivilegedExceptionAction<?>">
</parameter>
</method>
<method name="defaultThreadFactory"
@@ -312227,7 +310965,7 @@
static="false"
final="false"
deprecated="not deprecated"
- visibility=""
+ visibility="public"
>
<implements name="java.io.Serializable">
</implements>
@@ -337413,11 +336151,11 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="parameters" type="java.util.List">
+<parameter name="parameters" type="java.util.List<java.security.KeyStore.Builder>">
</parameter>
</constructor>
<method name="getParameters"
- return="java.util.List"
+ return="java.util.List<java.security.KeyStore.Builder>"
abstract="false"
native="false"
synchronized="false"
@@ -339048,7 +337786,7 @@
visibility="public"
>
<method name="getIds"
- return="java.util.Enumeration"
+ return="java.util.Enumeration<byte[]>"
abstract="true"
native="false"
synchronized="false"
diff --git a/api/current.xml b/api/current.xml
index d002534..0ffbb1b 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -2132,6 +2132,17 @@
visibility="public"
>
</field>
+<field name="adapter"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843521"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="addStatesFromChildren"
type="int"
transient="false"
@@ -2165,6 +2176,17 @@
visibility="public"
>
</field>
+<field name="allContactsName"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843533"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="allowBackup"
type="int"
transient="false"
@@ -2341,6 +2363,17 @@
visibility="public"
>
</field>
+<field name="as"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843527"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="author"
type="int"
transient="false"
@@ -3001,6 +3034,17 @@
visibility="public"
>
</field>
+<field name="column"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843530"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="columnDelay"
type="int"
transient="false"
@@ -3144,6 +3188,17 @@
visibility="public"
>
</field>
+<field name="customNavigationLayout"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843539"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="cycles"
type="int"
transient="false"
@@ -3408,6 +3463,17 @@
visibility="public"
>
</field>
+<field name="displayOptions"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843537"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="dither"
type="int"
transient="false"
@@ -4167,6 +4233,17 @@
visibility="public"
>
</field>
+<field name="from"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843525"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="fromAlpha"
type="int"
transient="false"
@@ -4189,6 +4266,17 @@
visibility="public"
>
</field>
+<field name="fromValue"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843528"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="fromXDelta"
type="int"
transient="false"
@@ -4475,6 +4563,17 @@
visibility="public"
>
</field>
+<field name="hardwareAccelerated"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843540"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="hasCode"
type="int"
transient="false"
@@ -6818,6 +6917,17 @@
visibility="public"
>
</field>
+<field name="navigationMode"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843536"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="negativeButtonText"
type="int"
transient="false"
@@ -8303,6 +8413,17 @@
visibility="public"
>
</field>
+<field name="selection"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843522"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="settingsActivity"
type="int"
transient="false"
@@ -8490,6 +8611,17 @@
visibility="public"
>
</field>
+<field name="sortOrder"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843523"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="soundEffectsEnabled"
type="int"
transient="false"
@@ -8842,6 +8974,17 @@
visibility="public"
>
</field>
+<field name="subtitle"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843538"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="suggestActionMsg"
type="int"
transient="false"
@@ -9678,6 +9821,17 @@
visibility="public"
>
</field>
+<field name="to"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843526"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="toAlpha"
type="int"
transient="false"
@@ -9700,6 +9854,17 @@
visibility="public"
>
</field>
+<field name="toValue"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843529"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="toXDelta"
type="int"
transient="false"
@@ -9876,6 +10041,17 @@
visibility="public"
>
</field>
+<field name="uri"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843524"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="useLevel"
type="int"
transient="false"
@@ -10217,6 +10393,28 @@
visibility="public"
>
</field>
+<field name="windowActionBar"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843534"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="windowActionBarStyle"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843535"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="windowAnimationStyle"
type="int"
transient="false"
@@ -10426,6 +10624,28 @@
visibility="public"
>
</field>
+<field name="withClass"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843532"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="withExpression"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843531"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="writePermission"
type="int"
transient="false"
@@ -14075,6 +14295,17 @@
visibility="public"
>
</field>
+<field name="home"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16908353"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="icon"
type="int"
transient="false"
@@ -16245,6 +16476,17 @@
visibility="public"
>
</field>
+<field name="Theme_WithActionBar"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16973969"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="Widget"
type="int"
transient="false"
@@ -16641,6 +16883,17 @@
visibility="public"
>
</field>
+<field name="Widget_Spinner_DropDown"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16973970"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="Widget_TabWidget"
type="int"
transient="false"
@@ -19067,6 +19320,501 @@
</package>
<package name="android.app"
>
+<class name="ActionBar"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="ActionBar"
+ type="android.app.ActionBar"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="getCustomNavigationView"
+ return="android.view.View"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getDisplayOptions"
+ return="int"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getNavigationMode"
+ return="int"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getSubtitle"
+ return="java.lang.CharSequence"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getTitle"
+ return="java.lang.CharSequence"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="setBackgroundDrawable"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="d" type="android.graphics.drawable.Drawable">
+</parameter>
+</method>
+<method name="setCallback"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="callback" type="android.app.ActionBar.Callback">
+</parameter>
+</method>
+<method name="setCustomNavigationMode"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="view" type="android.view.View">
+</parameter>
+</method>
+<method name="setDisplayOptions"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="options" type="int">
+</parameter>
+</method>
+<method name="setDisplayOptions"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="options" type="int">
+</parameter>
+<parameter name="mask" type="int">
+</parameter>
+</method>
+<method name="setDividerDrawable"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="d" type="android.graphics.drawable.Drawable">
+</parameter>
+</method>
+<method name="setDropdownNavigationMode"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="adapter" type="android.widget.SpinnerAdapter">
+</parameter>
+</method>
+<method name="setStandardNavigationMode"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="title" type="java.lang.CharSequence">
+</parameter>
+<parameter name="subtitle" type="java.lang.CharSequence">
+</parameter>
+</method>
+<method name="setStandardNavigationMode"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="title" type="java.lang.CharSequence">
+</parameter>
+</method>
+<method name="updateActionMenu"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="DISPLAY_HIDE_HOME"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="DISPLAY_USE_LOGO"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="NAVIGATION_MODE_CUSTOM"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="NAVIGATION_MODE_DROPDOWN_LIST"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="NAVIGATION_MODE_STANDARD"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="NAVIGATION_MODE_TABS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<interface name="ActionBar.Callback"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onActionItemClicked"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="item" type="android.view.MenuItem">
+</parameter>
+</method>
+<method name="onContextItemClicked"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="modeId" type="int">
+</parameter>
+<parameter name="item" type="android.view.MenuItem">
+</parameter>
+</method>
+<method name="onCreateActionMenu"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="menu" type="android.view.Menu">
+</parameter>
+</method>
+<method name="onCreateContextMode"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="modeId" type="int">
+</parameter>
+<parameter name="menu" type="android.view.Menu">
+</parameter>
+</method>
+<method name="onNavigationItemSelected"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="itemPosition" type="int">
+</parameter>
+<parameter name="itemId" type="long">
+</parameter>
+</method>
+<method name="onPrepareContextMode"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="modeId" type="int">
+</parameter>
+<parameter name="menu" type="android.view.Menu">
+</parameter>
+</method>
+<method name="onUpdateActionMenu"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="menu" type="android.view.Menu">
+</parameter>
+</method>
+</interface>
+<class name="ActionBar.SimpleCallback"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.app.ActionBar.Callback">
+</implements>
+<constructor name="ActionBar.SimpleCallback"
+ type="android.app.ActionBar.SimpleCallback"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="onActionItemClicked"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="item" type="android.view.MenuItem">
+</parameter>
+</method>
+<method name="onContextItemClicked"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="modeId" type="int">
+</parameter>
+<parameter name="item" type="android.view.MenuItem">
+</parameter>
+</method>
+<method name="onCreateActionMenu"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="menu" type="android.view.Menu">
+</parameter>
+</method>
+<method name="onCreateContextMode"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="modeId" type="int">
+</parameter>
+<parameter name="menu" type="android.view.Menu">
+</parameter>
+</method>
+<method name="onNavigationItemSelected"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="itemPosition" type="int">
+</parameter>
+<parameter name="itemId" type="long">
+</parameter>
+</method>
+<method name="onPrepareContextMode"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="modeId" type="int">
+</parameter>
+<parameter name="menu" type="android.view.Menu">
+</parameter>
+</method>
+<method name="onUpdateActionMenu"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="menu" type="android.view.Menu">
+</parameter>
+</method>
+</class>
<class name="Activity"
extends="android.view.ContextThemeWrapper"
abstract="false"
@@ -19212,6 +19960,32 @@
<parameter name="ev" type="android.view.MotionEvent">
</parameter>
</method>
+<method name="findFragmentById"
+ return="android.app.Fragment"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="id" type="int">
+</parameter>
+</method>
+<method name="findFragmentByTag"
+ return="android.app.Fragment"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="tag" type="java.lang.String">
+</parameter>
+</method>
<method name="findViewById"
return="android.view.View"
abstract="false"
@@ -19277,6 +20051,17 @@
<parameter name="child" type="android.app.Activity">
</parameter>
</method>
+<method name="getActionBar"
+ return="android.app.ActionBar"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getApplication"
return="android.app.Application"
abstract="false"
@@ -19521,6 +20306,17 @@
visibility="public"
>
</method>
+<method name="isChangingConfigurations"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="isChild"
return="boolean"
abstract="false"
@@ -20304,6 +21100,17 @@
<parameter name="view" type="android.view.View">
</parameter>
</method>
+<method name="openFragmentTransaction"
+ return="android.app.FragmentTransaction"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="openOptionsMenu"
return="void"
abstract="false"
@@ -20330,6 +21137,19 @@
<parameter name="exitAnim" type="int">
</parameter>
</method>
+<method name="popBackStack"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="name" type="java.lang.String">
+</parameter>
+</method>
<method name="registerForContextMenu"
return="void"
abstract="false"
@@ -20753,6 +21573,23 @@
<parameter name="requestCode" type="int">
</parameter>
</method>
+<method name="startActivityFromFragment"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fragment" type="android.app.Fragment">
+</parameter>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+<parameter name="requestCode" type="int">
+</parameter>
+</method>
<method name="startActivityIfNeeded"
return="boolean"
abstract="false"
@@ -24669,6 +25506,801 @@
</parameter>
</method>
</class>
+<class name="Fragment"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.content.ComponentCallbacks">
+</implements>
+<constructor name="Fragment"
+ type="android.app.Fragment"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="equals"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+<method name="getActivity"
+ return="android.app.Activity"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getRetainInstance"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getTag"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getView"
+ return="android.view.View"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="hashCode"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isAdded"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isHidden"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isVisible"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onActivityResult"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="requestCode" type="int">
+</parameter>
+<parameter name="resultCode" type="int">
+</parameter>
+<parameter name="data" type="android.content.Intent">
+</parameter>
+</method>
+<method name="onAttach"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="activity" type="android.app.Activity">
+</parameter>
+</method>
+<method name="onConfigurationChanged"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="newConfig" type="android.content.res.Configuration">
+</parameter>
+</method>
+<method name="onCreate"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="savedInstanceState" type="android.os.Bundle">
+</parameter>
+</method>
+<method name="onCreateAnimation"
+ return="android.view.animation.Animation"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="transit" type="int">
+</parameter>
+<parameter name="enter" type="boolean">
+</parameter>
+<parameter name="nextAnim" type="int">
+</parameter>
+</method>
+<method name="onCreateView"
+ return="android.view.View"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="inflater" type="android.view.LayoutInflater">
+</parameter>
+<parameter name="container" type="android.view.ViewGroup">
+</parameter>
+<parameter name="savedInstanceState" type="android.os.Bundle">
+</parameter>
+</method>
+<method name="onDestroy"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onDetach"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onHiddenChanged"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="hidden" type="boolean">
+</parameter>
+</method>
+<method name="onInflate"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="activity" type="android.app.Activity">
+</parameter>
+<parameter name="attrs" type="android.util.AttributeSet">
+</parameter>
+<parameter name="savedInstanceState" type="android.os.Bundle">
+</parameter>
+</method>
+<method name="onLowMemory"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onPause"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onReady"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="savedInstanceState" type="android.os.Bundle">
+</parameter>
+</method>
+<method name="onResume"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onSaveInstanceState"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="outState" type="android.os.Bundle">
+</parameter>
+</method>
+<method name="onStart"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onStop"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="setRetainInstance"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="retain" type="boolean">
+</parameter>
+</method>
+<method name="startActivity"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+</method>
+<method name="startActivityForResult"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+<parameter name="requestCode" type="int">
+</parameter>
+</method>
+</class>
+<interface name="FragmentTransaction"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="add"
+ return="android.app.FragmentTransaction"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fragment" type="android.app.Fragment">
+</parameter>
+<parameter name="tag" type="java.lang.String">
+</parameter>
+</method>
+<method name="add"
+ return="android.app.FragmentTransaction"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="containerViewId" type="int">
+</parameter>
+<parameter name="fragment" type="android.app.Fragment">
+</parameter>
+</method>
+<method name="add"
+ return="android.app.FragmentTransaction"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="containerViewId" type="int">
+</parameter>
+<parameter name="fragment" type="android.app.Fragment">
+</parameter>
+<parameter name="tag" type="java.lang.String">
+</parameter>
+</method>
+<method name="addToBackStack"
+ return="android.app.FragmentTransaction"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="name" type="java.lang.String">
+</parameter>
+</method>
+<method name="commit"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="hide"
+ return="android.app.FragmentTransaction"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fragment" type="android.app.Fragment">
+</parameter>
+</method>
+<method name="remove"
+ return="android.app.FragmentTransaction"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fragment" type="android.app.Fragment">
+</parameter>
+</method>
+<method name="replace"
+ return="android.app.FragmentTransaction"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="containerViewId" type="int">
+</parameter>
+<parameter name="fragment" type="android.app.Fragment">
+</parameter>
+</method>
+<method name="replace"
+ return="android.app.FragmentTransaction"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="containerViewId" type="int">
+</parameter>
+<parameter name="fragment" type="android.app.Fragment">
+</parameter>
+<parameter name="tag" type="java.lang.String">
+</parameter>
+</method>
+<method name="setCustomAnimations"
+ return="android.app.FragmentTransaction"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="enter" type="int">
+</parameter>
+<parameter name="exit" type="int">
+</parameter>
+</method>
+<method name="setTransition"
+ return="android.app.FragmentTransaction"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="transit" type="int">
+</parameter>
+</method>
+<method name="setTransitionStyle"
+ return="android.app.FragmentTransaction"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="styleRes" type="int">
+</parameter>
+</method>
+<method name="show"
+ return="android.app.FragmentTransaction"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fragment" type="android.app.Fragment">
+</parameter>
+</method>
+<field name="TRANSIT_ACTIVITY_CLOSE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="8199"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TRANSIT_ACTIVITY_OPEN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4102"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TRANSIT_ENTER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4097"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TRANSIT_ENTER_MASK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4096"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TRANSIT_EXIT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="8194"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TRANSIT_EXIT_MASK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="8192"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TRANSIT_HIDE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="8196"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TRANSIT_NONE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TRANSIT_PREVIEW_DONE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="5"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TRANSIT_SHOW"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4099"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TRANSIT_TASK_CLOSE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="8201"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TRANSIT_TASK_OPEN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4104"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TRANSIT_TASK_TO_BACK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="8203"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TRANSIT_TASK_TO_FRONT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4106"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TRANSIT_UNSET"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TRANSIT_WALLPAPER_CLOSE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="8204"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TRANSIT_WALLPAPER_INTRA_CLOSE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="8207"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TRANSIT_WALLPAPER_INTRA_OPEN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4110"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TRANSIT_WALLPAPER_OPEN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4109"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</interface>
<class name="Instrumentation"
extends="java.lang.Object"
abstract="false"
@@ -26118,6 +27750,109 @@
</parameter>
</method>
</class>
+<class name="LoaderManagingFragment"
+ extends="android.app.Fragment"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.content.Loader.OnLoadCompleteListener">
+</implements>
+<constructor name="LoaderManagingFragment"
+ type="android.app.LoaderManagingFragment"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="getLoader"
+ return="android.content.Loader<D>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="id" type="int">
+</parameter>
+</method>
+<method name="onCreateLoader"
+ return="android.content.Loader<D>"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="id" type="int">
+</parameter>
+<parameter name="args" type="android.os.Bundle">
+</parameter>
+</method>
+<method name="onInitializeLoaders"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</method>
+<method name="onLoadComplete"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="loader" type="android.content.Loader<D>">
+</parameter>
+<parameter name="data" type="D">
+</parameter>
+</method>
+<method name="onLoadFinished"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="loader" type="android.content.Loader<D>">
+</parameter>
+<parameter name="data" type="D">
+</parameter>
+</method>
+<method name="startLoading"
+ return="android.content.Loader<D>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="id" type="int">
+</parameter>
+<parameter name="args" type="android.os.Bundle">
+</parameter>
+</method>
+</class>
<class name="LocalActivityManager"
extends="java.lang.Object"
abstract="false"
@@ -30071,6 +31806,19 @@
<parameter name="admin" type="android.content.ComponentName">
</parameter>
</method>
+<method name="getPasswordHistoryLength"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="admin" type="android.content.ComponentName">
+</parameter>
+</method>
<method name="getPasswordMaximumLength"
return="int"
abstract="false"
@@ -30097,6 +31845,84 @@
<parameter name="admin" type="android.content.ComponentName">
</parameter>
</method>
+<method name="getPasswordMinimumLetters"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="admin" type="android.content.ComponentName">
+</parameter>
+</method>
+<method name="getPasswordMinimumLowerCase"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="admin" type="android.content.ComponentName">
+</parameter>
+</method>
+<method name="getPasswordMinimumNonLetter"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="admin" type="android.content.ComponentName">
+</parameter>
+</method>
+<method name="getPasswordMinimumNumeric"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="admin" type="android.content.ComponentName">
+</parameter>
+</method>
+<method name="getPasswordMinimumSymbols"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="admin" type="android.content.ComponentName">
+</parameter>
+</method>
+<method name="getPasswordMinimumUpperCase"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="admin" type="android.content.ComponentName">
+</parameter>
+</method>
<method name="getPasswordQuality"
return="int"
abstract="false"
@@ -30203,6 +32029,21 @@
<parameter name="timeMs" type="long">
</parameter>
</method>
+<method name="setPasswordHistoryLength"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="admin" type="android.content.ComponentName">
+</parameter>
+<parameter name="length" type="int">
+</parameter>
+</method>
<method name="setPasswordMinimumLength"
return="void"
abstract="false"
@@ -30218,6 +32059,96 @@
<parameter name="length" type="int">
</parameter>
</method>
+<method name="setPasswordMinimumLetters"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="admin" type="android.content.ComponentName">
+</parameter>
+<parameter name="length" type="int">
+</parameter>
+</method>
+<method name="setPasswordMinimumLowerCase"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="admin" type="android.content.ComponentName">
+</parameter>
+<parameter name="length" type="int">
+</parameter>
+</method>
+<method name="setPasswordMinimumNonLetter"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="admin" type="android.content.ComponentName">
+</parameter>
+<parameter name="length" type="int">
+</parameter>
+</method>
+<method name="setPasswordMinimumNumeric"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="admin" type="android.content.ComponentName">
+</parameter>
+<parameter name="length" type="int">
+</parameter>
+</method>
+<method name="setPasswordMinimumSymbols"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="admin" type="android.content.ComponentName">
+</parameter>
+<parameter name="length" type="int">
+</parameter>
+</method>
+<method name="setPasswordMinimumUpperCase"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="admin" type="android.content.ComponentName">
+</parameter>
+<parameter name="length" type="int">
+</parameter>
+</method>
<method name="setPasswordQuality"
return="void"
abstract="false"
@@ -30312,6 +32243,17 @@
visibility="public"
>
</field>
+<field name="PASSWORD_QUALITY_COMPLEX"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="393216"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="PASSWORD_QUALITY_NUMERIC"
type="int"
transient="false"
@@ -33906,6 +35848,58 @@
</parameter>
</constructor>
</class>
+<class name="AsyncTaskLoader"
+ extends="android.content.Loader"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="AsyncTaskLoader"
+ type="android.content.AsyncTaskLoader"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</constructor>
+<method name="cancelLoad"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="forceLoad"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="loadInBackground"
+ return="D"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
<class name="BroadcastReceiver"
extends="java.lang.Object"
abstract="true"
@@ -37549,6 +39543,25 @@
<parameter name="factory" type="android.database.sqlite.SQLiteDatabase.CursorFactory">
</parameter>
</method>
+<method name="openOrCreateDatabase"
+ return="android.database.sqlite.SQLiteDatabase"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="name" type="java.lang.String">
+</parameter>
+<parameter name="mode" type="int">
+</parameter>
+<parameter name="factory" type="android.database.sqlite.SQLiteDatabase.CursorFactory">
+</parameter>
+<parameter name="errorHandler" type="android.database.DatabaseErrorHandler">
+</parameter>
+</method>
<method name="peekWallpaper"
return="android.graphics.drawable.Drawable"
abstract="true"
@@ -38171,6 +40184,17 @@
visibility="public"
>
</field>
+<field name="STORAGE_SERVICE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""storage""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="TELEPHONY_SERVICE"
type="java.lang.String"
transient="false"
@@ -38965,6 +40989,25 @@
<parameter name="factory" type="android.database.sqlite.SQLiteDatabase.CursorFactory">
</parameter>
</method>
+<method name="openOrCreateDatabase"
+ return="android.database.sqlite.SQLiteDatabase"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="name" type="java.lang.String">
+</parameter>
+<parameter name="mode" type="int">
+</parameter>
+<parameter name="factory" type="android.database.sqlite.SQLiteDatabase.CursorFactory">
+</parameter>
+<parameter name="errorHandler" type="android.database.DatabaseErrorHandler">
+</parameter>
+</method>
<method name="peekWallpaper"
return="android.graphics.drawable.Drawable"
abstract="false"
@@ -39291,6 +41334,212 @@
</parameter>
</method>
</class>
+<class name="CursorLoader"
+ extends="android.content.AsyncTaskLoader"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="CursorLoader"
+ type="android.content.CursorLoader"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="projection" type="java.lang.String[]">
+</parameter>
+<parameter name="selection" type="java.lang.String">
+</parameter>
+<parameter name="selectionArgs" type="java.lang.String[]">
+</parameter>
+<parameter name="sortOrder" type="java.lang.String">
+</parameter>
+</constructor>
+<method name="deliverResult"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cursor" type="android.database.Cursor">
+</parameter>
+</method>
+<method name="destroy"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getProjection"
+ return="java.lang.String[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getSelection"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getSelectionArgs"
+ return="java.lang.String[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getSortOrder"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getUri"
+ return="android.net.Uri"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="loadInBackground"
+ return="android.database.Cursor"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="setProjection"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="projection" type="java.lang.String[]">
+</parameter>
+</method>
+<method name="setSelection"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="selection" type="java.lang.String">
+</parameter>
+</method>
+<method name="setSelectionArgs"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="selectionArgs" type="java.lang.String[]">
+</parameter>
+</method>
+<method name="setSortOrder"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="sortOrder" type="java.lang.String">
+</parameter>
+</method>
+<method name="setUri"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+</method>
+<method name="startLoading"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="stopLoading"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
<interface name="DialogInterface"
abstract="true"
static="false"
@@ -44268,6 +46517,172 @@
</parameter>
</constructor>
</class>
+<class name="Loader"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Loader"
+ type="android.content.Loader"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</constructor>
+<method name="deliverResult"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="data" type="D">
+</parameter>
+</method>
+<method name="destroy"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="forceLoad"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getContext"
+ return="android.content.Context"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="registerListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="id" type="int">
+</parameter>
+<parameter name="listener" type="android.content.Loader.OnLoadCompleteListener<D>">
+</parameter>
+</method>
+<method name="startLoading"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="stopLoading"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="unregisterListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.content.Loader.OnLoadCompleteListener<D>">
+</parameter>
+</method>
+</class>
+<class name="Loader.ForceLoadContentObserver"
+ extends="android.database.ContentObserver"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Loader.ForceLoadContentObserver"
+ type="android.content.Loader.ForceLoadContentObserver"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+</class>
+<interface name="Loader.OnLoadCompleteListener"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onLoadComplete"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="loader" type="android.content.Loader<D>">
+</parameter>
+<parameter name="data" type="D">
+</parameter>
+</method>
+</interface>
<class name="MutableContextWrapper"
extends="android.content.ContextWrapper"
abstract="false"
@@ -44807,6 +47222,21 @@
<parameter name="defValue" type="java.lang.String">
</parameter>
</method>
+<method name="getStringSet"
+ return="java.util.Set<java.lang.String>"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="java.lang.String">
+</parameter>
+<parameter name="defValues" type="java.util.Set<java.lang.String>">
+</parameter>
+</method>
<method name="registerOnSharedPreferenceChangeListener"
return="void"
abstract="true"
@@ -44938,6 +47368,21 @@
<parameter name="value" type="java.lang.String">
</parameter>
</method>
+<method name="putStringSet"
+ return="android.content.SharedPreferences.Editor"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="java.lang.String">
+</parameter>
+<parameter name="values" type="java.util.Set<java.lang.String>">
+</parameter>
+</method>
<method name="remove"
return="android.content.SharedPreferences.Editor"
abstract="true"
@@ -46308,6 +48753,17 @@
visibility="public"
>
</field>
+<field name="FLAG_HARDWARE_ACCELERATED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2097152"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="FLAG_HAS_CODE"
type="int"
transient="false"
@@ -53355,6 +55811,19 @@
<parameter name="column" type="int">
</parameter>
</method>
+<method name="getType"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="column" type="int">
+</parameter>
+</method>
<method name="getUpdatedField"
return="java.lang.Object"
abstract="false"
@@ -54378,6 +56847,19 @@
<parameter name="columnIndex" type="int">
</parameter>
</method>
+<method name="getType"
+ return="int"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnIndex" type="int">
+</parameter>
+</method>
<method name="getWantsAllOnMoveCalls"
return="boolean"
abstract="true"
@@ -54618,6 +57100,61 @@
<parameter name="observer" type="android.database.DataSetObserver">
</parameter>
</method>
+<field name="FIELD_TYPE_BLOB"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FIELD_TYPE_FLOAT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FIELD_TYPE_INTEGER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FIELD_TYPE_NULL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FIELD_TYPE_STRING"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
</interface>
<class name="CursorIndexOutOfBoundsException"
extends="java.lang.IndexOutOfBoundsException"
@@ -54975,6 +57512,21 @@
<parameter name="col" type="int">
</parameter>
</method>
+<method name="getType"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="row" type="int">
+</parameter>
+<parameter name="col" type="int">
+</parameter>
+</method>
<method name="isBlob"
return="boolean"
abstract="false"
@@ -54982,7 +57534,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="row" type="int">
@@ -54997,7 +57549,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="row" type="int">
@@ -55012,7 +57564,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="row" type="int">
@@ -55027,7 +57579,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="row" type="int">
@@ -55042,7 +57594,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="row" type="int">
@@ -55453,6 +58005,19 @@
<parameter name="columnIndex" type="int">
</parameter>
</method>
+<method name="getType"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnIndex" type="int">
+</parameter>
+</method>
<method name="getWantsAllOnMoveCalls"
return="boolean"
abstract="false"
@@ -55772,6 +58337,27 @@
>
</method>
</class>
+<interface name="DatabaseErrorHandler"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onCorruption"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dbObj" type="android.database.sqlite.SQLiteDatabase">
+</parameter>
+</method>
+</interface>
<class name="DatabaseUtils"
extends="java.lang.Object"
abstract="false"
@@ -56656,6 +59242,38 @@
>
</field>
</class>
+<class name="DefaultDatabaseErrorHandler"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.database.DatabaseErrorHandler">
+</implements>
+<constructor name="DefaultDatabaseErrorHandler"
+ type="android.database.DefaultDatabaseErrorHandler"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="onCorruption"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dbObj" type="android.database.sqlite.SQLiteDatabase">
+</parameter>
+</method>
+</class>
<class name="MatrixCursor"
extends="android.database.AbstractCursor"
abstract="false"
@@ -57524,6 +60142,17 @@
<parameter name="tables" type="java.lang.String">
</parameter>
</method>
+<method name="getAttachedDbs"
+ return="java.util.ArrayList<android.util.Pair<java.lang.String, java.lang.String>>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getMaximumSize"
return="long"
abstract="false"
@@ -57645,6 +60274,17 @@
<parameter name="conflictAlgorithm" type="int">
</parameter>
</method>
+<method name="isDatabaseIntegrityOk"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="isDbLockedByCurrentThread"
return="boolean"
abstract="false"
@@ -57762,6 +60402,25 @@
<parameter name="flags" type="int">
</parameter>
</method>
+<method name="openDatabase"
+ return="android.database.sqlite.SQLiteDatabase"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="path" type="java.lang.String">
+</parameter>
+<parameter name="factory" type="android.database.sqlite.SQLiteDatabase.CursorFactory">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+<parameter name="errorHandler" type="android.database.DatabaseErrorHandler">
+</parameter>
+</method>
<method name="openOrCreateDatabase"
return="android.database.sqlite.SQLiteDatabase"
abstract="false"
@@ -57792,6 +60451,23 @@
<parameter name="factory" type="android.database.sqlite.SQLiteDatabase.CursorFactory">
</parameter>
</method>
+<method name="openOrCreateDatabase"
+ return="android.database.sqlite.SQLiteDatabase"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="path" type="java.lang.String">
+</parameter>
+<parameter name="factory" type="android.database.sqlite.SQLiteDatabase.CursorFactory">
+</parameter>
+<parameter name="errorHandler" type="android.database.DatabaseErrorHandler">
+</parameter>
+</method>
<method name="query"
return="android.database.Cursor"
abstract="false"
@@ -58011,6 +60687,19 @@
<parameter name="lockingEnabled" type="boolean">
</parameter>
</method>
+<method name="setMaxSqlCacheSize"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cacheSize" type="int">
+</parameter>
+</method>
<method name="setMaximumSize"
return="long"
abstract="false"
@@ -58213,6 +60902,17 @@
visibility="public"
>
</field>
+<field name="MAX_SQL_CACHE_SIZE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="100"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="NO_LOCALIZED_COLLATORS"
type="int"
transient="false"
@@ -58471,6 +61171,24 @@
<parameter name="version" type="int">
</parameter>
</constructor>
+<constructor name="SQLiteOpenHelper"
+ type="android.database.sqlite.SQLiteOpenHelper"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="name" type="java.lang.String">
+</parameter>
+<parameter name="factory" type="android.database.sqlite.SQLiteDatabase.CursorFactory">
+</parameter>
+<parameter name="version" type="int">
+</parameter>
+<parameter name="errorHandler" type="android.database.DatabaseErrorHandler">
+</parameter>
+</constructor>
<method name="close"
return="void"
abstract="false"
@@ -63129,7 +65847,7 @@
<method name="drawText"
return="void"
abstract="false"
- native="true"
+ native="false"
synchronized="false"
static="false"
final="false"
@@ -73071,6 +75789,17 @@
visibility="public"
>
</method>
+<method name="computeConstantSize"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</method>
<method name="getChangingConfigurations"
return="int"
abstract="false"
@@ -73965,6 +76694,36 @@
</parameter>
</method>
</class>
+<class name="MipmapDrawable"
+ extends="android.graphics.drawable.DrawableContainer"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="MipmapDrawable"
+ type="android.graphics.drawable.MipmapDrawable"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="addDrawable"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="drawable" type="android.graphics.drawable.Drawable">
+</parameter>
+</method>
+</class>
<class name="NinePatchDrawable"
extends="android.graphics.drawable.Drawable"
abstract="false"
@@ -125175,6 +127934,240 @@
</method>
</class>
</package>
+<package name="android.os.storage"
+>
+<class name="StorageEventListener"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="StorageEventListener"
+ type="android.os.storage.StorageEventListener"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="onStorageStateChanged"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="path" type="java.lang.String">
+</parameter>
+<parameter name="oldState" type="java.lang.String">
+</parameter>
+<parameter name="newState" type="java.lang.String">
+</parameter>
+</method>
+<method name="onUsbMassStorageConnectionChanged"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="connected" type="boolean">
+</parameter>
+</method>
+</class>
+<class name="StorageManager"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="disableUsbMassStorage"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="enableUsbMassStorage"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isUsbMassStorageConnected"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isUsbMassStorageEnabled"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="registerListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.os.storage.StorageEventListener">
+</parameter>
+</method>
+<method name="unregisterListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.os.storage.StorageEventListener">
+</parameter>
+</method>
+</class>
+<class name="StorageResultCode"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="StorageResultCode"
+ type="android.os.storage.StorageResultCode"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<field name="OperationFailedInternalError"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="OperationFailedMediaBlank"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="OperationFailedMediaCorrupt"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="OperationFailedNoMedia"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="OperationFailedStorageBusy"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-7"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="OperationFailedStorageMounted"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-6"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="OperationFailedStorageNotMounted"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-5"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="OperationSucceeded"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+</package>
<package name="android.preference"
>
<class name="CheckBoxPreference"
@@ -125968,6 +128961,148 @@
</parameter>
</method>
</class>
+<class name="MultiSelectListPreference"
+ extends="android.preference.DialogPreference"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="MultiSelectListPreference"
+ type="android.preference.MultiSelectListPreference"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="attrs" type="android.util.AttributeSet">
+</parameter>
+</constructor>
+<constructor name="MultiSelectListPreference"
+ type="android.preference.MultiSelectListPreference"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</constructor>
+<method name="findIndexOfValue"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="java.lang.String">
+</parameter>
+</method>
+<method name="getEntries"
+ return="java.lang.CharSequence[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getEntryValues"
+ return="java.lang.CharSequence[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getValues"
+ return="java.util.Set<java.lang.String>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="setEntries"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="entries" type="java.lang.CharSequence[]">
+</parameter>
+</method>
+<method name="setEntries"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="entriesResId" type="int">
+</parameter>
+</method>
+<method name="setEntryValues"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="entryValues" type="java.lang.CharSequence[]">
+</parameter>
+</method>
+<method name="setEntryValues"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="entryValuesResId" type="int">
+</parameter>
+</method>
+<method name="setValues"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="values" type="java.util.Set<java.lang.String>">
+</parameter>
+</method>
+</class>
<class name="Preference"
extends="java.lang.Object"
abstract="false"
@@ -134338,6 +137473,17 @@
deprecated="not deprecated"
visibility="protected"
>
+<field name="AUTO_ADD"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""auto_add""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="DELETED"
type="java.lang.String"
transient="false"
@@ -134349,6 +137495,17 @@
visibility="public"
>
</field>
+<field name="FAVORITES"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""favorites""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="GROUP_VISIBLE"
type="java.lang.String"
transient="false"
@@ -152125,6 +155282,25 @@
<parameter name="factory" type="android.database.sqlite.SQLiteDatabase.CursorFactory">
</parameter>
</method>
+<method name="openOrCreateDatabase"
+ return="android.database.sqlite.SQLiteDatabase"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="file" type="java.lang.String">
+</parameter>
+<parameter name="mode" type="int">
+</parameter>
+<parameter name="factory" type="android.database.sqlite.SQLiteDatabase.CursorFactory">
+</parameter>
+<parameter name="errorHandler" type="android.database.DatabaseErrorHandler">
+</parameter>
+</method>
<method name="peekWallpaper"
return="android.graphics.drawable.Drawable"
abstract="false"
@@ -152469,17 +155645,6 @@
visibility="public"
>
</constructor>
-<method name="abortUpdates"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
<method name="close"
return="void"
abstract="false"
@@ -152491,30 +155656,6 @@
visibility="public"
>
</method>
-<method name="commitUpdates"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="commitUpdates"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="values" type="java.util.Map<? extends java.lang.Long, ? extends java.util.Map<java.lang.String, java.lang.Object>>">
-</parameter>
-</method>
<method name="copyStringToBuffer"
return="void"
abstract="false"
@@ -152541,17 +155682,6 @@
visibility="public"
>
</method>
-<method name="deleteRow"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
<method name="getBlob"
return="byte[]"
abstract="false"
@@ -152737,8 +155867,8 @@
<parameter name="columnIndex" type="int">
</parameter>
</method>
-<method name="getWantsAllOnMoveCalls"
- return="boolean"
+<method name="getType"
+ return="int"
abstract="false"
native="false"
synchronized="false"
@@ -152747,8 +155877,10 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="columnIndex" type="int">
+</parameter>
</method>
-<method name="hasUpdates"
+<method name="getWantsAllOnMoveCalls"
return="boolean"
abstract="false"
native="false"
@@ -152962,17 +156094,6 @@
<parameter name="uri" type="android.net.Uri">
</parameter>
</method>
-<method name="supportsUpdates"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
<method name="unregisterContentObserver"
return="void"
abstract="false"
@@ -152999,124 +156120,6 @@
<parameter name="observer" type="android.database.DataSetObserver">
</parameter>
</method>
-<method name="updateBlob"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="columnIndex" type="int">
-</parameter>
-<parameter name="value" type="byte[]">
-</parameter>
-</method>
-<method name="updateDouble"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="columnIndex" type="int">
-</parameter>
-<parameter name="value" type="double">
-</parameter>
-</method>
-<method name="updateFloat"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="columnIndex" type="int">
-</parameter>
-<parameter name="value" type="float">
-</parameter>
-</method>
-<method name="updateInt"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="columnIndex" type="int">
-</parameter>
-<parameter name="value" type="int">
-</parameter>
-</method>
-<method name="updateLong"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="columnIndex" type="int">
-</parameter>
-<parameter name="value" type="long">
-</parameter>
-</method>
-<method name="updateShort"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="columnIndex" type="int">
-</parameter>
-<parameter name="value" type="short">
-</parameter>
-</method>
-<method name="updateString"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="columnIndex" type="int">
-</parameter>
-<parameter name="value" type="java.lang.String">
-</parameter>
-</method>
-<method name="updateToNull"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="columnIndex" type="int">
-</parameter>
-</method>
</class>
<class name="MockDialogInterface"
extends="java.lang.Object"
@@ -159152,7 +162155,7 @@
>
<parameter name="text" type="java.lang.CharSequence">
</parameter>
-<parameter name="p" type="android.text.TextPaint">
+<parameter name="paint" type="android.text.TextPaint">
</parameter>
<parameter name="avail" type="float">
</parameter>
@@ -169441,7 +172444,7 @@
type="java.lang.String"
transient="false"
volatile="false"
- value=""((aero|arpa|asia|a[cdefgilmnoqrstuwxz])|(biz|b[abdefghijmnorstvwyz])|(cat|com|coop|c[acdfghiklmnoruvxyz])|d[ejkmoz]|(edu|e[cegrstu])|f[ijkmor]|(gov|g[abdefghilmnpqrstuwy])|h[kmnrtu]|(info|int|i[delmnoqrst])|(jobs|j[emop])|k[eghimnprwyz]|l[abcikrstuvy]|(mil|mobi|museum|m[acdeghklmnopqrstuvwxyz])|(name|net|n[acefgilopruz])|(org|om)|(pro|p[aefghklmnrstwy])|qa|r[eosuw]|s[abcdeghijklmnortuvyz]|(tel|travel|t[cdfghjklmnoprtvwz])|u[agksyz]|v[aceginu]|w[fs]|(xn\\-\\-0zwm56d|xn\\-\\-11b5bs3a9aj6g|xn\\-\\-80akhbyknj4f|xn\\-\\-9t4b11yi5a|xn\\-\\-deba0ad|xn\\-\\-g6w251d|xn\\-\\-hgbk6aj7f53bba|xn\\-\\-hlcj6aya9esc7a|xn\\-\\-jxalpdlp|xn\\-\\-kgbechtv|xn\\-\\-zckzah)|y[etu]|z[amw])""
+ value=""((aero|arpa|asia|a[cdefgilmnoqrstuwxz])|(biz|b[abdefghijmnorstvwyz])|(cat|com|coop|c[acdfghiklmnoruvxyz])|d[ejkmoz]|(edu|e[cegrstu])|f[ijkmor]|(gov|g[abdefghilmnpqrstuwy])|h[kmnrtu]|(info|int|i[delmnoqrst])|(jobs|j[emop])|k[eghimnprwyz]|l[abcikrstuvy]|(mil|mobi|museum|m[acdeghklmnopqrstuvwxyz])|(name|net|n[acefgilopruz])|(org|om)|(pro|p[aefghklmnrstwy])|qa|r[eosuw]|s[abcdeghijklmnortuvyz]|(tel|travel|t[cdfghjklmnoprtvwz])|u[agksyz]|v[aceginu]|w[fs]|(xn\\-\\-0zwm56d|xn\\-\\-11b5bs3a9aj6g|xn\\-\\-80akhbyknj4f|xn\\-\\-9t4b11yi5a|xn\\-\\-deba0ad|xn\\-\\-g6w251d|xn\\-\\-hgbk6aj7f53bba|xn\\-\\-hlcj6aya9esc7a|xn\\-\\-jxalpdlp|xn\\-\\-kgbechtv|xn\\-\\-mgbaam7a8h|xn\\-\\-mgberp4a5d4ar|xn\\-\\-wgbh1c|xn\\-\\-zckzah)|y[et]|z[amw])""
static="true"
final="true"
deprecated="not deprecated"
@@ -169452,7 +172455,7 @@
type="java.lang.String"
transient="false"
volatile="false"
- value=""(?:(?:aero|arpa|asia|a[cdefgilmnoqrstuwxz])|(?:biz|b[abdefghijmnorstvwyz])|(?:cat|com|coop|c[acdfghiklmnoruvxyz])|d[ejkmoz]|(?:edu|e[cegrstu])|f[ijkmor]|(?:gov|g[abdefghilmnpqrstuwy])|h[kmnrtu]|(?:info|int|i[delmnoqrst])|(?:jobs|j[emop])|k[eghimnprwyz]|l[abcikrstuvy]|(?:mil|mobi|museum|m[acdeghklmnopqrstuvwxyz])|(?:name|net|n[acefgilopruz])|(?:org|om)|(?:pro|p[aefghklmnrstwy])|qa|r[eosuw]|s[abcdeghijklmnortuvyz]|(?:tel|travel|t[cdfghjklmnoprtvwz])|u[agksyz]|v[aceginu]|w[fs]|(?:xn\\-\\-0zwm56d|xn\\-\\-11b5bs3a9aj6g|xn\\-\\-80akhbyknj4f|xn\\-\\-9t4b11yi5a|xn\\-\\-deba0ad|xn\\-\\-g6w251d|xn\\-\\-hgbk6aj7f53bba|xn\\-\\-hlcj6aya9esc7a|xn\\-\\-jxalpdlp|xn\\-\\-kgbechtv|xn\\-\\-zckzah)|y[etu]|z[amw]))""
+ value=""(?:(?:aero|arpa|asia|a[cdefgilmnoqrstuwxz])|(?:biz|b[abdefghijmnorstvwyz])|(?:cat|com|coop|c[acdfghiklmnoruvxyz])|d[ejkmoz]|(?:edu|e[cegrstu])|f[ijkmor]|(?:gov|g[abdefghilmnpqrstuwy])|h[kmnrtu]|(?:info|int|i[delmnoqrst])|(?:jobs|j[emop])|k[eghimnprwyz]|l[abcikrstuvy]|(?:mil|mobi|museum|m[acdeghklmnopqrstuvwxyz])|(?:name|net|n[acefgilopruz])|(?:org|om)|(?:pro|p[aefghklmnrstwy])|qa|r[eosuw]|s[abcdeghijklmnortuvyz]|(?:tel|travel|t[cdfghjklmnoprtvwz])|u[agksyz]|v[aceginu]|w[fs]|(?:xn\\-\\-0zwm56d|xn\\-\\-11b5bs3a9aj6g|xn\\-\\-80akhbyknj4f|xn\\-\\-9t4b11yi5a|xn\\-\\-deba0ad|xn\\-\\-g6w251d|xn\\-\\-hgbk6aj7f53bba|xn\\-\\-hlcj6aya9esc7a|xn\\-\\-jxalpdlp|xn\\-\\-kgbechtv|xn\\-\\-mgbaam7a8h|xn\\-\\-mgberp4a5d4ar|xn\\-\\-wgbh1c|xn\\-\\-zckzah)|y[et]|z[amw]))""
static="true"
final="true"
deprecated="not deprecated"
@@ -180578,6 +183581,17 @@
visibility="public"
>
</method>
+<method name="isSaveFromParentEnabled"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="isScrollbarFadingEnabled"
return="boolean"
abstract="false"
@@ -182056,6 +185070,19 @@
<parameter name="enabled" type="boolean">
</parameter>
</method>
+<method name="setSaveFromParentEnabled"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="enabled" type="boolean">
+</parameter>
+</method>
<method name="setScrollBarStyle"
return="void"
abstract="false"
@@ -186381,6 +189408,19 @@
visibility="public"
>
</method>
+<method name="hasFeature"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="feature" type="int">
+</parameter>
+</method>
<method name="hasSoftInputMode"
return="boolean"
abstract="false"
@@ -187044,6 +190084,17 @@
visibility="protected"
>
</field>
+<field name="FEATURE_ACTION_BAR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="9"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="FEATURE_CONTEXT_MENU"
type="int"
transient="false"
@@ -198713,6 +201764,28 @@
visibility="public"
>
</method>
+<method name="canZoomIn"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="canZoomOut"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="capturePicture"
return="android.graphics.Picture"
abstract="false"
@@ -202302,6 +205375,195 @@
</parameter>
</method>
</interface>
+<class name="Adapters"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Adapters"
+ type="android.widget.Adapters"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="loadAdapter"
+ return="android.widget.BaseAdapter"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="id" type="int">
+</parameter>
+<parameter name="parameters" type="java.lang.Object...">
+</parameter>
+</method>
+<method name="loadCursorAdapter"
+ return="android.widget.CursorAdapter"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="id" type="int">
+</parameter>
+<parameter name="uri" type="java.lang.String">
+</parameter>
+<parameter name="parameters" type="java.lang.Object...">
+</parameter>
+</method>
+<method name="loadCursorAdapter"
+ return="android.widget.CursorAdapter"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="id" type="int">
+</parameter>
+<parameter name="cursor" type="android.database.Cursor">
+</parameter>
+<parameter name="parameters" type="java.lang.Object...">
+</parameter>
+</method>
+</class>
+<class name="Adapters.CursorBinder"
+ extends="java.lang.Object"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Adapters.CursorBinder"
+ type="android.widget.Adapters.CursorBinder"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="transformation" type="android.widget.Adapters.CursorTransformation">
+</parameter>
+</constructor>
+<method name="bind"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="view" type="android.view.View">
+</parameter>
+<parameter name="cursor" type="android.database.Cursor">
+</parameter>
+<parameter name="columnIndex" type="int">
+</parameter>
+</method>
+<field name="mContext"
+ type="android.content.Context"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</field>
+<field name="mTransformation"
+ type="android.widget.Adapters.CursorTransformation"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</field>
+</class>
+<class name="Adapters.CursorTransformation"
+ extends="java.lang.Object"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Adapters.CursorTransformation"
+ type="android.widget.Adapters.CursorTransformation"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</constructor>
+<method name="transform"
+ return="java.lang.String"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cursor" type="android.database.Cursor">
+</parameter>
+<parameter name="columnIndex" type="int">
+</parameter>
+</method>
+<method name="transformToResource"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cursor" type="android.database.Cursor">
+</parameter>
+<parameter name="columnIndex" type="int">
+</parameter>
+</method>
+<field name="mContext"
+ type="android.content.Context"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</field>
+</class>
<class name="AlphabetIndexer"
extends="android.database.DataSetObserver"
abstract="false"
@@ -204263,6 +207525,20 @@
<parameter name="autoRequery" type="boolean">
</parameter>
</constructor>
+<constructor name="CursorAdapter"
+ type="android.widget.CursorAdapter"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="c" type="android.database.Cursor">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</constructor>
<method name="bindView"
return="void"
abstract="true"
@@ -204410,6 +207686,23 @@
<parameter name="autoRequery" type="boolean">
</parameter>
</method>
+<method name="init"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="c" type="android.database.Cursor">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
<method name="newDropDownView"
return="android.view.View"
abstract="false"
@@ -204481,6 +207774,28 @@
<parameter name="filterQueryProvider" type="android.widget.FilterQueryProvider">
</parameter>
</method>
+<field name="FLAG_AUTO_REQUERY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FLAG_REGISTER_CONTENT_OBSERVER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
</class>
<class name="CursorTreeAdapter"
extends="android.widget.BaseExpandableListAdapter"
@@ -206920,6 +210235,17 @@
visibility="public"
>
</method>
+<method name="getNumColumns"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getStretchMode"
return="int"
abstract="false"
@@ -208419,6 +211745,665 @@
</parameter>
</method>
</interface>
+<class name="ListPopupWindow"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="ListPopupWindow"
+ type="android.widget.ListPopupWindow"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</constructor>
+<constructor name="ListPopupWindow"
+ type="android.widget.ListPopupWindow"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="attrs" type="android.util.AttributeSet">
+</parameter>
+</constructor>
+<constructor name="ListPopupWindow"
+ type="android.widget.ListPopupWindow"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="attrs" type="android.util.AttributeSet">
+</parameter>
+<parameter name="defStyleAttr" type="int">
+</parameter>
+</constructor>
+<constructor name="ListPopupWindow"
+ type="android.widget.ListPopupWindow"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="attrs" type="android.util.AttributeSet">
+</parameter>
+<parameter name="defStyleAttr" type="int">
+</parameter>
+<parameter name="defStyleRes" type="int">
+</parameter>
+</constructor>
+<method name="clearListSelection"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="dismiss"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getAnchorView"
+ return="android.view.View"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getAnimationStyle"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getBackground"
+ return="android.graphics.drawable.Drawable"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getHeight"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getHorizontalOffset"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getInputMethodMode"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getListView"
+ return="android.widget.ListView"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getPromptPosition"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getSelectedItem"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getSelectedItemId"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getSelectedItemPosition"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getSelectedView"
+ return="android.view.View"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getSoftInputMode"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getVerticalOffset"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getWidth"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isInputMethodNotNeeded"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isModal"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isShowing"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onKeyDown"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="keyCode" type="int">
+</parameter>
+<parameter name="event" type="android.view.KeyEvent">
+</parameter>
+</method>
+<method name="onKeyPreIme"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="keyCode" type="int">
+</parameter>
+<parameter name="event" type="android.view.KeyEvent">
+</parameter>
+</method>
+<method name="onKeyUp"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="keyCode" type="int">
+</parameter>
+<parameter name="event" type="android.view.KeyEvent">
+</parameter>
+</method>
+<method name="performItemClick"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="position" type="int">
+</parameter>
+</method>
+<method name="postShow"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="setAdapter"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="adapter" type="android.widget.ListAdapter">
+</parameter>
+</method>
+<method name="setAnchorView"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="anchor" type="android.view.View">
+</parameter>
+</method>
+<method name="setAnimationStyle"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="animationStyle" type="int">
+</parameter>
+</method>
+<method name="setBackgroundDrawable"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="d" type="android.graphics.drawable.Drawable">
+</parameter>
+</method>
+<method name="setHeight"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="height" type="int">
+</parameter>
+</method>
+<method name="setHorizontalOffset"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="offset" type="int">
+</parameter>
+</method>
+<method name="setInputMethodMode"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="mode" type="int">
+</parameter>
+</method>
+<method name="setListSelector"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="selector" type="android.graphics.drawable.Drawable">
+</parameter>
+</method>
+<method name="setModal"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="modal" type="boolean">
+</parameter>
+</method>
+<method name="setOnItemClickListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="clickListener" type="android.widget.AdapterView.OnItemClickListener">
+</parameter>
+</method>
+<method name="setOnItemSelectedListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="selectedListener" type="android.widget.AdapterView.OnItemSelectedListener">
+</parameter>
+</method>
+<method name="setPromptPosition"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="position" type="int">
+</parameter>
+</method>
+<method name="setPromptView"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="prompt" type="android.view.View">
+</parameter>
+</method>
+<method name="setSelection"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="position" type="int">
+</parameter>
+</method>
+<method name="setSoftInputMode"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="mode" type="int">
+</parameter>
+</method>
+<method name="setVerticalOffset"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="offset" type="int">
+</parameter>
+</method>
+<method name="setWidth"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="width" type="int">
+</parameter>
+</method>
+<method name="show"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="INPUT_METHOD_FROM_FOCUSABLE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="INPUT_METHOD_NEEDED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="INPUT_METHOD_NOT_NEEDED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MATCH_PARENT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="POSITION_PROMPT_ABOVE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="POSITION_PROMPT_BELOW"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="WRAP_CONTENT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
<class name="ListView"
extends="android.widget.AbsListView"
abstract="false"
@@ -209459,6 +213444,22 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="attrs" type="android.util.AttributeSet">
+</parameter>
+<parameter name="defStyleAttr" type="int">
+</parameter>
+<parameter name="defStyleRes" type="int">
+</parameter>
+</constructor>
+<constructor name="PopupWindow"
+ type="android.widget.PopupWindow"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
</constructor>
<constructor name="PopupWindow"
type="android.widget.PopupWindow"
@@ -210488,6 +214489,17 @@
<parameter name="excludeMimes" type="java.lang.String[]">
</parameter>
</method>
+<method name="setImageToDefault"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="setMode"
return="void"
abstract="false"
@@ -214034,6 +218046,28 @@
<parameter name="promptId" type="int">
</parameter>
</method>
+<field name="MODE_DIALOG"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MODE_DROPDOWN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
</class>
<interface name="SpinnerAdapter"
abstract="true"
@@ -219863,6 +223897,17 @@
visibility="public"
>
</field>
+<field name="OP_IGET_WIDE_VOLATILE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="232"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="OP_INSTANCE_OF"
type="int"
transient="false"
@@ -220215,6 +224260,17 @@
visibility="public"
>
</field>
+<field name="OP_IPUT_WIDE_VOLATILE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="233"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="OP_LONG_TO_DOUBLE"
type="int"
transient="false"
@@ -220952,6 +225008,17 @@
visibility="public"
>
</field>
+<field name="OP_SGET_WIDE_VOLATILE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="234"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="OP_SHL_INT"
type="int"
transient="false"
@@ -221150,6 +225217,17 @@
visibility="public"
>
</field>
+<field name="OP_SPUT_WIDE_VOLATILE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="235"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="OP_SUB_DOUBLE"
type="int"
transient="false"
@@ -221385,33 +225463,6 @@
</package>
<package name="dalvik.system"
>
-<class name="AllocationLimitError"
- extends="java.lang.VirtualMachineError"
- abstract="false"
- static="false"
- final="false"
- deprecated="deprecated"
- visibility="public"
->
-<constructor name="AllocationLimitError"
- type="dalvik.system.AllocationLimitError"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</constructor>
-<constructor name="AllocationLimitError"
- type="dalvik.system.AllocationLimitError"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="detailMessage" type="java.lang.String">
-</parameter>
-</constructor>
-</class>
<class name="DexClassLoader"
extends="java.lang.ClassLoader"
abstract="false"
@@ -221604,1010 +225655,6 @@
</parameter>
</method>
</class>
-<class name="PotentialDeadlockError"
- extends="java.lang.VirtualMachineError"
- abstract="false"
- static="false"
- final="false"
- deprecated="deprecated"
- visibility="public"
->
-<constructor name="PotentialDeadlockError"
- type="dalvik.system.PotentialDeadlockError"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</constructor>
-<constructor name="PotentialDeadlockError"
- type="dalvik.system.PotentialDeadlockError"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="detailMessage" type="java.lang.String">
-</parameter>
-</constructor>
-</class>
-<class name="StaleDexCacheError"
- extends="java.lang.VirtualMachineError"
- abstract="false"
- static="false"
- final="false"
- deprecated="deprecated"
- visibility="public"
->
-<constructor name="StaleDexCacheError"
- type="dalvik.system.StaleDexCacheError"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</constructor>
-<constructor name="StaleDexCacheError"
- type="dalvik.system.StaleDexCacheError"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="detailMessage" type="java.lang.String">
-</parameter>
-</constructor>
-</class>
-<class name="TemporaryDirectory"
- extends="java.lang.Object"
- abstract="false"
- static="false"
- final="false"
- deprecated="deprecated"
- visibility="public"
->
-<constructor name="TemporaryDirectory"
- type="dalvik.system.TemporaryDirectory"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</constructor>
-<method name="setUpDirectory"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="baseDir" type="java.lang.String">
-</parameter>
-</method>
-<method name="setUpDirectory"
- return="void"
- abstract="false"
- native="false"
- synchronized="true"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="baseDir" type="java.io.File">
-</parameter>
-</method>
-</class>
-<class name="TouchDex"
- extends="java.lang.Object"
- abstract="false"
- static="false"
- final="false"
- deprecated="deprecated"
- visibility="public"
->
-<constructor name="TouchDex"
- type="dalvik.system.TouchDex"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</constructor>
-<method name="main"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="args" type="java.lang.String[]">
-</parameter>
-</method>
-<method name="start"
- return="int"
- abstract="false"
- native="false"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="dexFiles" type="java.lang.String">
-</parameter>
-</method>
-</class>
-<class name="VMDebug"
- extends="java.lang.Object"
- abstract="false"
- static="false"
- final="true"
- deprecated="deprecated"
- visibility="public"
->
-<method name="dumpHprofData"
- return="void"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="fileName" type="java.lang.String">
-</parameter>
-<exception name="IOException" type="java.io.IOException">
-</exception>
-</method>
-<method name="getAllocCount"
- return="int"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="kind" type="int">
-</parameter>
-</method>
-<method name="getInstructionCount"
- return="void"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="counts" type="int[]">
-</parameter>
-</method>
-<method name="getLoadedClassCount"
- return="int"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="isDebuggerConnected"
- return="boolean"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="isDebuggingEnabled"
- return="boolean"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="lastDebuggerActivity"
- return="long"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="printLoadedClasses"
- return="void"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="flags" type="int">
-</parameter>
-</method>
-<method name="resetAllocCount"
- return="void"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="kinds" type="int">
-</parameter>
-</method>
-<method name="resetInstructionCount"
- return="void"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="setAllocationLimit"
- return="int"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="limit" type="int">
-</parameter>
-</method>
-<method name="setGlobalAllocationLimit"
- return="int"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="limit" type="int">
-</parameter>
-</method>
-<method name="startAllocCounting"
- return="void"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="startEmulatorTracing"
- return="void"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="startInstructionCounting"
- return="void"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="startMethodTracing"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="true"
- final="false"
- deprecated="deprecated"
- visibility="public"
->
-</method>
-<method name="startMethodTracing"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="traceFileName" type="java.lang.String">
-</parameter>
-<parameter name="bufferSize" type="int">
-</parameter>
-<parameter name="flags" type="int">
-</parameter>
-</method>
-<method name="stopAllocCounting"
- return="void"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="stopEmulatorTracing"
- return="void"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="stopInstructionCounting"
- return="void"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="stopMethodTracing"
- return="void"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="threadCpuTimeNanos"
- return="long"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<field name="DEFAULT_METHOD_TRACE_FILE_NAME"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value=""/sdcard/dmtrace.trace""
- static="true"
- final="true"
- deprecated="deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_ALL_COUNTS"
- type="int"
- transient="false"
- volatile="false"
- value="-1"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_GLOBAL_ALLOCATED_BYTES"
- type="int"
- transient="false"
- volatile="false"
- value="2"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_GLOBAL_ALLOCATED_OBJECTS"
- type="int"
- transient="false"
- volatile="false"
- value="1"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_GLOBAL_CLASS_INIT_COUNT"
- type="int"
- transient="false"
- volatile="false"
- value="32"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_GLOBAL_CLASS_INIT_TIME"
- type="int"
- transient="false"
- volatile="false"
- value="64"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_GLOBAL_EXT_ALLOCATED_BYTES"
- type="int"
- transient="false"
- volatile="false"
- value="8192"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_GLOBAL_EXT_ALLOCATED_OBJECTS"
- type="int"
- transient="false"
- volatile="false"
- value="4096"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_GLOBAL_EXT_FREED_BYTES"
- type="int"
- transient="false"
- volatile="false"
- value="32768"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_GLOBAL_EXT_FREED_OBJECTS"
- type="int"
- transient="false"
- volatile="false"
- value="16384"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_GLOBAL_FREED_BYTES"
- type="int"
- transient="false"
- volatile="false"
- value="8"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_GLOBAL_FREED_OBJECTS"
- type="int"
- transient="false"
- volatile="false"
- value="4"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_GLOBAL_GC_INVOCATIONS"
- type="int"
- transient="false"
- volatile="false"
- value="16"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_THREAD_ALLOCATED_BYTES"
- type="int"
- transient="false"
- volatile="false"
- value="131072"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_THREAD_ALLOCATED_OBJECTS"
- type="int"
- transient="false"
- volatile="false"
- value="65536"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_THREAD_CLASS_INIT_COUNT"
- type="int"
- transient="false"
- volatile="false"
- value="2097152"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_THREAD_CLASS_INIT_TIME"
- type="int"
- transient="false"
- volatile="false"
- value="4194304"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_THREAD_EXT_ALLOCATED_BYTES"
- type="int"
- transient="false"
- volatile="false"
- value="536870912"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_THREAD_EXT_ALLOCATED_OBJECTS"
- type="int"
- transient="false"
- volatile="false"
- value="268435456"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_THREAD_EXT_FREED_BYTES"
- type="int"
- transient="false"
- volatile="false"
- value="-2147483648"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_THREAD_EXT_FREED_OBJECTS"
- type="int"
- transient="false"
- volatile="false"
- value="1073741824"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_THREAD_FREED_BYTES"
- type="int"
- transient="false"
- volatile="false"
- value="524288"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_THREAD_FREED_OBJECTS"
- type="int"
- transient="false"
- volatile="false"
- value="262144"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="KIND_THREAD_GC_INVOCATIONS"
- type="int"
- transient="false"
- volatile="false"
- value="1048576"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="TRACE_COUNT_ALLOCS"
- type="int"
- transient="false"
- volatile="false"
- value="1"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-</class>
-<class name="VMRuntime"
- extends="java.lang.Object"
- abstract="false"
- static="false"
- final="true"
- deprecated="deprecated"
- visibility="public"
->
-<method name="gcSoftReferences"
- return="void"
- abstract="false"
- native="true"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="getExternalBytesAllocated"
- return="long"
- abstract="false"
- native="true"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="getMinimumHeapSize"
- return="long"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="getRuntime"
- return="dalvik.system.VMRuntime"
- abstract="false"
- native="false"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="getTargetHeapUtilization"
- return="float"
- abstract="false"
- native="true"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="runFinalizationSync"
- return="void"
- abstract="false"
- native="true"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="setMinimumHeapSize"
- return="long"
- abstract="false"
- native="false"
- synchronized="true"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="size" type="long">
-</parameter>
-</method>
-<method name="setTargetHeapUtilization"
- return="float"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="newTarget" type="float">
-</parameter>
-</method>
-</class>
-<class name="VMStack"
- extends="java.lang.Object"
- abstract="false"
- static="false"
- final="true"
- deprecated="deprecated"
- visibility="public"
->
-<constructor name="VMStack"
- type="dalvik.system.VMStack"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</constructor>
-<method name="getCallingClassLoader"
- return="java.lang.ClassLoader"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="getCallingClassLoader2"
- return="java.lang.ClassLoader"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="getClasses"
- return="java.lang.Class<?>[]"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="maxDepth" type="int">
-</parameter>
-<parameter name="stopAtPrivileged" type="boolean">
-</parameter>
-</method>
-<method name="getThreadStackTrace"
- return="java.lang.StackTraceElement[]"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="t" type="java.lang.Thread">
-</parameter>
-</method>
-</class>
-<class name="Zygote"
- extends="java.lang.Object"
- abstract="false"
- static="false"
- final="false"
- deprecated="deprecated"
- visibility="public"
->
-<method name="fork"
- return="int"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="forkAndSpecialize"
- return="int"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="uid" type="int">
-</parameter>
-<parameter name="gid" type="int">
-</parameter>
-<parameter name="gids" type="int[]">
-</parameter>
-<parameter name="debugFlags" type="int">
-</parameter>
-<parameter name="rlimits" type="int[][]">
-</parameter>
-</method>
-<method name="forkAndSpecialize"
- return="int"
- abstract="false"
- native="false"
- synchronized="false"
- static="true"
- final="false"
- deprecated="deprecated"
- visibility="public"
->
-<parameter name="uid" type="int">
-</parameter>
-<parameter name="gid" type="int">
-</parameter>
-<parameter name="gids" type="int[]">
-</parameter>
-<parameter name="enableDebugger" type="boolean">
-</parameter>
-<parameter name="rlimits" type="int[][]">
-</parameter>
-</method>
-<method name="forkSystemServer"
- return="int"
- abstract="false"
- native="true"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="uid" type="int">
-</parameter>
-<parameter name="gid" type="int">
-</parameter>
-<parameter name="gids" type="int[]">
-</parameter>
-<parameter name="debugFlags" type="int">
-</parameter>
-<parameter name="rlimits" type="int[][]">
-</parameter>
-</method>
-<method name="forkSystemServer"
- return="int"
- abstract="false"
- native="false"
- synchronized="false"
- static="true"
- final="false"
- deprecated="deprecated"
- visibility="public"
->
-<parameter name="uid" type="int">
-</parameter>
-<parameter name="gid" type="int">
-</parameter>
-<parameter name="gids" type="int[]">
-</parameter>
-<parameter name="enableDebugger" type="boolean">
-</parameter>
-<parameter name="rlimits" type="int[][]">
-</parameter>
-</method>
-<field name="DEBUG_ENABLE_ASSERT"
- type="int"
- transient="false"
- volatile="false"
- value="4"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="DEBUG_ENABLE_CHECKJNI"
- type="int"
- transient="false"
- volatile="false"
- value="2"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="DEBUG_ENABLE_DEBUGGER"
- type="int"
- transient="false"
- volatile="false"
- value="1"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="DEBUG_ENABLE_SAFEMODE"
- type="int"
- transient="false"
- volatile="false"
- value="8"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-</class>
</package>
<package name="java.awt.font"
>
@@ -223069,6 +226116,46 @@
visibility="public"
>
</field>
+<field name="KERNING"
+ type="java.awt.font.TextAttribute"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KERNING_ON"
+ type="java.lang.Integer"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="LIGATURES"
+ type="java.awt.font.TextAttribute"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="LIGATURES_ON"
+ type="java.lang.Integer"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="NUMERIC_SHAPING"
type="java.awt.font.TextAttribute"
transient="false"
@@ -223219,6 +226306,36 @@
visibility="public"
>
</field>
+<field name="TRACKING"
+ type="java.awt.font.TextAttribute"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TRACKING_LOOSE"
+ type="java.lang.Float"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TRACKING_TIGHT"
+ type="java.lang.Float"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="TRANSFORM"
type="java.awt.font.TextAttribute"
transient="false"
@@ -224627,7 +227744,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="c" type="char[]">
+<parameter name="buffer" type="char[]">
</parameter>
<parameter name="offset" type="int">
</parameter>
@@ -224719,6 +227836,132 @@
</exception>
</method>
</interface>
+<class name="Console"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="java.io.Flushable">
+</implements>
+<method name="flush"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="format"
+ return="java.io.Console"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="format" type="java.lang.String">
+</parameter>
+<parameter name="args" type="java.lang.Object...">
+</parameter>
+</method>
+<method name="printf"
+ return="java.io.Console"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="format" type="java.lang.String">
+</parameter>
+<parameter name="args" type="java.lang.Object...">
+</parameter>
+</method>
+<method name="readLine"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="readLine"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="format" type="java.lang.String">
+</parameter>
+<parameter name="args" type="java.lang.Object...">
+</parameter>
+</method>
+<method name="readPassword"
+ return="char[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="readPassword"
+ return="char[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="format" type="java.lang.String">
+</parameter>
+<parameter name="args" type="java.lang.Object...">
+</parameter>
+</method>
+<method name="reader"
+ return="java.io.Reader"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="writer"
+ return="java.io.PrintWriter"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
<interface name="DataInput"
abstract="true"
static="false"
@@ -225761,6 +229004,17 @@
<parameter name="uri" type="java.net.URI">
</parameter>
</constructor>
+<method name="canExecute"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="canRead"
return="boolean"
abstract="false"
@@ -225926,6 +229180,17 @@
<exception name="IOException" type="java.io.IOException">
</exception>
</method>
+<method name="getFreeSpace"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getName"
return="java.lang.String"
abstract="false"
@@ -225970,6 +229235,28 @@
visibility="public"
>
</method>
+<method name="getTotalSpace"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getUsableSpace"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="isAbsolute"
return="boolean"
abstract="false"
@@ -226143,6 +229430,34 @@
<parameter name="dest" type="java.io.File">
</parameter>
</method>
+<method name="setExecutable"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="executable" type="boolean">
+</parameter>
+<parameter name="ownerOnly" type="boolean">
+</parameter>
+</method>
+<method name="setExecutable"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="executable" type="boolean">
+</parameter>
+</method>
<method name="setLastModified"
return="boolean"
abstract="false"
@@ -226167,6 +229482,62 @@
visibility="public"
>
</method>
+<method name="setReadable"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="readable" type="boolean">
+</parameter>
+<parameter name="ownerOnly" type="boolean">
+</parameter>
+</method>
+<method name="setReadable"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="readable" type="boolean">
+</parameter>
+</method>
+<method name="setWritable"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="writable" type="boolean">
+</parameter>
+<parameter name="ownerOnly" type="boolean">
+</parameter>
+</method>
+<method name="setWritable"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="writable" type="boolean">
+</parameter>
+</method>
<method name="toURI"
return="java.net.URI"
abstract="false"
@@ -226185,7 +229556,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<exception name="MalformedURLException" type="java.net.MalformedURLException">
@@ -226995,6 +230366,25 @@
</exception>
</method>
</interface>
+<class name="IOError"
+ extends="java.lang.Error"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="IOError"
+ type="java.io.IOError"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+</class>
<class name="IOException"
extends="java.lang.Exception"
abstract="false"
@@ -227021,6 +230411,28 @@
<parameter name="detailMessage" type="java.lang.String">
</parameter>
</constructor>
+<constructor name="IOException"
+ type="java.io.IOException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="message" type="java.lang.String">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="IOException"
+ type="java.io.IOException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
</class>
<class name="InputStream"
extends="java.lang.Object"
@@ -227256,7 +230668,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="buf" type="char[]">
+<parameter name="buffer" type="char[]">
</parameter>
<parameter name="offset" type="int">
</parameter>
@@ -229095,6 +232507,19 @@
<parameter name="cl" type="java.lang.Class<?>">
</parameter>
</method>
+<method name="lookupAny"
+ return="java.io.ObjectStreamClass"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cl" type="java.lang.Class<?>">
+</parameter>
+</method>
<field name="NO_FIELDS"
type="java.io.ObjectStreamField[]"
transient="false"
@@ -229829,7 +233254,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="buf" type="char[]">
+<parameter name="buffer" type="char[]">
</parameter>
<parameter name="offset" type="int">
</parameter>
@@ -229867,6 +233292,30 @@
<exception name="IOException" type="java.io.IOException">
</exception>
</constructor>
+<constructor name="PipedInputStream"
+ type="java.io.PipedInputStream"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pipeSize" type="int">
+</parameter>
+</constructor>
+<constructor name="PipedInputStream"
+ type="java.io.PipedInputStream"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="out" type="java.io.PipedOutputStream">
+</parameter>
+<parameter name="pipeSize" type="int">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</constructor>
<method name="connect"
return="void"
abstract="false"
@@ -230040,6 +233489,30 @@
<exception name="IOException" type="java.io.IOException">
</exception>
</constructor>
+<constructor name="PipedReader"
+ type="java.io.PipedReader"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pipeSize" type="int">
+</parameter>
+</constructor>
+<constructor name="PipedReader"
+ type="java.io.PipedReader"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="out" type="java.io.PipedWriter">
+</parameter>
+<parameter name="pipeSize" type="int">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</constructor>
<method name="close"
return="void"
abstract="false"
@@ -230337,6 +233810,17 @@
visibility="public"
>
</method>
+<method name="clearError"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</method>
<method name="format"
return="java.io.PrintStream"
abstract="false"
@@ -230777,6 +234261,17 @@
visibility="public"
>
</method>
+<method name="clearError"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</method>
<method name="close"
return="void"
abstract="false"
@@ -231680,7 +235175,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="pos" type="long">
+<parameter name="offset" type="long">
</parameter>
<exception name="IOException" type="java.io.IOException">
</exception>
@@ -232699,7 +236194,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="cbuf" type="char[]">
+<parameter name="chars" type="char[]">
</parameter>
<parameter name="offset" type="int">
</parameter>
@@ -238815,6 +242310,17 @@
<parameter name="d" type="double">
</parameter>
</method>
+<field name="MAX_EXPONENT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1023"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="MAX_VALUE"
type="double"
transient="false"
@@ -238826,6 +242332,28 @@
visibility="public"
>
</field>
+<field name="MIN_EXPONENT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-1022"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MIN_NORMAL"
+ type="double"
+ transient="false"
+ volatile="false"
+ value="2.2250738585072014E-308"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="MIN_VALUE"
type="double"
transient="false"
@@ -238955,6 +242483,17 @@
<parameter name="other" type="java.lang.Object">
</parameter>
</method>
+<method name="finalize"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</method>
<method name="getDeclaringClass"
return="java.lang.Class<E>"
abstract="false"
@@ -239474,6 +243013,17 @@
<parameter name="f" type="float">
</parameter>
</method>
+<field name="MAX_EXPONENT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="127"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="MAX_VALUE"
type="float"
transient="false"
@@ -239485,6 +243035,28 @@
visibility="public"
>
</field>
+<field name="MIN_EXPONENT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-126"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MIN_NORMAL"
+ type="float"
+ transient="false"
+ volatile="false"
+ value="1.17549435E-38f"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="MIN_VALUE"
type="float"
transient="false"
@@ -241088,6 +244660,36 @@
<parameter name="d" type="double">
</parameter>
</method>
+<method name="copySign"
+ return="double"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="magnitude" type="double">
+</parameter>
+<parameter name="sign" type="double">
+</parameter>
+</method>
+<method name="copySign"
+ return="float"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="magnitude" type="float">
+</parameter>
+<parameter name="sign" type="float">
+</parameter>
+</method>
<method name="cos"
return="double"
abstract="false"
@@ -241153,6 +244755,32 @@
<parameter name="d" type="double">
</parameter>
</method>
+<method name="getExponent"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="f" type="float">
+</parameter>
+</method>
+<method name="getExponent"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="d" type="double">
+</parameter>
+</method>
<method name="hypot"
return="double"
abstract="false"
@@ -241327,6 +244955,62 @@
<parameter name="l2" type="long">
</parameter>
</method>
+<method name="nextAfter"
+ return="double"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="start" type="double">
+</parameter>
+<parameter name="direction" type="double">
+</parameter>
+</method>
+<method name="nextAfter"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="start" type="float">
+</parameter>
+<parameter name="direction" type="double">
+</parameter>
+</method>
+<method name="nextUp"
+ return="double"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="d" type="double">
+</parameter>
+</method>
+<method name="nextUp"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="f" type="float">
+</parameter>
+</method>
<method name="pow"
return="double"
abstract="false"
@@ -241392,6 +245076,36 @@
<parameter name="f" type="float">
</parameter>
</method>
+<method name="scalb"
+ return="double"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="d" type="double">
+</parameter>
+<parameter name="scaleFactor" type="int">
+</parameter>
+</method>
+<method name="scalb"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="d" type="float">
+</parameter>
+<parameter name="scaleFactor" type="int">
+</parameter>
+</method>
<method name="signum"
return="double"
abstract="false"
@@ -242063,7 +245777,7 @@
<implements name="java.lang.reflect.AnnotatedElement">
</implements>
<method name="getAnnotation"
- return="T"
+ return="A"
abstract="false"
native="false"
synchronized="false"
@@ -242072,7 +245786,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="annotationType" type="java.lang.Class<T>">
+<parameter name="annotationType" type="java.lang.Class<A>">
</parameter>
</method>
<method name="getAnnotations"
@@ -244039,6 +247753,36 @@
<parameter name="d" type="double">
</parameter>
</method>
+<method name="copySign"
+ return="double"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="magnitude" type="double">
+</parameter>
+<parameter name="sign" type="double">
+</parameter>
+</method>
+<method name="copySign"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="magnitude" type="float">
+</parameter>
+<parameter name="sign" type="float">
+</parameter>
+</method>
<method name="cos"
return="double"
abstract="false"
@@ -244104,6 +247848,32 @@
<parameter name="d" type="double">
</parameter>
</method>
+<method name="getExponent"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="f" type="float">
+</parameter>
+</method>
+<method name="getExponent"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="d" type="double">
+</parameter>
+</method>
<method name="hypot"
return="double"
abstract="false"
@@ -244278,6 +248048,62 @@
<parameter name="l2" type="long">
</parameter>
</method>
+<method name="nextAfter"
+ return="double"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="start" type="double">
+</parameter>
+<parameter name="direction" type="double">
+</parameter>
+</method>
+<method name="nextAfter"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="start" type="float">
+</parameter>
+<parameter name="direction" type="double">
+</parameter>
+</method>
+<method name="nextUp"
+ return="double"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="d" type="double">
+</parameter>
+</method>
+<method name="nextUp"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="f" type="float">
+</parameter>
+</method>
<method name="pow"
return="double"
abstract="false"
@@ -244343,6 +248169,36 @@
<parameter name="f" type="float">
</parameter>
</method>
+<method name="scalb"
+ return="double"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="d" type="double">
+</parameter>
+<parameter name="scaleFactor" type="int">
+</parameter>
+</method>
+<method name="scalb"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="d" type="float">
+</parameter>
+<parameter name="scaleFactor" type="int">
+</parameter>
+</method>
<method name="signum"
return="double"
abstract="false"
@@ -244622,6 +248478,34 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="data" type="byte[]">
+</parameter>
+<parameter name="start" type="int">
+</parameter>
+<parameter name="length" type="int">
+</parameter>
+<parameter name="encoding" type="java.nio.charset.Charset">
+</parameter>
+</constructor>
+<constructor name="String"
+ type="java.lang.String"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="data" type="byte[]">
+</parameter>
+<parameter name="encoding" type="java.nio.charset.Charset">
+</parameter>
+</constructor>
+<constructor name="String"
+ type="java.lang.String"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
<parameter name="data" type="char[]">
</parameter>
</constructor>
@@ -244896,7 +248780,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="loc" type="java.util.Locale">
+<parameter name="locale" type="java.util.Locale">
</parameter>
<parameter name="format" type="java.lang.String">
</parameter>
@@ -244948,6 +248832,19 @@
<exception name="UnsupportedEncodingException" type="java.io.UnsupportedEncodingException">
</exception>
</method>
+<method name="getBytes"
+ return="byte[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="encoding" type="java.nio.charset.Charset">
+</parameter>
+</method>
<method name="getChars"
return="void"
abstract="false"
@@ -245034,6 +248931,17 @@
visibility="public"
>
</method>
+<method name="isEmpty"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="lastIndexOf"
return="int"
abstract="false"
@@ -245111,7 +249019,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="expr" type="java.lang.String">
+<parameter name="regularExpression" type="java.lang.String">
</parameter>
</method>
<method name="offsetByCodePoints"
@@ -245209,9 +249117,9 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="expr" type="java.lang.String">
+<parameter name="regularExpression" type="java.lang.String">
</parameter>
-<parameter name="substitute" type="java.lang.String">
+<parameter name="replacement" type="java.lang.String">
</parameter>
</method>
<method name="replaceFirst"
@@ -245224,9 +249132,9 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="expr" type="java.lang.String">
+<parameter name="regularExpression" type="java.lang.String">
</parameter>
-<parameter name="substitute" type="java.lang.String">
+<parameter name="replacement" type="java.lang.String">
</parameter>
</method>
<method name="split"
@@ -245239,7 +249147,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="expr" type="java.lang.String">
+<parameter name="regularExpression" type="java.lang.String">
</parameter>
</method>
<method name="split"
@@ -245252,9 +249160,9 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="expr" type="java.lang.String">
+<parameter name="regularExpression" type="java.lang.String">
</parameter>
-<parameter name="max" type="int">
+<parameter name="limit" type="int">
</parameter>
</method>
<method name="startsWith"
@@ -246594,6 +250502,17 @@
<parameter name="key" type="java.lang.String">
</parameter>
</method>
+<method name="console"
+ return="java.io.Console"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="currentTimeMillis"
return="long"
abstract="false"
@@ -253452,6 +257371,233 @@
</parameter>
</method>
</class>
+<class name="CookieManager"
+ extends="java.net.CookieHandler"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="CookieManager"
+ type="java.net.CookieManager"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<constructor name="CookieManager"
+ type="java.net.CookieManager"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="store" type="java.net.CookieStore">
+</parameter>
+<parameter name="cookiePolicy" type="java.net.CookiePolicy">
+</parameter>
+</constructor>
+<method name="get"
+ return="java.util.Map<java.lang.String, java.util.List<java.lang.String>>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="java.net.URI">
+</parameter>
+<parameter name="requestHeaders" type="java.util.Map<java.lang.String, java.util.List<java.lang.String>>">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<method name="getCookieStore"
+ return="java.net.CookieStore"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="put"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="java.net.URI">
+</parameter>
+<parameter name="responseHeaders" type="java.util.Map<java.lang.String, java.util.List<java.lang.String>>">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<method name="setCookiePolicy"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cookiePolicy" type="java.net.CookiePolicy">
+</parameter>
+</method>
+</class>
+<interface name="CookiePolicy"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="shouldAccept"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="java.net.URI">
+</parameter>
+<parameter name="cookie" type="java.net.HttpCookie">
+</parameter>
+</method>
+<field name="ACCEPT_ALL"
+ type="java.net.CookiePolicy"
+ transient="false"
+ volatile="false"
+ value="null"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACCEPT_NONE"
+ type="java.net.CookiePolicy"
+ transient="false"
+ volatile="false"
+ value="null"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACCEPT_ORIGINAL_SERVER"
+ type="java.net.CookiePolicy"
+ transient="false"
+ volatile="false"
+ value="null"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</interface>
+<interface name="CookieStore"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="add"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="java.net.URI">
+</parameter>
+<parameter name="cookie" type="java.net.HttpCookie">
+</parameter>
+</method>
+<method name="get"
+ return="java.util.List<java.net.HttpCookie>"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="java.net.URI">
+</parameter>
+</method>
+<method name="getCookies"
+ return="java.util.List<java.net.HttpCookie>"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getURIs"
+ return="java.util.List<java.net.URI>"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="remove"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="java.net.URI">
+</parameter>
+<parameter name="cookie" type="java.net.HttpCookie">
+</parameter>
+</method>
+<method name="removeAll"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</interface>
<class name="DatagramPacket"
extends="java.lang.Object"
abstract="false"
@@ -254510,6 +258656,330 @@
</parameter>
</method>
</interface>
+<class name="HttpCookie"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="java.lang.Cloneable">
+</implements>
+<constructor name="HttpCookie"
+ type="java.net.HttpCookie"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="name" type="java.lang.String">
+</parameter>
+<parameter name="value" type="java.lang.String">
+</parameter>
+</constructor>
+<method name="clone"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="domainMatches"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="domainPattern" type="java.lang.String">
+</parameter>
+<parameter name="host" type="java.lang.String">
+</parameter>
+</method>
+<method name="getComment"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getCommentURL"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getDiscard"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getDomain"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getMaxAge"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getName"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getPath"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getPortlist"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getSecure"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getValue"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getVersion"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="hasExpired"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="parse"
+ return="java.util.List<java.net.HttpCookie>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="header" type="java.lang.String">
+</parameter>
+</method>
+<method name="setComment"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="comment" type="java.lang.String">
+</parameter>
+</method>
+<method name="setCommentURL"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="commentURL" type="java.lang.String">
+</parameter>
+</method>
+<method name="setDiscard"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="discard" type="boolean">
+</parameter>
+</method>
+<method name="setDomain"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pattern" type="java.lang.String">
+</parameter>
+</method>
+<method name="setMaxAge"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="deltaSeconds" type="long">
+</parameter>
+</method>
+<method name="setPath"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="path" type="java.lang.String">
+</parameter>
+</method>
+<method name="setPortlist"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="portList" type="java.lang.String">
+</parameter>
+</method>
+<method name="setSecure"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="secure" type="boolean">
+</parameter>
+</method>
+<method name="setValue"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="java.lang.String">
+</parameter>
+</method>
+<method name="setVersion"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="v" type="int">
+</parameter>
+</method>
+</class>
<class name="HttpRetryException"
extends="java.io.IOException"
abstract="false"
@@ -255212,6 +259682,93 @@
>
</field>
</class>
+<class name="IDN"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="toASCII"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="input" type="java.lang.String">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+<method name="toASCII"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="input" type="java.lang.String">
+</parameter>
+</method>
+<method name="toUnicode"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="input" type="java.lang.String">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+<method name="toUnicode"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="input" type="java.lang.String">
+</parameter>
+</method>
+<field name="ALLOW_UNASSIGNED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="USE_STD3_ASCII_RULES"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
<class name="Inet4Address"
extends="java.net.InetAddress"
abstract="false"
@@ -255554,7 +260111,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="netif" type="java.net.NetworkInterface">
+<parameter name="networkInterface" type="java.net.NetworkInterface">
</parameter>
<parameter name="ttl" type="int">
</parameter>
@@ -255701,6 +260258,48 @@
>
</method>
</class>
+<class name="InterfaceAddress"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="getAddress"
+ return="java.net.InetAddress"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getBroadcast"
+ return="java.net.InetAddress"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getNetworkPrefixLength"
+ return="short"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
<class name="JarURLConnection"
extends="java.net.URLConnection"
abstract="true"
@@ -256203,6 +260802,19 @@
visibility="public"
>
</method>
+<method name="getHardwareAddress"
+ return="byte[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="SocketException" type="java.net.SocketException">
+</exception>
+</method>
<method name="getInetAddresses"
return="java.util.Enumeration<java.net.InetAddress>"
abstract="false"
@@ -256214,6 +260826,30 @@
visibility="public"
>
</method>
+<method name="getInterfaceAddresses"
+ return="java.util.List<java.net.InterfaceAddress>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getMTU"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="SocketException" type="java.net.SocketException">
+</exception>
+</method>
<method name="getName"
return="java.lang.String"
abstract="false"
@@ -256238,6 +260874,91 @@
<exception name="SocketException" type="java.net.SocketException">
</exception>
</method>
+<method name="getParent"
+ return="java.net.NetworkInterface"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getSubInterfaces"
+ return="java.util.Enumeration<java.net.NetworkInterface>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isLoopback"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="SocketException" type="java.net.SocketException">
+</exception>
+</method>
+<method name="isPointToPoint"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="SocketException" type="java.net.SocketException">
+</exception>
+</method>
+<method name="isUp"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="SocketException" type="java.net.SocketException">
+</exception>
+</method>
+<method name="isVirtual"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="supportsMulticast"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="SocketException" type="java.net.SocketException">
+</exception>
+</method>
</class>
<class name="NoRouteToHostException"
extends="java.net.SocketException"
@@ -256572,9 +261293,9 @@
>
<parameter name="uri" type="java.net.URI">
</parameter>
-<parameter name="rqstMethod" type="java.lang.String">
+<parameter name="requestMethod" type="java.lang.String">
</parameter>
-<parameter name="rqstHeaders" type="java.util.Map<java.lang.String, java.util.List<java.lang.String>>">
+<parameter name="requestHeaders" type="java.util.Map<java.lang.String, java.util.List<java.lang.String>>">
</parameter>
<exception name="IOException" type="java.io.IOException">
</exception>
@@ -257144,7 +261865,7 @@
deprecated="not deprecated"
visibility="protected"
>
-<parameter name="anImpl" type="java.net.SocketImpl">
+<parameter name="impl" type="java.net.SocketImpl">
</parameter>
<exception name="SocketException" type="java.net.SocketException">
</exception>
@@ -258470,7 +263191,7 @@
>
<parameter name="scheme" type="java.lang.String">
</parameter>
-<parameter name="userinfo" type="java.lang.String">
+<parameter name="userInfo" type="java.lang.String">
</parameter>
<parameter name="host" type="java.lang.String">
</parameter>
@@ -260150,7 +264871,7 @@
>
<parameter name="s" type="java.lang.String">
</parameter>
-<parameter name="enc" type="java.lang.String">
+<parameter name="encoding" type="java.lang.String">
</parameter>
<exception name="UnsupportedEncodingException" type="java.io.UnsupportedEncodingException">
</exception>
@@ -260496,6 +265217,28 @@
deprecated="not deprecated"
visibility="public"
>
+<method name="array"
+ return="java.lang.Object"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="arrayOffset"
+ return="int"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="capacity"
return="int"
abstract="false"
@@ -260529,6 +265272,17 @@
visibility="public"
>
</method>
+<method name="hasArray"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="hasRemaining"
return="boolean"
abstract="false"
@@ -260540,6 +265294,17 @@
visibility="public"
>
</method>
+<method name="isDirect"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="isReadOnly"
return="boolean"
abstract="true"
@@ -266976,7 +271741,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="repl" type="byte[]">
+<parameter name="replacement" type="byte[]">
</parameter>
</method>
<method name="malformedInputAction"
@@ -267295,7 +272060,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="charset" type="java.lang.String">
+<parameter name="charsetName" type="java.lang.String">
</parameter>
</constructor>
<method name="getCharsetName"
@@ -267385,7 +272150,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="charset" type="java.lang.String">
+<parameter name="charsetName" type="java.lang.String">
</parameter>
</constructor>
<method name="getCharsetName"
@@ -281096,6 +285861,19 @@
deprecated="not deprecated"
visibility="public"
>
+<method name="free"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="getArray"
return="java.lang.Object"
abstract="true"
@@ -281276,6 +286054,76 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="BatchUpdateException"
+ type="java.sql.BatchUpdateException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="updateCounts" type="int[]">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="BatchUpdateException"
+ type="java.sql.BatchUpdateException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="updateCounts" type="int[]">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="BatchUpdateException"
+ type="java.sql.BatchUpdateException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="SQLState" type="java.lang.String">
+</parameter>
+<parameter name="updateCounts" type="int[]">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="BatchUpdateException"
+ type="java.sql.BatchUpdateException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="SQLState" type="java.lang.String">
+</parameter>
+<parameter name="vendorCode" type="int">
+</parameter>
+<parameter name="updateCounts" type="int[]">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="BatchUpdateException"
+ type="java.sql.BatchUpdateException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
<parameter name="updateCounts" type="int[]">
</parameter>
</constructor>
@@ -281340,6 +286188,19 @@
deprecated="not deprecated"
visibility="public"
>
+<method name="free"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="getBinaryStream"
return="java.io.InputStream"
abstract="true"
@@ -281353,6 +286214,23 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="getBinaryStream"
+ return="java.io.InputStream"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pos" type="long">
+</parameter>
+<parameter name="length" type="long">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="getBytes"
return="byte[]"
abstract="true"
@@ -281692,6 +286570,36 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="getCharacterStream"
+ return="java.io.Reader"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterIndex" type="int">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="getCharacterStream"
+ return="java.io.Reader"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="getClob"
return="java.sql.Clob"
abstract="true"
@@ -281906,6 +286814,96 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="getNCharacterStream"
+ return="java.io.Reader"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterIndex" type="int">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="getNCharacterStream"
+ return="java.io.Reader"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="getNClob"
+ return="java.sql.NClob"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterIndex" type="int">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="getNClob"
+ return="java.sql.NClob"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="getNString"
+ return="java.lang.String"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterIndex" type="int">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="getNString"
+ return="java.lang.String"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="getObject"
return="java.lang.Object"
abstract="true"
@@ -282000,6 +286998,66 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="getRowId"
+ return="java.sql.RowId"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterIndex" type="int">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="getRowId"
+ return="java.sql.RowId"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="getSQLXML"
+ return="java.sql.SQLXML"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterIndex" type="int">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="getSQLXML"
+ return="java.sql.SQLXML"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="getShort"
return="short"
abstract="true"
@@ -282347,6 +287405,42 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="setAsciiStream"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="x" type="java.io.InputStream">
+</parameter>
+<parameter name="length" type="long">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setAsciiStream"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="x" type="java.io.InputStream">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="setBigDecimal"
return="void"
abstract="true"
@@ -282383,6 +287477,95 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="setBinaryStream"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="x" type="java.io.InputStream">
+</parameter>
+<parameter name="length" type="long">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setBinaryStream"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="x" type="java.io.InputStream">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setBlob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="inputStream" type="java.io.InputStream">
+</parameter>
+<parameter name="length" type="long">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setBlob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="x" type="java.sql.Blob">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setBlob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="inputStream" type="java.io.InputStream">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="setBoolean"
return="void"
abstract="true"
@@ -282453,6 +287636,95 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="setCharacterStream"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="reader" type="java.io.Reader">
+</parameter>
+<parameter name="length" type="long">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setCharacterStream"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="reader" type="java.io.Reader">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setClob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="reader" type="java.io.Reader">
+</parameter>
+<parameter name="length" type="long">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setClob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="x" type="java.sql.Clob">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setClob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="reader" type="java.io.Reader">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="setDate"
return="void"
abstract="true"
@@ -282557,6 +287829,112 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="setNCharacterStream"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="value" type="java.io.Reader">
+</parameter>
+<parameter name="length" type="long">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setNCharacterStream"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="value" type="java.io.Reader">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setNClob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="value" type="java.sql.NClob">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setNClob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="reader" type="java.io.Reader">
+</parameter>
+<parameter name="length" type="long">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setNClob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="reader" type="java.io.Reader">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setNString"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="value" type="java.lang.String">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="setNull"
return="void"
abstract="true"
@@ -282650,6 +288028,40 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="setRowId"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="x" type="java.sql.RowId">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setSQLXML"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="xmlObject" type="java.sql.SQLXML">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="setShort"
return="void"
abstract="true"
@@ -282787,6 +288199,39 @@
</exception>
</method>
</interface>
+<class name="ClientInfoStatus"
+ extends="java.lang.Enum"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="valueOf"
+ return="java.sql.ClientInfoStatus"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="name" type="java.lang.String">
+</parameter>
+</method>
+<method name="values"
+ return="java.sql.ClientInfoStatus[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
<interface name="Clob"
abstract="true"
static="false"
@@ -282794,6 +288239,19 @@
deprecated="not deprecated"
visibility="public"
>
+<method name="free"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="getAsciiStream"
return="java.io.InputStream"
abstract="true"
@@ -282820,6 +288278,23 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="getCharacterStream"
+ return="java.io.Reader"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pos" type="long">
+</parameter>
+<parameter name="length" type="long">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="getSubString"
return="java.lang.String"
abstract="true"
@@ -282975,6 +288450,8 @@
deprecated="not deprecated"
visibility="public"
>
+<implements name="java.sql.Wrapper">
+</implements>
<method name="clearWarnings"
return="void"
abstract="true"
@@ -283014,6 +288491,75 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="createArrayOf"
+ return="java.sql.Array"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="typeName" type="java.lang.String">
+</parameter>
+<parameter name="elements" type="java.lang.Object[]">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="createBlob"
+ return="java.sql.Blob"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="createClob"
+ return="java.sql.Clob"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="createNClob"
+ return="java.sql.NClob"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="createSQLXML"
+ return="java.sql.SQLXML"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="createStatement"
return="java.sql.Statement"
abstract="true"
@@ -283063,6 +288609,23 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="createStruct"
+ return="java.sql.Struct"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="typeName" type="java.lang.String">
+</parameter>
+<parameter name="attributes" type="java.lang.Object[]">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="getAutoCommit"
return="boolean"
abstract="true"
@@ -283089,6 +288652,34 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="getClientInfo"
+ return="java.lang.String"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="name" type="java.lang.String">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="getClientInfo"
+ return="java.util.Properties"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="getHoldability"
return="int"
abstract="true"
@@ -283180,6 +288771,21 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="isValid"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="timeout" type="int">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="nativeSQL"
return="java.lang.String"
abstract="true"
@@ -283429,6 +289035,38 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="setClientInfo"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="name" type="java.lang.String">
+</parameter>
+<parameter name="value" type="java.lang.String">
+</parameter>
+<exception name="SQLClientInfoException" type="java.sql.SQLClientInfoException">
+</exception>
+</method>
+<method name="setClientInfo"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="properties" type="java.util.Properties">
+</parameter>
+<exception name="SQLClientInfoException" type="java.sql.SQLClientInfoException">
+</exception>
+</method>
<method name="setHoldability"
return="void"
abstract="true"
@@ -283601,6 +289239,26 @@
<parameter name="transferSize" type="int">
</parameter>
</constructor>
+<constructor name="DataTruncation"
+ type="java.sql.DataTruncation"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="index" type="int">
+</parameter>
+<parameter name="parameter" type="boolean">
+</parameter>
+<parameter name="read" type="boolean">
+</parameter>
+<parameter name="dataSize" type="int">
+</parameter>
+<parameter name="transferSize" type="int">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
<method name="getDataSize"
return="int"
abstract="false"
@@ -283664,6 +289322,8 @@
deprecated="not deprecated"
visibility="public"
>
+<implements name="java.sql.Wrapper">
+</implements>
<method name="allProceduresAreCallable"
return="boolean"
abstract="true"
@@ -283690,6 +289350,19 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="autoCommitFailureClosesAllResultSets"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="dataDefinitionCausesTransactionCommit"
return="boolean"
abstract="true"
@@ -283827,6 +289500,19 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="getClientInfoProperties"
+ return="java.sql.ResultSet"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="getColumnPrivileges"
return="java.sql.ResultSet"
abstract="true"
@@ -284052,6 +289738,46 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="getFunctionColumns"
+ return="java.sql.ResultSet"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="catalog" type="java.lang.String">
+</parameter>
+<parameter name="schemaPattern" type="java.lang.String">
+</parameter>
+<parameter name="functionNamePattern" type="java.lang.String">
+</parameter>
+<parameter name="columnNamePattern" type="java.lang.String">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="getFunctions"
+ return="java.sql.ResultSet"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="catalog" type="java.lang.String">
+</parameter>
+<parameter name="schemaPattern" type="java.lang.String">
+</parameter>
+<parameter name="functionNamePattern" type="java.lang.String">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="getIdentifierQuoteString"
return="java.lang.String"
abstract="true"
@@ -284491,6 +290217,19 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="getRowIdLifetime"
+ return="java.sql.RowIdLifetime"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="getSQLKeywords"
return="java.lang.String"
abstract="true"
@@ -284543,6 +290282,23 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="getSchemas"
+ return="java.sql.ResultSet"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="catalog" type="java.lang.String">
+</parameter>
+<parameter name="schemaPattern" type="java.lang.String">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="getSearchStringEscape"
return="java.lang.String"
abstract="true"
@@ -285792,6 +291548,19 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="supportsStoredFunctionsUsingCallSyntax"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="supportsStoredProcedures"
return="boolean"
abstract="true"
@@ -286097,6 +291866,138 @@
visibility="public"
>
</field>
+<field name="functionColumnIn"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="functionColumnInOut"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="functionColumnOut"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="functionColumnResult"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="5"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="functionColumnUnknown"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="functionNoNulls"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="functionNoTable"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="functionNullable"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="functionNullableUnknown"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="functionResultUnknown"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="functionReturn"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="functionReturnsTable"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="importedKeyCascade"
type="int"
transient="false"
@@ -286317,6 +292218,17 @@
visibility="public"
>
</field>
+<field name="sqlStateSQL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="sqlStateSQL99"
type="int"
transient="false"
@@ -286903,6 +292815,16 @@
>
</field>
</class>
+<interface name="NClob"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="java.sql.Clob">
+</implements>
+</interface>
<interface name="ParameterMetaData"
abstract="true"
static="false"
@@ -286910,6 +292832,8 @@
deprecated="not deprecated"
visibility="public"
>
+<implements name="java.sql.Wrapper">
+</implements>
<method name="getParameterClassName"
return="java.lang.String"
abstract="true"
@@ -287257,6 +293181,42 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="setAsciiStream"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterIndex" type="int">
+</parameter>
+<parameter name="x" type="java.io.InputStream">
+</parameter>
+<parameter name="length" type="long">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setAsciiStream"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterIndex" type="int">
+</parameter>
+<parameter name="x" type="java.io.InputStream">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="setBigDecimal"
return="void"
abstract="true"
@@ -287293,6 +293253,42 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="setBinaryStream"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterIndex" type="int">
+</parameter>
+<parameter name="x" type="java.io.InputStream">
+</parameter>
+<parameter name="length" type="long">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setBinaryStream"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterIndex" type="int">
+</parameter>
+<parameter name="x" type="java.io.InputStream">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="setBlob"
return="void"
abstract="true"
@@ -287310,6 +293306,42 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="setBlob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterIndex" type="int">
+</parameter>
+<parameter name="inputStream" type="java.io.InputStream">
+</parameter>
+<parameter name="length" type="long">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setBlob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterIndex" type="int">
+</parameter>
+<parameter name="inputStream" type="java.io.InputStream">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="setBoolean"
return="void"
abstract="true"
@@ -287380,6 +293412,42 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="setCharacterStream"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterIndex" type="int">
+</parameter>
+<parameter name="reader" type="java.io.Reader">
+</parameter>
+<parameter name="length" type="long">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setCharacterStream"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterIndex" type="int">
+</parameter>
+<parameter name="reader" type="java.io.Reader">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="setClob"
return="void"
abstract="true"
@@ -287397,6 +293465,42 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="setClob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterIndex" type="int">
+</parameter>
+<parameter name="reader" type="java.io.Reader">
+</parameter>
+<parameter name="length" type="long">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setClob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterIndex" type="int">
+</parameter>
+<parameter name="reader" type="java.io.Reader">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="setDate"
return="void"
abstract="true"
@@ -287501,6 +293605,112 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="setNCharacterStream"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterIndex" type="int">
+</parameter>
+<parameter name="value" type="java.io.Reader">
+</parameter>
+<parameter name="length" type="long">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setNCharacterStream"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterIndex" type="int">
+</parameter>
+<parameter name="value" type="java.io.Reader">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setNClob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterIndex" type="int">
+</parameter>
+<parameter name="value" type="java.sql.NClob">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setNClob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterIndex" type="int">
+</parameter>
+<parameter name="reader" type="java.io.Reader">
+</parameter>
+<parameter name="length" type="long">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setNClob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterIndex" type="int">
+</parameter>
+<parameter name="reader" type="java.io.Reader">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setNString"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterIndex" type="int">
+</parameter>
+<parameter name="value" type="java.lang.String">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="setNull"
return="void"
abstract="true"
@@ -287611,6 +293821,40 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="setRowId"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterIndex" type="int">
+</parameter>
+<parameter name="x" type="java.sql.RowId">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setSQLXML"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterIndex" type="int">
+</parameter>
+<parameter name="xmlObject" type="java.sql.SQLXML">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="setShort"
return="void"
abstract="true"
@@ -287825,6 +294069,8 @@
deprecated="not deprecated"
visibility="public"
>
+<implements name="java.sql.Wrapper">
+</implements>
<method name="absolute"
return="boolean"
abstract="true"
@@ -288456,6 +294702,19 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="getHoldability"
+ return="int"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="getInt"
return="int"
abstract="true"
@@ -288529,6 +294788,96 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="getNCharacterStream"
+ return="java.io.Reader"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnIndex" type="int">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="getNCharacterStream"
+ return="java.io.Reader"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnLabel" type="java.lang.String">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="getNClob"
+ return="java.sql.NClob"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnIndex" type="int">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="getNClob"
+ return="java.sql.NClob"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnLabel" type="java.lang.String">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="getNString"
+ return="java.lang.String"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnIndex" type="int">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="getNString"
+ return="java.lang.String"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnLabel" type="java.lang.String">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="getObject"
return="java.lang.Object"
abstract="true"
@@ -288636,6 +294985,66 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="getRowId"
+ return="java.sql.RowId"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnIndex" type="int">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="getRowId"
+ return="java.sql.RowId"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnLabel" type="java.lang.String">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="getSQLXML"
+ return="java.sql.SQLXML"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnIndex" type="int">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="getSQLXML"
+ return="java.sql.SQLXML"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnLabel" type="java.lang.String">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="getShort"
return="short"
abstract="true"
@@ -288962,6 +295371,19 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="isClosed"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="isFirst"
return="boolean"
abstract="true"
@@ -289222,6 +295644,78 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="updateAsciiStream"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnIndex" type="int">
+</parameter>
+<parameter name="x" type="java.io.InputStream">
+</parameter>
+<parameter name="length" type="long">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="updateAsciiStream"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnLabel" type="java.lang.String">
+</parameter>
+<parameter name="x" type="java.io.InputStream">
+</parameter>
+<parameter name="length" type="long">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="updateAsciiStream"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnIndex" type="int">
+</parameter>
+<parameter name="x" type="java.io.InputStream">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="updateAsciiStream"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnLabel" type="java.lang.String">
+</parameter>
+<parameter name="x" type="java.io.InputStream">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="updateBigDecimal"
return="void"
abstract="true"
@@ -289294,6 +295788,78 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="updateBinaryStream"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnIndex" type="int">
+</parameter>
+<parameter name="x" type="java.io.InputStream">
+</parameter>
+<parameter name="length" type="long">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="updateBinaryStream"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnLabel" type="java.lang.String">
+</parameter>
+<parameter name="x" type="java.io.InputStream">
+</parameter>
+<parameter name="length" type="long">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="updateBinaryStream"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnIndex" type="int">
+</parameter>
+<parameter name="x" type="java.io.InputStream">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="updateBinaryStream"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnLabel" type="java.lang.String">
+</parameter>
+<parameter name="x" type="java.io.InputStream">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="updateBlob"
return="void"
abstract="true"
@@ -289328,6 +295894,78 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="updateBlob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnIndex" type="int">
+</parameter>
+<parameter name="inputStream" type="java.io.InputStream">
+</parameter>
+<parameter name="length" type="long">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="updateBlob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnLabel" type="java.lang.String">
+</parameter>
+<parameter name="inputStream" type="java.io.InputStream">
+</parameter>
+<parameter name="length" type="long">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="updateBlob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnIndex" type="int">
+</parameter>
+<parameter name="inputStream" type="java.io.InputStream">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="updateBlob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnLabel" type="java.lang.String">
+</parameter>
+<parameter name="inputStream" type="java.io.InputStream">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="updateBoolean"
return="void"
abstract="true"
@@ -289468,6 +296106,78 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="updateCharacterStream"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnIndex" type="int">
+</parameter>
+<parameter name="x" type="java.io.Reader">
+</parameter>
+<parameter name="length" type="long">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="updateCharacterStream"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnLabel" type="java.lang.String">
+</parameter>
+<parameter name="reader" type="java.io.Reader">
+</parameter>
+<parameter name="length" type="long">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="updateCharacterStream"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnIndex" type="int">
+</parameter>
+<parameter name="x" type="java.io.Reader">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="updateCharacterStream"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnLabel" type="java.lang.String">
+</parameter>
+<parameter name="reader" type="java.io.Reader">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="updateClob"
return="void"
abstract="true"
@@ -289502,6 +296212,78 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="updateClob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnIndex" type="int">
+</parameter>
+<parameter name="reader" type="java.io.Reader">
+</parameter>
+<parameter name="length" type="long">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="updateClob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnLabel" type="java.lang.String">
+</parameter>
+<parameter name="reader" type="java.io.Reader">
+</parameter>
+<parameter name="length" type="long">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="updateClob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnIndex" type="int">
+</parameter>
+<parameter name="reader" type="java.io.Reader">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="updateClob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnLabel" type="java.lang.String">
+</parameter>
+<parameter name="reader" type="java.io.Reader">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="updateDate"
return="void"
abstract="true"
@@ -289672,6 +296454,218 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="updateNCharacterStream"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnIndex" type="int">
+</parameter>
+<parameter name="x" type="java.io.Reader">
+</parameter>
+<parameter name="length" type="long">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="updateNCharacterStream"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnLabel" type="java.lang.String">
+</parameter>
+<parameter name="reader" type="java.io.Reader">
+</parameter>
+<parameter name="length" type="long">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="updateNCharacterStream"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnIndex" type="int">
+</parameter>
+<parameter name="x" type="java.io.Reader">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="updateNCharacterStream"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnLabel" type="java.lang.String">
+</parameter>
+<parameter name="reader" type="java.io.Reader">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="updateNClob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnIndex" type="int">
+</parameter>
+<parameter name="nClob" type="java.sql.NClob">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="updateNClob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnLabel" type="java.lang.String">
+</parameter>
+<parameter name="nClob" type="java.sql.NClob">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="updateNClob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnIndex" type="int">
+</parameter>
+<parameter name="reader" type="java.io.Reader">
+</parameter>
+<parameter name="length" type="long">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="updateNClob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnLabel" type="java.lang.String">
+</parameter>
+<parameter name="reader" type="java.io.Reader">
+</parameter>
+<parameter name="length" type="long">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="updateNClob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnIndex" type="int">
+</parameter>
+<parameter name="reader" type="java.io.Reader">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="updateNClob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnLabel" type="java.lang.String">
+</parameter>
+<parameter name="reader" type="java.io.Reader">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="updateNString"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnIndex" type="int">
+</parameter>
+<parameter name="nString" type="java.lang.String">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="updateNString"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnLabel" type="java.lang.String">
+</parameter>
+<parameter name="nString" type="java.lang.String">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="updateNull"
return="void"
abstract="true"
@@ -289821,6 +296815,74 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="updateRowId"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnIndex" type="int">
+</parameter>
+<parameter name="x" type="java.sql.RowId">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="updateRowId"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnLabel" type="java.lang.String">
+</parameter>
+<parameter name="x" type="java.sql.RowId">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="updateSQLXML"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnIndex" type="int">
+</parameter>
+<parameter name="xmlObject" type="java.sql.SQLXML">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="updateSQLXML"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnLabel" type="java.lang.String">
+</parameter>
+<parameter name="xmlObject" type="java.sql.SQLXML">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="updateShort"
return="void"
abstract="true"
@@ -290088,6 +297150,8 @@
deprecated="not deprecated"
visibility="public"
>
+<implements name="java.sql.Wrapper">
+</implements>
<method name="getCatalogName"
return="java.lang.String"
abstract="true"
@@ -290435,6 +297499,233 @@
>
</field>
</interface>
+<interface name="RowId"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="equals"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="obj" type="java.lang.Object">
+</parameter>
+</method>
+<method name="getBytes"
+ return="byte[]"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="hashCode"
+ return="int"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="toString"
+ return="java.lang.String"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</interface>
+<class name="RowIdLifetime"
+ extends="java.lang.Enum"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="valueOf"
+ return="java.sql.RowIdLifetime"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="name" type="java.lang.String">
+</parameter>
+</method>
+<method name="values"
+ return="java.sql.RowIdLifetime[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="SQLClientInfoException"
+ extends="java.sql.SQLException"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="SQLClientInfoException"
+ type="java.sql.SQLClientInfoException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<constructor name="SQLClientInfoException"
+ type="java.sql.SQLClientInfoException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="failedProperties" type="java.util.Map<java.lang.String, java.sql.ClientInfoStatus>">
+</parameter>
+</constructor>
+<constructor name="SQLClientInfoException"
+ type="java.sql.SQLClientInfoException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="failedProperties" type="java.util.Map<java.lang.String, java.sql.ClientInfoStatus>">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="SQLClientInfoException"
+ type="java.sql.SQLClientInfoException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="failedProperties" type="java.util.Map<java.lang.String, java.sql.ClientInfoStatus>">
+</parameter>
+</constructor>
+<constructor name="SQLClientInfoException"
+ type="java.sql.SQLClientInfoException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="failedProperties" type="java.util.Map<java.lang.String, java.sql.ClientInfoStatus>">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="SQLClientInfoException"
+ type="java.sql.SQLClientInfoException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+<parameter name="vendorCode" type="int">
+</parameter>
+<parameter name="failedProperties" type="java.util.Map<java.lang.String, java.sql.ClientInfoStatus>">
+</parameter>
+</constructor>
+<constructor name="SQLClientInfoException"
+ type="java.sql.SQLClientInfoException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+<parameter name="vendorCode" type="int">
+</parameter>
+<parameter name="failedProperties" type="java.util.Map<java.lang.String, java.sql.ClientInfoStatus>">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="SQLClientInfoException"
+ type="java.sql.SQLClientInfoException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+<parameter name="failedProperties" type="java.util.Map<java.lang.String, java.sql.ClientInfoStatus>">
+</parameter>
+</constructor>
+<constructor name="SQLClientInfoException"
+ type="java.sql.SQLClientInfoException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+<parameter name="failedProperties" type="java.util.Map<java.lang.String, java.sql.ClientInfoStatus>">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<method name="getFailedProperties"
+ return="java.util.Map<java.lang.String, java.sql.ClientInfoStatus>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
<interface name="SQLData"
abstract="true"
static="false"
@@ -290488,6 +297779,111 @@
</exception>
</method>
</interface>
+<class name="SQLDataException"
+ extends="java.sql.SQLNonTransientException"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="SQLDataException"
+ type="java.sql.SQLDataException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<constructor name="SQLDataException"
+ type="java.sql.SQLDataException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="SQLDataException"
+ type="java.sql.SQLDataException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="SQLDataException"
+ type="java.sql.SQLDataException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+<parameter name="vendorCode" type="int">
+</parameter>
+</constructor>
+<constructor name="SQLDataException"
+ type="java.sql.SQLDataException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="SQLDataException"
+ type="java.sql.SQLDataException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="SQLDataException"
+ type="java.sql.SQLDataException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="SQLDataException"
+ type="java.sql.SQLDataException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+<parameter name="vendorCode" type="int">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+</class>
<class name="SQLException"
extends="java.lang.Exception"
abstract="false"
@@ -290496,6 +297892,8 @@
deprecated="not deprecated"
visibility="public"
>
+<implements name="java.lang.Iterable">
+</implements>
<implements name="java.io.Serializable">
</implements>
<constructor name="SQLException"
@@ -290542,6 +297940,58 @@
<parameter name="theErrorCode" type="int">
</parameter>
</constructor>
+<constructor name="SQLException"
+ type="java.sql.SQLException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="theCause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="SQLException"
+ type="java.sql.SQLException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="theReason" type="java.lang.String">
+</parameter>
+<parameter name="theCause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="SQLException"
+ type="java.sql.SQLException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="theReason" type="java.lang.String">
+</parameter>
+<parameter name="theSQLState" type="java.lang.String">
+</parameter>
+<parameter name="theCause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="SQLException"
+ type="java.sql.SQLException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="theReason" type="java.lang.String">
+</parameter>
+<parameter name="theSQLState" type="java.lang.String">
+</parameter>
+<parameter name="theErrorCode" type="int">
+</parameter>
+<parameter name="theCause" type="java.lang.Throwable">
+</parameter>
+</constructor>
<method name="getErrorCode"
return="int"
abstract="false"
@@ -290575,6 +298025,17 @@
visibility="public"
>
</method>
+<method name="iterator"
+ return="java.util.Iterator<java.lang.Throwable>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="setNextException"
return="void"
abstract="false"
@@ -290589,6 +298050,111 @@
</parameter>
</method>
</class>
+<class name="SQLFeatureNotSupportedException"
+ extends="java.sql.SQLNonTransientException"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="SQLFeatureNotSupportedException"
+ type="java.sql.SQLFeatureNotSupportedException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<constructor name="SQLFeatureNotSupportedException"
+ type="java.sql.SQLFeatureNotSupportedException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="SQLFeatureNotSupportedException"
+ type="java.sql.SQLFeatureNotSupportedException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="SQLFeatureNotSupportedException"
+ type="java.sql.SQLFeatureNotSupportedException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+<parameter name="vendorCode" type="int">
+</parameter>
+</constructor>
+<constructor name="SQLFeatureNotSupportedException"
+ type="java.sql.SQLFeatureNotSupportedException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="SQLFeatureNotSupportedException"
+ type="java.sql.SQLFeatureNotSupportedException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="SQLFeatureNotSupportedException"
+ type="java.sql.SQLFeatureNotSupportedException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="SQLFeatureNotSupportedException"
+ type="java.sql.SQLFeatureNotSupportedException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+<parameter name="vendorCode" type="int">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+</class>
<interface name="SQLInput"
abstract="true"
static="false"
@@ -290791,6 +298357,32 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="readNClob"
+ return="java.sql.NClob"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="readNString"
+ return="java.lang.String"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="readObject"
return="java.lang.Object"
abstract="true"
@@ -290817,6 +298409,32 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="readRowId"
+ return="java.sql.RowId"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="readSQLXML"
+ return="java.sql.SQLXML"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="readShort"
return="short"
abstract="true"
@@ -290896,6 +298514,426 @@
</exception>
</method>
</interface>
+<class name="SQLIntegrityConstraintViolationException"
+ extends="java.sql.SQLNonTransientException"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="SQLIntegrityConstraintViolationException"
+ type="java.sql.SQLIntegrityConstraintViolationException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<constructor name="SQLIntegrityConstraintViolationException"
+ type="java.sql.SQLIntegrityConstraintViolationException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="SQLIntegrityConstraintViolationException"
+ type="java.sql.SQLIntegrityConstraintViolationException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="SQLIntegrityConstraintViolationException"
+ type="java.sql.SQLIntegrityConstraintViolationException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+<parameter name="vendorCode" type="int">
+</parameter>
+</constructor>
+<constructor name="SQLIntegrityConstraintViolationException"
+ type="java.sql.SQLIntegrityConstraintViolationException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="SQLIntegrityConstraintViolationException"
+ type="java.sql.SQLIntegrityConstraintViolationException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="SQLIntegrityConstraintViolationException"
+ type="java.sql.SQLIntegrityConstraintViolationException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="SQLIntegrityConstraintViolationException"
+ type="java.sql.SQLIntegrityConstraintViolationException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+<parameter name="vendorCode" type="int">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+</class>
+<class name="SQLInvalidAuthorizationSpecException"
+ extends="java.sql.SQLNonTransientException"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="SQLInvalidAuthorizationSpecException"
+ type="java.sql.SQLInvalidAuthorizationSpecException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<constructor name="SQLInvalidAuthorizationSpecException"
+ type="java.sql.SQLInvalidAuthorizationSpecException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="SQLInvalidAuthorizationSpecException"
+ type="java.sql.SQLInvalidAuthorizationSpecException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="SQLInvalidAuthorizationSpecException"
+ type="java.sql.SQLInvalidAuthorizationSpecException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+<parameter name="vendorCode" type="int">
+</parameter>
+</constructor>
+<constructor name="SQLInvalidAuthorizationSpecException"
+ type="java.sql.SQLInvalidAuthorizationSpecException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="SQLInvalidAuthorizationSpecException"
+ type="java.sql.SQLInvalidAuthorizationSpecException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="SQLInvalidAuthorizationSpecException"
+ type="java.sql.SQLInvalidAuthorizationSpecException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="SQLInvalidAuthorizationSpecException"
+ type="java.sql.SQLInvalidAuthorizationSpecException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+<parameter name="vendorCode" type="int">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+</class>
+<class name="SQLNonTransientConnectionException"
+ extends="java.sql.SQLNonTransientException"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="SQLNonTransientConnectionException"
+ type="java.sql.SQLNonTransientConnectionException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<constructor name="SQLNonTransientConnectionException"
+ type="java.sql.SQLNonTransientConnectionException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="SQLNonTransientConnectionException"
+ type="java.sql.SQLNonTransientConnectionException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="SQLNonTransientConnectionException"
+ type="java.sql.SQLNonTransientConnectionException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+<parameter name="vendorCode" type="int">
+</parameter>
+</constructor>
+<constructor name="SQLNonTransientConnectionException"
+ type="java.sql.SQLNonTransientConnectionException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="SQLNonTransientConnectionException"
+ type="java.sql.SQLNonTransientConnectionException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="SQLNonTransientConnectionException"
+ type="java.sql.SQLNonTransientConnectionException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="SQLNonTransientConnectionException"
+ type="java.sql.SQLNonTransientConnectionException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+<parameter name="vendorCode" type="int">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+</class>
+<class name="SQLNonTransientException"
+ extends="java.sql.SQLException"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="SQLNonTransientException"
+ type="java.sql.SQLNonTransientException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<constructor name="SQLNonTransientException"
+ type="java.sql.SQLNonTransientException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="SQLNonTransientException"
+ type="java.sql.SQLNonTransientException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="SQLNonTransientException"
+ type="java.sql.SQLNonTransientException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+<parameter name="vendorCode" type="int">
+</parameter>
+</constructor>
+<constructor name="SQLNonTransientException"
+ type="java.sql.SQLNonTransientException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="SQLNonTransientException"
+ type="java.sql.SQLNonTransientException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="SQLNonTransientException"
+ type="java.sql.SQLNonTransientException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="SQLNonTransientException"
+ type="java.sql.SQLNonTransientException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+<parameter name="vendorCode" type="int">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+</class>
<interface name="SQLOutput"
abstract="true"
static="false"
@@ -291128,6 +299166,36 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="writeNClob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="x" type="java.sql.NClob">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="writeNString"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="x" type="java.lang.String">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="writeObject"
return="void"
abstract="true"
@@ -291158,6 +299226,36 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="writeRowId"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="x" type="java.sql.RowId">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="writeSQLXML"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="x" type="java.sql.SQLXML">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="writeShort"
return="void"
abstract="true"
@@ -291284,6 +299382,636 @@
</parameter>
</constructor>
</class>
+<class name="SQLRecoverableException"
+ extends="java.sql.SQLException"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="SQLRecoverableException"
+ type="java.sql.SQLRecoverableException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<constructor name="SQLRecoverableException"
+ type="java.sql.SQLRecoverableException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="SQLRecoverableException"
+ type="java.sql.SQLRecoverableException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="SQLRecoverableException"
+ type="java.sql.SQLRecoverableException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+<parameter name="vendorCode" type="int">
+</parameter>
+</constructor>
+<constructor name="SQLRecoverableException"
+ type="java.sql.SQLRecoverableException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="SQLRecoverableException"
+ type="java.sql.SQLRecoverableException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="SQLRecoverableException"
+ type="java.sql.SQLRecoverableException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="SQLRecoverableException"
+ type="java.sql.SQLRecoverableException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+<parameter name="vendorCode" type="int">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+</class>
+<class name="SQLSyntaxErrorException"
+ extends="java.sql.SQLNonTransientException"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="SQLSyntaxErrorException"
+ type="java.sql.SQLSyntaxErrorException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<constructor name="SQLSyntaxErrorException"
+ type="java.sql.SQLSyntaxErrorException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="SQLSyntaxErrorException"
+ type="java.sql.SQLSyntaxErrorException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="SQLSyntaxErrorException"
+ type="java.sql.SQLSyntaxErrorException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+<parameter name="vendorCode" type="int">
+</parameter>
+</constructor>
+<constructor name="SQLSyntaxErrorException"
+ type="java.sql.SQLSyntaxErrorException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="SQLSyntaxErrorException"
+ type="java.sql.SQLSyntaxErrorException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="SQLSyntaxErrorException"
+ type="java.sql.SQLSyntaxErrorException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="SQLSyntaxErrorException"
+ type="java.sql.SQLSyntaxErrorException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+<parameter name="vendorCode" type="int">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+</class>
+<class name="SQLTimeoutException"
+ extends="java.sql.SQLTransientException"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="SQLTimeoutException"
+ type="java.sql.SQLTimeoutException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<constructor name="SQLTimeoutException"
+ type="java.sql.SQLTimeoutException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="SQLTimeoutException"
+ type="java.sql.SQLTimeoutException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="SQLTimeoutException"
+ type="java.sql.SQLTimeoutException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+<parameter name="vendorCode" type="int">
+</parameter>
+</constructor>
+<constructor name="SQLTimeoutException"
+ type="java.sql.SQLTimeoutException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="SQLTimeoutException"
+ type="java.sql.SQLTimeoutException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="SQLTimeoutException"
+ type="java.sql.SQLTimeoutException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="SQLTimeoutException"
+ type="java.sql.SQLTimeoutException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+<parameter name="vendorCode" type="int">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+</class>
+<class name="SQLTransactionRollbackException"
+ extends="java.sql.SQLTransientException"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="SQLTransactionRollbackException"
+ type="java.sql.SQLTransactionRollbackException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<constructor name="SQLTransactionRollbackException"
+ type="java.sql.SQLTransactionRollbackException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="SQLTransactionRollbackException"
+ type="java.sql.SQLTransactionRollbackException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="SQLTransactionRollbackException"
+ type="java.sql.SQLTransactionRollbackException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+<parameter name="vendorCode" type="int">
+</parameter>
+</constructor>
+<constructor name="SQLTransactionRollbackException"
+ type="java.sql.SQLTransactionRollbackException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="SQLTransactionRollbackException"
+ type="java.sql.SQLTransactionRollbackException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="SQLTransactionRollbackException"
+ type="java.sql.SQLTransactionRollbackException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="SQLTransactionRollbackException"
+ type="java.sql.SQLTransactionRollbackException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+<parameter name="vendorCode" type="int">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+</class>
+<class name="SQLTransientConnectionException"
+ extends="java.sql.SQLTransientException"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="SQLTransientConnectionException"
+ type="java.sql.SQLTransientConnectionException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<constructor name="SQLTransientConnectionException"
+ type="java.sql.SQLTransientConnectionException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="SQLTransientConnectionException"
+ type="java.sql.SQLTransientConnectionException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="SQLTransientConnectionException"
+ type="java.sql.SQLTransientConnectionException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+<parameter name="vendorCode" type="int">
+</parameter>
+</constructor>
+<constructor name="SQLTransientConnectionException"
+ type="java.sql.SQLTransientConnectionException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="SQLTransientConnectionException"
+ type="java.sql.SQLTransientConnectionException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="SQLTransientConnectionException"
+ type="java.sql.SQLTransientConnectionException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="SQLTransientConnectionException"
+ type="java.sql.SQLTransientConnectionException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+<parameter name="vendorCode" type="int">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+</class>
+<class name="SQLTransientException"
+ extends="java.sql.SQLException"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="SQLTransientException"
+ type="java.sql.SQLTransientException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<constructor name="SQLTransientException"
+ type="java.sql.SQLTransientException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="SQLTransientException"
+ type="java.sql.SQLTransientException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="SQLTransientException"
+ type="java.sql.SQLTransientException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+<parameter name="vendorCode" type="int">
+</parameter>
+</constructor>
+<constructor name="SQLTransientException"
+ type="java.sql.SQLTransientException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="SQLTransientException"
+ type="java.sql.SQLTransientException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="SQLTransientException"
+ type="java.sql.SQLTransientException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="SQLTransientException"
+ type="java.sql.SQLTransientException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="sqlState" type="java.lang.String">
+</parameter>
+<parameter name="vendorCode" type="int">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+</class>
<class name="SQLWarning"
extends="java.sql.SQLException"
abstract="false"
@@ -291338,6 +300066,58 @@
<parameter name="theErrorCode" type="int">
</parameter>
</constructor>
+<constructor name="SQLWarning"
+ type="java.sql.SQLWarning"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="SQLWarning"
+ type="java.sql.SQLWarning"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="SQLWarning"
+ type="java.sql.SQLWarning"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="SQLState" type="java.lang.String">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="SQLWarning"
+ type="java.sql.SQLWarning"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reason" type="java.lang.String">
+</parameter>
+<parameter name="SQLState" type="java.lang.String">
+</parameter>
+<parameter name="vendorCode" type="int">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
<method name="getNextWarning"
return="java.sql.SQLWarning"
abstract="false"
@@ -291363,6 +300143,137 @@
</parameter>
</method>
</class>
+<interface name="SQLXML"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="free"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="getBinaryStream"
+ return="java.io.InputStream"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="getCharacterStream"
+ return="java.io.Reader"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="getSource"
+ return="T"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="sourceClass" type="java.lang.Class<T>">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="getString"
+ return="java.lang.String"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setBinaryStream"
+ return="java.io.OutputStream"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setCharacterStream"
+ return="java.io.Writer"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setResult"
+ return="T"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="resultClass" type="java.lang.Class<T>">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setString"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="java.lang.String">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+</interface>
<interface name="Savepoint"
abstract="true"
static="false"
@@ -291404,6 +300315,8 @@
deprecated="not deprecated"
visibility="public"
>
+<implements name="java.sql.Wrapper">
+</implements>
<method name="addBatch"
return="void"
abstract="true"
@@ -291828,6 +300741,32 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="isClosed"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="isPoolable"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="setCursorName"
return="void"
abstract="true"
@@ -291918,6 +300857,21 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="setPoolable"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="poolable" type="boolean">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="setQueryTimeout"
return="void"
abstract="true"
@@ -292426,6 +301380,17 @@
visibility="public"
>
</field>
+<field name="LONGNVARCHAR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-16"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="LONGVARBINARY"
type="int"
transient="false"
@@ -292448,6 +301413,28 @@
visibility="public"
>
</field>
+<field name="NCHAR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-15"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="NCLOB"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2011"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="NULL"
type="int"
transient="false"
@@ -292470,6 +301457,17 @@
visibility="public"
>
</field>
+<field name="NVARCHAR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-9"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="OTHER"
type="int"
transient="false"
@@ -292503,6 +301501,17 @@
visibility="public"
>
</field>
+<field name="ROWID"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-8"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="SMALLINT"
type="int"
transient="false"
@@ -292514,6 +301523,17 @@
visibility="public"
>
</field>
+<field name="SQLXML"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2009"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="STRUCT"
type="int"
transient="false"
@@ -292581,6 +301601,44 @@
>
</field>
</class>
+<interface name="Wrapper"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="isWrapperFor"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="iface" type="java.lang.Class<?>">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="unwrap"
+ return="T"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="iface" type="java.lang.Class<T>">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+</interface>
</package>
<package name="java.text"
>
@@ -293371,21 +302429,6 @@
<parameter name="where" type="java.util.Locale">
</parameter>
</method>
-<method name="getInt"
- return="int"
- abstract="false"
- native="false"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="protected"
->
-<parameter name="buf" type="byte[]">
-</parameter>
-<parameter name="offset" type="int">
-</parameter>
-</method>
<method name="getLineInstance"
return="java.text.BreakIterator"
abstract="false"
@@ -293410,21 +302453,6 @@
<parameter name="where" type="java.util.Locale">
</parameter>
</method>
-<method name="getLong"
- return="long"
- abstract="false"
- native="false"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="protected"
->
-<parameter name="buf" type="byte[]">
-</parameter>
-<parameter name="offset" type="int">
-</parameter>
-</method>
<method name="getSentenceInstance"
return="java.text.BreakIterator"
abstract="false"
@@ -293449,21 +302477,6 @@
<parameter name="where" type="java.util.Locale">
</parameter>
</method>
-<method name="getShort"
- return="short"
- abstract="false"
- native="false"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="protected"
->
-<parameter name="buf" type="byte[]">
-</parameter>
-<parameter name="offset" type="int">
-</parameter>
-</method>
<method name="getText"
return="java.text.CharacterIterator"
abstract="true"
@@ -294081,17 +303094,27 @@
</class>
<class name="CollationKey"
extends="java.lang.Object"
- abstract="false"
+ abstract="true"
static="false"
- final="true"
+ final="false"
deprecated="not deprecated"
visibility="public"
>
<implements name="java.lang.Comparable">
</implements>
+<constructor name="CollationKey"
+ type="java.text.CollationKey"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="source" type="java.lang.String">
+</parameter>
+</constructor>
<method name="compareTo"
return="int"
- abstract="false"
+ abstract="true"
native="false"
synchronized="false"
static="false"
@@ -294115,7 +303138,7 @@
</method>
<method name="toByteArray"
return="byte[]"
- abstract="false"
+ abstract="true"
native="false"
synchronized="false"
static="false"
@@ -295284,6 +304307,17 @@
visibility="public"
>
</method>
+<method name="getAvailableLocales"
+ return="java.util.Locale[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getEras"
return="java.lang.String[]"
abstract="false"
@@ -295295,6 +304329,30 @@
visibility="public"
>
</method>
+<method name="getInstance"
+ return="java.text.DateFormatSymbols"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getInstance"
+ return="java.text.DateFormatSymbols"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="locale" type="java.util.Locale">
+</parameter>
+</method>
<method name="getLocalPatternChars"
return="java.lang.String"
abstract="false"
@@ -295462,7 +304520,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="data" type="java.lang.String[][]">
+<parameter name="zoneStrings" type="java.lang.String[][]">
</parameter>
</method>
</class>
@@ -295839,7 +304897,7 @@
extends="java.lang.Object"
abstract="false"
static="false"
- final="true"
+ final="false"
deprecated="not deprecated"
visibility="public"
>
@@ -295876,6 +304934,17 @@
visibility="public"
>
</method>
+<method name="getAvailableLocales"
+ return="java.util.Locale[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getCurrency"
return="java.util.Currency"
abstract="false"
@@ -295920,6 +304989,17 @@
visibility="public"
>
</method>
+<method name="getExponentSeparator"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getGroupingSeparator"
return="char"
abstract="false"
@@ -295942,6 +305022,30 @@
visibility="public"
>
</method>
+<method name="getInstance"
+ return="java.text.DecimalFormatSymbols"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getInstance"
+ return="java.text.DecimalFormatSymbols"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="locale" type="java.util.Locale">
+</parameter>
+</method>
<method name="getInternationalCurrencySymbol"
return="java.lang.String"
abstract="false"
@@ -296082,6 +305186,19 @@
<parameter name="value" type="char">
</parameter>
</method>
+<method name="setExponentSeparator"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="java.lang.String">
+</parameter>
+</method>
<method name="setGroupingSeparator"
return="void"
abstract="false"
@@ -296341,7 +305458,7 @@
static="false"
final="false"
deprecated="not deprecated"
- visibility="public"
+ visibility="protected"
>
</constructor>
<method name="clone"
@@ -296535,9 +305652,9 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="template" type="java.lang.String">
+<parameter name="format" type="java.lang.String">
</parameter>
-<parameter name="objects" type="java.lang.Object...">
+<parameter name="args" type="java.lang.Object...">
</parameter>
</method>
<method name="getFormats"
@@ -296728,6 +305845,78 @@
>
</field>
</class>
+<class name="Normalizer"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="isNormalized"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="src" type="java.lang.CharSequence">
+</parameter>
+<parameter name="form" type="java.text.Normalizer.Form">
+</parameter>
+</method>
+<method name="normalize"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="src" type="java.lang.CharSequence">
+</parameter>
+<parameter name="form" type="java.text.Normalizer.Form">
+</parameter>
+</method>
+</class>
+<class name="Normalizer.Form"
+ extends="java.lang.Enum"
+ abstract="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="valueOf"
+ return="java.text.Normalizer.Form"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="name" type="java.lang.String">
+</parameter>
+</method>
+<method name="values"
+ return="java.text.Normalizer.Form[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
<class name="NumberFormat"
extends="java.text.Format"
abstract="true"
@@ -296741,7 +305930,7 @@
static="false"
final="false"
deprecated="not deprecated"
- visibility="public"
+ visibility="protected"
>
</constructor>
<method name="format"
@@ -297007,6 +306196,17 @@
<parameter name="locale" type="java.util.Locale">
</parameter>
</method>
+<method name="getRoundingMode"
+ return="java.math.RoundingMode"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="isGroupingUsed"
return="boolean"
abstract="false"
@@ -297165,6 +306365,19 @@
<parameter name="value" type="boolean">
</parameter>
</method>
+<method name="setRoundingMode"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="roundingMode" type="java.math.RoundingMode">
+</parameter>
+</method>
<field name="FRACTION_FIELD"
type="int"
transient="false"
@@ -298403,6 +307616,146 @@
>
</method>
</class>
+<class name="AbstractMap.SimpleEntry"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="java.util.Map.Entry">
+</implements>
+<implements name="java.io.Serializable">
+</implements>
+<constructor name="AbstractMap.SimpleEntry"
+ type="java.util.AbstractMap.SimpleEntry"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="theKey" type="K">
+</parameter>
+<parameter name="theValue" type="V">
+</parameter>
+</constructor>
+<constructor name="AbstractMap.SimpleEntry"
+ type="java.util.AbstractMap.SimpleEntry"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="copyFrom" type="java.util.Map.Entry<? extends K, ? extends V>">
+</parameter>
+</constructor>
+<method name="getKey"
+ return="K"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getValue"
+ return="V"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="setValue"
+ return="V"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="object" type="V">
+</parameter>
+</method>
+</class>
+<class name="AbstractMap.SimpleImmutableEntry"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="java.util.Map.Entry">
+</implements>
+<implements name="java.io.Serializable">
+</implements>
+<constructor name="AbstractMap.SimpleImmutableEntry"
+ type="java.util.AbstractMap.SimpleImmutableEntry"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="theKey" type="K">
+</parameter>
+<parameter name="theValue" type="V">
+</parameter>
+</constructor>
+<constructor name="AbstractMap.SimpleImmutableEntry"
+ type="java.util.AbstractMap.SimpleImmutableEntry"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="copyFrom" type="java.util.Map.Entry<? extends K, ? extends V>">
+</parameter>
+</constructor>
+<method name="getKey"
+ return="K"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getValue"
+ return="V"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="setValue"
+ return="V"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="object" type="V">
+</parameter>
+</method>
+</class>
<class name="AbstractQueue"
extends="java.util.AbstractCollection"
abstract="true"
@@ -298506,6 +307859,340 @@
>
</constructor>
</class>
+<class name="ArrayDeque"
+ extends="java.util.AbstractCollection"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="java.lang.Cloneable">
+</implements>
+<implements name="java.util.Deque">
+</implements>
+<implements name="java.io.Serializable">
+</implements>
+<constructor name="ArrayDeque"
+ type="java.util.ArrayDeque"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<constructor name="ArrayDeque"
+ type="java.util.ArrayDeque"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="minSize" type="int">
+</parameter>
+</constructor>
+<constructor name="ArrayDeque"
+ type="java.util.ArrayDeque"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="c" type="java.util.Collection<? extends E>">
+</parameter>
+</constructor>
+<method name="addFirst"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+</method>
+<method name="addLast"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+</method>
+<method name="clone"
+ return="java.util.ArrayDeque<E>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="descendingIterator"
+ return="java.util.Iterator<E>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="element"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getFirst"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getLast"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="iterator"
+ return="java.util.Iterator<E>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="offer"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+</method>
+<method name="offerFirst"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+</method>
+<method name="offerLast"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+</method>
+<method name="peek"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="peekFirst"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="peekLast"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="poll"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="pollFirst"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="pollLast"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="pop"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="push"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+</method>
+<method name="remove"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="removeFirst"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="removeFirstOccurrence"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="obj" type="java.lang.Object">
+</parameter>
+</method>
+<method name="removeLast"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="removeLastOccurrence"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="obj" type="java.lang.Object">
+</parameter>
+</method>
+<method name="size"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
<class name="ArrayList"
extends="java.util.AbstractList"
abstract="false"
@@ -298654,6 +308341,25 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="array" type="byte[]">
+</parameter>
+<parameter name="startIndex" type="int">
+</parameter>
+<parameter name="endIndex" type="int">
+</parameter>
+<parameter name="value" type="byte">
+</parameter>
+</method>
+<method name="binarySearch"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
<parameter name="array" type="char[]">
</parameter>
<parameter name="value" type="char">
@@ -298669,6 +308375,25 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="array" type="char[]">
+</parameter>
+<parameter name="startIndex" type="int">
+</parameter>
+<parameter name="endIndex" type="int">
+</parameter>
+<parameter name="value" type="char">
+</parameter>
+</method>
+<method name="binarySearch"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
<parameter name="array" type="double[]">
</parameter>
<parameter name="value" type="double">
@@ -298684,6 +308409,25 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="array" type="double[]">
+</parameter>
+<parameter name="startIndex" type="int">
+</parameter>
+<parameter name="endIndex" type="int">
+</parameter>
+<parameter name="value" type="double">
+</parameter>
+</method>
+<method name="binarySearch"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
<parameter name="array" type="float[]">
</parameter>
<parameter name="value" type="float">
@@ -298699,6 +308443,25 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="array" type="float[]">
+</parameter>
+<parameter name="startIndex" type="int">
+</parameter>
+<parameter name="endIndex" type="int">
+</parameter>
+<parameter name="value" type="float">
+</parameter>
+</method>
+<method name="binarySearch"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
<parameter name="array" type="int[]">
</parameter>
<parameter name="value" type="int">
@@ -298714,6 +308477,25 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="array" type="int[]">
+</parameter>
+<parameter name="startIndex" type="int">
+</parameter>
+<parameter name="endIndex" type="int">
+</parameter>
+<parameter name="value" type="int">
+</parameter>
+</method>
+<method name="binarySearch"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
<parameter name="array" type="long[]">
</parameter>
<parameter name="value" type="long">
@@ -298729,6 +308511,25 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="array" type="long[]">
+</parameter>
+<parameter name="startIndex" type="int">
+</parameter>
+<parameter name="endIndex" type="int">
+</parameter>
+<parameter name="value" type="long">
+</parameter>
+</method>
+<method name="binarySearch"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
<parameter name="array" type="java.lang.Object[]">
</parameter>
<parameter name="value" type="java.lang.Object">
@@ -298744,6 +308545,25 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="array" type="java.lang.Object[]">
+</parameter>
+<parameter name="startIndex" type="int">
+</parameter>
+<parameter name="endIndex" type="int">
+</parameter>
+<parameter name="value" type="java.lang.Object">
+</parameter>
+</method>
+<method name="binarySearch"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
<parameter name="array" type="T[]">
</parameter>
<parameter name="value" type="T">
@@ -298761,11 +308581,375 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="array" type="T[]">
+</parameter>
+<parameter name="startIndex" type="int">
+</parameter>
+<parameter name="endIndex" type="int">
+</parameter>
+<parameter name="value" type="T">
+</parameter>
+<parameter name="comparator" type="java.util.Comparator<? super T>">
+</parameter>
+</method>
+<method name="binarySearch"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
<parameter name="array" type="short[]">
</parameter>
<parameter name="value" type="short">
</parameter>
</method>
+<method name="binarySearch"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="array" type="short[]">
+</parameter>
+<parameter name="startIndex" type="int">
+</parameter>
+<parameter name="endIndex" type="int">
+</parameter>
+<parameter name="value" type="short">
+</parameter>
+</method>
+<method name="copyOf"
+ return="boolean[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="original" type="boolean[]">
+</parameter>
+<parameter name="newLength" type="int">
+</parameter>
+</method>
+<method name="copyOf"
+ return="byte[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="original" type="byte[]">
+</parameter>
+<parameter name="newLength" type="int">
+</parameter>
+</method>
+<method name="copyOf"
+ return="char[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="original" type="char[]">
+</parameter>
+<parameter name="newLength" type="int">
+</parameter>
+</method>
+<method name="copyOf"
+ return="double[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="original" type="double[]">
+</parameter>
+<parameter name="newLength" type="int">
+</parameter>
+</method>
+<method name="copyOf"
+ return="float[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="original" type="float[]">
+</parameter>
+<parameter name="newLength" type="int">
+</parameter>
+</method>
+<method name="copyOf"
+ return="int[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="original" type="int[]">
+</parameter>
+<parameter name="newLength" type="int">
+</parameter>
+</method>
+<method name="copyOf"
+ return="long[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="original" type="long[]">
+</parameter>
+<parameter name="newLength" type="int">
+</parameter>
+</method>
+<method name="copyOf"
+ return="short[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="original" type="short[]">
+</parameter>
+<parameter name="newLength" type="int">
+</parameter>
+</method>
+<method name="copyOf"
+ return="T[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="original" type="T[]">
+</parameter>
+<parameter name="newLength" type="int">
+</parameter>
+</method>
+<method name="copyOf"
+ return="T[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="original" type="U[]">
+</parameter>
+<parameter name="newLength" type="int">
+</parameter>
+<parameter name="newType" type="java.lang.Class<? extends T[]>">
+</parameter>
+</method>
+<method name="copyOfRange"
+ return="boolean[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="original" type="boolean[]">
+</parameter>
+<parameter name="start" type="int">
+</parameter>
+<parameter name="end" type="int">
+</parameter>
+</method>
+<method name="copyOfRange"
+ return="byte[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="original" type="byte[]">
+</parameter>
+<parameter name="start" type="int">
+</parameter>
+<parameter name="end" type="int">
+</parameter>
+</method>
+<method name="copyOfRange"
+ return="char[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="original" type="char[]">
+</parameter>
+<parameter name="start" type="int">
+</parameter>
+<parameter name="end" type="int">
+</parameter>
+</method>
+<method name="copyOfRange"
+ return="double[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="original" type="double[]">
+</parameter>
+<parameter name="start" type="int">
+</parameter>
+<parameter name="end" type="int">
+</parameter>
+</method>
+<method name="copyOfRange"
+ return="float[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="original" type="float[]">
+</parameter>
+<parameter name="start" type="int">
+</parameter>
+<parameter name="end" type="int">
+</parameter>
+</method>
+<method name="copyOfRange"
+ return="int[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="original" type="int[]">
+</parameter>
+<parameter name="start" type="int">
+</parameter>
+<parameter name="end" type="int">
+</parameter>
+</method>
+<method name="copyOfRange"
+ return="long[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="original" type="long[]">
+</parameter>
+<parameter name="start" type="int">
+</parameter>
+<parameter name="end" type="int">
+</parameter>
+</method>
+<method name="copyOfRange"
+ return="short[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="original" type="short[]">
+</parameter>
+<parameter name="start" type="int">
+</parameter>
+<parameter name="end" type="int">
+</parameter>
+</method>
+<method name="copyOfRange"
+ return="T[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="original" type="T[]">
+</parameter>
+<parameter name="start" type="int">
+</parameter>
+<parameter name="end" type="int">
+</parameter>
+</method>
+<method name="copyOfRange"
+ return="T[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="original" type="U[]">
+</parameter>
+<parameter name="start" type="int">
+</parameter>
+<parameter name="end" type="int">
+</parameter>
+<parameter name="newType" type="java.lang.Class<? extends T[]>">
+</parameter>
+</method>
<method name="deepEquals"
return="boolean"
abstract="false"
@@ -299845,7 +310029,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="pos" type="int">
+<parameter name="index" type="int">
</parameter>
</method>
<method name="clear"
@@ -299858,9 +310042,9 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="pos1" type="int">
+<parameter name="fromIndex" type="int">
</parameter>
-<parameter name="pos2" type="int">
+<parameter name="toIndex" type="int">
</parameter>
</method>
<method name="clone"
@@ -299884,7 +310068,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="pos" type="int">
+<parameter name="index" type="int">
</parameter>
</method>
<method name="flip"
@@ -299897,9 +310081,9 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="pos1" type="int">
+<parameter name="fromIndex" type="int">
</parameter>
-<parameter name="pos2" type="int">
+<parameter name="toIndex" type="int">
</parameter>
</method>
<method name="get"
@@ -299912,7 +310096,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="pos" type="int">
+<parameter name="index" type="int">
</parameter>
</method>
<method name="get"
@@ -299925,9 +310109,9 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="pos1" type="int">
+<parameter name="fromIndex" type="int">
</parameter>
-<parameter name="pos2" type="int">
+<parameter name="toIndex" type="int">
</parameter>
</method>
<method name="intersects"
@@ -299975,7 +310159,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="pos" type="int">
+<parameter name="index" type="int">
</parameter>
</method>
<method name="nextSetBit"
@@ -299988,7 +310172,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="pos" type="int">
+<parameter name="index" type="int">
</parameter>
</method>
<method name="or"
@@ -300014,7 +310198,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="pos" type="int">
+<parameter name="index" type="int">
</parameter>
</method>
<method name="set"
@@ -300027,7 +310211,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="pos" type="int">
+<parameter name="index" type="int">
</parameter>
<parameter name="val" type="boolean">
</parameter>
@@ -300042,9 +310226,9 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="pos1" type="int">
+<parameter name="fromIndex" type="int">
</parameter>
-<parameter name="pos2" type="int">
+<parameter name="toIndex" type="int">
</parameter>
</method>
<method name="set"
@@ -300057,9 +310241,9 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="pos1" type="int">
+<parameter name="fromIndex" type="int">
</parameter>
-<parameter name="pos2" type="int">
+<parameter name="toIndex" type="int">
</parameter>
<parameter name="val" type="boolean">
</parameter>
@@ -300295,6 +310479,40 @@
visibility="public"
>
</method>
+<method name="getDisplayName"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="field" type="int">
+</parameter>
+<parameter name="style" type="int">
+</parameter>
+<parameter name="locale" type="java.util.Locale">
+</parameter>
+</method>
+<method name="getDisplayNames"
+ return="java.util.Map<java.lang.String, java.lang.Integer>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="field" type="int">
+</parameter>
+<parameter name="style" type="int">
+</parameter>
+<parameter name="locale" type="java.util.Locale">
+</parameter>
+</method>
<method name="getFirstDayOfWeek"
return="int"
abstract="false"
@@ -300675,6 +310893,17 @@
<parameter name="timezone" type="java.util.TimeZone">
</parameter>
</method>
+<field name="ALL_STYLES"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="AM"
type="int"
transient="false"
@@ -300895,6 +311124,17 @@
visibility="public"
>
</field>
+<field name="LONG"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="MARCH"
type="int"
transient="false"
@@ -301027,6 +311267,17 @@
visibility="public"
>
</field>
+<field name="SHORT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="SUNDAY"
type="int"
transient="false"
@@ -301395,6 +311646,19 @@
<parameter name="a" type="T...">
</parameter>
</method>
+<method name="asLifoQueue"
+ return="java.util.Queue<T>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="deque" type="java.util.Deque<T>">
+</parameter>
+</method>
<method name="binarySearch"
return="int"
abstract="false"
@@ -301741,6 +312005,19 @@
<parameter name="object" type="T">
</parameter>
</method>
+<method name="newSetFromMap"
+ return="java.util.Set<E>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="map" type="java.util.Map<E, java.lang.Boolean>">
+</parameter>
+</method>
<method name="replaceAll"
return="boolean"
abstract="false"
@@ -302650,6 +312927,217 @@
>
</method>
</class>
+<interface name="Deque"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="java.util.Queue">
+</implements>
+<method name="addFirst"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+</method>
+<method name="addLast"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+</method>
+<method name="descendingIterator"
+ return="java.util.Iterator<E>"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getFirst"
+ return="E"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getLast"
+ return="E"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="offerFirst"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+</method>
+<method name="offerLast"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+</method>
+<method name="peekFirst"
+ return="E"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="peekLast"
+ return="E"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="pollFirst"
+ return="E"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="pollLast"
+ return="E"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="pop"
+ return="E"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="push"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+</method>
+<method name="removeFirst"
+ return="E"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="removeFirstOccurrence"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+<method name="removeLast"
+ return="E"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="removeLastOccurrence"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+</interface>
<class name="Dictionary"
extends="java.lang.Object"
abstract="true"
@@ -304802,6 +315290,8 @@
>
<implements name="java.lang.Cloneable">
</implements>
+<implements name="java.util.Deque">
+</implements>
<implements name="java.util.List">
</implements>
<implements name="java.util.Queue">
@@ -304863,6 +315353,17 @@
visibility="public"
>
</method>
+<method name="descendingIterator"
+ return="java.util.Iterator<E>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="element"
return="E"
abstract="false"
@@ -304922,6 +315423,32 @@
<parameter name="o" type="E">
</parameter>
</method>
+<method name="offerFirst"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+</method>
+<method name="offerLast"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+</method>
<method name="peek"
return="E"
abstract="false"
@@ -304933,6 +315460,28 @@
visibility="public"
>
</method>
+<method name="peekFirst"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="peekLast"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="poll"
return="E"
abstract="false"
@@ -304944,6 +315493,52 @@
visibility="public"
>
</method>
+<method name="pollFirst"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="pollLast"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="pop"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="push"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+</method>
<method name="remove"
return="E"
abstract="false"
@@ -304966,6 +315561,19 @@
visibility="public"
>
</method>
+<method name="removeFirstOccurrence"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
<method name="removeLast"
return="E"
abstract="false"
@@ -304977,6 +315585,19 @@
visibility="public"
>
</method>
+<method name="removeLastOccurrence"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
<method name="size"
return="int"
abstract="false"
@@ -305925,6 +316546,16 @@
visibility="public"
>
</field>
+<field name="ROOT"
+ type="java.util.Locale"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="SIMPLIFIED_CHINESE"
type="java.util.Locale"
transient="false"
@@ -306326,6 +316957,401 @@
>
</method>
</class>
+<interface name="NavigableMap"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="java.util.SortedMap">
+</implements>
+<method name="ceilingEntry"
+ return="java.util.Map.Entry<K, V>"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="K">
+</parameter>
+</method>
+<method name="ceilingKey"
+ return="K"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="K">
+</parameter>
+</method>
+<method name="descendingKeySet"
+ return="java.util.NavigableSet<K>"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="descendingMap"
+ return="java.util.NavigableMap<K, V>"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="firstEntry"
+ return="java.util.Map.Entry<K, V>"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="floorEntry"
+ return="java.util.Map.Entry<K, V>"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="K">
+</parameter>
+</method>
+<method name="floorKey"
+ return="K"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="K">
+</parameter>
+</method>
+<method name="headMap"
+ return="java.util.NavigableMap<K, V>"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="endKey" type="K">
+</parameter>
+<parameter name="inclusive" type="boolean">
+</parameter>
+</method>
+<method name="higherEntry"
+ return="java.util.Map.Entry<K, V>"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="K">
+</parameter>
+</method>
+<method name="higherKey"
+ return="K"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="K">
+</parameter>
+</method>
+<method name="lastEntry"
+ return="java.util.Map.Entry<K, V>"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="lowerEntry"
+ return="java.util.Map.Entry<K, V>"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="K">
+</parameter>
+</method>
+<method name="lowerKey"
+ return="K"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="K">
+</parameter>
+</method>
+<method name="navigableKeySet"
+ return="java.util.NavigableSet<K>"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="pollFirstEntry"
+ return="java.util.Map.Entry<K, V>"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="pollLastEntry"
+ return="java.util.Map.Entry<K, V>"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="subMap"
+ return="java.util.NavigableMap<K, V>"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="startKey" type="K">
+</parameter>
+<parameter name="startInclusive" type="boolean">
+</parameter>
+<parameter name="endKey" type="K">
+</parameter>
+<parameter name="endInclusive" type="boolean">
+</parameter>
+</method>
+<method name="tailMap"
+ return="java.util.NavigableMap<K, V>"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="startKey" type="K">
+</parameter>
+<parameter name="inclusive" type="boolean">
+</parameter>
+</method>
+</interface>
+<interface name="NavigableSet"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="java.util.SortedSet">
+</implements>
+<method name="ceiling"
+ return="E"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+</method>
+<method name="descendingIterator"
+ return="java.util.Iterator<E>"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="descendingSet"
+ return="java.util.NavigableSet<E>"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="floor"
+ return="E"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+</method>
+<method name="headSet"
+ return="java.util.NavigableSet<E>"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="end" type="E">
+</parameter>
+<parameter name="endInclusive" type="boolean">
+</parameter>
+</method>
+<method name="higher"
+ return="E"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+</method>
+<method name="lower"
+ return="E"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+</method>
+<method name="pollFirst"
+ return="E"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="pollLast"
+ return="E"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="subSet"
+ return="java.util.NavigableSet<E>"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="start" type="E">
+</parameter>
+<parameter name="startInclusive" type="boolean">
+</parameter>
+<parameter name="end" type="E">
+</parameter>
+<parameter name="endInclusive" type="boolean">
+</parameter>
+</method>
+<method name="tailSet"
+ return="java.util.NavigableSet<E>"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="start" type="E">
+</parameter>
+<parameter name="startInclusive" type="boolean">
+</parameter>
+</method>
+</interface>
<class name="NoSuchElementException"
extends="java.lang.RuntimeException"
abstract="false"
@@ -306732,6 +317758,21 @@
<exception name="IOException" type="java.io.IOException">
</exception>
</method>
+<method name="load"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="in" type="java.io.Reader">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
<method name="loadFromXML"
return="void"
abstract="false"
@@ -306807,6 +317848,23 @@
<exception name="IOException" type="java.io.IOException">
</exception>
</method>
+<method name="store"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="writer" type="java.io.Writer">
+</parameter>
+<parameter name="comment" type="java.lang.String">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
<method name="storeToXML"
return="void"
abstract="false"
@@ -306843,6 +317901,17 @@
<exception name="IOException" type="java.io.IOException">
</exception>
</method>
+<method name="stringPropertyNames"
+ return="java.util.Set<java.lang.String>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<field name="defaults"
type="java.util.Properties"
transient="false"
@@ -306895,6 +317964,18 @@
<exception name="IOException" type="java.io.IOException">
</exception>
</constructor>
+<constructor name="PropertyResourceBundle"
+ type="java.util.PropertyResourceBundle"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reader" type="java.io.Reader">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</constructor>
<method name="getKeys"
return="java.util.Enumeration<java.lang.String>"
abstract="false"
@@ -307158,6 +318239,43 @@
visibility="public"
>
</constructor>
+<method name="clearCache"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="clearCache"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="loader" type="java.lang.ClassLoader">
+</parameter>
+</method>
+<method name="containsKey"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="java.lang.String">
+</parameter>
+</method>
<method name="getBundle"
return="java.util.ResourceBundle"
abstract="false"
@@ -307207,6 +318325,57 @@
<exception name="MissingResourceException" type="java.util.MissingResourceException">
</exception>
</method>
+<method name="getBundle"
+ return="java.util.ResourceBundle"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="baseName" type="java.lang.String">
+</parameter>
+<parameter name="control" type="java.util.ResourceBundle.Control">
+</parameter>
+</method>
+<method name="getBundle"
+ return="java.util.ResourceBundle"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="baseName" type="java.lang.String">
+</parameter>
+<parameter name="targetLocale" type="java.util.Locale">
+</parameter>
+<parameter name="control" type="java.util.ResourceBundle.Control">
+</parameter>
+</method>
+<method name="getBundle"
+ return="java.util.ResourceBundle"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="baseName" type="java.lang.String">
+</parameter>
+<parameter name="targetLocale" type="java.util.Locale">
+</parameter>
+<parameter name="loader" type="java.lang.ClassLoader">
+</parameter>
+<parameter name="control" type="java.util.ResourceBundle.Control">
+</parameter>
+</method>
<method name="getKeys"
return="java.util.Enumeration<java.lang.String>"
abstract="true"
@@ -307281,6 +318450,28 @@
<parameter name="key" type="java.lang.String">
</parameter>
</method>
+<method name="handleKeySet"
+ return="java.util.Set<java.lang.String>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</method>
+<method name="keySet"
+ return="java.util.Set<java.lang.String>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="setParent"
return="void"
abstract="false"
@@ -307305,6 +318496,239 @@
>
</field>
</class>
+<class name="ResourceBundle.Control"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="ResourceBundle.Control"
+ type="java.util.ResourceBundle.Control"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</constructor>
+<method name="getCandidateLocales"
+ return="java.util.List<java.util.Locale>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="baseName" type="java.lang.String">
+</parameter>
+<parameter name="locale" type="java.util.Locale">
+</parameter>
+</method>
+<method name="getControl"
+ return="java.util.ResourceBundle.Control"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="formats" type="java.util.List<java.lang.String>">
+</parameter>
+</method>
+<method name="getFallbackLocale"
+ return="java.util.Locale"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="baseName" type="java.lang.String">
+</parameter>
+<parameter name="locale" type="java.util.Locale">
+</parameter>
+</method>
+<method name="getFormats"
+ return="java.util.List<java.lang.String>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="baseName" type="java.lang.String">
+</parameter>
+</method>
+<method name="getNoFallbackControl"
+ return="java.util.ResourceBundle.Control"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="formats" type="java.util.List<java.lang.String>">
+</parameter>
+</method>
+<method name="getTimeToLive"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="baseName" type="java.lang.String">
+</parameter>
+<parameter name="locale" type="java.util.Locale">
+</parameter>
+</method>
+<method name="needsReload"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="baseName" type="java.lang.String">
+</parameter>
+<parameter name="locale" type="java.util.Locale">
+</parameter>
+<parameter name="format" type="java.lang.String">
+</parameter>
+<parameter name="loader" type="java.lang.ClassLoader">
+</parameter>
+<parameter name="bundle" type="java.util.ResourceBundle">
+</parameter>
+<parameter name="loadTime" type="long">
+</parameter>
+</method>
+<method name="newBundle"
+ return="java.util.ResourceBundle"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="baseName" type="java.lang.String">
+</parameter>
+<parameter name="locale" type="java.util.Locale">
+</parameter>
+<parameter name="format" type="java.lang.String">
+</parameter>
+<parameter name="loader" type="java.lang.ClassLoader">
+</parameter>
+<parameter name="reload" type="boolean">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+<exception name="IllegalAccessException" type="java.lang.IllegalAccessException">
+</exception>
+<exception name="InstantiationException" type="java.lang.InstantiationException">
+</exception>
+</method>
+<method name="toBundleName"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="baseName" type="java.lang.String">
+</parameter>
+<parameter name="locale" type="java.util.Locale">
+</parameter>
+</method>
+<method name="toResourceName"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="bundleName" type="java.lang.String">
+</parameter>
+<parameter name="suffix" type="java.lang.String">
+</parameter>
+</method>
+<field name="FORMAT_CLASS"
+ type="java.util.List"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_DEFAULT"
+ type="java.util.List"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_PROPERTIES"
+ type="java.util.List"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TTL_DONT_CACHE"
+ type="long"
+ transient="false"
+ volatile="false"
+ value="-1L"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TTL_NO_EXPIRATION_CONTROL"
+ type="long"
+ transient="false"
+ volatile="false"
+ value="-2L"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
<class name="Scanner"
extends="java.lang.Object"
abstract="false"
@@ -307962,6 +319386,17 @@
visibility="public"
>
</method>
+<method name="reset"
+ return="java.util.Scanner"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="skip"
return="java.util.Scanner"
abstract="false"
@@ -308041,6 +319476,111 @@
</parameter>
</method>
</class>
+<class name="ServiceConfigurationError"
+ extends="java.lang.Error"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="ServiceConfigurationError"
+ type="java.util.ServiceConfigurationError"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="message" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="ServiceConfigurationError"
+ type="java.util.ServiceConfigurationError"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="message" type="java.lang.String">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+</class>
+<class name="ServiceLoader"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="java.lang.Iterable">
+</implements>
+<method name="iterator"
+ return="java.util.Iterator<S>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="load"
+ return="java.util.ServiceLoader<S>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="service" type="java.lang.Class<S>">
+</parameter>
+<parameter name="classLoader" type="java.lang.ClassLoader">
+</parameter>
+</method>
+<method name="load"
+ return="java.util.ServiceLoader<S>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="service" type="java.lang.Class<S>">
+</parameter>
+</method>
+<method name="loadInstalled"
+ return="java.util.ServiceLoader<S>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="service" type="java.lang.Class<S>">
+</parameter>
+</method>
+<method name="reload"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
<interface name="Set"
abstract="true"
static="false"
@@ -309002,7 +320542,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="offset" type="int">
+<parameter name="offsetMillis" type="int">
</parameter>
</method>
<method name="getDSTSavings"
@@ -309127,7 +320667,7 @@
</parameter>
<parameter name="dayOfWeek" type="int">
</parameter>
-<parameter name="time" type="int">
+<parameter name="timeOfDayMillis" type="int">
</parameter>
</method>
<method name="getRawOffset"
@@ -309151,7 +320691,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="name" type="java.lang.String">
+<parameter name="id" type="java.lang.String">
</parameter>
</method>
<method name="hasSameRules"
@@ -309164,7 +320704,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="zone" type="java.util.TimeZone">
+<parameter name="timeZone" type="java.util.TimeZone">
</parameter>
</method>
<method name="inDaylightTime"
@@ -309190,7 +320730,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="timezone" type="java.util.TimeZone">
+<parameter name="timeZone" type="java.util.TimeZone">
</parameter>
</method>
<method name="setID"
@@ -309203,7 +320743,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="name" type="java.lang.String">
+<parameter name="id" type="java.lang.String">
</parameter>
</method>
<method name="setRawOffset"
@@ -309216,7 +320756,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="offset" type="int">
+<parameter name="offsetMillis" type="int">
</parameter>
</method>
<method name="useDaylightTime"
@@ -309511,6 +321051,8 @@
>
<implements name="java.lang.Cloneable">
</implements>
+<implements name="java.util.NavigableMap">
+</implements>
<implements name="java.io.Serializable">
</implements>
<implements name="java.util.SortedMap">
@@ -309530,6 +321072,16 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="copyFrom" type="java.util.Map<? extends K, ? extends V>">
+</parameter>
+</constructor>
+<constructor name="TreeMap"
+ type="java.util.TreeMap"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
<parameter name="comparator" type="java.util.Comparator<? super K>">
</parameter>
</constructor>
@@ -309540,19 +321092,35 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="map" type="java.util.Map<? extends K, ? extends V>">
+<parameter name="copyFrom" type="java.util.SortedMap<K, ? extends V>">
</parameter>
</constructor>
-<constructor name="TreeMap"
- type="java.util.TreeMap"
+<method name="ceilingEntry"
+ return="java.util.Map.Entry<K, V>"
+ abstract="false"
+ native="false"
+ synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
-<parameter name="map" type="java.util.SortedMap<K, ? extends V>">
+<parameter name="key" type="K">
</parameter>
-</constructor>
+</method>
+<method name="ceilingKey"
+ return="K"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="K">
+</parameter>
+</method>
<method name="clone"
return="java.lang.Object"
abstract="false"
@@ -309575,6 +321143,28 @@
visibility="public"
>
</method>
+<method name="descendingKeySet"
+ return="java.util.NavigableSet<K>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="descendingMap"
+ return="java.util.NavigableMap<K, V>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="entrySet"
return="java.util.Set<java.util.Map.Entry<K, V>>"
abstract="false"
@@ -309586,6 +321176,17 @@
visibility="public"
>
</method>
+<method name="firstEntry"
+ return="java.util.Map.Entry<K, V>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="firstKey"
return="K"
abstract="false"
@@ -309597,6 +321198,47 @@
visibility="public"
>
</method>
+<method name="floorEntry"
+ return="java.util.Map.Entry<K, V>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="K">
+</parameter>
+</method>
+<method name="floorKey"
+ return="K"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="K">
+</parameter>
+</method>
+<method name="headMap"
+ return="java.util.NavigableMap<K, V>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="to" type="K">
+</parameter>
+<parameter name="inclusive" type="boolean">
+</parameter>
+</method>
<method name="headMap"
return="java.util.SortedMap<K, V>"
abstract="false"
@@ -309607,9 +321249,46 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="endKey" type="K">
+<parameter name="toExclusive" type="K">
</parameter>
</method>
+<method name="higherEntry"
+ return="java.util.Map.Entry<K, V>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="K">
+</parameter>
+</method>
+<method name="higherKey"
+ return="K"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="K">
+</parameter>
+</method>
+<method name="lastEntry"
+ return="java.util.Map.Entry<K, V>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="lastKey"
return="K"
abstract="false"
@@ -309621,6 +321300,84 @@
visibility="public"
>
</method>
+<method name="lowerEntry"
+ return="java.util.Map.Entry<K, V>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="K">
+</parameter>
+</method>
+<method name="lowerKey"
+ return="K"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="K">
+</parameter>
+</method>
+<method name="navigableKeySet"
+ return="java.util.NavigableSet<K>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="pollFirstEntry"
+ return="java.util.Map.Entry<K, V>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="pollLastEntry"
+ return="java.util.Map.Entry<K, V>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="subMap"
+ return="java.util.NavigableMap<K, V>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="from" type="K">
+</parameter>
+<parameter name="fromInclusive" type="boolean">
+</parameter>
+<parameter name="to" type="K">
+</parameter>
+<parameter name="toInclusive" type="boolean">
+</parameter>
+</method>
<method name="subMap"
return="java.util.SortedMap<K, V>"
abstract="false"
@@ -309631,9 +321388,24 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="startKey" type="K">
+<parameter name="fromInclusive" type="K">
</parameter>
-<parameter name="endKey" type="K">
+<parameter name="toExclusive" type="K">
+</parameter>
+</method>
+<method name="tailMap"
+ return="java.util.NavigableMap<K, V>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="from" type="K">
+</parameter>
+<parameter name="inclusive" type="boolean">
</parameter>
</method>
<method name="tailMap"
@@ -309646,7 +321418,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="startKey" type="K">
+<parameter name="fromInclusive" type="K">
</parameter>
</method>
</class>
@@ -309660,9 +321432,9 @@
>
<implements name="java.lang.Cloneable">
</implements>
-<implements name="java.io.Serializable">
+<implements name="java.util.NavigableSet">
</implements>
-<implements name="java.util.SortedSet">
+<implements name="java.io.Serializable">
</implements>
<constructor name="TreeSet"
type="java.util.TreeSet"
@@ -309702,6 +321474,19 @@
<parameter name="set" type="java.util.SortedSet<E>">
</parameter>
</constructor>
+<method name="ceiling"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+</method>
<method name="clone"
return="java.lang.Object"
abstract="false"
@@ -309724,6 +321509,28 @@
visibility="public"
>
</method>
+<method name="descendingIterator"
+ return="java.util.Iterator<E>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="descendingSet"
+ return="java.util.NavigableSet<E>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="first"
return="E"
abstract="false"
@@ -309735,6 +321542,34 @@
visibility="public"
>
</method>
+<method name="floor"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+</method>
+<method name="headSet"
+ return="java.util.NavigableSet<E>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="end" type="E">
+</parameter>
+<parameter name="endInclusive" type="boolean">
+</parameter>
+</method>
<method name="headSet"
return="java.util.SortedSet<E>"
abstract="false"
@@ -309748,6 +321583,19 @@
<parameter name="end" type="E">
</parameter>
</method>
+<method name="higher"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+</method>
<method name="iterator"
return="java.util.Iterator<E>"
abstract="false"
@@ -309770,6 +321618,41 @@
visibility="public"
>
</method>
+<method name="lower"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+</method>
+<method name="pollFirst"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="pollLast"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="size"
return="int"
abstract="false"
@@ -309782,6 +321665,25 @@
>
</method>
<method name="subSet"
+ return="java.util.NavigableSet<E>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="start" type="E">
+</parameter>
+<parameter name="startInclusive" type="boolean">
+</parameter>
+<parameter name="end" type="E">
+</parameter>
+<parameter name="endInclusive" type="boolean">
+</parameter>
+</method>
+<method name="subSet"
return="java.util.SortedSet<E>"
abstract="false"
native="false"
@@ -309797,6 +321699,21 @@
</parameter>
</method>
<method name="tailSet"
+ return="java.util.NavigableSet<E>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="start" type="E">
+</parameter>
+<parameter name="startInclusive" type="boolean">
+</parameter>
+</method>
+<method name="tailSet"
return="java.util.SortedSet<E>"
abstract="false"
native="false"
@@ -310455,7 +322372,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="tasks" type="java.util.Collection<java.util.concurrent.Callable<T>>">
+<parameter name="tasks" type="java.util.Collection<? extends java.util.concurrent.Callable<T>>">
</parameter>
<exception name="InterruptedException" type="java.lang.InterruptedException">
</exception>
@@ -310470,7 +322387,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="tasks" type="java.util.Collection<java.util.concurrent.Callable<T>>">
+<parameter name="tasks" type="java.util.Collection<? extends java.util.concurrent.Callable<T>>">
</parameter>
<parameter name="timeout" type="long">
</parameter>
@@ -310489,7 +322406,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="tasks" type="java.util.Collection<java.util.concurrent.Callable<T>>">
+<parameter name="tasks" type="java.util.Collection<? extends java.util.concurrent.Callable<T>>">
</parameter>
<exception name="ExecutionException" type="java.util.concurrent.ExecutionException">
</exception>
@@ -310506,7 +322423,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="tasks" type="java.util.Collection<java.util.concurrent.Callable<T>>">
+<parameter name="tasks" type="java.util.Collection<? extends java.util.concurrent.Callable<T>>">
</parameter>
<parameter name="timeout" type="long">
</parameter>
@@ -310519,6 +322436,34 @@
<exception name="TimeoutException" type="java.util.concurrent.TimeoutException">
</exception>
</method>
+<method name="newTaskFor"
+ return="java.util.concurrent.RunnableFuture<T>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="runnable" type="java.lang.Runnable">
+</parameter>
+<parameter name="value" type="T">
+</parameter>
+</method>
+<method name="newTaskFor"
+ return="java.util.concurrent.RunnableFuture<T>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="callable" type="java.util.concurrent.Callable<T>">
+</parameter>
+</method>
<method name="submit"
return="java.util.concurrent.Future<?>"
abstract="false"
@@ -310770,6 +322715,419 @@
</exception>
</method>
</class>
+<interface name="BlockingDeque"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="java.util.concurrent.BlockingQueue">
+</implements>
+<implements name="java.util.Deque">
+</implements>
+<method name="add"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+</method>
+<method name="addFirst"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+</method>
+<method name="addLast"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+</method>
+<method name="contains"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+<method name="element"
+ return="E"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="iterator"
+ return="java.util.Iterator<E>"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="offer"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+</method>
+<method name="offer"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+<parameter name="timeout" type="long">
+</parameter>
+<parameter name="unit" type="java.util.concurrent.TimeUnit">
+</parameter>
+<exception name="InterruptedException" type="java.lang.InterruptedException">
+</exception>
+</method>
+<method name="offerFirst"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+</method>
+<method name="offerFirst"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+<parameter name="timeout" type="long">
+</parameter>
+<parameter name="unit" type="java.util.concurrent.TimeUnit">
+</parameter>
+<exception name="InterruptedException" type="java.lang.InterruptedException">
+</exception>
+</method>
+<method name="offerLast"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+</method>
+<method name="offerLast"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+<parameter name="timeout" type="long">
+</parameter>
+<parameter name="unit" type="java.util.concurrent.TimeUnit">
+</parameter>
+<exception name="InterruptedException" type="java.lang.InterruptedException">
+</exception>
+</method>
+<method name="peek"
+ return="E"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="poll"
+ return="E"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="poll"
+ return="E"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="timeout" type="long">
+</parameter>
+<parameter name="unit" type="java.util.concurrent.TimeUnit">
+</parameter>
+<exception name="InterruptedException" type="java.lang.InterruptedException">
+</exception>
+</method>
+<method name="pollFirst"
+ return="E"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="timeout" type="long">
+</parameter>
+<parameter name="unit" type="java.util.concurrent.TimeUnit">
+</parameter>
+<exception name="InterruptedException" type="java.lang.InterruptedException">
+</exception>
+</method>
+<method name="pollLast"
+ return="E"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="timeout" type="long">
+</parameter>
+<parameter name="unit" type="java.util.concurrent.TimeUnit">
+</parameter>
+<exception name="InterruptedException" type="java.lang.InterruptedException">
+</exception>
+</method>
+<method name="push"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+</method>
+<method name="put"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+<exception name="InterruptedException" type="java.lang.InterruptedException">
+</exception>
+</method>
+<method name="putFirst"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+<exception name="InterruptedException" type="java.lang.InterruptedException">
+</exception>
+</method>
+<method name="putLast"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+<exception name="InterruptedException" type="java.lang.InterruptedException">
+</exception>
+</method>
+<method name="remove"
+ return="E"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="remove"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+<method name="removeFirstOccurrence"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+<method name="removeLastOccurrence"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+<method name="size"
+ return="int"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="take"
+ return="E"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="InterruptedException" type="java.lang.InterruptedException">
+</exception>
+</method>
+<method name="takeFirst"
+ return="E"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="InterruptedException" type="java.lang.InterruptedException">
+</exception>
+</method>
+<method name="takeLast"
+ return="E"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="InterruptedException" type="java.lang.InterruptedException">
+</exception>
+</method>
+</interface>
<interface name="BlockingQueue"
abstract="true"
static="false"
@@ -311122,6 +323480,18 @@
>
<parameter name="initialCapacity" type="int">
</parameter>
+<parameter name="loadFactor" type="float">
+</parameter>
+</constructor>
+<constructor name="ConcurrentHashMap"
+ type="java.util.concurrent.ConcurrentHashMap"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="initialCapacity" type="int">
+</parameter>
</constructor>
<constructor name="ConcurrentHashMap"
type="java.util.concurrent.ConcurrentHashMap"
@@ -311410,6 +323780,898 @@
</parameter>
</method>
</interface>
+<interface name="ConcurrentNavigableMap"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="java.util.concurrent.ConcurrentMap">
+</implements>
+<implements name="java.util.NavigableMap">
+</implements>
+<method name="descendingKeySet"
+ return="java.util.NavigableSet<K>"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="descendingMap"
+ return="java.util.concurrent.ConcurrentNavigableMap<K, V>"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="headMap"
+ return="java.util.concurrent.ConcurrentNavigableMap<K, V>"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="toKey" type="K">
+</parameter>
+<parameter name="inclusive" type="boolean">
+</parameter>
+</method>
+<method name="headMap"
+ return="java.util.concurrent.ConcurrentNavigableMap<K, V>"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="toKey" type="K">
+</parameter>
+</method>
+<method name="keySet"
+ return="java.util.NavigableSet<K>"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="navigableKeySet"
+ return="java.util.NavigableSet<K>"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="subMap"
+ return="java.util.concurrent.ConcurrentNavigableMap<K, V>"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fromKey" type="K">
+</parameter>
+<parameter name="fromInclusive" type="boolean">
+</parameter>
+<parameter name="toKey" type="K">
+</parameter>
+<parameter name="toInclusive" type="boolean">
+</parameter>
+</method>
+<method name="subMap"
+ return="java.util.concurrent.ConcurrentNavigableMap<K, V>"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fromKey" type="K">
+</parameter>
+<parameter name="toKey" type="K">
+</parameter>
+</method>
+<method name="tailMap"
+ return="java.util.concurrent.ConcurrentNavigableMap<K, V>"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fromKey" type="K">
+</parameter>
+<parameter name="inclusive" type="boolean">
+</parameter>
+</method>
+<method name="tailMap"
+ return="java.util.concurrent.ConcurrentNavigableMap<K, V>"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fromKey" type="K">
+</parameter>
+</method>
+</interface>
+<class name="ConcurrentSkipListMap"
+ extends="java.util.AbstractMap"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="java.lang.Cloneable">
+</implements>
+<implements name="java.util.concurrent.ConcurrentNavigableMap">
+</implements>
+<implements name="java.io.Serializable">
+</implements>
+<constructor name="ConcurrentSkipListMap"
+ type="java.util.concurrent.ConcurrentSkipListMap"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<constructor name="ConcurrentSkipListMap"
+ type="java.util.concurrent.ConcurrentSkipListMap"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="comparator" type="java.util.Comparator<? super K>">
+</parameter>
+</constructor>
+<constructor name="ConcurrentSkipListMap"
+ type="java.util.concurrent.ConcurrentSkipListMap"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="m" type="java.util.Map<? extends K, ? extends V>">
+</parameter>
+</constructor>
+<constructor name="ConcurrentSkipListMap"
+ type="java.util.concurrent.ConcurrentSkipListMap"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="m" type="java.util.SortedMap<K, ? extends V>">
+</parameter>
+</constructor>
+<method name="ceilingEntry"
+ return="java.util.Map.Entry<K, V>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="K">
+</parameter>
+</method>
+<method name="ceilingKey"
+ return="K"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="K">
+</parameter>
+</method>
+<method name="clone"
+ return="java.util.concurrent.ConcurrentSkipListMap<K, V>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="comparator"
+ return="java.util.Comparator<? super K>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="descendingKeySet"
+ return="java.util.NavigableSet<K>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="descendingMap"
+ return="java.util.concurrent.ConcurrentNavigableMap<K, V>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="entrySet"
+ return="java.util.Set<java.util.Map.Entry<K, V>>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="firstEntry"
+ return="java.util.Map.Entry<K, V>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="firstKey"
+ return="K"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="floorEntry"
+ return="java.util.Map.Entry<K, V>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="K">
+</parameter>
+</method>
+<method name="floorKey"
+ return="K"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="K">
+</parameter>
+</method>
+<method name="headMap"
+ return="java.util.concurrent.ConcurrentNavigableMap<K, V>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="toKey" type="K">
+</parameter>
+<parameter name="inclusive" type="boolean">
+</parameter>
+</method>
+<method name="headMap"
+ return="java.util.concurrent.ConcurrentNavigableMap<K, V>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="toKey" type="K">
+</parameter>
+</method>
+<method name="higherEntry"
+ return="java.util.Map.Entry<K, V>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="K">
+</parameter>
+</method>
+<method name="higherKey"
+ return="K"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="K">
+</parameter>
+</method>
+<method name="lastEntry"
+ return="java.util.Map.Entry<K, V>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="lastKey"
+ return="K"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="lowerEntry"
+ return="java.util.Map.Entry<K, V>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="K">
+</parameter>
+</method>
+<method name="lowerKey"
+ return="K"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="K">
+</parameter>
+</method>
+<method name="navigableKeySet"
+ return="java.util.NavigableSet<K>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="pollFirstEntry"
+ return="java.util.Map.Entry<K, V>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="pollLastEntry"
+ return="java.util.Map.Entry<K, V>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="putIfAbsent"
+ return="V"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="K">
+</parameter>
+<parameter name="value" type="V">
+</parameter>
+</method>
+<method name="remove"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="java.lang.Object">
+</parameter>
+<parameter name="value" type="java.lang.Object">
+</parameter>
+</method>
+<method name="replace"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="K">
+</parameter>
+<parameter name="oldValue" type="V">
+</parameter>
+<parameter name="newValue" type="V">
+</parameter>
+</method>
+<method name="replace"
+ return="V"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="K">
+</parameter>
+<parameter name="value" type="V">
+</parameter>
+</method>
+<method name="subMap"
+ return="java.util.concurrent.ConcurrentNavigableMap<K, V>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fromKey" type="K">
+</parameter>
+<parameter name="fromInclusive" type="boolean">
+</parameter>
+<parameter name="toKey" type="K">
+</parameter>
+<parameter name="toInclusive" type="boolean">
+</parameter>
+</method>
+<method name="subMap"
+ return="java.util.concurrent.ConcurrentNavigableMap<K, V>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fromKey" type="K">
+</parameter>
+<parameter name="toKey" type="K">
+</parameter>
+</method>
+<method name="tailMap"
+ return="java.util.concurrent.ConcurrentNavigableMap<K, V>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fromKey" type="K">
+</parameter>
+<parameter name="inclusive" type="boolean">
+</parameter>
+</method>
+<method name="tailMap"
+ return="java.util.concurrent.ConcurrentNavigableMap<K, V>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fromKey" type="K">
+</parameter>
+</method>
+</class>
+<class name="ConcurrentSkipListSet"
+ extends="java.util.AbstractSet"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="java.lang.Cloneable">
+</implements>
+<implements name="java.util.NavigableSet">
+</implements>
+<implements name="java.io.Serializable">
+</implements>
+<constructor name="ConcurrentSkipListSet"
+ type="java.util.concurrent.ConcurrentSkipListSet"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<constructor name="ConcurrentSkipListSet"
+ type="java.util.concurrent.ConcurrentSkipListSet"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="comparator" type="java.util.Comparator<? super E>">
+</parameter>
+</constructor>
+<constructor name="ConcurrentSkipListSet"
+ type="java.util.concurrent.ConcurrentSkipListSet"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="c" type="java.util.Collection<? extends E>">
+</parameter>
+</constructor>
+<constructor name="ConcurrentSkipListSet"
+ type="java.util.concurrent.ConcurrentSkipListSet"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="s" type="java.util.SortedSet<E>">
+</parameter>
+</constructor>
+<method name="ceiling"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+</method>
+<method name="clone"
+ return="java.util.concurrent.ConcurrentSkipListSet<E>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="comparator"
+ return="java.util.Comparator<? super E>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="descendingIterator"
+ return="java.util.Iterator<E>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="descendingSet"
+ return="java.util.NavigableSet<E>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="first"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="floor"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+</method>
+<method name="headSet"
+ return="java.util.NavigableSet<E>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="toElement" type="E">
+</parameter>
+<parameter name="inclusive" type="boolean">
+</parameter>
+</method>
+<method name="headSet"
+ return="java.util.NavigableSet<E>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="toElement" type="E">
+</parameter>
+</method>
+<method name="higher"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+</method>
+<method name="iterator"
+ return="java.util.Iterator<E>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="last"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="lower"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+</method>
+<method name="pollFirst"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="pollLast"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="size"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="subSet"
+ return="java.util.NavigableSet<E>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fromElement" type="E">
+</parameter>
+<parameter name="fromInclusive" type="boolean">
+</parameter>
+<parameter name="toElement" type="E">
+</parameter>
+<parameter name="toInclusive" type="boolean">
+</parameter>
+</method>
+<method name="subSet"
+ return="java.util.NavigableSet<E>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fromElement" type="E">
+</parameter>
+<parameter name="toElement" type="E">
+</parameter>
+</method>
+<method name="tailSet"
+ return="java.util.NavigableSet<E>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fromElement" type="E">
+</parameter>
+<parameter name="inclusive" type="boolean">
+</parameter>
+</method>
+<method name="tailSet"
+ return="java.util.NavigableSet<E>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fromElement" type="E">
+</parameter>
+</method>
+</class>
<class name="CopyOnWriteArrayList"
extends="java.lang.Object"
abstract="false"
@@ -312519,7 +325781,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="tasks" type="java.util.Collection<java.util.concurrent.Callable<T>>">
+<parameter name="tasks" type="java.util.Collection<? extends java.util.concurrent.Callable<T>>">
</parameter>
<exception name="InterruptedException" type="java.lang.InterruptedException">
</exception>
@@ -312534,7 +325796,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="tasks" type="java.util.Collection<java.util.concurrent.Callable<T>>">
+<parameter name="tasks" type="java.util.Collection<? extends java.util.concurrent.Callable<T>>">
</parameter>
<parameter name="timeout" type="long">
</parameter>
@@ -312553,7 +325815,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="tasks" type="java.util.Collection<java.util.concurrent.Callable<T>>">
+<parameter name="tasks" type="java.util.Collection<? extends java.util.concurrent.Callable<T>>">
</parameter>
<exception name="ExecutionException" type="java.util.concurrent.ExecutionException">
</exception>
@@ -312570,7 +325832,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="tasks" type="java.util.Collection<java.util.concurrent.Callable<T>>">
+<parameter name="tasks" type="java.util.Collection<? extends java.util.concurrent.Callable<T>>">
</parameter>
<parameter name="timeout" type="long">
</parameter>
@@ -312715,7 +325977,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="action" type="java.security.PrivilegedAction">
+<parameter name="action" type="java.security.PrivilegedAction<?>">
</parameter>
</method>
<method name="callable"
@@ -312728,7 +325990,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="action" type="java.security.PrivilegedExceptionAction">
+<parameter name="action" type="java.security.PrivilegedExceptionAction<?>">
</parameter>
</method>
<method name="defaultThreadFactory"
@@ -313021,9 +326283,7 @@
deprecated="not deprecated"
visibility="public"
>
-<implements name="java.util.concurrent.Future">
-</implements>
-<implements name="java.lang.Runnable">
+<implements name="java.util.concurrent.RunnableFuture">
</implements>
<constructor name="FutureTask"
type="java.util.concurrent.FutureTask"
@@ -313178,6 +326438,536 @@
</parameter>
</method>
</class>
+<class name="LinkedBlockingDeque"
+ extends="java.util.AbstractQueue"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="java.util.concurrent.BlockingDeque">
+</implements>
+<implements name="java.io.Serializable">
+</implements>
+<constructor name="LinkedBlockingDeque"
+ type="java.util.concurrent.LinkedBlockingDeque"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<constructor name="LinkedBlockingDeque"
+ type="java.util.concurrent.LinkedBlockingDeque"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="capacity" type="int">
+</parameter>
+</constructor>
+<constructor name="LinkedBlockingDeque"
+ type="java.util.concurrent.LinkedBlockingDeque"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="c" type="java.util.Collection<? extends E>">
+</parameter>
+</constructor>
+<method name="addFirst"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+</method>
+<method name="addLast"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+</method>
+<method name="descendingIterator"
+ return="java.util.Iterator<E>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="drainTo"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="c" type="java.util.Collection<? super E>">
+</parameter>
+</method>
+<method name="drainTo"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="c" type="java.util.Collection<? super E>">
+</parameter>
+<parameter name="maxElements" type="int">
+</parameter>
+</method>
+<method name="getFirst"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getLast"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="iterator"
+ return="java.util.Iterator<E>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="offer"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+</method>
+<method name="offer"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+<parameter name="timeout" type="long">
+</parameter>
+<parameter name="unit" type="java.util.concurrent.TimeUnit">
+</parameter>
+<exception name="InterruptedException" type="java.lang.InterruptedException">
+</exception>
+</method>
+<method name="offerFirst"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+</method>
+<method name="offerFirst"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+<parameter name="timeout" type="long">
+</parameter>
+<parameter name="unit" type="java.util.concurrent.TimeUnit">
+</parameter>
+<exception name="InterruptedException" type="java.lang.InterruptedException">
+</exception>
+</method>
+<method name="offerLast"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+</method>
+<method name="offerLast"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+<parameter name="timeout" type="long">
+</parameter>
+<parameter name="unit" type="java.util.concurrent.TimeUnit">
+</parameter>
+<exception name="InterruptedException" type="java.lang.InterruptedException">
+</exception>
+</method>
+<method name="peek"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="peekFirst"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="peekLast"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="poll"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="poll"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="timeout" type="long">
+</parameter>
+<parameter name="unit" type="java.util.concurrent.TimeUnit">
+</parameter>
+<exception name="InterruptedException" type="java.lang.InterruptedException">
+</exception>
+</method>
+<method name="pollFirst"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="pollFirst"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="timeout" type="long">
+</parameter>
+<parameter name="unit" type="java.util.concurrent.TimeUnit">
+</parameter>
+<exception name="InterruptedException" type="java.lang.InterruptedException">
+</exception>
+</method>
+<method name="pollLast"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="pollLast"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="timeout" type="long">
+</parameter>
+<parameter name="unit" type="java.util.concurrent.TimeUnit">
+</parameter>
+<exception name="InterruptedException" type="java.lang.InterruptedException">
+</exception>
+</method>
+<method name="pop"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="push"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+</method>
+<method name="put"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+<exception name="InterruptedException" type="java.lang.InterruptedException">
+</exception>
+</method>
+<method name="putFirst"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+<exception name="InterruptedException" type="java.lang.InterruptedException">
+</exception>
+</method>
+<method name="putLast"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+<exception name="InterruptedException" type="java.lang.InterruptedException">
+</exception>
+</method>
+<method name="remainingCapacity"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="removeFirst"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="removeFirstOccurrence"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+<method name="removeLast"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="removeLastOccurrence"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
+<method name="size"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="take"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="InterruptedException" type="java.lang.InterruptedException">
+</exception>
+</method>
+<method name="takeFirst"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="InterruptedException" type="java.lang.InterruptedException">
+</exception>
+</method>
+<method name="takeLast"
+ return="E"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="InterruptedException" type="java.lang.InterruptedException">
+</exception>
+</method>
+</class>
<class name="LinkedBlockingQueue"
extends="java.util.AbstractQueue"
abstract="false"
@@ -313671,6 +327461,52 @@
</parameter>
</method>
</interface>
+<interface name="RunnableFuture"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="java.util.concurrent.Future">
+</implements>
+<implements name="java.lang.Runnable">
+</implements>
+<method name="run"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</interface>
+<interface name="RunnableScheduledFuture"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="java.util.concurrent.RunnableFuture">
+</implements>
+<implements name="java.util.concurrent.ScheduledFuture">
+</implements>
+<method name="isPeriodic"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</interface>
<interface name="ScheduledExecutorService"
abstract="true"
static="false"
@@ -313823,6 +327659,36 @@
<parameter name="handler" type="java.util.concurrent.RejectedExecutionHandler">
</parameter>
</constructor>
+<method name="decorateTask"
+ return="java.util.concurrent.RunnableScheduledFuture<V>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="runnable" type="java.lang.Runnable">
+</parameter>
+<parameter name="task" type="java.util.concurrent.RunnableScheduledFuture<V>">
+</parameter>
+</method>
+<method name="decorateTask"
+ return="java.util.concurrent.RunnableScheduledFuture<V>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="callable" type="java.util.concurrent.Callable<V>">
+</parameter>
+<parameter name="task" type="java.util.concurrent.RunnableScheduledFuture<V>">
+</parameter>
+</method>
<method name="getContinueExistingPeriodicTasksAfterShutdownPolicy"
return="boolean"
abstract="false"
@@ -314507,6 +328373,30 @@
<parameter name="t" type="java.lang.Throwable">
</parameter>
</method>
+<method name="allowCoreThreadTimeOut"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="boolean">
+</parameter>
+</method>
+<method name="allowsCoreThreadTimeOut"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="awaitTermination"
return="boolean"
abstract="false"
@@ -315063,6 +328953,32 @@
<exception name="InterruptedException" type="java.lang.InterruptedException">
</exception>
</method>
+<method name="toDays"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="duration" type="long">
+</parameter>
+</method>
+<method name="toHours"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="duration" type="long">
+</parameter>
+</method>
<method name="toMicros"
return="long"
abstract="false"
@@ -315089,6 +329005,19 @@
<parameter name="duration" type="long">
</parameter>
</method>
+<method name="toMinutes"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="duration" type="long">
+</parameter>
+</method>
<method name="toNanos"
return="long"
abstract="false"
@@ -315237,6 +329166,19 @@
<parameter name="newValue" type="boolean">
</parameter>
</method>
+<method name="lazySet"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="newValue" type="boolean">
+</parameter>
+</method>
<method name="set"
return="void"
abstract="false"
@@ -315436,6 +329378,19 @@
visibility="public"
>
</method>
+<method name="lazySet"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="newValue" type="int">
+</parameter>
+</method>
<method name="longValue"
return="long"
abstract="false"
@@ -315633,6 +329588,21 @@
<parameter name="i" type="int">
</parameter>
</method>
+<method name="lazySet"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="i" type="int">
+</parameter>
+<parameter name="newValue" type="int">
+</parameter>
+</method>
<method name="length"
return="int"
abstract="false"
@@ -315820,6 +329790,21 @@
<parameter name="obj" type="T">
</parameter>
</method>
+<method name="lazySet"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="obj" type="T">
+</parameter>
+<parameter name="newValue" type="int">
+</parameter>
+</method>
<method name="newUpdater"
return="java.util.concurrent.atomic.AtomicIntegerFieldUpdater<U>"
abstract="false"
@@ -316038,6 +330023,19 @@
visibility="public"
>
</method>
+<method name="lazySet"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="newValue" type="long">
+</parameter>
+</method>
<method name="longValue"
return="long"
abstract="false"
@@ -316235,6 +330233,21 @@
<parameter name="i" type="int">
</parameter>
</method>
+<method name="lazySet"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="i" type="int">
+</parameter>
+<parameter name="newValue" type="long">
+</parameter>
+</method>
<method name="length"
return="int"
abstract="false"
@@ -316422,6 +330435,21 @@
<parameter name="obj" type="T">
</parameter>
</method>
+<method name="lazySet"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="obj" type="T">
+</parameter>
+<parameter name="newValue" type="long">
+</parameter>
+</method>
<method name="newUpdater"
return="java.util.concurrent.atomic.AtomicLongFieldUpdater<U>"
abstract="false"
@@ -316661,6 +330689,19 @@
<parameter name="newValue" type="V">
</parameter>
</method>
+<method name="lazySet"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="newValue" type="V">
+</parameter>
+</method>
<method name="set"
return="void"
abstract="false"
@@ -316765,6 +330806,21 @@
<parameter name="newValue" type="E">
</parameter>
</method>
+<method name="lazySet"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="i" type="int">
+</parameter>
+<parameter name="newValue" type="E">
+</parameter>
+</method>
<method name="length"
return="int"
abstract="false"
@@ -316870,6 +330926,21 @@
<parameter name="newValue" type="V">
</parameter>
</method>
+<method name="lazySet"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="obj" type="T">
+</parameter>
+<parameter name="newValue" type="V">
+</parameter>
+</method>
<method name="newUpdater"
return="java.util.concurrent.atomic.AtomicReferenceFieldUpdater<U, W>"
abstract="false"
@@ -317053,7 +331124,7 @@
static="false"
final="false"
deprecated="not deprecated"
- visibility=""
+ visibility="public"
>
<implements name="java.io.Serializable">
</implements>
@@ -317090,6 +331161,532 @@
</parameter>
</method>
</class>
+<class name="AbstractQueuedLongSynchronizer"
+ extends="java.util.concurrent.locks.AbstractOwnableSynchronizer"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="java.io.Serializable">
+</implements>
+<constructor name="AbstractQueuedLongSynchronizer"
+ type="java.util.concurrent.locks.AbstractQueuedLongSynchronizer"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</constructor>
+<method name="acquire"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="arg" type="long">
+</parameter>
+</method>
+<method name="acquireInterruptibly"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="arg" type="long">
+</parameter>
+<exception name="InterruptedException" type="java.lang.InterruptedException">
+</exception>
+</method>
+<method name="acquireShared"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="arg" type="long">
+</parameter>
+</method>
+<method name="acquireSharedInterruptibly"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="arg" type="long">
+</parameter>
+<exception name="InterruptedException" type="java.lang.InterruptedException">
+</exception>
+</method>
+<method name="compareAndSetState"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="expect" type="long">
+</parameter>
+<parameter name="update" type="long">
+</parameter>
+</method>
+<method name="getExclusiveQueuedThreads"
+ return="java.util.Collection<java.lang.Thread>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getFirstQueuedThread"
+ return="java.lang.Thread"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getQueueLength"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getQueuedThreads"
+ return="java.util.Collection<java.lang.Thread>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getSharedQueuedThreads"
+ return="java.util.Collection<java.lang.Thread>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getState"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</method>
+<method name="getWaitQueueLength"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="condition" type="java.util.concurrent.locks.AbstractQueuedLongSynchronizer.ConditionObject">
+</parameter>
+</method>
+<method name="getWaitingThreads"
+ return="java.util.Collection<java.lang.Thread>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="condition" type="java.util.concurrent.locks.AbstractQueuedLongSynchronizer.ConditionObject">
+</parameter>
+</method>
+<method name="hasContended"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="hasQueuedThreads"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="hasWaiters"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="condition" type="java.util.concurrent.locks.AbstractQueuedLongSynchronizer.ConditionObject">
+</parameter>
+</method>
+<method name="isHeldExclusively"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</method>
+<method name="isQueued"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="thread" type="java.lang.Thread">
+</parameter>
+</method>
+<method name="owns"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="condition" type="java.util.concurrent.locks.AbstractQueuedLongSynchronizer.ConditionObject">
+</parameter>
+</method>
+<method name="release"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="arg" type="long">
+</parameter>
+</method>
+<method name="releaseShared"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="arg" type="long">
+</parameter>
+</method>
+<method name="setState"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="newState" type="long">
+</parameter>
+</method>
+<method name="tryAcquire"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="arg" type="long">
+</parameter>
+</method>
+<method name="tryAcquireNanos"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="arg" type="long">
+</parameter>
+<parameter name="nanosTimeout" type="long">
+</parameter>
+<exception name="InterruptedException" type="java.lang.InterruptedException">
+</exception>
+</method>
+<method name="tryAcquireShared"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="arg" type="long">
+</parameter>
+</method>
+<method name="tryAcquireSharedNanos"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="arg" type="long">
+</parameter>
+<parameter name="nanosTimeout" type="long">
+</parameter>
+<exception name="InterruptedException" type="java.lang.InterruptedException">
+</exception>
+</method>
+<method name="tryRelease"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="arg" type="long">
+</parameter>
+</method>
+<method name="tryReleaseShared"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="arg" type="long">
+</parameter>
+</method>
+</class>
+<class name="AbstractQueuedLongSynchronizer.ConditionObject"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="java.util.concurrent.locks.Condition">
+</implements>
+<implements name="java.io.Serializable">
+</implements>
+<constructor name="AbstractQueuedLongSynchronizer.ConditionObject"
+ type="java.util.concurrent.locks.AbstractQueuedLongSynchronizer.ConditionObject"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="await"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="InterruptedException" type="java.lang.InterruptedException">
+</exception>
+</method>
+<method name="await"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="time" type="long">
+</parameter>
+<parameter name="unit" type="java.util.concurrent.TimeUnit">
+</parameter>
+<exception name="InterruptedException" type="java.lang.InterruptedException">
+</exception>
+</method>
+<method name="awaitNanos"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="nanosTimeout" type="long">
+</parameter>
+<exception name="InterruptedException" type="java.lang.InterruptedException">
+</exception>
+</method>
+<method name="awaitUninterruptibly"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="awaitUntil"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="deadline" type="java.util.Date">
+</parameter>
+<exception name="InterruptedException" type="java.lang.InterruptedException">
+</exception>
+</method>
+<method name="getWaitQueueLength"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</method>
+<method name="getWaitingThreads"
+ return="java.util.Collection<java.lang.Thread>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</method>
+<method name="hasWaiters"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</method>
+<method name="signal"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="signalAll"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
<class name="AbstractQueuedSynchronizer"
extends="java.util.concurrent.locks.AbstractOwnableSynchronizer"
abstract="true"
@@ -317807,6 +332404,32 @@
deprecated="not deprecated"
visibility="public"
>
+<method name="getBlocker"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="t" type="java.lang.Thread">
+</parameter>
+</method>
+<method name="park"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="blocker" type="java.lang.Object">
+</parameter>
+</method>
<method name="park"
return="void"
abstract="false"
@@ -317828,9 +332451,39 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="blocker" type="java.lang.Object">
+</parameter>
<parameter name="nanos" type="long">
</parameter>
</method>
+<method name="parkNanos"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="nanos" type="long">
+</parameter>
+</method>
+<method name="parkUntil"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="blocker" type="java.lang.Object">
+</parameter>
+<parameter name="deadline" type="long">
+</parameter>
+</method>
<method name="parkUntil"
return="void"
abstract="false"
@@ -318218,6 +332871,17 @@
visibility="protected"
>
</method>
+<method name="getReadHoldCount"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getReadLockCount"
return="int"
abstract="false"
@@ -318478,6 +333142,28 @@
<parameter name="lock" type="java.util.concurrent.locks.ReentrantReadWriteLock">
</parameter>
</constructor>
+<method name="getHoldCount"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isHeldByCurrentThread"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="lock"
return="void"
abstract="false"
@@ -321754,13 +336440,24 @@
<parameter name="msg" type="java.lang.String">
</parameter>
</method>
+<field name="GLOBAL_LOGGER_NAME"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""global""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="global"
type="java.util.logging.Logger"
transient="false"
volatile="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -324127,7 +338824,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="pattern" type="java.lang.String">
+<parameter name="regularExpression" type="java.lang.String">
</parameter>
<parameter name="flags" type="int">
</parameter>
@@ -324181,7 +338878,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="regex" type="java.lang.String">
+<parameter name="regularExpression" type="java.lang.String">
</parameter>
<parameter name="input" type="java.lang.CharSequence">
</parameter>
@@ -324207,7 +338904,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="s" type="java.lang.String">
+<parameter name="string" type="java.lang.String">
</parameter>
</method>
<method name="split"
@@ -324220,7 +338917,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="inputSeq" type="java.lang.CharSequence">
+<parameter name="input" type="java.lang.CharSequence">
</parameter>
<parameter name="limit" type="int">
</parameter>
@@ -325058,6 +339755,72 @@
>
</field>
</class>
+<class name="DeflaterInputStream"
+ extends="java.io.FilterInputStream"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DeflaterInputStream"
+ type="java.util.zip.DeflaterInputStream"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="in" type="java.io.InputStream">
+</parameter>
+</constructor>
+<constructor name="DeflaterInputStream"
+ type="java.util.zip.DeflaterInputStream"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="in" type="java.io.InputStream">
+</parameter>
+<parameter name="deflater" type="java.util.zip.Deflater">
+</parameter>
+</constructor>
+<constructor name="DeflaterInputStream"
+ type="java.util.zip.DeflaterInputStream"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="in" type="java.io.InputStream">
+</parameter>
+<parameter name="deflater" type="java.util.zip.Deflater">
+</parameter>
+<parameter name="bufferSize" type="int">
+</parameter>
+</constructor>
+<field name="buf"
+ type="byte[]"
+ transient="false"
+ volatile="false"
+ value="null"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</field>
+<field name="def"
+ type="java.util.zip.Deflater"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</field>
+</class>
<class name="DeflaterOutputStream"
extends="java.io.FilterOutputStream"
abstract="false"
@@ -325530,7 +340293,7 @@
>
<parameter name="is" type="java.io.InputStream">
</parameter>
-<parameter name="inf" type="java.util.zip.Inflater">
+<parameter name="inflater" type="java.util.zip.Inflater">
</parameter>
</constructor>
<constructor name="InflaterInputStream"
@@ -325542,7 +340305,7 @@
>
<parameter name="is" type="java.io.InputStream">
</parameter>
-<parameter name="inf" type="java.util.zip.Inflater">
+<parameter name="inflater" type="java.util.zip.Inflater">
</parameter>
<parameter name="bsize" type="int">
</parameter>
@@ -325592,6 +340355,85 @@
>
</field>
</class>
+<class name="InflaterOutputStream"
+ extends="java.io.FilterOutputStream"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="InflaterOutputStream"
+ type="java.util.zip.InflaterOutputStream"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="out" type="java.io.OutputStream">
+</parameter>
+</constructor>
+<constructor name="InflaterOutputStream"
+ type="java.util.zip.InflaterOutputStream"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="out" type="java.io.OutputStream">
+</parameter>
+<parameter name="inf" type="java.util.zip.Inflater">
+</parameter>
+</constructor>
+<constructor name="InflaterOutputStream"
+ type="java.util.zip.InflaterOutputStream"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="out" type="java.io.OutputStream">
+</parameter>
+<parameter name="inf" type="java.util.zip.Inflater">
+</parameter>
+<parameter name="bufferSize" type="int">
+</parameter>
+</constructor>
+<method name="finish"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<field name="buf"
+ type="byte[]"
+ transient="false"
+ volatile="false"
+ value="null"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</field>
+<field name="inf"
+ type="java.util.zip.Inflater"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</field>
+</class>
<class name="ZipEntry"
extends="java.lang.Object"
abstract="false"
@@ -325846,6 +340688,25 @@
>
</field>
</class>
+<class name="ZipError"
+ extends="java.lang.InternalError"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="ZipError"
+ type="java.util.zip.ZipError"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="s" type="java.lang.String">
+</parameter>
+</constructor>
+</class>
<class name="ZipException"
extends="java.io.IOException"
abstract="false"
@@ -341647,8 +356508,6 @@
deprecated="not deprecated"
visibility="public"
>
-<implements name="java.io.Serializable">
-</implements>
<constructor name="HandshakeCompletedEvent"
type="javax.net.ssl.HandshakeCompletedEvent"
static="false"
@@ -342239,11 +357098,11 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="parameters" type="java.util.List">
+<parameter name="parameters" type="java.util.List<java.security.KeyStore.Builder>">
</parameter>
</constructor>
<method name="getParameters"
- return="java.util.List"
+ return="java.util.List<java.security.KeyStore.Builder>"
abstract="false"
native="false"
synchronized="false"
@@ -342321,6 +357180,30 @@
visibility="public"
>
</method>
+<method name="getDefault"
+ return="javax.net.ssl.SSLContext"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="NoSuchAlgorithmException" type="java.security.NoSuchAlgorithmException">
+</exception>
+</method>
+<method name="getDefaultSSLParameters"
+ return="javax.net.ssl.SSLParameters"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getInstance"
return="javax.net.ssl.SSLContext"
abstract="false"
@@ -342427,6 +357310,17 @@
visibility="public"
>
</method>
+<method name="getSupportedSSLParameters"
+ return="javax.net.ssl.SSLParameters"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="init"
return="void"
abstract="false"
@@ -342446,6 +357340,19 @@
<exception name="KeyManagementException" type="java.security.KeyManagementException">
</exception>
</method>
+<method name="setDefault"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="sslContext" type="javax.net.ssl.SSLContext">
+</parameter>
+</method>
</class>
<class name="SSLContextSpi"
extends="java.lang.Object"
@@ -342500,6 +357407,17 @@
visibility="protected"
>
</method>
+<method name="engineGetDefaultSSLParameters"
+ return="javax.net.ssl.SSLParameters"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</method>
<method name="engineGetServerSessionContext"
return="javax.net.ssl.SSLSessionContext"
abstract="true"
@@ -342533,6 +357451,17 @@
visibility="protected"
>
</method>
+<method name="engineGetSupportedSSLParameters"
+ return="javax.net.ssl.SSLParameters"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</method>
<method name="engineInit"
return="void"
abstract="true"
@@ -342706,6 +357635,17 @@
visibility="public"
>
</method>
+<method name="getSSLParameters"
+ return="javax.net.ssl.SSLParameters"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getSession"
return="javax.net.ssl.SSLSession"
abstract="true"
@@ -342835,6 +357775,19 @@
<parameter name="need" type="boolean">
</parameter>
</method>
+<method name="setSSLParameters"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="p" type="javax.net.ssl.SSLParameters">
+</parameter>
+</method>
<method name="setUseClientMode"
return="void"
abstract="true"
@@ -343186,6 +358139,141 @@
</parameter>
</constructor>
</class>
+<class name="SSLParameters"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="SSLParameters"
+ type="javax.net.ssl.SSLParameters"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<constructor name="SSLParameters"
+ type="javax.net.ssl.SSLParameters"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cipherSuites" type="java.lang.String[]">
+</parameter>
+</constructor>
+<constructor name="SSLParameters"
+ type="javax.net.ssl.SSLParameters"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cipherSuites" type="java.lang.String[]">
+</parameter>
+<parameter name="protocols" type="java.lang.String[]">
+</parameter>
+</constructor>
+<method name="getCipherSuites"
+ return="java.lang.String[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getNeedClientAuth"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getProtocols"
+ return="java.lang.String[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getWantClientAuth"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="setCipherSuites"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cipherSuites" type="java.lang.String[]">
+</parameter>
+</method>
+<method name="setNeedClientAuth"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="needClientAuth" type="boolean">
+</parameter>
+</method>
+<method name="setProtocols"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="protocols" type="java.lang.String[]">
+</parameter>
+</method>
+<method name="setWantClientAuth"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="wantClientAuth" type="boolean">
+</parameter>
+</method>
+</class>
<class name="SSLPeerUnverifiedException"
extends="javax.net.ssl.SSLException"
abstract="false"
@@ -343793,8 +358881,6 @@
deprecated="not deprecated"
visibility="public"
>
-<implements name="java.io.Serializable">
-</implements>
<constructor name="SSLSessionBindingEvent"
type="javax.net.ssl.SSLSessionBindingEvent"
static="false"
@@ -343874,7 +358960,7 @@
visibility="public"
>
<method name="getIds"
- return="java.util.Enumeration"
+ return="java.util.Enumeration<byte[]>"
abstract="true"
native="false"
synchronized="false"
@@ -344091,6 +359177,17 @@
visibility="public"
>
</method>
+<method name="getSSLParameters"
+ return="javax.net.ssl.SSLParameters"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getSession"
return="javax.net.ssl.SSLSession"
abstract="true"
@@ -344211,6 +359308,19 @@
<parameter name="need" type="boolean">
</parameter>
</method>
+<method name="setSSLParameters"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="p" type="javax.net.ssl.SSLParameters">
+</parameter>
+</method>
<method name="setUseClientMode"
return="void"
abstract="true"
@@ -345420,6 +360530,18 @@
<parameter name="name" type="java.lang.String">
</parameter>
</constructor>
+<constructor name="X500Principal"
+ type="javax.security.auth.x500.X500Principal"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="name" type="java.lang.String">
+</parameter>
+<parameter name="keywordMap" type="java.util.Map<java.lang.String, java.lang.String>">
+</parameter>
+</constructor>
<method name="getEncoded"
return="byte[]"
abstract="false"
@@ -345455,6 +360577,21 @@
<parameter name="format" type="java.lang.String">
</parameter>
</method>
+<method name="getName"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="format" type="java.lang.String">
+</parameter>
+<parameter name="oidMap" type="java.util.Map<java.lang.String, java.lang.String>">
+</parameter>
+</method>
<field name="CANONICAL"
type="java.lang.String"
transient="false"
@@ -345908,6 +361045,70 @@
</package>
<package name="javax.sql"
>
+<interface name="CommonDataSource"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="getLogWriter"
+ return="java.io.PrintWriter"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="getLoginTimeout"
+ return="int"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setLogWriter"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="out" type="java.io.PrintWriter">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setLoginTimeout"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="seconds" type="int">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+</interface>
<class name="ConnectionEvent"
extends="java.util.EventObject"
abstract="false"
@@ -345995,32 +361196,8 @@
deprecated="not deprecated"
visibility="public"
>
-<method name="getLogWriter"
- return="java.io.PrintWriter"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<exception name="SQLException" type="java.sql.SQLException">
-</exception>
-</method>
-<method name="getLoginTimeout"
- return="int"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<exception name="SQLException" type="java.sql.SQLException">
-</exception>
-</method>
+<implements name="javax.sql.CommonDataSource">
+</implements>
<method name="getPooledConnection"
return="javax.sql.PooledConnection"
abstract="true"
@@ -346051,36 +361228,6 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
-<method name="setLogWriter"
- return="void"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="theWriter" type="java.io.PrintWriter">
-</parameter>
-<exception name="SQLException" type="java.sql.SQLException">
-</exception>
-</method>
-<method name="setLoginTimeout"
- return="void"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="theTimeout" type="int">
-</parameter>
-<exception name="SQLException" type="java.sql.SQLException">
-</exception>
-</method>
</interface>
<interface name="DataSource"
abstract="true"
@@ -346089,6 +361236,10 @@
deprecated="not deprecated"
visibility="public"
>
+<implements name="javax.sql.CommonDataSource">
+</implements>
+<implements name="java.sql.Wrapper">
+</implements>
<method name="getConnection"
return="java.sql.Connection"
abstract="true"
@@ -346119,62 +361270,6 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
-<method name="getLogWriter"
- return="java.io.PrintWriter"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<exception name="SQLException" type="java.sql.SQLException">
-</exception>
-</method>
-<method name="getLoginTimeout"
- return="int"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<exception name="SQLException" type="java.sql.SQLException">
-</exception>
-</method>
-<method name="setLogWriter"
- return="void"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="theWriter" type="java.io.PrintWriter">
-</parameter>
-<exception name="SQLException" type="java.sql.SQLException">
-</exception>
-</method>
-<method name="setLoginTimeout"
- return="void"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="theTimeout" type="int">
-</parameter>
-<exception name="SQLException" type="java.sql.SQLException">
-</exception>
-</method>
</interface>
<interface name="PooledConnection"
abstract="true"
@@ -346196,6 +361291,19 @@
<parameter name="theListener" type="javax.sql.ConnectionEventListener">
</parameter>
</method>
+<method name="addStatementEventListener"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="javax.sql.StatementEventListener">
+</parameter>
+</method>
<method name="close"
return="void"
abstract="true"
@@ -346235,6 +361343,19 @@
<parameter name="theListener" type="javax.sql.ConnectionEventListener">
</parameter>
</method>
+<method name="removeStatementEventListener"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="javax.sql.StatementEventListener">
+</parameter>
+</method>
</interface>
<interface name="RowSet"
abstract="true"
@@ -346477,6 +361598,59 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="setAsciiStream"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterIndex" type="int">
+</parameter>
+<parameter name="theInputStream" type="java.io.InputStream">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setAsciiStream"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="theInputStream" type="java.io.InputStream">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setAsciiStream"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="theInputStream" type="java.io.InputStream">
+</parameter>
+<parameter name="length" type="int">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="setBigDecimal"
return="void"
abstract="true"
@@ -346494,6 +361668,23 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="setBigDecimal"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="theBigDecimal" type="java.math.BigDecimal">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="setBinaryStream"
return="void"
abstract="true"
@@ -346513,6 +361704,59 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="setBinaryStream"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterIndex" type="int">
+</parameter>
+<parameter name="theInputStream" type="java.io.InputStream">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setBinaryStream"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="theInputStream" type="java.io.InputStream">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setBinaryStream"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="theInputStream" type="java.io.InputStream">
+</parameter>
+<parameter name="length" type="int">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="setBlob"
return="void"
abstract="true"
@@ -346530,6 +361774,95 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="setBlob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterIndex" type="int">
+</parameter>
+<parameter name="theInputStream" type="java.io.InputStream">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setBlob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterIndex" type="int">
+</parameter>
+<parameter name="theInputStream" type="java.io.InputStream">
+</parameter>
+<parameter name="length" type="long">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setBlob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="theInputStream" type="java.io.InputStream">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setBlob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="theInputStream" type="java.io.InputStream">
+</parameter>
+<parameter name="length" type="long">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setBlob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="theBlob" type="java.sql.Blob">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="setBoolean"
return="void"
abstract="true"
@@ -346547,6 +361880,23 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="setBoolean"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="theBoolean" type="boolean">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="setByte"
return="void"
abstract="true"
@@ -346564,6 +361914,23 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="setByte"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="theByte" type="byte">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="setBytes"
return="void"
abstract="true"
@@ -346581,6 +361948,23 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="setBytes"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="theByteArray" type="byte[]">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="setCharacterStream"
return="void"
abstract="true"
@@ -346600,6 +361984,59 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="setCharacterStream"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterIndex" type="int">
+</parameter>
+<parameter name="theReader" type="java.io.Reader">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setCharacterStream"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="theReader" type="java.io.Reader">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setCharacterStream"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="theReader" type="java.io.Reader">
+</parameter>
+<parameter name="length" type="int">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="setClob"
return="void"
abstract="true"
@@ -346617,6 +362054,95 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="setClob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterIndex" type="int">
+</parameter>
+<parameter name="theReader" type="java.io.Reader">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setClob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterIndex" type="int">
+</parameter>
+<parameter name="theReader" type="java.io.Reader">
+</parameter>
+<parameter name="length" type="long">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setClob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="theClob" type="java.sql.Clob">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setClob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="theReader" type="java.io.Reader">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setClob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="theReader" type="java.io.Reader">
+</parameter>
+<parameter name="length" type="long">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="setCommand"
return="void"
abstract="true"
@@ -346698,6 +362224,42 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="setDate"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="theDate" type="java.sql.Date">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setDate"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="theDate" type="java.sql.Date">
+</parameter>
+<parameter name="theCalendar" type="java.util.Calendar">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="setDouble"
return="void"
abstract="true"
@@ -346715,6 +362277,23 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="setDouble"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="theDouble" type="double">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="setEscapeProcessing"
return="void"
abstract="true"
@@ -346747,6 +362326,23 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="setFloat"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="theFloat" type="float">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="setInt"
return="void"
abstract="true"
@@ -346764,6 +362360,23 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="setInt"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="theInteger" type="int">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="setLong"
return="void"
abstract="true"
@@ -346781,6 +362394,23 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="setLong"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="theLong" type="long">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="setMaxFieldSize"
return="void"
abstract="true"
@@ -346811,6 +362441,218 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="setNCharacterStream"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterIndex" type="int">
+</parameter>
+<parameter name="theReader" type="java.io.Reader">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setNCharacterStream"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterIndex" type="int">
+</parameter>
+<parameter name="theReader" type="java.io.Reader">
+</parameter>
+<parameter name="length" type="long">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setNCharacterStream"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="theReader" type="java.io.Reader">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setNCharacterStream"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="theReader" type="java.io.Reader">
+</parameter>
+<parameter name="length" type="long">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setNClob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterIndex" type="int">
+</parameter>
+<parameter name="theNClob" type="java.sql.NClob">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setNClob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterIndex" type="int">
+</parameter>
+<parameter name="theReader" type="java.io.Reader">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setNClob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterIndex" type="int">
+</parameter>
+<parameter name="theReader" type="java.io.Reader">
+</parameter>
+<parameter name="length" type="long">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setNClob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="theNClob" type="java.sql.NClob">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setNClob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="theReader" type="java.io.Reader">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setNClob"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="theReader" type="java.io.Reader">
+</parameter>
+<parameter name="length" type="long">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setNString"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterIndex" type="int">
+</parameter>
+<parameter name="theNString" type="java.lang.String">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setNString"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="theNString" type="java.lang.String">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="setNull"
return="void"
abstract="true"
@@ -346847,6 +362689,42 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="setNull"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="sqlType" type="int">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setNull"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="sqlType" type="int">
+</parameter>
+<parameter name="typeName" type="java.lang.String">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="setObject"
return="void"
abstract="true"
@@ -346904,6 +362782,63 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="setObject"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="theObject" type="java.lang.Object">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setObject"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="theObject" type="java.lang.Object">
+</parameter>
+<parameter name="targetSqlType" type="int">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setObject"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="theObject" type="java.lang.Object">
+</parameter>
+<parameter name="targetSqlType" type="int">
+</parameter>
+<parameter name="scale" type="int">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="setPassword"
return="void"
abstract="true"
@@ -346966,6 +362901,74 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="setRowId"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterIndex" type="int">
+</parameter>
+<parameter name="theRowId" type="java.sql.RowId">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setRowId"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="theRowId" type="java.sql.RowId">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setSQLXML"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterIndex" type="int">
+</parameter>
+<parameter name="theSQLXML" type="java.sql.SQLXML">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setSQLXML"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="theSQLXML" type="java.sql.SQLXML">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="setShort"
return="void"
abstract="true"
@@ -346983,6 +362986,23 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="setShort"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="theShort" type="short">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="setString"
return="void"
abstract="true"
@@ -347000,6 +363020,23 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="setString"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="theString" type="java.lang.String">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="setTime"
return="void"
abstract="true"
@@ -347036,6 +363073,42 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="setTime"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="theTime" type="java.sql.Time">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setTime"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="theTime" type="java.sql.Time">
+</parameter>
+<parameter name="theCalendar" type="java.util.Calendar">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="setTimestamp"
return="void"
abstract="true"
@@ -347072,6 +363145,42 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="setTimestamp"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="theTimestamp" type="java.sql.Timestamp">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
+<method name="setTimestamp"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterName" type="java.lang.String">
+</parameter>
+<parameter name="theTimestamp" type="java.sql.Timestamp">
+</parameter>
+<parameter name="theCalendar" type="java.util.Calendar">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="setTransactionIsolation"
return="void"
abstract="true"
@@ -347117,6 +363226,23 @@
<exception name="SQLException" type="java.sql.SQLException">
</exception>
</method>
+<method name="setURL"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parameterIndex" type="int">
+</parameter>
+<parameter name="theURL" type="java.net.URL">
+</parameter>
+<exception name="SQLException" type="java.sql.SQLException">
+</exception>
+</method>
<method name="setUrl"
return="void"
abstract="true"
@@ -347636,6 +363762,99 @@
</exception>
</method>
</interface>
+<class name="StatementEvent"
+ extends="java.util.EventObject"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="StatementEvent"
+ type="javax.sql.StatementEvent"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="con" type="javax.sql.PooledConnection">
+</parameter>
+<parameter name="statement" type="java.sql.PreparedStatement">
+</parameter>
+<parameter name="exception" type="java.sql.SQLException">
+</parameter>
+</constructor>
+<constructor name="StatementEvent"
+ type="javax.sql.StatementEvent"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="con" type="javax.sql.PooledConnection">
+</parameter>
+<parameter name="statement" type="java.sql.PreparedStatement">
+</parameter>
+</constructor>
+<method name="getSQLException"
+ return="java.sql.SQLException"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getStatement"
+ return="java.sql.PreparedStatement"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<interface name="StatementEventListener"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="java.util.EventListener">
+</implements>
+<method name="statementClosed"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="event" type="javax.sql.StatementEvent">
+</parameter>
+</method>
+<method name="statementErrorOccurred"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="event" type="javax.sql.StatementEvent">
+</parameter>
+</method>
+</interface>
</package>
<package name="javax.xml"
>
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index 082e704..1fde437 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -103,6 +103,9 @@
dump_file("NETWORK ROUTES", "/proc/net/route");
dump_file("ARP CACHE", "/proc/net/arp");
+ run_command("WIFI NETWORKS", 20,
+ "su", "root", "wpa_cli", "list_networks", NULL);
+
#ifdef FWDUMP_bcm4329
run_command("DUMP WIFI FIRMWARE LOG", 60,
"su", "root", "dhdutil", "-i", "eth0", "upload", "/data/local/tmp/wlan_crash.dump", NULL);
diff --git a/common/java/com/android/common/speech/LoggingEvents.java b/common/java/com/android/common/speech/LoggingEvents.java
index 1f3c6ef..4b438dc 100644
--- a/common/java/com/android/common/speech/LoggingEvents.java
+++ b/common/java/com/android/common/speech/LoggingEvents.java
@@ -110,6 +110,11 @@
public static final int START = 14;
public static final String EXTRA_START_LOCALE = "locale"; // value should be String
public static final String EXTRA_START_SWIPE = "swipe"; // value should be boolean
+ // EXTRA_START_SWIPE is deprecated; switch to EXTRA_START_METHOD instead
+ public static final String EXTRA_START_METHOD = "method"; // value should be int below
+ public static final int START_METHOD_BUTTON = 1;
+ public static final int START_METHOD_SWIPE = 2;
+ public static final int START_METHOD_MOTION = 3;
public static final int VOICE_INPUT_DELIVERED = 15;
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java
index 1d9e0f1..2ead976 100644
--- a/core/java/android/accounts/AccountManagerService.java
+++ b/core/java/android/accounts/AccountManagerService.java
@@ -1657,7 +1657,7 @@
}
boolean needsProvisioning;
try {
- needsProvisioning = telephony.getCdmaNeedsProvisioning();
+ needsProvisioning = telephony.needsOtaServiceProvisioning();
} catch (RemoteException e) {
Log.w(TAG, "exception while checking provisioning", e);
// default to NOT wiping out the passwords
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
new file mode 100644
index 0000000..cbad72e
--- /dev/null
+++ b/core/java/android/app/ActionBar.java
@@ -0,0 +1,308 @@
+/*
+ * 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.app;
+
+import android.graphics.drawable.Drawable;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.SpinnerAdapter;
+
+/**
+ * This is the public interface to the contextual ActionBar.
+ * The ActionBar acts as a replacement for the title bar in Activities.
+ * It provides facilities for creating toolbar actions as well as
+ * methods of navigating around an application.
+ */
+public abstract class ActionBar {
+ /**
+ * Standard navigation mode. Consists of either a logo or icon
+ * and title text with an optional subtitle. Clicking any of these elements
+ * will dispatch onActionItemSelected to the registered Callback with
+ * a MenuItem with item ID android.R.id.home.
+ */
+ public static final int NAVIGATION_MODE_STANDARD = 0;
+
+ /**
+ * Dropdown list navigation mode. Instead of static title text this mode
+ * presents a dropdown menu for navigation within the activity.
+ */
+ public static final int NAVIGATION_MODE_DROPDOWN_LIST = 1;
+
+ /**
+ * Tab navigation mode. Instead of static title text this mode
+ * presents a series of tabs for navigation within the activity.
+ */
+ public static final int NAVIGATION_MODE_TABS = 2;
+
+ /**
+ * Custom navigation mode. This navigation mode is set implicitly whenever
+ * a custom navigation view is set. See {@link #setCustomNavigationView(View)}.
+ */
+ public static final int NAVIGATION_MODE_CUSTOM = 3;
+
+ /**
+ * Use logo instead of icon if available. This flag will cause appropriate
+ * navigation modes to use a wider logo in place of the standard icon.
+ */
+ public static final int DISPLAY_USE_LOGO = 0x1;
+
+ /**
+ * Hide 'home' elements in this action bar, leaving more space for other
+ * navigation elements. This includes logo and icon.
+ */
+ public static final int DISPLAY_HIDE_HOME = 0x2;
+
+ /**
+ * Set the callback that the ActionBar will use to handle events
+ * and populate menus.
+ * @param callback Callback to use
+ */
+ public abstract void setCallback(Callback callback);
+
+ /**
+ * Set the action bar into custom navigation mode, supplying a view
+ * for custom navigation.
+ *
+ * Custom navigation views appear between the application icon and
+ * any action buttons and may use any space available there. Common
+ * use cases for custom navigation views might include an auto-suggesting
+ * address bar for a browser or other navigation mechanisms that do not
+ * translate well to provided navigation modes.
+ *
+ * @param view Custom navigation view to place in the ActionBar.
+ */
+ public abstract void setCustomNavigationMode(View view);
+
+ /**
+ * Set the action bar into dropdown navigation mode and supply an adapter
+ * that will provide views for navigation choices.
+ *
+ * @param adapter An adapter that will provide views both to display
+ * the current navigation selection and populate views
+ * within the dropdown navigation menu.
+ */
+ public abstract void setDropdownNavigationMode(SpinnerAdapter adapter);
+
+ /**
+ * Set the action bar into standard navigation mode, supplying a title and subtitle.
+ *
+ * Standard navigation mode is default. The title is automatically set to the
+ * name of your Activity. Subtitles are displayed underneath the title, usually
+ * in a smaller font or otherwise less prominently than the title. Subtitles are
+ * good for extended descriptions of activity state.
+ *
+ * @param title The action bar's title. null is treated as an empty string.
+ * @param subtitle The action bar's subtitle. null is treated as an empty string.
+ */
+ public abstract void setStandardNavigationMode(CharSequence title, CharSequence subtitle);
+
+ /**
+ * Set the action bar into standard navigation mode, supplying a title and subtitle.
+ *
+ * Standard navigation mode is default. The title is automatically set to the
+ * name of your Activity.
+ *
+ * @param title The action bar's title. null is treated as an empty string.
+ */
+ public abstract void setStandardNavigationMode(CharSequence title);
+
+ /**
+ * Set display options. This changes all display option bits at once. To change
+ * a limited subset of display options, see {@link #setDisplayOptions(int, int)}.
+ *
+ * @param options A combination of the bits defined by the DISPLAY_ constants
+ * defined in ActionBar.
+ */
+ public abstract void setDisplayOptions(int options);
+
+ /**
+ * Set selected display options. Only the options specified by mask will be changed.
+ * To change all display option bits at once, see {@link #setDisplayOptions(int)}.
+ *
+ * <p>Example: setDisplayOptions(0, DISPLAY_HIDE_HOME) will disable the
+ * {@link #DISPLAY_HIDE_HOME} option.
+ * setDisplayOptions(DISPLAY_HIDE_HOME, DISPLAY_HIDE_HOME | DISPLAY_USE_LOGO)
+ * will enable {@link #DISPLAY_HIDE_HOME} and disable {@link #DISPLAY_USE_LOGO}.
+ *
+ * @param options A combination of the bits defined by the DISPLAY_ constants
+ * defined in ActionBar.
+ * @param mask A bit mask declaring which display options should be changed.
+ */
+ public abstract void setDisplayOptions(int options, int mask);
+
+ /**
+ * Set the ActionBar's background.
+ *
+ * @param d Background drawable
+ */
+ public abstract void setBackgroundDrawable(Drawable d);
+
+ /**
+ * Set a drawable to use as a divider between sections of the ActionBar.
+ *
+ * @param d Divider drawable
+ */
+ public abstract void setDividerDrawable(Drawable d);
+
+ /**
+ * @return The current custom navigation view.
+ */
+ public abstract View getCustomNavigationView();
+
+ /**
+ * Returns the current ActionBar title in standard mode.
+ * Returns null if {@link #getNavigationMode()} would not return
+ * {@link #NAVIGATION_MODE_STANDARD}.
+ *
+ * @return The current ActionBar title or null.
+ */
+ public abstract CharSequence getTitle();
+
+ /**
+ * Returns the current ActionBar subtitle in standard mode.
+ * Returns null if {@link #getNavigationMode()} would not return
+ * {@link #NAVIGATION_MODE_STANDARD}.
+ *
+ * @return The current ActionBar subtitle or null.
+ */
+ public abstract CharSequence getSubtitle();
+
+ /**
+ * Returns the current navigation mode. The result will be one of:
+ * <ul>
+ * <li>{@link #NAVIGATION_MODE_STANDARD}</li>
+ * <li>{@link #NAVIGATION_MODE_DROPDOWN_LIST}</li>
+ * <li>{@link #NAVIGATION_MODE_TABS}</li>
+ * <li>{@link #NAVIGATION_MODE_CUSTOM}</li>
+ * </ul>
+ *
+ * @return The current navigation mode.
+ *
+ * @see #setStandardNavigationMode(CharSequence)
+ * @see #setStandardNavigationMode(CharSequence, CharSequence)
+ * @see #setDropdownNavigationMode(SpinnerAdapter)
+ * @see #setCustomNavigationMode(View)
+ */
+ public abstract int getNavigationMode();
+
+ /**
+ * @return The current set of display options.
+ */
+ public abstract int getDisplayOptions();
+
+ /**
+ * Request an update of the items in the action menu.
+ * This will result in a call to Callback.onUpdateActionMenu(Menu)
+ * and the ActionBar will update based on any changes made there.
+ */
+ public abstract void updateActionMenu();
+
+ /**
+ * Callback interface for ActionBar events.
+ */
+ public interface Callback {
+ /**
+ * Initialize the always-visible contents of the action bar.
+ * You should place your menu items into <var>menu</var>.
+ *
+ * <p>This is only called once, the first time the action bar is displayed.
+ *
+ * @param menu The action menu in which to place your items.
+ * @return You must return true for actions to be displayed;
+ * if you return false they will not be shown.
+ *
+ * @see #onActionItemClicked(MenuItem)
+ */
+ public boolean onCreateActionMenu(Menu menu);
+
+ /**
+ * Update the action bar. This is called in response to {@link #updateActionMenu()}
+ * calls, which may be application-initiated or the result of changing fragment state.
+ *
+ * @return true if the action bar should update based on altered menu contents,
+ * false if no changes are necessary.
+ */
+ public boolean onUpdateActionMenu(Menu menu);
+
+ /**
+ * This hook is called whenever an action item in your action bar is clicked.
+ * The default implementation simply returns false to have the normal
+ * processing happen (sending a message to its handler). You can use this
+ * method for any items for which you would like to do processing without
+ * those other facilities.
+ *
+ * @param item The action bar item that was selected.
+ * @return boolean Return false to allow normal menu processing to proceed,
+ * true to consume it here.
+ */
+ public boolean onActionItemClicked(MenuItem item);
+
+ /**
+ * This method is called whenever a navigation item in your action bar
+ * is selected.
+ *
+ * @param itemPosition Position of the item clicked.
+ * @param itemId ID of the item clicked.
+ * @return True if the event was handled, false otherwise.
+ */
+ public boolean onNavigationItemSelected(int itemPosition, long itemId);
+
+ /*
+ * In progress
+ */
+ public boolean onCreateContextMode(int modeId, Menu menu);
+ public boolean onPrepareContextMode(int modeId, Menu menu);
+ public boolean onContextItemClicked(int modeId, MenuItem item);
+ }
+
+ /**
+ * Simple stub implementations of ActionBar.Callback methods.
+ * Extend this if you only need a subset of Callback functionality.
+ */
+ public static class SimpleCallback implements Callback {
+ public boolean onCreateActionMenu(Menu menu) {
+ return false;
+ }
+
+ public boolean onUpdateActionMenu(Menu menu) {
+ return false;
+ }
+
+ public boolean onActionItemClicked(MenuItem item) {
+ return false;
+ }
+
+ public boolean onCreateContextMode(int modeId, Menu menu) {
+ return false;
+ }
+
+ public boolean onPrepareContextMode(int modeId, Menu menu) {
+ return false;
+ }
+
+ public boolean onContextItemClicked(int modeId, MenuItem item) {
+ return false;
+ }
+
+ public boolean onNavigationItemSelected(int itemPosition, long itemId) {
+ return false;
+ }
+ }
+
+}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index a962391..d64f2c5 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -16,19 +16,21 @@
package android.app;
-import com.android.internal.policy.PolicyManager;
+import java.util.ArrayList;
+import java.util.HashMap;
import android.content.ComponentCallbacks;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
-import android.content.Intent;
import android.content.IIntentSender;
+import android.content.Intent;
import android.content.IntentSender;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -39,7 +41,7 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
-import android.os.Looper;
+import android.os.Parcelable;
import android.os.RemoteException;
import android.text.Selection;
import android.text.SpannableStringBuilder;
@@ -50,8 +52,10 @@
import android.util.EventLog;
import android.util.Log;
import android.util.SparseArray;
+import android.view.ActionBarView;
import android.view.ContextMenu;
import android.view.ContextThemeWrapper;
+import android.view.InflateException;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -68,6 +72,10 @@
import android.view.ViewGroup.LayoutParams;
import android.view.accessibility.AccessibilityEvent;
import android.widget.AdapterView;
+import android.widget.LinearLayout;
+
+import com.android.internal.app.SplitActionBar;
+import com.android.internal.policy.PolicyManager;
import java.util.ArrayList;
import java.util.HashMap;
@@ -606,6 +614,7 @@
private static long sInstanceCount = 0;
private static final String WINDOW_HIERARCHY_TAG = "android:viewHierarchyState";
+ private static final String FRAGMENTS_TAG = "android:fragments";
private static final String SAVED_DIALOG_IDS_KEY = "android:savedDialogIds";
private static final String SAVED_DIALOGS_TAG = "android:savedDialogs";
private static final String SAVED_DIALOG_KEY_PREFIX = "android:dialog_";
@@ -627,18 +636,25 @@
private ComponentName mComponent;
/*package*/ ActivityInfo mActivityInfo;
/*package*/ ActivityThread mMainThread;
- /*package*/ Object mLastNonConfigurationInstance;
- /*package*/ HashMap<String,Object> mLastNonConfigurationChildInstances;
Activity mParent;
boolean mCalled;
private boolean mResumed;
private boolean mStopped;
boolean mFinished;
boolean mStartedActivity;
+ /** true if the activity is being destroyed in order to recreate it with a new configuration */
+ /*package*/ boolean mChangingConfigurations = false;
/*package*/ int mConfigChangeFlags;
/*package*/ Configuration mCurrentConfig;
private SearchManager mSearchManager;
+ static final class NonConfigurationInstances {
+ Object activity;
+ HashMap<String, Object> children;
+ ArrayList<Fragment> fragments;
+ }
+ /* package */ NonConfigurationInstances mLastNonConfigurationInstances;
+
private Window mWindow;
private WindowManager mWindowManager;
@@ -646,10 +662,13 @@
/*package*/ boolean mWindowAdded = false;
/*package*/ boolean mVisibleFromServer = false;
/*package*/ boolean mVisibleFromClient = true;
+ /*package*/ ActionBar mActionBar = null;
private CharSequence mTitle;
private int mTitleColor = 0;
+ final FragmentManager mFragments = new FragmentManager();
+
private static final class ManagedCursor {
ManagedCursor(Cursor cursor) {
mCursor = cursor;
@@ -676,7 +695,7 @@
protected static final int[] FOCUSED_STATE_SET = {com.android.internal.R.attr.state_focused};
private Thread mUiThread;
- private final Handler mHandler = new Handler();
+ final Handler mHandler = new Handler();
// Used for debug only
/*
@@ -800,6 +819,12 @@
protected void onCreate(Bundle savedInstanceState) {
mVisibleFromClient = !mWindow.getWindowStyle().getBoolean(
com.android.internal.R.styleable.Window_windowNoDisplay, false);
+ if (savedInstanceState != null) {
+ Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
+ mFragments.restoreAllState(p, mLastNonConfigurationInstances != null
+ ? mLastNonConfigurationInstances.fragments : null);
+ }
+ mFragments.dispatchCreate();
mCalled = true;
}
@@ -1084,6 +1109,10 @@
*/
protected void onSaveInstanceState(Bundle outState) {
outState.putBundle(WINDOW_HIERARCHY_TAG, mWindow.saveHierarchyState());
+ Parcelable p = mFragments.saveAllState();
+ if (p != null) {
+ outState.putParcelable(FRAGMENTS_TAG, p);
+ }
}
/**
@@ -1388,7 +1417,8 @@
* {@link #onRetainNonConfigurationInstance()}.
*/
public Object getLastNonConfigurationInstance() {
- return mLastNonConfigurationInstance;
+ return mLastNonConfigurationInstances != null
+ ? mLastNonConfigurationInstances.activity : null;
}
/**
@@ -1444,8 +1474,9 @@
* @return Returns the object previously returned by
* {@link #onRetainNonConfigurationChildInstances()}
*/
- HashMap<String,Object> getLastNonConfigurationChildInstances() {
- return mLastNonConfigurationChildInstances;
+ HashMap<String, Object> getLastNonConfigurationChildInstances() {
+ return mLastNonConfigurationInstances != null
+ ? mLastNonConfigurationInstances.children : null;
}
/**
@@ -1459,11 +1490,34 @@
return null;
}
+ NonConfigurationInstances retainNonConfigurationInstances() {
+ Object activity = onRetainNonConfigurationInstance();
+ HashMap<String, Object> children = onRetainNonConfigurationChildInstances();
+ ArrayList<Fragment> fragments = mFragments.retainNonConfig();
+ if (activity == null && children == null && fragments == null) {
+ return null;
+ }
+
+ NonConfigurationInstances nci = new NonConfigurationInstances();
+ nci.activity = activity;
+ nci.children = children;
+ nci.fragments = fragments;
+ return nci;
+ }
+
public void onLowMemory() {
mCalled = true;
}
/**
+ * Start a series of edit operations on the Fragments associated with
+ * this activity.
+ */
+ public FragmentTransaction openFragmentTransaction() {
+ return new BackStackEntry(mFragments);
+ }
+
+ /**
* Wrapper around
* {@link ContentResolver#query(android.net.Uri , String[], String, String[], String)}
* that gives the resulting {@link Cursor} to call
@@ -1525,40 +1579,6 @@
}
/**
- * Wrapper around {@link Cursor#commitUpdates()} that takes care of noting
- * that the Cursor needs to be requeried. You can call this method in
- * {@link #onPause} or {@link #onStop} to have the system call
- * {@link Cursor#requery} for you if the activity is later resumed. This
- * allows you to avoid determing when to do the requery yourself (which is
- * required for the Cursor to see any data changes that were committed with
- * it).
- *
- * @param c The Cursor whose changes are to be committed.
- *
- * @see #managedQuery(android.net.Uri , String[], String, String[], String)
- * @see #startManagingCursor
- * @see Cursor#commitUpdates()
- * @see Cursor#requery
- * @hide
- */
- @Deprecated
- public void managedCommitUpdates(Cursor c) {
- synchronized (mManagedCursors) {
- final int N = mManagedCursors.size();
- for (int i=0; i<N; i++) {
- ManagedCursor mc = mManagedCursors.get(i);
- if (mc.mCursor == c) {
- c.commitUpdates();
- mc.mUpdated = true;
- return;
- }
- }
- throw new RuntimeException(
- "Cursor " + c + " is not currently managed");
- }
- }
-
- /**
* This method allows the activity to take care of managing the given
* {@link Cursor}'s lifecycle for you based on the activity's lifecycle.
* That is, when the activity is stopped it will automatically call
@@ -1636,7 +1656,60 @@
public View findViewById(int id) {
return getWindow().findViewById(id);
}
-
+
+ /**
+ * Retrieve a reference to this activity's ActionBar.
+ *
+ * <p><em>Note:</em> The ActionBar is initialized when a content view
+ * is set. This function will return null if called before {@link #setContentView}
+ * or {@link #addContentView}.
+ * @return The Activity's ActionBar, or null if it does not have one.
+ */
+ public ActionBar getActionBar() {
+ return mActionBar;
+ }
+
+ /**
+ * Creates a new ActionBar, locates the inflated ActionBarView,
+ * initializes the ActionBar with the view, and sets mActionBar.
+ */
+ private void initActionBar() {
+ if (!getWindow().hasFeature(Window.FEATURE_ACTION_BAR)) {
+ return;
+ }
+
+ ActionBarView view = (ActionBarView) findViewById(com.android.internal.R.id.action_bar);
+ if (view != null) {
+ LinearLayout splitView =
+ (LinearLayout) findViewById(com.android.internal.R.id.context_action_bar);
+ if (splitView != null) {
+ mActionBar = new SplitActionBar(view, splitView);
+ }
+ } else {
+ Log.e(TAG, "Could not create action bar; view not found in window decor.");
+ }
+ }
+
+ /**
+ * Finds a fragment that was identified by the given id either when inflated
+ * from XML or as the container ID when added in a transaction. This only
+ * returns fragments that are currently added to the activity's content.
+ * @return The fragment if found or null otherwise.
+ */
+ public Fragment findFragmentById(int id) {
+ return mFragments.findFragmentById(id);
+ }
+
+ /**
+ * Finds a fragment that was identified by the given tag either when inflated
+ * from XML or as supplied when added in a transaction. This only
+ * returns fragments that are currently added to the activity's content.
+ * @return The fragment if found or null otherwise.
+ */
+ public Fragment findFragmentByTag(String tag) {
+ return mFragments.findFragmentByTag(tag);
+ }
+
/**
* Set the activity content from a layout resource. The resource will be
* inflated, adding all top-level views to the activity.
@@ -1645,6 +1718,7 @@
*/
public void setContentView(int layoutResID) {
getWindow().setContentView(layoutResID);
+ initActionBar();
}
/**
@@ -1656,6 +1730,7 @@
*/
public void setContentView(View view) {
getWindow().setContentView(view);
+ initActionBar();
}
/**
@@ -1668,6 +1743,7 @@
*/
public void setContentView(View view, ViewGroup.LayoutParams params) {
getWindow().setContentView(view, params);
+ initActionBar();
}
/**
@@ -1679,6 +1755,7 @@
*/
public void addContentView(View view, ViewGroup.LayoutParams params) {
getWindow().addContentView(view, params);
+ initActionBar();
}
/**
@@ -1902,12 +1979,25 @@
}
/**
+ * Pop the last fragment transition from the local activity's fragment
+ * back stack. If there is nothing to pop, false is returned.
+ * @param name If non-null, this is the name of a previous back state
+ * to look for; if found, all states up to (but not including) that
+ * state will be popped. If null, only the top state is popped.
+ */
+ public boolean popBackStack(String name) {
+ return mFragments.popBackStackState(mHandler, name);
+ }
+
+ /**
* Called when the activity has detected the user's press of the back
* key. The default implementation simply finishes the current activity,
* but you can override this to do whatever you want.
*/
public void onBackPressed() {
- finish();
+ if (!popBackStack(null)) {
+ finish();
+ }
}
/**
@@ -1977,6 +2067,13 @@
}
public void onContentChanged() {
+ // First time content is available, let the fragment manager
+ // attach all of the fragments to it. Don't do this if the
+ // activity is no longer attached (because it is being destroyed).
+ if (mFragments.mCurState < Fragment.CONTENT
+ && mFragments.mActivity != null) {
+ mFragments.moveToState(Fragment.CONTENT, false);
+ }
}
/**
@@ -3066,6 +3163,36 @@
}
/**
+ * This is called when a Fragment in this activity calls its
+ * {@link Fragment#startActivity} or {@link Fragment#startActivityForResult}
+ * method.
+ *
+ * <p>This method throws {@link android.content.ActivityNotFoundException}
+ * if there was no Activity found to run the given Intent.
+ *
+ * @param fragment The fragment making the call.
+ * @param intent The intent to start.
+ * @param requestCode Reply request code. < 0 if reply is not requested.
+ *
+ * @throws android.content.ActivityNotFoundException
+ *
+ * @see Fragment#startActivity
+ * @see Fragment#startActivityForResult
+ */
+ public void startActivityFromFragment(Fragment fragment, Intent intent,
+ int requestCode) {
+ Instrumentation.ActivityResult ar =
+ mInstrumentation.execStartActivity(
+ this, mMainThread.getApplicationThread(), mToken, fragment,
+ intent, requestCode);
+ if (ar != null) {
+ mMainThread.sendActivityResult(
+ mToken, fragment.mWho, requestCode,
+ ar.getResultCode(), ar.getResultData());
+ }
+ }
+
+ /**
* Like {@link #startActivityFromChild(Activity, Intent, int)}, but
* taking a IntentSender; see
* {@link #startIntentSenderForResult(IntentSender, int, Intent, int, int, int)}
@@ -3224,6 +3351,19 @@
}
/**
+ * Check to see whether this activity is in the process of being destroyed in order to be
+ * recreated with a new configuration. This is often used in
+ * {@link #onStop} to determine whether the state needs to be cleaned up or will be passed
+ * on to the next instance of the activity via {@link #onRetainNonConfigurationInstance()}.
+ *
+ * @return If the activity is being torn down in order to be recreated with a new configuration,
+ * returns true; else returns false.
+ */
+ public boolean isChangingConfigurations() {
+ return mChangingConfigurations;
+ }
+
+ /**
* Call this when your activity is done and should be closed. The
* ActivityResult is propagated back to whoever launched you via
* onActivityResult().
@@ -3324,8 +3464,7 @@
* @see #createPendingResult
* @see #setResult(int)
*/
- protected void onActivityResult(int requestCode, int resultCode,
- Intent data) {
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
}
/**
@@ -3709,15 +3848,68 @@
}
/**
- * Stub implementation of {@link android.view.LayoutInflater.Factory#onCreateView} used when
- * inflating with the LayoutInflater returned by {@link #getSystemService}. This
- * implementation simply returns null for all view names.
+ * Standard implementation of
+ * {@link android.view.LayoutInflater.Factory#onCreateView} used when
+ * inflating with the LayoutInflater returned by {@link #getSystemService}.
+ * This implementation handles <fragment> tags to embed fragments inside
+ * of the activity.
*
* @see android.view.LayoutInflater#createView
* @see android.view.Window#getLayoutInflater
*/
public View onCreateView(String name, Context context, AttributeSet attrs) {
- return null;
+ if (!"fragment".equals(name)) {
+ return null;
+ }
+
+ TypedArray a =
+ context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.Fragment);
+ String fname = a.getString(com.android.internal.R.styleable.Fragment_name);
+ int id = a.getResourceId(com.android.internal.R.styleable.Fragment_id, 0);
+ String tag = a.getString(com.android.internal.R.styleable.Fragment_tag);
+ a.recycle();
+
+ if (id == 0) {
+ throw new IllegalArgumentException(attrs.getPositionDescription()
+ + ": Must specify unique android:id for " + fname);
+ }
+
+ try {
+ // If we restored from a previous state, we may already have
+ // instantiated this fragment from the state and should use
+ // that instance instead of making a new one.
+ Fragment fragment = mFragments.findFragmentById(id);
+ if (FragmentManager.DEBUG) Log.v(TAG, "onCreateView: id=0x"
+ + Integer.toHexString(id) + " fname=" + fname
+ + " existing=" + fragment);
+ if (fragment == null) {
+ fragment = Fragment.instantiate(this, fname);
+ fragment.mFromLayout = true;
+ fragment.mFragmentId = id;
+ fragment.mTag = tag;
+ mFragments.addFragment(fragment, true);
+ }
+ // If this fragment is newly instantiated (either right now, or
+ // from last saved state), then give it the attributes to
+ // initialize itself.
+ if (!fragment.mRetaining) {
+ fragment.onInflate(this, attrs, fragment.mSavedFragmentState);
+ }
+ if (fragment.mView == null) {
+ throw new IllegalStateException("Fragment " + fname
+ + " did not create a view.");
+ }
+ fragment.mView.setId(id);
+ if (fragment.mView.getTag() == null) {
+ fragment.mView.setTag(tag);
+ }
+ return fragment.mView;
+ } catch (Exception e) {
+ InflateException ie = new InflateException(attrs.getPositionDescription()
+ + ": Error inflating fragment " + fname);
+ ie.initCause(e);
+ throw ie;
+ }
}
// ------------------ Internal API ------------------
@@ -3728,23 +3920,25 @@
final void attach(Context context, ActivityThread aThread, Instrumentation instr, IBinder token,
Application application, Intent intent, ActivityInfo info, CharSequence title,
- Activity parent, String id, Object lastNonConfigurationInstance,
+ Activity parent, String id, NonConfigurationInstances lastNonConfigurationInstances,
Configuration config) {
attach(context, aThread, instr, token, 0, application, intent, info, title, parent, id,
- lastNonConfigurationInstance, null, config);
+ lastNonConfigurationInstances, config);
}
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
- Object lastNonConfigurationInstance,
- HashMap<String,Object> lastNonConfigurationChildInstances,
+ NonConfigurationInstances lastNonConfigurationInstances,
Configuration config) {
attachBaseContext(context);
+ mFragments.attachActivity(this);
+
mWindow = PolicyManager.makeNewWindow(this);
mWindow.setCallback(this);
+ mWindow.getLayoutInflater().setFactory(this);
if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
mWindow.setSoftInputMode(info.softInputMode);
}
@@ -3761,8 +3955,7 @@
mTitle = title;
mParent = parent;
mEmbeddedID = id;
- mLastNonConfigurationInstance = lastNonConfigurationInstance;
- mLastNonConfigurationChildInstances = lastNonConfigurationChildInstances;
+ mLastNonConfigurationInstances = lastNonConfigurationInstances;
mWindow.setWindowManager(null, mToken, mComponent.flattenToString());
if (mParent != null) {
@@ -3776,6 +3969,10 @@
return mParent != null ? mParent.getActivityToken() : mToken;
}
+ final void performCreate(Bundle icicle) {
+ onCreate(icicle);
+ }
+
final void performStart() {
mCalled = false;
mInstrumentation.callActivityOnStart(this);
@@ -3784,6 +3981,7 @@
"Activity " + mComponent.toShortString() +
" did not call through to super.onStart()");
}
+ mFragments.dispatchStart();
}
final void performRestart() {
@@ -3815,7 +4013,7 @@
final void performResume() {
performRestart();
- mLastNonConfigurationInstance = null;
+ mLastNonConfigurationInstances = null;
// First call onResume() -before- setting mResumed, so we don't
// send out any status bar / menu notifications the client makes.
@@ -3830,6 +4028,9 @@
// Now really resume, and install the current status bar and menu.
mResumed = true;
mCalled = false;
+
+ mFragments.dispatchResume();
+
onPostResume();
if (!mCalled) {
throw new SuperNotCalledException(
@@ -3839,6 +4040,7 @@
}
final void performPause() {
+ mFragments.dispatchPause();
onPause();
}
@@ -3853,6 +4055,8 @@
mWindow.closeAllPanels();
}
+ mFragments.dispatchStop();
+
mCalled = false;
mInstrumentation.callActivityOnStop(this);
if (!mCalled) {
@@ -3877,6 +4081,11 @@
mResumed = false;
}
+ final void performDestroy() {
+ mFragments.dispatchDestroy();
+ onDestroy();
+ }
+
final boolean isResumed() {
return mResumed;
}
@@ -3888,6 +4097,11 @@
+ ", resCode=" + resultCode + ", data=" + data);
if (who == null) {
onActivityResult(requestCode, resultCode, data);
+ } else {
+ Fragment frag = mFragments.findFragmentByWho(who);
+ if (frag != null) {
+ frag.onActivityResult(requestCode, resultCode, data);
+ }
}
}
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 773c344..1f2fa26 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1300,8 +1300,7 @@
Window window;
Activity parent;
String embeddedID;
- Object lastNonConfigurationInstance;
- HashMap<String,Object> lastNonConfigurationChildInstances;
+ Activity.NonConfigurationInstances lastNonConfigurationInstances;
boolean paused;
boolean stopped;
boolean hideForNow;
@@ -1466,7 +1465,7 @@
private static final String HEAP_COLUMN = "%17s %8s %8s %8s %8s";
private static final String ONE_COUNT_COLUMN = "%17s %8d";
private static final String TWO_COUNT_COLUMNS = "%17s %8d %17s %8d";
- private static final String DB_INFO_FORMAT = " %8d %8d %10d %s";
+ private static final String DB_INFO_FORMAT = " %4d %6d %8d %14s %s";
// Formatting for checkin service - update version if row format changes
private static final int ACTIVITY_THREAD_CHECKIN_VERSION = 1;
@@ -1870,7 +1869,7 @@
for (int i = 0; i < stats.dbStats.size(); i++) {
DbStats dbStats = stats.dbStats.get(i);
printRow(pw, DB_INFO_FORMAT, dbStats.pageSize, dbStats.dbSize,
- dbStats.lookaside, dbStats.dbName);
+ dbStats.lookaside, dbStats.cache, dbStats.dbName);
pw.print(',');
}
@@ -1921,11 +1920,12 @@
int N = stats.dbStats.size();
if (N > 0) {
pw.println(" DATABASES");
- printRow(pw, " %8s %8s %10s %s", "Pagesize", "Dbsize", "Lookaside", "Dbname");
+ printRow(pw, " %4s %6s %8s %14s %s", "pgsz", "dbsz", "lkaside", "cache",
+ "Dbname");
for (int i = 0; i < N; i++) {
DbStats dbStats = stats.dbStats.get(i);
printRow(pw, DB_INFO_FORMAT, dbStats.pageSize, dbStats.dbSize,
- dbStats.lookaside, dbStats.dbName);
+ dbStats.lookaside, dbStats.cache, dbStats.dbName);
}
}
@@ -2478,7 +2478,7 @@
public final Activity startActivityNow(Activity parent, String id,
Intent intent, ActivityInfo activityInfo, IBinder token, Bundle state,
- Object lastNonConfigurationInstance) {
+ Activity.NonConfigurationInstances lastNonConfigurationInstances) {
ActivityRecord r = new ActivityRecord();
r.token = token;
r.ident = 0;
@@ -2487,7 +2487,7 @@
r.parent = parent;
r.embeddedID = id;
r.activityInfo = activityInfo;
- r.lastNonConfigurationInstance = lastNonConfigurationInstance;
+ r.lastNonConfigurationInstances = lastNonConfigurationInstances;
if (localLOGV) {
ComponentName compname = intent.getComponent();
String name;
@@ -2609,14 +2609,12 @@
+ r.activityInfo.name + " with config " + config);
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
- r.embeddedID, r.lastNonConfigurationInstance,
- r.lastNonConfigurationChildInstances, config);
+ r.embeddedID, r.lastNonConfigurationInstances, config);
if (customIntent != null) {
activity.mIntent = customIntent;
}
- r.lastNonConfigurationInstance = null;
- r.lastNonConfigurationChildInstances = null;
+ r.lastNonConfigurationInstances = null;
activity.mStartedActivity = false;
int theme = r.activityInfo.getThemeResource();
if (theme != 0) {
@@ -3574,6 +3572,9 @@
if (finishing) {
r.activity.mFinished = true;
}
+ if (getNonConfigInstance) {
+ r.activity.mChangingConfigurations = true;
+ }
if (!r.paused) {
try {
r.activity.mCalled = false;
@@ -3614,8 +3615,8 @@
}
if (getNonConfigInstance) {
try {
- r.lastNonConfigurationInstance
- = r.activity.onRetainNonConfigurationInstance();
+ r.lastNonConfigurationInstances
+ = r.activity.retainNonConfigurationInstances();
} catch (Exception e) {
if (!mInstrumentation.onException(r.activity, e)) {
throw new RuntimeException(
@@ -3624,22 +3625,10 @@
+ ": " + e.toString(), e);
}
}
- try {
- r.lastNonConfigurationChildInstances
- = r.activity.onRetainNonConfigurationChildInstances();
- } catch (Exception e) {
- if (!mInstrumentation.onException(r.activity, e)) {
- throw new RuntimeException(
- "Unable to retain child activities "
- + safeToComponentShortString(r.intent)
- + ": " + e.toString(), e);
- }
- }
-
}
try {
r.activity.mCalled = false;
- r.activity.onDestroy();
+ mInstrumentation.callActivityOnDestroy(r.activity);
if (!r.activity.mCalled) {
throw new SuperNotCalledException(
"Activity " + safeToComponentShortString(r.intent) +
diff --git a/core/java/android/app/BackStackEntry.java b/core/java/android/app/BackStackEntry.java
new file mode 100644
index 0000000..33e456d
--- /dev/null
+++ b/core/java/android/app/BackStackEntry.java
@@ -0,0 +1,379 @@
+/*
+ * 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.app;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+
+final class BackStackState implements Parcelable {
+ final int[] mOps;
+ final int mTransition;
+ final int mTransitionStyle;
+ final String mName;
+
+ public BackStackState(FragmentManager fm, BackStackEntry bse) {
+ mOps = new int[bse.mNumOp*4];
+ BackStackEntry.Op op = bse.mHead;
+ int pos = 0;
+ while (op != null) {
+ mOps[pos++] = op.cmd;
+ mOps[pos++] = op.fragment.mIndex;
+ mOps[pos++] = op.enterAnim;
+ mOps[pos++] = op.exitAnim;
+ op = op.next;
+ }
+ mTransition = bse.mTransition;
+ mTransitionStyle = bse.mTransitionStyle;
+ mName = bse.mName;
+ }
+
+ public BackStackState(Parcel in) {
+ mOps = in.createIntArray();
+ mTransition = in.readInt();
+ mTransitionStyle = in.readInt();
+ mName = in.readString();
+ }
+
+ public BackStackEntry instantiate(FragmentManager fm) {
+ BackStackEntry bse = new BackStackEntry(fm);
+ int pos = 0;
+ while (pos < mOps.length) {
+ BackStackEntry.Op op = new BackStackEntry.Op();
+ op.cmd = mOps[pos++];
+ Fragment f = fm.mActive.get(mOps[pos++]);
+ f.mBackStackNesting++;
+ op.fragment = f;
+ op.enterAnim = mOps[pos++];
+ op.exitAnim = mOps[pos++];
+ bse.addOp(op);
+ }
+ bse.mTransition = mTransition;
+ bse.mTransitionStyle = mTransitionStyle;
+ bse.mName = mName;
+ return bse;
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeIntArray(mOps);
+ dest.writeInt(mTransition);
+ dest.writeInt(mTransitionStyle);
+ dest.writeString(mName);
+ }
+
+ public static final Parcelable.Creator<BackStackState> CREATOR
+ = new Parcelable.Creator<BackStackState>() {
+ public BackStackState createFromParcel(Parcel in) {
+ return new BackStackState(in);
+ }
+
+ public BackStackState[] newArray(int size) {
+ return new BackStackState[size];
+ }
+ };
+}
+
+/**
+ * @hide Entry of an operation on the fragment back stack.
+ */
+final class BackStackEntry implements FragmentTransaction, Runnable {
+ final FragmentManager mManager;
+
+ static final int OP_NULL = 0;
+ static final int OP_ADD = 1;
+ static final int OP_REMOVE = 2;
+ static final int OP_HIDE = 3;
+ static final int OP_SHOW = 4;
+
+ static final class Op {
+ Op next;
+ Op prev;
+ int cmd;
+ Fragment fragment;
+ int enterAnim;
+ int exitAnim;
+ }
+
+ Op mHead;
+ Op mTail;
+ int mNumOp;
+ int mEnterAnim;
+ int mExitAnim;
+ int mTransition;
+ int mTransitionStyle;
+ boolean mAddToBackStack;
+ String mName;
+ boolean mCommitted;
+
+ public BackStackEntry(FragmentManager manager) {
+ mManager = manager;
+ }
+
+ void addOp(Op op) {
+ if (mHead == null) {
+ mHead = mTail = op;
+ } else {
+ op.prev = mTail;
+ mTail.next = op;
+ mTail = op;
+ }
+ op.enterAnim = mEnterAnim;
+ op.exitAnim = mExitAnim;
+ mNumOp++;
+ }
+
+ public FragmentTransaction add(Fragment fragment, String tag) {
+ return add(0, fragment, tag);
+ }
+
+ public FragmentTransaction add(int containerViewId, Fragment fragment) {
+ return add(containerViewId, fragment, null);
+ }
+
+ public FragmentTransaction add(int containerViewId, Fragment fragment, String tag) {
+ if (fragment.mActivity != null) {
+ throw new IllegalStateException("Fragment already added: " + fragment);
+ }
+
+ if (tag != null) {
+ if (fragment.mTag != null && !tag.equals(fragment.mTag)) {
+ throw new IllegalStateException("Can't change tag of fragment "
+ + fragment + ": was " + fragment.mTag
+ + " now " + tag);
+ }
+ fragment.mTag = tag;
+ }
+
+ if (containerViewId != 0) {
+ if (fragment.mFragmentId != 0 && fragment.mFragmentId != containerViewId) {
+ throw new IllegalStateException("Can't change container ID of fragment "
+ + fragment + ": was " + fragment.mFragmentId
+ + " now " + containerViewId);
+ }
+ fragment.mContainerId = fragment.mFragmentId = containerViewId;
+ }
+
+ Op op = new Op();
+ op.cmd = OP_ADD;
+ op.fragment = fragment;
+ addOp(op);
+
+ return this;
+ }
+
+ public FragmentTransaction replace(int containerViewId, Fragment fragment) {
+ return replace(containerViewId, fragment, null);
+ }
+
+ public FragmentTransaction replace(int containerViewId, Fragment fragment, String tag) {
+ if (containerViewId == 0) {
+ throw new IllegalArgumentException("Must use non-zero containerViewId");
+ }
+ if (mManager.mAdded != null) {
+ for (int i=0; i<mManager.mAdded.size(); i++) {
+ Fragment old = mManager.mAdded.get(i);
+ if (old.mContainerId == containerViewId) {
+ remove(old);
+ }
+ }
+ }
+ return add(containerViewId, fragment, tag);
+ }
+
+ public FragmentTransaction remove(Fragment fragment) {
+ if (fragment.mActivity == null) {
+ throw new IllegalStateException("Fragment not added: " + fragment);
+ }
+
+ Op op = new Op();
+ op.cmd = OP_REMOVE;
+ op.fragment = fragment;
+ addOp(op);
+
+ return this;
+ }
+
+ public FragmentTransaction hide(Fragment fragment) {
+ if (fragment.mActivity == null) {
+ throw new IllegalStateException("Fragment not added: " + fragment);
+ }
+
+ Op op = new Op();
+ op.cmd = OP_HIDE;
+ op.fragment = fragment;
+ addOp(op);
+
+ return this;
+ }
+
+ public FragmentTransaction show(Fragment fragment) {
+ if (fragment.mActivity == null) {
+ throw new IllegalStateException("Fragment not added: " + fragment);
+ }
+
+ Op op = new Op();
+ op.cmd = OP_SHOW;
+ op.fragment = fragment;
+ addOp(op);
+
+ return this;
+ }
+
+ public FragmentTransaction setCustomAnimations(int enter, int exit) {
+ mEnterAnim = enter;
+ mExitAnim = exit;
+ return this;
+ }
+
+ public FragmentTransaction setTransition(int transition) {
+ mTransition = transition;
+ return this;
+ }
+
+ public FragmentTransaction setTransitionStyle(int styleRes) {
+ mTransitionStyle = styleRes;
+ return this;
+ }
+
+ public FragmentTransaction addToBackStack(String name) {
+ mAddToBackStack = true;
+ mName = name;
+ return this;
+ }
+
+ public void commit() {
+ if (mCommitted) throw new IllegalStateException("commit already called");
+ mCommitted = true;
+ mManager.mActivity.mHandler.post(this);
+ }
+
+ public void run() {
+ Op op = mHead;
+ while (op != null) {
+ switch (op.cmd) {
+ case OP_ADD: {
+ Fragment f = op.fragment;
+ if (mAddToBackStack) {
+ f.mBackStackNesting++;
+ }
+ f.mNextAnim = op.enterAnim;
+ mManager.addFragment(f, false);
+ } break;
+ case OP_REMOVE: {
+ Fragment f = op.fragment;
+ if (mAddToBackStack) {
+ f.mBackStackNesting++;
+ }
+ f.mNextAnim = op.exitAnim;
+ mManager.removeFragment(f, mTransition, mTransitionStyle);
+ } break;
+ case OP_HIDE: {
+ Fragment f = op.fragment;
+ if (mAddToBackStack) {
+ f.mBackStackNesting++;
+ }
+ f.mNextAnim = op.exitAnim;
+ mManager.hideFragment(f, mTransition, mTransitionStyle);
+ } break;
+ case OP_SHOW: {
+ Fragment f = op.fragment;
+ if (mAddToBackStack) {
+ f.mBackStackNesting++;
+ }
+ f.mNextAnim = op.enterAnim;
+ mManager.showFragment(f, mTransition, mTransitionStyle);
+ } break;
+ default: {
+ throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
+ }
+ }
+
+ op = op.next;
+ }
+
+ mManager.moveToState(mManager.mCurState, mTransition,
+ mTransitionStyle, true);
+ if (mAddToBackStack) {
+ mManager.addBackStackState(this);
+ }
+ }
+
+ public void popFromBackStack() {
+ Op op = mTail;
+ while (op != null) {
+ switch (op.cmd) {
+ case OP_ADD: {
+ Fragment f = op.fragment;
+ if (mAddToBackStack) {
+ f.mBackStackNesting--;
+ }
+ mManager.removeFragment(f,
+ FragmentManager.reverseTransit(mTransition),
+ mTransitionStyle);
+ } break;
+ case OP_REMOVE: {
+ Fragment f = op.fragment;
+ if (mAddToBackStack) {
+ f.mBackStackNesting--;
+ }
+ mManager.addFragment(f, false);
+ } break;
+ case OP_HIDE: {
+ Fragment f = op.fragment;
+ if (mAddToBackStack) {
+ f.mBackStackNesting--;
+ }
+ mManager.showFragment(f,
+ FragmentManager.reverseTransit(mTransition), mTransitionStyle);
+ } break;
+ case OP_SHOW: {
+ Fragment f = op.fragment;
+ if (mAddToBackStack) {
+ f.mBackStackNesting--;
+ }
+ mManager.hideFragment(f,
+ FragmentManager.reverseTransit(mTransition), mTransitionStyle);
+ } break;
+ default: {
+ throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
+ }
+ }
+
+ op = op.prev;
+ }
+
+ mManager.moveToState(mManager.mCurState,
+ FragmentManager.reverseTransit(mTransition), mTransitionStyle, true);
+ }
+
+ public String getName() {
+ return mName;
+ }
+
+ public int getTransition() {
+ return mTransition;
+ }
+
+ public int getTransitionStyle() {
+ return mTransitionStyle;
+ }
+}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 11b7b02..1be05b2 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -57,6 +57,7 @@
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
+import android.database.DatabaseErrorHandler;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.graphics.Bitmap;
@@ -543,6 +544,15 @@
}
@Override
+ public SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory,
+ DatabaseErrorHandler errorHandler) {
+ File f = validateFilePath(name, true);
+ SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(f.getPath(), factory, errorHandler);
+ setFilePermissionsFromMode(f.getPath(), mode, 0);
+ return db;
+ }
+
+ @Override
public boolean deleteDatabase(String name) {
try {
File f = validateFilePath(name, false);
@@ -620,7 +630,8 @@
+ " Is this really what you want?");
}
mMainThread.getInstrumentation().execStartActivity(
- getOuterContext(), mMainThread.getApplicationThread(), null, null, intent, -1);
+ getOuterContext(), mMainThread.getApplicationThread(), null,
+ (Activity)null, intent, -1);
}
@Override
@@ -2733,6 +2744,13 @@
return v != null ? v : defValue;
}
}
+
+ public Set<String> getStringSet(String key, Set<String> defValues) {
+ synchronized (this) {
+ Set<String> v = (Set<String>) mMap.get(key);
+ return v != null ? v : defValues;
+ }
+ }
public int getInt(String key, int defValue) {
synchronized (this) {
@@ -2775,6 +2793,12 @@
return this;
}
}
+ public Editor putStringSet(String key, Set<String> values) {
+ synchronized (this) {
+ mModified.put(key, values);
+ return this;
+ }
+ }
public Editor putInt(String key, int value) {
synchronized (this) {
mModified.put(key, value);
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
new file mode 100644
index 0000000..58ae2d5
--- /dev/null
+++ b/core/java/android/app/Fragment.java
@@ -0,0 +1,529 @@
+/*
+ * 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.app;
+
+import android.content.ComponentCallbacks;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.AttributeSet;
+import android.util.SparseArray;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.Animation;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.HashMap;
+
+final class FragmentState implements Parcelable {
+ static final String VIEW_STATE_TAG = "android:view_state";
+
+ final String mClassName;
+ final int mIndex;
+ final boolean mFromLayout;
+ final int mFragmentId;
+ final int mContainerId;
+ final String mTag;
+ final boolean mRetainInstance;
+
+ Bundle mSavedFragmentState;
+
+ Fragment mInstance;
+
+ public FragmentState(Fragment frag) {
+ mClassName = frag.getClass().getName();
+ mIndex = frag.mIndex;
+ mFromLayout = frag.mFromLayout;
+ mFragmentId = frag.mFragmentId;
+ mContainerId = frag.mContainerId;
+ mTag = frag.mTag;
+ mRetainInstance = frag.mRetainInstance;
+ }
+
+ public FragmentState(Parcel in) {
+ mClassName = in.readString();
+ mIndex = in.readInt();
+ mFromLayout = in.readInt() != 0;
+ mFragmentId = in.readInt();
+ mContainerId = in.readInt();
+ mTag = in.readString();
+ mRetainInstance = in.readInt() != 0;
+ mSavedFragmentState = in.readBundle();
+ }
+
+ public Fragment instantiate(Activity activity) {
+ if (mInstance != null) {
+ return mInstance;
+ }
+
+ try {
+ mInstance = Fragment.instantiate(activity, mClassName);
+ } catch (Exception e) {
+ throw new RuntimeException("Unable to restore fragment " + mClassName, e);
+ }
+
+ if (mSavedFragmentState != null) {
+ mSavedFragmentState.setClassLoader(activity.getClassLoader());
+ mInstance.mSavedFragmentState = mSavedFragmentState;
+ mInstance.mSavedViewState
+ = mSavedFragmentState.getSparseParcelableArray(VIEW_STATE_TAG);
+ }
+ mInstance.setIndex(mIndex);
+ mInstance.mFromLayout = mFromLayout;
+ mInstance.mFragmentId = mFragmentId;
+ mInstance.mContainerId = mContainerId;
+ mInstance.mTag = mTag;
+ mInstance.mRetainInstance = mRetainInstance;
+
+ return mInstance;
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mClassName);
+ dest.writeInt(mIndex);
+ dest.writeInt(mFromLayout ? 1 : 0);
+ dest.writeInt(mFragmentId);
+ dest.writeInt(mContainerId);
+ dest.writeString(mTag);
+ dest.writeInt(mRetainInstance ? 1 : 0);
+ dest.writeBundle(mSavedFragmentState);
+ }
+
+ public static final Parcelable.Creator<FragmentState> CREATOR
+ = new Parcelable.Creator<FragmentState>() {
+ public FragmentState createFromParcel(Parcel in) {
+ return new FragmentState(in);
+ }
+
+ public FragmentState[] newArray(int size) {
+ return new FragmentState[size];
+ }
+ };
+}
+
+/**
+ * A Fragment is a piece of an application's user interface or behavior
+ * that can be placed in an {@link Activity}.
+ */
+public class Fragment implements ComponentCallbacks {
+ private static final HashMap<String, Class> sClassMap =
+ new HashMap<String, Class>();
+
+ static final int INITIALIZING = 0; // Not yet created.
+ static final int CREATED = 1; // Created.
+ static final int CONTENT = 2; // View hierarchy content available.
+ static final int STARTED = 3; // Created and started, not resumed.
+ static final int RESUMED = 4; // Created started and resumed.
+
+ int mState = INITIALIZING;
+
+ // When instantiated from saved state, this is the saved state.
+ Bundle mSavedFragmentState;
+ SparseArray<Parcelable> mSavedViewState;
+
+ // Index into active fragment array.
+ int mIndex = -1;
+
+ // Internal unique name for this fragment;
+ String mWho;
+
+ // True if the fragment is in the list of added fragments.
+ boolean mAdded;
+
+ // Set to true if this fragment was instantiated from a layout file.
+ boolean mFromLayout;
+
+ // Number of active back stack entries this fragment is in.
+ int mBackStackNesting;
+
+ // Activity this fragment is attached to.
+ Activity mActivity;
+
+ // The optional identifier for this fragment -- either the container ID if it
+ // was dynamically added to the view hierarchy, or the ID supplied in
+ // layout.
+ int mFragmentId;
+
+ // When a fragment is being dynamically added to the view hierarchy, this
+ // is the identifier of the parent container it is being added to.
+ int mContainerId;
+
+ // The optional named tag for this fragment -- usually used to find
+ // fragments that are not part of the layout.
+ String mTag;
+
+ // Set to true when the app has requested that this fragment be hidden
+ // from the user.
+ boolean mHidden;
+
+ // If set this fragment would like its instance retained across
+ // configuration changes.
+ boolean mRetainInstance;
+
+ // If set this fragment is being retained across the current config change.
+ boolean mRetaining;
+
+ // Used to verify that subclasses call through to super class.
+ boolean mCalled;
+
+ // If app has requested a specific animation, this is the one to use.
+ int mNextAnim;
+
+ // The parent container of the fragment after dynamically added to UI.
+ ViewGroup mContainer;
+
+ // The View generated for this fragment.
+ View mView;
+
+ public Fragment() {
+ }
+
+ static Fragment instantiate(Activity activity, String fname)
+ throws NoSuchMethodException, ClassNotFoundException,
+ IllegalArgumentException, InstantiationException,
+ IllegalAccessException, InvocationTargetException {
+ Class clazz = sClassMap.get(fname);
+
+ if (clazz == null) {
+ // Class not found in the cache, see if it's real, and try to add it
+ clazz = activity.getClassLoader().loadClass(fname);
+ sClassMap.put(fname, clazz);
+ }
+ return (Fragment)clazz.newInstance();
+ }
+
+ void restoreViewState() {
+ if (mSavedViewState != null) {
+ mView.restoreHierarchyState(mSavedViewState);
+ mSavedViewState = null;
+ }
+ }
+
+ void setIndex(int index) {
+ mIndex = index;
+ mWho = "android:fragment:" + mIndex;
+ }
+
+ void clearIndex() {
+ mIndex = -1;
+ mWho = null;
+ }
+
+ /**
+ * Subclasses can not override equals().
+ */
+ @Override final public boolean equals(Object o) {
+ return super.equals(o);
+ }
+
+ /**
+ * Subclasses can not override hashCode().
+ */
+ @Override final public int hashCode() {
+ return super.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder(128);
+ sb.append("Fragment{");
+ sb.append(Integer.toHexString(System.identityHashCode(this)));
+ if (mIndex >= 0) {
+ sb.append(" #");
+ sb.append(mIndex);
+ }
+ if (mFragmentId != 0) {
+ sb.append(" id=0x");
+ sb.append(Integer.toHexString(mFragmentId));
+ }
+ if (mTag != null) {
+ sb.append(" ");
+ sb.append(mTag);
+ }
+ sb.append('}');
+ return sb.toString();
+ }
+
+ /**
+ * Return the identifier this fragment is known by. This is either
+ * the android:id value supplied in a layout or the container view ID
+ * supplied when adding the fragment.
+ */
+ public int getId() {
+ return mFragmentId;
+ }
+
+ /**
+ * Get the tag name of the fragment, if specified.
+ */
+ public String getTag() {
+ return mTag;
+ }
+
+ /**
+ * Return the Activity this fragment is currently associated with.
+ */
+ public Activity getActivity() {
+ return mActivity;
+ }
+
+ /**
+ * Return true if the fragment is currently added to its activity.
+ */
+ public boolean isAdded() {
+ return mActivity != null && mActivity.mFragments.mAdded.contains(this);
+ }
+
+ /**
+ * Return true if the fragment is currently visible to the user. This means
+ * it: (1) has been added, (2) has its view attached to the window, and
+ * (3) is not hidden.
+ */
+ public boolean isVisible() {
+ return isAdded() && !isHidden() && mView != null
+ && mView.getWindowToken() != null && mView.getVisibility() == View.VISIBLE;
+ }
+
+ /**
+ * Return true if the fragment has been hidden. By default fragments
+ * are shown. You can find out about changes to this state with
+ * {@link #onHiddenChanged}. Note that the hidden state is orthogonal
+ * to other states -- that is, to be visible to the user, a fragment
+ * must be both started and not hidden.
+ */
+ public boolean isHidden() {
+ return mHidden;
+ }
+
+ /**
+ * Called when the hidden state (as returned by {@link #isHidden()} of
+ * the fragment has changed. Fragments start out not hidden; this will
+ * be called whenever the fragment changes state from that.
+ * @param hidden True if the fragment is now hidden, false if it is not
+ * visible.
+ */
+ public void onHiddenChanged(boolean hidden) {
+ }
+
+ /**
+ * Control whether a fragment instance is retained across Activity
+ * re-creation (such as from a configuration change). This can only
+ * be used with fragments not in the back stack. If set, the fragment
+ * lifecycle will be slightly different when an activity is recreated:
+ * <ul>
+ * <li> {@link #onDestroy()} will not be called (but {@link #onDetach()} still
+ * will be, because the fragment is being detached from its current activity).
+ * <li> {@link #onCreate(Bundle)} will not be called since the fragment
+ * is not being re-created.
+ * <li> {@link #onAttach(Activity)} and {@link #onReady(Bundle)} <b>will</b>
+ * still be called.
+ * </ul>
+ */
+ public void setRetainInstance(boolean retain) {
+ mRetainInstance = retain;
+ }
+
+ public boolean getRetainInstance() {
+ return mRetainInstance;
+ }
+
+ /**
+ * Call {@link Activity#startActivity(Intent)} on the fragment's
+ * containing Activity.
+ */
+ public void startActivity(Intent intent) {
+ mActivity.startActivityFromFragment(this, intent, -1);
+ }
+
+ /**
+ * Call {@link Activity#startActivityForResult(Intent, int)} on the fragment's
+ * containing Activity.
+ */
+ public void startActivityForResult(Intent intent, int requestCode) {
+ mActivity.startActivityFromFragment(this, intent, requestCode);
+ }
+
+ /**
+ * Receive the result from a previous call to
+ * {@link #startActivityForResult(Intent, int)}. This follows the
+ * related Activity API as described there in
+ * {@link Activity#onActivityResult(int, int, Intent)}.
+ *
+ * @param requestCode The integer request code originally supplied to
+ * startActivityForResult(), allowing you to identify who this
+ * result came from.
+ * @param resultCode The integer result code returned by the child activity
+ * through its setResult().
+ * @param data An Intent, which can return result data to the caller
+ * (various data can be attached to Intent "extras").
+ */
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ }
+
+ /**
+ * Called when a fragment is being created as part of a view layout
+ * inflation, typically from setting the content view of an activity. This
+ * will be called both the first time the fragment is created, as well
+ * later when it is being re-created from its saved state (which is also
+ * given here).
+ *
+ * XXX This is kind-of yucky... maybe we could just supply the
+ * AttributeSet to onCreate()?
+ *
+ * @param activity The Activity that is inflating the fragment.
+ * @param attrs The attributes at the tag where the fragment is
+ * being created.
+ * @param savedInstanceState If the fragment is being re-created from
+ * a previous saved state, this is the state.
+ */
+ public void onInflate(Activity activity, AttributeSet attrs,
+ Bundle savedInstanceState) {
+ mCalled = true;
+ }
+
+ /**
+ * Called when a fragment is first attached to its activity.
+ * {@link #onCreate(Bundle)} will be called after this.
+ */
+ public void onAttach(Activity activity) {
+ mCalled = true;
+ }
+
+ public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {
+ return null;
+ }
+
+ /**
+ * Called to do initial creation of a fragment. This is called after
+ * {@link #onAttach(Activity)} and before {@link #onReady(Bundle)}.
+ * @param savedInstanceState If the fragment is being re-created from
+ * a previous saved state, this is the state.
+ */
+ public void onCreate(Bundle savedInstanceState) {
+ mCalled = true;
+ }
+
+ /**
+ * Called to have the fragment instantiate its user interface view.
+ * This is optional, and non-graphical fragments can return null (which
+ * is the default implementation). This will be called between
+ * {@link #onCreate(Bundle)} and {@link #onReady(Bundle)}.
+ *
+ * @param inflater The LayoutInflater object that can be used to inflate
+ * any views in the fragment,
+ * @param container If non-null, this is the parent view that the fragment's
+ * UI should be attached to. The fragment should not add the view itself,
+ * but this can be used to generate the LayoutParams of the view.
+ * @param savedInstanceState If non-null, this fragment is being re-constructed
+ * from a previous saved state as given here.
+ *
+ * @return Return the View for the fragment's UI, or null.
+ */
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ return null;
+ }
+
+ public View getView() {
+ return mView;
+ }
+
+ /**
+ * Called when the activity is ready for the fragment to run. This is
+ * most useful for fragments that use {@link #setRetainInstance(boolean)}
+ * instance, as this tells the fragment when it is fully associated with
+ * the new activity instance. This is called after {@link #onCreate(Bundle)}
+ * and before {@link #onStart()}.
+ *
+ * @param savedInstanceState If the fragment is being re-created from
+ * a previous saved state, this is the state.
+ */
+ public void onReady(Bundle savedInstanceState) {
+ mCalled = true;
+ }
+
+ /**
+ * Called when the Fragment is visible to the user. This is generally
+ * tied to {@link Activity#onStart() Activity.onStart} of the containing
+ * Activity's lifecycle.
+ */
+ public void onStart() {
+ mCalled = true;
+ }
+
+ /**
+ * Called when the fragment is visible to the user and actively running.
+ * This is generally
+ * tied to {@link Activity#onResume() Activity.onResume} of the containing
+ * Activity's lifecycle.
+ */
+ public void onResume() {
+ mCalled = true;
+ }
+
+ public void onSaveInstanceState(Bundle outState) {
+ }
+
+ public void onConfigurationChanged(Configuration newConfig) {
+ mCalled = true;
+ }
+
+ /**
+ * Called when the Fragment is no longer resumed. This is generally
+ * tied to {@link Activity#onPause() Activity.onPause} of the containing
+ * Activity's lifecycle.
+ */
+ public void onPause() {
+ mCalled = true;
+ }
+
+ /**
+ * Called when the Fragment is no longer started. This is generally
+ * tied to {@link Activity#onStop() Activity.onStop} of the containing
+ * Activity's lifecycle.
+ */
+ public void onStop() {
+ mCalled = true;
+ }
+
+ public void onLowMemory() {
+ mCalled = true;
+ }
+
+ /**
+ * Called when the fragment is no longer in use. This is called
+ * after {@link #onStop()} and before {@link #onDetach()}.
+ */
+ public void onDestroy() {
+ mCalled = true;
+ }
+
+ /**
+ * Called when the fragment is no longer attached to its activity. This
+ * is called after {@link #onDestroy()}.
+ */
+ public void onDetach() {
+ mCalled = true;
+ }
+}
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
new file mode 100644
index 0000000..a10a191
--- /dev/null
+++ b/core/java/android/app/FragmentManager.java
@@ -0,0 +1,842 @@
+/*
+ * 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.app;
+
+import android.content.res.TypedArray;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
+
+import java.util.ArrayList;
+
+final class FragmentManagerState implements Parcelable {
+ FragmentState[] mActive;
+ int[] mAdded;
+ BackStackState[] mBackStack;
+
+ public FragmentManagerState() {
+ }
+
+ public FragmentManagerState(Parcel in) {
+ mActive = in.createTypedArray(FragmentState.CREATOR);
+ mAdded = in.createIntArray();
+ mBackStack = in.createTypedArray(BackStackState.CREATOR);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeTypedArray(mActive, flags);
+ dest.writeIntArray(mAdded);
+ dest.writeTypedArray(mBackStack, flags);
+ }
+
+ public static final Parcelable.Creator<FragmentManagerState> CREATOR
+ = new Parcelable.Creator<FragmentManagerState>() {
+ public FragmentManagerState createFromParcel(Parcel in) {
+ return new FragmentManagerState(in);
+ }
+
+ public FragmentManagerState[] newArray(int size) {
+ return new FragmentManagerState[size];
+ }
+ };
+}
+
+/**
+ * @hide
+ * Container for fragments associated with an activity.
+ */
+public class FragmentManager {
+ static final boolean DEBUG = true;
+ static final String TAG = "FragmentManager";
+
+ ArrayList<Fragment> mActive;
+ ArrayList<Fragment> mAdded;
+ ArrayList<Integer> mAvailIndices;
+ ArrayList<BackStackEntry> mBackStack;
+
+ int mCurState = Fragment.INITIALIZING;
+ Activity mActivity;
+
+ // Temporary vars for state save and restore.
+ Bundle mStateBundle = null;
+ SparseArray<Parcelable> mStateArray = null;
+
+ Animation loadAnimation(Fragment fragment, int transit, boolean enter,
+ int transitionStyle) {
+ Animation animObj = fragment.onCreateAnimation(transitionStyle, enter,
+ fragment.mNextAnim);
+ if (animObj != null) {
+ return animObj;
+ }
+
+ if (fragment.mNextAnim != 0) {
+ Animation anim = AnimationUtils.loadAnimation(mActivity, fragment.mNextAnim);
+ if (anim != null) {
+ return anim;
+ }
+ }
+
+ if (transit == 0) {
+ return null;
+ }
+
+ int styleIndex = transitToStyleIndex(transit, enter);
+ if (styleIndex < 0) {
+ return null;
+ }
+
+ if (transitionStyle == 0 && mActivity.getWindow() != null) {
+ transitionStyle = mActivity.getWindow().getAttributes().windowAnimations;
+ }
+ if (transitionStyle == 0) {
+ return null;
+ }
+
+ TypedArray attrs = mActivity.obtainStyledAttributes(transitionStyle,
+ com.android.internal.R.styleable.WindowAnimation);
+ int anim = attrs.getResourceId(styleIndex, 0);
+ attrs.recycle();
+
+ if (anim == 0) {
+ return null;
+ }
+
+ return AnimationUtils.loadAnimation(mActivity, anim);
+ }
+
+ void moveToState(Fragment f, int newState, int transit, int transitionStyle) {
+ // Fragments that are not currently added will sit in the onCreate() state.
+ if (!f.mAdded && newState > Fragment.CREATED) {
+ newState = Fragment.CREATED;
+ }
+
+ if (f.mState < newState) {
+ switch (f.mState) {
+ case Fragment.INITIALIZING:
+ if (DEBUG) Log.v(TAG, "moveto CREATED: " + f);
+ f.mActivity = mActivity;
+ f.mCalled = false;
+ f.onAttach(mActivity);
+ if (!f.mCalled) {
+ throw new SuperNotCalledException("Fragment " + f
+ + " did not call through to super.onAttach()");
+ }
+
+ if (!f.mRetaining) {
+ f.mCalled = false;
+ f.onCreate(f.mSavedFragmentState);
+ if (!f.mCalled) {
+ throw new SuperNotCalledException("Fragment " + f
+ + " did not call through to super.onCreate()");
+ }
+ }
+ f.mRetaining = false;
+ if (f.mFromLayout) {
+ // For fragments that are part of the content view
+ // layout, we need to instantiate the view immediately
+ // and the inflater will take care of adding it.
+ f.mView = f.onCreateView(mActivity.getLayoutInflater(),
+ null, f.mSavedFragmentState);
+ if (f.mView != null) {
+ f.mView.setSaveFromParentEnabled(false);
+ f.restoreViewState();
+ if (f.mHidden) f.mView.setVisibility(View.GONE);
+ }
+ }
+ case Fragment.CREATED:
+ if (newState > Fragment.CREATED) {
+ if (DEBUG) Log.v(TAG, "moveto CONTENT: " + f);
+ if (!f.mFromLayout) {
+ ViewGroup container = null;
+ if (f.mContainerId != 0) {
+ container = (ViewGroup)mActivity.findViewById(f.mContainerId);
+ if (container == null) {
+ throw new IllegalArgumentException("New view found for id 0x"
+ + Integer.toHexString(f.mContainerId)
+ + " for fragment " + f);
+ }
+ }
+ f.mContainer = container;
+ f.mView = f.onCreateView(mActivity.getLayoutInflater(),
+ container, f.mSavedFragmentState);
+ if (f.mView != null) {
+ f.mView.setSaveFromParentEnabled(false);
+ if (container != null) {
+ Animation anim = loadAnimation(f, transit, true,
+ transitionStyle);
+ if (anim != null) {
+ f.mView.setAnimation(anim);
+ }
+ container.addView(f.mView);
+ f.restoreViewState();
+ }
+ if (f.mHidden) f.mView.setVisibility(View.GONE);
+ }
+ }
+
+ f.mCalled = false;
+ f.onReady(f.mSavedFragmentState);
+ if (!f.mCalled) {
+ throw new SuperNotCalledException("Fragment " + f
+ + " did not call through to super.onReady()");
+ }
+ f.mSavedFragmentState = null;
+ }
+ case Fragment.CONTENT:
+ if (newState > Fragment.CONTENT) {
+ if (DEBUG) Log.v(TAG, "moveto STARTED: " + f);
+ f.mCalled = false;
+ f.onStart();
+ if (!f.mCalled) {
+ throw new SuperNotCalledException("Fragment " + f
+ + " did not call through to super.onStart()");
+ }
+ }
+ case Fragment.STARTED:
+ if (newState > Fragment.STARTED) {
+ if (DEBUG) Log.v(TAG, "moveto RESUMED: " + f);
+ f.mCalled = false;
+ f.onResume();
+ if (!f.mCalled) {
+ throw new SuperNotCalledException("Fragment " + f
+ + " did not call through to super.onResume()");
+ }
+ }
+ }
+ } else if (f.mState > newState) {
+ switch (f.mState) {
+ case Fragment.RESUMED:
+ if (newState < Fragment.RESUMED) {
+ if (DEBUG) Log.v(TAG, "movefrom RESUMED: " + f);
+ f.mCalled = false;
+ f.onPause();
+ if (!f.mCalled) {
+ throw new SuperNotCalledException("Fragment " + f
+ + " did not call through to super.onPause()");
+ }
+ }
+ case Fragment.STARTED:
+ if (newState < Fragment.STARTED) {
+ if (DEBUG) Log.v(TAG, "movefrom STARTED: " + f);
+ f.mCalled = false;
+ f.onStop();
+ if (!f.mCalled) {
+ throw new SuperNotCalledException("Fragment " + f
+ + " did not call through to super.onStop()");
+ }
+ }
+ case Fragment.CONTENT:
+ if (newState < Fragment.CONTENT) {
+ if (DEBUG) Log.v(TAG, "movefrom CONTENT: " + f);
+ if (f.mView != null) {
+ // Need to save the current view state if not
+ // done already.
+ if (!mActivity.isFinishing() && f.mSavedFragmentState == null) {
+ saveFragmentViewState(f);
+ }
+ if (f.mContainer != null) {
+ if (mCurState > Fragment.INITIALIZING) {
+ Animation anim = loadAnimation(f, transit, false,
+ transitionStyle);
+ if (anim != null) {
+ f.mView.setAnimation(anim);
+ }
+ }
+ f.mContainer.removeView(f.mView);
+ }
+ }
+ f.mContainer = null;
+ f.mView = null;
+ }
+ case Fragment.CREATED:
+ if (newState < Fragment.CREATED) {
+ if (DEBUG) Log.v(TAG, "movefrom CREATED: " + f);
+ if (!f.mRetaining) {
+ f.mCalled = false;
+ f.onDestroy();
+ if (!f.mCalled) {
+ throw new SuperNotCalledException("Fragment " + f
+ + " did not call through to super.onDestroy()");
+ }
+ }
+
+ f.mCalled = false;
+ f.onDetach();
+ if (!f.mCalled) {
+ throw new SuperNotCalledException("Fragment " + f
+ + " did not call through to super.onDetach()");
+ }
+ f.mActivity = null;
+ }
+ }
+ }
+
+ f.mState = newState;
+ }
+
+ void moveToState(int newState, boolean always) {
+ moveToState(newState, 0, 0, always);
+ }
+
+ void moveToState(int newState, int transit, int transitStyle, boolean always) {
+ if (mActivity == null && newState != Fragment.INITIALIZING) {
+ throw new IllegalStateException("No activity");
+ }
+
+ if (!always && mCurState == newState) {
+ return;
+ }
+
+ mCurState = newState;
+ if (mActive != null) {
+ for (int i=0; i<mActive.size(); i++) {
+ Fragment f = mActive.get(i);
+ if (f != null) {
+ moveToState(f, newState, transit, transitStyle);
+ }
+ }
+ }
+ }
+
+ void makeActive(Fragment f) {
+ if (f.mIndex >= 0) {
+ return;
+ }
+
+ if (mAvailIndices == null || mAvailIndices.size() <= 0) {
+ if (mActive == null) {
+ mActive = new ArrayList<Fragment>();
+ }
+ f.setIndex(mActive.size());
+ mActive.add(f);
+
+ } else {
+ f.setIndex(mAvailIndices.remove(mAvailIndices.size()-1));
+ mActive.set(f.mIndex, f);
+ }
+ }
+
+ void makeInactive(Fragment f) {
+ if (f.mIndex < 0) {
+ return;
+ }
+
+ mActive.set(f.mIndex, null);
+ if (mAvailIndices == null) {
+ mAvailIndices = new ArrayList<Integer>();
+ }
+ mAvailIndices.add(f.mIndex);
+ f.clearIndex();
+ }
+
+ public void addFragment(Fragment fragment, boolean moveToStateNow) {
+ if (DEBUG) Log.v(TAG, "add: " + fragment);
+ if (mAdded == null) {
+ mAdded = new ArrayList<Fragment>();
+ }
+ mAdded.add(fragment);
+ makeActive(fragment);
+ fragment.mAdded = true;
+ if (moveToStateNow) {
+ moveToState(fragment, mCurState, 0, 0);
+ }
+ }
+
+ public void removeFragment(Fragment fragment, int transition, int transitionStyle) {
+ if (DEBUG) Log.v(TAG, "remove: " + fragment);
+ mAdded.remove(fragment);
+ final boolean inactive = fragment.mBackStackNesting <= 0;
+ if (inactive) {
+ makeInactive(fragment);
+ }
+ fragment.mAdded = false;
+ moveToState(fragment, inactive ? Fragment.INITIALIZING : Fragment.CREATED,
+ transition, transitionStyle);
+ }
+
+ public void hideFragment(Fragment fragment, int transition, int transitionStyle) {
+ if (DEBUG) Log.v(TAG, "hide: " + fragment);
+ if (!fragment.mHidden) {
+ fragment.mHidden = true;
+ if (fragment.mView != null) {
+ Animation anim = loadAnimation(fragment, transition, false,
+ transitionStyle);
+ if (anim != null) {
+ fragment.mView.setAnimation(anim);
+ }
+ fragment.mView.setVisibility(View.GONE);
+ }
+ fragment.onHiddenChanged(true);
+ }
+ }
+
+ public void showFragment(Fragment fragment, int transition, int transitionStyle) {
+ if (DEBUG) Log.v(TAG, "show: " + fragment);
+ if (fragment.mHidden) {
+ fragment.mHidden = false;
+ if (fragment.mView != null) {
+ Animation anim = loadAnimation(fragment, transition, true,
+ transitionStyle);
+ if (anim != null) {
+ fragment.mView.setAnimation(anim);
+ }
+ fragment.mView.setVisibility(View.VISIBLE);
+ }
+ fragment.onHiddenChanged(false);
+ }
+ }
+
+ public Fragment findFragmentById(int id) {
+ if (mActive != null) {
+ // First look through added fragments.
+ for (int i=mAdded.size()-1; i>=0; i--) {
+ Fragment f = mAdded.get(i);
+ if (f != null && f.mFragmentId == id) {
+ return f;
+ }
+ }
+ // Now for any known fragment.
+ for (int i=mActive.size()-1; i>=0; i--) {
+ Fragment f = mActive.get(i);
+ if (f != null && f.mFragmentId == id) {
+ return f;
+ }
+ }
+ }
+ return null;
+ }
+
+ public Fragment findFragmentByTag(String tag) {
+ if (mActive != null && tag != null) {
+ // First look through added fragments.
+ for (int i=mAdded.size()-1; i>=0; i--) {
+ Fragment f = mAdded.get(i);
+ if (f != null && tag.equals(f.mTag)) {
+ return f;
+ }
+ }
+ // Now for any known fragment.
+ for (int i=mActive.size()-1; i>=0; i--) {
+ Fragment f = mActive.get(i);
+ if (f != null && tag.equals(f.mTag)) {
+ return f;
+ }
+ }
+ }
+ return null;
+ }
+
+ public Fragment findFragmentByWho(String who) {
+ if (mActive != null && who != null) {
+ for (int i=mActive.size()-1; i>=0; i--) {
+ Fragment f = mActive.get(i);
+ if (f != null && who.equals(f.mWho)) {
+ return f;
+ }
+ }
+ }
+ return null;
+ }
+
+ public void addBackStackState(BackStackEntry state) {
+ if (mBackStack == null) {
+ mBackStack = new ArrayList<BackStackEntry>();
+ }
+ mBackStack.add(state);
+ }
+
+ public boolean popBackStackState(Handler handler, String name) {
+ if (mBackStack == null) {
+ return false;
+ }
+ if (name == null) {
+ int last = mBackStack.size()-1;
+ if (last < 0) {
+ return false;
+ }
+ final BackStackEntry bss = mBackStack.remove(last);
+ handler.post(new Runnable() {
+ public void run() {
+ bss.popFromBackStack();
+ moveToState(mCurState, reverseTransit(bss.getTransition()),
+ bss.getTransitionStyle(), true);
+ }
+ });
+ } else {
+ int index = mBackStack.size()-1;
+ while (index >= 0) {
+ BackStackEntry bss = mBackStack.get(index);
+ if (name.equals(bss.getName())) {
+ break;
+ }
+ }
+ if (index < 0 || index == mBackStack.size()-1) {
+ return false;
+ }
+ final ArrayList<BackStackEntry> states
+ = new ArrayList<BackStackEntry>();
+ for (int i=mBackStack.size()-1; i>index; i--) {
+ states.add(mBackStack.remove(i));
+ }
+ handler.post(new Runnable() {
+ public void run() {
+ for (int i=0; i<states.size(); i++) {
+ states.get(i).popFromBackStack();
+ }
+ moveToState(mCurState, true);
+ }
+ });
+ }
+ return true;
+ }
+
+ ArrayList<Fragment> retainNonConfig() {
+ ArrayList<Fragment> fragments = null;
+ if (mActive != null) {
+ for (int i=0; i<mActive.size(); i++) {
+ Fragment f = mActive.get(i);
+ if (f != null && f.mRetainInstance) {
+ if (fragments == null) {
+ fragments = new ArrayList<Fragment>();
+ }
+ fragments.add(f);
+ f.mRetaining = true;
+ }
+ }
+ }
+ return fragments;
+ }
+
+ void saveFragmentViewState(Fragment f) {
+ if (f.mView == null) {
+ return;
+ }
+ if (mStateArray == null) {
+ mStateArray = new SparseArray<Parcelable>();
+ }
+ f.mView.saveHierarchyState(mStateArray);
+ if (mStateArray.size() > 0) {
+ f.mSavedViewState = mStateArray;
+ mStateArray = null;
+ }
+ }
+
+ Parcelable saveAllState() {
+ if (mActive == null || mActive.size() <= 0) {
+ return null;
+ }
+
+ // First collect all active fragments.
+ int N = mActive.size();
+ FragmentState[] active = new FragmentState[N];
+ boolean haveFragments = false;
+ for (int i=0; i<N; i++) {
+ Fragment f = mActive.get(i);
+ if (f != null) {
+ haveFragments = true;
+
+ FragmentState fs = new FragmentState(f);
+ active[i] = fs;
+
+ if (mStateBundle == null) {
+ mStateBundle = new Bundle();
+ }
+ f.onSaveInstanceState(mStateBundle);
+ if (!mStateBundle.isEmpty()) {
+ fs.mSavedFragmentState = mStateBundle;
+ mStateBundle = null;
+ }
+
+ if (f.mView != null) {
+ saveFragmentViewState(f);
+ if (f.mSavedViewState != null) {
+ if (fs.mSavedFragmentState == null) {
+ fs.mSavedFragmentState = new Bundle();
+ }
+ fs.mSavedFragmentState.putSparseParcelableArray(
+ FragmentState.VIEW_STATE_TAG, f.mSavedViewState);
+ }
+ }
+
+ }
+ }
+
+ if (!haveFragments) {
+ return null;
+ }
+
+ int[] added = null;
+ BackStackState[] backStack = null;
+
+ // Build list of currently added fragments.
+ N = mAdded.size();
+ if (N > 0) {
+ added = new int[N];
+ for (int i=0; i<N; i++) {
+ added[i] = mAdded.get(i).mIndex;
+ }
+ }
+
+ // Now save back stack.
+ if (mBackStack != null) {
+ N = mBackStack.size();
+ if (N > 0) {
+ backStack = new BackStackState[N];
+ for (int i=0; i<N; i++) {
+ backStack[i] = new BackStackState(this, mBackStack.get(i));
+ }
+ }
+ }
+
+ FragmentManagerState fms = new FragmentManagerState();
+ fms.mActive = active;
+ fms.mAdded = added;
+ fms.mBackStack = backStack;
+ return fms;
+ }
+
+ void restoreAllState(Parcelable state, ArrayList<Fragment> nonConfig) {
+ // If there is no saved state at all, then there can not be
+ // any nonConfig fragments either, so that is that.
+ if (state == null) return;
+ FragmentManagerState fms = (FragmentManagerState)state;
+ if (fms.mActive == null) return;
+
+ // First re-attach any non-config instances we are retaining back
+ // to their saved state, so we don't try to instantiate them again.
+ if (nonConfig != null) {
+ for (int i=0; i<nonConfig.size(); i++) {
+ Fragment f = nonConfig.get(i);
+ FragmentState fs = fms.mActive[f.mIndex];
+ fs.mInstance = f;
+ f.mSavedViewState = null;
+ f.mBackStackNesting = 0;
+ f.mAdded = false;
+ if (fs.mSavedFragmentState != null) {
+ f.mSavedViewState = fs.mSavedFragmentState.getSparseParcelableArray(
+ FragmentState.VIEW_STATE_TAG);
+ }
+ }
+ }
+
+ // Build the full list of active fragments, instantiating them from
+ // their saved state.
+ mActive = new ArrayList<Fragment>(fms.mActive.length);
+ if (mAvailIndices != null) {
+ mAvailIndices.clear();
+ }
+ for (int i=0; i<fms.mActive.length; i++) {
+ FragmentState fs = fms.mActive[i];
+ if (fs != null) {
+ mActive.add(fs.instantiate(mActivity));
+ } else {
+ mActive.add(null);
+ if (mAvailIndices == null) {
+ mAvailIndices = new ArrayList<Integer>();
+ }
+ mAvailIndices.add(i);
+ }
+ }
+
+ // Build the list of currently added fragments.
+ if (fms.mAdded != null) {
+ mAdded = new ArrayList<Fragment>(fms.mAdded.length);
+ for (int i=0; i<fms.mAdded.length; i++) {
+ Fragment f = mActive.get(fms.mAdded[i]);
+ if (f == null) {
+ throw new IllegalStateException(
+ "No instantiated fragment for index #" + fms.mAdded[i]);
+ }
+ f.mAdded = true;
+ mAdded.add(f);
+ }
+ } else {
+ mAdded = null;
+ }
+
+ // Build the back stack.
+ if (fms.mBackStack != null) {
+ mBackStack = new ArrayList<BackStackEntry>(fms.mBackStack.length);
+ for (int i=0; i<fms.mBackStack.length; i++) {
+ BackStackEntry bse = fms.mBackStack[i].instantiate(this);
+ mBackStack.add(bse);
+ }
+ } else {
+ mBackStack = null;
+ }
+ }
+
+ public void attachActivity(Activity activity) {
+ if (mActivity != null) throw new IllegalStateException();
+ mActivity = activity;
+ }
+
+ public void dispatchCreate() {
+ moveToState(Fragment.CREATED, false);
+ }
+
+ public void dispatchStart() {
+ moveToState(Fragment.STARTED, false);
+ }
+
+ public void dispatchResume() {
+ moveToState(Fragment.RESUMED, false);
+ }
+
+ public void dispatchPause() {
+ moveToState(Fragment.STARTED, false);
+ }
+
+ public void dispatchStop() {
+ moveToState(Fragment.CONTENT, false);
+ }
+
+ public void dispatchDestroy() {
+ moveToState(Fragment.INITIALIZING, false);
+ mActivity = null;
+ }
+
+ public static int reverseTransit(int transit) {
+ int rev = 0;
+ switch (transit) {
+ case FragmentTransaction.TRANSIT_ENTER:
+ rev = FragmentTransaction.TRANSIT_EXIT;
+ break;
+ case FragmentTransaction.TRANSIT_EXIT:
+ rev = FragmentTransaction.TRANSIT_ENTER;
+ break;
+ case FragmentTransaction.TRANSIT_SHOW:
+ rev = FragmentTransaction.TRANSIT_HIDE;
+ break;
+ case FragmentTransaction.TRANSIT_HIDE:
+ rev = FragmentTransaction.TRANSIT_SHOW;
+ break;
+ case FragmentTransaction.TRANSIT_ACTIVITY_OPEN:
+ rev = FragmentTransaction.TRANSIT_ACTIVITY_CLOSE;
+ break;
+ case FragmentTransaction.TRANSIT_ACTIVITY_CLOSE:
+ rev = FragmentTransaction.TRANSIT_ACTIVITY_OPEN;
+ break;
+ case FragmentTransaction.TRANSIT_TASK_OPEN:
+ rev = FragmentTransaction.TRANSIT_TASK_CLOSE;
+ break;
+ case FragmentTransaction.TRANSIT_TASK_CLOSE:
+ rev = FragmentTransaction.TRANSIT_TASK_OPEN;
+ break;
+ case FragmentTransaction.TRANSIT_TASK_TO_FRONT:
+ rev = FragmentTransaction.TRANSIT_TASK_TO_BACK;
+ break;
+ case FragmentTransaction.TRANSIT_TASK_TO_BACK:
+ rev = FragmentTransaction.TRANSIT_TASK_TO_FRONT;
+ break;
+ case FragmentTransaction.TRANSIT_WALLPAPER_OPEN:
+ rev = FragmentTransaction.TRANSIT_WALLPAPER_CLOSE;
+ break;
+ case FragmentTransaction.TRANSIT_WALLPAPER_CLOSE:
+ rev = FragmentTransaction.TRANSIT_WALLPAPER_OPEN;
+ break;
+ case FragmentTransaction.TRANSIT_WALLPAPER_INTRA_OPEN:
+ rev = FragmentTransaction.TRANSIT_WALLPAPER_INTRA_CLOSE;
+ break;
+ case FragmentTransaction.TRANSIT_WALLPAPER_INTRA_CLOSE:
+ rev = FragmentTransaction.TRANSIT_WALLPAPER_INTRA_OPEN;
+ break;
+ }
+ return rev;
+
+ }
+
+ public static int transitToStyleIndex(int transit, boolean enter) {
+ int animAttr = -1;
+ switch (transit) {
+ case FragmentTransaction.TRANSIT_ENTER:
+ animAttr = com.android.internal.R.styleable.WindowAnimation_windowEnterAnimation;
+ break;
+ case FragmentTransaction.TRANSIT_EXIT:
+ animAttr = com.android.internal.R.styleable.WindowAnimation_windowExitAnimation;
+ break;
+ case FragmentTransaction.TRANSIT_SHOW:
+ animAttr = com.android.internal.R.styleable.WindowAnimation_windowShowAnimation;
+ break;
+ case FragmentTransaction.TRANSIT_HIDE:
+ animAttr = com.android.internal.R.styleable.WindowAnimation_windowHideAnimation;
+ break;
+ case FragmentTransaction.TRANSIT_ACTIVITY_OPEN:
+ animAttr = enter
+ ? com.android.internal.R.styleable.WindowAnimation_activityOpenEnterAnimation
+ : com.android.internal.R.styleable.WindowAnimation_activityOpenExitAnimation;
+ break;
+ case FragmentTransaction.TRANSIT_ACTIVITY_CLOSE:
+ animAttr = enter
+ ? com.android.internal.R.styleable.WindowAnimation_activityCloseEnterAnimation
+ : com.android.internal.R.styleable.WindowAnimation_activityCloseExitAnimation;
+ break;
+ case FragmentTransaction.TRANSIT_TASK_OPEN:
+ animAttr = enter
+ ? com.android.internal.R.styleable.WindowAnimation_taskOpenEnterAnimation
+ : com.android.internal.R.styleable.WindowAnimation_taskOpenExitAnimation;
+ break;
+ case FragmentTransaction.TRANSIT_TASK_CLOSE:
+ animAttr = enter
+ ? com.android.internal.R.styleable.WindowAnimation_taskCloseEnterAnimation
+ : com.android.internal.R.styleable.WindowAnimation_taskCloseExitAnimation;
+ break;
+ case FragmentTransaction.TRANSIT_TASK_TO_FRONT:
+ animAttr = enter
+ ? com.android.internal.R.styleable.WindowAnimation_taskToFrontEnterAnimation
+ : com.android.internal.R.styleable.WindowAnimation_taskToFrontExitAnimation;
+ break;
+ case FragmentTransaction.TRANSIT_TASK_TO_BACK:
+ animAttr = enter
+ ? com.android.internal.R.styleable.WindowAnimation_taskToBackEnterAnimation
+ : com.android.internal.R.styleable.WindowAnimation_taskToBackExitAnimation;
+ break;
+ case FragmentTransaction.TRANSIT_WALLPAPER_OPEN:
+ animAttr = enter
+ ? com.android.internal.R.styleable.WindowAnimation_wallpaperOpenEnterAnimation
+ : com.android.internal.R.styleable.WindowAnimation_wallpaperOpenExitAnimation;
+ break;
+ case FragmentTransaction.TRANSIT_WALLPAPER_CLOSE:
+ animAttr = enter
+ ? com.android.internal.R.styleable.WindowAnimation_wallpaperCloseEnterAnimation
+ : com.android.internal.R.styleable.WindowAnimation_wallpaperCloseExitAnimation;
+ break;
+ case FragmentTransaction.TRANSIT_WALLPAPER_INTRA_OPEN:
+ animAttr = enter
+ ? com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenEnterAnimation
+ : com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation;
+ break;
+ case FragmentTransaction.TRANSIT_WALLPAPER_INTRA_CLOSE:
+ animAttr = enter
+ ? com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseEnterAnimation
+ : com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseExitAnimation;
+ break;
+ }
+ return animAttr;
+ }
+}
diff --git a/core/java/android/app/FragmentTransaction.java b/core/java/android/app/FragmentTransaction.java
new file mode 100644
index 0000000..840f274
--- /dev/null
+++ b/core/java/android/app/FragmentTransaction.java
@@ -0,0 +1,151 @@
+package android.app;
+
+/**
+ * API for performing a set of Fragment operations.
+ */
+public interface FragmentTransaction {
+ /**
+ * Calls {@link #add(int, Fragment, String)} with a 0 containerViewId.
+ */
+ public FragmentTransaction add(Fragment fragment, String tag);
+
+ /**
+ * Calls {@link #add(int, Fragment, String)} with a null tag.
+ */
+ public FragmentTransaction add(int containerViewId, Fragment fragment);
+
+ /**
+ * Add a fragment to the activity state. This fragment may optionally
+ * also have its view (if {@link Fragment#onCreateView Fragment.onCreateView}
+ * returns non-null) into a container view of the activity.
+ *
+ * @param containerViewId Optional identifier of the container this fragment is
+ * to be placed in. If 0, it will not be placed in a container.
+ * @param fragment The fragment to be added. This fragment must not already
+ * be added to the activity.
+ * @param tag Optional tag name for the fragment, to later retrieve the
+ * fragment with {@link Activity#findFragmentByTag(String)
+ * Activity.findFragmentByTag(String)}.
+ *
+ * @return Returns the same FragmentTransaction instance.
+ */
+ public FragmentTransaction add(int containerViewId, Fragment fragment, String tag);
+
+ /**
+ * Calls {@link #replace(int, Fragment, String)} with a null tag.
+ */
+ public FragmentTransaction replace(int containerViewId, Fragment fragment);
+
+ /**
+ * Replace an existing fragment that was added to a container. This is
+ * essentially the same as calling {@link #remove(Fragment)} for all
+ * currently added fragments that were added with the same containerViewId
+ * and then {@link #add(int, Fragment, String)} with the same arguments
+ * given here.
+ *
+ * @param containerViewId Identifier of the container whose fragment(s) are
+ * to be replaced.
+ * @param fragment The new fragment to place in the container.
+ * @param tag Optional tag name for the fragment, to later retrieve the
+ * fragment with {@link Activity#findFragmentByTag(String)
+ * Activity.findFragmentByTag(String)}.
+ *
+ * @return Returns the same FragmentTransaction instance.
+ */
+ public FragmentTransaction replace(int containerViewId, Fragment fragment, String tag);
+
+ /**
+ * Remove an existing fragment. If it was added to a container, its view
+ * is also removed from that container.
+ *
+ * @param fragment The fragment to be removed.
+ *
+ * @return Returns the same FragmentTransaction instance.
+ */
+ public FragmentTransaction remove(Fragment fragment);
+
+ /**
+ * Hides an existing fragment. This is only relevant for fragments whose
+ * views have been added to a container, as this will cause the view to
+ * be hidden.
+ *
+ * @param fragment The fragment to be hidden.
+ *
+ * @return Returns the same FragmentTransaction instance.
+ */
+ public FragmentTransaction hide(Fragment fragment);
+
+ /**
+ * Hides a previously hidden fragment. This is only relevant for fragments whose
+ * views have been added to a container, as this will cause the view to
+ * be shown.
+ *
+ * @param fragment The fragment to be shown.
+ *
+ * @return Returns the same FragmentTransaction instance.
+ */
+ public FragmentTransaction show(Fragment fragment);
+
+ /**
+ * Bit mask that is set for all enter transitions.
+ */
+ public final int TRANSIT_ENTER_MASK = 0x1000;
+
+ /**
+ * Bit mask that is set for all exit transitions.
+ */
+ public final int TRANSIT_EXIT_MASK = 0x2000;
+
+ /** Not set up for a transition. */
+ public final int TRANSIT_UNSET = -1;
+ /** No animation for transition. */
+ public final int TRANSIT_NONE = 0;
+ /** Window has been added to the screen. */
+ public final int TRANSIT_ENTER = 1 | TRANSIT_ENTER_MASK;
+ /** Window has been removed from the screen. */
+ public final int TRANSIT_EXIT = 2 | TRANSIT_EXIT_MASK;
+ /** Window has been made visible. */
+ public final int TRANSIT_SHOW = 3 | TRANSIT_ENTER_MASK;
+ /** Window has been made invisible. */
+ public final int TRANSIT_HIDE = 4 | TRANSIT_EXIT_MASK;
+ /** The "application starting" preview window is no longer needed, and will
+ * animate away to show the real window. */
+ public final int TRANSIT_PREVIEW_DONE = 5;
+ /** A window in a new activity is being opened on top of an existing one
+ * in the same task. */
+ public final int TRANSIT_ACTIVITY_OPEN = 6 | TRANSIT_ENTER_MASK;
+ /** The window in the top-most activity is being closed to reveal the
+ * previous activity in the same task. */
+ public final int TRANSIT_ACTIVITY_CLOSE = 7 | TRANSIT_EXIT_MASK;
+ /** A window in a new task is being opened on top of an existing one
+ * in another activity's task. */
+ public final int TRANSIT_TASK_OPEN = 8 | TRANSIT_ENTER_MASK;
+ /** A window in the top-most activity is being closed to reveal the
+ * previous activity in a different task. */
+ public final int TRANSIT_TASK_CLOSE = 9 | TRANSIT_EXIT_MASK;
+ /** A window in an existing task is being displayed on top of an existing one
+ * in another activity's task. */
+ public final int TRANSIT_TASK_TO_FRONT = 10 | TRANSIT_ENTER_MASK;
+ /** A window in an existing task is being put below all other tasks. */
+ public final int TRANSIT_TASK_TO_BACK = 11 | TRANSIT_EXIT_MASK;
+ /** A window in a new activity that doesn't have a wallpaper is being
+ * opened on top of one that does, effectively closing the wallpaper. */
+ public final int TRANSIT_WALLPAPER_CLOSE = 12 | TRANSIT_EXIT_MASK;
+ /** A window in a new activity that does have a wallpaper is being
+ * opened on one that didn't, effectively opening the wallpaper. */
+ public final int TRANSIT_WALLPAPER_OPEN = 13 | TRANSIT_ENTER_MASK;
+ /** A window in a new activity is being opened on top of an existing one,
+ * and both are on top of the wallpaper. */
+ public final int TRANSIT_WALLPAPER_INTRA_OPEN = 14 | TRANSIT_ENTER_MASK;
+ /** The window in the top-most activity is being closed to reveal the
+ * previous activity, and both are on top of he wallpaper. */
+ public final int TRANSIT_WALLPAPER_INTRA_CLOSE = 15 | TRANSIT_EXIT_MASK;
+
+ public FragmentTransaction setCustomAnimations(int enter, int exit);
+
+ public FragmentTransaction setTransition(int transit);
+ public FragmentTransaction setTransitionStyle(int styleRes);
+
+ public FragmentTransaction addToBackStack(String name);
+ public void commit();
+}
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index b8c3aa3..4d5f36a 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -997,8 +997,10 @@
IllegalAccessException {
Activity activity = (Activity)clazz.newInstance();
ActivityThread aThread = null;
- activity.attach(context, aThread, this, token, application, intent, info, title,
- parent, id, lastNonConfigurationInstance, new Configuration());
+ activity.attach(context, aThread, this, token, application, intent,
+ info, title, parent, id,
+ (Activity.NonConfigurationInstances)lastNonConfigurationInstance,
+ new Configuration());
return activity;
}
@@ -1058,21 +1060,23 @@
}
public void callActivityOnDestroy(Activity activity) {
- if (mWaitingActivities != null) {
- synchronized (mSync) {
- final int N = mWaitingActivities.size();
- for (int i=0; i<N; i++) {
- final ActivityWaiter aw = mWaitingActivities.get(i);
- final Intent intent = aw.intent;
- if (intent.filterEquals(activity.getIntent())) {
- aw.activity = activity;
- mMessageQueue.addIdleHandler(new ActivityGoing(aw));
- }
- }
- }
- }
+ // TODO: the following block causes intermittent hangs when using startActivity
+ // temporarily comment out until root cause is fixed (bug 2630683)
+// if (mWaitingActivities != null) {
+// synchronized (mSync) {
+// final int N = mWaitingActivities.size();
+// for (int i=0; i<N; i++) {
+// final ActivityWaiter aw = mWaitingActivities.get(i);
+// final Intent intent = aw.intent;
+// if (intent.filterEquals(activity.getIntent())) {
+// aw.activity = activity;
+// mMessageQueue.addIdleHandler(new ActivityGoing(aw));
+// }
+// }
+// }
+// }
- activity.onDestroy();
+ activity.performDestroy();
if (mActivityMonitors != null) {
synchronized (mSync) {
@@ -1331,7 +1335,7 @@
* is being started.
* @param token Internal token identifying to the system who is starting
* the activity; may be null.
- * @param target Which activity is perform the start (and thus receiving
+ * @param target Which activity is performing the start (and thus receiving
* any result); may be null if this call is not being made
* from an activity.
* @param intent The actual Intent to start.
@@ -1381,6 +1385,64 @@
return null;
}
+ /**
+ * Like {@link #execStartActivity(Context, IBinder, IBinder, Activity, Intent, int)},
+ * but for calls from a {#link Fragment}.
+ *
+ * @param who The Context from which the activity is being started.
+ * @param contextThread The main thread of the Context from which the activity
+ * is being started.
+ * @param token Internal token identifying to the system who is starting
+ * the activity; may be null.
+ * @param target Which fragment is performing the start (and thus receiving
+ * any result).
+ * @param intent The actual Intent to start.
+ * @param requestCode Identifier for this request's result; less than zero
+ * if the caller is not expecting a result.
+ *
+ * @return To force the return of a particular result, return an
+ * ActivityResult object containing the desired data; otherwise
+ * return null. The default implementation always returns null.
+ *
+ * @throws android.content.ActivityNotFoundException
+ *
+ * @see Activity#startActivity(Intent)
+ * @see Activity#startActivityForResult(Intent, int)
+ * @see Activity#startActivityFromChild
+ *
+ * {@hide}
+ */
+ public ActivityResult execStartActivity(
+ Context who, IBinder contextThread, IBinder token, Fragment target,
+ Intent intent, int requestCode) {
+ IApplicationThread whoThread = (IApplicationThread) contextThread;
+ if (mActivityMonitors != null) {
+ synchronized (mSync) {
+ final int N = mActivityMonitors.size();
+ for (int i=0; i<N; i++) {
+ final ActivityMonitor am = mActivityMonitors.get(i);
+ if (am.match(who, null, intent)) {
+ am.mHits++;
+ if (am.isBlocking()) {
+ return requestCode >= 0 ? am.getResult() : null;
+ }
+ break;
+ }
+ }
+ }
+ }
+ try {
+ int result = ActivityManagerNative.getDefault()
+ .startActivity(whoThread, intent,
+ intent.resolveTypeIfNeeded(who.getContentResolver()),
+ null, 0, token, target != null ? target.mWho : null,
+ requestCode, false, false);
+ checkStartActivityResult(result, intent);
+ } catch (RemoteException e) {
+ }
+ return null;
+ }
+
/*package*/ final void init(ActivityThread thread,
Context instrContext, Context appContext, ComponentName component,
IInstrumentationWatcher watcher) {
diff --git a/core/java/android/app/LoaderManagingFragment.java b/core/java/android/app/LoaderManagingFragment.java
new file mode 100644
index 0000000..1659adf
--- /dev/null
+++ b/core/java/android/app/LoaderManagingFragment.java
@@ -0,0 +1,188 @@
+/*
+ * 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.app;
+
+import android.content.Loader;
+import android.os.Bundle;
+
+import java.util.HashMap;
+
+/**
+ * A Fragment that has utility methods for managing {@link Loader}s.
+ *
+ * @param <D> The type of data returned by the Loader. If you're using multiple Loaders with
+ * different return types use Object and case the results.
+ */
+public abstract class LoaderManagingFragment<D> extends Fragment
+ implements Loader.OnLoadCompleteListener<D> {
+ private boolean mStarted = false;
+
+ static final class LoaderInfo<D> {
+ public Bundle args;
+ public Loader<D> loader;
+ }
+ private HashMap<Integer, LoaderInfo<D>> mLoaders;
+ private HashMap<Integer, LoaderInfo<D>> mInactiveLoaders;
+
+ /**
+ * Registers a loader with this activity, registers the callbacks on it, and starts it loading.
+ * If a loader with the same id has previously been started it will automatically be destroyed
+ * when the new loader completes it's work. The callback will be delivered before the old loader
+ * is destroyed.
+ */
+ protected Loader<D> startLoading(int id, Bundle args) {
+ LoaderInfo<D> info = mLoaders.get(id);
+ if (info != null) {
+ // Keep track of the previous instance of this loader so we can destroy
+ // it when the new one completes.
+ mInactiveLoaders.put(id, info);
+ }
+ info = new LoaderInfo<D>();
+ info.args = args;
+ mLoaders.put(id, info);
+ Loader<D> loader = onCreateLoader(id, args);
+ info.loader = loader;
+ if (mStarted) {
+ // The activity will start all existing loaders in it's onStart(), so only start them
+ // here if we're past that point of the activitiy's life cycle
+ loader.registerListener(id, this);
+ loader.startLoading();
+ }
+ return loader;
+ }
+
+ protected abstract Loader<D> onCreateLoader(int id, Bundle args);
+ protected abstract void onInitializeLoaders();
+ protected abstract void onLoadFinished(Loader<D> loader, D data);
+
+ public final void onLoadComplete(Loader<D> loader, D data) {
+ // Notify of the new data so the app can switch out the old data before
+ // we try to destroy it.
+ onLoadFinished(loader, data);
+
+ // Look for an inactive loader and destroy it if found
+ int id = loader.getId();
+ LoaderInfo<D> info = mInactiveLoaders.get(id);
+ if (info != null) {
+ Loader<D> oldLoader = info.loader;
+ if (oldLoader != null) {
+ oldLoader.destroy();
+ }
+ mInactiveLoaders.remove(id);
+ }
+ }
+
+ @Override
+ public void onCreate(Bundle savedState) {
+ super.onCreate(savedState);
+
+ if (mLoaders == null) {
+ // Look for a passed along loader and create a new one if it's not there
+// TODO: uncomment once getLastNonConfigurationInstance method is available
+// mLoaders = (HashMap<Integer, LoaderInfo>) getLastNonConfigurationInstance();
+ if (mLoaders == null) {
+ mLoaders = new HashMap<Integer, LoaderInfo<D>>();
+ onInitializeLoaders();
+ }
+ }
+ if (mInactiveLoaders == null) {
+ mInactiveLoaders = new HashMap<Integer, LoaderInfo<D>>();
+ }
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+
+ // Call out to sub classes so they can start their loaders
+ // Let the existing loaders know that we want to be notified when a load is complete
+ for (HashMap.Entry<Integer, LoaderInfo<D>> entry : mLoaders.entrySet()) {
+ LoaderInfo<D> info = entry.getValue();
+ Loader<D> loader = info.loader;
+ int id = entry.getKey();
+ if (loader == null) {
+ loader = onCreateLoader(id, info.args);
+ info.loader = loader;
+ }
+ loader.registerListener(id, this);
+ loader.startLoading();
+ }
+
+ mStarted = true;
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+
+ for (HashMap.Entry<Integer, LoaderInfo<D>> entry : mLoaders.entrySet()) {
+ LoaderInfo<D> info = entry.getValue();
+ Loader<D> loader = info.loader;
+ if (loader == null) {
+ continue;
+ }
+
+ // Let the loader know we're done with it
+ loader.unregisterListener(this);
+
+ // The loader isn't getting passed along to the next instance so ask it to stop loading
+ if (!getActivity().isChangingConfigurations()) {
+ loader.stopLoading();
+ }
+ }
+
+ mStarted = false;
+ }
+
+ /** TO DO: This needs to be turned into a retained fragment.
+ @Override
+ public Object onRetainNonConfigurationInstance() {
+ // Pass the loader along to the next guy
+ Object result = mLoaders;
+ mLoaders = null;
+ return result;
+ }
+ **/
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+
+ if (mLoaders != null) {
+ for (HashMap.Entry<Integer, LoaderInfo<D>> entry : mLoaders.entrySet()) {
+ LoaderInfo<D> info = entry.getValue();
+ Loader<D> loader = info.loader;
+ if (loader == null) {
+ continue;
+ }
+ loader.destroy();
+ }
+ }
+ }
+
+ /**
+ * @return the Loader with the given id or null if no matching Loader
+ * is found.
+ */
+ public Loader<D> getLoader(int id) {
+ LoaderInfo<D> loaderInfo = mLoaders.get(id);
+ if (loaderInfo != null) {
+ return mLoaders.get(id).loader;
+ }
+ return null;
+ }
+}
diff --git a/core/java/android/app/LocalActivityManager.java b/core/java/android/app/LocalActivityManager.java
index a24fcae..524de6f 100644
--- a/core/java/android/app/LocalActivityManager.java
+++ b/core/java/android/app/LocalActivityManager.java
@@ -20,13 +20,11 @@
import android.content.pm.ActivityInfo;
import android.os.Binder;
import android.os.Bundle;
-import android.util.Config;
import android.util.Log;
import android.view.Window;
import java.util.ArrayList;
import java.util.HashMap;
-import java.util.Iterator;
import java.util.Map;
/**
@@ -38,7 +36,7 @@
*/
public class LocalActivityManager {
private static final String TAG = "LocalActivityManager";
- private static final boolean localLOGV = false || Config.LOGV;
+ private static final boolean localLOGV = false;
// Internal token for an Activity being managed by LocalActivityManager.
private static class LocalActivityRecord extends Binder {
@@ -112,11 +110,16 @@
if (r.curState == INITIALIZING) {
// Get the lastNonConfigurationInstance for the activity
- HashMap<String,Object> lastNonConfigurationInstances =
- mParent.getLastNonConfigurationChildInstances();
- Object instance = null;
+ HashMap<String, Object> lastNonConfigurationInstances =
+ mParent.getLastNonConfigurationChildInstances();
+ Object instanceObj = null;
if (lastNonConfigurationInstances != null) {
- instance = lastNonConfigurationInstances.get(r.id);
+ instanceObj = lastNonConfigurationInstances.get(r.id);
+ }
+ Activity.NonConfigurationInstances instance = null;
+ if (instanceObj != null) {
+ instance = new Activity.NonConfigurationInstances();
+ instance.activity = instanceObj;
}
// We need to have always created the activity.
@@ -346,7 +349,7 @@
}
private Window performDestroy(LocalActivityRecord r, boolean finish) {
- Window win = null;
+ Window win;
win = r.window;
if (r.curState == RESUMED && !finish) {
performPause(r, finish);
@@ -380,7 +383,8 @@
if (r != null) {
win = performDestroy(r, finish);
if (finish) {
- mActivities.remove(r);
+ mActivities.remove(id);
+ mActivityArray.remove(r);
}
}
return win;
@@ -441,10 +445,8 @@
*/
public void dispatchCreate(Bundle state) {
if (state != null) {
- final Iterator<String> i = state.keySet().iterator();
- while (i.hasNext()) {
+ for (String id : state.keySet()) {
try {
- final String id = i.next();
final Bundle astate = state.getBundle(id);
LocalActivityRecord r = mActivities.get(id);
if (r != null) {
@@ -457,9 +459,7 @@
}
} catch (Exception e) {
// Recover from -all- app errors.
- Log.e(TAG,
- "Exception thrown when restoring LocalActivityManager state",
- e);
+ Log.e(TAG, "Exception thrown when restoring LocalActivityManager state", e);
}
}
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 296d70a4..3066f5c 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -46,7 +46,7 @@
private final Context mContext;
private final IDevicePolicyManager mService;
-
+
private final Handler mHandler;
private DevicePolicyManager(Context context, Handler handler) {
@@ -61,14 +61,14 @@
DevicePolicyManager me = new DevicePolicyManager(context, handler);
return me.mService != null ? me : null;
}
-
+
/**
* Activity action: ask the user to add a new device administrator to the system.
* The desired policy is the ComponentName of the policy in the
* {@link #EXTRA_DEVICE_ADMIN} extra field. This will invoke a UI to
* bring the user through adding the device administrator to the system (or
* allowing them to reject it).
- *
+ *
* <p>You can optionally include the {@link #EXTRA_ADD_EXPLANATION}
* field to provide the user with additional explanation (in addition
* to your component's description) about what is being added.
@@ -76,7 +76,7 @@
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_ADD_DEVICE_ADMIN
= "android.app.action.ADD_DEVICE_ADMIN";
-
+
/**
* Activity action: send when any policy admin changes a policy.
* This is generally used to find out when a new policy is in effect.
@@ -92,7 +92,7 @@
* @see #ACTION_ADD_DEVICE_ADMIN
*/
public static final String EXTRA_DEVICE_ADMIN = "android.app.extra.DEVICE_ADMIN";
-
+
/**
* An optional CharSequence providing additional explanation for why the
* admin is being added.
@@ -100,22 +100,21 @@
* @see #ACTION_ADD_DEVICE_ADMIN
*/
public static final String EXTRA_ADD_EXPLANATION = "android.app.extra.ADD_EXPLANATION";
-
+
/**
- * Activity action: have the user enter a new password. This activity
- * should be launched after using {@link #setPasswordQuality(ComponentName, int)}
- * or {@link #setPasswordMinimumLength(ComponentName, int)} to have the
- * user enter a new password that meets the current requirements. You can
- * use {@link #isActivePasswordSufficient()} to determine whether you need
- * to have the user select a new password in order to meet the current
- * constraints. Upon being resumed from this activity,
- * you can check the new password characteristics to see if they are
- * sufficient.
+ * Activity action: have the user enter a new password. This activity should
+ * be launched after using {@link #setPasswordQuality(ComponentName, int)},
+ * or {@link #setPasswordMinimumLength(ComponentName, int)} to have the user
+ * enter a new password that meets the current requirements. You can use
+ * {@link #isActivePasswordSufficient()} to determine whether you need to
+ * have the user select a new password in order to meet the current
+ * constraints. Upon being resumed from this activity, you can check the new
+ * password characteristics to see if they are sufficient.
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_SET_NEW_PASSWORD
= "android.app.action.SET_NEW_PASSWORD";
-
+
/**
* Return true if the given administrator component is currently
* active (enabled) in the system.
@@ -130,7 +129,7 @@
}
return false;
}
-
+
/**
* Return a list of all currently active device administrator's component
* names. Note that if there are no administrators than null may be
@@ -146,7 +145,7 @@
}
return null;
}
-
+
/**
* @hide
*/
@@ -160,7 +159,7 @@
}
return false;
}
-
+
/**
* Remove a current administration component. This can only be called
* by the application that owns the administration component; if you
@@ -176,28 +175,28 @@
}
}
}
-
+
/**
* Constant for {@link #setPasswordQuality}: the policy has no requirements
* for the password. Note that quality constants are ordered so that higher
* values are more restrictive.
*/
public static final int PASSWORD_QUALITY_UNSPECIFIED = 0;
-
+
/**
* Constant for {@link #setPasswordQuality}: the policy requires some kind
* of password, but doesn't care what it is. Note that quality constants
* are ordered so that higher values are more restrictive.
*/
public static final int PASSWORD_QUALITY_SOMETHING = 0x10000;
-
+
/**
* Constant for {@link #setPasswordQuality}: the user must have entered a
* password containing at least numeric characters. Note that quality
* constants are ordered so that higher values are more restrictive.
*/
public static final int PASSWORD_QUALITY_NUMERIC = 0x20000;
-
+
/**
* Constant for {@link #setPasswordQuality}: the user must have entered a
* password containing at least alphabetic (or other symbol) characters.
@@ -205,7 +204,7 @@
* restrictive.
*/
public static final int PASSWORD_QUALITY_ALPHABETIC = 0x40000;
-
+
/**
* Constant for {@link #setPasswordQuality}: the user must have entered a
* password containing at least <em>both></em> numeric <em>and</em>
@@ -213,7 +212,19 @@
* ordered so that higher values are more restrictive.
*/
public static final int PASSWORD_QUALITY_ALPHANUMERIC = 0x50000;
-
+
+ /**
+ * Constant for {@link #setPasswordQuality}: the user must have entered a
+ * password containing at least a letter, a numerical digit and a special
+ * symbol, by default. With this password quality, passwords can be
+ * restricted to contain various sets of characters, like at least an
+ * uppercase letter, etc. These are specified using various methods,
+ * like {@link #setPasswordMinimumLowerCase(ComponentName, int)}. Note
+ * that quality constants are ordered so that higher values are more
+ * restrictive.
+ */
+ public static final int PASSWORD_QUALITY_COMPLEX = 0x60000;
+
/**
* Called by an application that is administering the device to set the
* password restrictions it is imposing. After setting this, the user
@@ -222,21 +233,21 @@
* will remain until the user has set a new one, so the change does not
* take place immediately. To prompt the user for a new password, use
* {@link #ACTION_SET_NEW_PASSWORD} after setting this value.
- *
+ *
* <p>Quality constants are ordered so that higher values are more restrictive;
* thus the highest requested quality constant (between the policy set here,
* the user's preference, and any other considerations) is the one that
* is in effect.
- *
+ *
* <p>The calling device admin must have requested
* {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call
* this method; if it has not, a security exception will be thrown.
- *
+ *
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param quality The new desired quality. One of
* {@link #PASSWORD_QUALITY_UNSPECIFIED}, {@link #PASSWORD_QUALITY_SOMETHING},
* {@link #PASSWORD_QUALITY_NUMERIC}, {@link #PASSWORD_QUALITY_ALPHABETIC},
- * or {@link #PASSWORD_QUALITY_ALPHANUMERIC}.
+ * {@link #PASSWORD_QUALITY_ALPHANUMERIC} or {@link #PASSWORD_QUALITY_COMPLEX}.
*/
public void setPasswordQuality(ComponentName admin, int quality) {
if (mService != null) {
@@ -247,7 +258,7 @@
}
}
}
-
+
/**
* Retrieve the current minimum password quality for all admins
* or a particular one.
@@ -264,7 +275,7 @@
}
return PASSWORD_QUALITY_UNSPECIFIED;
}
-
+
/**
* Called by an application that is administering the device to set the
* minimum allowed password length. After setting this, the user
@@ -274,14 +285,14 @@
* take place immediately. To prompt the user for a new password, use
* {@link #ACTION_SET_NEW_PASSWORD} after setting this value. This
* constraint is only imposed if the administrator has also requested either
- * {@link #PASSWORD_QUALITY_NUMERIC}, {@link #PASSWORD_QUALITY_ALPHABETIC},
- * or {@link #PASSWORD_QUALITY_ALPHANUMERIC}
+ * {@link #PASSWORD_QUALITY_NUMERIC}, {@link #PASSWORD_QUALITY_ALPHABETIC}
+ * {@link #PASSWORD_QUALITY_ALPHANUMERIC}, or {@link #PASSWORD_QUALITY_COMPLEX}
* with {@link #setPasswordQuality}.
- *
+ *
* <p>The calling device admin must have requested
* {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call
* this method; if it has not, a security exception will be thrown.
- *
+ *
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param length The new desired minimum password length. A value of 0
* means there is no restriction.
@@ -295,7 +306,7 @@
}
}
}
-
+
/**
* Retrieve the current minimum password length for all admins
* or a particular one.
@@ -312,7 +323,379 @@
}
return 0;
}
-
+
+ /**
+ * Called by an application that is administering the device to set the
+ * minimum number of upper case letters required in the password. After
+ * setting this, the user will not be able to enter a new password that is
+ * not at least as restrictive as what has been set. Note that the current
+ * password will remain until the user has set a new one, so the change does
+ * not take place immediately. To prompt the user for a new password, use
+ * {@link #ACTION_SET_NEW_PASSWORD} after setting this value. This
+ * constraint is only imposed if the administrator has also requested
+ * {@link #PASSWORD_QUALITY_COMPLEX} with {@link #setPasswordQuality}. The
+ * default value is 0.
+ * <p>
+ * The calling device admin must have requested
+ * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call
+ * this method; if it has not, a security exception will be thrown.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated
+ * with.
+ * @param length The new desired minimum number of upper case letters
+ * required in the password. A value of 0 means there is no
+ * restriction.
+ */
+ public void setPasswordMinimumUpperCase(ComponentName admin, int length) {
+ if (mService != null) {
+ try {
+ mService.setPasswordMinimumUpperCase(admin, length);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ }
+
+ /**
+ * Retrieve the current number of upper case letters required in the
+ * password for all admins or a particular one. This is the same value as
+ * set by {#link {@link #setPasswordMinimumUpperCase(ComponentName, int)}
+ * and only applies when the password quality is
+ * {@link #PASSWORD_QUALITY_COMPLEX}.
+ *
+ * @param admin The name of the admin component to check, or null to
+ * aggregate all admins.
+ * @return The minimum number of upper case letters required in the
+ * password.
+ */
+ public int getPasswordMinimumUpperCase(ComponentName admin) {
+ if (mService != null) {
+ try {
+ return mService.getPasswordMinimumUpperCase(admin);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * Called by an application that is administering the device to set the
+ * minimum number of lower case letters required in the password. After
+ * setting this, the user will not be able to enter a new password that is
+ * not at least as restrictive as what has been set. Note that the current
+ * password will remain until the user has set a new one, so the change does
+ * not take place immediately. To prompt the user for a new password, use
+ * {@link #ACTION_SET_NEW_PASSWORD} after setting this value. This
+ * constraint is only imposed if the administrator has also requested
+ * {@link #PASSWORD_QUALITY_COMPLEX} with {@link #setPasswordQuality}. The
+ * default value is 0.
+ * <p>
+ * The calling device admin must have requested
+ * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call
+ * this method; if it has not, a security exception will be thrown.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated
+ * with.
+ * @param length The new desired minimum number of lower case letters
+ * required in the password. A value of 0 means there is no
+ * restriction.
+ */
+ public void setPasswordMinimumLowerCase(ComponentName admin, int length) {
+ if (mService != null) {
+ try {
+ mService.setPasswordMinimumLowerCase(admin, length);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ }
+
+ /**
+ * Retrieve the current number of lower case letters required in the
+ * password for all admins or a particular one. This is the same value as
+ * set by {#link {@link #setPasswordMinimumLowerCase(ComponentName, int)}
+ * and only applies when the password quality is
+ * {@link #PASSWORD_QUALITY_COMPLEX}.
+ *
+ * @param admin The name of the admin component to check, or null to
+ * aggregate all admins.
+ * @return The minimum number of lower case letters required in the
+ * password.
+ */
+ public int getPasswordMinimumLowerCase(ComponentName admin) {
+ if (mService != null) {
+ try {
+ return mService.getPasswordMinimumLowerCase(admin);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * Called by an application that is administering the device to set the
+ * minimum number of letters required in the password. After setting this,
+ * the user will not be able to enter a new password that is not at least as
+ * restrictive as what has been set. Note that the current password will
+ * remain until the user has set a new one, so the change does not take
+ * place immediately. To prompt the user for a new password, use
+ * {@link #ACTION_SET_NEW_PASSWORD} after setting this value. This
+ * constraint is only imposed if the administrator has also requested
+ * {@link #PASSWORD_QUALITY_COMPLEX} with {@link #setPasswordQuality}. The
+ * default value is 1.
+ * <p>
+ * The calling device admin must have requested
+ * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call
+ * this method; if it has not, a security exception will be thrown.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated
+ * with.
+ * @param length The new desired minimum number of letters required in the
+ * password. A value of 0 means there is no restriction.
+ */
+ public void setPasswordMinimumLetters(ComponentName admin, int length) {
+ if (mService != null) {
+ try {
+ mService.setPasswordMinimumLetters(admin, length);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ }
+
+ /**
+ * Retrieve the current number of letters required in the password for all
+ * admins or a particular one. This is the same value as
+ * set by {#link {@link #setPasswordMinimumLetters(ComponentName, int)}
+ * and only applies when the password quality is
+ * {@link #PASSWORD_QUALITY_COMPLEX}.
+ *
+ * @param admin The name of the admin component to check, or null to
+ * aggregate all admins.
+ * @return The minimum number of letters required in the password.
+ */
+ public int getPasswordMinimumLetters(ComponentName admin) {
+ if (mService != null) {
+ try {
+ return mService.getPasswordMinimumLetters(admin);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * Called by an application that is administering the device to set the
+ * minimum number of numerical digits required in the password. After
+ * setting this, the user will not be able to enter a new password that is
+ * not at least as restrictive as what has been set. Note that the current
+ * password will remain until the user has set a new one, so the change does
+ * not take place immediately. To prompt the user for a new password, use
+ * {@link #ACTION_SET_NEW_PASSWORD} after setting this value. This
+ * constraint is only imposed if the administrator has also requested
+ * {@link #PASSWORD_QUALITY_COMPLEX} with {@link #setPasswordQuality}. The
+ * default value is 1.
+ * <p>
+ * The calling device admin must have requested
+ * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call
+ * this method; if it has not, a security exception will be thrown.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated
+ * with.
+ * @param length The new desired minimum number of numerical digits required
+ * in the password. A value of 0 means there is no restriction.
+ */
+ public void setPasswordMinimumNumeric(ComponentName admin, int length) {
+ if (mService != null) {
+ try {
+ mService.setPasswordMinimumNumeric(admin, length);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ }
+
+ /**
+ * Retrieve the current number of numerical digits required in the password
+ * for all admins or a particular one. This is the same value as
+ * set by {#link {@link #setPasswordMinimumNumeric(ComponentName, int)}
+ * and only applies when the password quality is
+ * {@link #PASSWORD_QUALITY_COMPLEX}.
+ *
+ * @param admin The name of the admin component to check, or null to
+ * aggregate all admins.
+ * @return The minimum number of numerical digits required in the password.
+ */
+ public int getPasswordMinimumNumeric(ComponentName admin) {
+ if (mService != null) {
+ try {
+ return mService.getPasswordMinimumNumeric(admin);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * Called by an application that is administering the device to set the
+ * minimum number of symbols required in the password. After setting this,
+ * the user will not be able to enter a new password that is not at least as
+ * restrictive as what has been set. Note that the current password will
+ * remain until the user has set a new one, so the change does not take
+ * place immediately. To prompt the user for a new password, use
+ * {@link #ACTION_SET_NEW_PASSWORD} after setting this value. This
+ * constraint is only imposed if the administrator has also requested
+ * {@link #PASSWORD_QUALITY_COMPLEX} with {@link #setPasswordQuality}. The
+ * default value is 1.
+ * <p>
+ * The calling device admin must have requested
+ * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call
+ * this method; if it has not, a security exception will be thrown.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated
+ * with.
+ * @param length The new desired minimum number of symbols required in the
+ * password. A value of 0 means there is no restriction.
+ */
+ public void setPasswordMinimumSymbols(ComponentName admin, int length) {
+ if (mService != null) {
+ try {
+ mService.setPasswordMinimumSymbols(admin, length);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ }
+
+ /**
+ * Retrieve the current number of symbols required in the password for all
+ * admins or a particular one. This is the same value as
+ * set by {#link {@link #setPasswordMinimumSymbols(ComponentName, int)}
+ * and only applies when the password quality is
+ * {@link #PASSWORD_QUALITY_COMPLEX}.
+ *
+ * @param admin The name of the admin component to check, or null to
+ * aggregate all admins.
+ * @return The minimum number of symbols required in the password.
+ */
+ public int getPasswordMinimumSymbols(ComponentName admin) {
+ if (mService != null) {
+ try {
+ return mService.getPasswordMinimumSymbols(admin);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * Called by an application that is administering the device to set the
+ * minimum number of non-letter characters (numerical digits or symbols)
+ * required in the password. After setting this, the user will not be able
+ * to enter a new password that is not at least as restrictive as what has
+ * been set. Note that the current password will remain until the user has
+ * set a new one, so the change does not take place immediately. To prompt
+ * the user for a new password, use {@link #ACTION_SET_NEW_PASSWORD} after
+ * setting this value. This constraint is only imposed if the administrator
+ * has also requested {@link #PASSWORD_QUALITY_COMPLEX} with
+ * {@link #setPasswordQuality}. The default value is 0.
+ * <p>
+ * The calling device admin must have requested
+ * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call
+ * this method; if it has not, a security exception will be thrown.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated
+ * with.
+ * @param length The new desired minimum number of letters required in the
+ * password. A value of 0 means there is no restriction.
+ */
+ public void setPasswordMinimumNonLetter(ComponentName admin, int length) {
+ if (mService != null) {
+ try {
+ mService.setPasswordMinimumNonLetter(admin, length);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ }
+
+ /**
+ * Retrieve the current number of non-letter characters required in the
+ * password for all admins or a particular one. This is the same value as
+ * set by {#link {@link #setPasswordMinimumNonLetter(ComponentName, int)}
+ * and only applies when the password quality is
+ * {@link #PASSWORD_QUALITY_COMPLEX}.
+ *
+ * @param admin The name of the admin component to check, or null to
+ * aggregate all admins.
+ * @return The minimum number of letters required in the password.
+ */
+ public int getPasswordMinimumNonLetter(ComponentName admin) {
+ if (mService != null) {
+ try {
+ return mService.getPasswordMinimumNonLetter(admin);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * Called by an application that is administering the device to set the length
+ * of the password history. After setting this, the user will not be able to
+ * enter a new password that is the same as any password in the history. Note
+ * that the current password will remain until the user has set a new one, so
+ * the change does not take place immediately. To prompt the user for a new
+ * password, use {@link #ACTION_SET_NEW_PASSWORD} after setting this value.
+ * This constraint is only imposed if the administrator has also requested
+ * either {@link #PASSWORD_QUALITY_NUMERIC},
+ * {@link #PASSWORD_QUALITY_ALPHABETIC}, or
+ * {@link #PASSWORD_QUALITY_ALPHANUMERIC} with {@link #setPasswordQuality}.
+ *
+ * <p>
+ * The calling device admin must have requested
+ * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call this
+ * method; if it has not, a security exception will be thrown.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated
+ * with.
+ * @param length The new desired length of password history. A value of 0
+ * means there is no restriction.
+ */
+ public void setPasswordHistoryLength(ComponentName admin, int length) {
+ if (mService != null) {
+ try {
+ mService.setPasswordHistoryLength(admin, length);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ }
+
+ /**
+ * Retrieve the current password history length for all admins
+ * or a particular one.
+ * @param admin The name of the admin component to check, or null to aggregate
+ * all admins.
+ * @return The length of the password history
+ */
+ public int getPasswordHistoryLength(ComponentName admin) {
+ if (mService != null) {
+ try {
+ return mService.getPasswordHistoryLength(admin);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ return 0;
+ }
+
/**
* Return the maximum password length that the device supports for a
* particular password quality.
@@ -323,16 +706,16 @@
// Kind-of arbitrary.
return 16;
}
-
+
/**
* Determine whether the current password the user has set is sufficient
* to meet the policy requirements (quality, minimum length) that have been
* requested.
- *
+ *
* <p>The calling device admin must have requested
* {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call
* this method; if it has not, a security exception will be thrown.
- *
+ *
* @return Returns true if the password meets the current requirements,
* else false.
*/
@@ -346,11 +729,11 @@
}
return false;
}
-
+
/**
* Retrieve the number of times the user has failed at entering a
* password since that last successful password entry.
- *
+ *
* <p>The calling device admin must have requested
* {@link DeviceAdminInfo#USES_POLICY_WATCH_LOGIN} to be able to call
* this method; if it has not, a security exception will be thrown.
@@ -373,14 +756,14 @@
* watching for failed passwords and wiping the device, and requires
* that you request both {@link DeviceAdminInfo#USES_POLICY_WATCH_LOGIN} and
* {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA}}.
- *
+ *
* <p>To implement any other policy (e.g. wiping data for a particular
* application only, erasing or revoking credentials, or reporting the
* failure to a server), you should implement
* {@link DeviceAdminReceiver#onPasswordFailed(Context, android.content.Intent)}
* instead. Do not use this API, because if the maximum count is reached,
* the device will be wiped immediately, and your callback will not be invoked.
- *
+ *
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param num The number of failed password attempts at which point the
* device will wipe its data.
@@ -394,7 +777,7 @@
}
}
}
-
+
/**
* Retrieve the current maximum number of login attempts that are allowed
* before the device wipes itself, for all admins
@@ -412,13 +795,13 @@
}
return 0;
}
-
+
/**
* Flag for {@link #resetPassword}: don't allow other admins to change
* the password again until the user has entered it.
*/
public static final int RESET_PASSWORD_REQUIRE_ENTRY = 0x0001;
-
+
/**
* Force a new device unlock password (the password needed to access the
* entire device, not for individual accounts) on the user. This takes
@@ -431,11 +814,11 @@
* that the password may be a stronger quality (containing alphanumeric
* characters when the requested quality is only numeric), in which case
* the currently active quality will be increased to match.
- *
+ *
* <p>The calling device admin must have requested
* {@link DeviceAdminInfo#USES_POLICY_RESET_PASSWORD} to be able to call
* this method; if it has not, a security exception will be thrown.
- *
+ *
* @param password The new password for the user.
* @param flags May be 0 or {@link #RESET_PASSWORD_REQUIRE_ENTRY}.
* @return Returns true if the password was applied, or false if it is
@@ -451,16 +834,16 @@
}
return false;
}
-
+
/**
* Called by an application that is administering the device to set the
* maximum time for user activity until the device will lock. This limits
* the length that the user can set. It takes effect immediately.
- *
+ *
* <p>The calling device admin must have requested
* {@link DeviceAdminInfo#USES_POLICY_FORCE_LOCK} to be able to call
* this method; if it has not, a security exception will be thrown.
- *
+ *
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param timeMs The new desired maximum time to lock in milliseconds.
* A value of 0 means there is no restriction.
@@ -474,7 +857,7 @@
}
}
}
-
+
/**
* Retrieve the current maximum time to unlock for all admins
* or a particular one.
@@ -491,11 +874,11 @@
}
return 0;
}
-
+
/**
* Make the device lock immediately, as if the lock screen timeout has
* expired at the point of this call.
- *
+ *
* <p>The calling device admin must have requested
* {@link DeviceAdminInfo#USES_POLICY_FORCE_LOCK} to be able to call
* this method; if it has not, a security exception will be thrown.
@@ -509,16 +892,16 @@
}
}
}
-
+
/**
* Ask the user date be wiped. This will cause the device to reboot,
* erasing all user data while next booting up. External storage such
* as SD cards will not be erased.
- *
+ *
* <p>The calling device admin must have requested
* {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA} to be able to call
* this method; if it has not, a security exception will be thrown.
- *
+ *
* @param flags Bit mask of additional options: currently must be 0.
*/
public void wipeData(int flags) {
@@ -530,7 +913,7 @@
}
}
}
-
+
/**
* @hide
*/
@@ -543,7 +926,7 @@
}
}
}
-
+
/**
* @hide
*/
@@ -556,10 +939,10 @@
Log.w(TAG, "Unable to retrieve device policy " + cn, e);
return null;
}
-
+
ResolveInfo ri = new ResolveInfo();
ri.activityInfo = ai;
-
+
try {
return new DeviceAdminInfo(mContext, ri);
} catch (XmlPullParserException e) {
@@ -570,7 +953,7 @@
return null;
}
}
-
+
/**
* @hide
*/
@@ -587,16 +970,18 @@
/**
* @hide
*/
- public void setActivePasswordState(int quality, int length) {
+ public void setActivePasswordState(int quality, int length, int letters, int uppercase,
+ int lowercase, int numbers, int symbols, int nonletter) {
if (mService != null) {
try {
- mService.setActivePasswordState(quality, length);
+ mService.setActivePasswordState(quality, length, letters, uppercase, lowercase,
+ numbers, symbols, nonletter);
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
}
}
-
+
/**
* @hide
*/
@@ -609,7 +994,7 @@
}
}
}
-
+
/**
* @hide
*/
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 6fc4dc5..3ada95c 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -27,10 +27,31 @@
interface IDevicePolicyManager {
void setPasswordQuality(in ComponentName who, int quality);
int getPasswordQuality(in ComponentName who);
-
+
void setPasswordMinimumLength(in ComponentName who, int length);
int getPasswordMinimumLength(in ComponentName who);
+
+ void setPasswordMinimumUpperCase(in ComponentName who, int length);
+ int getPasswordMinimumUpperCase(in ComponentName who);
+
+ void setPasswordMinimumLowerCase(in ComponentName who, int length);
+ int getPasswordMinimumLowerCase(in ComponentName who);
+
+ void setPasswordMinimumLetters(in ComponentName who, int length);
+ int getPasswordMinimumLetters(in ComponentName who);
+
+ void setPasswordMinimumNumeric(in ComponentName who, int length);
+ int getPasswordMinimumNumeric(in ComponentName who);
+
+ void setPasswordMinimumSymbols(in ComponentName who, int length);
+ int getPasswordMinimumSymbols(in ComponentName who);
+
+ void setPasswordMinimumNonLetter(in ComponentName who, int length);
+ int getPasswordMinimumNonLetter(in ComponentName who);
+ void setPasswordHistoryLength(in ComponentName who, int length);
+ int getPasswordHistoryLength(in ComponentName who);
+
boolean isActivePasswordSufficient();
int getCurrentFailedPasswordAttempts();
@@ -53,7 +74,8 @@
void getRemoveWarning(in ComponentName policyReceiver, in RemoteCallback result);
void removeActiveAdmin(in ComponentName policyReceiver);
- void setActivePasswordState(int quality, int length);
+ void setActivePasswordState(int quality, int length, int letters, int uppercase, int lowercase,
+ int numbers, int symbols, int nonletter);
void reportFailedPasswordAttempt();
void reportSuccessfulPasswordAttempt();
}
diff --git a/core/java/android/content/AsyncTaskLoader.java b/core/java/android/content/AsyncTaskLoader.java
new file mode 100644
index 0000000..f43921fa
--- /dev/null
+++ b/core/java/android/content/AsyncTaskLoader.java
@@ -0,0 +1,88 @@
+/*
+ * 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.content;
+
+import android.os.AsyncTask;
+
+/**
+ * Abstract Loader that provides an {@link AsyncTask} to do the work.
+ *
+ * @param <D> the data type to be loaded.
+ */
+public abstract class AsyncTaskLoader<D> extends Loader<D> {
+ final class LoadTask extends AsyncTask<Void, Void, D> {
+ /* Runs on a worker thread */
+ @Override
+ protected D doInBackground(Void... params) {
+ return AsyncTaskLoader.this.loadInBackground();
+ }
+
+ /* Runs on the UI thread */
+ @Override
+ protected void onPostExecute(D data) {
+ AsyncTaskLoader.this.dispatchOnLoadComplete(data);
+ }
+ }
+
+ LoadTask mTask;
+
+ public AsyncTaskLoader(Context context) {
+ super(context);
+ }
+
+ /**
+ * Force an asynchronous load. Unlike {@link #startLoading()} this will ignore a previously
+ * loaded data set and load a new one.
+ */
+ @Override
+ public void forceLoad() {
+ mTask = new LoadTask();
+ mTask.execute((Void[]) null);
+ }
+
+ /**
+ * Attempt to cancel the current load task. See {@link AsyncTask#cancel(boolean)}
+ * for more info.
+ *
+ * @return <tt>false</tt> if the task could not be canceled,
+ * typically because it has already completed normally, or
+ * because {@link #startLoading()} hasn't been called, and
+ * <tt>true</tt> otherwise
+ */
+ public boolean cancelLoad() {
+ if (mTask != null) {
+ return mTask.cancel(false);
+ }
+ return false;
+ }
+
+ void dispatchOnLoadComplete(D data) {
+ mTask = null;
+ deliverResult(data);
+ }
+
+ /**
+ * Called on a worker thread to perform the actual load. Implementations should not deliver the
+ * results directly, but should return them from this method, which will eventually end up
+ * calling deliverResult on the UI thread. If implementations need to process
+ * the results on the UI thread they may override deliverResult and do so
+ * there.
+ *
+ * @return the result of the load
+ */
+ public abstract D loadInBackground();
+}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 30822d4..86ddee4 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -21,6 +21,7 @@
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.database.DatabaseErrorHandler;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.graphics.Bitmap;
@@ -588,6 +589,32 @@
int mode, CursorFactory factory);
/**
+ * Open a new private SQLiteDatabase associated with this Context's
+ * application package. Creates the database file if it doesn't exist.
+ *
+ * <p>Accepts input param: a concrete instance of {@link DatabaseErrorHandler} to be
+ * used to handle corruption when sqlite reports database corruption.</p>
+ *
+ * @param name The name (unique in the application package) of the database.
+ * @param mode Operating mode. Use 0 or {@link #MODE_PRIVATE} for the
+ * default operation, {@link #MODE_WORLD_READABLE}
+ * and {@link #MODE_WORLD_WRITEABLE} to control permissions.
+ * @param factory An optional factory class that is called to instantiate a
+ * cursor when query is called.
+ * @param errorHandler the {@link DatabaseErrorHandler} to be used when sqlite reports database
+ * corruption. if null, {@link android.database.DefaultDatabaseErrorHandler} is assumed.
+ * @return The contents of a newly created database with the given name.
+ * @throws android.database.sqlite.SQLiteException if the database file could not be opened.
+ *
+ * @see #MODE_PRIVATE
+ * @see #MODE_WORLD_READABLE
+ * @see #MODE_WORLD_WRITEABLE
+ * @see #deleteDatabase
+ */
+ public abstract SQLiteDatabase openOrCreateDatabase(String name,
+ int mode, CursorFactory factory, DatabaseErrorHandler errorHandler);
+
+ /**
* Delete an existing private SQLiteDatabase associated with this Context's
* application package.
*
@@ -1372,7 +1399,6 @@
public static final String SENSOR_SERVICE = "sensor";
/**
- * @hide
* Use with {@link #getSystemService} to retrieve a {@link
* android.os.storage.StorageManager} for accesssing system storage
* functions.
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index a447108..3f5d215 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -20,6 +20,7 @@
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.content.res.Resources;
+import android.database.DatabaseErrorHandler;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.graphics.Bitmap;
@@ -204,6 +205,12 @@
}
@Override
+ public SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory,
+ DatabaseErrorHandler errorHandler) {
+ return mBase.openOrCreateDatabase(name, mode, factory, errorHandler);
+ }
+
+ @Override
public boolean deleteDatabase(String name) {
return mBase.deleteDatabase(name);
}
diff --git a/core/java/android/content/CursorLoader.java b/core/java/android/content/CursorLoader.java
new file mode 100644
index 0000000..e1f9dca
--- /dev/null
+++ b/core/java/android/content/CursorLoader.java
@@ -0,0 +1,151 @@
+/*
+ * 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.content;
+
+import android.database.Cursor;
+import android.net.Uri;
+
+/**
+ * A loader that queries the {@link ContentResolver} and returns a {@link Cursor}.
+ */
+public class CursorLoader extends AsyncTaskLoader<Cursor> {
+ Cursor mCursor;
+ ForceLoadContentObserver mObserver;
+ boolean mStopped;
+ Uri mUri;
+ String[] mProjection;
+ String mSelection;
+ String[] mSelectionArgs;
+ String mSortOrder;
+
+ /* Runs on a worker thread */
+ @Override
+ public Cursor loadInBackground() {
+ Cursor cursor = getContext().getContentResolver().query(mUri, mProjection, mSelection,
+ mSelectionArgs, mSortOrder);
+ // Ensure the cursor window is filled
+ if (cursor != null) {
+ cursor.getCount();
+ cursor.registerContentObserver(mObserver);
+ }
+ return cursor;
+ }
+
+ /* Runs on the UI thread */
+ @Override
+ public void deliverResult(Cursor cursor) {
+ if (mStopped) {
+ // An async query came in while the loader is stopped
+ cursor.close();
+ return;
+ }
+ mCursor = cursor;
+ super.deliverResult(cursor);
+ }
+
+ public CursorLoader(Context context, Uri uri, String[] projection, String selection,
+ String[] selectionArgs, String sortOrder) {
+ super(context);
+ mObserver = new ForceLoadContentObserver();
+ mUri = uri;
+ mProjection = projection;
+ mSelection = selection;
+ mSelectionArgs = selectionArgs;
+ mSortOrder = sortOrder;
+ }
+
+ /**
+ * Starts an asynchronous load of the contacts list data. When the result is ready the callbacks
+ * will be called on the UI thread. If a previous load has been completed and is still valid
+ * the result may be passed to the callbacks immediately.
+ *
+ * Must be called from the UI thread
+ */
+ @Override
+ public void startLoading() {
+ mStopped = false;
+
+ if (mCursor != null) {
+ deliverResult(mCursor);
+ } else {
+ forceLoad();
+ }
+ }
+
+ /**
+ * Must be called from the UI thread
+ */
+ @Override
+ public void stopLoading() {
+ if (mCursor != null && !mCursor.isClosed()) {
+ mCursor.close();
+ mCursor = null;
+ }
+
+ // Attempt to cancel the current load task if possible.
+ cancelLoad();
+
+ // Make sure that any outstanding loads clean themselves up properly
+ mStopped = true;
+ }
+
+ @Override
+ public void destroy() {
+ // Ensure the loader is stopped
+ stopLoading();
+ }
+
+ public Uri getUri() {
+ return mUri;
+ }
+
+ public void setUri(Uri uri) {
+ mUri = uri;
+ }
+
+ public String[] getProjection() {
+ return mProjection;
+ }
+
+ public void setProjection(String[] projection) {
+ mProjection = projection;
+ }
+
+ public String getSelection() {
+ return mSelection;
+ }
+
+ public void setSelection(String selection) {
+ mSelection = selection;
+ }
+
+ public String[] getSelectionArgs() {
+ return mSelectionArgs;
+ }
+
+ public void setSelectionArgs(String[] selectionArgs) {
+ mSelectionArgs = selectionArgs;
+ }
+
+ public String getSortOrder() {
+ return mSortOrder;
+ }
+
+ public void setSortOrder(String sortOrder) {
+ mSortOrder = sortOrder;
+ }
+}
diff --git a/core/java/android/content/Loader.java b/core/java/android/content/Loader.java
new file mode 100644
index 0000000..db40e48
--- /dev/null
+++ b/core/java/android/content/Loader.java
@@ -0,0 +1,154 @@
+/*
+ * 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.content;
+
+import android.database.ContentObserver;
+import android.os.Handler;
+
+/**
+ * An abstract class that performs asynchronous loading of data. While Loaders are active
+ * they should monitor the source of their data and deliver new results when the contents
+ * change.
+ *
+ * @param <D> The result returned when the load is complete
+ */
+public abstract class Loader<D> {
+ int mId;
+ OnLoadCompleteListener<D> mListener;
+ Context mContext;
+
+ public final class ForceLoadContentObserver extends ContentObserver {
+ public ForceLoadContentObserver() {
+ super(new Handler());
+ }
+
+ @Override
+ public boolean deliverSelfNotifications() {
+ return true;
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ forceLoad();
+ }
+ }
+
+ public interface OnLoadCompleteListener<D> {
+ /**
+ * Called on the thread that created the Loader when the load is complete.
+ *
+ * @param loader the loader that completed the load
+ * @param data the result of the load
+ */
+ public void onLoadComplete(Loader<D> loader, D data);
+ }
+
+ /**
+ * Stores away the application context associated with context. Since Loaders can be used
+ * across multiple activities it's dangerous to store the context directly.
+ *
+ * @param context used to retrieve the application context.
+ */
+ public Loader(Context context) {
+ mContext = context.getApplicationContext();
+ }
+
+ /**
+ * Sends the result of the load to the registered listener. Should only be called by subclasses.
+ *
+ * Must be called from the UI thread.
+ *
+ * @param data the result of the load
+ */
+ public void deliverResult(D data) {
+ if (mListener != null) {
+ mListener.onLoadComplete(this, data);
+ }
+ }
+
+ /**
+ * @return an application context retrieved from the Context passed to the constructor.
+ */
+ public Context getContext() {
+ return mContext;
+ }
+
+ /**
+ * @return the ID of this loader
+ */
+ public int getId() {
+ return mId;
+ }
+
+ /**
+ * Registers a class that will receive callbacks when a load is complete. The callbacks will
+ * be called on the UI thread so it's safe to pass the results to widgets.
+ *
+ * Must be called from the UI thread
+ */
+ public void registerListener(int id, OnLoadCompleteListener<D> listener) {
+ if (mListener != null) {
+ throw new IllegalStateException("There is already a listener registered");
+ }
+ mListener = listener;
+ mId = id;
+ }
+
+ /**
+ * Must be called from the UI thread
+ */
+ public void unregisterListener(OnLoadCompleteListener<D> listener) {
+ if (mListener == null) {
+ throw new IllegalStateException("No listener register");
+ }
+ if (mListener != listener) {
+ throw new IllegalArgumentException("Attempting to unregister the wrong listener");
+ }
+ mListener = null;
+ }
+
+ /**
+ * Starts an asynchronous load of the contacts list data. When the result is ready the callbacks
+ * will be called on the UI thread. If a previous load has been completed and is still valid
+ * the result may be passed to the callbacks immediately. The loader will monitor the source of
+ * the data set and may deliver future callbacks if the source changes. Calling
+ * {@link #stopLoading} will stop the delivery of callbacks.
+ *
+ * Must be called from the UI thread
+ */
+ public abstract void startLoading();
+
+ /**
+ * Force an asynchronous load. Unlike {@link #startLoading()} this will ignore a previously
+ * loaded data set and load a new one.
+ */
+ public abstract void forceLoad();
+
+ /**
+ * Stops delivery of updates until the next time {@link #startLoading()} is called
+ *
+ * Must be called from the UI thread
+ */
+ public abstract void stopLoading();
+
+ /**
+ * Destroys the loader and frees its resources, making it unusable.
+ *
+ * Must be called from the UI thread
+ */
+ public abstract void destroy();
+}
\ No newline at end of file
diff --git a/core/java/android/content/SharedPreferences.java b/core/java/android/content/SharedPreferences.java
index a15e29e..5847216 100644
--- a/core/java/android/content/SharedPreferences.java
+++ b/core/java/android/content/SharedPreferences.java
@@ -17,6 +17,7 @@
package android.content;
import java.util.Map;
+import java.util.Set;
/**
* Interface for accessing and modifying preference data returned by {@link
@@ -69,6 +70,17 @@
Editor putString(String key, String value);
/**
+ * Set a set of String values in the preferences editor, to be written
+ * back once {@link #commit} is called.
+ *
+ * @param key The name of the preference to modify.
+ * @param values The new values for the preference.
+ * @return Returns a reference to the same Editor object, so you can
+ * chain put calls together.
+ */
+ Editor putStringSet(String key, Set<String> values);
+
+ /**
* Set an int value in the preferences editor, to be written back once
* {@link #commit} is called.
*
@@ -186,6 +198,20 @@
String getString(String key, String defValue);
/**
+ * Retrieve a set of String values from the preferences.
+ *
+ * @param key The name of the preference to retrieve.
+ * @param defValues Values to return if this preference does not exist.
+ *
+ * @return Returns the preference values if they exist, or defValues.
+ * Throws ClassCastException if there is a preference with this name
+ * that is not a Set.
+ *
+ * @throws ClassCastException
+ */
+ Set<String> getStringSet(String key, Set<String> defValues);
+
+ /**
* Retrieve an int value from the preferences.
*
* @param key The name of the preference to retrieve.
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index d0b67cc..7f749bb 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -16,6 +16,8 @@
package android.content;
+import com.google.android.collect.Maps;
+
import com.android.internal.R;
import com.android.internal.util.ArrayUtils;
@@ -55,6 +57,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
@@ -126,14 +129,13 @@
private static final int INITIALIZATION_UNBIND_DELAY_MS = 5000;
- private static final String SYNC_WAKE_LOCK = "SyncManagerSyncWakeLock";
+ private static final String SYNC_WAKE_LOCK_PREFIX = "SyncWakeLock";
private static final String HANDLE_SYNC_ALARM_WAKE_LOCK = "SyncManagerHandleSyncAlarmWakeLock";
private Context mContext;
private volatile Account[] mAccounts = INITIAL_ACCOUNTS_ARRAY;
- volatile private PowerManager.WakeLock mSyncWakeLock;
volatile private PowerManager.WakeLock mHandleAlarmWakeLock;
volatile private boolean mDataConnectionIsConnected = false;
volatile private boolean mStorageIsLow = false;
@@ -195,6 +197,8 @@
private static final Account[] INITIAL_ACCOUNTS_ARRAY = new Account[0];
+ private final PowerManager mPowerManager;
+
public void onAccountsUpdated(Account[] accounts) {
// remember if this was the first time this was called after an update
final boolean justBootedUp = mAccounts == INITIAL_ACCOUNTS_ARRAY;
@@ -356,15 +360,13 @@
} else {
mNotificationMgr = null;
}
- PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
- mSyncWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, SYNC_WAKE_LOCK);
- mSyncWakeLock.setReferenceCounted(false);
+ mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
// This WakeLock is used to ensure that we stay awake between the time that we receive
// a sync alarm notification and when we finish processing it. We need to do this
// because we don't do the work in the alarm handler, rather we do it in a message
// handler.
- mHandleAlarmWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
+ mHandleAlarmWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
HANDLE_SYNC_ALARM_WAKE_LOCK);
mHandleAlarmWakeLock.setReferenceCounted(false);
@@ -1302,6 +1304,9 @@
public final SyncNotificationInfo mSyncNotificationInfo = new SyncNotificationInfo();
private Long mAlarmScheduleTime = null;
public final SyncTimeTracker mSyncTimeTracker = new SyncTimeTracker();
+ private PowerManager.WakeLock mSyncWakeLock;
+ private final HashMap<Pair<String, String>, PowerManager.WakeLock> mWakeLocks =
+ Maps.newHashMap();
// used to track if we have installed the error notification so that we don't reinstall
// it if sync is still failing
@@ -1315,6 +1320,18 @@
}
}
+ private PowerManager.WakeLock getSyncWakeLock(String accountType, String authority) {
+ final Pair<String, String> wakeLockKey = Pair.create(accountType, authority);
+ PowerManager.WakeLock wakeLock = mWakeLocks.get(wakeLockKey);
+ if (wakeLock == null) {
+ final String name = SYNC_WAKE_LOCK_PREFIX + "_" + authority + "_" + accountType;
+ wakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, name);
+ wakeLock.setReferenceCounted(false);
+ mWakeLocks.put(wakeLockKey, wakeLock);
+ }
+ return wakeLock;
+ }
+
private void waitUntilReadyToRun() {
CountDownLatch latch = mReadyToRunLatch;
if (latch != null) {
@@ -1477,8 +1494,9 @@
}
} finally {
final boolean isSyncInProgress = mActiveSyncContext != null;
- if (!isSyncInProgress) {
+ if (!isSyncInProgress && mSyncWakeLock != null) {
mSyncWakeLock.release();
+ mSyncWakeLock = null;
}
manageSyncNotification();
manageErrorNotification();
@@ -1704,7 +1722,26 @@
return;
}
- mSyncWakeLock.acquire();
+ // Find the wakelock for this account and authority and store it in mSyncWakeLock.
+ // Be sure to release the previous wakelock so that we don't end up with it being
+ // held until it is used again.
+ // There are a couple tricky things about this code:
+ // - make sure that we acquire the new wakelock before releasing the old one,
+ // otherwise the device might go to sleep as soon as we release it.
+ // - since we use non-reference counted wakelocks we have to be sure not to do
+ // the release if the wakelock didn't change. Othewise we would do an
+ // acquire followed by a release on the same lock, resulting in no lock
+ // being held.
+ PowerManager.WakeLock oldWakeLock = mSyncWakeLock;
+ try {
+ mSyncWakeLock = getSyncWakeLock(op.account.type, op.authority);
+ mSyncWakeLock.acquire();
+ } finally {
+ if (oldWakeLock != null && oldWakeLock != mSyncWakeLock) {
+ oldWakeLock.release();
+ }
+ }
+
// no need to schedule an alarm, as that will be done by our caller.
// the next step will occur when we get either a timeout or a
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 7901b155..35f22dc 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -284,6 +284,12 @@
public static final int FLAG_HEAVY_WEIGHT = 1<<20;
/**
+ * Value for {@link #flags}: true when the application's rendering should
+ * be hardware accelerated.
+ */
+ public static final int FLAG_HARDWARE_ACCELERATED = 1<<21;
+
+ /**
* Value for {@link #flags}: this is true if the application has set
* its android:neverEncrypt to true, false otherwise. It is used to specify
* that this package specifically "opts-out" of a secured file system solution,
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index a5f5acc..78379d2 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1536,6 +1536,12 @@
}
if (sa.getBoolean(
+ com.android.internal.R.styleable.AndroidManifestApplication_hardwareAccelerated,
+ false)) {
+ ai.flags |= ApplicationInfo.FLAG_HARDWARE_ACCELERATED;
+ }
+
+ if (sa.getBoolean(
com.android.internal.R.styleable.AndroidManifestApplication_hasCode,
true)) {
ai.flags |= ApplicationInfo.FLAG_HAS_CODE;
diff --git a/core/java/android/database/AbstractCursor.java b/core/java/android/database/AbstractCursor.java
index 038eedf..b1f33ec 100644
--- a/core/java/android/database/AbstractCursor.java
+++ b/core/java/android/database/AbstractCursor.java
@@ -18,16 +18,11 @@
import android.content.ContentResolver;
import android.net.Uri;
+import android.os.Bundle;
import android.util.Config;
import android.util.Log;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Message;
import java.lang.ref.WeakReference;
-import java.lang.UnsupportedOperationException;
import java.util.HashMap;
import java.util.Map;
@@ -56,6 +51,10 @@
abstract public double getDouble(int column);
abstract public boolean isNull(int column);
+ public int getType(int column) {
+ throw new UnsupportedOperationException();
+ }
+
// TODO implement getBlob in all cursor types
public byte[] getBlob(int column) {
throw new UnsupportedOperationException("getBlob is not supported");
@@ -88,7 +87,7 @@
}
mDataSetObservable.notifyInvalidated();
}
-
+
public boolean requery() {
if (mSelfObserver != null && mSelfObserverRegistered == false) {
mContentResolver.registerContentObserver(mNotifyUri, true, mSelfObserver);
@@ -109,22 +108,6 @@
}
/**
- * @hide
- * @deprecated
- */
- public boolean commitUpdates(Map<? extends Long,? extends Map<String,Object>> values) {
- return false;
- }
-
- /**
- * @hide
- * @deprecated
- */
- public boolean deleteRow() {
- return false;
- }
-
- /**
* This function is called every time the cursor is successfully scrolled
* to a new position, giving the subclass a chance to update any state it
* may have. If it returns false the move function will also do so and the
@@ -320,137 +303,6 @@
return getColumnNames()[columnIndex];
}
- /**
- * @hide
- * @deprecated
- */
- public boolean updateBlob(int columnIndex, byte[] value) {
- return update(columnIndex, value);
- }
-
- /**
- * @hide
- * @deprecated
- */
- public boolean updateString(int columnIndex, String value) {
- return update(columnIndex, value);
- }
-
- /**
- * @hide
- * @deprecated
- */
- public boolean updateShort(int columnIndex, short value) {
- return update(columnIndex, Short.valueOf(value));
- }
-
- /**
- * @hide
- * @deprecated
- */
- public boolean updateInt(int columnIndex, int value) {
- return update(columnIndex, Integer.valueOf(value));
- }
-
- /**
- * @hide
- * @deprecated
- */
- public boolean updateLong(int columnIndex, long value) {
- return update(columnIndex, Long.valueOf(value));
- }
-
- /**
- * @hide
- * @deprecated
- */
- public boolean updateFloat(int columnIndex, float value) {
- return update(columnIndex, Float.valueOf(value));
- }
-
- /**
- * @hide
- * @deprecated
- */
- public boolean updateDouble(int columnIndex, double value) {
- return update(columnIndex, Double.valueOf(value));
- }
-
- /**
- * @hide
- * @deprecated
- */
- public boolean updateToNull(int columnIndex) {
- return update(columnIndex, null);
- }
-
- /**
- * @hide
- * @deprecated
- */
- public boolean update(int columnIndex, Object obj) {
- if (!supportsUpdates()) {
- return false;
- }
-
- // Long.valueOf() returns null sometimes!
-// Long rowid = Long.valueOf(getLong(mRowIdColumnIndex));
- Long rowid = new Long(getLong(mRowIdColumnIndex));
- if (rowid == null) {
- throw new IllegalStateException("null rowid. mRowIdColumnIndex = " + mRowIdColumnIndex);
- }
-
- synchronized(mUpdatedRows) {
- Map<String, Object> row = mUpdatedRows.get(rowid);
- if (row == null) {
- row = new HashMap<String, Object>();
- mUpdatedRows.put(rowid, row);
- }
- row.put(getColumnNames()[columnIndex], obj);
- }
-
- return true;
- }
-
- /**
- * Returns <code>true</code> if there are pending updates that have not yet been committed.
- *
- * @return <code>true</code> if there are pending updates that have not yet been committed.
- * @hide
- * @deprecated
- */
- public boolean hasUpdates() {
- synchronized(mUpdatedRows) {
- return mUpdatedRows.size() > 0;
- }
- }
-
- /**
- * @hide
- * @deprecated
- */
- public void abortUpdates() {
- synchronized(mUpdatedRows) {
- mUpdatedRows.clear();
- }
- }
-
- /**
- * @hide
- * @deprecated
- */
- public boolean commitUpdates() {
- return commitUpdates(null);
- }
-
- /**
- * @hide
- * @deprecated
- */
- public boolean supportsUpdates() {
- return mRowIdColumnIndex != -1;
- }
-
public void registerContentObserver(ContentObserver observer) {
mContentObservable.registerObserver(observer);
}
diff --git a/core/java/android/database/AbstractWindowedCursor.java b/core/java/android/database/AbstractWindowedCursor.java
index 27a02e2..e47d9ce 100644
--- a/core/java/android/database/AbstractWindowedCursor.java
+++ b/core/java/android/database/AbstractWindowedCursor.java
@@ -149,63 +149,36 @@
}
}
- return mWindow.isNull(mPos, columnIndex);
+ return mWindow.getType(mPos, columnIndex) == Cursor.FIELD_TYPE_NULL;
}
- public boolean isBlob(int columnIndex)
+ public boolean isBlob(int columnIndex) {
+ return getType(columnIndex) == Cursor.FIELD_TYPE_BLOB;
+ }
+
+ public boolean isString(int columnIndex) {
+ return getType(columnIndex) == Cursor.FIELD_TYPE_STRING;
+ }
+
+ public boolean isLong(int columnIndex) {
+ return getType(columnIndex) == Cursor.FIELD_TYPE_INTEGER;
+ }
+
+ public boolean isFloat(int columnIndex) {
+ return getType(columnIndex) == Cursor.FIELD_TYPE_FLOAT;
+ }
+
+ @Override
+ public int getType(int columnIndex)
{
checkPosition();
-
synchronized(mUpdatedRows) {
if (isFieldUpdated(columnIndex)) {
- Object object = getUpdatedField(columnIndex);
- return object == null || object instanceof byte[];
+ return DatabaseUtils.getTypeOfObject(getUpdatedField(columnIndex));
}
}
- return mWindow.isBlob(mPos, columnIndex);
- }
-
- public boolean isString(int columnIndex)
- {
- checkPosition();
-
- synchronized(mUpdatedRows) {
- if (isFieldUpdated(columnIndex)) {
- Object object = getUpdatedField(columnIndex);
- return object == null || object instanceof String;
- }
- }
-
- return mWindow.isString(mPos, columnIndex);
- }
-
- public boolean isLong(int columnIndex)
- {
- checkPosition();
-
- synchronized(mUpdatedRows) {
- if (isFieldUpdated(columnIndex)) {
- Object object = getUpdatedField(columnIndex);
- return object != null && (object instanceof Integer || object instanceof Long);
- }
- }
-
- return mWindow.isLong(mPos, columnIndex);
- }
-
- public boolean isFloat(int columnIndex)
- {
- checkPosition();
-
- synchronized(mUpdatedRows) {
- if (isFieldUpdated(columnIndex)) {
- Object object = getUpdatedField(columnIndex);
- return object != null && (object instanceof Float || object instanceof Double);
- }
- }
-
- return mWindow.isFloat(mPos, columnIndex);
+ return mWindow.getType(mPos, columnIndex);
}
@Override
diff --git a/core/java/android/database/BulkCursorNative.java b/core/java/android/database/BulkCursorNative.java
index baa94d8..fa62d69 100644
--- a/core/java/android/database/BulkCursorNative.java
+++ b/core/java/android/database/BulkCursorNative.java
@@ -17,13 +17,10 @@
package android.database;
import android.os.Binder;
-import android.os.RemoteException;
+import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
-import android.os.Bundle;
-
-import java.util.HashMap;
-import java.util.Map;
+import android.os.RemoteException;
/**
* Native implementation of the bulk cursor. This is only for use in implementing
@@ -120,26 +117,6 @@
return true;
}
- case UPDATE_ROWS_TRANSACTION: {
- data.enforceInterface(IBulkCursor.descriptor);
- // TODO - what ClassLoader should be passed to readHashMap?
- // TODO - switch to Bundle
- HashMap<Long, Map<String, Object>> values = data.readHashMap(null);
- boolean result = updateRows(values);
- reply.writeNoException();
- reply.writeInt((result == true ? 1 : 0));
- return true;
- }
-
- case DELETE_ROW_TRANSACTION: {
- data.enforceInterface(IBulkCursor.descriptor);
- int position = data.readInt();
- boolean result = deleteRow(position);
- reply.writeNoException();
- reply.writeInt((result == true ? 1 : 0));
- return true;
- }
-
case ON_MOVE_TRANSACTION: {
data.enforceInterface(IBulkCursor.descriptor);
int position = data.readInt();
@@ -343,48 +320,6 @@
return count;
}
- public boolean updateRows(Map values) throws RemoteException
- {
- Parcel data = Parcel.obtain();
- Parcel reply = Parcel.obtain();
-
- data.writeInterfaceToken(IBulkCursor.descriptor);
-
- data.writeMap(values);
-
- mRemote.transact(UPDATE_ROWS_TRANSACTION, data, reply, 0);
-
- DatabaseUtils.readExceptionFromParcel(reply);
-
- boolean result = (reply.readInt() == 1 ? true : false);
-
- data.recycle();
- reply.recycle();
-
- return result;
- }
-
- public boolean deleteRow(int position) throws RemoteException
- {
- Parcel data = Parcel.obtain();
- Parcel reply = Parcel.obtain();
-
- data.writeInterfaceToken(IBulkCursor.descriptor);
-
- data.writeInt(position);
-
- mRemote.transact(DELETE_ROW_TRANSACTION, data, reply, 0);
-
- DatabaseUtils.readExceptionFromParcel(reply);
-
- boolean result = (reply.readInt() == 1 ? true : false);
-
- data.recycle();
- reply.recycle();
-
- return result;
- }
-
public boolean getWantsAllOnMoveCalls() throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
diff --git a/core/java/android/database/BulkCursorToCursorAdaptor.java b/core/java/android/database/BulkCursorToCursorAdaptor.java
index 1469ea2..2cb2aec 100644
--- a/core/java/android/database/BulkCursorToCursorAdaptor.java
+++ b/core/java/android/database/BulkCursorToCursorAdaptor.java
@@ -16,12 +16,10 @@
package android.database;
-import android.os.RemoteException;
import android.os.Bundle;
+import android.os.RemoteException;
import android.util.Log;
-import java.util.Map;
-
/**
* Adapts an {@link IBulkCursor} to a {@link Cursor} for use in the local
* process.
@@ -174,38 +172,6 @@
}
}
- /**
- * @hide
- * @deprecated
- */
- @Override
- public boolean deleteRow() {
- try {
- boolean result = mBulkCursor.deleteRow(mPos);
- if (result != false) {
- // The window contains the old value, discard it
- mWindow = null;
-
- // Fix up the position
- mCount = mBulkCursor.count();
- if (mPos < mCount) {
- int oldPos = mPos;
- mPos = -1;
- moveToPosition(oldPos);
- } else {
- mPos = mCount;
- }
-
- // Send the change notification
- onChange(true);
- }
- return result;
- } catch (RemoteException ex) {
- Log.e(TAG, "Unable to delete row because the remote process is dead");
- return false;
- }
- }
-
@Override
public String[] getColumnNames() {
if (mColumns == null) {
@@ -219,44 +185,6 @@
return mColumns;
}
- /**
- * @hide
- * @deprecated
- */
- @Override
- public boolean commitUpdates(Map<? extends Long,
- ? extends Map<String,Object>> additionalValues) {
- if (!supportsUpdates()) {
- Log.e(TAG, "commitUpdates not supported on this cursor, did you include the _id column?");
- return false;
- }
-
- synchronized(mUpdatedRows) {
- if (additionalValues != null) {
- mUpdatedRows.putAll(additionalValues);
- }
-
- if (mUpdatedRows.size() <= 0) {
- return false;
- }
-
- try {
- boolean result = mBulkCursor.updateRows(mUpdatedRows);
-
- if (result == true) {
- mUpdatedRows.clear();
-
- // Send the change notification
- onChange(true);
- }
- return result;
- } catch (RemoteException ex) {
- Log.e(TAG, "Unable to commit updates because the remote process is dead");
- return false;
- }
- }
- }
-
@Override
public Bundle getExtras() {
try {
diff --git a/core/java/android/database/Cursor.java b/core/java/android/database/Cursor.java
index 6539156..c03c586 100644
--- a/core/java/android/database/Cursor.java
+++ b/core/java/android/database/Cursor.java
@@ -30,6 +30,25 @@
* threads should perform its own synchronization when using the Cursor.
*/
public interface Cursor {
+ /*
+ * Values returned by {@link #getType(int)}.
+ * These should be consistent with the corresponding types defined in CursorWindow.h
+ */
+ /** Value returned by {@link #getType(int)} if the specified column is null */
+ static final int FIELD_TYPE_NULL = 0;
+
+ /** Value returned by {@link #getType(int)} if the specified column type is integer */
+ static final int FIELD_TYPE_INTEGER = 1;
+
+ /** Value returned by {@link #getType(int)} if the specified column type is float */
+ static final int FIELD_TYPE_FLOAT = 2;
+
+ /** Value returned by {@link #getType(int)} if the specified column type is string */
+ static final int FIELD_TYPE_STRING = 3;
+
+ /** Value returned by {@link #getType(int)} if the specified column type is blob */
+ static final int FIELD_TYPE_BLOB = 4;
+
/**
* Returns the numbers of rows in the cursor.
*
@@ -146,22 +165,6 @@
boolean isAfterLast();
/**
- * Removes the row at the current cursor position from the underlying data
- * store. After this method returns the cursor will be pointing to the row
- * after the row that is deleted. This has the side effect of decrementing
- * the result of count() by one.
- * <p>
- * The query must have the row ID column in its selection, otherwise this
- * call will fail.
- *
- * @hide
- * @return whether the record was successfully deleted.
- * @deprecated use {@link ContentResolver#delete(Uri, String, String[])}
- */
- @Deprecated
- boolean deleteRow();
-
- /**
* Returns the zero-based index for the given column name, or -1 if the column doesn't exist.
* If you expect the column to exist use {@link #getColumnIndexOrThrow(String)} instead, which
* will make the error more clear.
@@ -295,6 +298,27 @@
double getDouble(int columnIndex);
/**
+ * Returns data type of the given column's value.
+ * The preferred type of the column is returned but the data may be converted to other types
+ * as documented in the get-type methods such as {@link #getInt(int)}, {@link #getFloat(int)}
+ * etc.
+ *<p>
+ * Returned column types are
+ * <ul>
+ * <li>{@link #FIELD_TYPE_NULL}</li>
+ * <li>{@link #FIELD_TYPE_INTEGER}</li>
+ * <li>{@link #FIELD_TYPE_FLOAT}</li>
+ * <li>{@link #FIELD_TYPE_STRING}</li>
+ * <li>{@link #FIELD_TYPE_BLOB}</li>
+ *</ul>
+ *</p>
+ *
+ * @param columnIndex the zero-based index of the target column.
+ * @return column value type
+ */
+ int getType(int columnIndex);
+
+ /**
* Returns <code>true</code> if the value in the indicated column is null.
*
* @param columnIndex the zero-based index of the target column.
@@ -303,188 +327,6 @@
boolean isNull(int columnIndex);
/**
- * Returns <code>true</code> if the cursor supports updates.
- *
- * @return whether the cursor supports updates.
- * @hide
- * @deprecated use the {@link ContentResolver} update methods instead of the Cursor
- * update methods
- */
- @Deprecated
- boolean supportsUpdates();
-
- /**
- * Returns <code>true</code> if there are pending updates that have not yet been committed.
- *
- * @return <code>true</code> if there are pending updates that have not yet been committed.
- * @hide
- * @deprecated use the {@link ContentResolver} update methods instead of the Cursor
- * update methods
- */
- @Deprecated
- boolean hasUpdates();
-
- /**
- * Updates the value for the given column in the row the cursor is
- * currently pointing at. Updates are not committed to the backing store
- * until {@link #commitUpdates()} is called.
- *
- * @param columnIndex the zero-based index of the target column.
- * @param value the new value.
- * @return whether the operation succeeded.
- * @hide
- * @deprecated use the {@link ContentResolver} update methods instead of the Cursor
- * update methods
- */
- @Deprecated
- boolean updateBlob(int columnIndex, byte[] value);
-
- /**
- * Updates the value for the given column in the row the cursor is
- * currently pointing at. Updates are not committed to the backing store
- * until {@link #commitUpdates()} is called.
- *
- * @param columnIndex the zero-based index of the target column.
- * @param value the new value.
- * @return whether the operation succeeded.
- * @hide
- * @deprecated use the {@link ContentResolver} update methods instead of the Cursor
- * update methods
- */
- @Deprecated
- boolean updateString(int columnIndex, String value);
-
- /**
- * Updates the value for the given column in the row the cursor is
- * currently pointing at. Updates are not committed to the backing store
- * until {@link #commitUpdates()} is called.
- *
- * @param columnIndex the zero-based index of the target column.
- * @param value the new value.
- * @return whether the operation succeeded.
- * @hide
- * @deprecated use the {@link ContentResolver} update methods instead of the Cursor
- * update methods
- */
- @Deprecated
- boolean updateShort(int columnIndex, short value);
-
- /**
- * Updates the value for the given column in the row the cursor is
- * currently pointing at. Updates are not committed to the backing store
- * until {@link #commitUpdates()} is called.
- *
- * @param columnIndex the zero-based index of the target column.
- * @param value the new value.
- * @return whether the operation succeeded.
- * @hide
- * @deprecated use the {@link ContentResolver} update methods instead of the Cursor
- * update methods
- */
- @Deprecated
- boolean updateInt(int columnIndex, int value);
-
- /**
- * Updates the value for the given column in the row the cursor is
- * currently pointing at. Updates are not committed to the backing store
- * until {@link #commitUpdates()} is called.
- *
- * @param columnIndex the zero-based index of the target column.
- * @param value the new value.
- * @return whether the operation succeeded.
- * @hide
- * @deprecated use the {@link ContentResolver} update methods instead of the Cursor
- * update methods
- */
- @Deprecated
- boolean updateLong(int columnIndex, long value);
-
- /**
- * Updates the value for the given column in the row the cursor is
- * currently pointing at. Updates are not committed to the backing store
- * until {@link #commitUpdates()} is called.
- *
- * @param columnIndex the zero-based index of the target column.
- * @param value the new value.
- * @return whether the operation succeeded.
- * @hide
- * @deprecated use the {@link ContentResolver} update methods instead of the Cursor
- * update methods
- */
- @Deprecated
- boolean updateFloat(int columnIndex, float value);
-
- /**
- * Updates the value for the given column in the row the cursor is
- * currently pointing at. Updates are not committed to the backing store
- * until {@link #commitUpdates()} is called.
- *
- * @param columnIndex the zero-based index of the target column.
- * @param value the new value.
- * @return whether the operation succeeded.
- * @hide
- * @deprecated use the {@link ContentResolver} update methods instead of the Cursor
- * update methods
- */
- @Deprecated
- boolean updateDouble(int columnIndex, double value);
-
- /**
- * Removes the value for the given column in the row the cursor is
- * currently pointing at. Updates are not committed to the backing store
- * until {@link #commitUpdates()} is called.
- *
- * @param columnIndex the zero-based index of the target column.
- * @return whether the operation succeeded.
- * @hide
- * @deprecated use the {@link ContentResolver} update methods instead of the Cursor
- * update methods
- */
- @Deprecated
- boolean updateToNull(int columnIndex);
-
- /**
- * Atomically commits all updates to the backing store. After completion,
- * this method leaves the data in an inconsistent state and you should call
- * {@link #requery} before reading data from the cursor again.
- *
- * @return whether the operation succeeded.
- * @hide
- * @deprecated use the {@link ContentResolver} update methods instead of the Cursor
- * update methods
- */
- @Deprecated
- boolean commitUpdates();
-
- /**
- * Atomically commits all updates to the backing store, as well as the
- * updates included in values. After completion,
- * this method leaves the data in an inconsistent state and you should call
- * {@link #requery} before reading data from the cursor again.
- *
- * @param values A map from row IDs to Maps associating column names with
- * updated values. A null value indicates the field should be
- removed.
- * @return whether the operation succeeded.
- * @hide
- * @deprecated use the {@link ContentResolver} update methods instead of the Cursor
- * update methods
- */
- @Deprecated
- boolean commitUpdates(Map<? extends Long,
- ? extends Map<String,Object>> values);
-
- /**
- * Reverts all updates made to the cursor since the last call to
- * commitUpdates.
- * @hide
- * @deprecated use the {@link ContentResolver} update methods instead of the Cursor
- * update methods
- */
- @Deprecated
- void abortUpdates();
-
- /**
* Deactivates the Cursor, making all calls on it fail until {@link #requery} is called.
* Inactive Cursors use fewer resources than active Cursors.
* Calling {@link #requery} will make the cursor active again.
@@ -496,6 +338,10 @@
* contents. This may be done at any time, including after a call to {@link
* #deactivate}.
*
+ * Since this method could execute a query on the database and potentially take
+ * a while, it could cause ANR if it is called on Main (UI) thread.
+ * A warning is printed if this method is being executed on Main thread.
+ *
* @return true if the requery succeeded, false if not, in which case the
* cursor becomes invalid.
*/
diff --git a/core/java/android/database/CursorToBulkCursorAdaptor.java b/core/java/android/database/CursorToBulkCursorAdaptor.java
index 748eb99..8bc7de2 100644
--- a/core/java/android/database/CursorToBulkCursorAdaptor.java
+++ b/core/java/android/database/CursorToBulkCursorAdaptor.java
@@ -16,16 +16,12 @@
package android.database;
-import android.database.sqlite.SQLiteMisuseException;
-import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Config;
import android.util.Log;
-import java.util.Map;
-
/**
* Wraps a BulkCursor around an existing Cursor making it remotable.
@@ -38,7 +34,6 @@
private final CrossProcessCursor mCursor;
private CursorWindow mWindow;
private final String mProviderName;
- private final boolean mReadOnly;
private ContentObserverProxy mObserver;
private static final class ContentObserverProxy extends ContentObserver
@@ -98,7 +93,6 @@
"Only CrossProcessCursor cursors are supported across process for now", e);
}
mProviderName = providerName;
- mReadOnly = !allowWrite;
createAndRegisterObserverProxy(observer);
}
@@ -197,31 +191,6 @@
}
}
- public boolean updateRows(Map<? extends Long, ? extends Map<String, Object>> values) {
- if (mReadOnly) {
- Log.w("ContentProvider", "Permission Denial: modifying "
- + mProviderName
- + " from pid=" + Binder.getCallingPid()
- + ", uid=" + Binder.getCallingUid());
- return false;
- }
- return mCursor.commitUpdates(values);
- }
-
- public boolean deleteRow(int position) {
- if (mReadOnly) {
- Log.w("ContentProvider", "Permission Denial: modifying "
- + mProviderName
- + " from pid=" + Binder.getCallingPid()
- + ", uid=" + Binder.getCallingUid());
- return false;
- }
- if (mCursor.moveToPosition(position) == false) {
- return false;
- }
- return mCursor.deleteRow();
- }
-
public Bundle getExtras() {
return mCursor.getExtras();
}
diff --git a/core/java/android/database/CursorWindow.java b/core/java/android/database/CursorWindow.java
index c756825..39889b9 100644
--- a/core/java/android/database/CursorWindow.java
+++ b/core/java/android/database/CursorWindow.java
@@ -217,14 +217,11 @@
* @param row the row to read from, row - getStartPosition() being the actual row in the window
* @param col the column to read from
* @return {@code true} if given field is {@code NULL}
+ * @deprecated use {@link #getType(int, int)} instead
*/
+ @Deprecated
public boolean isNull(int row, int col) {
- acquireReference();
- try {
- return isNull_native(row - mStartPos, col);
- } finally {
- releaseReference();
- }
+ return getType(row, col) == Cursor.FIELD_TYPE_NULL;
}
private native boolean isNull_native(int row, int col);
@@ -248,19 +245,42 @@
private native byte[] getBlob_native(int row, int col);
/**
+ * Returns data type of the given column's value.
+ *<p>
+ * Returned column types are
+ * <ul>
+ * <li>{@link Cursor#FIELD_TYPE_NULL}</li>
+ * <li>{@link Cursor#FIELD_TYPE_INTEGER}</li>
+ * <li>{@link Cursor#FIELD_TYPE_FLOAT}</li>
+ * <li>{@link Cursor#FIELD_TYPE_STRING}</li>
+ * <li>{@link Cursor#FIELD_TYPE_BLOB}</li>
+ *</ul>
+ *</p>
+ *
+ * @param row the row to read from, row - getStartPosition() being the actual row in the window
+ * @param col the column to read from
+ * @return the value type
+ */
+ public int getType(int row, int col) {
+ acquireReference();
+ try {
+ return getType_native(row - mStartPos, col);
+ } finally {
+ releaseReference();
+ }
+ }
+
+ /**
* Checks if a field contains either a blob or is null.
*
* @param row the row to read from, row - getStartPosition() being the actual row in the window
* @param col the column to read from
* @return {@code true} if given field is {@code NULL} or a blob
+ * @deprecated use {@link #getType(int, int)} instead
*/
+ @Deprecated
public boolean isBlob(int row, int col) {
- acquireReference();
- try {
- return isBlob_native(row - mStartPos, col);
- } finally {
- releaseReference();
- }
+ return getType(row, col) == Cursor.FIELD_TYPE_BLOB;
}
/**
@@ -269,14 +289,11 @@
* @param row the row to read from, row - getStartPosition() being the actual row in the window
* @param col the column to read from
* @return {@code true} if given field is a long
+ * @deprecated use {@link #getType(int, int)} instead
*/
+ @Deprecated
public boolean isLong(int row, int col) {
- acquireReference();
- try {
- return isInteger_native(row - mStartPos, col);
- } finally {
- releaseReference();
- }
+ return getType(row, col) == Cursor.FIELD_TYPE_INTEGER;
}
/**
@@ -285,14 +302,11 @@
* @param row the row to read from, row - getStartPosition() being the actual row in the window
* @param col the column to read from
* @return {@code true} if given field is a float
+ * @deprecated use {@link #getType(int, int)} instead
*/
+ @Deprecated
public boolean isFloat(int row, int col) {
- acquireReference();
- try {
- return isFloat_native(row - mStartPos, col);
- } finally {
- releaseReference();
- }
+ return getType(row, col) == Cursor.FIELD_TYPE_FLOAT;
}
/**
@@ -301,20 +315,18 @@
* @param row the row to read from, row - getStartPosition() being the actual row in the window
* @param col the column to read from
* @return {@code true} if given field is {@code NULL} or a String
+ * @deprecated use {@link #getType(int, int)} instead
*/
+ @Deprecated
public boolean isString(int row, int col) {
- acquireReference();
- try {
- return isString_native(row - mStartPos, col);
- } finally {
- releaseReference();
- }
+ return getType(row, col) == Cursor.FIELD_TYPE_STRING;
}
private native boolean isBlob_native(int row, int col);
private native boolean isString_native(int row, int col);
private native boolean isInteger_native(int row, int col);
private native boolean isFloat_native(int row, int col);
+ private native int getType_native(int row, int col);
/**
* Returns a String for the given field.
diff --git a/core/java/android/database/CursorWrapper.java b/core/java/android/database/CursorWrapper.java
index f0aa7d7..2ac9470 100644
--- a/core/java/android/database/CursorWrapper.java
+++ b/core/java/android/database/CursorWrapper.java
@@ -32,14 +32,6 @@
public CursorWrapper(Cursor cursor) {
mCursor = cursor;
}
-
- /**
- * @hide
- * @deprecated
- */
- public void abortUpdates() {
- mCursor.abortUpdates();
- }
public void close() {
mCursor.close();
@@ -49,23 +41,6 @@
return mCursor.isClosed();
}
- /**
- * @hide
- * @deprecated
- */
- public boolean commitUpdates() {
- return mCursor.commitUpdates();
- }
-
- /**
- * @hide
- * @deprecated
- */
- public boolean commitUpdates(
- Map<? extends Long, ? extends Map<String, Object>> values) {
- return mCursor.commitUpdates(values);
- }
-
public int getCount() {
return mCursor.getCount();
}
@@ -74,14 +49,6 @@
mCursor.deactivate();
}
- /**
- * @hide
- * @deprecated
- */
- public boolean deleteRow() {
- return mCursor.deleteRow();
- }
-
public boolean moveToFirst() {
return mCursor.moveToFirst();
}
@@ -147,14 +114,6 @@
return mCursor.getWantsAllOnMoveCalls();
}
- /**
- * @hide
- * @deprecated
- */
- public boolean hasUpdates() {
- return mCursor.hasUpdates();
- }
-
public boolean isAfterLast() {
return mCursor.isAfterLast();
}
@@ -171,6 +130,10 @@
return mCursor.isLast();
}
+ public int getType(int columnIndex) {
+ return mCursor.getType(columnIndex);
+ }
+
public boolean isNull(int columnIndex) {
return mCursor.isNull(columnIndex);
}
@@ -219,14 +182,6 @@
mCursor.setNotificationUri(cr, uri);
}
- /**
- * @hide
- * @deprecated
- */
- public boolean supportsUpdates() {
- return mCursor.supportsUpdates();
- }
-
public void unregisterContentObserver(ContentObserver observer) {
mCursor.unregisterContentObserver(observer);
}
@@ -235,71 +190,6 @@
mCursor.unregisterDataSetObserver(observer);
}
- /**
- * @hide
- * @deprecated
- */
- public boolean updateDouble(int columnIndex, double value) {
- return mCursor.updateDouble(columnIndex, value);
- }
-
- /**
- * @hide
- * @deprecated
- */
- public boolean updateFloat(int columnIndex, float value) {
- return mCursor.updateFloat(columnIndex, value);
- }
-
- /**
- * @hide
- * @deprecated
- */
- public boolean updateInt(int columnIndex, int value) {
- return mCursor.updateInt(columnIndex, value);
- }
-
- /**
- * @hide
- * @deprecated
- */
- public boolean updateLong(int columnIndex, long value) {
- return mCursor.updateLong(columnIndex, value);
- }
-
- /**
- * @hide
- * @deprecated
- */
- public boolean updateShort(int columnIndex, short value) {
- return mCursor.updateShort(columnIndex, value);
- }
-
- /**
- * @hide
- * @deprecated
- */
- public boolean updateString(int columnIndex, String value) {
- return mCursor.updateString(columnIndex, value);
- }
-
- /**
- * @hide
- * @deprecated
- */
- public boolean updateBlob(int columnIndex, byte[] value) {
- return mCursor.updateBlob(columnIndex, value);
- }
-
- /**
- * @hide
- * @deprecated
- */
- public boolean updateToNull(int columnIndex) {
- return mCursor.updateToNull(columnIndex);
- }
-
- private Cursor mCursor;
-
+ private Cursor mCursor;
}
diff --git a/core/java/android/database/DataSetObservable.java b/core/java/android/database/DataSetObservable.java
index 9200e81..51c72c1 100644
--- a/core/java/android/database/DataSetObservable.java
+++ b/core/java/android/database/DataSetObservable.java
@@ -27,8 +27,12 @@
*/
public void notifyChanged() {
synchronized(mObservers) {
- for (DataSetObserver observer : mObservers) {
- observer.onChanged();
+ // since onChanged() is implemented by the app, it could do anything, including
+ // removing itself from {@link mObservers} - and that could cause problems if
+ // an iterator is used on the ArrayList {@link mObservers}.
+ // to avoid such problems, just march thru the list in the reverse order.
+ for (int i = mObservers.size() - 1; i >= 0; i--) {
+ mObservers.get(i).onChanged();
}
}
}
@@ -39,8 +43,8 @@
*/
public void notifyInvalidated() {
synchronized (mObservers) {
- for (DataSetObserver observer : mObservers) {
- observer.onInvalidated();
+ for (int i = mObservers.size() - 1; i >= 0; i--) {
+ mObservers.get(i).onInvalidated();
}
}
}
diff --git a/core/java/android/database/DatabaseErrorHandler.java b/core/java/android/database/DatabaseErrorHandler.java
new file mode 100644
index 0000000..f0c5452
--- /dev/null
+++ b/core/java/android/database/DatabaseErrorHandler.java
@@ -0,0 +1,33 @@
+/*
+ * 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.database;
+
+import android.database.sqlite.SQLiteDatabase;
+
+/**
+ * An interface to let the apps define the actions to take when the following errors are detected
+ * database corruption
+ */
+public interface DatabaseErrorHandler {
+
+ /**
+ * defines the method to be invoked when database corruption is detected.
+ * @param dbObj the {@link SQLiteDatabase} object representing the database on which corruption
+ * is detected.
+ */
+ void onCorruption(SQLiteDatabase dbObj);
+}
diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java
index 9bfbb74..af93eee 100644
--- a/core/java/android/database/DatabaseUtils.java
+++ b/core/java/android/database/DatabaseUtils.java
@@ -193,6 +193,37 @@
}
/**
+ * Returns data type of the given object's value.
+ *<p>
+ * Returned values are
+ * <ul>
+ * <li>{@link Cursor#FIELD_TYPE_NULL}</li>
+ * <li>{@link Cursor#FIELD_TYPE_INTEGER}</li>
+ * <li>{@link Cursor#FIELD_TYPE_FLOAT}</li>
+ * <li>{@link Cursor#FIELD_TYPE_STRING}</li>
+ * <li>{@link Cursor#FIELD_TYPE_BLOB}</li>
+ *</ul>
+ *</p>
+ *
+ * @param obj the object whose value type is to be returned
+ * @return object value type
+ * @hide
+ */
+ public static int getTypeOfObject(Object obj) {
+ if (obj == null) {
+ return Cursor.FIELD_TYPE_NULL;
+ } else if (obj instanceof byte[]) {
+ return Cursor.FIELD_TYPE_BLOB;
+ } else if (obj instanceof Float || obj instanceof Double) {
+ return Cursor.FIELD_TYPE_FLOAT;
+ } else if (obj instanceof Long || obj instanceof Integer) {
+ return Cursor.FIELD_TYPE_INTEGER;
+ } else {
+ return Cursor.FIELD_TYPE_STRING;
+ }
+ }
+
+ /**
* Appends an SQL string to the given StringBuilder, including the opening
* and closing single quotes. Any single quotes internal to sqlString will
* be escaped.
diff --git a/core/java/android/database/DefaultDatabaseErrorHandler.java b/core/java/android/database/DefaultDatabaseErrorHandler.java
new file mode 100644
index 0000000..0bad37a
--- /dev/null
+++ b/core/java/android/database/DefaultDatabaseErrorHandler.java
@@ -0,0 +1,89 @@
+/*
+ * 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.database;
+
+import java.io.File;
+import java.util.ArrayList;
+
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteException;
+import android.util.Log;
+import android.util.Pair;
+
+/**
+ * Default class used defining the actions to take when the following errors are detected
+ * database corruption
+ */
+public final class DefaultDatabaseErrorHandler implements DatabaseErrorHandler {
+
+ private static final String TAG = "DefaultDatabaseErrorHandler";
+
+ /**
+ * defines the default method to be invoked when database corruption is detected.
+ * @param dbObj the {@link SQLiteDatabase} object representing the database on which corruption
+ * is detected.
+ */
+ public void onCorruption(SQLiteDatabase dbObj) {
+ Log.e(TAG, "Corruption reported by sqlite on database: " + dbObj.getPath());
+
+ // is the corruption detected even before database could be 'opened'?
+ if (!dbObj.isOpen()) {
+ // database files are not even openable. delete this database file.
+ // NOTE if the database has attached databases, then any of them could be corrupt.
+ // and not deleting all of them could cause corrupted database file to remain and
+ // make the application crash on database open operation. To avoid this problem,
+ // the application should provide its own {@link DatabaseErrorHandler} impl class
+ // to delete ALL files of the database (including the attached databases).
+ if (!dbObj.getPath().equalsIgnoreCase(":memory:")) {
+ // not memory database.
+ try {
+ new File(dbObj.getPath()).delete();
+ } catch (Exception e) {
+ /* ignore */
+ }
+ }
+ return;
+ }
+
+ ArrayList<Pair<String, String>> attachedDbs = null;
+ try {
+ // Close the database, which will cause subsequent operations to fail.
+ // before that, get the attached database list first.
+ attachedDbs = dbObj.getAttachedDbs();
+ try {
+ dbObj.close();
+ } catch (SQLiteException e) {
+ /* ignore */
+ }
+ } finally {
+ // Delete all files of this corrupt database and/or attached databases
+ if (attachedDbs != null) {
+ for (Pair<String, String> p : attachedDbs) {
+ // delete file if it is a non-memory database file
+ if (p.second.equalsIgnoreCase(":memory:") || p.second.trim().length() == 0) {
+ continue;
+ }
+ Log.e(TAG, "deleting the database file: " + p.second);
+ try {
+ new File(p.second).delete();
+ } catch (Exception e) {
+ /* ignore */
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/core/java/android/database/IBulkCursor.java b/core/java/android/database/IBulkCursor.java
index 46790a3..244c88f 100644
--- a/core/java/android/database/IBulkCursor.java
+++ b/core/java/android/database/IBulkCursor.java
@@ -16,16 +16,14 @@
package android.database;
-import android.os.RemoteException;
+import android.os.Bundle;
import android.os.IBinder;
import android.os.IInterface;
-import android.os.Bundle;
-
-import java.util.Map;
+import android.os.RemoteException;
/**
* This interface provides a low-level way to pass bulk cursor data across
- * both process and language boundries. Application code should use the Cursor
+ * both process and language boundaries. Application code should use the Cursor
* interface directly.
*
* {@hide}
@@ -54,10 +52,6 @@
*/
public String[] getColumnNames() throws RemoteException;
- public boolean updateRows(Map<? extends Long, ? extends Map<String, Object>> values) throws RemoteException;
-
- public boolean deleteRow(int position) throws RemoteException;
-
public void deactivate() throws RemoteException;
public void close() throws RemoteException;
@@ -76,8 +70,6 @@
static final int GET_CURSOR_WINDOW_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION;
static final int COUNT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 1;
static final int GET_COLUMN_NAMES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 2;
- static final int UPDATE_ROWS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 3;
- static final int DELETE_ROW_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 4;
static final int DEACTIVATE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 5;
static final int REQUERY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 6;
static final int ON_MOVE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 7;
diff --git a/core/java/android/database/MatrixCursor.java b/core/java/android/database/MatrixCursor.java
index d5c3a32..5c1b968 100644
--- a/core/java/android/database/MatrixCursor.java
+++ b/core/java/android/database/MatrixCursor.java
@@ -272,6 +272,11 @@
}
@Override
+ public int getType(int column) {
+ return DatabaseUtils.getTypeOfObject(get(column));
+ }
+
+ @Override
public boolean isNull(int column) {
return get(column) == null;
}
diff --git a/core/java/android/database/MergeCursor.java b/core/java/android/database/MergeCursor.java
index 722d707..2c25db7 100644
--- a/core/java/android/database/MergeCursor.java
+++ b/core/java/android/database/MergeCursor.java
@@ -92,32 +92,6 @@
return false;
}
- /**
- * @hide
- * @deprecated
- */
- @Override
- public boolean deleteRow()
- {
- return mCursor.deleteRow();
- }
-
- /**
- * @hide
- * @deprecated
- */
- @Override
- public boolean commitUpdates() {
- int length = mCursors.length;
- for (int i = 0 ; i < length ; i++) {
- if (mCursors[i] != null) {
- mCursors[i].commitUpdates();
- }
- }
- onChange(true);
- return true;
- }
-
@Override
public String getString(int column)
{
@@ -155,6 +129,11 @@
}
@Override
+ public int getType(int column) {
+ return mCursor.getType(column);
+ }
+
+ @Override
public boolean isNull(int column)
{
return mCursor.isNull(column);
diff --git a/core/java/android/database/RequeryOnUiThreadException.java b/core/java/android/database/RequeryOnUiThreadException.java
new file mode 100644
index 0000000..97a50d8
--- /dev/null
+++ b/core/java/android/database/RequeryOnUiThreadException.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.database;
+
+/**
+ * An exception that indicates invoking {@link Cursor#requery()} on Main thread could cause ANR.
+ * This exception should encourage apps to invoke {@link Cursor#requery()} in a background thread.
+ * @hide
+ */
+public class RequeryOnUiThreadException extends RuntimeException {
+ public RequeryOnUiThreadException(String packageName) {
+ super("In " + packageName + " Requery is executing on main (UI) thread. could cause ANR. " +
+ "do it in background thread.");
+ }
+}
diff --git a/core/java/android/database/sqlite/DatabaseObjectNotClosedException.java b/core/java/android/database/sqlite/DatabaseObjectNotClosedException.java
index 8ac4c0f..f28c70f 100644
--- a/core/java/android/database/sqlite/DatabaseObjectNotClosedException.java
+++ b/core/java/android/database/sqlite/DatabaseObjectNotClosedException.java
@@ -21,13 +21,11 @@
* that is not explicitly closed
* @hide
*/
-public class DatabaseObjectNotClosedException extends RuntimeException
-{
+public class DatabaseObjectNotClosedException extends RuntimeException {
private static final String s = "Application did not close the cursor or database object " +
"that was opened here";
- public DatabaseObjectNotClosedException()
- {
+ public DatabaseObjectNotClosedException() {
super(s);
}
}
diff --git a/core/java/android/database/sqlite/SQLiteCompiledSql.java b/core/java/android/database/sqlite/SQLiteCompiledSql.java
index 25aa9b3..9889a21 100644
--- a/core/java/android/database/sqlite/SQLiteCompiledSql.java
+++ b/core/java/android/database/sqlite/SQLiteCompiledSql.java
@@ -78,20 +78,13 @@
* existing compiled SQL program already around
*/
private void compile(String sql, boolean forceCompilation) {
- if (!mDatabase.isOpen()) {
- throw new IllegalStateException("database " + mDatabase.getPath() + " already closed");
- }
+ mDatabase.verifyLockOwner();
// Only compile if we don't have a valid statement already or the caller has
// explicitly requested a recompile.
if (forceCompilation) {
- mDatabase.lock();
- try {
- // Note that the native_compile() takes care of destroying any previously
- // existing programs before it compiles.
- native_compile(sql);
- } finally {
- mDatabase.unlock();
- }
+ // Note that the native_compile() takes care of destroying any previously
+ // existing programs before it compiles.
+ native_compile(sql);
}
}
@@ -102,13 +95,8 @@
if (SQLiteDebug.DEBUG_ACTIVE_CURSOR_FINALIZATION) {
Log.v(TAG, "closed and deallocated DbObj (id#" + nStatement +")");
}
- try {
- mDatabase.lock();
- native_finalize();
- nStatement = 0;
- } finally {
- mDatabase.unlock();
- }
+ mDatabase.finalizeStatementLater(nStatement);
+ nStatement = 0;
}
}
@@ -134,6 +122,10 @@
mInUse = false;
}
+ /* package */ synchronized boolean isInUse() {
+ return mInUse;
+ }
+
/**
* Make sure that the native resource is cleaned up.
*/
@@ -162,5 +154,4 @@
* @param sql The SQL to compile.
*/
private final native void native_compile(String sql);
- private final native void native_finalize();
}
diff --git a/core/java/android/database/sqlite/SQLiteCursor.java b/core/java/android/database/sqlite/SQLiteCursor.java
index c7e58fa..eecd01e 100644
--- a/core/java/android/database/sqlite/SQLiteCursor.java
+++ b/core/java/android/database/sqlite/SQLiteCursor.java
@@ -16,20 +16,19 @@
package android.database.sqlite;
+import android.app.ActivityThread;
import android.database.AbstractWindowedCursor;
import android.database.CursorWindow;
import android.database.DataSetObserver;
-import android.database.SQLException;
-
+import android.database.RequeryOnUiThreadException;
import android.os.Handler;
+import android.os.Looper;
import android.os.Message;
import android.os.Process;
-import android.text.TextUtils;
import android.util.Config;
import android.util.Log;
import java.util.HashMap;
-import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
@@ -77,6 +76,11 @@
private int mCursorState = 0;
private ReentrantLock mLock = null;
private boolean mPendingData = false;
+
+ /**
+ * Used by {@link #requery()} to remember for which database we've already shown the warning.
+ */
+ private static final HashMap<String, Boolean> sAlreadyWarned = new HashMap<String, Boolean>();
/**
* support for a cursor variant that doesn't always read all results
@@ -321,166 +325,11 @@
}
}
- /**
- * @hide
- * @deprecated
- */
- @Override
- public boolean deleteRow() {
- checkPosition();
-
- // Only allow deletes if there is an ID column, and the ID has been read from it
- if (mRowIdColumnIndex == -1 || mCurrentRowID == null) {
- Log.e(TAG,
- "Could not delete row because either the row ID column is not available or it" +
- "has not been read.");
- return false;
- }
-
- boolean success;
-
- /*
- * Ensure we don't change the state of the database when another
- * thread is holding the database lock. requery() and moveTo() are also
- * synchronized here to make sure they get the state of the database
- * immediately following the DELETE.
- */
- mDatabase.lock();
- try {
- try {
- mDatabase.delete(mEditTable, mColumns[mRowIdColumnIndex] + "=?",
- new String[] {mCurrentRowID.toString()});
- success = true;
- } catch (SQLException e) {
- success = false;
- }
-
- int pos = mPos;
- requery();
-
- /*
- * Ensure proper cursor state. Note that mCurrentRowID changes
- * in this call.
- */
- moveToPosition(pos);
- } finally {
- mDatabase.unlock();
- }
-
- if (success) {
- onChange(true);
- return true;
- } else {
- return false;
- }
- }
-
@Override
public String[] getColumnNames() {
return mColumns;
}
- /**
- * @hide
- * @deprecated
- */
- @Override
- public boolean supportsUpdates() {
- return super.supportsUpdates() && !TextUtils.isEmpty(mEditTable);
- }
-
- /**
- * @hide
- * @deprecated
- */
- @Override
- public boolean commitUpdates(Map<? extends Long,
- ? extends Map<String, Object>> additionalValues) {
- if (!supportsUpdates()) {
- Log.e(TAG, "commitUpdates not supported on this cursor, did you "
- + "include the _id column?");
- return false;
- }
-
- /*
- * Prevent other threads from changing the updated rows while they're
- * being processed here.
- */
- synchronized (mUpdatedRows) {
- if (additionalValues != null) {
- mUpdatedRows.putAll(additionalValues);
- }
-
- if (mUpdatedRows.size() == 0) {
- return true;
- }
-
- /*
- * Prevent other threads from changing the database state while
- * we process the updated rows, and prevents us from changing the
- * database behind the back of another thread.
- */
- mDatabase.beginTransaction();
- try {
- StringBuilder sql = new StringBuilder(128);
-
- // For each row that has been updated
- for (Map.Entry<Long, Map<String, Object>> rowEntry :
- mUpdatedRows.entrySet()) {
- Map<String, Object> values = rowEntry.getValue();
- Long rowIdObj = rowEntry.getKey();
-
- if (rowIdObj == null || values == null) {
- throw new IllegalStateException("null rowId or values found! rowId = "
- + rowIdObj + ", values = " + values);
- }
-
- if (values.size() == 0) {
- continue;
- }
-
- long rowId = rowIdObj.longValue();
-
- Iterator<Map.Entry<String, Object>> valuesIter =
- values.entrySet().iterator();
-
- sql.setLength(0);
- sql.append("UPDATE " + mEditTable + " SET ");
-
- // For each column value that has been updated
- Object[] bindings = new Object[values.size()];
- int i = 0;
- while (valuesIter.hasNext()) {
- Map.Entry<String, Object> entry = valuesIter.next();
- sql.append(entry.getKey());
- sql.append("=?");
- bindings[i] = entry.getValue();
- if (valuesIter.hasNext()) {
- sql.append(", ");
- }
- i++;
- }
-
- sql.append(" WHERE " + mColumns[mRowIdColumnIndex]
- + '=' + rowId);
- sql.append(';');
- mDatabase.execSQL(sql.toString(), bindings);
- mDatabase.rowUpdated(mEditTable, rowId);
- }
- mDatabase.setTransactionSuccessful();
- } finally {
- mDatabase.endTransaction();
- }
-
- mUpdatedRows.clear();
- }
-
- // Let any change observers know about the update
- onChange(true);
-
- return true;
- }
-
private void deactivateCommon() {
if (Config.LOGV) Log.v(TAG, "<<< Releasing cursor " + this);
mCursorState = 0;
@@ -506,11 +355,30 @@
mDriver.cursorClosed();
}
+ /**
+ * Show a warning against the use of requery() if called on the main thread.
+ * This warning is shown per database per process.
+ */
+ private void warnIfUiThread() {
+ if (Looper.getMainLooper() == Looper.myLooper()) {
+ String databasePath = mDatabase.getPath();
+ // We show the warning once per database in order not to spam logcat.
+ if (!sAlreadyWarned.containsKey(databasePath)) {
+ sAlreadyWarned.put(databasePath, true);
+ String packageName = ActivityThread.currentPackageName();
+ Log.w(TAG, "should not attempt requery on main (UI) thread: app = " +
+ packageName == null ? "'unknown'" : packageName,
+ new RequeryOnUiThreadException(packageName));
+ }
+ }
+ }
+
@Override
public boolean requery() {
if (isClosed()) {
return false;
}
+ warnIfUiThread();
long timeStart = 0;
if (Config.LOGV) {
timeStart = System.currentTimeMillis();
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 0e798dc..4fdc46d 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -16,15 +16,16 @@
package android.database.sqlite;
-import com.google.android.collect.Maps;
-
import android.app.ActivityThread;
import android.content.ContentValues;
import android.database.Cursor;
+import android.database.DatabaseErrorHandler;
import android.database.DatabaseUtils;
+import android.database.DefaultDatabaseErrorHandler;
import android.database.SQLException;
import android.database.sqlite.SQLiteDebug.DbStats;
import android.os.Debug;
+import android.os.StatFs;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.text.TextUtils;
@@ -37,11 +38,11 @@
import java.io.File;
import java.lang.ref.WeakReference;
-import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Random;
@@ -232,48 +233,81 @@
// lock acquistions of the database.
/* package */ static final String GET_LOCK_LOG_PREFIX = "GETLOCK:";
- /** Used by native code, do not rename */
- /* package */ int mNativeHandle = 0;
+ /** Used by native code, do not rename. make it volatile, so it is thread-safe. */
+ /* package */ volatile int mNativeHandle = 0;
/** Used to make temp table names unique */
/* package */ int mTempTableSequence = 0;
+ /**
+ * The size, in bytes, of a block on "/data". This corresponds to the Unix
+ * statfs.f_bsize field. note that this field is lazily initialized.
+ */
+ private static int sBlockSize = 0;
+
/** The path for the database file */
- private String mPath;
+ private final String mPath;
/** The anonymized path for the database file for logging purposes */
private String mPathForLogs = null; // lazily populated
/** The flags passed to open/create */
- private int mFlags;
+ private final int mFlags;
/** The optional factory to use when creating new Cursors */
- private CursorFactory mFactory;
+ private final CursorFactory mFactory;
- private WeakHashMap<SQLiteClosable, Object> mPrograms;
+ private final WeakHashMap<SQLiteClosable, Object> mPrograms;
/**
- * for each instance of this class, a cache is maintained to store
+ * for each instance of this class, a LRU cache is maintained to store
* the compiled query statement ids returned by sqlite database.
- * key = sql statement with "?" for bind args
+ * key = SQL statement with "?" for bind args
* value = {@link SQLiteCompiledSql}
* If an application opens the database and keeps it open during its entire life, then
- * there will not be an overhead of compilation of sql statements by sqlite.
+ * there will not be an overhead of compilation of SQL statements by sqlite.
*
* why is this cache NOT static? because sqlite attaches compiledsql statements to the
* struct created when {@link SQLiteDatabase#openDatabase(String, CursorFactory, int)} is
* invoked.
*
* this cache has an upper limit of mMaxSqlCacheSize (settable by calling the method
- * (@link setMaxCacheSize(int)}). its default is 0 - i.e., no caching by default because
- * most of the apps don't use "?" syntax in their sql, caching is not useful for them.
+ * (@link setMaxSqlCacheSize(int)}).
*/
- /* package */ Map<String, SQLiteCompiledSql> mCompiledQueries = Maps.newHashMap();
+ // default statement-cache size per database connection ( = instance of this class)
+ private int mMaxSqlCacheSize = 25;
+ /* package */ final Map<String, SQLiteCompiledSql> mCompiledQueries =
+ new LinkedHashMap<String, SQLiteCompiledSql>(mMaxSqlCacheSize + 1, 0.75f, true) {
+ @Override
+ public boolean removeEldestEntry(Map.Entry<String, SQLiteCompiledSql> eldest) {
+ // eldest = least-recently used entry
+ // if it needs to be removed to accommodate a new entry,
+ // close {@link SQLiteCompiledSql} represented by this entry, if not in use
+ // and then let it be removed from the Map.
+ // when this is called, the caller must be trying to add a just-compiled stmt
+ // to cache; i.e., caller should already have acquired database lock AND
+ // the lock on mCompiledQueries. do as assert of these two 2 facts.
+ verifyLockOwner();
+ if (this.size() <= mMaxSqlCacheSize) {
+ // cache is not full. nothing needs to be removed
+ return false;
+ }
+ // cache is full. eldest will be removed.
+ SQLiteCompiledSql entry = eldest.getValue();
+ if (!entry.isInUse()) {
+ // this {@link SQLiteCompiledSql} is not in use. release it.
+ entry.releaseSqlStatement();
+ }
+ // return true, so that this entry is removed automatically by the caller.
+ return true;
+ }
+ };
/**
- * @hide
+ * absolute max value that can be set by {@link #setMaxSqlCacheSize(int)}
+ * size of each prepared-statement is between 1K - 6K, depending on the complexity of the
+ * SQL statement & schema.
*/
- public static final int MAX_SQL_CACHE_SIZE = 250;
- private int mMaxSqlCacheSize = MAX_SQL_CACHE_SIZE; // max cache size per Database instance
+ public static final int MAX_SQL_CACHE_SIZE = 100;
private int mCacheFullWarnings;
private static final int MAX_WARNINGS_ON_CACHESIZE_CONDITION = 1;
@@ -281,17 +315,21 @@
private int mNumCacheHits;
private int mNumCacheMisses;
- /** the following 2 members maintain the time when a database is opened and closed */
- private String mTimeOpened = null;
- private String mTimeClosed = null;
-
/** Used to find out where this object was created in case it never got closed. */
- private Throwable mStackTrace = null;
+ private final Throwable mStackTrace;
// System property that enables logging of slow queries. Specify the threshold in ms.
private static final String LOG_SLOW_QUERIES_PROPERTY = "db.log.slow_query_threshold";
private final int mSlowQueryThreshold;
+ /** stores the list of statement ids that need to be finalized by sqlite */
+ private final ArrayList<Integer> mClosedStatementIds = new ArrayList<Integer>();
+
+ /** {@link DatabaseErrorHandler} to be used when SQLite returns any of the following errors
+ * Corruption
+ * */
+ private final DatabaseErrorHandler mErrorHandler;
+
/**
* @param closable
*/
@@ -316,9 +354,6 @@
@Override
protected void onAllReferencesReleased() {
if (isOpen()) {
- if (SQLiteDebug.DEBUG_SQL_CACHE) {
- mTimeClosed = getTime();
- }
dbclose();
}
}
@@ -349,19 +384,8 @@
private boolean mLockingEnabled = true;
/* package */ void onCorruption() {
- Log.e(TAG, "Removing corrupt database: " + mPath);
EventLog.writeEvent(EVENT_DB_CORRUPT, mPath);
- try {
- // Close the database (if we can), which will cause subsequent operations to fail.
- close();
- } finally {
- // Delete the corrupt file. Don't re-create it now -- that would just confuse people
- // -- but the next time someone tries to open it, they can set it up from scratch.
- if (!mPath.equalsIgnoreCase(":memory")) {
- // delete is only for non-memory database files
- new File(mPath).delete();
- }
- }
+ mErrorHandler.onCorruption(this);
}
/**
@@ -459,11 +483,14 @@
}
/**
- * Begins a transaction. Transactions can be nested. When the outer transaction is ended all of
+ * Begins a transaction in EXCLUSIVE mode.
+ * <p>
+ * Transactions can be nested.
+ * When the outer transaction is ended all of
* the work done in that transaction and all of the nested transactions will be committed or
* rolled back. The changes will be rolled back if any transaction is ended without being
* marked as clean (by calling setTransactionSuccessful). Otherwise they will be committed.
- *
+ * </p>
* <p>Here is the standard idiom for transactions:
*
* <pre>
@@ -481,11 +508,14 @@
}
/**
- * Begins a transaction. Transactions can be nested. When the outer transaction is ended all of
+ * Begins a transaction in EXCLUSIVE mode.
+ * <p>
+ * Transactions can be nested.
+ * When the outer transaction is ended all of
* the work done in that transaction and all of the nested transactions will be committed or
* rolled back. The changes will be rolled back if any transaction is ended without being
* marked as clean (by calling setTransactionSuccessful). Otherwise they will be committed.
- *
+ * </p>
* <p>Here is the standard idiom for transactions:
*
* <pre>
@@ -497,15 +527,14 @@
* db.endTransaction();
* }
* </pre>
+ *
* @param transactionListener listener that should be notified when the transaction begins,
* commits, or is rolled back, either explicitly or by a call to
* {@link #yieldIfContendedSafely}.
*/
public void beginTransactionWithListener(SQLiteTransactionListener transactionListener) {
+ verifyDbIsOpen();
lockForced();
- if (!isOpen()) {
- throw new IllegalStateException("database not open");
- }
boolean ok = false;
try {
// If this thread already had the lock then get out
@@ -550,12 +579,7 @@
* are committed and rolled back.
*/
public void endTransaction() {
- if (!isOpen()) {
- throw new IllegalStateException("database not open");
- }
- if (!mLock.isHeldByCurrentThread()) {
- throw new IllegalStateException("no transaction pending");
- }
+ verifyLockOwner();
try {
if (mInnerTransactionIsSuccessful) {
mInnerTransactionIsSuccessful = false;
@@ -613,9 +637,7 @@
* transaction is already marked as successful.
*/
public void setTransactionSuccessful() {
- if (!isOpen()) {
- throw new IllegalStateException("database not open");
- }
+ verifyDbIsOpen();
if (!mLock.isHeldByCurrentThread()) {
throw new IllegalStateException("no transaction pending");
}
@@ -813,10 +835,35 @@
* @throws SQLiteException if the database cannot be opened
*/
public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags) {
- SQLiteDatabase sqliteDatabase = null;
+ return openDatabase(path, factory, flags, new DefaultDatabaseErrorHandler());
+ }
+
+ /**
+ * Open the database according to the flags {@link #OPEN_READWRITE}
+ * {@link #OPEN_READONLY} {@link #CREATE_IF_NECESSARY} and/or {@link #NO_LOCALIZED_COLLATORS}.
+ *
+ * <p>Sets the locale of the database to the the system's current locale.
+ * Call {@link #setLocale} if you would like something else.</p>
+ *
+ * <p>Accepts input param: a concrete instance of {@link DatabaseErrorHandler} to be
+ * used to handle corruption when sqlite reports database corruption.</p>
+ *
+ * @param path to database file to open and/or create
+ * @param factory an optional factory class that is called to instantiate a
+ * cursor when query is called, or null for default
+ * @param flags to control database access mode
+ * @param errorHandler the {@link DatabaseErrorHandler} obj to be used to handle corruption
+ * when sqlite reports database corruption
+ * @return the newly opened database
+ * @throws SQLiteException if the database cannot be opened
+ */
+ public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags,
+ DatabaseErrorHandler errorHandler) {
+ SQLiteDatabase sqliteDatabase = new SQLiteDatabase(path, factory, flags, errorHandler);
+
try {
// Open the database.
- sqliteDatabase = new SQLiteDatabase(path, factory, flags);
+ sqliteDatabase.openDatabase(path, flags);
if (SQLiteDebug.DEBUG_SQL_STATEMENTS) {
sqliteDatabase.enableSqlTracing(path);
}
@@ -824,21 +871,43 @@
sqliteDatabase.enableSqlProfiling(path);
}
} catch (SQLiteDatabaseCorruptException e) {
- // Try to recover from this, if we can.
- // TODO: should we do this for other open failures?
- Log.e(TAG, "Deleting and re-creating corrupt database " + path, e);
- EventLog.writeEvent(EVENT_DB_CORRUPT, path);
- if (!path.equalsIgnoreCase(":memory")) {
- // delete is only for non-memory database files
- new File(path).delete();
- }
- sqliteDatabase = new SQLiteDatabase(path, factory, flags);
+ // Database is not even openable.
+ errorHandler.onCorruption(sqliteDatabase);
+ sqliteDatabase = new SQLiteDatabase(path, factory, flags, errorHandler);
}
- ActiveDatabases.getInstance().mActiveDatabases.add(
- new WeakReference<SQLiteDatabase>(sqliteDatabase));
+
+ // set sqlite pagesize to mBlockSize
+ if (sBlockSize == 0) {
+ // TODO: "/data" should be a static final String constant somewhere. it is hardcoded
+ // in several places right now.
+ sBlockSize = new StatFs("/data").getBlockSize();
+ }
+ sqliteDatabase.setPageSize(sBlockSize);
+
+ // set journal_mode to truncate
+ String s = DatabaseUtils.stringForQuery(sqliteDatabase, "PRAGMA journal_mode=TRUNCATE",
+ null);
+ if (!s.equalsIgnoreCase("TRUNCATE")) {
+ Log.e(TAG, "setting journal_mode to TRUNCATE failed");
+ }
+
+ // add this database to the list of databases opened in this process
+ ActiveDatabases.addActiveDatabase(sqliteDatabase);
return sqliteDatabase;
}
+ private void openDatabase(String path, int flags) {
+ // Open the database.
+ dbopen(path, flags);
+ try {
+ setLocale(Locale.getDefault());
+ } catch (RuntimeException e) {
+ Log.e(TAG, "Failed to setLocale(). closing the database", e);
+ dbclose();
+ throw e;
+ }
+ }
+
/**
* Equivalent to openDatabase(file.getPath(), factory, CREATE_IF_NECESSARY).
*/
@@ -854,6 +923,17 @@
}
/**
+ * same as {@link #openOrCreateDatabase(String, CursorFactory)} except for an additional param
+ * errorHandler.
+ * @param errorHandler the {@link DatabaseErrorHandler} obj to be used when database
+ * corruption is detected on the database.
+ */
+ public static SQLiteDatabase openOrCreateDatabase(String path, CursorFactory factory,
+ DatabaseErrorHandler errorHandler) {
+ return openDatabase(path, factory, CREATE_IF_NECESSARY, errorHandler);
+ }
+
+ /**
* Create a memory backed SQLite database. Its contents will be destroyed
* when the database is closed.
*
@@ -879,6 +959,8 @@
lock();
try {
closeClosable();
+ // finalize ALL statements queued up so far
+ closePendingStatements();
// close this database instance - regardless of its reference count value
onAllReferencesReleased();
} finally {
@@ -887,7 +969,7 @@
}
private void closeClosable() {
- /* deallocate all compiled sql statement objects from mCompiledQueries cache.
+ /* deallocate all compiled SQL statement objects from mCompiledQueries cache.
* this should be done before de-referencing all {@link SQLiteClosable} objects
* from this database object because calling
* {@link SQLiteClosable#onAllReferencesReleasedFromContainer()} could cause the database
@@ -917,19 +999,7 @@
* @return the database version
*/
public int getVersion() {
- SQLiteStatement prog = null;
- lock();
- if (!isOpen()) {
- throw new IllegalStateException("database not open");
- }
- try {
- prog = new SQLiteStatement(this, "PRAGMA user_version;");
- long version = prog.simpleQueryForLong();
- return (int) version;
- } finally {
- if (prog != null) prog.close();
- unlock();
- }
+ return ((Long) DatabaseUtils.longForQuery(this, "PRAGMA user_version;", null)).intValue();
}
/**
@@ -947,20 +1017,8 @@
* @return the new maximum database size
*/
public long getMaximumSize() {
- SQLiteStatement prog = null;
- lock();
- if (!isOpen()) {
- throw new IllegalStateException("database not open");
- }
- try {
- prog = new SQLiteStatement(this,
- "PRAGMA max_page_count;");
- long pageCount = prog.simpleQueryForLong();
- return pageCount * getPageSize();
- } finally {
- if (prog != null) prog.close();
- unlock();
- }
+ long pageCount = DatabaseUtils.longForQuery(this, "PRAGMA max_page_count;", null);
+ return pageCount * getPageSize();
}
/**
@@ -971,26 +1029,15 @@
* @return the new maximum database size
*/
public long setMaximumSize(long numBytes) {
- SQLiteStatement prog = null;
- lock();
- if (!isOpen()) {
- throw new IllegalStateException("database not open");
+ long pageSize = getPageSize();
+ long numPages = numBytes / pageSize;
+ // If numBytes isn't a multiple of pageSize, bump up a page
+ if ((numBytes % pageSize) != 0) {
+ numPages++;
}
- try {
- long pageSize = getPageSize();
- long numPages = numBytes / pageSize;
- // If numBytes isn't a multiple of pageSize, bump up a page
- if ((numBytes % pageSize) != 0) {
- numPages++;
- }
- prog = new SQLiteStatement(this,
- "PRAGMA max_page_count = " + numPages);
- long newPageCount = prog.simpleQueryForLong();
- return newPageCount * pageSize;
- } finally {
- if (prog != null) prog.close();
- unlock();
- }
+ long newPageCount = DatabaseUtils.longForQuery(this, "PRAGMA max_page_count = " + numPages,
+ null);
+ return newPageCount * pageSize;
}
/**
@@ -999,20 +1046,7 @@
* @return the database page size, in bytes
*/
public long getPageSize() {
- SQLiteStatement prog = null;
- lock();
- if (!isOpen()) {
- throw new IllegalStateException("database not open");
- }
- try {
- prog = new SQLiteStatement(this,
- "PRAGMA page_size;");
- long size = prog.simpleQueryForLong();
- return size;
- } finally {
- if (prog != null) prog.close();
- unlock();
- }
+ return DatabaseUtils.longForQuery(this, "PRAGMA page_size;", null);
}
/**
@@ -1100,7 +1134,7 @@
if (info != null) {
execSQL("UPDATE " + info.masterTable
+ " SET _sync_dirty=1 WHERE _id=(SELECT " + info.foreignKey
- + " FROM " + table + " WHERE _id=" + rowId + ")");
+ + " FROM " + table + " WHERE _id=?)", new String[] {String.valueOf(rowId)});
}
}
@@ -1140,10 +1174,8 @@
* {@link SQLiteStatement}s are not synchronized, see the documentation for more details.
*/
public SQLiteStatement compileStatement(String sql) throws SQLException {
+ verifyDbIsOpen();
lock();
- if (!isOpen()) {
- throw new IllegalStateException("database not open");
- }
try {
return new SQLiteStatement(this, sql);
} finally {
@@ -1225,9 +1257,7 @@
boolean distinct, String table, String[] columns,
String selection, String[] selectionArgs, String groupBy,
String having, String orderBy, String limit) {
- if (!isOpen()) {
- throw new IllegalStateException("database not open");
- }
+ verifyDbIsOpen();
String sql = SQLiteQueryBuilder.buildQueryString(
distinct, table, columns, selection, groupBy, having, orderBy, limit);
@@ -1338,9 +1368,7 @@
public Cursor rawQueryWithFactory(
CursorFactory cursorFactory, String sql, String[] selectionArgs,
String editTable) {
- if (!isOpen()) {
- throw new IllegalStateException("database not open");
- }
+ verifyDbIsOpen();
BlockGuard.getThreadPolicy().onReadFromDisk();
long timeStart = 0;
@@ -1500,10 +1528,8 @@
*/
public long insertWithOnConflict(String table, String nullColumnHack,
ContentValues initialValues, int conflictAlgorithm) {
+ verifyDbIsOpen();
BlockGuard.getThreadPolicy().onWriteToDisk();
- if (!isOpen()) {
- throw new IllegalStateException("database not open");
- }
// Measurements show most sql lengths <= 152
StringBuilder sql = new StringBuilder(152);
@@ -1592,11 +1618,9 @@
* whereClause.
*/
public int delete(String table, String whereClause, String[] whereArgs) {
+ verifyDbIsOpen();
BlockGuard.getThreadPolicy().onWriteToDisk();
lock();
- if (!isOpen()) {
- throw new IllegalStateException("database not open");
- }
SQLiteStatement statement = null;
try {
statement = compileStatement("DELETE FROM " + table
@@ -1676,10 +1700,8 @@
sql.append(whereClause);
}
+ verifyDbIsOpen();
lock();
- if (!isOpen()) {
- throw new IllegalStateException("database not open");
- }
SQLiteStatement statement = null;
try {
statement = compileStatement(sql.toString());
@@ -1724,21 +1746,28 @@
}
/**
- * Execute a single SQL statement that is not a query. For example, CREATE
- * TABLE, DELETE, INSERT, etc. Multiple statements separated by ;s are not
- * supported. it takes a write lock
+ * Execute a single SQL statement that is NOT a SELECT
+ * or any other SQL statement that returns data.
+ * <p>
+ * Use of this method is discouraged as it doesn't perform well when issuing the same SQL
+ * statement repeatedly (see {@link #compileStatement(String)} to prepare statements for
+ * repeated use), and it has no means to return any data (such as the number of affected rows).
+ * Instead, you're encouraged to use {@link #insert(String, String, ContentValues)},
+ * {@link #update(String, ContentValues, String, String[])}, et al, when possible.
+ * </p>
*
+ * @param sql the SQL statement to be executed. Multiple statements separated by semicolons are
+ * not supported.
* @throws SQLException If the SQL string is invalid for some reason
*/
public void execSQL(String sql) throws SQLException {
+ verifyDbIsOpen();
BlockGuard.getThreadPolicy().onWriteToDisk();
long timeStart = SystemClock.uptimeMillis();
lock();
- if (!isOpen()) {
- throw new IllegalStateException("database not open");
- }
logTimeStat(mLastSqlStatement, timeStart, GET_LOCK_LOG_PREFIX);
try {
+ closePendingStatements();
native_execSQL(sql);
} catch (SQLiteDatabaseCorruptException e) {
onCorruption();
@@ -1758,11 +1787,39 @@
}
/**
- * Execute a single SQL statement that is not a query. For example, CREATE
- * TABLE, DELETE, INSERT, etc. Multiple statements separated by ;s are not
- * supported. it takes a write lock,
+ * Execute a single SQL statement that is NOT a SELECT/INSERT/UPDATE/DELETE.
+ * <p>
+ * For INSERT statements, use any of the following instead.
+ * <ul>
+ * <li>{@link #insert(String, String, ContentValues)}</li>
+ * <li>{@link #insertOrThrow(String, String, ContentValues)}</li>
+ * <li>{@link #insertWithOnConflict(String, String, ContentValues, int)}</li>
+ * </ul>
+ * <p>
+ * For UPDATE statements, use any of the following instead.
+ * <ul>
+ * <li>{@link #update(String, ContentValues, String, String[])}</li>
+ * <li>{@link #updateWithOnConflict(String, ContentValues, String, String[], int)}</li>
+ * </ul>
+ * <p>
+ * For DELETE statements, use any of the following instead.
+ * <ul>
+ * <li>{@link #delete(String, String, String[])}</li>
+ * </ul>
+ * <p>
+ * For example, the following are good candidates for using this method:
+ * <ul>
+ * <li>ALTER TABLE</li>
+ * <li>CREATE or DROP table / trigger / view / index / virtual table</li>
+ * <li>REINDEX</li>
+ * <li>RELEASE</li>
+ * <li>SAVEPOINT</li>
+ * <li>PRAGMA that returns no data</li>
+ * </ul>
+ * </p>
*
- * @param sql
+ * @param sql the SQL statement to be executed. Multiple statements separated by semicolons are
+ * not supported.
* @param bindArgs only byte[], String, Long and Double are supported in bindArgs.
* @throws SQLException If the SQL string is invalid for some reason
*/
@@ -1771,11 +1828,9 @@
if (bindArgs == null) {
throw new IllegalArgumentException("Empty bindArgs");
}
+ verifyDbIsOpen();
long timeStart = SystemClock.uptimeMillis();
lock();
- if (!isOpen()) {
- throw new IllegalStateException("database not open");
- }
SQLiteStatement statement = null;
try {
statement = compileStatement(sql);
@@ -1809,14 +1864,17 @@
}
/**
- * Private constructor. See {@link #create} and {@link #openDatabase}.
+ * Private constructor.
*
* @param path The full path to the database
* @param factory The factory to use when creating cursors, may be NULL.
* @param flags 0 or {@link #NO_LOCALIZED_COLLATORS}. If the database file already
* exists, mFlags will be updated appropriately.
+ * @param errorHandler The {@link DatabaseErrorHandler} to be used when sqlite reports database
+ * corruption. may be NULL.
*/
- private SQLiteDatabase(String path, CursorFactory factory, int flags) {
+ private SQLiteDatabase(String path, CursorFactory factory, int flags,
+ DatabaseErrorHandler errorHandler) {
if (path == null) {
throw new IllegalArgumentException("path should not be null");
}
@@ -1825,25 +1883,10 @@
mSlowQueryThreshold = SystemProperties.getInt(LOG_SLOW_QUERIES_PROPERTY, -1);
mStackTrace = new DatabaseObjectNotClosedException().fillInStackTrace();
mFactory = factory;
- dbopen(mPath, mFlags);
- if (SQLiteDebug.DEBUG_SQL_CACHE) {
- mTimeOpened = getTime();
- }
mPrograms = new WeakHashMap<SQLiteClosable,Object>();
- try {
- setLocale(Locale.getDefault());
- } catch (RuntimeException e) {
- Log.e(TAG, "Failed to setLocale() when constructing, closing the database", e);
- dbclose();
- if (SQLiteDebug.DEBUG_SQL_CACHE) {
- mTimeClosed = getTime();
- }
- throw e;
- }
- }
-
- private String getTime() {
- return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS ").format(System.currentTimeMillis());
+ // Set the DatabaseErrorHandler to be used when SQLite reports corruption.
+ // If the caller sets errorHandler = null, then use default errorhandler.
+ mErrorHandler = (errorHandler == null) ? new DefaultDatabaseErrorHandler() : errorHandler;
}
/**
@@ -1969,6 +2012,19 @@
}
}
+ /* package */ void verifyDbIsOpen() {
+ if (!isOpen()) {
+ throw new IllegalStateException("database " + getPath() + " already closed");
+ }
+ }
+
+ /* package */ void verifyLockOwner() {
+ verifyDbIsOpen();
+ if (mLockingEnabled && !isDbLockedByCurrentThread()) {
+ throw new IllegalStateException("Don't have database lock!");
+ }
+ }
+
/*
* ============================================================================
*
@@ -1976,22 +2032,14 @@
* ============================================================================
*/
/**
- * adds the given sql and its compiled-statement-id-returned-by-sqlite to the
+ * Adds the given SQL and its compiled-statement-id-returned-by-sqlite to the
* cache of compiledQueries attached to 'this'.
- *
- * if there is already a {@link SQLiteCompiledSql} in compiledQueries for the given sql,
+ * <p>
+ * If there is already a {@link SQLiteCompiledSql} in compiledQueries for the given SQL,
* the new {@link SQLiteCompiledSql} object is NOT inserted into the cache (i.e.,the current
* mapping is NOT replaced with the new mapping).
*/
/* package */ void addToCompiledQueries(String sql, SQLiteCompiledSql compiledStatement) {
- if (mMaxSqlCacheSize == 0) {
- // for this database, there is no cache of compiled sql.
- if (SQLiteDebug.DEBUG_SQL_CACHE) {
- Log.v(TAG, "|NOT adding_sql_to_cache|" + getPath() + "|" + sql);
- }
- return;
- }
-
SQLiteCompiledSql compiledSql = null;
synchronized(mCompiledQueries) {
// don't insert the new mapping if a mapping already exists
@@ -1999,35 +2047,30 @@
if (compiledSql != null) {
return;
}
- // add this <sql, compiledStatement> to the cache
+
if (mCompiledQueries.size() == mMaxSqlCacheSize) {
/*
* cache size of {@link #mMaxSqlCacheSize} is not enough for this app.
- * log a warning MAX_WARNINGS_ON_CACHESIZE_CONDITION times
- * chances are it is NOT using ? for bindargs - so caching is useless.
- * TODO: either let the callers set max cchesize for their app, or intelligently
- * figure out what should be cached for a given app.
+ * log a warning.
+ * chances are it is NOT using ? for bindargs - or cachesize is too small.
*/
if (++mCacheFullWarnings == MAX_WARNINGS_ON_CACHESIZE_CONDITION) {
Log.w(TAG, "Reached MAX size for compiled-sql statement cache for database " +
- getPath() + "; i.e., NO space for this sql statement in cache: " +
- sql + ". Please change your sql statements to use '?' for " +
- "bindargs, instead of using actual values");
+ getPath() + ". Consider increasing cachesize.");
}
- // don't add this entry to cache
- } else {
- // cache is NOT full. add this to cache.
- mCompiledQueries.put(sql, compiledStatement);
- if (SQLiteDebug.DEBUG_SQL_CACHE) {
- Log.v(TAG, "|adding_sql_to_cache|" + getPath() + "|" +
- mCompiledQueries.size() + "|" + sql);
- }
+ }
+ /* add the given SQLiteCompiledSql compiledStatement to cache.
+ * no need to worry about the cache size - because {@link #mCompiledQueries}
+ * self-limits its size to {@link #mMaxSqlCacheSize}.
+ */
+ mCompiledQueries.put(sql, compiledStatement);
+ if (SQLiteDebug.DEBUG_SQL_CACHE) {
+ Log.v(TAG, "|adding_sql_to_cache|" + getPath() + "|" +
+ mCompiledQueries.size() + "|" + sql);
}
}
- return;
}
-
private void deallocCachedSqlStatements() {
synchronized (mCompiledQueries) {
for (SQLiteCompiledSql compiledSql : mCompiledQueries.values()) {
@@ -2038,20 +2081,13 @@
}
/**
- * from the compiledQueries cache, returns the compiled-statement-id for the given sql.
- * returns null, if not found in the cache.
+ * From the compiledQueries cache, returns the compiled-statement-id for the given SQL.
+ * Returns null, if not found in the cache.
*/
/* package */ SQLiteCompiledSql getCompiledStatementForSql(String sql) {
SQLiteCompiledSql compiledStatement = null;
boolean cacheHit;
synchronized(mCompiledQueries) {
- if (mMaxSqlCacheSize == 0) {
- // for this database, there is no cache of compiled sql.
- if (SQLiteDebug.DEBUG_SQL_CACHE) {
- Log.v(TAG, "|cache NOT found|" + getPath());
- }
- return null;
- }
cacheHit = (compiledStatement = mCompiledQueries.get(sql)) != null;
}
if (cacheHit) {
@@ -2064,63 +2100,24 @@
Log.v(TAG, "|cache_stats|" +
getPath() + "|" + mCompiledQueries.size() +
"|" + mNumCacheHits + "|" + mNumCacheMisses +
- "|" + cacheHit + "|" + mTimeOpened + "|" + mTimeClosed + "|" + sql);
+ "|" + cacheHit + "|" + sql);
}
return compiledStatement;
}
/**
- * returns true if the given sql is cached in compiled-sql cache.
- * @hide
- */
- public boolean isInCompiledSqlCache(String sql) {
- synchronized(mCompiledQueries) {
- return mCompiledQueries.containsKey(sql);
- }
- }
-
- /**
- * purges the given sql from the compiled-sql cache.
- * @hide
- */
- public void purgeFromCompiledSqlCache(String sql) {
- synchronized(mCompiledQueries) {
- mCompiledQueries.remove(sql);
- }
- }
-
- /**
- * remove everything from the compiled sql cache
- * @hide
- */
- public void resetCompiledSqlCache() {
- synchronized(mCompiledQueries) {
- mCompiledQueries.clear();
- }
- }
-
- /**
- * return the current maxCacheSqlCacheSize
- * @hide
- */
- public synchronized int getMaxSqlCacheSize() {
- return mMaxSqlCacheSize;
- }
-
- /**
- * set the max size of the compiled sql cache for this database after purging the cache.
+ * Sets the maximum size of the prepared-statement cache for this database.
* (size of the cache = number of compiled-sql-statements stored in the cache).
+ *<p>
+ * Maximum cache size can ONLY be increased from its current size (default = 10).
+ * If this method is called with smaller size than the current maximum value,
+ * then IllegalStateException is thrown.
+ *<p>
+ * This method is thread-safe.
*
- * max cache size can ONLY be increased from its current size (default = 0).
- * if this method is called with smaller size than the current value of mMaxSqlCacheSize,
- * then IllegalStateException is thrown
- *
- * synchronized because we don't want t threads to change cache size at the same time.
- * @param cacheSize the size of the cache. can be (0 to MAX_SQL_CACHE_SIZE)
- * @throws IllegalStateException if input cacheSize > MAX_SQL_CACHE_SIZE or < 0 or
- * < the value set with previous setMaxSqlCacheSize() call.
- *
- * @hide
+ * @param cacheSize the size of the cache. can be (0 to {@link #MAX_SQL_CACHE_SIZE})
+ * @throws IllegalStateException if input cacheSize > {@link #MAX_SQL_CACHE_SIZE} or
+ * > the value set with previous setMaxSqlCacheSize() call.
*/
public synchronized void setMaxSqlCacheSize(int cacheSize) {
if (cacheSize > MAX_SQL_CACHE_SIZE || cacheSize < 0) {
@@ -2132,12 +2129,63 @@
mMaxSqlCacheSize = cacheSize;
}
+ /* package */ void finalizeStatementLater(int id) {
+ if (!isOpen()) {
+ // database already closed. this statement will already have been finalized.
+ return;
+ }
+ synchronized(mClosedStatementIds) {
+ if (mClosedStatementIds.contains(id)) {
+ // this statement id is already queued up for finalization.
+ return;
+ }
+ mClosedStatementIds.add(id);
+ }
+ }
+
+ /**
+ * public visibility only for testing. otherwise, package visibility is sufficient
+ * @hide
+ */
+ public void closePendingStatements() {
+ if (!isOpen()) {
+ // since this database is already closed, no need to finalize anything.
+ mClosedStatementIds.clear();
+ return;
+ }
+ verifyLockOwner();
+ /* to minimize synchronization on mClosedStatementIds, make a copy of the list */
+ ArrayList<Integer> list = new ArrayList<Integer>(mClosedStatementIds.size());
+ synchronized(mClosedStatementIds) {
+ list.addAll(mClosedStatementIds);
+ mClosedStatementIds.clear();
+ }
+ // finalize all the statements from the copied list
+ int size = list.size();
+ for (int i = 0; i < size; i++) {
+ native_finalize(list.get(i));
+ }
+ }
+
+ /**
+ * for testing only
+ * @hide
+ */
+ public ArrayList<Integer> getQueuedUpStmtList() {
+ return mClosedStatementIds;
+ }
+
static class ActiveDatabases {
private static final ActiveDatabases activeDatabases = new ActiveDatabases();
private HashSet<WeakReference<SQLiteDatabase>> mActiveDatabases =
- new HashSet<WeakReference<SQLiteDatabase>>();
+ new HashSet<WeakReference<SQLiteDatabase>>();
private ActiveDatabases() {} // disable instantiation of this class
- static ActiveDatabases getInstance() {return activeDatabases;}
+ static ActiveDatabases getInstance() {
+ return activeDatabases;
+ }
+ private static void addActiveDatabase(SQLiteDatabase sqliteDatabase) {
+ activeDatabases.mActiveDatabases.add(new WeakReference<SQLiteDatabase>(sqliteDatabase));
+ }
}
/**
@@ -2151,86 +2199,126 @@
if (db == null || !db.isOpen()) {
continue;
}
- // get SQLITE_DBSTATUS_LOOKASIDE_USED for the db
- int lookasideUsed = db.native_getDbLookaside();
- // get the lastnode of the dbname
- String path = db.getPath();
- int indx = path.lastIndexOf("/");
- String lastnode = path.substring((indx != -1) ? ++indx : 0);
+ try {
+ // get SQLITE_DBSTATUS_LOOKASIDE_USED for the db
+ int lookasideUsed = db.native_getDbLookaside();
- // get list of attached dbs and for each db, get its size and pagesize
- ArrayList<Pair<String, String>> attachedDbs = getAttachedDbs(db);
- if (attachedDbs == null) {
- continue;
- }
- for (int i = 0; i < attachedDbs.size(); i++) {
- Pair<String, String> p = attachedDbs.get(i);
- long pageCount = getPragmaVal(db, p.first + ".page_count;");
+ // get the lastnode of the dbname
+ String path = db.getPath();
+ int indx = path.lastIndexOf("/");
+ String lastnode = path.substring((indx != -1) ? ++indx : 0);
- // first entry in the attached db list is always the main database
- // don't worry about prefixing the dbname with "main"
- String dbName;
- if (i == 0) {
- dbName = lastnode;
- } else {
- // lookaside is only relevant for the main db
- lookasideUsed = 0;
- dbName = " (attached) " + p.first;
- // if the attached db has a path, attach the lastnode from the path to above
- if (p.second.trim().length() > 0) {
- int idx = p.second.lastIndexOf("/");
- dbName += " : " + p.second.substring((idx != -1) ? ++idx : 0);
+ // get list of attached dbs and for each db, get its size and pagesize
+ ArrayList<Pair<String, String>> attachedDbs = db.getAttachedDbs();
+ if (attachedDbs == null) {
+ continue;
+ }
+ for (int i = 0; i < attachedDbs.size(); i++) {
+ Pair<String, String> p = attachedDbs.get(i);
+ long pageCount = DatabaseUtils.longForQuery(db, "PRAGMA " + p.first
+ + ".page_count;", null);
+
+ // first entry in the attached db list is always the main database
+ // don't worry about prefixing the dbname with "main"
+ String dbName;
+ if (i == 0) {
+ dbName = lastnode;
+ } else {
+ // lookaside is only relevant for the main db
+ lookasideUsed = 0;
+ dbName = " (attached) " + p.first;
+ // if the attached db has a path, attach the lastnode from the path to above
+ if (p.second.trim().length() > 0) {
+ int idx = p.second.lastIndexOf("/");
+ dbName += " : " + p.second.substring((idx != -1) ? ++idx : 0);
+ }
+ }
+ if (pageCount > 0) {
+ dbStatsList.add(new DbStats(dbName, pageCount, db.getPageSize(),
+ lookasideUsed, db.mNumCacheHits, db.mNumCacheMisses,
+ db.mCompiledQueries.size()));
}
}
- if (pageCount > 0) {
- dbStatsList.add(new DbStats(dbName, pageCount, db.getPageSize(),
- lookasideUsed));
- }
+ } catch (SQLiteException e) {
+ // ignore. we don't care about exceptions when we are taking adb
+ // bugreport!
}
}
return dbStatsList;
}
/**
- * get the specified pragma value from sqlite for the specified database.
- * only handles pragma's that return int/long.
- * NO JAVA locks are held in this method.
- * TODO: use this to do all pragma's in this class
+ * Returns list of full pathnames of all attached databases including the main database
+ * by executing 'pragma database_list' on the database.
+ *
+ * @return ArrayList of pairs of (database name, database file path) or null if the database
+ * is not open.
*/
- private static long getPragmaVal(SQLiteDatabase db, String pragma) {
- if (!db.isOpen()) {
- return 0;
- }
- SQLiteStatement prog = null;
- try {
- prog = new SQLiteStatement(db, "PRAGMA " + pragma);
- long val = prog.simpleQueryForLong();
- return val;
- } finally {
- if (prog != null) prog.close();
- }
- }
-
- /**
- * returns list of full pathnames of all attached databases
- * including the main database
- * TODO: move this to {@link DatabaseUtils}
- */
- private static ArrayList<Pair<String, String>> getAttachedDbs(SQLiteDatabase dbObj) {
- if (!dbObj.isOpen()) {
+ public ArrayList<Pair<String, String>> getAttachedDbs() {
+ if (!isOpen()) {
return null;
}
ArrayList<Pair<String, String>> attachedDbs = new ArrayList<Pair<String, String>>();
- Cursor c = dbObj.rawQuery("pragma database_list;", null);
- while (c.moveToNext()) {
- attachedDbs.add(new Pair<String, String>(c.getString(1), c.getString(2)));
+ Cursor c = null;
+ try {
+ c = rawQuery("pragma database_list;", null);
+ while (c.moveToNext()) {
+ // sqlite returns a row for each database in the returned list of databases.
+ // in each row,
+ // 1st column is the database name such as main, or the database
+ // name specified on the "ATTACH" command
+ // 2nd column is the database file path.
+ attachedDbs.add(new Pair<String, String>(c.getString(1), c.getString(2)));
+ }
+ } finally {
+ if (c != null) {
+ c.close();
+ }
}
- c.close();
return attachedDbs;
}
/**
+ * Runs 'pragma integrity_check' on the given database (and all the attached databases)
+ * and returns true if the given database (and all its attached databases) pass integrity_check,
+ * false otherwise.
+ *<p>
+ * If the result is false, then this method logs the errors reported by the integrity_check
+ * command execution.
+ *<p>
+ * Note that 'pragma integrity_check' on a database can take a long time.
+ *
+ * @return true if the given database (and all its attached databases) pass integrity_check,
+ * false otherwise.
+ */
+ public boolean isDatabaseIntegrityOk() {
+ verifyDbIsOpen();
+ ArrayList<Pair<String, String>> attachedDbs = getAttachedDbs();
+ if (attachedDbs == null) {
+ throw new IllegalStateException("databaselist for: " + getPath() + " couldn't " +
+ "be retrieved. probably because the database is closed");
+ }
+ boolean isDatabaseCorrupt = false;
+ for (int i = 0; i < attachedDbs.size(); i++) {
+ Pair<String, String> p = attachedDbs.get(i);
+ SQLiteStatement prog = null;
+ try {
+ prog = compileStatement("PRAGMA " + p.first + ".integrity_check(1);");
+ String rslt = prog.simpleQueryForString();
+ if (!rslt.equalsIgnoreCase("ok")) {
+ // integrity_checker failed on main or attached databases
+ isDatabaseCorrupt = true;
+ Log.e(TAG, "PRAGMA integrity_check on " + p.second + " returned: " + rslt);
+ }
+ } finally {
+ if (prog != null) prog.close();
+ }
+ }
+ return isDatabaseCorrupt;
+ }
+
+ /**
* Native call to open the database.
*
* @param path The full path to the database
@@ -2238,16 +2326,16 @@
private native void dbopen(String path, int flags);
/**
- * Native call to setup tracing of all sql statements
+ * Native call to setup tracing of all SQL statements
*
* @param path the full path to the database
*/
private native void enableSqlTracing(String path);
/**
- * Native call to setup profiling of all sql statements.
+ * Native call to setup profiling of all SQL statements.
* currently, sqlite's profiling = printing of execution-time
- * (wall-clock time) of each of the sql statements, as they
+ * (wall-clock time) of each of the SQL statements, as they
* are executed.
*
* @param path the full path to the database
@@ -2290,4 +2378,11 @@
* @return int value of SQLITE_DBSTATUS_LOOKASIDE_USED
*/
private native int native_getDbLookaside();
+
+ /**
+ * finalizes the given statement id.
+ *
+ * @param statementId statement to be finzlied by sqlite
+ */
+ private final native void native_finalize(int statementId);
}
diff --git a/core/java/android/database/sqlite/SQLiteDebug.java b/core/java/android/database/sqlite/SQLiteDebug.java
index 89c3f96..94960791 100644
--- a/core/java/android/database/sqlite/SQLiteDebug.java
+++ b/core/java/android/database/sqlite/SQLiteDebug.java
@@ -132,11 +132,16 @@
/** documented here http://www.sqlite.org/c3ref/c_dbstatus_lookaside_used.html */
public int lookaside;
- public DbStats(String dbName, long pageCount, long pageSize, int lookaside) {
+ /** statement cache stats: hits/misses/cachesize */
+ public String cache;
+
+ public DbStats(String dbName, long pageCount, long pageSize, int lookaside,
+ int hits, int misses, int cachesize) {
this.dbName = dbName;
- this.pageSize = pageSize;
+ this.pageSize = pageSize / 1024;
dbSize = (pageCount * pageSize) / 1024;
this.lookaside = lookaside;
+ this.cache = hits + "/" + misses + "/" + cachesize;
}
}
diff --git a/core/java/android/database/sqlite/SQLiteDirectCursorDriver.java b/core/java/android/database/sqlite/SQLiteDirectCursorDriver.java
index 2144fc3..be49257 100644
--- a/core/java/android/database/sqlite/SQLiteDirectCursorDriver.java
+++ b/core/java/android/database/sqlite/SQLiteDirectCursorDriver.java
@@ -39,9 +39,12 @@
public Cursor query(CursorFactory factory, String[] selectionArgs) {
// Compile the query
- SQLiteQuery query = new SQLiteQuery(mDatabase, mSql, 0, selectionArgs);
+ SQLiteQuery query = null;
try {
+ mDatabase.lock();
+ mDatabase.closePendingStatements();
+ query = new SQLiteQuery(mDatabase, mSql, 0, selectionArgs);
// Arg binding
int numArgs = selectionArgs == null ? 0 : selectionArgs.length;
for (int i = 0; i < numArgs; i++) {
@@ -61,6 +64,7 @@
} finally {
// Make sure this object is cleaned up if something happens
if (query != null) query.close();
+ mDatabase.unlock();
}
}
diff --git a/core/java/android/database/sqlite/SQLiteOpenHelper.java b/core/java/android/database/sqlite/SQLiteOpenHelper.java
index aefbabc..0f2e872 100644
--- a/core/java/android/database/sqlite/SQLiteOpenHelper.java
+++ b/core/java/android/database/sqlite/SQLiteOpenHelper.java
@@ -17,6 +17,8 @@
package android.database.sqlite;
import android.content.Context;
+import android.database.DatabaseErrorHandler;
+import android.database.DefaultDatabaseErrorHandler;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.util.Log;
@@ -45,6 +47,7 @@
private SQLiteDatabase mDatabase = null;
private boolean mIsInitializing = false;
+ private final DatabaseErrorHandler mErrorHandler;
/**
* Create a helper object to create, open, and/or manage a database.
@@ -58,12 +61,37 @@
* {@link #onUpgrade} will be used to upgrade the database
*/
public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version) {
+ this(context, name, factory, version, new DefaultDatabaseErrorHandler());
+ }
+
+ /**
+ * Create a helper object to create, open, and/or manage a database.
+ * The database is not actually created or opened until one of
+ * {@link #getWritableDatabase} or {@link #getReadableDatabase} is called.
+ *
+ * <p>Accepts input param: a concrete instance of {@link DatabaseErrorHandler} to be
+ * used to handle corruption when sqlite reports database corruption.</p>
+ *
+ * @param context to use to open or create the database
+ * @param name of the database file, or null for an in-memory database
+ * @param factory to use for creating cursor objects, or null for the default
+ * @param version number of the database (starting at 1); if the database is older,
+ * {@link #onUpgrade} will be used to upgrade the database
+ * @param errorHandler the {@link DatabaseErrorHandler} to be used when sqlite reports database
+ * corruption.
+ */
+ public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version,
+ DatabaseErrorHandler errorHandler) {
if (version < 1) throw new IllegalArgumentException("Version must be >= 1, was " + version);
+ if (errorHandler == null) {
+ throw new IllegalArgumentException("DatabaseErrorHandler param value can't be null.");
+ }
mContext = context;
mName = name;
mFactory = factory;
mNewVersion = version;
+ mErrorHandler = errorHandler;
}
/**
@@ -101,10 +129,14 @@
if (mName == null) {
db = SQLiteDatabase.create(null);
} else {
- db = mContext.openOrCreateDatabase(mName, 0, mFactory);
+ db = mContext.openOrCreateDatabase(mName, 0, mFactory, mErrorHandler);
}
int version = db.getVersion();
+ if (version > mNewVersion) {
+ throw new IllegalStateException("Database " + mName +
+ " cannot be downgraded. instead, please uninstall new version first.");
+ }
if (version != mNewVersion) {
db.beginTransaction();
try {
@@ -175,7 +207,8 @@
try {
mIsInitializing = true;
String path = mContext.getDatabasePath(mName).getPath();
- db = SQLiteDatabase.openDatabase(path, mFactory, SQLiteDatabase.OPEN_READONLY);
+ db = SQLiteDatabase.openDatabase(path, mFactory, SQLiteDatabase.OPEN_READONLY,
+ mErrorHandler);
if (db.getVersion() != mNewVersion) {
throw new SQLiteException("Can't upgrade read-only database from version " +
db.getVersion() + " to " + mNewVersion + ": " + path);
diff --git a/core/java/android/database/sqlite/SQLiteProgram.java b/core/java/android/database/sqlite/SQLiteProgram.java
index 4d96f12..a3513e6 100644
--- a/core/java/android/database/sqlite/SQLiteProgram.java
+++ b/core/java/android/database/sqlite/SQLiteProgram.java
@@ -20,7 +20,7 @@
/**
* A base class for compiled SQLite programs.
- *
+ *<p>
* SQLiteProgram is not internally synchronized so code using a SQLiteProgram from multiple
* threads should perform its own synchronization when using the SQLiteProgram.
*/
@@ -150,7 +150,7 @@
* @return a unique identifier for this program
*/
public final int getUniqueId() {
- return nStatement;
+ return (mCompiledSql != null) ? mCompiledSql.nStatement : 0;
}
/* package */ String getSqlString() {
@@ -176,9 +176,7 @@
* @param index The 1-based index to the parameter to bind null to
*/
public void bindNull(int index) {
- if (!mDatabase.isOpen()) {
- throw new IllegalStateException("database " + mDatabase.getPath() + " already closed");
- }
+ mDatabase.verifyDbIsOpen();
acquireReference();
try {
native_bind_null(index);
@@ -195,9 +193,7 @@
* @param value The value to bind
*/
public void bindLong(int index, long value) {
- if (!mDatabase.isOpen()) {
- throw new IllegalStateException("database " + mDatabase.getPath() + " already closed");
- }
+ mDatabase.verifyDbIsOpen();
acquireReference();
try {
native_bind_long(index, value);
@@ -214,9 +210,7 @@
* @param value The value to bind
*/
public void bindDouble(int index, double value) {
- if (!mDatabase.isOpen()) {
- throw new IllegalStateException("database " + mDatabase.getPath() + " already closed");
- }
+ mDatabase.verifyDbIsOpen();
acquireReference();
try {
native_bind_double(index, value);
@@ -236,9 +230,7 @@
if (value == null) {
throw new IllegalArgumentException("the bind value at index " + index + " is null");
}
- if (!mDatabase.isOpen()) {
- throw new IllegalStateException("database " + mDatabase.getPath() + " already closed");
- }
+ mDatabase.verifyDbIsOpen();
acquireReference();
try {
native_bind_string(index, value);
@@ -258,9 +250,7 @@
if (value == null) {
throw new IllegalArgumentException("the bind value at index " + index + " is null");
}
- if (!mDatabase.isOpen()) {
- throw new IllegalStateException("database " + mDatabase.getPath() + " already closed");
- }
+ mDatabase.verifyDbIsOpen();
acquireReference();
try {
native_bind_blob(index, value);
@@ -273,9 +263,7 @@
* Clears all existing bindings. Unset bindings are treated as NULL.
*/
public void clearBindings() {
- if (!mDatabase.isOpen()) {
- throw new IllegalStateException("database " + mDatabase.getPath() + " already closed");
- }
+ mDatabase.verifyDbIsOpen();
acquireReference();
try {
native_clear_bindings();
@@ -291,12 +279,7 @@
if (!mDatabase.isOpen()) {
return;
}
- mDatabase.lock();
- try {
- releaseReference();
- } finally {
- mDatabase.unlock();
- }
+ releaseReference();
}
/**
diff --git a/core/java/android/database/sqlite/SQLiteStatement.java b/core/java/android/database/sqlite/SQLiteStatement.java
index 9e425c3..e1ad306c 100644
--- a/core/java/android/database/sqlite/SQLiteStatement.java
+++ b/core/java/android/database/sqlite/SQLiteStatement.java
@@ -25,7 +25,7 @@
* The statement cannot return multiple rows, but 1x1 result sets are allowed.
* Don't use SQLiteStatement constructor directly, please use
* {@link SQLiteDatabase#compileStatement(String)}
- *
+ *<p>
* SQLiteStatement is not internally synchronized so code using a SQLiteStatement from multiple
* threads should perform its own synchronization when using the SQLiteStatement.
*/
@@ -49,15 +49,14 @@
* some reason
*/
public void execute() {
+ mDatabase.verifyDbIsOpen();
BlockGuard.getThreadPolicy().onWriteToDisk();
- if (!mDatabase.isOpen()) {
- throw new IllegalStateException("database " + mDatabase.getPath() + " already closed");
- }
long timeStart = SystemClock.uptimeMillis();
mDatabase.lock();
acquireReference();
try {
+ mDatabase.closePendingStatements();
native_execute();
mDatabase.logTimeStat(mSql, timeStart);
} finally {
@@ -76,15 +75,14 @@
* some reason
*/
public long executeInsert() {
+ mDatabase.verifyDbIsOpen();
BlockGuard.getThreadPolicy().onWriteToDisk();
- if (!mDatabase.isOpen()) {
- throw new IllegalStateException("database " + mDatabase.getPath() + " already closed");
- }
long timeStart = SystemClock.uptimeMillis();
mDatabase.lock();
acquireReference();
try {
+ mDatabase.closePendingStatements();
native_execute();
mDatabase.logTimeStat(mSql, timeStart);
return (mDatabase.lastChangeCount() > 0) ? mDatabase.lastInsertRow() : -1;
@@ -103,15 +101,14 @@
* @throws android.database.sqlite.SQLiteDoneException if the query returns zero rows
*/
public long simpleQueryForLong() {
+ mDatabase.verifyDbIsOpen();
BlockGuard.getThreadPolicy().onReadFromDisk();
- if (!mDatabase.isOpen()) {
- throw new IllegalStateException("database " + mDatabase.getPath() + " already closed");
- }
long timeStart = SystemClock.uptimeMillis();
mDatabase.lock();
acquireReference();
try {
+ mDatabase.closePendingStatements();
long retValue = native_1x1_long();
mDatabase.logTimeStat(mSql, timeStart);
return retValue;
@@ -130,15 +127,14 @@
* @throws android.database.sqlite.SQLiteDoneException if the query returns zero rows
*/
public String simpleQueryForString() {
+ mDatabase.verifyDbIsOpen();
BlockGuard.getThreadPolicy().onReadFromDisk();
- if (!mDatabase.isOpen()) {
- throw new IllegalStateException("database " + mDatabase.getPath() + " already closed");
- }
long timeStart = SystemClock.uptimeMillis();
mDatabase.lock();
acquireReference();
try {
+ mDatabase.closePendingStatements();
String retValue = native_1x1_string();
mDatabase.logTimeStat(mSql, timeStart);
return retValue;
diff --git a/core/java/android/net/Downloads.java b/core/java/android/net/Downloads.java
index fd33781..ddde5c1 100644
--- a/core/java/android/net/Downloads.java
+++ b/core/java/android/net/Downloads.java
@@ -430,11 +430,10 @@
ContentResolver cr = context.getContentResolver();
- Cursor c = cr.query(
- downloadUri, DOWNLOADS_PROJECTION, null /* selection */, null /* selection args */,
- null /* sort order */);
+ Cursor c = cr.query(downloadUri, DOWNLOADS_PROJECTION, null /* selection */,
+ null /* selection args */, null /* sort order */);
try {
- if (!c.moveToNext()) {
+ if (c == null || !c.moveToNext()) {
return result;
}
diff --git a/core/java/android/net/http/AndroidHttpClient.java b/core/java/android/net/http/AndroidHttpClient.java
index e07ee59..915e342 100644
--- a/core/java/android/net/http/AndroidHttpClient.java
+++ b/core/java/android/net/http/AndroidHttpClient.java
@@ -61,6 +61,7 @@
import android.net.SSLCertificateSocketFactory;
import android.net.SSLSessionCache;
import android.os.Looper;
+import android.util.Base64;
import android.util.Log;
/**
@@ -81,6 +82,11 @@
private static final String TAG = "AndroidHttpClient";
+ private static String[] textContentTypes = new String[] {
+ "text/",
+ "application/xml",
+ "application/json"
+ };
/** Interceptor throws an exception if the executing thread is blocked */
private static final HttpRequestInterceptor sThreadCheckInterceptor =
@@ -358,7 +364,7 @@
}
if (level < Log.VERBOSE || level > Log.ASSERT) {
throw new IllegalArgumentException("Level is out of range ["
- + Log.VERBOSE + ".." + Log.ASSERT + "]");
+ + Log.VERBOSE + ".." + Log.ASSERT + "]");
}
curlConfiguration = new LoggingConfiguration(name, level);
@@ -431,12 +437,17 @@
if (entity.getContentLength() < 1024) {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
entity.writeTo(stream);
- String entityString = stream.toString();
- // TODO: Check the content type, too.
- builder.append(" --data-ascii \"")
- .append(entityString)
- .append("\"");
+ if (isBinaryContent(request)) {
+ String base64 = Base64.encodeToString(stream.toByteArray(), Base64.NO_WRAP);
+ builder.insert(0, "echo '" + base64 + "' | base64 -d > /tmp/$$.bin; ");
+ builder.append(" --data-binary @/tmp/$$.bin");
+ } else {
+ String entityString = stream.toString();
+ builder.append(" --data-ascii \"")
+ .append(entityString)
+ .append("\"");
+ }
} else {
builder.append(" [TOO MUCH DATA TO INCLUDE]");
}
@@ -446,6 +457,30 @@
return builder.toString();
}
+ private static boolean isBinaryContent(HttpUriRequest request) {
+ Header[] headers;
+ headers = request.getHeaders(Headers.CONTENT_ENCODING);
+ if (headers != null) {
+ for (Header header : headers) {
+ if ("gzip".equalsIgnoreCase(header.getValue())) {
+ return true;
+ }
+ }
+ }
+
+ headers = request.getHeaders(Headers.CONTENT_TYPE);
+ if (headers != null) {
+ for (Header header : headers) {
+ for (String contentType : textContentTypes) {
+ if (header.getValue().startsWith(contentType)) {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+ }
+
/**
* Returns the date of the given HTTP date string. This method can identify
* and parse the date formats emitted by common HTTP servers, such as
diff --git a/core/java/android/net/http/CertificateChainValidator.java b/core/java/android/net/http/CertificateChainValidator.java
index c527fe4..c36ad38 100644
--- a/core/java/android/net/http/CertificateChainValidator.java
+++ b/core/java/android/net/http/CertificateChainValidator.java
@@ -80,14 +80,10 @@
throws IOException {
X509Certificate[] serverCertificates = null;
- // start handshake, close the socket if we fail
- try {
- sslSocket.setUseClientMode(true);
- sslSocket.startHandshake();
- } catch (IOException e) {
- closeSocketThrowException(
- sslSocket, e.getMessage(),
- "failed to perform SSL handshake");
+ // get a valid SSLSession, close the socket if we fail
+ SSLSession sslSession = sslSession = sslSocket.getSession();
+ if (!sslSession.isValid()) {
+ closeSocketThrowException(sslSocket, "failed to perform SSL handshake");
}
// retrieve the chain of the server peer certificates
diff --git a/core/java/android/os/AsyncTask.java b/core/java/android/os/AsyncTask.java
index d28148c..823134b 100644
--- a/core/java/android/os/AsyncTask.java
+++ b/core/java/android/os/AsyncTask.java
@@ -16,16 +16,16 @@
package android.os;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.FutureTask;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.Callable;
-import java.util.concurrent.FutureTask;
-import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
-import java.util.concurrent.CancellationException;
import java.util.concurrent.atomic.AtomicInteger;
/**
@@ -36,8 +36,8 @@
* <p>An asynchronous task is defined by a computation that runs on a background thread and
* whose result is published on the UI thread. An asynchronous task is defined by 3 generic
* types, called <code>Params</code>, <code>Progress</code> and <code>Result</code>,
- * and 4 steps, called <code>begin</code>, <code>doInBackground</code>,
- * <code>processProgress</code> and <code>end</code>.</p>
+ * and 4 steps, called <code>onPreExecute</code>, <code>doInBackground</code>,
+ * <code>onProgressUpdate</code> and <code>onPostExecute</code>.</p>
*
* <h2>Usage</h2>
* <p>AsyncTask must be subclassed to be used. The subclass will override at least
@@ -401,6 +401,9 @@
* publish updates on the UI thread while the background computation is
* still running. Each call to this method will trigger the execution of
* {@link #onProgressUpdate} on the UI thread.
+ *
+ * {@link #onProgressUpdate} will note be called if the task has been
+ * canceled.
*
* @param values The progress values to update the UI with.
*
@@ -408,8 +411,10 @@
* @see #doInBackground
*/
protected final void publishProgress(Progress... values) {
- sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
- new AsyncTaskResult<Progress>(this, values)).sendToTarget();
+ if (!isCancelled()) {
+ sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
+ new AsyncTaskResult<Progress>(this, values)).sendToTarget();
+ }
}
private void finish(Result result) {
diff --git a/core/java/android/os/storage/StorageEventListener.java b/core/java/android/os/storage/StorageEventListener.java
index 7b883a7..d3d39d6 100644
--- a/core/java/android/os/storage/StorageEventListener.java
+++ b/core/java/android/os/storage/StorageEventListener.java
@@ -18,7 +18,6 @@
/**
* Used for receiving notifications from the StorageManager
- * @hide
*/
public abstract class StorageEventListener {
/**
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index a12603c..b49979c 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -45,8 +45,6 @@
* {@link android.content.Context#getSystemService(java.lang.String)} with an argument
* of {@link android.content.Context#STORAGE_SERVICE}.
*
- * @hide
- *
*/
public class StorageManager
diff --git a/core/java/android/os/storage/StorageResultCode.java b/core/java/android/os/storage/StorageResultCode.java
index 075f47f..07d95df 100644
--- a/core/java/android/os/storage/StorageResultCode.java
+++ b/core/java/android/os/storage/StorageResultCode.java
@@ -19,8 +19,6 @@
/**
* Class that provides access to constants returned from StorageManager
* and lower level MountService APIs.
- *
- * @hide
*/
public class StorageResultCode
{
diff --git a/core/java/android/pim/RecurrenceSet.java b/core/java/android/pim/RecurrenceSet.java
index 635323e..282417d 100644
--- a/core/java/android/pim/RecurrenceSet.java
+++ b/core/java/android/pim/RecurrenceSet.java
@@ -181,7 +181,9 @@
boolean inUtc = start.parse(dtstart);
boolean allDay = start.allDay;
- if (inUtc) {
+ // We force TimeZone to UTC for "all day recurring events" as the server is sending no
+ // TimeZone in DTSTART for them
+ if (inUtc || allDay) {
tzid = Time.TIMEZONE_UTC;
}
@@ -204,10 +206,7 @@
}
if (allDay) {
- // TODO: also change tzid to be UTC? that would be consistent, but
- // that would not reflect the original timezone value back to the
- // server.
- start.timezone = Time.TIMEZONE_UTC;
+ start.timezone = Time.TIMEZONE_UTC;
}
long millis = start.toMillis(false /* use isDst */);
values.put(Calendar.Events.DTSTART, millis);
diff --git a/core/java/android/pim/vcard/JapaneseUtils.java b/core/java/android/pim/vcard/JapaneseUtils.java
deleted file mode 100644
index 875c29e..0000000
--- a/core/java/android/pim/vcard/JapaneseUtils.java
+++ /dev/null
@@ -1,380 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.pim.vcard;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * TextUtils especially for Japanese.
- */
-/* package */ class JapaneseUtils {
- static private final Map<Character, String> sHalfWidthMap =
- new HashMap<Character, String>();
-
- static {
- // There's no logical mapping rule in Unicode. Sigh.
- sHalfWidthMap.put('\u3001', "\uFF64");
- sHalfWidthMap.put('\u3002', "\uFF61");
- sHalfWidthMap.put('\u300C', "\uFF62");
- sHalfWidthMap.put('\u300D', "\uFF63");
- sHalfWidthMap.put('\u301C', "~");
- sHalfWidthMap.put('\u3041', "\uFF67");
- sHalfWidthMap.put('\u3042', "\uFF71");
- sHalfWidthMap.put('\u3043', "\uFF68");
- sHalfWidthMap.put('\u3044', "\uFF72");
- sHalfWidthMap.put('\u3045', "\uFF69");
- sHalfWidthMap.put('\u3046', "\uFF73");
- sHalfWidthMap.put('\u3047', "\uFF6A");
- sHalfWidthMap.put('\u3048', "\uFF74");
- sHalfWidthMap.put('\u3049', "\uFF6B");
- sHalfWidthMap.put('\u304A', "\uFF75");
- sHalfWidthMap.put('\u304B', "\uFF76");
- sHalfWidthMap.put('\u304C', "\uFF76\uFF9E");
- sHalfWidthMap.put('\u304D', "\uFF77");
- sHalfWidthMap.put('\u304E', "\uFF77\uFF9E");
- sHalfWidthMap.put('\u304F', "\uFF78");
- sHalfWidthMap.put('\u3050', "\uFF78\uFF9E");
- sHalfWidthMap.put('\u3051', "\uFF79");
- sHalfWidthMap.put('\u3052', "\uFF79\uFF9E");
- sHalfWidthMap.put('\u3053', "\uFF7A");
- sHalfWidthMap.put('\u3054', "\uFF7A\uFF9E");
- sHalfWidthMap.put('\u3055', "\uFF7B");
- sHalfWidthMap.put('\u3056', "\uFF7B\uFF9E");
- sHalfWidthMap.put('\u3057', "\uFF7C");
- sHalfWidthMap.put('\u3058', "\uFF7C\uFF9E");
- sHalfWidthMap.put('\u3059', "\uFF7D");
- sHalfWidthMap.put('\u305A', "\uFF7D\uFF9E");
- sHalfWidthMap.put('\u305B', "\uFF7E");
- sHalfWidthMap.put('\u305C', "\uFF7E\uFF9E");
- sHalfWidthMap.put('\u305D', "\uFF7F");
- sHalfWidthMap.put('\u305E', "\uFF7F\uFF9E");
- sHalfWidthMap.put('\u305F', "\uFF80");
- sHalfWidthMap.put('\u3060', "\uFF80\uFF9E");
- sHalfWidthMap.put('\u3061', "\uFF81");
- sHalfWidthMap.put('\u3062', "\uFF81\uFF9E");
- sHalfWidthMap.put('\u3063', "\uFF6F");
- sHalfWidthMap.put('\u3064', "\uFF82");
- sHalfWidthMap.put('\u3065', "\uFF82\uFF9E");
- sHalfWidthMap.put('\u3066', "\uFF83");
- sHalfWidthMap.put('\u3067', "\uFF83\uFF9E");
- sHalfWidthMap.put('\u3068', "\uFF84");
- sHalfWidthMap.put('\u3069', "\uFF84\uFF9E");
- sHalfWidthMap.put('\u306A', "\uFF85");
- sHalfWidthMap.put('\u306B', "\uFF86");
- sHalfWidthMap.put('\u306C', "\uFF87");
- sHalfWidthMap.put('\u306D', "\uFF88");
- sHalfWidthMap.put('\u306E', "\uFF89");
- sHalfWidthMap.put('\u306F', "\uFF8A");
- sHalfWidthMap.put('\u3070', "\uFF8A\uFF9E");
- sHalfWidthMap.put('\u3071', "\uFF8A\uFF9F");
- sHalfWidthMap.put('\u3072', "\uFF8B");
- sHalfWidthMap.put('\u3073', "\uFF8B\uFF9E");
- sHalfWidthMap.put('\u3074', "\uFF8B\uFF9F");
- sHalfWidthMap.put('\u3075', "\uFF8C");
- sHalfWidthMap.put('\u3076', "\uFF8C\uFF9E");
- sHalfWidthMap.put('\u3077', "\uFF8C\uFF9F");
- sHalfWidthMap.put('\u3078', "\uFF8D");
- sHalfWidthMap.put('\u3079', "\uFF8D\uFF9E");
- sHalfWidthMap.put('\u307A', "\uFF8D\uFF9F");
- sHalfWidthMap.put('\u307B', "\uFF8E");
- sHalfWidthMap.put('\u307C', "\uFF8E\uFF9E");
- sHalfWidthMap.put('\u307D', "\uFF8E\uFF9F");
- sHalfWidthMap.put('\u307E', "\uFF8F");
- sHalfWidthMap.put('\u307F', "\uFF90");
- sHalfWidthMap.put('\u3080', "\uFF91");
- sHalfWidthMap.put('\u3081', "\uFF92");
- sHalfWidthMap.put('\u3082', "\uFF93");
- sHalfWidthMap.put('\u3083', "\uFF6C");
- sHalfWidthMap.put('\u3084', "\uFF94");
- sHalfWidthMap.put('\u3085', "\uFF6D");
- sHalfWidthMap.put('\u3086', "\uFF95");
- sHalfWidthMap.put('\u3087', "\uFF6E");
- sHalfWidthMap.put('\u3088', "\uFF96");
- sHalfWidthMap.put('\u3089', "\uFF97");
- sHalfWidthMap.put('\u308A', "\uFF98");
- sHalfWidthMap.put('\u308B', "\uFF99");
- sHalfWidthMap.put('\u308C', "\uFF9A");
- sHalfWidthMap.put('\u308D', "\uFF9B");
- sHalfWidthMap.put('\u308E', "\uFF9C");
- sHalfWidthMap.put('\u308F', "\uFF9C");
- sHalfWidthMap.put('\u3090', "\uFF72");
- sHalfWidthMap.put('\u3091', "\uFF74");
- sHalfWidthMap.put('\u3092', "\uFF66");
- sHalfWidthMap.put('\u3093', "\uFF9D");
- sHalfWidthMap.put('\u309B', "\uFF9E");
- sHalfWidthMap.put('\u309C', "\uFF9F");
- sHalfWidthMap.put('\u30A1', "\uFF67");
- sHalfWidthMap.put('\u30A2', "\uFF71");
- sHalfWidthMap.put('\u30A3', "\uFF68");
- sHalfWidthMap.put('\u30A4', "\uFF72");
- sHalfWidthMap.put('\u30A5', "\uFF69");
- sHalfWidthMap.put('\u30A6', "\uFF73");
- sHalfWidthMap.put('\u30A7', "\uFF6A");
- sHalfWidthMap.put('\u30A8', "\uFF74");
- sHalfWidthMap.put('\u30A9', "\uFF6B");
- sHalfWidthMap.put('\u30AA', "\uFF75");
- sHalfWidthMap.put('\u30AB', "\uFF76");
- sHalfWidthMap.put('\u30AC', "\uFF76\uFF9E");
- sHalfWidthMap.put('\u30AD', "\uFF77");
- sHalfWidthMap.put('\u30AE', "\uFF77\uFF9E");
- sHalfWidthMap.put('\u30AF', "\uFF78");
- sHalfWidthMap.put('\u30B0', "\uFF78\uFF9E");
- sHalfWidthMap.put('\u30B1', "\uFF79");
- sHalfWidthMap.put('\u30B2', "\uFF79\uFF9E");
- sHalfWidthMap.put('\u30B3', "\uFF7A");
- sHalfWidthMap.put('\u30B4', "\uFF7A\uFF9E");
- sHalfWidthMap.put('\u30B5', "\uFF7B");
- sHalfWidthMap.put('\u30B6', "\uFF7B\uFF9E");
- sHalfWidthMap.put('\u30B7', "\uFF7C");
- sHalfWidthMap.put('\u30B8', "\uFF7C\uFF9E");
- sHalfWidthMap.put('\u30B9', "\uFF7D");
- sHalfWidthMap.put('\u30BA', "\uFF7D\uFF9E");
- sHalfWidthMap.put('\u30BB', "\uFF7E");
- sHalfWidthMap.put('\u30BC', "\uFF7E\uFF9E");
- sHalfWidthMap.put('\u30BD', "\uFF7F");
- sHalfWidthMap.put('\u30BE', "\uFF7F\uFF9E");
- sHalfWidthMap.put('\u30BF', "\uFF80");
- sHalfWidthMap.put('\u30C0', "\uFF80\uFF9E");
- sHalfWidthMap.put('\u30C1', "\uFF81");
- sHalfWidthMap.put('\u30C2', "\uFF81\uFF9E");
- sHalfWidthMap.put('\u30C3', "\uFF6F");
- sHalfWidthMap.put('\u30C4', "\uFF82");
- sHalfWidthMap.put('\u30C5', "\uFF82\uFF9E");
- sHalfWidthMap.put('\u30C6', "\uFF83");
- sHalfWidthMap.put('\u30C7', "\uFF83\uFF9E");
- sHalfWidthMap.put('\u30C8', "\uFF84");
- sHalfWidthMap.put('\u30C9', "\uFF84\uFF9E");
- sHalfWidthMap.put('\u30CA', "\uFF85");
- sHalfWidthMap.put('\u30CB', "\uFF86");
- sHalfWidthMap.put('\u30CC', "\uFF87");
- sHalfWidthMap.put('\u30CD', "\uFF88");
- sHalfWidthMap.put('\u30CE', "\uFF89");
- sHalfWidthMap.put('\u30CF', "\uFF8A");
- sHalfWidthMap.put('\u30D0', "\uFF8A\uFF9E");
- sHalfWidthMap.put('\u30D1', "\uFF8A\uFF9F");
- sHalfWidthMap.put('\u30D2', "\uFF8B");
- sHalfWidthMap.put('\u30D3', "\uFF8B\uFF9E");
- sHalfWidthMap.put('\u30D4', "\uFF8B\uFF9F");
- sHalfWidthMap.put('\u30D5', "\uFF8C");
- sHalfWidthMap.put('\u30D6', "\uFF8C\uFF9E");
- sHalfWidthMap.put('\u30D7', "\uFF8C\uFF9F");
- sHalfWidthMap.put('\u30D8', "\uFF8D");
- sHalfWidthMap.put('\u30D9', "\uFF8D\uFF9E");
- sHalfWidthMap.put('\u30DA', "\uFF8D\uFF9F");
- sHalfWidthMap.put('\u30DB', "\uFF8E");
- sHalfWidthMap.put('\u30DC', "\uFF8E\uFF9E");
- sHalfWidthMap.put('\u30DD', "\uFF8E\uFF9F");
- sHalfWidthMap.put('\u30DE', "\uFF8F");
- sHalfWidthMap.put('\u30DF', "\uFF90");
- sHalfWidthMap.put('\u30E0', "\uFF91");
- sHalfWidthMap.put('\u30E1', "\uFF92");
- sHalfWidthMap.put('\u30E2', "\uFF93");
- sHalfWidthMap.put('\u30E3', "\uFF6C");
- sHalfWidthMap.put('\u30E4', "\uFF94");
- sHalfWidthMap.put('\u30E5', "\uFF6D");
- sHalfWidthMap.put('\u30E6', "\uFF95");
- sHalfWidthMap.put('\u30E7', "\uFF6E");
- sHalfWidthMap.put('\u30E8', "\uFF96");
- sHalfWidthMap.put('\u30E9', "\uFF97");
- sHalfWidthMap.put('\u30EA', "\uFF98");
- sHalfWidthMap.put('\u30EB', "\uFF99");
- sHalfWidthMap.put('\u30EC', "\uFF9A");
- sHalfWidthMap.put('\u30ED', "\uFF9B");
- sHalfWidthMap.put('\u30EE', "\uFF9C");
- sHalfWidthMap.put('\u30EF', "\uFF9C");
- sHalfWidthMap.put('\u30F0', "\uFF72");
- sHalfWidthMap.put('\u30F1', "\uFF74");
- sHalfWidthMap.put('\u30F2', "\uFF66");
- sHalfWidthMap.put('\u30F3', "\uFF9D");
- sHalfWidthMap.put('\u30F4', "\uFF73\uFF9E");
- sHalfWidthMap.put('\u30F5', "\uFF76");
- sHalfWidthMap.put('\u30F6', "\uFF79");
- sHalfWidthMap.put('\u30FB', "\uFF65");
- sHalfWidthMap.put('\u30FC', "\uFF70");
- sHalfWidthMap.put('\uFF01', "!");
- sHalfWidthMap.put('\uFF02', "\"");
- sHalfWidthMap.put('\uFF03', "#");
- sHalfWidthMap.put('\uFF04', "$");
- sHalfWidthMap.put('\uFF05', "%");
- sHalfWidthMap.put('\uFF06', "&");
- sHalfWidthMap.put('\uFF07', "'");
- sHalfWidthMap.put('\uFF08', "(");
- sHalfWidthMap.put('\uFF09', ")");
- sHalfWidthMap.put('\uFF0A', "*");
- sHalfWidthMap.put('\uFF0B', "+");
- sHalfWidthMap.put('\uFF0C', ",");
- sHalfWidthMap.put('\uFF0D', "-");
- sHalfWidthMap.put('\uFF0E', ".");
- sHalfWidthMap.put('\uFF0F', "/");
- sHalfWidthMap.put('\uFF10', "0");
- sHalfWidthMap.put('\uFF11', "1");
- sHalfWidthMap.put('\uFF12', "2");
- sHalfWidthMap.put('\uFF13', "3");
- sHalfWidthMap.put('\uFF14', "4");
- sHalfWidthMap.put('\uFF15', "5");
- sHalfWidthMap.put('\uFF16', "6");
- sHalfWidthMap.put('\uFF17', "7");
- sHalfWidthMap.put('\uFF18', "8");
- sHalfWidthMap.put('\uFF19', "9");
- sHalfWidthMap.put('\uFF1A', ":");
- sHalfWidthMap.put('\uFF1B', ";");
- sHalfWidthMap.put('\uFF1C', "<");
- sHalfWidthMap.put('\uFF1D', "=");
- sHalfWidthMap.put('\uFF1E', ">");
- sHalfWidthMap.put('\uFF1F', "?");
- sHalfWidthMap.put('\uFF20', "@");
- sHalfWidthMap.put('\uFF21', "A");
- sHalfWidthMap.put('\uFF22', "B");
- sHalfWidthMap.put('\uFF23', "C");
- sHalfWidthMap.put('\uFF24', "D");
- sHalfWidthMap.put('\uFF25', "E");
- sHalfWidthMap.put('\uFF26', "F");
- sHalfWidthMap.put('\uFF27', "G");
- sHalfWidthMap.put('\uFF28', "H");
- sHalfWidthMap.put('\uFF29', "I");
- sHalfWidthMap.put('\uFF2A', "J");
- sHalfWidthMap.put('\uFF2B', "K");
- sHalfWidthMap.put('\uFF2C', "L");
- sHalfWidthMap.put('\uFF2D', "M");
- sHalfWidthMap.put('\uFF2E', "N");
- sHalfWidthMap.put('\uFF2F', "O");
- sHalfWidthMap.put('\uFF30', "P");
- sHalfWidthMap.put('\uFF31', "Q");
- sHalfWidthMap.put('\uFF32', "R");
- sHalfWidthMap.put('\uFF33', "S");
- sHalfWidthMap.put('\uFF34', "T");
- sHalfWidthMap.put('\uFF35', "U");
- sHalfWidthMap.put('\uFF36', "V");
- sHalfWidthMap.put('\uFF37', "W");
- sHalfWidthMap.put('\uFF38', "X");
- sHalfWidthMap.put('\uFF39', "Y");
- sHalfWidthMap.put('\uFF3A', "Z");
- sHalfWidthMap.put('\uFF3B', "[");
- sHalfWidthMap.put('\uFF3C', "\\");
- sHalfWidthMap.put('\uFF3D', "]");
- sHalfWidthMap.put('\uFF3E', "^");
- sHalfWidthMap.put('\uFF3F', "_");
- sHalfWidthMap.put('\uFF41', "a");
- sHalfWidthMap.put('\uFF42', "b");
- sHalfWidthMap.put('\uFF43', "c");
- sHalfWidthMap.put('\uFF44', "d");
- sHalfWidthMap.put('\uFF45', "e");
- sHalfWidthMap.put('\uFF46', "f");
- sHalfWidthMap.put('\uFF47', "g");
- sHalfWidthMap.put('\uFF48', "h");
- sHalfWidthMap.put('\uFF49', "i");
- sHalfWidthMap.put('\uFF4A', "j");
- sHalfWidthMap.put('\uFF4B', "k");
- sHalfWidthMap.put('\uFF4C', "l");
- sHalfWidthMap.put('\uFF4D', "m");
- sHalfWidthMap.put('\uFF4E', "n");
- sHalfWidthMap.put('\uFF4F', "o");
- sHalfWidthMap.put('\uFF50', "p");
- sHalfWidthMap.put('\uFF51', "q");
- sHalfWidthMap.put('\uFF52', "r");
- sHalfWidthMap.put('\uFF53', "s");
- sHalfWidthMap.put('\uFF54', "t");
- sHalfWidthMap.put('\uFF55', "u");
- sHalfWidthMap.put('\uFF56', "v");
- sHalfWidthMap.put('\uFF57', "w");
- sHalfWidthMap.put('\uFF58', "x");
- sHalfWidthMap.put('\uFF59', "y");
- sHalfWidthMap.put('\uFF5A', "z");
- sHalfWidthMap.put('\uFF5B', "{");
- sHalfWidthMap.put('\uFF5C', "|");
- sHalfWidthMap.put('\uFF5D', "}");
- sHalfWidthMap.put('\uFF5E', "~");
- sHalfWidthMap.put('\uFF61', "\uFF61");
- sHalfWidthMap.put('\uFF62', "\uFF62");
- sHalfWidthMap.put('\uFF63', "\uFF63");
- sHalfWidthMap.put('\uFF64', "\uFF64");
- sHalfWidthMap.put('\uFF65', "\uFF65");
- sHalfWidthMap.put('\uFF66', "\uFF66");
- sHalfWidthMap.put('\uFF67', "\uFF67");
- sHalfWidthMap.put('\uFF68', "\uFF68");
- sHalfWidthMap.put('\uFF69', "\uFF69");
- sHalfWidthMap.put('\uFF6A', "\uFF6A");
- sHalfWidthMap.put('\uFF6B', "\uFF6B");
- sHalfWidthMap.put('\uFF6C', "\uFF6C");
- sHalfWidthMap.put('\uFF6D', "\uFF6D");
- sHalfWidthMap.put('\uFF6E', "\uFF6E");
- sHalfWidthMap.put('\uFF6F', "\uFF6F");
- sHalfWidthMap.put('\uFF70', "\uFF70");
- sHalfWidthMap.put('\uFF71', "\uFF71");
- sHalfWidthMap.put('\uFF72', "\uFF72");
- sHalfWidthMap.put('\uFF73', "\uFF73");
- sHalfWidthMap.put('\uFF74', "\uFF74");
- sHalfWidthMap.put('\uFF75', "\uFF75");
- sHalfWidthMap.put('\uFF76', "\uFF76");
- sHalfWidthMap.put('\uFF77', "\uFF77");
- sHalfWidthMap.put('\uFF78', "\uFF78");
- sHalfWidthMap.put('\uFF79', "\uFF79");
- sHalfWidthMap.put('\uFF7A', "\uFF7A");
- sHalfWidthMap.put('\uFF7B', "\uFF7B");
- sHalfWidthMap.put('\uFF7C', "\uFF7C");
- sHalfWidthMap.put('\uFF7D', "\uFF7D");
- sHalfWidthMap.put('\uFF7E', "\uFF7E");
- sHalfWidthMap.put('\uFF7F', "\uFF7F");
- sHalfWidthMap.put('\uFF80', "\uFF80");
- sHalfWidthMap.put('\uFF81', "\uFF81");
- sHalfWidthMap.put('\uFF82', "\uFF82");
- sHalfWidthMap.put('\uFF83', "\uFF83");
- sHalfWidthMap.put('\uFF84', "\uFF84");
- sHalfWidthMap.put('\uFF85', "\uFF85");
- sHalfWidthMap.put('\uFF86', "\uFF86");
- sHalfWidthMap.put('\uFF87', "\uFF87");
- sHalfWidthMap.put('\uFF88', "\uFF88");
- sHalfWidthMap.put('\uFF89', "\uFF89");
- sHalfWidthMap.put('\uFF8A', "\uFF8A");
- sHalfWidthMap.put('\uFF8B', "\uFF8B");
- sHalfWidthMap.put('\uFF8C', "\uFF8C");
- sHalfWidthMap.put('\uFF8D', "\uFF8D");
- sHalfWidthMap.put('\uFF8E', "\uFF8E");
- sHalfWidthMap.put('\uFF8F', "\uFF8F");
- sHalfWidthMap.put('\uFF90', "\uFF90");
- sHalfWidthMap.put('\uFF91', "\uFF91");
- sHalfWidthMap.put('\uFF92', "\uFF92");
- sHalfWidthMap.put('\uFF93', "\uFF93");
- sHalfWidthMap.put('\uFF94', "\uFF94");
- sHalfWidthMap.put('\uFF95', "\uFF95");
- sHalfWidthMap.put('\uFF96', "\uFF96");
- sHalfWidthMap.put('\uFF97', "\uFF97");
- sHalfWidthMap.put('\uFF98', "\uFF98");
- sHalfWidthMap.put('\uFF99', "\uFF99");
- sHalfWidthMap.put('\uFF9A', "\uFF9A");
- sHalfWidthMap.put('\uFF9B', "\uFF9B");
- sHalfWidthMap.put('\uFF9C', "\uFF9C");
- sHalfWidthMap.put('\uFF9D', "\uFF9D");
- sHalfWidthMap.put('\uFF9E', "\uFF9E");
- sHalfWidthMap.put('\uFF9F', "\uFF9F");
- sHalfWidthMap.put('\uFFE5', "\u005C\u005C");
- }
-
- /**
- * Return half-width version of that character if possible. Return null if not possible
- * @param ch input character
- * @return CharSequence object if the mapping for ch exists. Return null otherwise.
- */
- public static String tryGetHalfWidthText(char ch) {
- if (sHalfWidthMap.containsKey(ch)) {
- return sHalfWidthMap.get(ch);
- } else {
- return null;
- }
- }
-}
diff --git a/core/java/android/pim/vcard/VCardBuilder.java b/core/java/android/pim/vcard/VCardBuilder.java
deleted file mode 100644
index 1da6d7a..0000000
--- a/core/java/android/pim/vcard/VCardBuilder.java
+++ /dev/null
@@ -1,1932 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package android.pim.vcard;
-
-import android.content.ContentValues;
-import android.provider.ContactsContract.CommonDataKinds.Email;
-import android.provider.ContactsContract.CommonDataKinds.Event;
-import android.provider.ContactsContract.CommonDataKinds.Im;
-import android.provider.ContactsContract.CommonDataKinds.Nickname;
-import android.provider.ContactsContract.CommonDataKinds.Note;
-import android.provider.ContactsContract.CommonDataKinds.Organization;
-import android.provider.ContactsContract.CommonDataKinds.Phone;
-import android.provider.ContactsContract.CommonDataKinds.Photo;
-import android.provider.ContactsContract.CommonDataKinds.Relation;
-import android.provider.ContactsContract.CommonDataKinds.StructuredName;
-import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
-import android.provider.ContactsContract.CommonDataKinds.Website;
-import android.telephony.PhoneNumberUtils;
-import android.text.TextUtils;
-import android.util.CharsetUtils;
-import android.util.Log;
-
-import org.apache.commons.codec.binary.Base64;
-
-import java.io.UnsupportedEncodingException;
-import java.nio.charset.UnsupportedCharsetException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * The class which lets users create their own vCard String.
- */
-public class VCardBuilder {
- private static final String LOG_TAG = "VCardBuilder";
-
- // If you add the other element, please check all the columns are able to be
- // converted to String.
- //
- // e.g. BLOB is not what we can handle here now.
- private static final Set<String> sAllowedAndroidPropertySet =
- Collections.unmodifiableSet(new HashSet<String>(Arrays.asList(
- Nickname.CONTENT_ITEM_TYPE, Event.CONTENT_ITEM_TYPE,
- Relation.CONTENT_ITEM_TYPE)));
-
- public static final int DEFAULT_PHONE_TYPE = Phone.TYPE_HOME;
- public static final int DEFAULT_POSTAL_TYPE = StructuredPostal.TYPE_HOME;
- public static final int DEFAULT_EMAIL_TYPE = Email.TYPE_OTHER;
-
- private static final String VCARD_DATA_VCARD = "VCARD";
- private static final String VCARD_DATA_PUBLIC = "PUBLIC";
-
- private static final String VCARD_PARAM_SEPARATOR = ";";
- private static final String VCARD_END_OF_LINE = "\r\n";
- private static final String VCARD_DATA_SEPARATOR = ":";
- private static final String VCARD_ITEM_SEPARATOR = ";";
- private static final String VCARD_WS = " ";
- private static final String VCARD_PARAM_EQUAL = "=";
-
- private static final String VCARD_PARAM_ENCODING_QP = "ENCODING=QUOTED-PRINTABLE";
-
- private static final String VCARD_PARAM_ENCODING_BASE64_V21 = "ENCODING=BASE64";
- private static final String VCARD_PARAM_ENCODING_BASE64_V30 = "ENCODING=b";
-
- private static final String SHIFT_JIS = "SHIFT_JIS";
- private static final String UTF_8 = "UTF-8";
-
- private final int mVCardType;
-
- private final boolean mIsV30;
- private final boolean mIsJapaneseMobilePhone;
- private final boolean mOnlyOneNoteFieldIsAvailable;
- private final boolean mIsDoCoMo;
- private final boolean mShouldUseQuotedPrintable;
- private final boolean mUsesAndroidProperty;
- private final boolean mUsesDefactProperty;
- private final boolean mUsesUtf8;
- private final boolean mUsesShiftJis;
- private final boolean mAppendTypeParamName;
- private final boolean mRefrainsQPToNameProperties;
- private final boolean mNeedsToConvertPhoneticString;
-
- private final boolean mShouldAppendCharsetParam;
-
- private final String mCharsetString;
- private final String mVCardCharsetParameter;
-
- private StringBuilder mBuilder;
- private boolean mEndAppended;
-
- public VCardBuilder(final int vcardType) {
- mVCardType = vcardType;
-
- mIsV30 = VCardConfig.isV30(vcardType);
- mShouldUseQuotedPrintable = VCardConfig.shouldUseQuotedPrintable(vcardType);
- mIsDoCoMo = VCardConfig.isDoCoMo(vcardType);
- mIsJapaneseMobilePhone = VCardConfig.needsToConvertPhoneticString(vcardType);
- mOnlyOneNoteFieldIsAvailable = VCardConfig.onlyOneNoteFieldIsAvailable(vcardType);
- mUsesAndroidProperty = VCardConfig.usesAndroidSpecificProperty(vcardType);
- mUsesDefactProperty = VCardConfig.usesDefactProperty(vcardType);
- mUsesUtf8 = VCardConfig.usesUtf8(vcardType);
- mUsesShiftJis = VCardConfig.usesShiftJis(vcardType);
- mRefrainsQPToNameProperties = VCardConfig.shouldRefrainQPToNameProperties(vcardType);
- mAppendTypeParamName = VCardConfig.appendTypeParamName(vcardType);
- mNeedsToConvertPhoneticString = VCardConfig.needsToConvertPhoneticString(vcardType);
-
- mShouldAppendCharsetParam = !(mIsV30 && mUsesUtf8);
-
- if (mIsDoCoMo) {
- String charset;
- try {
- charset = CharsetUtils.charsetForVendor(SHIFT_JIS, "docomo").name();
- } catch (UnsupportedCharsetException e) {
- Log.e(LOG_TAG, "DoCoMo-specific SHIFT_JIS was not found. Use SHIFT_JIS as is.");
- charset = SHIFT_JIS;
- }
- mCharsetString = charset;
- // Do not use mCharsetString bellow since it is different from "SHIFT_JIS" but
- // may be "DOCOMO_SHIFT_JIS" or something like that (internal expression used in
- // Android, not shown to the public).
- mVCardCharsetParameter = "CHARSET=" + SHIFT_JIS;
- } else if (mUsesShiftJis) {
- String charset;
- try {
- charset = CharsetUtils.charsetForVendor(SHIFT_JIS).name();
- } catch (UnsupportedCharsetException e) {
- Log.e(LOG_TAG, "Vendor-specific SHIFT_JIS was not found. Use SHIFT_JIS as is.");
- charset = SHIFT_JIS;
- }
- mCharsetString = charset;
- mVCardCharsetParameter = "CHARSET=" + SHIFT_JIS;
- } else {
- mCharsetString = UTF_8;
- mVCardCharsetParameter = "CHARSET=" + UTF_8;
- }
- clear();
- }
-
- public void clear() {
- mBuilder = new StringBuilder();
- mEndAppended = false;
- appendLine(VCardConstants.PROPERTY_BEGIN, VCARD_DATA_VCARD);
- if (mIsV30) {
- appendLine(VCardConstants.PROPERTY_VERSION, VCardConstants.VERSION_V30);
- } else {
- appendLine(VCardConstants.PROPERTY_VERSION, VCardConstants.VERSION_V21);
- }
- }
-
- private boolean containsNonEmptyName(final ContentValues contentValues) {
- final String familyName = contentValues.getAsString(StructuredName.FAMILY_NAME);
- final String middleName = contentValues.getAsString(StructuredName.MIDDLE_NAME);
- final String givenName = contentValues.getAsString(StructuredName.GIVEN_NAME);
- final String prefix = contentValues.getAsString(StructuredName.PREFIX);
- final String suffix = contentValues.getAsString(StructuredName.SUFFIX);
- final String phoneticFamilyName =
- contentValues.getAsString(StructuredName.PHONETIC_FAMILY_NAME);
- final String phoneticMiddleName =
- contentValues.getAsString(StructuredName.PHONETIC_MIDDLE_NAME);
- final String phoneticGivenName =
- contentValues.getAsString(StructuredName.PHONETIC_GIVEN_NAME);
- final String displayName = contentValues.getAsString(StructuredName.DISPLAY_NAME);
- return !(TextUtils.isEmpty(familyName) && TextUtils.isEmpty(middleName) &&
- TextUtils.isEmpty(givenName) && TextUtils.isEmpty(prefix) &&
- TextUtils.isEmpty(suffix) && TextUtils.isEmpty(phoneticFamilyName) &&
- TextUtils.isEmpty(phoneticMiddleName) && TextUtils.isEmpty(phoneticGivenName) &&
- TextUtils.isEmpty(displayName));
- }
-
- private ContentValues getPrimaryContentValue(final List<ContentValues> contentValuesList) {
- ContentValues primaryContentValues = null;
- ContentValues subprimaryContentValues = null;
- for (ContentValues contentValues : contentValuesList) {
- if (contentValues == null){
- continue;
- }
- Integer isSuperPrimary = contentValues.getAsInteger(StructuredName.IS_SUPER_PRIMARY);
- if (isSuperPrimary != null && isSuperPrimary > 0) {
- // We choose "super primary" ContentValues.
- primaryContentValues = contentValues;
- break;
- } else if (primaryContentValues == null) {
- // We choose the first "primary" ContentValues
- // if "super primary" ContentValues does not exist.
- final Integer isPrimary = contentValues.getAsInteger(StructuredName.IS_PRIMARY);
- if (isPrimary != null && isPrimary > 0 &&
- containsNonEmptyName(contentValues)) {
- primaryContentValues = contentValues;
- // Do not break, since there may be ContentValues with "super primary"
- // afterword.
- } else if (subprimaryContentValues == null &&
- containsNonEmptyName(contentValues)) {
- subprimaryContentValues = contentValues;
- }
- }
- }
-
- if (primaryContentValues == null) {
- if (subprimaryContentValues != null) {
- // We choose the first ContentValues if any "primary" ContentValues does not exist.
- primaryContentValues = subprimaryContentValues;
- } else {
- Log.e(LOG_TAG, "All ContentValues given from database is empty.");
- primaryContentValues = new ContentValues();
- }
- }
-
- return primaryContentValues;
- }
-
- /**
- * For safety, we'll emit just one value around StructuredName, as external importers
- * may get confused with multiple "N", "FN", etc. properties, though it is valid in
- * vCard spec.
- */
- public VCardBuilder appendNameProperties(final List<ContentValues> contentValuesList) {
- if (contentValuesList == null || contentValuesList.isEmpty()) {
- if (mIsDoCoMo) {
- appendLine(VCardConstants.PROPERTY_N, "");
- } else if (mIsV30) {
- // vCard 3.0 requires "N" and "FN" properties.
- appendLine(VCardConstants.PROPERTY_N, "");
- appendLine(VCardConstants.PROPERTY_FN, "");
- }
- return this;
- }
-
- final ContentValues contentValues = getPrimaryContentValue(contentValuesList);
- final String familyName = contentValues.getAsString(StructuredName.FAMILY_NAME);
- final String middleName = contentValues.getAsString(StructuredName.MIDDLE_NAME);
- final String givenName = contentValues.getAsString(StructuredName.GIVEN_NAME);
- final String prefix = contentValues.getAsString(StructuredName.PREFIX);
- final String suffix = contentValues.getAsString(StructuredName.SUFFIX);
- final String displayName = contentValues.getAsString(StructuredName.DISPLAY_NAME);
-
- if (!TextUtils.isEmpty(familyName) || !TextUtils.isEmpty(givenName)) {
- final boolean reallyAppendCharsetParameterToName =
- shouldAppendCharsetParam(familyName, givenName, middleName, prefix, suffix);
- final boolean reallyUseQuotedPrintableToName =
- (!mRefrainsQPToNameProperties &&
- !(VCardUtils.containsOnlyNonCrLfPrintableAscii(familyName) &&
- VCardUtils.containsOnlyNonCrLfPrintableAscii(givenName) &&
- VCardUtils.containsOnlyNonCrLfPrintableAscii(middleName) &&
- VCardUtils.containsOnlyNonCrLfPrintableAscii(prefix) &&
- VCardUtils.containsOnlyNonCrLfPrintableAscii(suffix)));
-
- final String formattedName;
- if (!TextUtils.isEmpty(displayName)) {
- formattedName = displayName;
- } else {
- formattedName = VCardUtils.constructNameFromElements(
- VCardConfig.getNameOrderType(mVCardType),
- familyName, middleName, givenName, prefix, suffix);
- }
- final boolean reallyAppendCharsetParameterToFN =
- shouldAppendCharsetParam(formattedName);
- final boolean reallyUseQuotedPrintableToFN =
- !mRefrainsQPToNameProperties &&
- !VCardUtils.containsOnlyNonCrLfPrintableAscii(formattedName);
-
- final String encodedFamily;
- final String encodedGiven;
- final String encodedMiddle;
- final String encodedPrefix;
- final String encodedSuffix;
- if (reallyUseQuotedPrintableToName) {
- encodedFamily = encodeQuotedPrintable(familyName);
- encodedGiven = encodeQuotedPrintable(givenName);
- encodedMiddle = encodeQuotedPrintable(middleName);
- encodedPrefix = encodeQuotedPrintable(prefix);
- encodedSuffix = encodeQuotedPrintable(suffix);
- } else {
- encodedFamily = escapeCharacters(familyName);
- encodedGiven = escapeCharacters(givenName);
- encodedMiddle = escapeCharacters(middleName);
- encodedPrefix = escapeCharacters(prefix);
- encodedSuffix = escapeCharacters(suffix);
- }
-
- final String encodedFormattedname =
- (reallyUseQuotedPrintableToFN ?
- encodeQuotedPrintable(formattedName) : escapeCharacters(formattedName));
-
- mBuilder.append(VCardConstants.PROPERTY_N);
- if (mIsDoCoMo) {
- if (reallyAppendCharsetParameterToName) {
- mBuilder.append(VCARD_PARAM_SEPARATOR);
- mBuilder.append(mVCardCharsetParameter);
- }
- if (reallyUseQuotedPrintableToName) {
- mBuilder.append(VCARD_PARAM_SEPARATOR);
- mBuilder.append(VCARD_PARAM_ENCODING_QP);
- }
- mBuilder.append(VCARD_DATA_SEPARATOR);
- // DoCoMo phones require that all the elements in the "family name" field.
- mBuilder.append(formattedName);
- mBuilder.append(VCARD_ITEM_SEPARATOR);
- mBuilder.append(VCARD_ITEM_SEPARATOR);
- mBuilder.append(VCARD_ITEM_SEPARATOR);
- mBuilder.append(VCARD_ITEM_SEPARATOR);
- } else {
- if (reallyAppendCharsetParameterToName) {
- mBuilder.append(VCARD_PARAM_SEPARATOR);
- mBuilder.append(mVCardCharsetParameter);
- }
- if (reallyUseQuotedPrintableToName) {
- mBuilder.append(VCARD_PARAM_SEPARATOR);
- mBuilder.append(VCARD_PARAM_ENCODING_QP);
- }
- mBuilder.append(VCARD_DATA_SEPARATOR);
- mBuilder.append(encodedFamily);
- mBuilder.append(VCARD_ITEM_SEPARATOR);
- mBuilder.append(encodedGiven);
- mBuilder.append(VCARD_ITEM_SEPARATOR);
- mBuilder.append(encodedMiddle);
- mBuilder.append(VCARD_ITEM_SEPARATOR);
- mBuilder.append(encodedPrefix);
- mBuilder.append(VCARD_ITEM_SEPARATOR);
- mBuilder.append(encodedSuffix);
- }
- mBuilder.append(VCARD_END_OF_LINE);
-
- // FN property
- mBuilder.append(VCardConstants.PROPERTY_FN);
- if (reallyAppendCharsetParameterToFN) {
- mBuilder.append(VCARD_PARAM_SEPARATOR);
- mBuilder.append(mVCardCharsetParameter);
- }
- if (reallyUseQuotedPrintableToFN) {
- mBuilder.append(VCARD_PARAM_SEPARATOR);
- mBuilder.append(VCARD_PARAM_ENCODING_QP);
- }
- mBuilder.append(VCARD_DATA_SEPARATOR);
- mBuilder.append(encodedFormattedname);
- mBuilder.append(VCARD_END_OF_LINE);
- } else if (!TextUtils.isEmpty(displayName)) {
- final boolean reallyUseQuotedPrintableToDisplayName =
- (!mRefrainsQPToNameProperties &&
- !VCardUtils.containsOnlyNonCrLfPrintableAscii(displayName));
- final String encodedDisplayName =
- reallyUseQuotedPrintableToDisplayName ?
- encodeQuotedPrintable(displayName) :
- escapeCharacters(displayName);
-
- mBuilder.append(VCardConstants.PROPERTY_N);
- if (shouldAppendCharsetParam(displayName)) {
- mBuilder.append(VCARD_PARAM_SEPARATOR);
- mBuilder.append(mVCardCharsetParameter);
- }
- if (reallyUseQuotedPrintableToDisplayName) {
- mBuilder.append(VCARD_PARAM_SEPARATOR);
- mBuilder.append(VCARD_PARAM_ENCODING_QP);
- }
- mBuilder.append(VCARD_DATA_SEPARATOR);
- mBuilder.append(encodedDisplayName);
- mBuilder.append(VCARD_ITEM_SEPARATOR);
- mBuilder.append(VCARD_ITEM_SEPARATOR);
- mBuilder.append(VCARD_ITEM_SEPARATOR);
- mBuilder.append(VCARD_ITEM_SEPARATOR);
- mBuilder.append(VCARD_END_OF_LINE);
- mBuilder.append(VCardConstants.PROPERTY_FN);
-
- // Note: "CHARSET" param is not allowed in vCard 3.0, but we may add it
- // when it would be useful for external importers, assuming no external
- // importer allows this vioration.
- if (shouldAppendCharsetParam(displayName)) {
- mBuilder.append(VCARD_PARAM_SEPARATOR);
- mBuilder.append(mVCardCharsetParameter);
- }
- mBuilder.append(VCARD_DATA_SEPARATOR);
- mBuilder.append(encodedDisplayName);
- mBuilder.append(VCARD_END_OF_LINE);
- } else if (mIsV30) {
- // vCard 3.0 specification requires these fields.
- appendLine(VCardConstants.PROPERTY_N, "");
- appendLine(VCardConstants.PROPERTY_FN, "");
- } else if (mIsDoCoMo) {
- appendLine(VCardConstants.PROPERTY_N, "");
- }
-
- appendPhoneticNameFields(contentValues);
- return this;
- }
-
- private void appendPhoneticNameFields(final ContentValues contentValues) {
- final String phoneticFamilyName;
- final String phoneticMiddleName;
- final String phoneticGivenName;
- {
- final String tmpPhoneticFamilyName =
- contentValues.getAsString(StructuredName.PHONETIC_FAMILY_NAME);
- final String tmpPhoneticMiddleName =
- contentValues.getAsString(StructuredName.PHONETIC_MIDDLE_NAME);
- final String tmpPhoneticGivenName =
- contentValues.getAsString(StructuredName.PHONETIC_GIVEN_NAME);
- if (mNeedsToConvertPhoneticString) {
- phoneticFamilyName = VCardUtils.toHalfWidthString(tmpPhoneticFamilyName);
- phoneticMiddleName = VCardUtils.toHalfWidthString(tmpPhoneticMiddleName);
- phoneticGivenName = VCardUtils.toHalfWidthString(tmpPhoneticGivenName);
- } else {
- phoneticFamilyName = tmpPhoneticFamilyName;
- phoneticMiddleName = tmpPhoneticMiddleName;
- phoneticGivenName = tmpPhoneticGivenName;
- }
- }
-
- if (TextUtils.isEmpty(phoneticFamilyName)
- && TextUtils.isEmpty(phoneticMiddleName)
- && TextUtils.isEmpty(phoneticGivenName)) {
- if (mIsDoCoMo) {
- mBuilder.append(VCardConstants.PROPERTY_SOUND);
- mBuilder.append(VCARD_PARAM_SEPARATOR);
- mBuilder.append(VCardConstants.PARAM_TYPE_X_IRMC_N);
- mBuilder.append(VCARD_DATA_SEPARATOR);
- mBuilder.append(VCARD_ITEM_SEPARATOR);
- mBuilder.append(VCARD_ITEM_SEPARATOR);
- mBuilder.append(VCARD_ITEM_SEPARATOR);
- mBuilder.append(VCARD_ITEM_SEPARATOR);
- mBuilder.append(VCARD_END_OF_LINE);
- }
- return;
- }
-
- // Try to emit the field(s) related to phonetic name.
- if (mIsV30) {
- final String sortString = VCardUtils
- .constructNameFromElements(mVCardType,
- phoneticFamilyName, phoneticMiddleName, phoneticGivenName);
- mBuilder.append(VCardConstants.PROPERTY_SORT_STRING);
- if (shouldAppendCharsetParam(sortString)) {
- mBuilder.append(VCARD_PARAM_SEPARATOR);
- mBuilder.append(mVCardCharsetParameter);
- }
- mBuilder.append(VCARD_DATA_SEPARATOR);
- mBuilder.append(escapeCharacters(sortString));
- mBuilder.append(VCARD_END_OF_LINE);
- } else if (mIsJapaneseMobilePhone) {
- // Note: There is no appropriate property for expressing
- // phonetic name in vCard 2.1, while there is in
- // vCard 3.0 (SORT-STRING).
- // We chose to use DoCoMo's way when the device is Japanese one
- // since it is supported by
- // a lot of Japanese mobile phones. This is "X-" property, so
- // any parser hopefully would not get confused with this.
- //
- // Also, DoCoMo's specification requires vCard composer to use just the first
- // column.
- // i.e.
- // o SOUND;X-IRMC-N:Miyakawa Daisuke;;;;
- // x SOUND;X-IRMC-N:Miyakawa;Daisuke;;;
- mBuilder.append(VCardConstants.PROPERTY_SOUND);
- mBuilder.append(VCARD_PARAM_SEPARATOR);
- mBuilder.append(VCardConstants.PARAM_TYPE_X_IRMC_N);
-
- boolean reallyUseQuotedPrintable =
- (!mRefrainsQPToNameProperties
- && !(VCardUtils.containsOnlyNonCrLfPrintableAscii(
- phoneticFamilyName)
- && VCardUtils.containsOnlyNonCrLfPrintableAscii(
- phoneticMiddleName)
- && VCardUtils.containsOnlyNonCrLfPrintableAscii(
- phoneticGivenName)));
-
- final String encodedPhoneticFamilyName;
- final String encodedPhoneticMiddleName;
- final String encodedPhoneticGivenName;
- if (reallyUseQuotedPrintable) {
- encodedPhoneticFamilyName = encodeQuotedPrintable(phoneticFamilyName);
- encodedPhoneticMiddleName = encodeQuotedPrintable(phoneticMiddleName);
- encodedPhoneticGivenName = encodeQuotedPrintable(phoneticGivenName);
- } else {
- encodedPhoneticFamilyName = escapeCharacters(phoneticFamilyName);
- encodedPhoneticMiddleName = escapeCharacters(phoneticMiddleName);
- encodedPhoneticGivenName = escapeCharacters(phoneticGivenName);
- }
-
- if (shouldAppendCharsetParam(encodedPhoneticFamilyName,
- encodedPhoneticMiddleName, encodedPhoneticGivenName)) {
- mBuilder.append(VCARD_PARAM_SEPARATOR);
- mBuilder.append(mVCardCharsetParameter);
- }
- mBuilder.append(VCARD_DATA_SEPARATOR);
- {
- boolean first = true;
- if (!TextUtils.isEmpty(encodedPhoneticFamilyName)) {
- mBuilder.append(encodedPhoneticFamilyName);
- first = false;
- }
- if (!TextUtils.isEmpty(encodedPhoneticMiddleName)) {
- if (first) {
- first = false;
- } else {
- mBuilder.append(' ');
- }
- mBuilder.append(encodedPhoneticMiddleName);
- }
- if (!TextUtils.isEmpty(encodedPhoneticGivenName)) {
- if (!first) {
- mBuilder.append(' ');
- }
- mBuilder.append(encodedPhoneticGivenName);
- }
- }
- mBuilder.append(VCARD_ITEM_SEPARATOR);
- mBuilder.append(VCARD_ITEM_SEPARATOR);
- mBuilder.append(VCARD_ITEM_SEPARATOR);
- mBuilder.append(VCARD_ITEM_SEPARATOR);
- mBuilder.append(VCARD_END_OF_LINE);
- }
-
- if (mUsesDefactProperty) {
- if (!TextUtils.isEmpty(phoneticGivenName)) {
- final boolean reallyUseQuotedPrintable =
- (mShouldUseQuotedPrintable &&
- !VCardUtils.containsOnlyNonCrLfPrintableAscii(phoneticGivenName));
- final String encodedPhoneticGivenName;
- if (reallyUseQuotedPrintable) {
- encodedPhoneticGivenName = encodeQuotedPrintable(phoneticGivenName);
- } else {
- encodedPhoneticGivenName = escapeCharacters(phoneticGivenName);
- }
- mBuilder.append(VCardConstants.PROPERTY_X_PHONETIC_FIRST_NAME);
- if (shouldAppendCharsetParam(phoneticGivenName)) {
- mBuilder.append(VCARD_PARAM_SEPARATOR);
- mBuilder.append(mVCardCharsetParameter);
- }
- if (reallyUseQuotedPrintable) {
- mBuilder.append(VCARD_PARAM_SEPARATOR);
- mBuilder.append(VCARD_PARAM_ENCODING_QP);
- }
- mBuilder.append(VCARD_DATA_SEPARATOR);
- mBuilder.append(encodedPhoneticGivenName);
- mBuilder.append(VCARD_END_OF_LINE);
- }
- if (!TextUtils.isEmpty(phoneticMiddleName)) {
- final boolean reallyUseQuotedPrintable =
- (mShouldUseQuotedPrintable &&
- !VCardUtils.containsOnlyNonCrLfPrintableAscii(phoneticMiddleName));
- final String encodedPhoneticMiddleName;
- if (reallyUseQuotedPrintable) {
- encodedPhoneticMiddleName = encodeQuotedPrintable(phoneticMiddleName);
- } else {
- encodedPhoneticMiddleName = escapeCharacters(phoneticMiddleName);
- }
- mBuilder.append(VCardConstants.PROPERTY_X_PHONETIC_MIDDLE_NAME);
- if (shouldAppendCharsetParam(phoneticMiddleName)) {
- mBuilder.append(VCARD_PARAM_SEPARATOR);
- mBuilder.append(mVCardCharsetParameter);
- }
- if (reallyUseQuotedPrintable) {
- mBuilder.append(VCARD_PARAM_SEPARATOR);
- mBuilder.append(VCARD_PARAM_ENCODING_QP);
- }
- mBuilder.append(VCARD_DATA_SEPARATOR);
- mBuilder.append(encodedPhoneticMiddleName);
- mBuilder.append(VCARD_END_OF_LINE);
- }
- if (!TextUtils.isEmpty(phoneticFamilyName)) {
- final boolean reallyUseQuotedPrintable =
- (mShouldUseQuotedPrintable &&
- !VCardUtils.containsOnlyNonCrLfPrintableAscii(phoneticFamilyName));
- final String encodedPhoneticFamilyName;
- if (reallyUseQuotedPrintable) {
- encodedPhoneticFamilyName = encodeQuotedPrintable(phoneticFamilyName);
- } else {
- encodedPhoneticFamilyName = escapeCharacters(phoneticFamilyName);
- }
- mBuilder.append(VCardConstants.PROPERTY_X_PHONETIC_LAST_NAME);
- if (shouldAppendCharsetParam(phoneticFamilyName)) {
- mBuilder.append(VCARD_PARAM_SEPARATOR);
- mBuilder.append(mVCardCharsetParameter);
- }
- if (reallyUseQuotedPrintable) {
- mBuilder.append(VCARD_PARAM_SEPARATOR);
- mBuilder.append(VCARD_PARAM_ENCODING_QP);
- }
- mBuilder.append(VCARD_DATA_SEPARATOR);
- mBuilder.append(encodedPhoneticFamilyName);
- mBuilder.append(VCARD_END_OF_LINE);
- }
- }
- }
-
- public VCardBuilder appendNickNames(final List<ContentValues> contentValuesList) {
- final boolean useAndroidProperty;
- if (mIsV30) {
- useAndroidProperty = false;
- } else if (mUsesAndroidProperty) {
- useAndroidProperty = true;
- } else {
- // There's no way to add this field.
- return this;
- }
- if (contentValuesList != null) {
- for (ContentValues contentValues : contentValuesList) {
- final String nickname = contentValues.getAsString(Nickname.NAME);
- if (TextUtils.isEmpty(nickname)) {
- continue;
- }
- if (useAndroidProperty) {
- appendAndroidSpecificProperty(Nickname.CONTENT_ITEM_TYPE, contentValues);
- } else {
- appendLineWithCharsetAndQPDetection(VCardConstants.PROPERTY_NICKNAME, nickname);
- }
- }
- }
- return this;
- }
-
- public VCardBuilder appendPhones(final List<ContentValues> contentValuesList) {
- boolean phoneLineExists = false;
- if (contentValuesList != null) {
- Set<String> phoneSet = new HashSet<String>();
- for (ContentValues contentValues : contentValuesList) {
- final Integer typeAsObject = contentValues.getAsInteger(Phone.TYPE);
- final String label = contentValues.getAsString(Phone.LABEL);
- final Integer isPrimaryAsInteger = contentValues.getAsInteger(Phone.IS_PRIMARY);
- final boolean isPrimary = (isPrimaryAsInteger != null ?
- (isPrimaryAsInteger > 0) : false);
- String phoneNumber = contentValues.getAsString(Phone.NUMBER);
- if (phoneNumber != null) {
- phoneNumber = phoneNumber.trim();
- }
- if (TextUtils.isEmpty(phoneNumber)) {
- continue;
- }
-
- // PAGER number needs unformatted "phone number".
- final int type = (typeAsObject != null ? typeAsObject : DEFAULT_PHONE_TYPE);
- if (type == Phone.TYPE_PAGER ||
- VCardConfig.refrainPhoneNumberFormatting(mVCardType)) {
- phoneLineExists = true;
- if (!phoneSet.contains(phoneNumber)) {
- phoneSet.add(phoneNumber);
- appendTelLine(type, label, phoneNumber, isPrimary);
- }
- } else {
- final List<String> phoneNumberList = splitAndTrimPhoneNumbers(phoneNumber);
- if (phoneNumberList.isEmpty()) {
- continue;
- }
- phoneLineExists = true;
- for (String actualPhoneNumber : phoneNumberList) {
- if (!phoneSet.contains(actualPhoneNumber)) {
- final int format = VCardUtils.getPhoneNumberFormat(mVCardType);
- final String formattedPhoneNumber =
- PhoneNumberUtils.formatNumber(actualPhoneNumber, format);
- phoneSet.add(actualPhoneNumber);
- appendTelLine(type, label, formattedPhoneNumber, isPrimary);
- }
- } // for (String actualPhoneNumber : phoneNumberList) {
- }
- }
- }
-
- if (!phoneLineExists && mIsDoCoMo) {
- appendTelLine(Phone.TYPE_HOME, "", "", false);
- }
-
- return this;
- }
-
- /**
- * <p>
- * Splits a given string expressing phone numbers into several strings, and remove
- * unnecessary characters inside them. The size of a returned list becomes 1 when
- * no split is needed.
- * </p>
- * <p>
- * The given number "may" have several phone numbers when the contact entry is corrupted
- * because of its original source.
- * e.g. "111-222-3333 (Miami)\n444-555-6666 (Broward; 305-653-6796 (Miami)"
- * </p>
- * <p>
- * This kind of "phone numbers" will not be created with Android vCard implementation,
- * but we may encounter them if the source of the input data has already corrupted
- * implementation.
- * </p>
- * <p>
- * To handle this case, this method first splits its input into multiple parts
- * (e.g. "111-222-3333 (Miami)", "444-555-6666 (Broward", and 305653-6796 (Miami)") and
- * removes unnecessary strings like "(Miami)".
- * </p>
- * <p>
- * Do not call this method when trimming is inappropriate for its receivers.
- * </p>
- */
- private List<String> splitAndTrimPhoneNumbers(final String phoneNumber) {
- final List<String> phoneList = new ArrayList<String>();
-
- StringBuilder builder = new StringBuilder();
- final int length = phoneNumber.length();
- for (int i = 0; i < length; i++) {
- final char ch = phoneNumber.charAt(i);
- if (Character.isDigit(ch) || ch == '+') {
- builder.append(ch);
- } else if ((ch == ';' || ch == '\n') && builder.length() > 0) {
- phoneList.add(builder.toString());
- builder = new StringBuilder();
- }
- }
- if (builder.length() > 0) {
- phoneList.add(builder.toString());
- }
-
- return phoneList;
- }
-
- public VCardBuilder appendEmails(final List<ContentValues> contentValuesList) {
- boolean emailAddressExists = false;
- if (contentValuesList != null) {
- final Set<String> addressSet = new HashSet<String>();
- for (ContentValues contentValues : contentValuesList) {
- String emailAddress = contentValues.getAsString(Email.DATA);
- if (emailAddress != null) {
- emailAddress = emailAddress.trim();
- }
- if (TextUtils.isEmpty(emailAddress)) {
- continue;
- }
- Integer typeAsObject = contentValues.getAsInteger(Email.TYPE);
- final int type = (typeAsObject != null ?
- typeAsObject : DEFAULT_EMAIL_TYPE);
- final String label = contentValues.getAsString(Email.LABEL);
- Integer isPrimaryAsInteger = contentValues.getAsInteger(Email.IS_PRIMARY);
- final boolean isPrimary = (isPrimaryAsInteger != null ?
- (isPrimaryAsInteger > 0) : false);
- emailAddressExists = true;
- if (!addressSet.contains(emailAddress)) {
- addressSet.add(emailAddress);
- appendEmailLine(type, label, emailAddress, isPrimary);
- }
- }
- }
-
- if (!emailAddressExists && mIsDoCoMo) {
- appendEmailLine(Email.TYPE_HOME, "", "", false);
- }
-
- return this;
- }
-
- public VCardBuilder appendPostals(final List<ContentValues> contentValuesList) {
- if (contentValuesList == null || contentValuesList.isEmpty()) {
- if (mIsDoCoMo) {
- mBuilder.append(VCardConstants.PROPERTY_ADR);
- mBuilder.append(VCARD_PARAM_SEPARATOR);
- mBuilder.append(VCardConstants.PARAM_TYPE_HOME);
- mBuilder.append(VCARD_DATA_SEPARATOR);
- mBuilder.append(VCARD_END_OF_LINE);
- }
- } else {
- if (mIsDoCoMo) {
- appendPostalsForDoCoMo(contentValuesList);
- } else {
- appendPostalsForGeneric(contentValuesList);
- }
- }
-
- return this;
- }
-
- private static final Map<Integer, Integer> sPostalTypePriorityMap;
-
- static {
- sPostalTypePriorityMap = new HashMap<Integer, Integer>();
- sPostalTypePriorityMap.put(StructuredPostal.TYPE_HOME, 0);
- sPostalTypePriorityMap.put(StructuredPostal.TYPE_WORK, 1);
- sPostalTypePriorityMap.put(StructuredPostal.TYPE_OTHER, 2);
- sPostalTypePriorityMap.put(StructuredPostal.TYPE_CUSTOM, 3);
- }
-
- /**
- * Tries to append just one line. If there's no appropriate address
- * information, append an empty line.
- */
- private void appendPostalsForDoCoMo(final List<ContentValues> contentValuesList) {
- int currentPriority = Integer.MAX_VALUE;
- int currentType = Integer.MAX_VALUE;
- ContentValues currentContentValues = null;
- for (final ContentValues contentValues : contentValuesList) {
- if (contentValues == null) {
- continue;
- }
- final Integer typeAsInteger = contentValues.getAsInteger(StructuredPostal.TYPE);
- final Integer priorityAsInteger = sPostalTypePriorityMap.get(typeAsInteger);
- final int priority =
- (priorityAsInteger != null ? priorityAsInteger : Integer.MAX_VALUE);
- if (priority < currentPriority) {
- currentPriority = priority;
- currentType = typeAsInteger;
- currentContentValues = contentValues;
- if (priority == 0) {
- break;
- }
- }
- }
-
- if (currentContentValues == null) {
- Log.w(LOG_TAG, "Should not come here. Must have at least one postal data.");
- return;
- }
-
- final String label = currentContentValues.getAsString(StructuredPostal.LABEL);
- appendPostalLine(currentType, label, currentContentValues, false, true);
- }
-
- private void appendPostalsForGeneric(final List<ContentValues> contentValuesList) {
- for (final ContentValues contentValues : contentValuesList) {
- if (contentValues == null) {
- continue;
- }
- final Integer typeAsInteger = contentValues.getAsInteger(StructuredPostal.TYPE);
- final int type = (typeAsInteger != null ?
- typeAsInteger : DEFAULT_POSTAL_TYPE);
- final String label = contentValues.getAsString(StructuredPostal.LABEL);
- final Integer isPrimaryAsInteger =
- contentValues.getAsInteger(StructuredPostal.IS_PRIMARY);
- final boolean isPrimary = (isPrimaryAsInteger != null ?
- (isPrimaryAsInteger > 0) : false);
- appendPostalLine(type, label, contentValues, isPrimary, false);
- }
- }
-
- private static class PostalStruct {
- final boolean reallyUseQuotedPrintable;
- final boolean appendCharset;
- final String addressData;
- public PostalStruct(final boolean reallyUseQuotedPrintable,
- final boolean appendCharset, final String addressData) {
- this.reallyUseQuotedPrintable = reallyUseQuotedPrintable;
- this.appendCharset = appendCharset;
- this.addressData = addressData;
- }
- }
-
- /**
- * @return null when there's no information available to construct the data.
- */
- private PostalStruct tryConstructPostalStruct(ContentValues contentValues) {
- // adr-value = 0*6(text-value ";") text-value
- // ; PO Box, Extended Address, Street, Locality, Region, Postal
- // ; Code, Country Name
- final String rawPoBox = contentValues.getAsString(StructuredPostal.POBOX);
- final String rawNeighborhood = contentValues.getAsString(StructuredPostal.NEIGHBORHOOD);
- final String rawStreet = contentValues.getAsString(StructuredPostal.STREET);
- final String rawLocality = contentValues.getAsString(StructuredPostal.CITY);
- final String rawRegion = contentValues.getAsString(StructuredPostal.REGION);
- final String rawPostalCode = contentValues.getAsString(StructuredPostal.POSTCODE);
- final String rawCountry = contentValues.getAsString(StructuredPostal.COUNTRY);
- final String[] rawAddressArray = new String[]{
- rawPoBox, rawNeighborhood, rawStreet, rawLocality,
- rawRegion, rawPostalCode, rawCountry};
- if (!VCardUtils.areAllEmpty(rawAddressArray)) {
- final boolean reallyUseQuotedPrintable =
- (mShouldUseQuotedPrintable &&
- !VCardUtils.containsOnlyNonCrLfPrintableAscii(rawAddressArray));
- final boolean appendCharset =
- !VCardUtils.containsOnlyPrintableAscii(rawAddressArray);
- final String encodedPoBox;
- final String encodedStreet;
- final String encodedLocality;
- final String encodedRegion;
- final String encodedPostalCode;
- final String encodedCountry;
- final String encodedNeighborhood;
-
- final String rawLocality2;
- // This looks inefficient since we encode rawLocality and rawNeighborhood twice,
- // but this is intentional.
- //
- // QP encoding may add line feeds when needed and the result of
- // - encodeQuotedPrintable(rawLocality + " " + rawNeighborhood)
- // may be different from
- // - encodedLocality + " " + encodedNeighborhood.
- //
- // We use safer way.
- if (TextUtils.isEmpty(rawLocality)) {
- if (TextUtils.isEmpty(rawNeighborhood)) {
- rawLocality2 = "";
- } else {
- rawLocality2 = rawNeighborhood;
- }
- } else {
- if (TextUtils.isEmpty(rawNeighborhood)) {
- rawLocality2 = rawLocality;
- } else {
- rawLocality2 = rawLocality + " " + rawNeighborhood;
- }
- }
- if (reallyUseQuotedPrintable) {
- encodedPoBox = encodeQuotedPrintable(rawPoBox);
- encodedStreet = encodeQuotedPrintable(rawStreet);
- encodedLocality = encodeQuotedPrintable(rawLocality2);
- encodedRegion = encodeQuotedPrintable(rawRegion);
- encodedPostalCode = encodeQuotedPrintable(rawPostalCode);
- encodedCountry = encodeQuotedPrintable(rawCountry);
- } else {
- encodedPoBox = escapeCharacters(rawPoBox);
- encodedStreet = escapeCharacters(rawStreet);
- encodedLocality = escapeCharacters(rawLocality2);
- encodedRegion = escapeCharacters(rawRegion);
- encodedPostalCode = escapeCharacters(rawPostalCode);
- encodedCountry = escapeCharacters(rawCountry);
- encodedNeighborhood = escapeCharacters(rawNeighborhood);
- }
- final StringBuffer addressBuffer = new StringBuffer();
- addressBuffer.append(encodedPoBox);
- addressBuffer.append(VCARD_ITEM_SEPARATOR);
- addressBuffer.append(VCARD_ITEM_SEPARATOR);
- addressBuffer.append(encodedStreet);
- addressBuffer.append(VCARD_ITEM_SEPARATOR);
- addressBuffer.append(encodedLocality);
- addressBuffer.append(VCARD_ITEM_SEPARATOR);
- addressBuffer.append(encodedRegion);
- addressBuffer.append(VCARD_ITEM_SEPARATOR);
- addressBuffer.append(encodedPostalCode);
- addressBuffer.append(VCARD_ITEM_SEPARATOR);
- addressBuffer.append(encodedCountry);
- return new PostalStruct(
- reallyUseQuotedPrintable, appendCharset, addressBuffer.toString());
- } else { // VCardUtils.areAllEmpty(rawAddressArray) == true
- // Try to use FORMATTED_ADDRESS instead.
- final String rawFormattedAddress =
- contentValues.getAsString(StructuredPostal.FORMATTED_ADDRESS);
- if (TextUtils.isEmpty(rawFormattedAddress)) {
- return null;
- }
- final boolean reallyUseQuotedPrintable =
- (mShouldUseQuotedPrintable &&
- !VCardUtils.containsOnlyNonCrLfPrintableAscii(rawFormattedAddress));
- final boolean appendCharset =
- !VCardUtils.containsOnlyPrintableAscii(rawFormattedAddress);
- final String encodedFormattedAddress;
- if (reallyUseQuotedPrintable) {
- encodedFormattedAddress = encodeQuotedPrintable(rawFormattedAddress);
- } else {
- encodedFormattedAddress = escapeCharacters(rawFormattedAddress);
- }
-
- // We use the second value ("Extended Address") just because Japanese mobile phones
- // do so. If the other importer expects the value be in the other field, some flag may
- // be needed.
- final StringBuffer addressBuffer = new StringBuffer();
- addressBuffer.append(VCARD_ITEM_SEPARATOR);
- addressBuffer.append(encodedFormattedAddress);
- addressBuffer.append(VCARD_ITEM_SEPARATOR);
- addressBuffer.append(VCARD_ITEM_SEPARATOR);
- addressBuffer.append(VCARD_ITEM_SEPARATOR);
- addressBuffer.append(VCARD_ITEM_SEPARATOR);
- addressBuffer.append(VCARD_ITEM_SEPARATOR);
- return new PostalStruct(
- reallyUseQuotedPrintable, appendCharset, addressBuffer.toString());
- }
- }
-
- public VCardBuilder appendIms(final List<ContentValues> contentValuesList) {
- if (contentValuesList != null) {
- for (ContentValues contentValues : contentValuesList) {
- final Integer protocolAsObject = contentValues.getAsInteger(Im.PROTOCOL);
- if (protocolAsObject == null) {
- continue;
- }
- final String propertyName = VCardUtils.getPropertyNameForIm(protocolAsObject);
- if (propertyName == null) {
- continue;
- }
- String data = contentValues.getAsString(Im.DATA);
- if (data != null) {
- data = data.trim();
- }
- if (TextUtils.isEmpty(data)) {
- continue;
- }
- final String typeAsString;
- {
- final Integer typeAsInteger = contentValues.getAsInteger(Im.TYPE);
- switch (typeAsInteger != null ? typeAsInteger : Im.TYPE_OTHER) {
- case Im.TYPE_HOME: {
- typeAsString = VCardConstants.PARAM_TYPE_HOME;
- break;
- }
- case Im.TYPE_WORK: {
- typeAsString = VCardConstants.PARAM_TYPE_WORK;
- break;
- }
- case Im.TYPE_CUSTOM: {
- final String label = contentValues.getAsString(Im.LABEL);
- typeAsString = (label != null ? "X-" + label : null);
- break;
- }
- case Im.TYPE_OTHER: // Ignore
- default: {
- typeAsString = null;
- break;
- }
- }
- }
-
- final List<String> parameterList = new ArrayList<String>();
- if (!TextUtils.isEmpty(typeAsString)) {
- parameterList.add(typeAsString);
- }
- final Integer isPrimaryAsInteger = contentValues.getAsInteger(Im.IS_PRIMARY);
- final boolean isPrimary = (isPrimaryAsInteger != null ?
- (isPrimaryAsInteger > 0) : false);
- if (isPrimary) {
- parameterList.add(VCardConstants.PARAM_TYPE_PREF);
- }
-
- appendLineWithCharsetAndQPDetection(propertyName, parameterList, data);
- }
- }
- return this;
- }
-
- public VCardBuilder appendWebsites(final List<ContentValues> contentValuesList) {
- if (contentValuesList != null) {
- for (ContentValues contentValues : contentValuesList) {
- String website = contentValues.getAsString(Website.URL);
- if (website != null) {
- website = website.trim();
- }
-
- // Note: vCard 3.0 does not allow any parameter addition toward "URL"
- // property, while there's no document in vCard 2.1.
- if (!TextUtils.isEmpty(website)) {
- appendLineWithCharsetAndQPDetection(VCardConstants.PROPERTY_URL, website);
- }
- }
- }
- return this;
- }
-
- public VCardBuilder appendOrganizations(final List<ContentValues> contentValuesList) {
- if (contentValuesList != null) {
- for (ContentValues contentValues : contentValuesList) {
- String company = contentValues.getAsString(Organization.COMPANY);
- if (company != null) {
- company = company.trim();
- }
- String department = contentValues.getAsString(Organization.DEPARTMENT);
- if (department != null) {
- department = department.trim();
- }
- String title = contentValues.getAsString(Organization.TITLE);
- if (title != null) {
- title = title.trim();
- }
-
- StringBuilder orgBuilder = new StringBuilder();
- if (!TextUtils.isEmpty(company)) {
- orgBuilder.append(company);
- }
- if (!TextUtils.isEmpty(department)) {
- if (orgBuilder.length() > 0) {
- orgBuilder.append(';');
- }
- orgBuilder.append(department);
- }
- final String orgline = orgBuilder.toString();
- appendLine(VCardConstants.PROPERTY_ORG, orgline,
- !VCardUtils.containsOnlyPrintableAscii(orgline),
- (mShouldUseQuotedPrintable &&
- !VCardUtils.containsOnlyNonCrLfPrintableAscii(orgline)));
-
- if (!TextUtils.isEmpty(title)) {
- appendLine(VCardConstants.PROPERTY_TITLE, title,
- !VCardUtils.containsOnlyPrintableAscii(title),
- (mShouldUseQuotedPrintable &&
- !VCardUtils.containsOnlyNonCrLfPrintableAscii(title)));
- }
- }
- }
- return this;
- }
-
- public VCardBuilder appendPhotos(final List<ContentValues> contentValuesList) {
- if (contentValuesList != null) {
- for (ContentValues contentValues : contentValuesList) {
- if (contentValues == null) {
- continue;
- }
- byte[] data = contentValues.getAsByteArray(Photo.PHOTO);
- if (data == null) {
- continue;
- }
- final String photoType = VCardUtils.guessImageType(data);
- if (photoType == null) {
- Log.d(LOG_TAG, "Unknown photo type. Ignored.");
- continue;
- }
- final String photoString = new String(Base64.encodeBase64(data));
- if (!TextUtils.isEmpty(photoString)) {
- appendPhotoLine(photoString, photoType);
- }
- }
- }
- return this;
- }
-
- public VCardBuilder appendNotes(final List<ContentValues> contentValuesList) {
- if (contentValuesList != null) {
- if (mOnlyOneNoteFieldIsAvailable) {
- final StringBuilder noteBuilder = new StringBuilder();
- boolean first = true;
- for (final ContentValues contentValues : contentValuesList) {
- String note = contentValues.getAsString(Note.NOTE);
- if (note == null) {
- note = "";
- }
- if (note.length() > 0) {
- if (first) {
- first = false;
- } else {
- noteBuilder.append('\n');
- }
- noteBuilder.append(note);
- }
- }
- final String noteStr = noteBuilder.toString();
- // This means we scan noteStr completely twice, which is redundant.
- // But for now, we assume this is not so time-consuming..
- final boolean shouldAppendCharsetInfo =
- !VCardUtils.containsOnlyPrintableAscii(noteStr);
- final boolean reallyUseQuotedPrintable =
- (mShouldUseQuotedPrintable &&
- !VCardUtils.containsOnlyNonCrLfPrintableAscii(noteStr));
- appendLine(VCardConstants.PROPERTY_NOTE, noteStr,
- shouldAppendCharsetInfo, reallyUseQuotedPrintable);
- } else {
- for (ContentValues contentValues : contentValuesList) {
- final String noteStr = contentValues.getAsString(Note.NOTE);
- if (!TextUtils.isEmpty(noteStr)) {
- final boolean shouldAppendCharsetInfo =
- !VCardUtils.containsOnlyPrintableAscii(noteStr);
- final boolean reallyUseQuotedPrintable =
- (mShouldUseQuotedPrintable &&
- !VCardUtils.containsOnlyNonCrLfPrintableAscii(noteStr));
- appendLine(VCardConstants.PROPERTY_NOTE, noteStr,
- shouldAppendCharsetInfo, reallyUseQuotedPrintable);
- }
- }
- }
- }
- return this;
- }
-
- public VCardBuilder appendEvents(final List<ContentValues> contentValuesList) {
- if (contentValuesList != null) {
- String primaryBirthday = null;
- String secondaryBirthday = null;
- for (final ContentValues contentValues : contentValuesList) {
- if (contentValues == null) {
- continue;
- }
- final Integer eventTypeAsInteger = contentValues.getAsInteger(Event.TYPE);
- final int eventType;
- if (eventTypeAsInteger != null) {
- eventType = eventTypeAsInteger;
- } else {
- eventType = Event.TYPE_OTHER;
- }
- if (eventType == Event.TYPE_BIRTHDAY) {
- final String birthdayCandidate = contentValues.getAsString(Event.START_DATE);
- if (birthdayCandidate == null) {
- continue;
- }
- final Integer isSuperPrimaryAsInteger =
- contentValues.getAsInteger(Event.IS_SUPER_PRIMARY);
- final boolean isSuperPrimary = (isSuperPrimaryAsInteger != null ?
- (isSuperPrimaryAsInteger > 0) : false);
- if (isSuperPrimary) {
- // "super primary" birthday should the prefered one.
- primaryBirthday = birthdayCandidate;
- break;
- }
- final Integer isPrimaryAsInteger =
- contentValues.getAsInteger(Event.IS_PRIMARY);
- final boolean isPrimary = (isPrimaryAsInteger != null ?
- (isPrimaryAsInteger > 0) : false);
- if (isPrimary) {
- // We don't break here since "super primary" birthday may exist later.
- primaryBirthday = birthdayCandidate;
- } else if (secondaryBirthday == null) {
- // First entry is set to the "secondary" candidate.
- secondaryBirthday = birthdayCandidate;
- }
- } else if (mUsesAndroidProperty) {
- // Event types other than Birthday is not supported by vCard.
- appendAndroidSpecificProperty(Event.CONTENT_ITEM_TYPE, contentValues);
- }
- }
- if (primaryBirthday != null) {
- appendLineWithCharsetAndQPDetection(VCardConstants.PROPERTY_BDAY,
- primaryBirthday.trim());
- } else if (secondaryBirthday != null){
- appendLineWithCharsetAndQPDetection(VCardConstants.PROPERTY_BDAY,
- secondaryBirthday.trim());
- }
- }
- return this;
- }
-
- public VCardBuilder appendRelation(final List<ContentValues> contentValuesList) {
- if (mUsesAndroidProperty && contentValuesList != null) {
- for (final ContentValues contentValues : contentValuesList) {
- if (contentValues == null) {
- continue;
- }
- appendAndroidSpecificProperty(Relation.CONTENT_ITEM_TYPE, contentValues);
- }
- }
- return this;
- }
-
- public void appendPostalLine(final int type, final String label,
- final ContentValues contentValues,
- final boolean isPrimary, final boolean emitLineEveryTime) {
- final boolean reallyUseQuotedPrintable;
- final boolean appendCharset;
- final String addressValue;
- {
- PostalStruct postalStruct = tryConstructPostalStruct(contentValues);
- if (postalStruct == null) {
- if (emitLineEveryTime) {
- reallyUseQuotedPrintable = false;
- appendCharset = false;
- addressValue = "";
- } else {
- return;
- }
- } else {
- reallyUseQuotedPrintable = postalStruct.reallyUseQuotedPrintable;
- appendCharset = postalStruct.appendCharset;
- addressValue = postalStruct.addressData;
- }
- }
-
- List<String> parameterList = new ArrayList<String>();
- if (isPrimary) {
- parameterList.add(VCardConstants.PARAM_TYPE_PREF);
- }
- switch (type) {
- case StructuredPostal.TYPE_HOME: {
- parameterList.add(VCardConstants.PARAM_TYPE_HOME);
- break;
- }
- case StructuredPostal.TYPE_WORK: {
- parameterList.add(VCardConstants.PARAM_TYPE_WORK);
- break;
- }
- case StructuredPostal.TYPE_CUSTOM: {
- if (!TextUtils.isEmpty(label)
- && VCardUtils.containsOnlyAlphaDigitHyphen(label)) {
- // We're not sure whether the label is valid in the spec
- // ("IANA-token" in the vCard 3.0 is unclear...)
- // Just for safety, we add "X-" at the beggining of each label.
- // Also checks the label obeys with vCard 3.0 spec.
- parameterList.add("X-" + label);
- }
- break;
- }
- case StructuredPostal.TYPE_OTHER: {
- break;
- }
- default: {
- Log.e(LOG_TAG, "Unknown StructuredPostal type: " + type);
- break;
- }
- }
-
- mBuilder.append(VCardConstants.PROPERTY_ADR);
- if (!parameterList.isEmpty()) {
- mBuilder.append(VCARD_PARAM_SEPARATOR);
- appendTypeParameters(parameterList);
- }
- if (appendCharset) {
- // Strictly, vCard 3.0 does not allow exporters to emit charset information,
- // but we will add it since the information should be useful for importers,
- //
- // Assume no parser does not emit error with this parameter in vCard 3.0.
- mBuilder.append(VCARD_PARAM_SEPARATOR);
- mBuilder.append(mVCardCharsetParameter);
- }
- if (reallyUseQuotedPrintable) {
- mBuilder.append(VCARD_PARAM_SEPARATOR);
- mBuilder.append(VCARD_PARAM_ENCODING_QP);
- }
- mBuilder.append(VCARD_DATA_SEPARATOR);
- mBuilder.append(addressValue);
- mBuilder.append(VCARD_END_OF_LINE);
- }
-
- public void appendEmailLine(final int type, final String label,
- final String rawValue, final boolean isPrimary) {
- final String typeAsString;
- switch (type) {
- case Email.TYPE_CUSTOM: {
- if (VCardUtils.isMobilePhoneLabel(label)) {
- typeAsString = VCardConstants.PARAM_TYPE_CELL;
- } else if (!TextUtils.isEmpty(label)
- && VCardUtils.containsOnlyAlphaDigitHyphen(label)) {
- typeAsString = "X-" + label;
- } else {
- typeAsString = null;
- }
- break;
- }
- case Email.TYPE_HOME: {
- typeAsString = VCardConstants.PARAM_TYPE_HOME;
- break;
- }
- case Email.TYPE_WORK: {
- typeAsString = VCardConstants.PARAM_TYPE_WORK;
- break;
- }
- case Email.TYPE_OTHER: {
- typeAsString = null;
- break;
- }
- case Email.TYPE_MOBILE: {
- typeAsString = VCardConstants.PARAM_TYPE_CELL;
- break;
- }
- default: {
- Log.e(LOG_TAG, "Unknown Email type: " + type);
- typeAsString = null;
- break;
- }
- }
-
- final List<String> parameterList = new ArrayList<String>();
- if (isPrimary) {
- parameterList.add(VCardConstants.PARAM_TYPE_PREF);
- }
- if (!TextUtils.isEmpty(typeAsString)) {
- parameterList.add(typeAsString);
- }
-
- appendLineWithCharsetAndQPDetection(VCardConstants.PROPERTY_EMAIL, parameterList,
- rawValue);
- }
-
- public void appendTelLine(final Integer typeAsInteger, final String label,
- final String encodedValue, boolean isPrimary) {
- mBuilder.append(VCardConstants.PROPERTY_TEL);
- mBuilder.append(VCARD_PARAM_SEPARATOR);
-
- final int type;
- if (typeAsInteger == null) {
- type = Phone.TYPE_OTHER;
- } else {
- type = typeAsInteger;
- }
-
- ArrayList<String> parameterList = new ArrayList<String>();
- switch (type) {
- case Phone.TYPE_HOME: {
- parameterList.addAll(
- Arrays.asList(VCardConstants.PARAM_TYPE_HOME));
- break;
- }
- case Phone.TYPE_WORK: {
- parameterList.addAll(
- Arrays.asList(VCardConstants.PARAM_TYPE_WORK));
- break;
- }
- case Phone.TYPE_FAX_HOME: {
- parameterList.addAll(
- Arrays.asList(VCardConstants.PARAM_TYPE_HOME, VCardConstants.PARAM_TYPE_FAX));
- break;
- }
- case Phone.TYPE_FAX_WORK: {
- parameterList.addAll(
- Arrays.asList(VCardConstants.PARAM_TYPE_WORK, VCardConstants.PARAM_TYPE_FAX));
- break;
- }
- case Phone.TYPE_MOBILE: {
- parameterList.add(VCardConstants.PARAM_TYPE_CELL);
- break;
- }
- case Phone.TYPE_PAGER: {
- if (mIsDoCoMo) {
- // Not sure about the reason, but previous implementation had
- // used "VOICE" instead of "PAGER"
- parameterList.add(VCardConstants.PARAM_TYPE_VOICE);
- } else {
- parameterList.add(VCardConstants.PARAM_TYPE_PAGER);
- }
- break;
- }
- case Phone.TYPE_OTHER: {
- parameterList.add(VCardConstants.PARAM_TYPE_VOICE);
- break;
- }
- case Phone.TYPE_CAR: {
- parameterList.add(VCardConstants.PARAM_TYPE_CAR);
- break;
- }
- case Phone.TYPE_COMPANY_MAIN: {
- // There's no relevant field in vCard (at least 2.1).
- parameterList.add(VCardConstants.PARAM_TYPE_WORK);
- isPrimary = true;
- break;
- }
- case Phone.TYPE_ISDN: {
- parameterList.add(VCardConstants.PARAM_TYPE_ISDN);
- break;
- }
- case Phone.TYPE_MAIN: {
- isPrimary = true;
- break;
- }
- case Phone.TYPE_OTHER_FAX: {
- parameterList.add(VCardConstants.PARAM_TYPE_FAX);
- break;
- }
- case Phone.TYPE_TELEX: {
- parameterList.add(VCardConstants.PARAM_TYPE_TLX);
- break;
- }
- case Phone.TYPE_WORK_MOBILE: {
- parameterList.addAll(
- Arrays.asList(VCardConstants.PARAM_TYPE_WORK, VCardConstants.PARAM_TYPE_CELL));
- break;
- }
- case Phone.TYPE_WORK_PAGER: {
- parameterList.add(VCardConstants.PARAM_TYPE_WORK);
- // See above.
- if (mIsDoCoMo) {
- parameterList.add(VCardConstants.PARAM_TYPE_VOICE);
- } else {
- parameterList.add(VCardConstants.PARAM_TYPE_PAGER);
- }
- break;
- }
- case Phone.TYPE_MMS: {
- parameterList.add(VCardConstants.PARAM_TYPE_MSG);
- break;
- }
- case Phone.TYPE_CUSTOM: {
- if (TextUtils.isEmpty(label)) {
- // Just ignore the custom type.
- parameterList.add(VCardConstants.PARAM_TYPE_VOICE);
- } else if (VCardUtils.isMobilePhoneLabel(label)) {
- parameterList.add(VCardConstants.PARAM_TYPE_CELL);
- } else {
- final String upperLabel = label.toUpperCase();
- if (VCardUtils.isValidInV21ButUnknownToContactsPhoteType(upperLabel)) {
- parameterList.add(upperLabel);
- } else if (VCardUtils.containsOnlyAlphaDigitHyphen(label)) {
- // Note: Strictly, vCard 2.1 does not allow "X-" parameter without
- // "TYPE=" string.
- parameterList.add("X-" + label);
- }
- }
- break;
- }
- case Phone.TYPE_RADIO:
- case Phone.TYPE_TTY_TDD:
- default: {
- break;
- }
- }
-
- if (isPrimary) {
- parameterList.add(VCardConstants.PARAM_TYPE_PREF);
- }
-
- if (parameterList.isEmpty()) {
- appendUncommonPhoneType(mBuilder, type);
- } else {
- appendTypeParameters(parameterList);
- }
-
- mBuilder.append(VCARD_DATA_SEPARATOR);
- mBuilder.append(encodedValue);
- mBuilder.append(VCARD_END_OF_LINE);
- }
-
- /**
- * Appends phone type string which may not be available in some devices.
- */
- private void appendUncommonPhoneType(final StringBuilder builder, final Integer type) {
- if (mIsDoCoMo) {
- // The previous implementation for DoCoMo had been conservative
- // about miscellaneous types.
- builder.append(VCardConstants.PARAM_TYPE_VOICE);
- } else {
- String phoneType = VCardUtils.getPhoneTypeString(type);
- if (phoneType != null) {
- appendTypeParameter(phoneType);
- } else {
- Log.e(LOG_TAG, "Unknown or unsupported (by vCard) Phone type: " + type);
- }
- }
- }
-
- /**
- * @param encodedValue Must be encoded by BASE64
- * @param photoType
- */
- public void appendPhotoLine(final String encodedValue, final String photoType) {
- StringBuilder tmpBuilder = new StringBuilder();
- tmpBuilder.append(VCardConstants.PROPERTY_PHOTO);
- tmpBuilder.append(VCARD_PARAM_SEPARATOR);
- if (mIsV30) {
- tmpBuilder.append(VCARD_PARAM_ENCODING_BASE64_V30);
- } else {
- tmpBuilder.append(VCARD_PARAM_ENCODING_BASE64_V21);
- }
- tmpBuilder.append(VCARD_PARAM_SEPARATOR);
- appendTypeParameter(tmpBuilder, photoType);
- tmpBuilder.append(VCARD_DATA_SEPARATOR);
- tmpBuilder.append(encodedValue);
-
- final String tmpStr = tmpBuilder.toString();
- tmpBuilder = new StringBuilder();
- int lineCount = 0;
- final int length = tmpStr.length();
- final int maxNumForFirstLine = VCardConstants.MAX_CHARACTER_NUMS_BASE64_V30
- - VCARD_END_OF_LINE.length();
- final int maxNumInGeneral = maxNumForFirstLine - VCARD_WS.length();
- int maxNum = maxNumForFirstLine;
- for (int i = 0; i < length; i++) {
- tmpBuilder.append(tmpStr.charAt(i));
- lineCount++;
- if (lineCount > maxNum) {
- tmpBuilder.append(VCARD_END_OF_LINE);
- tmpBuilder.append(VCARD_WS);
- maxNum = maxNumInGeneral;
- lineCount = 0;
- }
- }
- mBuilder.append(tmpBuilder.toString());
- mBuilder.append(VCARD_END_OF_LINE);
- mBuilder.append(VCARD_END_OF_LINE);
- }
-
- public void appendAndroidSpecificProperty(final String mimeType, ContentValues contentValues) {
- if (!sAllowedAndroidPropertySet.contains(mimeType)) {
- return;
- }
- final List<String> rawValueList = new ArrayList<String>();
- for (int i = 1; i <= VCardConstants.MAX_DATA_COLUMN; i++) {
- String value = contentValues.getAsString("data" + i);
- if (value == null) {
- value = "";
- }
- rawValueList.add(value);
- }
-
- boolean needCharset =
- (mShouldAppendCharsetParam &&
- !VCardUtils.containsOnlyNonCrLfPrintableAscii(rawValueList));
- boolean reallyUseQuotedPrintable =
- (mShouldUseQuotedPrintable &&
- !VCardUtils.containsOnlyNonCrLfPrintableAscii(rawValueList));
- mBuilder.append(VCardConstants.PROPERTY_X_ANDROID_CUSTOM);
- if (needCharset) {
- mBuilder.append(VCARD_PARAM_SEPARATOR);
- mBuilder.append(mVCardCharsetParameter);
- }
- if (reallyUseQuotedPrintable) {
- mBuilder.append(VCARD_PARAM_SEPARATOR);
- mBuilder.append(VCARD_PARAM_ENCODING_QP);
- }
- mBuilder.append(VCARD_DATA_SEPARATOR);
- mBuilder.append(mimeType); // Should not be encoded.
- for (String rawValue : rawValueList) {
- final String encodedValue;
- if (reallyUseQuotedPrintable) {
- encodedValue = encodeQuotedPrintable(rawValue);
- } else {
- // TODO: one line may be too huge, which may be invalid in vCard 3.0
- // (which says "When generating a content line, lines longer than
- // 75 characters SHOULD be folded"), though several
- // (even well-known) applications do not care this.
- encodedValue = escapeCharacters(rawValue);
- }
- mBuilder.append(VCARD_ITEM_SEPARATOR);
- mBuilder.append(encodedValue);
- }
- mBuilder.append(VCARD_END_OF_LINE);
- }
-
- public void appendLineWithCharsetAndQPDetection(final String propertyName,
- final String rawValue) {
- appendLineWithCharsetAndQPDetection(propertyName, null, rawValue);
- }
-
- public void appendLineWithCharsetAndQPDetection(
- final String propertyName, final List<String> rawValueList) {
- appendLineWithCharsetAndQPDetection(propertyName, null, rawValueList);
- }
-
- public void appendLineWithCharsetAndQPDetection(final String propertyName,
- final List<String> parameterList, final String rawValue) {
- final boolean needCharset =
- !VCardUtils.containsOnlyPrintableAscii(rawValue);
- final boolean reallyUseQuotedPrintable =
- (mShouldUseQuotedPrintable &&
- !VCardUtils.containsOnlyNonCrLfPrintableAscii(rawValue));
- appendLine(propertyName, parameterList,
- rawValue, needCharset, reallyUseQuotedPrintable);
- }
-
- public void appendLineWithCharsetAndQPDetection(final String propertyName,
- final List<String> parameterList, final List<String> rawValueList) {
- boolean needCharset =
- (mShouldAppendCharsetParam &&
- !VCardUtils.containsOnlyNonCrLfPrintableAscii(rawValueList));
- boolean reallyUseQuotedPrintable =
- (mShouldUseQuotedPrintable &&
- !VCardUtils.containsOnlyNonCrLfPrintableAscii(rawValueList));
- appendLine(propertyName, parameterList, rawValueList,
- needCharset, reallyUseQuotedPrintable);
- }
-
- /**
- * Appends one line with a given property name and value.
- */
- public void appendLine(final String propertyName, final String rawValue) {
- appendLine(propertyName, rawValue, false, false);
- }
-
- public void appendLine(final String propertyName, final List<String> rawValueList) {
- appendLine(propertyName, rawValueList, false, false);
- }
-
- public void appendLine(final String propertyName,
- final String rawValue, final boolean needCharset,
- boolean reallyUseQuotedPrintable) {
- appendLine(propertyName, null, rawValue, needCharset, reallyUseQuotedPrintable);
- }
-
- public void appendLine(final String propertyName, final List<String> parameterList,
- final String rawValue) {
- appendLine(propertyName, parameterList, rawValue, false, false);
- }
-
- public void appendLine(final String propertyName, final List<String> parameterList,
- final String rawValue, final boolean needCharset,
- boolean reallyUseQuotedPrintable) {
- mBuilder.append(propertyName);
- if (parameterList != null && parameterList.size() > 0) {
- mBuilder.append(VCARD_PARAM_SEPARATOR);
- appendTypeParameters(parameterList);
- }
- if (needCharset) {
- mBuilder.append(VCARD_PARAM_SEPARATOR);
- mBuilder.append(mVCardCharsetParameter);
- }
-
- final String encodedValue;
- if (reallyUseQuotedPrintable) {
- mBuilder.append(VCARD_PARAM_SEPARATOR);
- mBuilder.append(VCARD_PARAM_ENCODING_QP);
- encodedValue = encodeQuotedPrintable(rawValue);
- } else {
- // TODO: one line may be too huge, which may be invalid in vCard spec, though
- // several (even well-known) applications do not care this.
- encodedValue = escapeCharacters(rawValue);
- }
-
- mBuilder.append(VCARD_DATA_SEPARATOR);
- mBuilder.append(encodedValue);
- mBuilder.append(VCARD_END_OF_LINE);
- }
-
- public void appendLine(final String propertyName, final List<String> rawValueList,
- final boolean needCharset, boolean needQuotedPrintable) {
- appendLine(propertyName, null, rawValueList, needCharset, needQuotedPrintable);
- }
-
- public void appendLine(final String propertyName, final List<String> parameterList,
- final List<String> rawValueList, final boolean needCharset,
- final boolean needQuotedPrintable) {
- mBuilder.append(propertyName);
- if (parameterList != null && parameterList.size() > 0) {
- mBuilder.append(VCARD_PARAM_SEPARATOR);
- appendTypeParameters(parameterList);
- }
- if (needCharset) {
- mBuilder.append(VCARD_PARAM_SEPARATOR);
- mBuilder.append(mVCardCharsetParameter);
- }
- if (needQuotedPrintable) {
- mBuilder.append(VCARD_PARAM_SEPARATOR);
- mBuilder.append(VCARD_PARAM_ENCODING_QP);
- }
-
- mBuilder.append(VCARD_DATA_SEPARATOR);
- boolean first = true;
- for (String rawValue : rawValueList) {
- final String encodedValue;
- if (needQuotedPrintable) {
- encodedValue = encodeQuotedPrintable(rawValue);
- } else {
- // TODO: one line may be too huge, which may be invalid in vCard 3.0
- // (which says "When generating a content line, lines longer than
- // 75 characters SHOULD be folded"), though several
- // (even well-known) applications do not care this.
- encodedValue = escapeCharacters(rawValue);
- }
-
- if (first) {
- first = false;
- } else {
- mBuilder.append(VCARD_ITEM_SEPARATOR);
- }
- mBuilder.append(encodedValue);
- }
- mBuilder.append(VCARD_END_OF_LINE);
- }
-
- /**
- * VCARD_PARAM_SEPARATOR must be appended before this method being called.
- */
- private void appendTypeParameters(final List<String> types) {
- // We may have to make this comma separated form like "TYPE=DOM,WORK" in the future,
- // which would be recommended way in vcard 3.0 though not valid in vCard 2.1.
- boolean first = true;
- for (final String typeValue : types) {
- // Note: vCard 3.0 specifies the different type of acceptable type Strings, but
- // we don't emit that kind of vCard 3.0 specific type since there should be
- // high probabilyty in which external importers cannot understand them.
- //
- // e.g. TYPE="\u578B\u306B\u3087" (vCard 3.0 allows non-Ascii characters if they
- // are quoted.)
- if (!VCardUtils.isV21Word(typeValue)) {
- continue;
- }
- if (first) {
- first = false;
- } else {
- mBuilder.append(VCARD_PARAM_SEPARATOR);
- }
- appendTypeParameter(typeValue);
- }
- }
-
- /**
- * VCARD_PARAM_SEPARATOR must be appended before this method being called.
- */
- private void appendTypeParameter(final String type) {
- appendTypeParameter(mBuilder, type);
- }
-
- private void appendTypeParameter(final StringBuilder builder, final String type) {
- // Refrain from using appendType() so that "TYPE=" is not be appended when the
- // device is DoCoMo's (just for safety).
- //
- // Note: In vCard 3.0, Type strings also can be like this: "TYPE=HOME,PREF"
- if ((mIsV30 || mAppendTypeParamName) && !mIsDoCoMo) {
- builder.append(VCardConstants.PARAM_TYPE).append(VCARD_PARAM_EQUAL);
- }
- builder.append(type);
- }
-
- /**
- * Returns true when the property line should contain charset parameter
- * information. This method may return true even when vCard version is 3.0.
- *
- * Strictly, adding charset information is invalid in VCard 3.0.
- * However we'll add the info only when charset we use is not UTF-8
- * in vCard 3.0 format, since parser side may be able to use the charset
- * via this field, though we may encounter another problem by adding it.
- *
- * e.g. Japanese mobile phones use Shift_Jis while RFC 2426
- * recommends UTF-8. By adding this field, parsers may be able
- * to know this text is NOT UTF-8 but Shift_Jis.
- */
- private boolean shouldAppendCharsetParam(String...propertyValueList) {
- if (!mShouldAppendCharsetParam) {
- return false;
- }
- for (String propertyValue : propertyValueList) {
- if (!VCardUtils.containsOnlyPrintableAscii(propertyValue)) {
- return true;
- }
- }
- return false;
- }
-
- private String encodeQuotedPrintable(final String str) {
- if (TextUtils.isEmpty(str)) {
- return "";
- }
-
- final StringBuilder builder = new StringBuilder();
- int index = 0;
- int lineCount = 0;
- byte[] strArray = null;
-
- try {
- strArray = str.getBytes(mCharsetString);
- } catch (UnsupportedEncodingException e) {
- Log.e(LOG_TAG, "Charset " + mCharsetString + " cannot be used. "
- + "Try default charset");
- strArray = str.getBytes();
- }
- while (index < strArray.length) {
- builder.append(String.format("=%02X", strArray[index]));
- index += 1;
- lineCount += 3;
-
- if (lineCount >= 67) {
- // Specification requires CRLF must be inserted before the
- // length of the line
- // becomes more than 76.
- // Assuming that the next character is a multi-byte character,
- // it will become
- // 6 bytes.
- // 76 - 6 - 3 = 67
- builder.append("=\r\n");
- lineCount = 0;
- }
- }
-
- return builder.toString();
- }
-
- /**
- * Append '\' to the characters which should be escaped. The character set is different
- * not only between vCard 2.1 and vCard 3.0 but also among each device.
- *
- * Note that Quoted-Printable string must not be input here.
- */
- @SuppressWarnings("fallthrough")
- private String escapeCharacters(final String unescaped) {
- if (TextUtils.isEmpty(unescaped)) {
- return "";
- }
-
- final StringBuilder tmpBuilder = new StringBuilder();
- final int length = unescaped.length();
- for (int i = 0; i < length; i++) {
- final char ch = unescaped.charAt(i);
- switch (ch) {
- case ';': {
- tmpBuilder.append('\\');
- tmpBuilder.append(';');
- break;
- }
- case '\r': {
- if (i + 1 < length) {
- char nextChar = unescaped.charAt(i);
- if (nextChar == '\n') {
- break;
- } else {
- // fall through
- }
- } else {
- // fall through
- }
- }
- case '\n': {
- // In vCard 2.1, there's no specification about this, while
- // vCard 3.0 explicitly requires this should be encoded to "\n".
- tmpBuilder.append("\\n");
- break;
- }
- case '\\': {
- if (mIsV30) {
- tmpBuilder.append("\\\\");
- break;
- } else {
- // fall through
- }
- }
- case '<':
- case '>': {
- if (mIsDoCoMo) {
- tmpBuilder.append('\\');
- tmpBuilder.append(ch);
- } else {
- tmpBuilder.append(ch);
- }
- break;
- }
- case ',': {
- if (mIsV30) {
- tmpBuilder.append("\\,");
- } else {
- tmpBuilder.append(ch);
- }
- break;
- }
- default: {
- tmpBuilder.append(ch);
- break;
- }
- }
- }
- return tmpBuilder.toString();
- }
-
- @Override
- public String toString() {
- if (!mEndAppended) {
- if (mIsDoCoMo) {
- appendLine(VCardConstants.PROPERTY_X_CLASS, VCARD_DATA_PUBLIC);
- appendLine(VCardConstants.PROPERTY_X_REDUCTION, "");
- appendLine(VCardConstants.PROPERTY_X_NO, "");
- appendLine(VCardConstants.PROPERTY_X_DCM_HMN_MODE, "");
- }
- appendLine(VCardConstants.PROPERTY_END, VCARD_DATA_VCARD);
- mEndAppended = true;
- }
- return mBuilder.toString();
- }
-}
diff --git a/core/java/android/pim/vcard/VCardComposer.java b/core/java/android/pim/vcard/VCardComposer.java
deleted file mode 100644
index 0e8b665..0000000
--- a/core/java/android/pim/vcard/VCardComposer.java
+++ /dev/null
@@ -1,592 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package android.pim.vcard;
-
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.Entity;
-import android.content.EntityIterator;
-import android.content.Entity.NamedContentValues;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteException;
-import android.net.Uri;
-import android.pim.vcard.exception.VCardException;
-import android.provider.ContactsContract.Contacts;
-import android.provider.ContactsContract.Data;
-import android.provider.ContactsContract.RawContacts;
-import android.provider.ContactsContract.RawContactsEntity;
-import android.provider.ContactsContract.CommonDataKinds.Email;
-import android.provider.ContactsContract.CommonDataKinds.Event;
-import android.provider.ContactsContract.CommonDataKinds.Im;
-import android.provider.ContactsContract.CommonDataKinds.Nickname;
-import android.provider.ContactsContract.CommonDataKinds.Note;
-import android.provider.ContactsContract.CommonDataKinds.Organization;
-import android.provider.ContactsContract.CommonDataKinds.Phone;
-import android.provider.ContactsContract.CommonDataKinds.Photo;
-import android.provider.ContactsContract.CommonDataKinds.Relation;
-import android.provider.ContactsContract.CommonDataKinds.StructuredName;
-import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
-import android.provider.ContactsContract.CommonDataKinds.Website;
-import android.util.CharsetUtils;
-import android.util.Log;
-
-import java.io.BufferedWriter;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.UnsupportedEncodingException;
-import java.io.Writer;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.nio.charset.UnsupportedCharsetException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * <p>
- * The class for composing VCard from Contacts information. Note that this is
- * completely differnt implementation from
- * android.syncml.pim.vcard.VCardComposer, which is not maintained anymore.
- * </p>
- *
- * <p>
- * Usually, this class should be used like this.
- * </p>
- *
- * <pre class="prettyprint">VCardComposer composer = null;
- * try {
- * composer = new VCardComposer(context);
- * composer.addHandler(
- * composer.new HandlerForOutputStream(outputStream));
- * if (!composer.init()) {
- * // Do something handling the situation.
- * return;
- * }
- * while (!composer.isAfterLast()) {
- * if (mCanceled) {
- * // Assume a user may cancel this operation during the export.
- * return;
- * }
- * if (!composer.createOneEntry()) {
- * // Do something handling the error situation.
- * return;
- * }
- * }
- * } finally {
- * if (composer != null) {
- * composer.terminate();
- * }
- * } </pre>
- */
-public class VCardComposer {
- private static final String LOG_TAG = "VCardComposer";
-
- public static final int DEFAULT_PHONE_TYPE = Phone.TYPE_HOME;
- public static final int DEFAULT_POSTAL_TYPE = StructuredPostal.TYPE_HOME;
- public static final int DEFAULT_EMAIL_TYPE = Email.TYPE_OTHER;
-
- public static final String FAILURE_REASON_FAILED_TO_GET_DATABASE_INFO =
- "Failed to get database information";
-
- public static final String FAILURE_REASON_NO_ENTRY =
- "There's no exportable in the database";
-
- public static final String FAILURE_REASON_NOT_INITIALIZED =
- "The vCard composer object is not correctly initialized";
-
- /** Should be visible only from developers... (no need to translate, hopefully) */
- public static final String FAILURE_REASON_UNSUPPORTED_URI =
- "The Uri vCard composer received is not supported by the composer.";
-
- public static final String NO_ERROR = "No error";
-
- public static final String VCARD_TYPE_STRING_DOCOMO = "docomo";
-
- private static final String SHIFT_JIS = "SHIFT_JIS";
- private static final String UTF_8 = "UTF-8";
-
- /**
- * Special URI for testing.
- */
- public static final String VCARD_TEST_AUTHORITY = "com.android.unit_tests.vcard";
- public static final Uri VCARD_TEST_AUTHORITY_URI =
- Uri.parse("content://" + VCARD_TEST_AUTHORITY);
- public static final Uri CONTACTS_TEST_CONTENT_URI =
- Uri.withAppendedPath(VCARD_TEST_AUTHORITY_URI, "contacts");
-
- private static final Map<Integer, String> sImMap;
-
- static {
- sImMap = new HashMap<Integer, String>();
- sImMap.put(Im.PROTOCOL_AIM, VCardConstants.PROPERTY_X_AIM);
- sImMap.put(Im.PROTOCOL_MSN, VCardConstants.PROPERTY_X_MSN);
- sImMap.put(Im.PROTOCOL_YAHOO, VCardConstants.PROPERTY_X_YAHOO);
- sImMap.put(Im.PROTOCOL_ICQ, VCardConstants.PROPERTY_X_ICQ);
- sImMap.put(Im.PROTOCOL_JABBER, VCardConstants.PROPERTY_X_JABBER);
- sImMap.put(Im.PROTOCOL_SKYPE, VCardConstants.PROPERTY_X_SKYPE_USERNAME);
- // Google talk is a special case.
- }
-
- public static interface OneEntryHandler {
- public boolean onInit(Context context);
- public boolean onEntryCreated(String vcard);
- public void onTerminate();
- }
-
- /**
- * <p>
- * An useful example handler, which emits VCard String to outputstream one by one.
- * </p>
- * <p>
- * The input OutputStream object is closed() on {@link #onTerminate()}.
- * Must not close the stream outside.
- * </p>
- */
- public class HandlerForOutputStream implements OneEntryHandler {
- @SuppressWarnings("hiding")
- private static final String LOG_TAG = "vcard.VCardComposer.HandlerForOutputStream";
-
- final private OutputStream mOutputStream; // mWriter will close this.
- private Writer mWriter;
-
- private boolean mOnTerminateIsCalled = false;
-
- /**
- * Input stream will be closed on the detruction of this object.
- */
- public HandlerForOutputStream(OutputStream outputStream) {
- mOutputStream = outputStream;
- }
-
- public boolean onInit(Context context) {
- try {
- mWriter = new BufferedWriter(new OutputStreamWriter(
- mOutputStream, mCharsetString));
- } catch (UnsupportedEncodingException e1) {
- Log.e(LOG_TAG, "Unsupported charset: " + mCharsetString);
- mErrorReason = "Encoding is not supported (usually this does not happen!): "
- + mCharsetString;
- return false;
- }
-
- if (mIsDoCoMo) {
- try {
- // Create one empty entry.
- mWriter.write(createOneEntryInternal("-1", null));
- } catch (VCardException e) {
- Log.e(LOG_TAG, "VCardException has been thrown during on Init(): " +
- e.getMessage());
- return false;
- } catch (IOException e) {
- Log.e(LOG_TAG,
- "IOException occurred during exportOneContactData: "
- + e.getMessage());
- mErrorReason = "IOException occurred: " + e.getMessage();
- return false;
- }
- }
- return true;
- }
-
- public boolean onEntryCreated(String vcard) {
- try {
- mWriter.write(vcard);
- } catch (IOException e) {
- Log.e(LOG_TAG,
- "IOException occurred during exportOneContactData: "
- + e.getMessage());
- mErrorReason = "IOException occurred: " + e.getMessage();
- return false;
- }
- return true;
- }
-
- public void onTerminate() {
- mOnTerminateIsCalled = true;
- if (mWriter != null) {
- try {
- // Flush and sync the data so that a user is able to pull
- // the SDCard just after
- // the export.
- mWriter.flush();
- if (mOutputStream != null
- && mOutputStream instanceof FileOutputStream) {
- ((FileOutputStream) mOutputStream).getFD().sync();
- }
- } catch (IOException e) {
- Log.d(LOG_TAG,
- "IOException during closing the output stream: "
- + e.getMessage());
- } finally {
- try {
- mWriter.close();
- } catch (IOException e) {
- }
- }
- }
- }
-
- @Override
- public void finalize() {
- if (!mOnTerminateIsCalled) {
- onTerminate();
- }
- }
- }
-
- private final Context mContext;
- private final int mVCardType;
- private final boolean mCareHandlerErrors;
- private final ContentResolver mContentResolver;
-
- private final boolean mIsDoCoMo;
- private final boolean mUsesShiftJis;
- private Cursor mCursor;
- private int mIdColumn;
-
- private final String mCharsetString;
- private boolean mTerminateIsCalled;
- private final List<OneEntryHandler> mHandlerList;
-
- private String mErrorReason = NO_ERROR;
-
- private static final String[] sContactsProjection = new String[] {
- Contacts._ID,
- };
-
- public VCardComposer(Context context) {
- this(context, VCardConfig.VCARD_TYPE_DEFAULT, true);
- }
-
- public VCardComposer(Context context, int vcardType) {
- this(context, vcardType, true);
- }
-
- public VCardComposer(Context context, String vcardTypeStr, boolean careHandlerErrors) {
- this(context, VCardConfig.getVCardTypeFromString(vcardTypeStr), careHandlerErrors);
- }
-
- /**
- * Construct for supporting call log entry vCard composing.
- */
- public VCardComposer(final Context context, final int vcardType,
- final boolean careHandlerErrors) {
- mContext = context;
- mVCardType = vcardType;
- mCareHandlerErrors = careHandlerErrors;
- mContentResolver = context.getContentResolver();
-
- mIsDoCoMo = VCardConfig.isDoCoMo(vcardType);
- mUsesShiftJis = VCardConfig.usesShiftJis(vcardType);
- mHandlerList = new ArrayList<OneEntryHandler>();
-
- if (mIsDoCoMo) {
- String charset;
- try {
- charset = CharsetUtils.charsetForVendor(SHIFT_JIS, "docomo").name();
- } catch (UnsupportedCharsetException e) {
- Log.e(LOG_TAG, "DoCoMo-specific SHIFT_JIS was not found. Use SHIFT_JIS as is.");
- charset = SHIFT_JIS;
- }
- mCharsetString = charset;
- } else if (mUsesShiftJis) {
- String charset;
- try {
- charset = CharsetUtils.charsetForVendor(SHIFT_JIS).name();
- } catch (UnsupportedCharsetException e) {
- Log.e(LOG_TAG, "Vendor-specific SHIFT_JIS was not found. Use SHIFT_JIS as is.");
- charset = SHIFT_JIS;
- }
- mCharsetString = charset;
- } else {
- mCharsetString = UTF_8;
- }
- }
-
- /**
- * Must be called before {@link #init()}.
- */
- public void addHandler(OneEntryHandler handler) {
- if (handler != null) {
- mHandlerList.add(handler);
- }
- }
-
- /**
- * @return Returns true when initialization is successful and all the other
- * methods are available. Returns false otherwise.
- */
- public boolean init() {
- return init(null, null);
- }
-
- public boolean init(final String selection, final String[] selectionArgs) {
- return init(Contacts.CONTENT_URI, selection, selectionArgs, null);
- }
-
- /**
- * Note that this is unstable interface, may be deleted in the future.
- */
- public boolean init(final Uri contentUri, final String selection,
- final String[] selectionArgs, final String sortOrder) {
- if (contentUri == null) {
- return false;
- }
-
- if (mCareHandlerErrors) {
- List<OneEntryHandler> finishedList = new ArrayList<OneEntryHandler>(
- mHandlerList.size());
- for (OneEntryHandler handler : mHandlerList) {
- if (!handler.onInit(mContext)) {
- for (OneEntryHandler finished : finishedList) {
- finished.onTerminate();
- }
- return false;
- }
- }
- } else {
- // Just ignore the false returned from onInit().
- for (OneEntryHandler handler : mHandlerList) {
- handler.onInit(mContext);
- }
- }
-
- final String[] projection;
- if (Contacts.CONTENT_URI.equals(contentUri) ||
- CONTACTS_TEST_CONTENT_URI.equals(contentUri)) {
- projection = sContactsProjection;
- } else {
- mErrorReason = FAILURE_REASON_UNSUPPORTED_URI;
- return false;
- }
- mCursor = mContentResolver.query(
- contentUri, projection, selection, selectionArgs, sortOrder);
-
- if (mCursor == null) {
- mErrorReason = FAILURE_REASON_FAILED_TO_GET_DATABASE_INFO;
- return false;
- }
-
- if (getCount() == 0 || !mCursor.moveToFirst()) {
- try {
- mCursor.close();
- } catch (SQLiteException e) {
- Log.e(LOG_TAG, "SQLiteException on Cursor#close(): " + e.getMessage());
- } finally {
- mCursor = null;
- mErrorReason = FAILURE_REASON_NO_ENTRY;
- }
- return false;
- }
-
- mIdColumn = mCursor.getColumnIndex(Contacts._ID);
-
- return true;
- }
-
- public boolean createOneEntry() {
- return createOneEntry(null);
- }
-
- /**
- * @param getEntityIteratorMethod For Dependency Injection.
- * @hide just for testing.
- */
- public boolean createOneEntry(Method getEntityIteratorMethod) {
- if (mCursor == null || mCursor.isAfterLast()) {
- mErrorReason = FAILURE_REASON_NOT_INITIALIZED;
- return false;
- }
- String vcard;
- try {
- if (mIdColumn >= 0) {
- vcard = createOneEntryInternal(mCursor.getString(mIdColumn),
- getEntityIteratorMethod);
- } else {
- Log.e(LOG_TAG, "Incorrect mIdColumn: " + mIdColumn);
- return true;
- }
- } catch (VCardException e) {
- Log.e(LOG_TAG, "VCardException has been thrown: " + e.getMessage());
- return false;
- } catch (OutOfMemoryError error) {
- // Maybe some data (e.g. photo) is too big to have in memory. But it
- // should be rare.
- Log.e(LOG_TAG, "OutOfMemoryError occured. Ignore the entry.");
- System.gc();
- // TODO: should tell users what happened?
- return true;
- } finally {
- mCursor.moveToNext();
- }
-
- // This function does not care the OutOfMemoryError on the handler side
- // :-P
- if (mCareHandlerErrors) {
- List<OneEntryHandler> finishedList = new ArrayList<OneEntryHandler>(
- mHandlerList.size());
- for (OneEntryHandler handler : mHandlerList) {
- if (!handler.onEntryCreated(vcard)) {
- return false;
- }
- }
- } else {
- for (OneEntryHandler handler : mHandlerList) {
- handler.onEntryCreated(vcard);
- }
- }
-
- return true;
- }
-
- private String createOneEntryInternal(final String contactId,
- Method getEntityIteratorMethod) throws VCardException {
- final Map<String, List<ContentValues>> contentValuesListMap =
- new HashMap<String, List<ContentValues>>();
- // The resolver may return the entity iterator with no data. It is possible.
- // e.g. If all the data in the contact of the given contact id are not exportable ones,
- // they are hidden from the view of this method, though contact id itself exists.
- EntityIterator entityIterator = null;
- try {
- final Uri uri = RawContactsEntity.CONTENT_URI.buildUpon()
- .appendQueryParameter(Data.FOR_EXPORT_ONLY, "1")
- .build();
- final String selection = Data.CONTACT_ID + "=?";
- final String[] selectionArgs = new String[] {contactId};
- if (getEntityIteratorMethod != null) {
- // Please note that this branch is executed by some tests only
- try {
- entityIterator = (EntityIterator)getEntityIteratorMethod.invoke(null,
- mContentResolver, uri, selection, selectionArgs, null);
- } catch (IllegalArgumentException e) {
- Log.e(LOG_TAG, "IllegalArgumentException has been thrown: " +
- e.getMessage());
- } catch (IllegalAccessException e) {
- Log.e(LOG_TAG, "IllegalAccessException has been thrown: " +
- e.getMessage());
- } catch (InvocationTargetException e) {
- Log.e(LOG_TAG, "InvocationTargetException has been thrown: ");
- StackTraceElement[] stackTraceElements = e.getCause().getStackTrace();
- for (StackTraceElement element : stackTraceElements) {
- Log.e(LOG_TAG, " at " + element.toString());
- }
- throw new VCardException("InvocationTargetException has been thrown: " +
- e.getCause().getMessage());
- }
- } else {
- entityIterator = RawContacts.newEntityIterator(mContentResolver.query(
- uri, null, selection, selectionArgs, null));
- }
-
- if (entityIterator == null) {
- Log.e(LOG_TAG, "EntityIterator is null");
- return "";
- }
-
- if (!entityIterator.hasNext()) {
- Log.w(LOG_TAG, "Data does not exist. contactId: " + contactId);
- return "";
- }
-
- while (entityIterator.hasNext()) {
- Entity entity = entityIterator.next();
- for (NamedContentValues namedContentValues : entity.getSubValues()) {
- ContentValues contentValues = namedContentValues.values;
- String key = contentValues.getAsString(Data.MIMETYPE);
- if (key != null) {
- List<ContentValues> contentValuesList =
- contentValuesListMap.get(key);
- if (contentValuesList == null) {
- contentValuesList = new ArrayList<ContentValues>();
- contentValuesListMap.put(key, contentValuesList);
- }
- contentValuesList.add(contentValues);
- }
- }
- }
- } finally {
- if (entityIterator != null) {
- entityIterator.close();
- }
- }
-
- final VCardBuilder builder = new VCardBuilder(mVCardType);
- builder.appendNameProperties(contentValuesListMap.get(StructuredName.CONTENT_ITEM_TYPE))
- .appendNickNames(contentValuesListMap.get(Nickname.CONTENT_ITEM_TYPE))
- .appendPhones(contentValuesListMap.get(Phone.CONTENT_ITEM_TYPE))
- .appendEmails(contentValuesListMap.get(Email.CONTENT_ITEM_TYPE))
- .appendPostals(contentValuesListMap.get(StructuredPostal.CONTENT_ITEM_TYPE))
- .appendOrganizations(contentValuesListMap.get(Organization.CONTENT_ITEM_TYPE))
- .appendWebsites(contentValuesListMap.get(Website.CONTENT_ITEM_TYPE));
- if ((mVCardType & VCardConfig.FLAG_REFRAIN_IMAGE_EXPORT) == 0) {
- builder.appendPhotos(contentValuesListMap.get(Photo.CONTENT_ITEM_TYPE));
- }
- builder.appendNotes(contentValuesListMap.get(Note.CONTENT_ITEM_TYPE))
- .appendEvents(contentValuesListMap.get(Event.CONTENT_ITEM_TYPE))
- .appendIms(contentValuesListMap.get(Im.CONTENT_ITEM_TYPE))
- .appendRelation(contentValuesListMap.get(Relation.CONTENT_ITEM_TYPE));
- return builder.toString();
- }
-
- public void terminate() {
- for (OneEntryHandler handler : mHandlerList) {
- handler.onTerminate();
- }
-
- if (mCursor != null) {
- try {
- mCursor.close();
- } catch (SQLiteException e) {
- Log.e(LOG_TAG, "SQLiteException on Cursor#close(): " + e.getMessage());
- }
- mCursor = null;
- }
-
- mTerminateIsCalled = true;
- }
-
- @Override
- public void finalize() {
- if (!mTerminateIsCalled) {
- terminate();
- }
- }
-
- public int getCount() {
- if (mCursor == null) {
- return 0;
- }
- return mCursor.getCount();
- }
-
- public boolean isAfterLast() {
- if (mCursor == null) {
- return false;
- }
- return mCursor.isAfterLast();
- }
-
- /**
- * @return Return the error reason if possible.
- */
- public String getErrorReason() {
- return mErrorReason;
- }
-}
diff --git a/core/java/android/pim/vcard/VCardConfig.java b/core/java/android/pim/vcard/VCardConfig.java
deleted file mode 100644
index 8219840..0000000
--- a/core/java/android/pim/vcard/VCardConfig.java
+++ /dev/null
@@ -1,477 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.pim.vcard;
-
-import android.telephony.PhoneNumberUtils;
-import android.util.Log;
-
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * The class representing VCard related configurations. Useful static methods are not in this class
- * but in VCardUtils.
- */
-public class VCardConfig {
- private static final String LOG_TAG = "VCardConfig";
-
- /* package */ static final int LOG_LEVEL_NONE = 0;
- /* package */ static final int LOG_LEVEL_PERFORMANCE_MEASUREMENT = 0x1;
- /* package */ static final int LOG_LEVEL_SHOW_WARNING = 0x2;
- /* package */ static final int LOG_LEVEL_VERBOSE =
- LOG_LEVEL_PERFORMANCE_MEASUREMENT | LOG_LEVEL_SHOW_WARNING;
-
- /* package */ static final int LOG_LEVEL = LOG_LEVEL_NONE;
-
- /* package */ static final int PARSE_TYPE_UNKNOWN = 0;
- /* package */ static final int PARSE_TYPE_APPLE = 1;
- /* package */ static final int PARSE_TYPE_MOBILE_PHONE_JP = 2; // For Japanese mobile phones.
- /* package */ static final int PARSE_TYPE_FOMA = 3; // For Japanese FOMA mobile phones.
- /* package */ static final int PARSE_TYPE_WINDOWS_MOBILE_JP = 4;
-
- // Assumes that "iso-8859-1" is able to map "all" 8bit characters to some unicode and
- // decode the unicode to the original charset. If not, this setting will cause some bug.
- public static final String DEFAULT_CHARSET = "iso-8859-1";
-
- public static final int FLAG_V21 = 0;
- public static final int FLAG_V30 = 1;
-
- // 0x2 is reserved for the future use ...
-
- public static final int NAME_ORDER_DEFAULT = 0;
- public static final int NAME_ORDER_EUROPE = 0x4;
- public static final int NAME_ORDER_JAPANESE = 0x8;
- private static final int NAME_ORDER_MASK = 0xC;
-
- // 0x10 is reserved for safety
-
- private static final int FLAG_CHARSET_UTF8 = 0;
- private static final int FLAG_CHARSET_SHIFT_JIS = 0x100;
- private static final int FLAG_CHARSET_MASK = 0xF00;
-
- /**
- * The flag indicating the vCard composer will add some "X-" properties used only in Android
- * when the formal vCard specification does not have appropriate fields for that data.
- *
- * For example, Android accepts nickname information while vCard 2.1 does not.
- * When this flag is on, vCard composer emits alternative "X-" property (like "X-NICKNAME")
- * instead of just dropping it.
- *
- * vCard parser code automatically parses the field emitted even when this flag is off.
- *
- * Note that this flag does not assure all the information must be hold in the emitted vCard.
- */
- private static final int FLAG_USE_ANDROID_PROPERTY = 0x80000000;
-
- /**
- * The flag indicating the vCard composer will add some "X-" properties seen in the
- * vCard data emitted by the other softwares/devices when the formal vCard specification
- * does not have appropriate field(s) for that data.
- *
- * One example is X-PHONETIC-FIRST-NAME/X-PHONETIC-MIDDLE-NAME/X-PHONETIC-LAST-NAME, which are
- * for phonetic name (how the name is pronounced), seen in the vCard emitted by some other
- * non-Android devices/softwares. We chose to enable the vCard composer to use those
- * defact properties since they are also useful for Android devices.
- *
- * Note for developers: only "X-" properties should be added with this flag. vCard 2.1/3.0
- * allows any kind of "X-" properties but does not allow non-"X-" properties (except IANA tokens
- * in vCard 3.0). Some external parsers may get confused with non-valid, non-"X-" properties.
- */
- private static final int FLAG_USE_DEFACT_PROPERTY = 0x40000000;
-
- /**
- * The flag indicating some specific dialect seen in vcard of DoCoMo (one of Japanese
- * mobile careers) should be used. This flag does not include any other information like
- * that "the vCard is for Japanese". So it is "possible" that "the vCard should have DoCoMo's
- * dialect but the name order should be European", but it is not recommended.
- */
- private static final int FLAG_DOCOMO = 0x20000000;
-
- /**
- * <P>
- * The flag indicating the vCard composer does "NOT" use Quoted-Printable toward "primary"
- * properties even though it is required by vCard 2.1 (QP is prohibited in vCard 3.0).
- * </P>
- * <P>
- * We actually cannot define what is the "primary" property. Note that this is NOT defined
- * in vCard specification either. Also be aware that it is NOT related to "primary" notion
- * used in {@link android.provider.ContactsContract}.
- * This notion is just for vCard composition in Android.
- * </P>
- * <P>
- * We added this Android-specific notion since some (incomplete) vCard exporters for vCard 2.1
- * do NOT use Quoted-Printable encoding toward some properties related names like "N", "FN", etc.
- * even when their values contain non-ascii or/and CR/LF, while they use the encoding in the
- * other properties like "ADR", "ORG", etc.
- * <P>
- * We are afraid of the case where some vCard importer also forget handling QP presuming QP is
- * not used in such fields.
- * </P>
- * <P>
- * This flag is useful when some target importer you are going to focus on does not accept
- * such properties with Quoted-Printable encoding.
- * </P>
- * <P>
- * Again, we should not use this flag at all for complying vCard 2.1 spec.
- * </P>
- * <P>
- * In vCard 3.0, Quoted-Printable is explicitly "prohibitted", so we don't need to care this
- * kind of problem (hopefully).
- * </P>
- */
- public static final int FLAG_REFRAIN_QP_TO_NAME_PROPERTIES = 0x10000000;
-
- /**
- * <P>
- * The flag indicating that phonetic name related fields must be converted to
- * appropriate form. Note that "appropriate" is not defined in any vCard specification.
- * This is Android-specific.
- * </P>
- * <P>
- * One typical (and currently sole) example where we need this flag is the time when
- * we need to emit Japanese phonetic names into vCard entries. The property values
- * should be encoded into half-width katakana when the target importer is Japanese mobile
- * phones', which are probably not able to parse full-width hiragana/katakana for
- * historical reasons, while the vCard importers embedded to softwares for PC should be
- * able to parse them as we expect.
- * </P>
- */
- public static final int FLAG_CONVERT_PHONETIC_NAME_STRINGS = 0x0800000;
-
- /**
- * <P>
- * The flag indicating the vCard composer "for 2.1" emits "TYPE=" string toward TYPE params
- * every time possible. The default behavior does not emit it and is valid in the spec.
- * In vCrad 3.0, this flag is unnecessary, since "TYPE=" is MUST in vCard 3.0 specification.
- * </P>
- * <P>
- * Detail:
- * How more than one TYPE fields are expressed is different between vCard 2.1 and vCard 3.0.
- * </p>
- * <P>
- * e.g.<BR />
- * 1) Probably valid in both vCard 2.1 and vCard 3.0: "ADR;TYPE=DOM;TYPE=HOME:..."<BR />
- * 2) Valid in vCard 2.1 but not in vCard 3.0: "ADR;DOM;HOME:..."<BR />
- * 3) Valid in vCard 3.0 but not in vCard 2.1: "ADR;TYPE=DOM,HOME:..."<BR />
- * </P>
- * <P>
- * 2) had been the default of VCard exporter/importer in Android, but it is found that
- * some external exporter is not able to parse the type format like 2) but only 3).
- * </P>
- * <P>
- * If you are targeting to the importer which cannot accept TYPE params without "TYPE="
- * strings (which should be rare though), please use this flag.
- * </P>
- * <P>
- * Example usage: int vcardType = (VCARD_TYPE_V21_GENERIC | FLAG_APPEND_TYPE_PARAM);
- * </P>
- */
- public static final int FLAG_APPEND_TYPE_PARAM = 0x04000000;
-
- /**
- * <P>
- * The flag asking exporter to refrain image export.
- * </P>
- * @hide will be deleted in the near future.
- */
- public static final int FLAG_REFRAIN_IMAGE_EXPORT = 0x02000000;
-
- /**
- * <P>
- * The flag indicating the vCard composer does touch nothing toward phone number Strings
- * but leave it as is.
- * </P>
- * <P>
- * The vCard specifications mention nothing toward phone numbers, while some devices
- * do (wrongly, but with innevitable reasons).
- * For example, there's a possibility Japanese mobile phones are expected to have
- * just numbers, hypens, plus, etc. but not usual alphabets, while US mobile phones
- * should get such characters. To make exported vCard simple for external parsers,
- * we have used {@link PhoneNumberUtils#formatNumber(String)} during export, and
- * removed unnecessary characters inside the number (e.g. "111-222-3333 (Miami)"
- * becomes "111-222-3333").
- * Unfortunate side effect of that use was some control characters used in the other
- * areas may be badly affected by the formatting.
- * </P>
- * <P>
- * This flag disables that formatting, affecting both importer and exporter.
- * If the user is aware of some side effects due to the implicit formatting, use this flag.
- * </P>
- */
- public static final int FLAG_REFRAIN_PHONE_NUMBER_FORMATTING = 0x02000000;
-
- //// The followings are VCard types available from importer/exporter. ////
-
- /**
- * <P>
- * Generic vCard format with the vCard 2.1. Uses UTF-8 for the charset.
- * When composing a vCard entry, the US convension will be used toward formatting
- * some values.
- * </P>
- * <P>
- * e.g. The order of the display name would be "Prefix Given Middle Family Suffix",
- * while it should be "Prefix Family Middle Given Suffix" in Japan for example.
- * </P>
- */
- public static final int VCARD_TYPE_V21_GENERIC_UTF8 =
- (FLAG_V21 | NAME_ORDER_DEFAULT | FLAG_CHARSET_UTF8 |
- FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
-
- /* package */ static String VCARD_TYPE_V21_GENERIC_UTF8_STR = "v21_generic";
-
- /**
- * <P>
- * General vCard format with the version 3.0. Uses UTF-8 for the charset.
- * </P>
- * <P>
- * Not fully ready yet. Use with caution when you use this.
- * </P>
- */
- public static final int VCARD_TYPE_V30_GENERIC_UTF8 =
- (FLAG_V30 | NAME_ORDER_DEFAULT | FLAG_CHARSET_UTF8 |
- FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
-
- /* package */ static final String VCARD_TYPE_V30_GENERIC_UTF8_STR = "v30_generic";
-
- /**
- * <P>
- * General vCard format for the vCard 2.1 with some Europe convension. Uses Utf-8.
- * Currently, only name order is considered ("Prefix Middle Given Family Suffix")
- * </P>
- */
- public static final int VCARD_TYPE_V21_EUROPE_UTF8 =
- (FLAG_V21 | NAME_ORDER_EUROPE | FLAG_CHARSET_UTF8 |
- FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
-
- /* package */ static final String VCARD_TYPE_V21_EUROPE_UTF8_STR = "v21_europe";
-
- /**
- * <P>
- * General vCard format with the version 3.0 with some Europe convension. Uses UTF-8.
- * </P>
- * <P>
- * Not ready yet. Use with caution when you use this.
- * </P>
- */
- public static final int VCARD_TYPE_V30_EUROPE_UTF8 =
- (FLAG_V30 | NAME_ORDER_EUROPE | FLAG_CHARSET_UTF8 |
- FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
-
- /* package */ static final String VCARD_TYPE_V30_EUROPE_STR = "v30_europe";
-
- /**
- * <P>
- * The vCard 2.1 format for miscellaneous Japanese devices, using UTF-8 as default charset.
- * </P>
- * <P>
- * Not ready yet. Use with caution when you use this.
- * </P>
- */
- public static final int VCARD_TYPE_V21_JAPANESE_UTF8 =
- (FLAG_V21 | NAME_ORDER_JAPANESE | FLAG_CHARSET_UTF8 |
- FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
-
- /* package */ static final String VCARD_TYPE_V21_JAPANESE_UTF8_STR = "v21_japanese_utf8";
-
- /**
- * <P>
- * vCard 2.1 format for miscellaneous Japanese devices. Shift_Jis is used for
- * parsing/composing the vCard data.
- * </P>
- * <P>
- * Not ready yet. Use with caution when you use this.
- * </P>
- */
- public static final int VCARD_TYPE_V21_JAPANESE_SJIS =
- (FLAG_V21 | NAME_ORDER_JAPANESE | FLAG_CHARSET_SHIFT_JIS |
- FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
-
- /* package */ static final String VCARD_TYPE_V21_JAPANESE_SJIS_STR = "v21_japanese_sjis";
-
- /**
- * <P>
- * vCard format for miscellaneous Japanese devices, using Shift_Jis for
- * parsing/composing the vCard data.
- * </P>
- * <P>
- * Not ready yet. Use with caution when you use this.
- * </P>
- */
- public static final int VCARD_TYPE_V30_JAPANESE_SJIS =
- (FLAG_V30 | NAME_ORDER_JAPANESE | FLAG_CHARSET_SHIFT_JIS |
- FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
-
- /* package */ static final String VCARD_TYPE_V30_JAPANESE_SJIS_STR = "v30_japanese_sjis";
-
- /**
- * <P>
- * The vCard 3.0 format for miscellaneous Japanese devices, using UTF-8 as default charset.
- * </P>
- * <P>
- * Not ready yet. Use with caution when you use this.
- * </P>
- */
- public static final int VCARD_TYPE_V30_JAPANESE_UTF8 =
- (FLAG_V30 | NAME_ORDER_JAPANESE | FLAG_CHARSET_UTF8 |
- FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
-
- /* package */ static final String VCARD_TYPE_V30_JAPANESE_UTF8_STR = "v30_japanese_utf8";
-
- /**
- * <P>
- * The vCard 2.1 based format which (partially) considers the convention in Japanese
- * mobile phones, where phonetic names are translated to half-width katakana if
- * possible, etc.
- * </P>
- * <P>
- * Not ready yet. Use with caution when you use this.
- * </P>
- */
- public static final int VCARD_TYPE_V21_JAPANESE_MOBILE =
- (FLAG_V21 | NAME_ORDER_JAPANESE | FLAG_CHARSET_SHIFT_JIS |
- FLAG_CONVERT_PHONETIC_NAME_STRINGS |
- FLAG_REFRAIN_QP_TO_NAME_PROPERTIES);
-
- /* package */ static final String VCARD_TYPE_V21_JAPANESE_MOBILE_STR = "v21_japanese_mobile";
-
- /**
- * <P>
- * VCard format used in DoCoMo, which is one of Japanese mobile phone careers.
- * </p>
- * <P>
- * Base version is vCard 2.1, but the data has several DoCoMo-specific convensions.
- * No Android-specific property nor defact property is included. The "Primary" properties
- * are NOT encoded to Quoted-Printable.
- * </P>
- */
- public static final int VCARD_TYPE_DOCOMO =
- (VCARD_TYPE_V21_JAPANESE_MOBILE | FLAG_DOCOMO);
-
- /* package */ static final String VCARD_TYPE_DOCOMO_STR = "docomo";
-
- public static int VCARD_TYPE_DEFAULT = VCARD_TYPE_V21_GENERIC_UTF8;
-
- private static final Map<String, Integer> sVCardTypeMap;
- private static final Set<Integer> sJapaneseMobileTypeSet;
-
- static {
- sVCardTypeMap = new HashMap<String, Integer>();
- sVCardTypeMap.put(VCARD_TYPE_V21_GENERIC_UTF8_STR, VCARD_TYPE_V21_GENERIC_UTF8);
- sVCardTypeMap.put(VCARD_TYPE_V30_GENERIC_UTF8_STR, VCARD_TYPE_V30_GENERIC_UTF8);
- sVCardTypeMap.put(VCARD_TYPE_V21_EUROPE_UTF8_STR, VCARD_TYPE_V21_EUROPE_UTF8);
- sVCardTypeMap.put(VCARD_TYPE_V30_EUROPE_STR, VCARD_TYPE_V30_EUROPE_UTF8);
- sVCardTypeMap.put(VCARD_TYPE_V21_JAPANESE_SJIS_STR, VCARD_TYPE_V21_JAPANESE_SJIS);
- sVCardTypeMap.put(VCARD_TYPE_V21_JAPANESE_UTF8_STR, VCARD_TYPE_V21_JAPANESE_UTF8);
- sVCardTypeMap.put(VCARD_TYPE_V30_JAPANESE_SJIS_STR, VCARD_TYPE_V30_JAPANESE_SJIS);
- sVCardTypeMap.put(VCARD_TYPE_V30_JAPANESE_UTF8_STR, VCARD_TYPE_V30_JAPANESE_UTF8);
- sVCardTypeMap.put(VCARD_TYPE_V21_JAPANESE_MOBILE_STR, VCARD_TYPE_V21_JAPANESE_MOBILE);
- sVCardTypeMap.put(VCARD_TYPE_DOCOMO_STR, VCARD_TYPE_DOCOMO);
-
- sJapaneseMobileTypeSet = new HashSet<Integer>();
- sJapaneseMobileTypeSet.add(VCARD_TYPE_V21_JAPANESE_SJIS);
- sJapaneseMobileTypeSet.add(VCARD_TYPE_V21_JAPANESE_UTF8);
- sJapaneseMobileTypeSet.add(VCARD_TYPE_V21_JAPANESE_SJIS);
- sJapaneseMobileTypeSet.add(VCARD_TYPE_V30_JAPANESE_SJIS);
- sJapaneseMobileTypeSet.add(VCARD_TYPE_V30_JAPANESE_UTF8);
- sJapaneseMobileTypeSet.add(VCARD_TYPE_V21_JAPANESE_MOBILE);
- sJapaneseMobileTypeSet.add(VCARD_TYPE_DOCOMO);
- }
-
- public static int getVCardTypeFromString(final String vcardTypeString) {
- final String loweredKey = vcardTypeString.toLowerCase();
- if (sVCardTypeMap.containsKey(loweredKey)) {
- return sVCardTypeMap.get(loweredKey);
- } else if ("default".equalsIgnoreCase(vcardTypeString)) {
- return VCARD_TYPE_DEFAULT;
- } else {
- Log.e(LOG_TAG, "Unknown vCard type String: \"" + vcardTypeString + "\"");
- return VCARD_TYPE_DEFAULT;
- }
- }
-
- public static boolean isV30(final int vcardType) {
- return ((vcardType & FLAG_V30) != 0);
- }
-
- public static boolean shouldUseQuotedPrintable(final int vcardType) {
- return !isV30(vcardType);
- }
-
- public static boolean usesUtf8(final int vcardType) {
- return ((vcardType & FLAG_CHARSET_MASK) == FLAG_CHARSET_UTF8);
- }
-
- public static boolean usesShiftJis(final int vcardType) {
- return ((vcardType & FLAG_CHARSET_MASK) == FLAG_CHARSET_SHIFT_JIS);
- }
-
- public static int getNameOrderType(final int vcardType) {
- return vcardType & NAME_ORDER_MASK;
- }
-
- public static boolean usesAndroidSpecificProperty(final int vcardType) {
- return ((vcardType & FLAG_USE_ANDROID_PROPERTY) != 0);
- }
-
- public static boolean usesDefactProperty(final int vcardType) {
- return ((vcardType & FLAG_USE_DEFACT_PROPERTY) != 0);
- }
-
- public static boolean showPerformanceLog() {
- return (VCardConfig.LOG_LEVEL & VCardConfig.LOG_LEVEL_PERFORMANCE_MEASUREMENT) != 0;
- }
-
- public static boolean shouldRefrainQPToNameProperties(final int vcardType) {
- return (!shouldUseQuotedPrintable(vcardType) ||
- ((vcardType & FLAG_REFRAIN_QP_TO_NAME_PROPERTIES) != 0));
- }
-
- public static boolean appendTypeParamName(final int vcardType) {
- return (isV30(vcardType) || ((vcardType & FLAG_APPEND_TYPE_PARAM) != 0));
- }
-
- /**
- * @return true if the device is Japanese and some Japanese convension is
- * applied to creating "formatted" something like FORMATTED_ADDRESS.
- */
- public static boolean isJapaneseDevice(final int vcardType) {
- // TODO: Some mask will be required so that this method wrongly interpret
- // Japanese"-like" vCard type.
- // e.g. VCARD_TYPE_V21_JAPANESE_SJIS | FLAG_APPEND_TYPE_PARAMS
- return sJapaneseMobileTypeSet.contains(vcardType);
- }
-
- /* package */ static boolean refrainPhoneNumberFormatting(final int vcardType) {
- return ((vcardType & FLAG_REFRAIN_PHONE_NUMBER_FORMATTING) != 0);
- }
-
- public static boolean needsToConvertPhoneticString(final int vcardType) {
- return ((vcardType & FLAG_CONVERT_PHONETIC_NAME_STRINGS) != 0);
- }
-
- public static boolean onlyOneNoteFieldIsAvailable(final int vcardType) {
- return vcardType == VCARD_TYPE_DOCOMO;
- }
-
- public static boolean isDoCoMo(final int vcardType) {
- return ((vcardType & FLAG_DOCOMO) != 0);
- }
-
- private VCardConfig() {
- }
-}
diff --git a/core/java/android/pim/vcard/VCardConstants.java b/core/java/android/pim/vcard/VCardConstants.java
deleted file mode 100644
index 8c07126..0000000
--- a/core/java/android/pim/vcard/VCardConstants.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.pim.vcard;
-
-/**
- * Constants used in both exporter and importer code.
- */
-public class VCardConstants {
- public static final String VERSION_V21 = "2.1";
- public static final String VERSION_V30 = "3.0";
-
- // The property names valid both in vCard 2.1 and 3.0.
- public static final String PROPERTY_BEGIN = "BEGIN";
- public static final String PROPERTY_VERSION = "VERSION";
- public static final String PROPERTY_N = "N";
- public static final String PROPERTY_FN = "FN";
- public static final String PROPERTY_ADR = "ADR";
- public static final String PROPERTY_EMAIL = "EMAIL";
- public static final String PROPERTY_NOTE = "NOTE";
- public static final String PROPERTY_ORG = "ORG";
- public static final String PROPERTY_SOUND = "SOUND"; // Not fully supported.
- public static final String PROPERTY_TEL = "TEL";
- public static final String PROPERTY_TITLE = "TITLE";
- public static final String PROPERTY_ROLE = "ROLE";
- public static final String PROPERTY_PHOTO = "PHOTO";
- public static final String PROPERTY_LOGO = "LOGO";
- public static final String PROPERTY_URL = "URL";
- public static final String PROPERTY_BDAY = "BDAY"; // Birthday
- public static final String PROPERTY_END = "END";
-
- // Valid property names not supported (not appropriately handled) by our vCard importer now.
- public static final String PROPERTY_REV = "REV";
- public static final String PROPERTY_AGENT = "AGENT";
-
- // Available in vCard 3.0. Shoud not use when composing vCard 2.1 file.
- public static final String PROPERTY_NAME = "NAME";
- public static final String PROPERTY_NICKNAME = "NICKNAME";
- public static final String PROPERTY_SORT_STRING = "SORT-STRING";
-
- // De-fact property values expressing phonetic names.
- public static final String PROPERTY_X_PHONETIC_FIRST_NAME = "X-PHONETIC-FIRST-NAME";
- public static final String PROPERTY_X_PHONETIC_MIDDLE_NAME = "X-PHONETIC-MIDDLE-NAME";
- public static final String PROPERTY_X_PHONETIC_LAST_NAME = "X-PHONETIC-LAST-NAME";
-
- // Properties both ContactsStruct in Eclair and de-fact vCard extensions
- // shown in http://en.wikipedia.org/wiki/VCard support are defined here.
- public static final String PROPERTY_X_AIM = "X-AIM";
- public static final String PROPERTY_X_MSN = "X-MSN";
- public static final String PROPERTY_X_YAHOO = "X-YAHOO";
- public static final String PROPERTY_X_ICQ = "X-ICQ";
- public static final String PROPERTY_X_JABBER = "X-JABBER";
- public static final String PROPERTY_X_GOOGLE_TALK = "X-GOOGLE-TALK";
- public static final String PROPERTY_X_SKYPE_USERNAME = "X-SKYPE-USERNAME";
- // Properties only ContactsStruct has. We alse use this.
- public static final String PROPERTY_X_QQ = "X-QQ";
- public static final String PROPERTY_X_NETMEETING = "X-NETMEETING";
-
- // Phone number for Skype, available as usual phone.
- public static final String PROPERTY_X_SKYPE_PSTNNUMBER = "X-SKYPE-PSTNNUMBER";
-
- // Property for Android-specific fields.
- public static final String PROPERTY_X_ANDROID_CUSTOM = "X-ANDROID-CUSTOM";
-
- // Properties for DoCoMo vCard.
- public static final String PROPERTY_X_CLASS = "X-CLASS";
- public static final String PROPERTY_X_REDUCTION = "X-REDUCTION";
- public static final String PROPERTY_X_NO = "X-NO";
- public static final String PROPERTY_X_DCM_HMN_MODE = "X-DCM-HMN-MODE";
-
- public static final String PARAM_TYPE = "TYPE";
-
- public static final String PARAM_TYPE_HOME = "HOME";
- public static final String PARAM_TYPE_WORK = "WORK";
- public static final String PARAM_TYPE_FAX = "FAX";
- public static final String PARAM_TYPE_CELL = "CELL";
- public static final String PARAM_TYPE_VOICE = "VOICE";
- public static final String PARAM_TYPE_INTERNET = "INTERNET";
-
- // Abbreviation of "prefered" according to vCard 2.1 specification.
- // We interpret this value as "primary" property during import/export.
- //
- // Note: Both vCard specs does not mention anything about the requirement for this parameter,
- // but there may be some vCard importer which will get confused with more than
- // one "PREF"s in one property name, while Android accepts them.
- public static final String PARAM_TYPE_PREF = "PREF";
-
- // Phone type parameters valid in vCard and known to ContactsContract, but not so common.
- public static final String PARAM_TYPE_CAR = "CAR";
- public static final String PARAM_TYPE_ISDN = "ISDN";
- public static final String PARAM_TYPE_PAGER = "PAGER";
- public static final String PARAM_TYPE_TLX = "TLX"; // Telex
-
- // Phone types existing in vCard 2.1 but not known to ContactsContract.
- public static final String PARAM_TYPE_MODEM = "MODEM";
- public static final String PARAM_TYPE_MSG = "MSG";
- public static final String PARAM_TYPE_BBS = "BBS";
- public static final String PARAM_TYPE_VIDEO = "VIDEO";
-
- // TYPE parameters for Phones, which are not formally valid in vCard (at least 2.1).
- // These types are basically encoded to "X-" parameters when composing vCard.
- // Parser passes these when "X-" is added to the parameter or not.
- public static final String PARAM_PHONE_EXTRA_TYPE_CALLBACK = "CALLBACK";
- public static final String PARAM_PHONE_EXTRA_TYPE_RADIO = "RADIO";
- public static final String PARAM_PHONE_EXTRA_TYPE_TTY_TDD = "TTY-TDD";
- public static final String PARAM_PHONE_EXTRA_TYPE_ASSISTANT = "ASSISTANT";
- // vCard composer translates this type to "WORK" + "PREF". Just for parsing.
- public static final String PARAM_PHONE_EXTRA_TYPE_COMPANY_MAIN = "COMPANY-MAIN";
- // vCard composer translates this type to "VOICE" Just for parsing.
- public static final String PARAM_PHONE_EXTRA_TYPE_OTHER = "OTHER";
-
- // TYPE parameters for postal addresses.
- public static final String PARAM_ADR_TYPE_PARCEL = "PARCEL";
- public static final String PARAM_ADR_TYPE_DOM = "DOM";
- public static final String PARAM_ADR_TYPE_INTL = "INTL";
-
- // TYPE parameters not officially valid but used in some vCard exporter.
- // Do not use in composer side.
- public static final String PARAM_EXTRA_TYPE_COMPANY = "COMPANY";
-
- // DoCoMo specific type parameter. Used with "SOUND" property, which is alternate of SORT-STRING in
- // vCard 3.0.
- public static final String PARAM_TYPE_X_IRMC_N = "X-IRMC-N";
-
- public interface ImportOnly {
- public static final String PROPERTY_X_NICKNAME = "X-NICKNAME";
- // Some device emits this "X-" parameter for expressing Google Talk,
- // which is specifically invalid but should be always properly accepted, and emitted
- // in some special case (for that device/application).
- public static final String PROPERTY_X_GOOGLE_TALK_WITH_SPACE = "X-GOOGLE TALK";
- }
-
- /* package */ static final int MAX_DATA_COLUMN = 15;
-
- /* package */ static final int MAX_CHARACTER_NUMS_QP = 76;
- static final int MAX_CHARACTER_NUMS_BASE64_V30 = 75;
-
- private VCardConstants() {
- }
-}
\ No newline at end of file
diff --git a/core/java/android/pim/vcard/VCardEntry.java b/core/java/android/pim/vcard/VCardEntry.java
deleted file mode 100644
index 7c7e9b8..0000000
--- a/core/java/android/pim/vcard/VCardEntry.java
+++ /dev/null
@@ -1,1447 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.pim.vcard;
-
-import android.accounts.Account;
-import android.content.ContentProviderOperation;
-import android.content.ContentProviderResult;
-import android.content.ContentResolver;
-import android.content.OperationApplicationException;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.RemoteException;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.Contacts;
-import android.provider.ContactsContract.Data;
-import android.provider.ContactsContract.Groups;
-import android.provider.ContactsContract.RawContacts;
-import android.provider.ContactsContract.CommonDataKinds.Email;
-import android.provider.ContactsContract.CommonDataKinds.Event;
-import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
-import android.provider.ContactsContract.CommonDataKinds.Im;
-import android.provider.ContactsContract.CommonDataKinds.Nickname;
-import android.provider.ContactsContract.CommonDataKinds.Note;
-import android.provider.ContactsContract.CommonDataKinds.Organization;
-import android.provider.ContactsContract.CommonDataKinds.Phone;
-import android.provider.ContactsContract.CommonDataKinds.Photo;
-import android.provider.ContactsContract.CommonDataKinds.StructuredName;
-import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
-import android.provider.ContactsContract.CommonDataKinds.Website;
-import android.telephony.PhoneNumberUtils;
-import android.text.TextUtils;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-
-/**
- * This class bridges between data structure of Contact app and VCard data.
- */
-public class VCardEntry {
- private static final String LOG_TAG = "VCardEntry";
-
- private final static int DEFAULT_ORGANIZATION_TYPE = Organization.TYPE_WORK;
-
- private static final String ACCOUNT_TYPE_GOOGLE = "com.google";
- private static final String GOOGLE_MY_CONTACTS_GROUP = "System Group: My Contacts";
-
- private static final Map<String, Integer> sImMap = new HashMap<String, Integer>();
-
- static {
- sImMap.put(VCardConstants.PROPERTY_X_AIM, Im.PROTOCOL_AIM);
- sImMap.put(VCardConstants.PROPERTY_X_MSN, Im.PROTOCOL_MSN);
- sImMap.put(VCardConstants.PROPERTY_X_YAHOO, Im.PROTOCOL_YAHOO);
- sImMap.put(VCardConstants.PROPERTY_X_ICQ, Im.PROTOCOL_ICQ);
- sImMap.put(VCardConstants.PROPERTY_X_JABBER, Im.PROTOCOL_JABBER);
- sImMap.put(VCardConstants.PROPERTY_X_SKYPE_USERNAME, Im.PROTOCOL_SKYPE);
- sImMap.put(VCardConstants.PROPERTY_X_GOOGLE_TALK, Im.PROTOCOL_GOOGLE_TALK);
- sImMap.put(VCardConstants.ImportOnly.PROPERTY_X_GOOGLE_TALK_WITH_SPACE,
- Im.PROTOCOL_GOOGLE_TALK);
- }
-
- static public class PhoneData {
- public final int type;
- public final String data;
- public final String label;
- // isPrimary is changable only when there's no appropriate one existing in
- // the original VCard.
- public boolean isPrimary;
- public PhoneData(int type, String data, String label, boolean isPrimary) {
- this.type = type;
- this.data = data;
- this.label = label;
- this.isPrimary = isPrimary;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (!(obj instanceof PhoneData)) {
- return false;
- }
- PhoneData phoneData = (PhoneData)obj;
- return (type == phoneData.type && data.equals(phoneData.data) &&
- label.equals(phoneData.label) && isPrimary == phoneData.isPrimary);
- }
-
- @Override
- public String toString() {
- return String.format("type: %d, data: %s, label: %s, isPrimary: %s",
- type, data, label, isPrimary);
- }
- }
-
- static public class EmailData {
- public final int type;
- public final String data;
- // Used only when TYPE is TYPE_CUSTOM.
- public final String label;
- // isPrimary is changable only when there's no appropriate one existing in
- // the original VCard.
- public boolean isPrimary;
- public EmailData(int type, String data, String label, boolean isPrimary) {
- this.type = type;
- this.data = data;
- this.label = label;
- this.isPrimary = isPrimary;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (!(obj instanceof EmailData)) {
- return false;
- }
- EmailData emailData = (EmailData)obj;
- return (type == emailData.type && data.equals(emailData.data) &&
- label.equals(emailData.label) && isPrimary == emailData.isPrimary);
- }
-
- @Override
- public String toString() {
- return String.format("type: %d, data: %s, label: %s, isPrimary: %s",
- type, data, label, isPrimary);
- }
- }
-
- static public class PostalData {
- // Determined by vCard spec.
- // PO Box, Extended Addr, Street, Locality, Region, Postal Code, Country Name
- public static final int ADDR_MAX_DATA_SIZE = 7;
- private final String[] dataArray;
- public final String pobox;
- public final String extendedAddress;
- public final String street;
- public final String localty;
- public final String region;
- public final String postalCode;
- public final String country;
- public final int type;
- public final String label;
- public boolean isPrimary;
-
- public PostalData(final int type, final List<String> propValueList,
- final String label, boolean isPrimary) {
- this.type = type;
- dataArray = new String[ADDR_MAX_DATA_SIZE];
-
- int size = propValueList.size();
- if (size > ADDR_MAX_DATA_SIZE) {
- size = ADDR_MAX_DATA_SIZE;
- }
-
- // adr-value = 0*6(text-value ";") text-value
- // ; PO Box, Extended Address, Street, Locality, Region, Postal
- // ; Code, Country Name
- //
- // Use Iterator assuming List may be LinkedList, though actually it is
- // always ArrayList in the current implementation.
- int i = 0;
- for (String addressElement : propValueList) {
- dataArray[i] = addressElement;
- if (++i >= size) {
- break;
- }
- }
- while (i < ADDR_MAX_DATA_SIZE) {
- dataArray[i++] = null;
- }
-
- this.pobox = dataArray[0];
- this.extendedAddress = dataArray[1];
- this.street = dataArray[2];
- this.localty = dataArray[3];
- this.region = dataArray[4];
- this.postalCode = dataArray[5];
- this.country = dataArray[6];
- this.label = label;
- this.isPrimary = isPrimary;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (!(obj instanceof PostalData)) {
- return false;
- }
- final PostalData postalData = (PostalData)obj;
- return (Arrays.equals(dataArray, postalData.dataArray) &&
- (type == postalData.type &&
- (type == StructuredPostal.TYPE_CUSTOM ?
- (label == postalData.label) : true)) &&
- (isPrimary == postalData.isPrimary));
- }
-
- public String getFormattedAddress(final int vcardType) {
- StringBuilder builder = new StringBuilder();
- boolean empty = true;
- if (VCardConfig.isJapaneseDevice(vcardType)) {
- // In Japan, the order is reversed.
- for (int i = ADDR_MAX_DATA_SIZE - 1; i >= 0; i--) {
- String addressPart = dataArray[i];
- if (!TextUtils.isEmpty(addressPart)) {
- if (!empty) {
- builder.append(' ');
- } else {
- empty = false;
- }
- builder.append(addressPart);
- }
- }
- } else {
- for (int i = 0; i < ADDR_MAX_DATA_SIZE; i++) {
- String addressPart = dataArray[i];
- if (!TextUtils.isEmpty(addressPart)) {
- if (!empty) {
- builder.append(' ');
- } else {
- empty = false;
- }
- builder.append(addressPart);
- }
- }
- }
-
- return builder.toString().trim();
- }
-
- @Override
- public String toString() {
- return String.format("type: %d, label: %s, isPrimary: %s",
- type, label, isPrimary);
- }
- }
-
- static public class OrganizationData {
- public final int type;
- // non-final is Intentional: we may change the values since this info is separated into
- // two parts in vCard: "ORG" + "TITLE".
- public String companyName;
- public String departmentName;
- public String titleName;
- public boolean isPrimary;
-
- public OrganizationData(int type,
- String companyName,
- String departmentName,
- String titleName,
- boolean isPrimary) {
- this.type = type;
- this.companyName = companyName;
- this.departmentName = departmentName;
- this.titleName = titleName;
- this.isPrimary = isPrimary;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (!(obj instanceof OrganizationData)) {
- return false;
- }
- OrganizationData organization = (OrganizationData)obj;
- return (type == organization.type &&
- TextUtils.equals(companyName, organization.companyName) &&
- TextUtils.equals(departmentName, organization.departmentName) &&
- TextUtils.equals(titleName, organization.titleName) &&
- isPrimary == organization.isPrimary);
- }
-
- public String getFormattedString() {
- final StringBuilder builder = new StringBuilder();
- if (!TextUtils.isEmpty(companyName)) {
- builder.append(companyName);
- }
-
- if (!TextUtils.isEmpty(departmentName)) {
- if (builder.length() > 0) {
- builder.append(", ");
- }
- builder.append(departmentName);
- }
-
- if (!TextUtils.isEmpty(titleName)) {
- if (builder.length() > 0) {
- builder.append(", ");
- }
- builder.append(titleName);
- }
-
- return builder.toString();
- }
-
- @Override
- public String toString() {
- return String.format(
- "type: %d, company: %s, department: %s, title: %s, isPrimary: %s",
- type, companyName, departmentName, titleName, isPrimary);
- }
- }
-
- static public class ImData {
- public final int protocol;
- public final String customProtocol;
- public final int type;
- public final String data;
- public final boolean isPrimary;
-
- public ImData(final int protocol, final String customProtocol, final int type,
- final String data, final boolean isPrimary) {
- this.protocol = protocol;
- this.customProtocol = customProtocol;
- this.type = type;
- this.data = data;
- this.isPrimary = isPrimary;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (!(obj instanceof ImData)) {
- return false;
- }
- ImData imData = (ImData)obj;
- return (type == imData.type && protocol == imData.protocol
- && (customProtocol != null ? customProtocol.equals(imData.customProtocol) :
- (imData.customProtocol == null))
- && (data != null ? data.equals(imData.data) : (imData.data == null))
- && isPrimary == imData.isPrimary);
- }
-
- @Override
- public String toString() {
- return String.format(
- "type: %d, protocol: %d, custom_protcol: %s, data: %s, isPrimary: %s",
- type, protocol, customProtocol, data, isPrimary);
- }
- }
-
- public static class PhotoData {
- public static final String FORMAT_FLASH = "SWF";
- public final int type;
- public final String formatName; // used when type is not defined in ContactsContract.
- public final byte[] photoBytes;
- public final boolean isPrimary;
-
- public PhotoData(int type, String formatName, byte[] photoBytes, boolean isPrimary) {
- this.type = type;
- this.formatName = formatName;
- this.photoBytes = photoBytes;
- this.isPrimary = isPrimary;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (!(obj instanceof PhotoData)) {
- return false;
- }
- PhotoData photoData = (PhotoData)obj;
- return (type == photoData.type &&
- (formatName == null ? (photoData.formatName == null) :
- formatName.equals(photoData.formatName)) &&
- (Arrays.equals(photoBytes, photoData.photoBytes)) &&
- (isPrimary == photoData.isPrimary));
- }
-
- @Override
- public String toString() {
- return String.format("type: %d, format: %s: size: %d, isPrimary: %s",
- type, formatName, photoBytes.length, isPrimary);
- }
- }
-
- /* package */ static class Property {
- private String mPropertyName;
- private Map<String, Collection<String>> mParameterMap =
- new HashMap<String, Collection<String>>();
- private List<String> mPropertyValueList = new ArrayList<String>();
- private byte[] mPropertyBytes;
-
- public void setPropertyName(final String propertyName) {
- mPropertyName = propertyName;
- }
-
- public void addParameter(final String paramName, final String paramValue) {
- Collection<String> values;
- if (!mParameterMap.containsKey(paramName)) {
- if (paramName.equals("TYPE")) {
- values = new HashSet<String>();
- } else {
- values = new ArrayList<String>();
- }
- mParameterMap.put(paramName, values);
- } else {
- values = mParameterMap.get(paramName);
- }
- values.add(paramValue);
- }
-
- public void addToPropertyValueList(final String propertyValue) {
- mPropertyValueList.add(propertyValue);
- }
-
- public void setPropertyBytes(final byte[] propertyBytes) {
- mPropertyBytes = propertyBytes;
- }
-
- public final Collection<String> getParameters(String type) {
- return mParameterMap.get(type);
- }
-
- public final List<String> getPropertyValueList() {
- return mPropertyValueList;
- }
-
- public void clear() {
- mPropertyName = null;
- mParameterMap.clear();
- mPropertyValueList.clear();
- mPropertyBytes = null;
- }
- }
-
- private String mFamilyName;
- private String mGivenName;
- private String mMiddleName;
- private String mPrefix;
- private String mSuffix;
-
- // Used only when no family nor given name is found.
- private String mFullName;
-
- private String mPhoneticFamilyName;
- private String mPhoneticGivenName;
- private String mPhoneticMiddleName;
-
- private String mPhoneticFullName;
-
- private List<String> mNickNameList;
-
- private String mDisplayName;
-
- private String mBirthday;
-
- private List<String> mNoteList;
- private List<PhoneData> mPhoneList;
- private List<EmailData> mEmailList;
- private List<PostalData> mPostalList;
- private List<OrganizationData> mOrganizationList;
- private List<ImData> mImList;
- private List<PhotoData> mPhotoList;
- private List<String> mWebsiteList;
- private List<List<String>> mAndroidCustomPropertyList;
-
- private final int mVCardType;
- private final Account mAccount;
-
- public VCardEntry() {
- this(VCardConfig.VCARD_TYPE_V21_GENERIC_UTF8);
- }
-
- public VCardEntry(int vcardType) {
- this(vcardType, null);
- }
-
- public VCardEntry(int vcardType, Account account) {
- mVCardType = vcardType;
- mAccount = account;
- }
-
- private void addPhone(int type, String data, String label, boolean isPrimary) {
- if (mPhoneList == null) {
- mPhoneList = new ArrayList<PhoneData>();
- }
- final StringBuilder builder = new StringBuilder();
- final String trimed = data.trim();
- final String formattedNumber;
- if (type == Phone.TYPE_PAGER || VCardConfig.refrainPhoneNumberFormatting(mVCardType)) {
- formattedNumber = trimed;
- } else {
- final int length = trimed.length();
- for (int i = 0; i < length; i++) {
- char ch = trimed.charAt(i);
- if (('0' <= ch && ch <= '9') || (i == 0 && ch == '+')) {
- builder.append(ch);
- }
- }
-
- // Use NANP in default when there's no information about locale.
- final int formattingType = VCardUtils.getPhoneNumberFormat(mVCardType);
- formattedNumber = PhoneNumberUtils.formatNumber(builder.toString(), formattingType);
- }
- PhoneData phoneData = new PhoneData(type, formattedNumber, label, isPrimary);
- mPhoneList.add(phoneData);
- }
-
- private void addNickName(final String nickName) {
- if (mNickNameList == null) {
- mNickNameList = new ArrayList<String>();
- }
- mNickNameList.add(nickName);
- }
-
- private void addEmail(int type, String data, String label, boolean isPrimary){
- if (mEmailList == null) {
- mEmailList = new ArrayList<EmailData>();
- }
- mEmailList.add(new EmailData(type, data, label, isPrimary));
- }
-
- private void addPostal(int type, List<String> propValueList, String label, boolean isPrimary){
- if (mPostalList == null) {
- mPostalList = new ArrayList<PostalData>(0);
- }
- mPostalList.add(new PostalData(type, propValueList, label, isPrimary));
- }
-
- /**
- * Should be called via {@link #handleOrgValue(int, List, boolean)} or
- * {@link #handleTitleValue(String)}.
- */
- private void addNewOrganization(int type, final String companyName,
- final String departmentName,
- final String titleName, boolean isPrimary) {
- if (mOrganizationList == null) {
- mOrganizationList = new ArrayList<OrganizationData>();
- }
- mOrganizationList.add(new OrganizationData(type, companyName,
- departmentName, titleName, isPrimary));
- }
-
- private static final List<String> sEmptyList =
- Collections.unmodifiableList(new ArrayList<String>(0));
-
- /**
- * Set "ORG" related values to the appropriate data. If there's more than one
- * {@link OrganizationData} objects, this input data are attached to the last one which
- * does not have valid values (not including empty but only null). If there's no
- * {@link OrganizationData} object, a new {@link OrganizationData} is created,
- * whose title is set to null.
- */
- private void handleOrgValue(final int type, List<String> orgList, boolean isPrimary) {
- if (orgList == null) {
- orgList = sEmptyList;
- }
- final String companyName;
- final String departmentName;
- final int size = orgList.size();
- switch (size) {
- case 0: {
- companyName = "";
- departmentName = null;
- break;
- }
- case 1: {
- companyName = orgList.get(0);
- departmentName = null;
- break;
- }
- default: { // More than 1.
- companyName = orgList.get(0);
- // We're not sure which is the correct string for department.
- // In order to keep all the data, concatinate the rest of elements.
- StringBuilder builder = new StringBuilder();
- for (int i = 1; i < size; i++) {
- if (i > 1) {
- builder.append(' ');
- }
- builder.append(orgList.get(i));
- }
- departmentName = builder.toString();
- }
- }
- if (mOrganizationList == null) {
- // Create new first organization entry, with "null" title which may be
- // added via handleTitleValue().
- addNewOrganization(type, companyName, departmentName, null, isPrimary);
- return;
- }
- for (OrganizationData organizationData : mOrganizationList) {
- // Not use TextUtils.isEmpty() since ORG was set but the elements might be empty.
- // e.g. "ORG;PREF:;" -> Both companyName and departmentName become empty but not null.
- if (organizationData.companyName == null &&
- organizationData.departmentName == null) {
- // Probably the "TITLE" property comes before the "ORG" property via
- // handleTitleLine().
- organizationData.companyName = companyName;
- organizationData.departmentName = departmentName;
- organizationData.isPrimary = isPrimary;
- return;
- }
- }
- // No OrganizatioData is available. Create another one, with "null" title, which may be
- // added via handleTitleValue().
- addNewOrganization(type, companyName, departmentName, null, isPrimary);
- }
-
- /**
- * Set "title" value to the appropriate data. If there's more than one
- * OrganizationData objects, this input is attached to the last one which does not
- * have valid title value (not including empty but only null). If there's no
- * OrganizationData object, a new OrganizationData is created, whose company name is
- * set to null.
- */
- private void handleTitleValue(final String title) {
- if (mOrganizationList == null) {
- // Create new first organization entry, with "null" other info, which may be
- // added via handleOrgValue().
- addNewOrganization(DEFAULT_ORGANIZATION_TYPE, null, null, title, false);
- return;
- }
- for (OrganizationData organizationData : mOrganizationList) {
- if (organizationData.titleName == null) {
- organizationData.titleName = title;
- return;
- }
- }
- // No Organization is available. Create another one, with "null" other info, which may be
- // added via handleOrgValue().
- addNewOrganization(DEFAULT_ORGANIZATION_TYPE, null, null, title, false);
- }
-
- private void addIm(int protocol, String customProtocol, int type,
- String propValue, boolean isPrimary) {
- if (mImList == null) {
- mImList = new ArrayList<ImData>();
- }
- mImList.add(new ImData(protocol, customProtocol, type, propValue, isPrimary));
- }
-
- private void addNote(final String note) {
- if (mNoteList == null) {
- mNoteList = new ArrayList<String>(1);
- }
- mNoteList.add(note);
- }
-
- private void addPhotoBytes(String formatName, byte[] photoBytes, boolean isPrimary) {
- if (mPhotoList == null) {
- mPhotoList = new ArrayList<PhotoData>(1);
- }
- final PhotoData photoData = new PhotoData(0, null, photoBytes, isPrimary);
- mPhotoList.add(photoData);
- }
-
- @SuppressWarnings("fallthrough")
- private void handleNProperty(List<String> elems) {
- // Family, Given, Middle, Prefix, Suffix. (1 - 5)
- int size;
- if (elems == null || (size = elems.size()) < 1) {
- return;
- }
- if (size > 5) {
- size = 5;
- }
-
- switch (size) {
- // fallthrough
- case 5: mSuffix = elems.get(4);
- case 4: mPrefix = elems.get(3);
- case 3: mMiddleName = elems.get(2);
- case 2: mGivenName = elems.get(1);
- default: mFamilyName = elems.get(0);
- }
- }
-
- /**
- * Note: Some Japanese mobile phones use this field for phonetic name,
- * since vCard 2.1 does not have "SORT-STRING" type.
- * Also, in some cases, the field has some ';'s in it.
- * Assume the ';' means the same meaning in N property
- */
- @SuppressWarnings("fallthrough")
- private void handlePhoneticNameFromSound(List<String> elems) {
- if (!(TextUtils.isEmpty(mPhoneticFamilyName) &&
- TextUtils.isEmpty(mPhoneticMiddleName) &&
- TextUtils.isEmpty(mPhoneticGivenName))) {
- // This means the other properties like "X-PHONETIC-FIRST-NAME" was already found.
- // Ignore "SOUND;X-IRMC-N".
- return;
- }
-
- int size;
- if (elems == null || (size = elems.size()) < 1) {
- return;
- }
-
- // Assume that the order is "Family, Given, Middle".
- // This is not from specification but mere assumption. Some Japanese phones use this order.
- if (size > 3) {
- size = 3;
- }
-
- if (elems.get(0).length() > 0) {
- boolean onlyFirstElemIsNonEmpty = true;
- for (int i = 1; i < size; i++) {
- if (elems.get(i).length() > 0) {
- onlyFirstElemIsNonEmpty = false;
- break;
- }
- }
- if (onlyFirstElemIsNonEmpty) {
- final String[] namesArray = elems.get(0).split(" ");
- final int nameArrayLength = namesArray.length;
- if (nameArrayLength == 3) {
- // Assume the string is "Family Middle Given".
- mPhoneticFamilyName = namesArray[0];
- mPhoneticMiddleName = namesArray[1];
- mPhoneticGivenName = namesArray[2];
- } else if (nameArrayLength == 2) {
- // Assume the string is "Family Given" based on the Japanese mobile
- // phones' preference.
- mPhoneticFamilyName = namesArray[0];
- mPhoneticGivenName = namesArray[1];
- } else {
- mPhoneticFullName = elems.get(0);
- }
- return;
- }
- }
-
- switch (size) {
- // fallthrough
- case 3: mPhoneticMiddleName = elems.get(2);
- case 2: mPhoneticGivenName = elems.get(1);
- default: mPhoneticFamilyName = elems.get(0);
- }
- }
-
- public void addProperty(final Property property) {
- final String propName = property.mPropertyName;
- final Map<String, Collection<String>> paramMap = property.mParameterMap;
- final List<String> propValueList = property.mPropertyValueList;
- byte[] propBytes = property.mPropertyBytes;
-
- if (propValueList.size() == 0) {
- return;
- }
- final String propValue = listToString(propValueList).trim();
-
- if (propName.equals(VCardConstants.PROPERTY_VERSION)) {
- // vCard version. Ignore this.
- } else if (propName.equals(VCardConstants.PROPERTY_FN)) {
- mFullName = propValue;
- } else if (propName.equals(VCardConstants.PROPERTY_NAME) && mFullName == null) {
- // Only in vCard 3.0. Use this if FN, which must exist in vCard 3.0 but may not
- // actually exist in the real vCard data, does not exist.
- mFullName = propValue;
- } else if (propName.equals(VCardConstants.PROPERTY_N)) {
- handleNProperty(propValueList);
- } else if (propName.equals(VCardConstants.PROPERTY_SORT_STRING)) {
- mPhoneticFullName = propValue;
- } else if (propName.equals(VCardConstants.PROPERTY_NICKNAME) ||
- propName.equals(VCardConstants.ImportOnly.PROPERTY_X_NICKNAME)) {
- addNickName(propValue);
- } else if (propName.equals(VCardConstants.PROPERTY_SOUND)) {
- Collection<String> typeCollection = paramMap.get(VCardConstants.PARAM_TYPE);
- if (typeCollection != null
- && typeCollection.contains(VCardConstants.PARAM_TYPE_X_IRMC_N)) {
- // As of 2009-10-08, Parser side does not split a property value into separated
- // values using ';' (in other words, propValueList.size() == 1),
- // which is correct behavior from the view of vCard 2.1.
- // But we want it to be separated, so do the separation here.
- final List<String> phoneticNameList =
- VCardUtils.constructListFromValue(propValue,
- VCardConfig.isV30(mVCardType));
- handlePhoneticNameFromSound(phoneticNameList);
- } else {
- // Ignore this field since Android cannot understand what it is.
- }
- } else if (propName.equals(VCardConstants.PROPERTY_ADR)) {
- boolean valuesAreAllEmpty = true;
- for (String value : propValueList) {
- if (value.length() > 0) {
- valuesAreAllEmpty = false;
- break;
- }
- }
- if (valuesAreAllEmpty) {
- return;
- }
-
- int type = -1;
- String label = "";
- boolean isPrimary = false;
- Collection<String> typeCollection = paramMap.get(VCardConstants.PARAM_TYPE);
- if (typeCollection != null) {
- for (String typeString : typeCollection) {
- typeString = typeString.toUpperCase();
- if (typeString.equals(VCardConstants.PARAM_TYPE_PREF)) {
- isPrimary = true;
- } else if (typeString.equals(VCardConstants.PARAM_TYPE_HOME)) {
- type = StructuredPostal.TYPE_HOME;
- label = "";
- } else if (typeString.equals(VCardConstants.PARAM_TYPE_WORK) ||
- typeString.equalsIgnoreCase(VCardConstants.PARAM_EXTRA_TYPE_COMPANY)) {
- // "COMPANY" seems emitted by Windows Mobile, which is not
- // specifically supported by vCard 2.1. We assume this is same
- // as "WORK".
- type = StructuredPostal.TYPE_WORK;
- label = "";
- } else if (typeString.equals(VCardConstants.PARAM_ADR_TYPE_PARCEL) ||
- typeString.equals(VCardConstants.PARAM_ADR_TYPE_DOM) ||
- typeString.equals(VCardConstants.PARAM_ADR_TYPE_INTL)) {
- // We do not have any appropriate way to store this information.
- } else {
- if (typeString.startsWith("X-") && type < 0) {
- typeString = typeString.substring(2);
- }
- // vCard 3.0 allows iana-token. Also some vCard 2.1 exporters
- // emit non-standard types. We do not handle their values now.
- type = StructuredPostal.TYPE_CUSTOM;
- label = typeString;
- }
- }
- }
- // We use "HOME" as default
- if (type < 0) {
- type = StructuredPostal.TYPE_HOME;
- }
-
- addPostal(type, propValueList, label, isPrimary);
- } else if (propName.equals(VCardConstants.PROPERTY_EMAIL)) {
- int type = -1;
- String label = null;
- boolean isPrimary = false;
- Collection<String> typeCollection = paramMap.get(VCardConstants.PARAM_TYPE);
- if (typeCollection != null) {
- for (String typeString : typeCollection) {
- typeString = typeString.toUpperCase();
- if (typeString.equals(VCardConstants.PARAM_TYPE_PREF)) {
- isPrimary = true;
- } else if (typeString.equals(VCardConstants.PARAM_TYPE_HOME)) {
- type = Email.TYPE_HOME;
- } else if (typeString.equals(VCardConstants.PARAM_TYPE_WORK)) {
- type = Email.TYPE_WORK;
- } else if (typeString.equals(VCardConstants.PARAM_TYPE_CELL)) {
- type = Email.TYPE_MOBILE;
- } else {
- if (typeString.startsWith("X-") && type < 0) {
- typeString = typeString.substring(2);
- }
- // vCard 3.0 allows iana-token.
- // We may have INTERNET (specified in vCard spec),
- // SCHOOL, etc.
- type = Email.TYPE_CUSTOM;
- label = typeString;
- }
- }
- }
- if (type < 0) {
- type = Email.TYPE_OTHER;
- }
- addEmail(type, propValue, label, isPrimary);
- } else if (propName.equals(VCardConstants.PROPERTY_ORG)) {
- // vCard specification does not specify other types.
- final int type = Organization.TYPE_WORK;
- boolean isPrimary = false;
- Collection<String> typeCollection = paramMap.get(VCardConstants.PARAM_TYPE);
- if (typeCollection != null) {
- for (String typeString : typeCollection) {
- if (typeString.equals(VCardConstants.PARAM_TYPE_PREF)) {
- isPrimary = true;
- }
- }
- }
- handleOrgValue(type, propValueList, isPrimary);
- } else if (propName.equals(VCardConstants.PROPERTY_TITLE)) {
- handleTitleValue(propValue);
- } else if (propName.equals(VCardConstants.PROPERTY_ROLE)) {
- // This conflicts with TITLE. Ignore for now...
- // handleTitleValue(propValue);
- } else if (propName.equals(VCardConstants.PROPERTY_PHOTO) ||
- propName.equals(VCardConstants.PROPERTY_LOGO)) {
- Collection<String> paramMapValue = paramMap.get("VALUE");
- if (paramMapValue != null && paramMapValue.contains("URL")) {
- // Currently we do not have appropriate example for testing this case.
- } else {
- final Collection<String> typeCollection = paramMap.get("TYPE");
- String formatName = null;
- boolean isPrimary = false;
- if (typeCollection != null) {
- for (String typeValue : typeCollection) {
- if (VCardConstants.PARAM_TYPE_PREF.equals(typeValue)) {
- isPrimary = true;
- } else if (formatName == null){
- formatName = typeValue;
- }
- }
- }
- addPhotoBytes(formatName, propBytes, isPrimary);
- }
- } else if (propName.equals(VCardConstants.PROPERTY_TEL)) {
- final Collection<String> typeCollection = paramMap.get(VCardConstants.PARAM_TYPE);
- final Object typeObject =
- VCardUtils.getPhoneTypeFromStrings(typeCollection, propValue);
- final int type;
- final String label;
- if (typeObject instanceof Integer) {
- type = (Integer)typeObject;
- label = null;
- } else {
- type = Phone.TYPE_CUSTOM;
- label = typeObject.toString();
- }
-
- final boolean isPrimary;
- if (typeCollection != null && typeCollection.contains(VCardConstants.PARAM_TYPE_PREF)) {
- isPrimary = true;
- } else {
- isPrimary = false;
- }
- addPhone(type, propValue, label, isPrimary);
- } else if (propName.equals(VCardConstants.PROPERTY_X_SKYPE_PSTNNUMBER)) {
- // The phone number available via Skype.
- Collection<String> typeCollection = paramMap.get(VCardConstants.PARAM_TYPE);
- final int type = Phone.TYPE_OTHER;
- final boolean isPrimary;
- if (typeCollection != null && typeCollection.contains(VCardConstants.PARAM_TYPE_PREF)) {
- isPrimary = true;
- } else {
- isPrimary = false;
- }
- addPhone(type, propValue, null, isPrimary);
- } else if (sImMap.containsKey(propName)) {
- final int protocol = sImMap.get(propName);
- boolean isPrimary = false;
- int type = -1;
- final Collection<String> typeCollection = paramMap.get(VCardConstants.PARAM_TYPE);
- if (typeCollection != null) {
- for (String typeString : typeCollection) {
- if (typeString.equals(VCardConstants.PARAM_TYPE_PREF)) {
- isPrimary = true;
- } else if (type < 0) {
- if (typeString.equalsIgnoreCase(VCardConstants.PARAM_TYPE_HOME)) {
- type = Im.TYPE_HOME;
- } else if (typeString.equalsIgnoreCase(VCardConstants.PARAM_TYPE_WORK)) {
- type = Im.TYPE_WORK;
- }
- }
- }
- }
- if (type < 0) {
- type = Phone.TYPE_HOME;
- }
- addIm(protocol, null, type, propValue, isPrimary);
- } else if (propName.equals(VCardConstants.PROPERTY_NOTE)) {
- addNote(propValue);
- } else if (propName.equals(VCardConstants.PROPERTY_URL)) {
- if (mWebsiteList == null) {
- mWebsiteList = new ArrayList<String>(1);
- }
- mWebsiteList.add(propValue);
- } else if (propName.equals(VCardConstants.PROPERTY_BDAY)) {
- mBirthday = propValue;
- } else if (propName.equals(VCardConstants.PROPERTY_X_PHONETIC_FIRST_NAME)) {
- mPhoneticGivenName = propValue;
- } else if (propName.equals(VCardConstants.PROPERTY_X_PHONETIC_MIDDLE_NAME)) {
- mPhoneticMiddleName = propValue;
- } else if (propName.equals(VCardConstants.PROPERTY_X_PHONETIC_LAST_NAME)) {
- mPhoneticFamilyName = propValue;
- } else if (propName.equals(VCardConstants.PROPERTY_X_ANDROID_CUSTOM)) {
- final List<String> customPropertyList =
- VCardUtils.constructListFromValue(propValue,
- VCardConfig.isV30(mVCardType));
- handleAndroidCustomProperty(customPropertyList);
- /*} else if (propName.equals("REV")) {
- // Revision of this VCard entry. I think we can ignore this.
- } else if (propName.equals("UID")) {
- } else if (propName.equals("KEY")) {
- // Type is X509 or PGP? I don't know how to handle this...
- } else if (propName.equals("MAILER")) {
- } else if (propName.equals("TZ")) {
- } else if (propName.equals("GEO")) {
- } else if (propName.equals("CLASS")) {
- // vCard 3.0 only.
- // e.g. CLASS:CONFIDENTIAL
- } else if (propName.equals("PROFILE")) {
- // VCard 3.0 only. Must be "VCARD". I think we can ignore this.
- } else if (propName.equals("CATEGORIES")) {
- // VCard 3.0 only.
- // e.g. CATEGORIES:INTERNET,IETF,INDUSTRY,INFORMATION TECHNOLOGY
- } else if (propName.equals("SOURCE")) {
- // VCard 3.0 only.
- } else if (propName.equals("PRODID")) {
- // VCard 3.0 only.
- // To specify the identifier for the product that created
- // the vCard object.*/
- } else {
- // Unknown X- words and IANA token.
- }
- }
-
- private void handleAndroidCustomProperty(final List<String> customPropertyList) {
- if (mAndroidCustomPropertyList == null) {
- mAndroidCustomPropertyList = new ArrayList<List<String>>();
- }
- mAndroidCustomPropertyList.add(customPropertyList);
- }
-
- /**
- * Construct the display name. The constructed data must not be null.
- */
- private void constructDisplayName() {
- // FullName (created via "FN" or "NAME" field) is prefered.
- if (!TextUtils.isEmpty(mFullName)) {
- mDisplayName = mFullName;
- } else if (!(TextUtils.isEmpty(mFamilyName) && TextUtils.isEmpty(mGivenName))) {
- mDisplayName = VCardUtils.constructNameFromElements(mVCardType,
- mFamilyName, mMiddleName, mGivenName, mPrefix, mSuffix);
- } else if (!(TextUtils.isEmpty(mPhoneticFamilyName) &&
- TextUtils.isEmpty(mPhoneticGivenName))) {
- mDisplayName = VCardUtils.constructNameFromElements(mVCardType,
- mPhoneticFamilyName, mPhoneticMiddleName, mPhoneticGivenName);
- } else if (mEmailList != null && mEmailList.size() > 0) {
- mDisplayName = mEmailList.get(0).data;
- } else if (mPhoneList != null && mPhoneList.size() > 0) {
- mDisplayName = mPhoneList.get(0).data;
- } else if (mPostalList != null && mPostalList.size() > 0) {
- mDisplayName = mPostalList.get(0).getFormattedAddress(mVCardType);
- } else if (mOrganizationList != null && mOrganizationList.size() > 0) {
- mDisplayName = mOrganizationList.get(0).getFormattedString();
- }
-
- if (mDisplayName == null) {
- mDisplayName = "";
- }
- }
-
- /**
- * Consolidate several fielsds (like mName) using name candidates,
- */
- public void consolidateFields() {
- constructDisplayName();
-
- if (mPhoneticFullName != null) {
- mPhoneticFullName = mPhoneticFullName.trim();
- }
- }
-
- public Uri pushIntoContentResolver(ContentResolver resolver) {
- ArrayList<ContentProviderOperation> operationList =
- new ArrayList<ContentProviderOperation>();
- // After applying the batch the first result's Uri is returned so it is important that
- // the RawContact is the first operation that gets inserted into the list
- ContentProviderOperation.Builder builder =
- ContentProviderOperation.newInsert(RawContacts.CONTENT_URI);
- String myGroupsId = null;
- if (mAccount != null) {
- builder.withValue(RawContacts.ACCOUNT_NAME, mAccount.name);
- builder.withValue(RawContacts.ACCOUNT_TYPE, mAccount.type);
-
- // Assume that caller side creates this group if it does not exist.
- if (ACCOUNT_TYPE_GOOGLE.equals(mAccount.type)) {
- final Cursor cursor = resolver.query(Groups.CONTENT_URI, new String[] {
- Groups.SOURCE_ID },
- Groups.TITLE + "=?", new String[] {
- GOOGLE_MY_CONTACTS_GROUP }, null);
- try {
- if (cursor != null && cursor.moveToFirst()) {
- myGroupsId = cursor.getString(0);
- }
- } finally {
- if (cursor != null) {
- cursor.close();
- }
- }
- }
- } else {
- builder.withValue(RawContacts.ACCOUNT_NAME, null);
- builder.withValue(RawContacts.ACCOUNT_TYPE, null);
- }
- operationList.add(builder.build());
-
- if (!nameFieldsAreEmpty()) {
- builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
- builder.withValueBackReference(StructuredName.RAW_CONTACT_ID, 0);
- builder.withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
-
- builder.withValue(StructuredName.GIVEN_NAME, mGivenName);
- builder.withValue(StructuredName.FAMILY_NAME, mFamilyName);
- builder.withValue(StructuredName.MIDDLE_NAME, mMiddleName);
- builder.withValue(StructuredName.PREFIX, mPrefix);
- builder.withValue(StructuredName.SUFFIX, mSuffix);
-
- if (!(TextUtils.isEmpty(mPhoneticGivenName)
- && TextUtils.isEmpty(mPhoneticFamilyName)
- && TextUtils.isEmpty(mPhoneticMiddleName))) {
- builder.withValue(StructuredName.PHONETIC_GIVEN_NAME, mPhoneticGivenName);
- builder.withValue(StructuredName.PHONETIC_FAMILY_NAME, mPhoneticFamilyName);
- builder.withValue(StructuredName.PHONETIC_MIDDLE_NAME, mPhoneticMiddleName);
- } else if (!TextUtils.isEmpty(mPhoneticFullName)) {
- builder.withValue(StructuredName.PHONETIC_GIVEN_NAME, mPhoneticFullName);
- }
-
- builder.withValue(StructuredName.DISPLAY_NAME, getDisplayName());
- operationList.add(builder.build());
- }
-
- if (mNickNameList != null && mNickNameList.size() > 0) {
- for (String nickName : mNickNameList) {
- builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
- builder.withValueBackReference(Nickname.RAW_CONTACT_ID, 0);
- builder.withValue(Data.MIMETYPE, Nickname.CONTENT_ITEM_TYPE);
- builder.withValue(Nickname.TYPE, Nickname.TYPE_DEFAULT);
- builder.withValue(Nickname.NAME, nickName);
- operationList.add(builder.build());
- }
- }
-
- if (mPhoneList != null) {
- for (PhoneData phoneData : mPhoneList) {
- builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
- builder.withValueBackReference(Phone.RAW_CONTACT_ID, 0);
- builder.withValue(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
-
- builder.withValue(Phone.TYPE, phoneData.type);
- if (phoneData.type == Phone.TYPE_CUSTOM) {
- builder.withValue(Phone.LABEL, phoneData.label);
- }
- builder.withValue(Phone.NUMBER, phoneData.data);
- if (phoneData.isPrimary) {
- builder.withValue(Phone.IS_PRIMARY, 1);
- }
- operationList.add(builder.build());
- }
- }
-
- if (mOrganizationList != null) {
- for (OrganizationData organizationData : mOrganizationList) {
- builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
- builder.withValueBackReference(Organization.RAW_CONTACT_ID, 0);
- builder.withValue(Data.MIMETYPE, Organization.CONTENT_ITEM_TYPE);
- builder.withValue(Organization.TYPE, organizationData.type);
- if (organizationData.companyName != null) {
- builder.withValue(Organization.COMPANY, organizationData.companyName);
- }
- if (organizationData.departmentName != null) {
- builder.withValue(Organization.DEPARTMENT, organizationData.departmentName);
- }
- if (organizationData.titleName != null) {
- builder.withValue(Organization.TITLE, organizationData.titleName);
- }
- if (organizationData.isPrimary) {
- builder.withValue(Organization.IS_PRIMARY, 1);
- }
- operationList.add(builder.build());
- }
- }
-
- if (mEmailList != null) {
- for (EmailData emailData : mEmailList) {
- builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
- builder.withValueBackReference(Email.RAW_CONTACT_ID, 0);
- builder.withValue(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
-
- builder.withValue(Email.TYPE, emailData.type);
- if (emailData.type == Email.TYPE_CUSTOM) {
- builder.withValue(Email.LABEL, emailData.label);
- }
- builder.withValue(Email.DATA, emailData.data);
- if (emailData.isPrimary) {
- builder.withValue(Data.IS_PRIMARY, 1);
- }
- operationList.add(builder.build());
- }
- }
-
- if (mPostalList != null) {
- for (PostalData postalData : mPostalList) {
- builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
- VCardUtils.insertStructuredPostalDataUsingContactsStruct(
- mVCardType, builder, postalData);
- operationList.add(builder.build());
- }
- }
-
- if (mImList != null) {
- for (ImData imData : mImList) {
- builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
- builder.withValueBackReference(Im.RAW_CONTACT_ID, 0);
- builder.withValue(Data.MIMETYPE, Im.CONTENT_ITEM_TYPE);
- builder.withValue(Im.TYPE, imData.type);
- builder.withValue(Im.PROTOCOL, imData.protocol);
- if (imData.protocol == Im.PROTOCOL_CUSTOM) {
- builder.withValue(Im.CUSTOM_PROTOCOL, imData.customProtocol);
- }
- if (imData.isPrimary) {
- builder.withValue(Data.IS_PRIMARY, 1);
- }
- }
- }
-
- if (mNoteList != null) {
- for (String note : mNoteList) {
- builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
- builder.withValueBackReference(Note.RAW_CONTACT_ID, 0);
- builder.withValue(Data.MIMETYPE, Note.CONTENT_ITEM_TYPE);
- builder.withValue(Note.NOTE, note);
- operationList.add(builder.build());
- }
- }
-
- if (mPhotoList != null) {
- for (PhotoData photoData : mPhotoList) {
- builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
- builder.withValueBackReference(Photo.RAW_CONTACT_ID, 0);
- builder.withValue(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE);
- builder.withValue(Photo.PHOTO, photoData.photoBytes);
- if (photoData.isPrimary) {
- builder.withValue(Photo.IS_PRIMARY, 1);
- }
- operationList.add(builder.build());
- }
- }
-
- if (mWebsiteList != null) {
- for (String website : mWebsiteList) {
- builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
- builder.withValueBackReference(Website.RAW_CONTACT_ID, 0);
- builder.withValue(Data.MIMETYPE, Website.CONTENT_ITEM_TYPE);
- builder.withValue(Website.URL, website);
- // There's no information about the type of URL in vCard.
- // We use TYPE_HOMEPAGE for safety.
- builder.withValue(Website.TYPE, Website.TYPE_HOMEPAGE);
- operationList.add(builder.build());
- }
- }
-
- if (!TextUtils.isEmpty(mBirthday)) {
- builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
- builder.withValueBackReference(Event.RAW_CONTACT_ID, 0);
- builder.withValue(Data.MIMETYPE, Event.CONTENT_ITEM_TYPE);
- builder.withValue(Event.START_DATE, mBirthday);
- builder.withValue(Event.TYPE, Event.TYPE_BIRTHDAY);
- operationList.add(builder.build());
- }
-
- if (mAndroidCustomPropertyList != null) {
- for (List<String> customPropertyList : mAndroidCustomPropertyList) {
- int size = customPropertyList.size();
- if (size < 2 || TextUtils.isEmpty(customPropertyList.get(0))) {
- continue;
- } else if (size > VCardConstants.MAX_DATA_COLUMN + 1) {
- size = VCardConstants.MAX_DATA_COLUMN + 1;
- customPropertyList =
- customPropertyList.subList(0, VCardConstants.MAX_DATA_COLUMN + 2);
- }
-
- int i = 0;
- for (final String customPropertyValue : customPropertyList) {
- if (i == 0) {
- final String mimeType = customPropertyValue;
- builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
- builder.withValueBackReference(GroupMembership.RAW_CONTACT_ID, 0);
- builder.withValue(Data.MIMETYPE, mimeType);
- } else { // 1 <= i && i <= MAX_DATA_COLUMNS
- if (!TextUtils.isEmpty(customPropertyValue)) {
- builder.withValue("data" + i, customPropertyValue);
- }
- }
-
- i++;
- }
- operationList.add(builder.build());
- }
- }
-
- if (myGroupsId != null) {
- builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
- builder.withValueBackReference(GroupMembership.RAW_CONTACT_ID, 0);
- builder.withValue(Data.MIMETYPE, GroupMembership.CONTENT_ITEM_TYPE);
- builder.withValue(GroupMembership.GROUP_SOURCE_ID, myGroupsId);
- operationList.add(builder.build());
- }
-
- try {
- ContentProviderResult[] results = resolver.applyBatch(
- ContactsContract.AUTHORITY, operationList);
- // the first result is always the raw_contact. return it's uri so
- // that it can be found later. do null checking for badly behaving
- // ContentResolvers
- return (results == null || results.length == 0 || results[0] == null)
- ? null
- : results[0].uri;
- } catch (RemoteException e) {
- Log.e(LOG_TAG, String.format("%s: %s", e.toString(), e.getMessage()));
- return null;
- } catch (OperationApplicationException e) {
- Log.e(LOG_TAG, String.format("%s: %s", e.toString(), e.getMessage()));
- return null;
- }
- }
-
- public static VCardEntry buildFromResolver(ContentResolver resolver) {
- return buildFromResolver(resolver, Contacts.CONTENT_URI);
- }
-
- public static VCardEntry buildFromResolver(ContentResolver resolver, Uri uri) {
-
- return null;
- }
-
- private boolean nameFieldsAreEmpty() {
- return (TextUtils.isEmpty(mFamilyName)
- && TextUtils.isEmpty(mMiddleName)
- && TextUtils.isEmpty(mGivenName)
- && TextUtils.isEmpty(mPrefix)
- && TextUtils.isEmpty(mSuffix)
- && TextUtils.isEmpty(mFullName)
- && TextUtils.isEmpty(mPhoneticFamilyName)
- && TextUtils.isEmpty(mPhoneticMiddleName)
- && TextUtils.isEmpty(mPhoneticGivenName)
- && TextUtils.isEmpty(mPhoneticFullName));
- }
-
- public boolean isIgnorable() {
- return getDisplayName().length() == 0;
- }
-
- private String listToString(List<String> list){
- final int size = list.size();
- if (size > 1) {
- StringBuilder builder = new StringBuilder();
- int i = 0;
- for (String type : list) {
- builder.append(type);
- if (i < size - 1) {
- builder.append(";");
- }
- }
- return builder.toString();
- } else if (size == 1) {
- return list.get(0);
- } else {
- return "";
- }
- }
-
- // All getter methods should be used carefully, since they may change
- // in the future as of 2009-10-05, on which I cannot be sure this structure
- // is completely consolidated.
- //
- // Also note that these getter methods should be used only after
- // all properties being pushed into this object. If not, incorrect
- // value will "be stored in the local cache and" be returned to you.
-
- public String getFamilyName() {
- return mFamilyName;
- }
-
- public String getGivenName() {
- return mGivenName;
- }
-
- public String getMiddleName() {
- return mMiddleName;
- }
-
- public String getPrefix() {
- return mPrefix;
- }
-
- public String getSuffix() {
- return mSuffix;
- }
-
- public String getFullName() {
- return mFullName;
- }
-
- public String getPhoneticFamilyName() {
- return mPhoneticFamilyName;
- }
-
- public String getPhoneticGivenName() {
- return mPhoneticGivenName;
- }
-
- public String getPhoneticMiddleName() {
- return mPhoneticMiddleName;
- }
-
- public String getPhoneticFullName() {
- return mPhoneticFullName;
- }
-
- public final List<String> getNickNameList() {
- return mNickNameList;
- }
-
- public String getBirthday() {
- return mBirthday;
- }
-
- public final List<String> getNotes() {
- return mNoteList;
- }
-
- public final List<PhoneData> getPhoneList() {
- return mPhoneList;
- }
-
- public final List<EmailData> getEmailList() {
- return mEmailList;
- }
-
- public final List<PostalData> getPostalList() {
- return mPostalList;
- }
-
- public final List<OrganizationData> getOrganizationList() {
- return mOrganizationList;
- }
-
- public final List<ImData> getImList() {
- return mImList;
- }
-
- public final List<PhotoData> getPhotoList() {
- return mPhotoList;
- }
-
- public final List<String> getWebsiteList() {
- return mWebsiteList;
- }
-
- public String getDisplayName() {
- if (mDisplayName == null) {
- constructDisplayName();
- }
- return mDisplayName;
- }
-}
diff --git a/core/java/android/pim/vcard/VCardEntryCommitter.java b/core/java/android/pim/vcard/VCardEntryCommitter.java
deleted file mode 100644
index 59a2baf..0000000
--- a/core/java/android/pim/vcard/VCardEntryCommitter.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.pim.vcard;
-
-import android.content.ContentResolver;
-import android.net.Uri;
-import android.util.Log;
-
-import java.util.ArrayList;
-
-/**
- * <P>
- * {@link VCardEntryHandler} implementation which commits the entry to ContentResolver.
- * </P>
- * <P>
- * Note:<BR />
- * Each vCard may contain big photo images encoded by BASE64,
- * If we store all vCard entries in memory, OutOfMemoryError may be thrown.
- * Thus, this class push each VCard entry into ContentResolver immediately.
- * </P>
- */
-public class VCardEntryCommitter implements VCardEntryHandler {
- public static String LOG_TAG = "VCardEntryComitter";
-
- private final ContentResolver mContentResolver;
- private long mTimeToCommit;
- private ArrayList<Uri> mCreatedUris = new ArrayList<Uri>();
-
- public VCardEntryCommitter(ContentResolver resolver) {
- mContentResolver = resolver;
- }
-
- public void onStart() {
- }
-
- public void onEnd() {
- if (VCardConfig.showPerformanceLog()) {
- Log.d(LOG_TAG, String.format("time to commit entries: %d ms", mTimeToCommit));
- }
- }
-
- public void onEntryCreated(final VCardEntry contactStruct) {
- long start = System.currentTimeMillis();
- mCreatedUris.add(contactStruct.pushIntoContentResolver(mContentResolver));
- mTimeToCommit += System.currentTimeMillis() - start;
- }
-
- /**
- * Returns the list of created Uris. This list should not be modified by the caller as it is
- * not a clone.
- */
- public ArrayList<Uri> getCreatedUris() {
- return mCreatedUris;
- }
-}
\ No newline at end of file
diff --git a/core/java/android/pim/vcard/VCardEntryConstructor.java b/core/java/android/pim/vcard/VCardEntryConstructor.java
deleted file mode 100644
index 290ca2b..0000000
--- a/core/java/android/pim/vcard/VCardEntryConstructor.java
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.pim.vcard;
-
-import android.accounts.Account;
-import android.util.CharsetUtils;
-import android.util.Log;
-
-import org.apache.commons.codec.DecoderException;
-import org.apache.commons.codec.binary.Base64;
-import org.apache.commons.codec.net.QuotedPrintableCodec;
-
-import java.io.UnsupportedEncodingException;
-import java.nio.ByteBuffer;
-import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-public class VCardEntryConstructor implements VCardInterpreter {
- private static String LOG_TAG = "VCardEntryConstructor";
-
- /**
- * If there's no other information available, this class uses this charset for encoding
- * byte arrays to String.
- */
- /* package */ static final String DEFAULT_CHARSET_FOR_DECODED_BYTES = "UTF-8";
-
- private VCardEntry.Property mCurrentProperty = new VCardEntry.Property();
- private VCardEntry mCurrentContactStruct;
- private String mParamType;
-
- /**
- * The charset using which {@link VCardInterpreter} parses the text.
- */
- private String mInputCharset;
-
- /**
- * The charset with which byte array is encoded to String.
- */
- final private String mCharsetForDecodedBytes;
- final private boolean mStrictLineBreakParsing;
- final private int mVCardType;
- final private Account mAccount;
-
- /** For measuring performance. */
- private long mTimePushIntoContentResolver;
-
- final private List<VCardEntryHandler> mEntryHandlers = new ArrayList<VCardEntryHandler>();
-
- public VCardEntryConstructor() {
- this(null, null, false, VCardConfig.VCARD_TYPE_V21_GENERIC_UTF8, null);
- }
-
- public VCardEntryConstructor(final int vcardType) {
- this(null, null, false, vcardType, null);
- }
-
- public VCardEntryConstructor(final String charset, final boolean strictLineBreakParsing,
- final int vcardType, final Account account) {
- this(null, charset, strictLineBreakParsing, vcardType, account);
- }
-
- public VCardEntryConstructor(final String inputCharset, final String charsetForDetodedBytes,
- final boolean strictLineBreakParsing, final int vcardType,
- final Account account) {
- if (inputCharset != null) {
- mInputCharset = inputCharset;
- } else {
- mInputCharset = VCardConfig.DEFAULT_CHARSET;
- }
- if (charsetForDetodedBytes != null) {
- mCharsetForDecodedBytes = charsetForDetodedBytes;
- } else {
- mCharsetForDecodedBytes = DEFAULT_CHARSET_FOR_DECODED_BYTES;
- }
- mStrictLineBreakParsing = strictLineBreakParsing;
- mVCardType = vcardType;
- mAccount = account;
- }
-
- public void addEntryHandler(VCardEntryHandler entryHandler) {
- mEntryHandlers.add(entryHandler);
- }
-
- public void start() {
- for (VCardEntryHandler entryHandler : mEntryHandlers) {
- entryHandler.onStart();
- }
- }
-
- public void end() {
- for (VCardEntryHandler entryHandler : mEntryHandlers) {
- entryHandler.onEnd();
- }
- }
-
- /**
- * Called when the parse failed between {@link #startEntry()} and {@link #endEntry()}.
- */
- public void clear() {
- mCurrentContactStruct = null;
- mCurrentProperty = new VCardEntry.Property();
- }
-
- /**
- * Assume that VCard is not nested. In other words, this code does not accept
- */
- public void startEntry() {
- if (mCurrentContactStruct != null) {
- Log.e(LOG_TAG, "Nested VCard code is not supported now.");
- }
- mCurrentContactStruct = new VCardEntry(mVCardType, mAccount);
- }
-
- public void endEntry() {
- mCurrentContactStruct.consolidateFields();
- for (VCardEntryHandler entryHandler : mEntryHandlers) {
- entryHandler.onEntryCreated(mCurrentContactStruct);
- }
- mCurrentContactStruct = null;
- }
-
- public void startProperty() {
- mCurrentProperty.clear();
- }
-
- public void endProperty() {
- mCurrentContactStruct.addProperty(mCurrentProperty);
- }
-
- public void propertyName(String name) {
- mCurrentProperty.setPropertyName(name);
- }
-
- public void propertyGroup(String group) {
- }
-
- public void propertyParamType(String type) {
- if (mParamType != null) {
- Log.e(LOG_TAG, "propertyParamType() is called more than once " +
- "before propertyParamValue() is called");
- }
- mParamType = type;
- }
-
- public void propertyParamValue(String value) {
- if (mParamType == null) {
- // From vCard 2.1 specification. vCard 3.0 formally does not allow this case.
- mParamType = "TYPE";
- }
- mCurrentProperty.addParameter(mParamType, value);
- mParamType = null;
- }
-
- private String encodeString(String originalString, String charsetForDecodedBytes) {
- if (mInputCharset.equalsIgnoreCase(charsetForDecodedBytes)) {
- return originalString;
- }
- Charset charset = Charset.forName(mInputCharset);
- ByteBuffer byteBuffer = charset.encode(originalString);
- // byteBuffer.array() "may" return byte array which is larger than
- // byteBuffer.remaining(). Here, we keep on the safe side.
- byte[] bytes = new byte[byteBuffer.remaining()];
- byteBuffer.get(bytes);
- try {
- return new String(bytes, charsetForDecodedBytes);
- } catch (UnsupportedEncodingException e) {
- Log.e(LOG_TAG, "Failed to encode: charset=" + charsetForDecodedBytes);
- return null;
- }
- }
-
- private String handleOneValue(String value, String charsetForDecodedBytes, String encoding) {
- if (encoding != null) {
- if (encoding.equals("BASE64") || encoding.equals("B")) {
- mCurrentProperty.setPropertyBytes(Base64.decodeBase64(value.getBytes()));
- return value;
- } else if (encoding.equals("QUOTED-PRINTABLE")) {
- // "= " -> " ", "=\t" -> "\t".
- // Previous code had done this replacement. Keep on the safe side.
- StringBuilder builder = new StringBuilder();
- int length = value.length();
- for (int i = 0; i < length; i++) {
- char ch = value.charAt(i);
- if (ch == '=' && i < length - 1) {
- char nextCh = value.charAt(i + 1);
- if (nextCh == ' ' || nextCh == '\t') {
-
- builder.append(nextCh);
- i++;
- continue;
- }
- }
- builder.append(ch);
- }
- String quotedPrintable = builder.toString();
-
- String[] lines;
- if (mStrictLineBreakParsing) {
- lines = quotedPrintable.split("\r\n");
- } else {
- builder = new StringBuilder();
- length = quotedPrintable.length();
- ArrayList<String> list = new ArrayList<String>();
- for (int i = 0; i < length; i++) {
- char ch = quotedPrintable.charAt(i);
- if (ch == '\n') {
- list.add(builder.toString());
- builder = new StringBuilder();
- } else if (ch == '\r') {
- list.add(builder.toString());
- builder = new StringBuilder();
- if (i < length - 1) {
- char nextCh = quotedPrintable.charAt(i + 1);
- if (nextCh == '\n') {
- i++;
- }
- }
- } else {
- builder.append(ch);
- }
- }
- String finalLine = builder.toString();
- if (finalLine.length() > 0) {
- list.add(finalLine);
- }
- lines = list.toArray(new String[0]);
- }
-
- builder = new StringBuilder();
- for (String line : lines) {
- if (line.endsWith("=")) {
- line = line.substring(0, line.length() - 1);
- }
- builder.append(line);
- }
- byte[] bytes;
- try {
- bytes = builder.toString().getBytes(mInputCharset);
- } catch (UnsupportedEncodingException e1) {
- Log.e(LOG_TAG, "Failed to encode: charset=" + mInputCharset);
- bytes = builder.toString().getBytes();
- }
-
- try {
- bytes = QuotedPrintableCodec.decodeQuotedPrintable(bytes);
- } catch (DecoderException e) {
- Log.e(LOG_TAG, "Failed to decode quoted-printable: " + e);
- return "";
- }
-
- try {
- return new String(bytes, charsetForDecodedBytes);
- } catch (UnsupportedEncodingException e) {
- Log.e(LOG_TAG, "Failed to encode: charset=" + charsetForDecodedBytes);
- return new String(bytes);
- }
- }
- // Unknown encoding. Fall back to default.
- }
- return encodeString(value, charsetForDecodedBytes);
- }
-
- public void propertyValues(List<String> values) {
- if (values == null || values.isEmpty()) {
- return;
- }
-
- final Collection<String> charsetCollection = mCurrentProperty.getParameters("CHARSET");
- final String charset =
- ((charsetCollection != null) ? charsetCollection.iterator().next() : null);
- final Collection<String> encodingCollection = mCurrentProperty.getParameters("ENCODING");
- final String encoding =
- ((encodingCollection != null) ? encodingCollection.iterator().next() : null);
-
- String charsetForDecodedBytes = CharsetUtils.nameForDefaultVendor(charset);
- if (charsetForDecodedBytes == null || charsetForDecodedBytes.length() == 0) {
- charsetForDecodedBytes = mCharsetForDecodedBytes;
- }
-
- for (final String value : values) {
- mCurrentProperty.addToPropertyValueList(
- handleOneValue(value, charsetForDecodedBytes, encoding));
- }
- }
-
- public void showPerformanceInfo() {
- Log.d(LOG_TAG, "time for insert ContactStruct to database: " +
- mTimePushIntoContentResolver + " ms");
- }
-}
diff --git a/core/java/android/pim/vcard/VCardEntryCounter.java b/core/java/android/pim/vcard/VCardEntryCounter.java
deleted file mode 100644
index 7bab50d..0000000
--- a/core/java/android/pim/vcard/VCardEntryCounter.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.pim.vcard;
-
-import java.util.List;
-
-/**
- * The class which just counts the number of vCard entries in the specified input.
- */
-public class VCardEntryCounter implements VCardInterpreter {
- private int mCount;
-
- public int getCount() {
- return mCount;
- }
-
- public void start() {
- }
-
- public void end() {
- }
-
- public void startEntry() {
- }
-
- public void endEntry() {
- mCount++;
- }
-
- public void startProperty() {
- }
-
- public void endProperty() {
- }
-
- public void propertyGroup(String group) {
- }
-
- public void propertyName(String name) {
- }
-
- public void propertyParamType(String type) {
- }
-
- public void propertyParamValue(String value) {
- }
-
- public void propertyValues(List<String> values) {
- }
-}
diff --git a/core/java/android/pim/vcard/VCardEntryHandler.java b/core/java/android/pim/vcard/VCardEntryHandler.java
deleted file mode 100644
index 83a67fe..0000000
--- a/core/java/android/pim/vcard/VCardEntryHandler.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.pim.vcard;
-
-/**
- * The interface called by {@link VCardEntryConstructor}. Useful when you don't want to
- * handle detailed information as what {@link VCardParser} provides via {@link VCardInterpreter}.
- */
-public interface VCardEntryHandler {
- /**
- * Called when the parsing started.
- */
- public void onStart();
-
- /**
- * The method called when one VCard entry is successfully created
- */
- public void onEntryCreated(final VCardEntry entry);
-
- /**
- * Called when the parsing ended.
- * Able to be use this method for showing performance log, etc.
- */
- public void onEnd();
-}
diff --git a/core/java/android/pim/vcard/VCardInterpreter.java b/core/java/android/pim/vcard/VCardInterpreter.java
deleted file mode 100644
index b5237c0..0000000
--- a/core/java/android/pim/vcard/VCardInterpreter.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.pim.vcard;
-
-import java.util.List;
-
-/**
- * <P>
- * The interface which should be implemented by the classes which have to analyze each
- * vCard entry more minutely than {@link VCardEntry} class analysis.
- * </P>
- * <P>
- * Here, there are several terms specific to vCard (and this library).
- * </P>
- * <P>
- * The term "entry" is one vCard representation in the input, which should start with "BEGIN:VCARD"
- * and end with "END:VCARD".
- * </P>
- * <P>
- * The term "property" is one line in vCard entry, which consists of "group", "property name",
- * "parameter(param) names and values", and "property values".
- * </P>
- * <P>
- * e.g. group1.propName;paramName1=paramValue1;paramName2=paramValue2;propertyValue1;propertyValue2...
- * </P>
- */
-public interface VCardInterpreter {
- /**
- * Called when vCard interpretation started.
- */
- void start();
-
- /**
- * Called when vCard interpretation finished.
- */
- void end();
-
- /**
- * Called when parsing one vCard entry started.
- * More specifically, this method is called when "BEGIN:VCARD" is read.
- */
- void startEntry();
-
- /**
- * Called when parsing one vCard entry ended.
- * More specifically, this method is called when "END:VCARD" is read.
- * Note that {@link #startEntry()} may be called since
- * vCard (especially 2.1) allows nested vCard.
- */
- void endEntry();
-
- /**
- * Called when reading one property started.
- */
- void startProperty();
-
- /**
- * Called when reading one property ended.
- */
- void endProperty();
-
- /**
- * @param group A group name. This method may be called more than once or may not be
- * called at all, depending on how many gruoups are appended to the property.
- */
- void propertyGroup(String group);
-
- /**
- * @param name A property name like "N", "FN", "ADR", etc.
- */
- void propertyName(String name);
-
- /**
- * @param type A parameter name like "ENCODING", "CHARSET", etc.
- */
- void propertyParamType(String type);
-
- /**
- * @param value A parameter value. This method may be called without
- * {@link #propertyParamType(String)} being called (when the vCard is vCard 2.1).
- */
- void propertyParamValue(String value);
-
- /**
- * @param values List of property values. The size of values would be 1 unless
- * coressponding property name is "N", "ADR", or "ORG".
- */
- void propertyValues(List<String> values);
-}
diff --git a/core/java/android/pim/vcard/VCardInterpreterCollection.java b/core/java/android/pim/vcard/VCardInterpreterCollection.java
deleted file mode 100644
index 99f81f7..0000000
--- a/core/java/android/pim/vcard/VCardInterpreterCollection.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.pim.vcard;
-
-import java.util.Collection;
-import java.util.List;
-
-/**
- * The {@link VCardInterpreter} implementation which aggregates more than one
- * {@link VCardInterpreter} objects and make a user object treat them as one
- * {@link VCardInterpreter} object.
- */
-public class VCardInterpreterCollection implements VCardInterpreter {
- private final Collection<VCardInterpreter> mInterpreterCollection;
-
- public VCardInterpreterCollection(Collection<VCardInterpreter> interpreterCollection) {
- mInterpreterCollection = interpreterCollection;
- }
-
- public Collection<VCardInterpreter> getCollection() {
- return mInterpreterCollection;
- }
-
- public void start() {
- for (VCardInterpreter builder : mInterpreterCollection) {
- builder.start();
- }
- }
-
- public void end() {
- for (VCardInterpreter builder : mInterpreterCollection) {
- builder.end();
- }
- }
-
- public void startEntry() {
- for (VCardInterpreter builder : mInterpreterCollection) {
- builder.startEntry();
- }
- }
-
- public void endEntry() {
- for (VCardInterpreter builder : mInterpreterCollection) {
- builder.endEntry();
- }
- }
-
- public void startProperty() {
- for (VCardInterpreter builder : mInterpreterCollection) {
- builder.startProperty();
- }
- }
-
- public void endProperty() {
- for (VCardInterpreter builder : mInterpreterCollection) {
- builder.endProperty();
- }
- }
-
- public void propertyGroup(String group) {
- for (VCardInterpreter builder : mInterpreterCollection) {
- builder.propertyGroup(group);
- }
- }
-
- public void propertyName(String name) {
- for (VCardInterpreter builder : mInterpreterCollection) {
- builder.propertyName(name);
- }
- }
-
- public void propertyParamType(String type) {
- for (VCardInterpreter builder : mInterpreterCollection) {
- builder.propertyParamType(type);
- }
- }
-
- public void propertyParamValue(String value) {
- for (VCardInterpreter builder : mInterpreterCollection) {
- builder.propertyParamValue(value);
- }
- }
-
- public void propertyValues(List<String> values) {
- for (VCardInterpreter builder : mInterpreterCollection) {
- builder.propertyValues(values);
- }
- }
-}
diff --git a/core/java/android/pim/vcard/VCardParser.java b/core/java/android/pim/vcard/VCardParser.java
deleted file mode 100644
index 57c52a6..0000000
--- a/core/java/android/pim/vcard/VCardParser.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.pim.vcard;
-
-import android.pim.vcard.exception.VCardException;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-public abstract class VCardParser {
- protected final int mParseType;
- protected boolean mCanceled;
-
- public VCardParser() {
- this(VCardConfig.PARSE_TYPE_UNKNOWN);
- }
-
- public VCardParser(int parseType) {
- mParseType = parseType;
- }
-
- /**
- * <P>
- * Parses the given stream and send the VCard data into VCardBuilderBase object.
- * </P.
- * <P>
- * Note that vCard 2.1 specification allows "CHARSET" parameter, and some career sets
- * local encoding to it. For example, Japanese phone career uses Shift_JIS, which is
- * formally allowed in VCard 2.1, but not recommended in VCard 3.0. In VCard 2.1,
- * In some exreme case, some VCard may have different charsets in one VCard (though
- * we do not see any device which emits such kind of malicious data)
- * </P>
- * <P>
- * In order to avoid "misunderstanding" charset as much as possible, this method
- * use "ISO-8859-1" for reading the stream. When charset is specified in some property
- * (with "CHARSET=..." parameter), the string is decoded to raw bytes and encoded to
- * the charset. This method assumes that "ISO-8859-1" has 1 to 1 mapping in all 8bit
- * characters, which is not completely sure. In some cases, this "decoding-encoding"
- * scheme may fail. To avoid the case,
- * </P>
- * <P>
- * We recommend you to use {@link VCardSourceDetector} and detect which kind of source the
- * VCard comes from and explicitly specify a charset using the result.
- * </P>
- *
- * @param is The source to parse.
- * @param interepreter A {@link VCardInterpreter} object which used to construct data.
- * @return Returns true for success. Otherwise returns false.
- * @throws IOException, VCardException
- */
- public abstract boolean parse(InputStream is, VCardInterpreter interepreter)
- throws IOException, VCardException;
-
- /**
- * <P>
- * The method variants which accept charset.
- * </P>
- * <P>
- * RFC 2426 "recommends" (not forces) to use UTF-8, so it may be OK to use
- * UTF-8 as an encoding when parsing vCard 3.0. But note that some Japanese
- * phone uses Shift_JIS as a charset (e.g. W61SH), and another uses
- * "CHARSET=SHIFT_JIS", which is explicitly prohibited in vCard 3.0 specification (e.g. W53K).
- * </P>
- *
- * @param is The source to parse.
- * @param charset Charset to be used.
- * @param builder The VCardBuilderBase object.
- * @return Returns true when successful. Otherwise returns false.
- * @throws IOException, VCardException
- */
- public abstract boolean parse(InputStream is, String charset, VCardInterpreter builder)
- throws IOException, VCardException;
-
- /**
- * The method variants which tells this object the operation is already canceled.
- */
- public abstract void parse(InputStream is, String charset,
- VCardInterpreter builder, boolean canceled)
- throws IOException, VCardException;
-
- /**
- * Cancel parsing.
- * Actual cancel is done after the end of the current one vcard entry parsing.
- */
- public void cancel() {
- mCanceled = true;
- }
-}
diff --git a/core/java/android/pim/vcard/VCardParser_V21.java b/core/java/android/pim/vcard/VCardParser_V21.java
deleted file mode 100644
index fe8cfb0..0000000
--- a/core/java/android/pim/vcard/VCardParser_V21.java
+++ /dev/null
@@ -1,936 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.pim.vcard;
-
-import android.pim.vcard.exception.VCardAgentNotSupportedException;
-import android.pim.vcard.exception.VCardException;
-import android.pim.vcard.exception.VCardInvalidCommentLineException;
-import android.pim.vcard.exception.VCardInvalidLineException;
-import android.pim.vcard.exception.VCardNestedException;
-import android.pim.vcard.exception.VCardVersionException;
-import android.util.Log;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * This class is used to parse vCard. Please refer to vCard Specification 2.1 for more detail.
- */
-public class VCardParser_V21 extends VCardParser {
- private static final String LOG_TAG = "VCardParser_V21";
-
- /** Store the known-type */
- private static final HashSet<String> sKnownTypeSet = new HashSet<String>(
- Arrays.asList("DOM", "INTL", "POSTAL", "PARCEL", "HOME", "WORK",
- "PREF", "VOICE", "FAX", "MSG", "CELL", "PAGER", "BBS",
- "MODEM", "CAR", "ISDN", "VIDEO", "AOL", "APPLELINK",
- "ATTMAIL", "CIS", "EWORLD", "INTERNET", "IBMMAIL",
- "MCIMAIL", "POWERSHARE", "PRODIGY", "TLX", "X400", "GIF",
- "CGM", "WMF", "BMP", "MET", "PMB", "DIB", "PICT", "TIFF",
- "PDF", "PS", "JPEG", "QTIME", "MPEG", "MPEG2", "AVI",
- "WAVE", "AIFF", "PCM", "X509", "PGP"));
-
- /** Store the known-value */
- private static final HashSet<String> sKnownValueSet = new HashSet<String>(
- Arrays.asList("INLINE", "URL", "CONTENT-ID", "CID"));
-
- /** Store the property names available in vCard 2.1 */
- private static final HashSet<String> sAvailablePropertyNameSetV21 =
- new HashSet<String>(Arrays.asList(
- "BEGIN", "LOGO", "PHOTO", "LABEL", "FN", "TITLE", "SOUND",
- "VERSION", "TEL", "EMAIL", "TZ", "GEO", "NOTE", "URL",
- "BDAY", "ROLE", "REV", "UID", "KEY", "MAILER"));
-
- /**
- * Though vCard 2.1 specification does not allow "B" encoding, some data may have it.
- * We allow it for safety...
- */
- private static final HashSet<String> sAvailableEncodingV21 =
- new HashSet<String>(Arrays.asList(
- "7BIT", "8BIT", "QUOTED-PRINTABLE", "BASE64", "B"));
-
- // Used only for parsing END:VCARD.
- private String mPreviousLine;
-
- /** The builder to build parsed data */
- protected VCardInterpreter mBuilder = null;
-
- /**
- * The encoding type. "Encoding" in vCard is different from "Charset".
- * e.g. 7BIT, 8BIT, QUOTED-PRINTABLE.
- */
- protected String mEncoding = null;
-
- protected final String sDefaultEncoding = "8BIT";
-
- // Should not directly read a line from this object. Use getLine() instead.
- protected BufferedReader mReader;
-
- // In some cases, vCard is nested. Currently, we only consider the most interior vCard data.
- // See v21_foma_1.vcf in test directory for more information.
- private int mNestCount;
-
- // In order to reduce warning message as much as possible, we hold the value which made Logger
- // emit a warning message.
- protected Set<String> mUnknownTypeMap = new HashSet<String>();
- protected Set<String> mUnknownValueMap = new HashSet<String>();
-
- // For measuring performance.
- private long mTimeTotal;
- private long mTimeReadStartRecord;
- private long mTimeReadEndRecord;
- private long mTimeStartProperty;
- private long mTimeEndProperty;
- private long mTimeParseItems;
- private long mTimeParseLineAndHandleGroup;
- private long mTimeParsePropertyValues;
- private long mTimeParseAdrOrgN;
- private long mTimeHandleMiscPropertyValue;
- private long mTimeHandleQuotedPrintable;
- private long mTimeHandleBase64;
-
- public VCardParser_V21() {
- this(null);
- }
-
- public VCardParser_V21(VCardSourceDetector detector) {
- this(detector != null ? detector.getEstimatedType() : VCardConfig.PARSE_TYPE_UNKNOWN);
- }
-
- public VCardParser_V21(int parseType) {
- super(parseType);
- if (parseType == VCardConfig.PARSE_TYPE_FOMA) {
- mNestCount = 1;
- }
- }
-
- /**
- * Parses the file at the given position.
- *
- * vcard_file = [wsls] vcard [wsls]
- */
- protected void parseVCardFile() throws IOException, VCardException {
- boolean firstReading = true;
- while (true) {
- if (mCanceled) {
- break;
- }
- if (!parseOneVCard(firstReading)) {
- break;
- }
- firstReading = false;
- }
-
- if (mNestCount > 0) {
- boolean useCache = true;
- for (int i = 0; i < mNestCount; i++) {
- readEndVCard(useCache, true);
- useCache = false;
- }
- }
- }
-
- protected int getVersion() {
- return VCardConfig.FLAG_V21;
- }
-
- protected String getVersionString() {
- return VCardConstants.VERSION_V21;
- }
-
- /**
- * @return true when the propertyName is a valid property name.
- */
- protected boolean isValidPropertyName(String propertyName) {
- if (!(sAvailablePropertyNameSetV21.contains(propertyName.toUpperCase()) ||
- propertyName.startsWith("X-")) &&
- !mUnknownTypeMap.contains(propertyName)) {
- mUnknownTypeMap.add(propertyName);
- Log.w(LOG_TAG, "Property name unsupported by vCard 2.1: " + propertyName);
- }
- return true;
- }
-
- /**
- * @return true when the encoding is a valid encoding.
- */
- protected boolean isValidEncoding(String encoding) {
- return sAvailableEncodingV21.contains(encoding.toUpperCase());
- }
-
- /**
- * @return String. It may be null, or its length may be 0
- * @throws IOException
- */
- protected String getLine() throws IOException {
- return mReader.readLine();
- }
-
- /**
- * @return String with it's length > 0
- * @throws IOException
- * @throws VCardException when the stream reached end of line
- */
- protected String getNonEmptyLine() throws IOException, VCardException {
- String line;
- while (true) {
- line = getLine();
- if (line == null) {
- throw new VCardException("Reached end of buffer.");
- } else if (line.trim().length() > 0) {
- return line;
- }
- }
- }
-
- /**
- * vcard = "BEGIN" [ws] ":" [ws] "VCARD" [ws] 1*CRLF
- * items *CRLF
- * "END" [ws] ":" [ws] "VCARD"
- */
- private boolean parseOneVCard(boolean firstReading) throws IOException, VCardException {
- boolean allowGarbage = false;
- if (firstReading) {
- if (mNestCount > 0) {
- for (int i = 0; i < mNestCount; i++) {
- if (!readBeginVCard(allowGarbage)) {
- return false;
- }
- allowGarbage = true;
- }
- }
- }
-
- if (!readBeginVCard(allowGarbage)) {
- return false;
- }
- long start;
- if (mBuilder != null) {
- start = System.currentTimeMillis();
- mBuilder.startEntry();
- mTimeReadStartRecord += System.currentTimeMillis() - start;
- }
- start = System.currentTimeMillis();
- parseItems();
- mTimeParseItems += System.currentTimeMillis() - start;
- readEndVCard(true, false);
- if (mBuilder != null) {
- start = System.currentTimeMillis();
- mBuilder.endEntry();
- mTimeReadEndRecord += System.currentTimeMillis() - start;
- }
- return true;
- }
-
- /**
- * @return True when successful. False when reaching the end of line
- * @throws IOException
- * @throws VCardException
- */
- protected boolean readBeginVCard(boolean allowGarbage) throws IOException, VCardException {
- String line;
- do {
- while (true) {
- line = getLine();
- if (line == null) {
- return false;
- } else if (line.trim().length() > 0) {
- break;
- }
- }
- String[] strArray = line.split(":", 2);
- int length = strArray.length;
-
- // Though vCard 2.1/3.0 specification does not allow lower cases,
- // vCard file emitted by some external vCard expoter have such invalid Strings.
- // So we allow it.
- // e.g. BEGIN:vCard
- if (length == 2 &&
- strArray[0].trim().equalsIgnoreCase("BEGIN") &&
- strArray[1].trim().equalsIgnoreCase("VCARD")) {
- return true;
- } else if (!allowGarbage) {
- if (mNestCount > 0) {
- mPreviousLine = line;
- return false;
- } else {
- throw new VCardException(
- "Expected String \"BEGIN:VCARD\" did not come "
- + "(Instead, \"" + line + "\" came)");
- }
- }
- } while(allowGarbage);
-
- throw new VCardException("Reached where must not be reached.");
- }
-
- /**
- * The arguments useCache and allowGarbase are usually true and false accordingly when
- * this function is called outside this function itself.
- *
- * @param useCache When true, line is obtained from mPreviousline. Otherwise, getLine()
- * is used.
- * @param allowGarbage When true, ignore non "END:VCARD" line.
- * @throws IOException
- * @throws VCardException
- */
- protected void readEndVCard(boolean useCache, boolean allowGarbage)
- throws IOException, VCardException {
- String line;
- do {
- if (useCache) {
- // Though vCard specification does not allow lower cases,
- // some data may have them, so we allow it.
- line = mPreviousLine;
- } else {
- while (true) {
- line = getLine();
- if (line == null) {
- throw new VCardException("Expected END:VCARD was not found.");
- } else if (line.trim().length() > 0) {
- break;
- }
- }
- }
-
- String[] strArray = line.split(":", 2);
- if (strArray.length == 2 &&
- strArray[0].trim().equalsIgnoreCase("END") &&
- strArray[1].trim().equalsIgnoreCase("VCARD")) {
- return;
- } else if (!allowGarbage) {
- throw new VCardException("END:VCARD != \"" + mPreviousLine + "\"");
- }
- useCache = false;
- } while (allowGarbage);
- }
-
- /**
- * items = *CRLF item
- * / item
- */
- protected void parseItems() throws IOException, VCardException {
- boolean ended = false;
-
- if (mBuilder != null) {
- long start = System.currentTimeMillis();
- mBuilder.startProperty();
- mTimeStartProperty += System.currentTimeMillis() - start;
- }
- ended = parseItem();
- if (mBuilder != null && !ended) {
- long start = System.currentTimeMillis();
- mBuilder.endProperty();
- mTimeEndProperty += System.currentTimeMillis() - start;
- }
-
- while (!ended) {
- // follow VCARD ,it wont reach endProperty
- if (mBuilder != null) {
- long start = System.currentTimeMillis();
- mBuilder.startProperty();
- mTimeStartProperty += System.currentTimeMillis() - start;
- }
- try {
- ended = parseItem();
- } catch (VCardInvalidCommentLineException e) {
- Log.e(LOG_TAG, "Invalid line which looks like some comment was found. Ignored.");
- ended = false;
- }
- if (mBuilder != null && !ended) {
- long start = System.currentTimeMillis();
- mBuilder.endProperty();
- mTimeEndProperty += System.currentTimeMillis() - start;
- }
- }
- }
-
- /**
- * item = [groups "."] name [params] ":" value CRLF
- * / [groups "."] "ADR" [params] ":" addressparts CRLF
- * / [groups "."] "ORG" [params] ":" orgparts CRLF
- * / [groups "."] "N" [params] ":" nameparts CRLF
- * / [groups "."] "AGENT" [params] ":" vcard CRLF
- */
- protected boolean parseItem() throws IOException, VCardException {
- mEncoding = sDefaultEncoding;
-
- final String line = getNonEmptyLine();
- long start = System.currentTimeMillis();
-
- String[] propertyNameAndValue = separateLineAndHandleGroup(line);
- if (propertyNameAndValue == null) {
- return true;
- }
- if (propertyNameAndValue.length != 2) {
- throw new VCardInvalidLineException("Invalid line \"" + line + "\"");
- }
- String propertyName = propertyNameAndValue[0].toUpperCase();
- String propertyValue = propertyNameAndValue[1];
-
- mTimeParseLineAndHandleGroup += System.currentTimeMillis() - start;
-
- if (propertyName.equals("ADR") || propertyName.equals("ORG") ||
- propertyName.equals("N")) {
- start = System.currentTimeMillis();
- handleMultiplePropertyValue(propertyName, propertyValue);
- mTimeParseAdrOrgN += System.currentTimeMillis() - start;
- return false;
- } else if (propertyName.equals("AGENT")) {
- handleAgent(propertyValue);
- return false;
- } else if (isValidPropertyName(propertyName)) {
- if (propertyName.equals("BEGIN")) {
- if (propertyValue.equals("VCARD")) {
- throw new VCardNestedException("This vCard has nested vCard data in it.");
- } else {
- throw new VCardException("Unknown BEGIN type: " + propertyValue);
- }
- } else if (propertyName.equals("VERSION") &&
- !propertyValue.equals(getVersionString())) {
- throw new VCardVersionException("Incompatible version: " +
- propertyValue + " != " + getVersionString());
- }
- start = System.currentTimeMillis();
- handlePropertyValue(propertyName, propertyValue);
- mTimeParsePropertyValues += System.currentTimeMillis() - start;
- return false;
- }
-
- throw new VCardException("Unknown property name: \"" + propertyName + "\"");
- }
-
- static private final int STATE_GROUP_OR_PROPNAME = 0;
- static private final int STATE_PARAMS = 1;
- // vCard 3.0 specification allows double-quoted param-value, while vCard 2.1 does not.
- // This is just for safety.
- static private final int STATE_PARAMS_IN_DQUOTE = 2;
-
- protected String[] separateLineAndHandleGroup(String line) throws VCardException {
- int state = STATE_GROUP_OR_PROPNAME;
- int nameIndex = 0;
-
- final String[] propertyNameAndValue = new String[2];
-
- final int length = line.length();
- if (length > 0 && line.charAt(0) == '#') {
- throw new VCardInvalidCommentLineException();
- }
-
- for (int i = 0; i < length; i++) {
- char ch = line.charAt(i);
- switch (state) {
- case STATE_GROUP_OR_PROPNAME: {
- if (ch == ':') {
- final String propertyName = line.substring(nameIndex, i);
- if (propertyName.equalsIgnoreCase("END")) {
- mPreviousLine = line;
- return null;
- }
- if (mBuilder != null) {
- mBuilder.propertyName(propertyName);
- }
- propertyNameAndValue[0] = propertyName;
- if (i < length - 1) {
- propertyNameAndValue[1] = line.substring(i + 1);
- } else {
- propertyNameAndValue[1] = "";
- }
- return propertyNameAndValue;
- } else if (ch == '.') {
- String groupName = line.substring(nameIndex, i);
- if (mBuilder != null) {
- mBuilder.propertyGroup(groupName);
- }
- nameIndex = i + 1;
- } else if (ch == ';') {
- String propertyName = line.substring(nameIndex, i);
- if (propertyName.equalsIgnoreCase("END")) {
- mPreviousLine = line;
- return null;
- }
- if (mBuilder != null) {
- mBuilder.propertyName(propertyName);
- }
- propertyNameAndValue[0] = propertyName;
- nameIndex = i + 1;
- state = STATE_PARAMS;
- }
- break;
- }
- case STATE_PARAMS: {
- if (ch == '"') {
- state = STATE_PARAMS_IN_DQUOTE;
- } else if (ch == ';') {
- handleParams(line.substring(nameIndex, i));
- nameIndex = i + 1;
- } else if (ch == ':') {
- handleParams(line.substring(nameIndex, i));
- if (i < length - 1) {
- propertyNameAndValue[1] = line.substring(i + 1);
- } else {
- propertyNameAndValue[1] = "";
- }
- return propertyNameAndValue;
- }
- break;
- }
- case STATE_PARAMS_IN_DQUOTE: {
- if (ch == '"') {
- state = STATE_PARAMS;
- }
- break;
- }
- }
- }
-
- throw new VCardInvalidLineException("Invalid line: \"" + line + "\"");
- }
-
- /**
- * params = ";" [ws] paramlist
- * paramlist = paramlist [ws] ";" [ws] param
- * / param
- * param = "TYPE" [ws] "=" [ws] ptypeval
- * / "VALUE" [ws] "=" [ws] pvalueval
- * / "ENCODING" [ws] "=" [ws] pencodingval
- * / "CHARSET" [ws] "=" [ws] charsetval
- * / "LANGUAGE" [ws] "=" [ws] langval
- * / "X-" word [ws] "=" [ws] word
- * / knowntype
- */
- protected void handleParams(String params) throws VCardException {
- String[] strArray = params.split("=", 2);
- if (strArray.length == 2) {
- final String paramName = strArray[0].trim().toUpperCase();
- String paramValue = strArray[1].trim();
- if (paramName.equals("TYPE")) {
- handleType(paramValue);
- } else if (paramName.equals("VALUE")) {
- handleValue(paramValue);
- } else if (paramName.equals("ENCODING")) {
- handleEncoding(paramValue);
- } else if (paramName.equals("CHARSET")) {
- handleCharset(paramValue);
- } else if (paramName.equals("LANGUAGE")) {
- handleLanguage(paramValue);
- } else if (paramName.startsWith("X-")) {
- handleAnyParam(paramName, paramValue);
- } else {
- throw new VCardException("Unknown type \"" + paramName + "\"");
- }
- } else {
- handleParamWithoutName(strArray[0]);
- }
- }
-
- /**
- * vCard 3.0 parser may throw VCardException.
- */
- @SuppressWarnings("unused")
- protected void handleParamWithoutName(final String paramValue) throws VCardException {
- handleType(paramValue);
- }
-
- /**
- * ptypeval = knowntype / "X-" word
- */
- protected void handleType(final String ptypeval) {
- String upperTypeValue = ptypeval;
- if (!(sKnownTypeSet.contains(upperTypeValue) || upperTypeValue.startsWith("X-")) &&
- !mUnknownTypeMap.contains(ptypeval)) {
- mUnknownTypeMap.add(ptypeval);
- Log.w(LOG_TAG, "TYPE unsupported by vCard 2.1: " + ptypeval);
- }
- if (mBuilder != null) {
- mBuilder.propertyParamType("TYPE");
- mBuilder.propertyParamValue(upperTypeValue);
- }
- }
-
- /**
- * pvalueval = "INLINE" / "URL" / "CONTENT-ID" / "CID" / "X-" word
- */
- protected void handleValue(final String pvalueval) {
- if (!sKnownValueSet.contains(pvalueval.toUpperCase()) &&
- pvalueval.startsWith("X-") &&
- !mUnknownValueMap.contains(pvalueval)) {
- mUnknownValueMap.add(pvalueval);
- Log.w(LOG_TAG, "VALUE unsupported by vCard 2.1: " + pvalueval);
- }
- if (mBuilder != null) {
- mBuilder.propertyParamType("VALUE");
- mBuilder.propertyParamValue(pvalueval);
- }
- }
-
- /**
- * pencodingval = "7BIT" / "8BIT" / "QUOTED-PRINTABLE" / "BASE64" / "X-" word
- */
- protected void handleEncoding(String pencodingval) throws VCardException {
- if (isValidEncoding(pencodingval) ||
- pencodingval.startsWith("X-")) {
- if (mBuilder != null) {
- mBuilder.propertyParamType("ENCODING");
- mBuilder.propertyParamValue(pencodingval);
- }
- mEncoding = pencodingval;
- } else {
- throw new VCardException("Unknown encoding \"" + pencodingval + "\"");
- }
- }
-
- /**
- * vCard 2.1 specification only allows us-ascii and iso-8859-xxx (See RFC 1521),
- * but today's vCard often contains other charset, so we allow them.
- */
- protected void handleCharset(String charsetval) {
- if (mBuilder != null) {
- mBuilder.propertyParamType("CHARSET");
- mBuilder.propertyParamValue(charsetval);
- }
- }
-
- /**
- * See also Section 7.1 of RFC 1521
- */
- protected void handleLanguage(String langval) throws VCardException {
- String[] strArray = langval.split("-");
- if (strArray.length != 2) {
- throw new VCardException("Invalid Language: \"" + langval + "\"");
- }
- String tmp = strArray[0];
- int length = tmp.length();
- for (int i = 0; i < length; i++) {
- if (!isLetter(tmp.charAt(i))) {
- throw new VCardException("Invalid Language: \"" + langval + "\"");
- }
- }
- tmp = strArray[1];
- length = tmp.length();
- for (int i = 0; i < length; i++) {
- if (!isLetter(tmp.charAt(i))) {
- throw new VCardException("Invalid Language: \"" + langval + "\"");
- }
- }
- if (mBuilder != null) {
- mBuilder.propertyParamType("LANGUAGE");
- mBuilder.propertyParamValue(langval);
- }
- }
-
- /**
- * Mainly for "X-" type. This accepts any kind of type without check.
- */
- protected void handleAnyParam(String paramName, String paramValue) {
- if (mBuilder != null) {
- mBuilder.propertyParamType(paramName);
- mBuilder.propertyParamValue(paramValue);
- }
- }
-
- protected void handlePropertyValue(String propertyName, String propertyValue)
- throws IOException, VCardException {
- if (mEncoding.equalsIgnoreCase("QUOTED-PRINTABLE")) {
- final long start = System.currentTimeMillis();
- final String result = getQuotedPrintable(propertyValue);
- if (mBuilder != null) {
- ArrayList<String> v = new ArrayList<String>();
- v.add(result);
- mBuilder.propertyValues(v);
- }
- mTimeHandleQuotedPrintable += System.currentTimeMillis() - start;
- } else if (mEncoding.equalsIgnoreCase("BASE64") ||
- mEncoding.equalsIgnoreCase("B")) {
- final long start = System.currentTimeMillis();
- // It is very rare, but some BASE64 data may be so big that
- // OutOfMemoryError occurs. To ignore such cases, use try-catch.
- try {
- final String result = getBase64(propertyValue);
- if (mBuilder != null) {
- ArrayList<String> v = new ArrayList<String>();
- v.add(result);
- mBuilder.propertyValues(v);
- }
- } catch (OutOfMemoryError error) {
- Log.e(LOG_TAG, "OutOfMemoryError happened during parsing BASE64 data!");
- if (mBuilder != null) {
- mBuilder.propertyValues(null);
- }
- }
- mTimeHandleBase64 += System.currentTimeMillis() - start;
- } else {
- if (!(mEncoding == null || mEncoding.equalsIgnoreCase("7BIT")
- || mEncoding.equalsIgnoreCase("8BIT")
- || mEncoding.toUpperCase().startsWith("X-"))) {
- Log.w(LOG_TAG, "The encoding unsupported by vCard spec: \"" + mEncoding + "\".");
- }
-
- final long start = System.currentTimeMillis();
- if (mBuilder != null) {
- ArrayList<String> v = new ArrayList<String>();
- v.add(maybeUnescapeText(propertyValue));
- mBuilder.propertyValues(v);
- }
- mTimeHandleMiscPropertyValue += System.currentTimeMillis() - start;
- }
- }
-
- protected String getQuotedPrintable(String firstString) throws IOException, VCardException {
- // Specifically, there may be some padding between = and CRLF.
- // See the following:
- //
- // qp-line := *(qp-segment transport-padding CRLF)
- // qp-part transport-padding
- // qp-segment := qp-section *(SPACE / TAB) "="
- // ; Maximum length of 76 characters
- //
- // e.g. (from RFC 2045)
- // Now's the time =
- // for all folk to come=
- // to the aid of their country.
- if (firstString.trim().endsWith("=")) {
- // remove "transport-padding"
- int pos = firstString.length() - 1;
- while(firstString.charAt(pos) != '=') {
- }
- StringBuilder builder = new StringBuilder();
- builder.append(firstString.substring(0, pos + 1));
- builder.append("\r\n");
- String line;
- while (true) {
- line = getLine();
- if (line == null) {
- throw new VCardException(
- "File ended during parsing quoted-printable String");
- }
- if (line.trim().endsWith("=")) {
- // remove "transport-padding"
- pos = line.length() - 1;
- while(line.charAt(pos) != '=') {
- }
- builder.append(line.substring(0, pos + 1));
- builder.append("\r\n");
- } else {
- builder.append(line);
- break;
- }
- }
- return builder.toString();
- } else {
- return firstString;
- }
- }
-
- protected String getBase64(String firstString) throws IOException, VCardException {
- StringBuilder builder = new StringBuilder();
- builder.append(firstString);
-
- while (true) {
- String line = getLine();
- if (line == null) {
- throw new VCardException(
- "File ended during parsing BASE64 binary");
- }
- if (line.length() == 0) {
- break;
- }
- builder.append(line);
- }
-
- return builder.toString();
- }
-
- /**
- * Mainly for "ADR", "ORG", and "N"
- * We do not care the number of strnosemi here.
- *
- * addressparts = 0*6(strnosemi ";") strnosemi
- * ; PO Box, Extended Addr, Street, Locality, Region,
- * Postal Code, Country Name
- * orgparts = *(strnosemi ";") strnosemi
- * ; First is Organization Name,
- * remainder are Organization Units.
- * nameparts = 0*4(strnosemi ";") strnosemi
- * ; Family, Given, Middle, Prefix, Suffix.
- * ; Example:Public;John;Q.;Reverend Dr.;III, Esq.
- * strnosemi = *(*nonsemi ("\;" / "\" CRLF)) *nonsemi
- * ; To include a semicolon in this string, it must be escaped
- * ; with a "\" character.
- *
- * We are not sure whether we should add "\" CRLF to each value.
- * For now, we exclude them.
- */
- protected void handleMultiplePropertyValue(String propertyName, String propertyValue)
- throws IOException, VCardException {
- // vCard 2.1 does not allow QUOTED-PRINTABLE here,
- // but some softwares/devices emit such data.
- if (mEncoding.equalsIgnoreCase("QUOTED-PRINTABLE")) {
- propertyValue = getQuotedPrintable(propertyValue);
- }
-
- if (mBuilder != null) {
- mBuilder.propertyValues(VCardUtils.constructListFromValue(
- propertyValue, (getVersion() == VCardConfig.FLAG_V30)));
- }
- }
-
- /**
- * vCard 2.1 specifies AGENT allows one vcard entry. It is not encoded at all.
- *
- * item = ...
- * / [groups "."] "AGENT"
- * [params] ":" vcard CRLF
- * vcard = "BEGIN" [ws] ":" [ws] "VCARD" [ws] 1*CRLF
- * items *CRLF "END" [ws] ":" [ws] "VCARD"
- */
- protected void handleAgent(final String propertyValue) throws VCardException {
- if (!propertyValue.toUpperCase().contains("BEGIN:VCARD")) {
- // Apparently invalid line seen in Windows Mobile 6.5. Ignore them.
- return;
- } else {
- throw new VCardAgentNotSupportedException("AGENT Property is not supported now.");
- }
- // TODO: Support AGENT property.
- }
-
- /**
- * For vCard 3.0.
- */
- protected String maybeUnescapeText(final String text) {
- return text;
- }
-
- /**
- * Returns unescaped String if the character should be unescaped. Return null otherwise.
- * e.g. In vCard 2.1, "\;" should be unescaped into ";" while "\x" should not be.
- */
- protected String maybeUnescapeCharacter(final char ch) {
- return unescapeCharacter(ch);
- }
-
- public static String unescapeCharacter(final char ch) {
- // Original vCard 2.1 specification does not allow transformation
- // "\:" -> ":", "\," -> ",", and "\\" -> "\", but previous implementation of
- // this class allowed them, so keep it as is.
- if (ch == '\\' || ch == ';' || ch == ':' || ch == ',') {
- return String.valueOf(ch);
- } else {
- return null;
- }
- }
-
- @Override
- public boolean parse(final InputStream is, final VCardInterpreter builder)
- throws IOException, VCardException {
- return parse(is, VCardConfig.DEFAULT_CHARSET, builder);
- }
-
- @Override
- public boolean parse(InputStream is, String charset, VCardInterpreter builder)
- throws IOException, VCardException {
- if (charset == null) {
- charset = VCardConfig.DEFAULT_CHARSET;
- }
- final InputStreamReader tmpReader = new InputStreamReader(is, charset);
- if (VCardConfig.showPerformanceLog()) {
- mReader = new CustomBufferedReader(tmpReader);
- } else {
- mReader = new BufferedReader(tmpReader);
- }
-
- mBuilder = builder;
-
- long start = System.currentTimeMillis();
- if (mBuilder != null) {
- mBuilder.start();
- }
- parseVCardFile();
- if (mBuilder != null) {
- mBuilder.end();
- }
- mTimeTotal += System.currentTimeMillis() - start;
-
- if (VCardConfig.showPerformanceLog()) {
- showPerformanceInfo();
- }
-
- return true;
- }
-
- @Override
- public void parse(InputStream is, String charset, VCardInterpreter builder, boolean canceled)
- throws IOException, VCardException {
- mCanceled = canceled;
- parse(is, charset, builder);
- }
-
- private void showPerformanceInfo() {
- Log.d(LOG_TAG, "Total parsing time: " + mTimeTotal + " ms");
- if (mReader instanceof CustomBufferedReader) {
- Log.d(LOG_TAG, "Total readLine time: " +
- ((CustomBufferedReader)mReader).getTotalmillisecond() + " ms");
- }
- Log.d(LOG_TAG, "Time for handling the beggining of the record: " +
- mTimeReadStartRecord + " ms");
- Log.d(LOG_TAG, "Time for handling the end of the record: " +
- mTimeReadEndRecord + " ms");
- Log.d(LOG_TAG, "Time for parsing line, and handling group: " +
- mTimeParseLineAndHandleGroup + " ms");
- Log.d(LOG_TAG, "Time for parsing ADR, ORG, and N fields:" + mTimeParseAdrOrgN + " ms");
- Log.d(LOG_TAG, "Time for parsing property values: " + mTimeParsePropertyValues + " ms");
- Log.d(LOG_TAG, "Time for handling normal property values: " +
- mTimeHandleMiscPropertyValue + " ms");
- Log.d(LOG_TAG, "Time for handling Quoted-Printable: " +
- mTimeHandleQuotedPrintable + " ms");
- Log.d(LOG_TAG, "Time for handling Base64: " + mTimeHandleBase64 + " ms");
- }
-
- private boolean isLetter(char ch) {
- if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) {
- return true;
- }
- return false;
- }
-}
-
-class CustomBufferedReader extends BufferedReader {
- private long mTime;
-
- public CustomBufferedReader(Reader in) {
- super(in);
- }
-
- @Override
- public String readLine() throws IOException {
- long start = System.currentTimeMillis();
- String ret = super.readLine();
- long end = System.currentTimeMillis();
- mTime += end - start;
- return ret;
- }
-
- public long getTotalmillisecond() {
- return mTime;
- }
-}
diff --git a/core/java/android/pim/vcard/VCardParser_V30.java b/core/java/android/pim/vcard/VCardParser_V30.java
deleted file mode 100644
index 4ecfe97..0000000
--- a/core/java/android/pim/vcard/VCardParser_V30.java
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.pim.vcard;
-
-import android.pim.vcard.exception.VCardException;
-import android.util.Log;
-
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.HashSet;
-
-/**
- * The class used to parse vCard 3.0.
- * Please refer to vCard Specification 3.0 (http://tools.ietf.org/html/rfc2426).
- */
-public class VCardParser_V30 extends VCardParser_V21 {
- private static final String LOG_TAG = "VCardParser_V30";
-
- private static final HashSet<String> sAcceptablePropsWithParam = new HashSet<String>(
- Arrays.asList(
- "BEGIN", "LOGO", "PHOTO", "LABEL", "FN", "TITLE", "SOUND",
- "VERSION", "TEL", "EMAIL", "TZ", "GEO", "NOTE", "URL",
- "BDAY", "ROLE", "REV", "UID", "KEY", "MAILER", // 2.1
- "NAME", "PROFILE", "SOURCE", "NICKNAME", "CLASS",
- "SORT-STRING", "CATEGORIES", "PRODID")); // 3.0
-
- // Although "7bit" and "BASE64" is not allowed in vCard 3.0, we allow it for safety.
- private static final HashSet<String> sAcceptableEncodingV30 = new HashSet<String>(
- Arrays.asList("7BIT", "8BIT", "BASE64", "B"));
-
- // Although RFC 2426 specifies some property must not have parameters, we allow it,
- // since there may be some careers which violates the RFC...
- private static final HashSet<String> acceptablePropsWithoutParam = new HashSet<String>();
-
- private String mPreviousLine;
-
- private boolean mEmittedAgentWarning = false;
-
- /**
- * True when the caller wants the parser to be strict about the input.
- * Currently this is only for testing.
- */
- private final boolean mStrictParsing;
-
- public VCardParser_V30() {
- super();
- mStrictParsing = false;
- }
-
- /**
- * @param strictParsing when true, this object throws VCardException when the vcard is not
- * valid from the view of vCard 3.0 specification (defined in RFC 2426). Note that this class
- * is not fully yet for being used with this flag and may not notice invalid line(s).
- *
- * @hide currently only for testing!
- */
- public VCardParser_V30(boolean strictParsing) {
- super();
- mStrictParsing = strictParsing;
- }
-
- public VCardParser_V30(int parseMode) {
- super(parseMode);
- mStrictParsing = false;
- }
-
- @Override
- protected int getVersion() {
- return VCardConfig.FLAG_V30;
- }
-
- @Override
- protected String getVersionString() {
- return VCardConstants.VERSION_V30;
- }
-
- @Override
- protected boolean isValidPropertyName(String propertyName) {
- if (!(sAcceptablePropsWithParam.contains(propertyName) ||
- acceptablePropsWithoutParam.contains(propertyName) ||
- propertyName.startsWith("X-")) &&
- !mUnknownTypeMap.contains(propertyName)) {
- mUnknownTypeMap.add(propertyName);
- Log.w(LOG_TAG, "Property name unsupported by vCard 3.0: " + propertyName);
- }
- return true;
- }
-
- @Override
- protected boolean isValidEncoding(String encoding) {
- return sAcceptableEncodingV30.contains(encoding.toUpperCase());
- }
-
- @Override
- protected String getLine() throws IOException {
- if (mPreviousLine != null) {
- String ret = mPreviousLine;
- mPreviousLine = null;
- return ret;
- } else {
- return mReader.readLine();
- }
- }
-
- /**
- * vCard 3.0 requires that the line with space at the beginning of the line
- * must be combined with previous line.
- */
- @Override
- protected String getNonEmptyLine() throws IOException, VCardException {
- String line;
- StringBuilder builder = null;
- while (true) {
- line = mReader.readLine();
- if (line == null) {
- if (builder != null) {
- return builder.toString();
- } else if (mPreviousLine != null) {
- String ret = mPreviousLine;
- mPreviousLine = null;
- return ret;
- }
- throw new VCardException("Reached end of buffer.");
- } else if (line.length() == 0) {
- if (builder != null) {
- return builder.toString();
- } else if (mPreviousLine != null) {
- String ret = mPreviousLine;
- mPreviousLine = null;
- return ret;
- }
- } else if (line.charAt(0) == ' ' || line.charAt(0) == '\t') {
- if (builder != null) {
- // See Section 5.8.1 of RFC 2425 (MIME-DIR document).
- // Following is the excerpts from it.
- //
- // DESCRIPTION:This is a long description that exists on a long line.
- //
- // Can be represented as:
- //
- // DESCRIPTION:This is a long description
- // that exists on a long line.
- //
- // It could also be represented as:
- //
- // DESCRIPTION:This is a long descrip
- // tion that exists o
- // n a long line.
- builder.append(line.substring(1));
- } else if (mPreviousLine != null) {
- builder = new StringBuilder();
- builder.append(mPreviousLine);
- mPreviousLine = null;
- builder.append(line.substring(1));
- } else {
- throw new VCardException("Space exists at the beginning of the line");
- }
- } else {
- if (mPreviousLine == null) {
- mPreviousLine = line;
- if (builder != null) {
- return builder.toString();
- }
- } else {
- String ret = mPreviousLine;
- mPreviousLine = line;
- return ret;
- }
- }
- }
- }
-
-
- /**
- * vcard = [group "."] "BEGIN" ":" "VCARD" 1 * CRLF
- * 1 * (contentline)
- * ;A vCard object MUST include the VERSION, FN and N types.
- * [group "."] "END" ":" "VCARD" 1 * CRLF
- */
- @Override
- protected boolean readBeginVCard(boolean allowGarbage) throws IOException, VCardException {
- // TODO: vCard 3.0 supports group.
- return super.readBeginVCard(allowGarbage);
- }
-
- @Override
- protected void readEndVCard(boolean useCache, boolean allowGarbage)
- throws IOException, VCardException {
- // TODO: vCard 3.0 supports group.
- super.readEndVCard(useCache, allowGarbage);
- }
-
- /**
- * vCard 3.0 allows iana-token as paramType, while vCard 2.1 does not.
- */
- @Override
- protected void handleParams(String params) throws VCardException {
- try {
- super.handleParams(params);
- } catch (VCardException e) {
- // maybe IANA type
- String[] strArray = params.split("=", 2);
- if (strArray.length == 2) {
- handleAnyParam(strArray[0], strArray[1]);
- } else {
- // Must not come here in the current implementation.
- throw new VCardException(
- "Unknown params value: " + params);
- }
- }
- }
-
- @Override
- protected void handleAnyParam(String paramName, String paramValue) {
- super.handleAnyParam(paramName, paramValue);
- }
-
- @Override
- protected void handleParamWithoutName(final String paramValue) throws VCardException {
- if (mStrictParsing) {
- throw new VCardException("Parameter without name is not acceptable in vCard 3.0");
- } else {
- super.handleParamWithoutName(paramValue);
- }
- }
-
- /**
- * vCard 3.0 defines
- *
- * param = param-name "=" param-value *("," param-value)
- * param-name = iana-token / x-name
- * param-value = ptext / quoted-string
- * quoted-string = DQUOTE QSAFE-CHAR DQUOTE
- */
- @Override
- protected void handleType(String ptypevalues) {
- String[] ptypeArray = ptypevalues.split(",");
- mBuilder.propertyParamType("TYPE");
- for (String value : ptypeArray) {
- int length = value.length();
- if (length >= 2 && value.startsWith("\"") && value.endsWith("\"")) {
- mBuilder.propertyParamValue(value.substring(1, value.length() - 1));
- } else {
- mBuilder.propertyParamValue(value);
- }
- }
- }
-
- @Override
- protected void handleAgent(String propertyValue) {
- // The way how vCard 3.0 supports "AGENT" is completely different from vCard 2.1.
- //
- // e.g.
- // AGENT:BEGIN:VCARD\nFN:Joe Friday\nTEL:+1-919-555-7878\n
- // TITLE:Area Administrator\, Assistant\n EMAIL\;TYPE=INTERN\n
- // ET:jfriday@host.com\nEND:VCARD\n
- //
- // TODO: fix this.
- //
- // issue:
- // vCard 3.0 also allows this as an example.
- //
- // AGENT;VALUE=uri:
- // CID:JQPUBLIC.part3.960129T083020.xyzMail@host3.com
- //
- // This is not vCard. Should we support this?
- //
- // Just ignore the line for now, since we cannot know how to handle it...
- if (!mEmittedAgentWarning) {
- Log.w(LOG_TAG, "AGENT in vCard 3.0 is not supported yet. Ignore it");
- mEmittedAgentWarning = true;
- }
- }
-
- /**
- * vCard 3.0 does not require two CRLF at the last of BASE64 data.
- * It only requires that data should be MIME-encoded.
- */
- @Override
- protected String getBase64(String firstString) throws IOException, VCardException {
- StringBuilder builder = new StringBuilder();
- builder.append(firstString);
-
- while (true) {
- String line = getLine();
- if (line == null) {
- throw new VCardException(
- "File ended during parsing BASE64 binary");
- }
- if (line.length() == 0) {
- break;
- } else if (!line.startsWith(" ") && !line.startsWith("\t")) {
- mPreviousLine = line;
- break;
- }
- builder.append(line);
- }
-
- return builder.toString();
- }
-
- /**
- * ESCAPED-CHAR = "\\" / "\;" / "\," / "\n" / "\N")
- * ; \\ encodes \, \n or \N encodes newline
- * ; \; encodes ;, \, encodes ,
- *
- * Note: Apple escapes ':' into '\:' while does not escape '\'
- */
- @Override
- protected String maybeUnescapeText(String text) {
- return unescapeText(text);
- }
-
- public static String unescapeText(String text) {
- StringBuilder builder = new StringBuilder();
- int length = text.length();
- for (int i = 0; i < length; i++) {
- char ch = text.charAt(i);
- if (ch == '\\' && i < length - 1) {
- char next_ch = text.charAt(++i);
- if (next_ch == 'n' || next_ch == 'N') {
- builder.append("\n");
- } else {
- builder.append(next_ch);
- }
- } else {
- builder.append(ch);
- }
- }
- return builder.toString();
- }
-
- @Override
- protected String maybeUnescapeCharacter(char ch) {
- return unescapeCharacter(ch);
- }
-
- public static String unescapeCharacter(char ch) {
- if (ch == 'n' || ch == 'N') {
- return "\n";
- } else {
- return String.valueOf(ch);
- }
- }
-}
diff --git a/core/java/android/pim/vcard/VCardSourceDetector.java b/core/java/android/pim/vcard/VCardSourceDetector.java
deleted file mode 100644
index 7297c50..0000000
--- a/core/java/android/pim/vcard/VCardSourceDetector.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.pim.vcard;
-
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * Class which tries to detects the source of the vCard from its properties.
- * Currently this implementation is very premature.
- * @hide
- */
-public class VCardSourceDetector implements VCardInterpreter {
- private static Set<String> APPLE_SIGNS = new HashSet<String>(Arrays.asList(
- "X-PHONETIC-FIRST-NAME", "X-PHONETIC-MIDDLE-NAME", "X-PHONETIC-LAST-NAME",
- "X-ABADR", "X-ABUID"));
-
- private static Set<String> JAPANESE_MOBILE_PHONE_SIGNS = new HashSet<String>(Arrays.asList(
- "X-GNO", "X-GN", "X-REDUCTION"));
-
- private static Set<String> WINDOWS_MOBILE_PHONE_SIGNS = new HashSet<String>(Arrays.asList(
- "X-MICROSOFT-ASST_TEL", "X-MICROSOFT-ASSISTANT", "X-MICROSOFT-OFFICELOC"));
-
- // Note: these signes appears before the signs of the other type (e.g. "X-GN").
- // In other words, Japanese FOMA mobile phones are detected as FOMA, not JAPANESE_MOBILE_PHONES.
- private static Set<String> FOMA_SIGNS = new HashSet<String>(Arrays.asList(
- "X-SD-VERN", "X-SD-FORMAT_VER", "X-SD-CATEGORIES", "X-SD-CLASS", "X-SD-DCREATED",
- "X-SD-DESCRIPTION"));
- private static String TYPE_FOMA_CHARSET_SIGN = "X-SD-CHAR_CODE";
-
- private int mType = VCardConfig.PARSE_TYPE_UNKNOWN;
- // Some mobile phones (like FOMA) tells us the charset of the data.
- private boolean mNeedParseSpecifiedCharset;
- private String mSpecifiedCharset;
-
- public void start() {
- }
-
- public void end() {
- }
-
- public void startEntry() {
- }
-
- public void startProperty() {
- mNeedParseSpecifiedCharset = false;
- }
-
- public void endProperty() {
- }
-
- public void endEntry() {
- }
-
- public void propertyGroup(String group) {
- }
-
- public void propertyName(String name) {
- if (name.equalsIgnoreCase(TYPE_FOMA_CHARSET_SIGN)) {
- mType = VCardConfig.PARSE_TYPE_FOMA;
- mNeedParseSpecifiedCharset = true;
- return;
- }
- if (mType != VCardConfig.PARSE_TYPE_UNKNOWN) {
- return;
- }
- if (WINDOWS_MOBILE_PHONE_SIGNS.contains(name)) {
- mType = VCardConfig.PARSE_TYPE_WINDOWS_MOBILE_JP;
- } else if (FOMA_SIGNS.contains(name)) {
- mType = VCardConfig.PARSE_TYPE_FOMA;
- } else if (JAPANESE_MOBILE_PHONE_SIGNS.contains(name)) {
- mType = VCardConfig.PARSE_TYPE_MOBILE_PHONE_JP;
- } else if (APPLE_SIGNS.contains(name)) {
- mType = VCardConfig.PARSE_TYPE_APPLE;
- }
- }
-
- public void propertyParamType(String type) {
- }
-
- public void propertyParamValue(String value) {
- }
-
- public void propertyValues(List<String> values) {
- if (mNeedParseSpecifiedCharset && values.size() > 0) {
- mSpecifiedCharset = values.get(0);
- }
- }
-
- /* package */ int getEstimatedType() {
- return mType;
- }
-
- /**
- * Return charset String guessed from the source's properties.
- * This method must be called after parsing target file(s).
- * @return Charset String. Null is returned if guessing the source fails.
- */
- public String getEstimatedCharset() {
- if (mSpecifiedCharset != null) {
- return mSpecifiedCharset;
- }
- switch (mType) {
- case VCardConfig.PARSE_TYPE_WINDOWS_MOBILE_JP:
- case VCardConfig.PARSE_TYPE_FOMA:
- case VCardConfig.PARSE_TYPE_MOBILE_PHONE_JP:
- return "SHIFT_JIS";
- case VCardConfig.PARSE_TYPE_APPLE:
- return "UTF-8";
- default:
- return null;
- }
- }
-}
diff --git a/core/java/android/pim/vcard/VCardUtils.java b/core/java/android/pim/vcard/VCardUtils.java
deleted file mode 100644
index 11b112b..0000000
--- a/core/java/android/pim/vcard/VCardUtils.java
+++ /dev/null
@@ -1,545 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.pim.vcard;
-
-import android.content.ContentProviderOperation;
-import android.provider.ContactsContract.Data;
-import android.provider.ContactsContract.CommonDataKinds.Im;
-import android.provider.ContactsContract.CommonDataKinds.Phone;
-import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
-import android.telephony.PhoneNumberUtils;
-import android.text.TextUtils;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Utilities for VCard handling codes.
- */
-public class VCardUtils {
- // Note that not all types are included in this map/set, since, for example, TYPE_HOME_FAX is
- // converted to two parameter Strings. These only contain some minor fields valid in both
- // vCard and current (as of 2009-08-07) Contacts structure.
- private static final Map<Integer, String> sKnownPhoneTypesMap_ItoS;
- private static final Set<String> sPhoneTypesUnknownToContactsSet;
- private static final Map<String, Integer> sKnownPhoneTypeMap_StoI;
- private static final Map<Integer, String> sKnownImPropNameMap_ItoS;
- private static final Set<String> sMobilePhoneLabelSet;
-
- static {
- sKnownPhoneTypesMap_ItoS = new HashMap<Integer, String>();
- sKnownPhoneTypeMap_StoI = new HashMap<String, Integer>();
-
- sKnownPhoneTypesMap_ItoS.put(Phone.TYPE_CAR, VCardConstants.PARAM_TYPE_CAR);
- sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_TYPE_CAR, Phone.TYPE_CAR);
- sKnownPhoneTypesMap_ItoS.put(Phone.TYPE_PAGER, VCardConstants.PARAM_TYPE_PAGER);
- sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_TYPE_PAGER, Phone.TYPE_PAGER);
- sKnownPhoneTypesMap_ItoS.put(Phone.TYPE_ISDN, VCardConstants.PARAM_TYPE_ISDN);
- sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_TYPE_ISDN, Phone.TYPE_ISDN);
-
- sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_TYPE_HOME, Phone.TYPE_HOME);
- sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_TYPE_WORK, Phone.TYPE_WORK);
- sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_TYPE_CELL, Phone.TYPE_MOBILE);
-
- sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_PHONE_EXTRA_TYPE_OTHER, Phone.TYPE_OTHER);
- sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_PHONE_EXTRA_TYPE_CALLBACK,
- Phone.TYPE_CALLBACK);
- sKnownPhoneTypeMap_StoI.put(
- VCardConstants.PARAM_PHONE_EXTRA_TYPE_COMPANY_MAIN, Phone.TYPE_COMPANY_MAIN);
- sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_PHONE_EXTRA_TYPE_RADIO, Phone.TYPE_RADIO);
- sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_PHONE_EXTRA_TYPE_TTY_TDD,
- Phone.TYPE_TTY_TDD);
- sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_PHONE_EXTRA_TYPE_ASSISTANT,
- Phone.TYPE_ASSISTANT);
-
- sPhoneTypesUnknownToContactsSet = new HashSet<String>();
- sPhoneTypesUnknownToContactsSet.add(VCardConstants.PARAM_TYPE_MODEM);
- sPhoneTypesUnknownToContactsSet.add(VCardConstants.PARAM_TYPE_MSG);
- sPhoneTypesUnknownToContactsSet.add(VCardConstants.PARAM_TYPE_BBS);
- sPhoneTypesUnknownToContactsSet.add(VCardConstants.PARAM_TYPE_VIDEO);
-
- sKnownImPropNameMap_ItoS = new HashMap<Integer, String>();
- sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_AIM, VCardConstants.PROPERTY_X_AIM);
- sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_MSN, VCardConstants.PROPERTY_X_MSN);
- sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_YAHOO, VCardConstants.PROPERTY_X_YAHOO);
- sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_SKYPE, VCardConstants.PROPERTY_X_SKYPE_USERNAME);
- sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_GOOGLE_TALK,
- VCardConstants.PROPERTY_X_GOOGLE_TALK);
- sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_ICQ, VCardConstants.PROPERTY_X_ICQ);
- sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_JABBER, VCardConstants.PROPERTY_X_JABBER);
- sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_QQ, VCardConstants.PROPERTY_X_QQ);
- sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_NETMEETING, VCardConstants.PROPERTY_X_NETMEETING);
-
- // \u643A\u5E2F\u96FB\u8A71 = Full-width Hiragana "Keitai-Denwa" (mobile phone)
- // \u643A\u5E2F = Full-width Hiragana "Keitai" (mobile phone)
- // \u30B1\u30A4\u30BF\u30A4 = Full-width Katakana "Keitai" (mobile phone)
- // \uFF79\uFF72\uFF80\uFF72 = Half-width Katakana "Keitai" (mobile phone)
- sMobilePhoneLabelSet = new HashSet<String>(Arrays.asList(
- "MOBILE", "\u643A\u5E2F\u96FB\u8A71", "\u643A\u5E2F", "\u30B1\u30A4\u30BF\u30A4",
- "\uFF79\uFF72\uFF80\uFF72"));
- }
-
- public static String getPhoneTypeString(Integer type) {
- return sKnownPhoneTypesMap_ItoS.get(type);
- }
-
- /**
- * Returns Interger when the given types can be parsed as known type. Returns String object
- * when not, which should be set to label.
- */
- public static Object getPhoneTypeFromStrings(Collection<String> types,
- String number) {
- if (number == null) {
- number = "";
- }
- int type = -1;
- String label = null;
- boolean isFax = false;
- boolean hasPref = false;
-
- if (types != null) {
- for (String typeString : types) {
- if (typeString == null) {
- continue;
- }
- typeString = typeString.toUpperCase();
- if (typeString.equals(VCardConstants.PARAM_TYPE_PREF)) {
- hasPref = true;
- } else if (typeString.equals(VCardConstants.PARAM_TYPE_FAX)) {
- isFax = true;
- } else {
- if (typeString.startsWith("X-") && type < 0) {
- typeString = typeString.substring(2);
- }
- if (typeString.length() == 0) {
- continue;
- }
- final Integer tmp = sKnownPhoneTypeMap_StoI.get(typeString);
- if (tmp != null) {
- final int typeCandidate = tmp;
- // TYPE_PAGER is prefered when the number contains @ surronded by
- // a pager number and a domain name.
- // e.g.
- // o 1111@domain.com
- // x @domain.com
- // x 1111@
- final int indexOfAt = number.indexOf("@");
- if ((typeCandidate == Phone.TYPE_PAGER
- && 0 < indexOfAt && indexOfAt < number.length() - 1)
- || type < 0
- || type == Phone.TYPE_CUSTOM) {
- type = tmp;
- }
- } else if (type < 0) {
- type = Phone.TYPE_CUSTOM;
- label = typeString;
- }
- }
- }
- }
- if (type < 0) {
- if (hasPref) {
- type = Phone.TYPE_MAIN;
- } else {
- // default to TYPE_HOME
- type = Phone.TYPE_HOME;
- }
- }
- if (isFax) {
- if (type == Phone.TYPE_HOME) {
- type = Phone.TYPE_FAX_HOME;
- } else if (type == Phone.TYPE_WORK) {
- type = Phone.TYPE_FAX_WORK;
- } else if (type == Phone.TYPE_OTHER) {
- type = Phone.TYPE_OTHER_FAX;
- }
- }
- if (type == Phone.TYPE_CUSTOM) {
- return label;
- } else {
- return type;
- }
- }
-
- @SuppressWarnings("deprecation")
- public static boolean isMobilePhoneLabel(final String label) {
- // For backward compatibility.
- // Detail: Until Donut, there isn't TYPE_MOBILE for email while there is now.
- // To support mobile type at that time, this custom label had been used.
- return (android.provider.Contacts.ContactMethodsColumns.MOBILE_EMAIL_TYPE_NAME.equals(label)
- || sMobilePhoneLabelSet.contains(label));
- }
-
- public static boolean isValidInV21ButUnknownToContactsPhoteType(final String label) {
- return sPhoneTypesUnknownToContactsSet.contains(label);
- }
-
- public static String getPropertyNameForIm(final int protocol) {
- return sKnownImPropNameMap_ItoS.get(protocol);
- }
-
- public static String[] sortNameElements(final int vcardType,
- final String familyName, final String middleName, final String givenName) {
- final String[] list = new String[3];
- final int nameOrderType = VCardConfig.getNameOrderType(vcardType);
- switch (nameOrderType) {
- case VCardConfig.NAME_ORDER_JAPANESE: {
- if (containsOnlyPrintableAscii(familyName) &&
- containsOnlyPrintableAscii(givenName)) {
- list[0] = givenName;
- list[1] = middleName;
- list[2] = familyName;
- } else {
- list[0] = familyName;
- list[1] = middleName;
- list[2] = givenName;
- }
- break;
- }
- case VCardConfig.NAME_ORDER_EUROPE: {
- list[0] = middleName;
- list[1] = givenName;
- list[2] = familyName;
- break;
- }
- default: {
- list[0] = givenName;
- list[1] = middleName;
- list[2] = familyName;
- break;
- }
- }
- return list;
- }
-
- public static int getPhoneNumberFormat(final int vcardType) {
- if (VCardConfig.isJapaneseDevice(vcardType)) {
- return PhoneNumberUtils.FORMAT_JAPAN;
- } else {
- return PhoneNumberUtils.FORMAT_NANP;
- }
- }
-
- /**
- * Inserts postal data into the builder object.
- *
- * Note that the data structure of ContactsContract is different from that defined in vCard.
- * So some conversion may be performed in this method.
- */
- public static void insertStructuredPostalDataUsingContactsStruct(int vcardType,
- final ContentProviderOperation.Builder builder,
- final VCardEntry.PostalData postalData) {
- builder.withValueBackReference(StructuredPostal.RAW_CONTACT_ID, 0);
- builder.withValue(Data.MIMETYPE, StructuredPostal.CONTENT_ITEM_TYPE);
-
- builder.withValue(StructuredPostal.TYPE, postalData.type);
- if (postalData.type == StructuredPostal.TYPE_CUSTOM) {
- builder.withValue(StructuredPostal.LABEL, postalData.label);
- }
-
- final String streetString;
- if (TextUtils.isEmpty(postalData.street)) {
- if (TextUtils.isEmpty(postalData.extendedAddress)) {
- streetString = null;
- } else {
- streetString = postalData.extendedAddress;
- }
- } else {
- if (TextUtils.isEmpty(postalData.extendedAddress)) {
- streetString = postalData.street;
- } else {
- streetString = postalData.street + " " + postalData.extendedAddress;
- }
- }
- builder.withValue(StructuredPostal.POBOX, postalData.pobox);
- builder.withValue(StructuredPostal.STREET, streetString);
- builder.withValue(StructuredPostal.CITY, postalData.localty);
- builder.withValue(StructuredPostal.REGION, postalData.region);
- builder.withValue(StructuredPostal.POSTCODE, postalData.postalCode);
- builder.withValue(StructuredPostal.COUNTRY, postalData.country);
-
- builder.withValue(StructuredPostal.FORMATTED_ADDRESS,
- postalData.getFormattedAddress(vcardType));
- if (postalData.isPrimary) {
- builder.withValue(Data.IS_PRIMARY, 1);
- }
- }
-
- public static String constructNameFromElements(final int vcardType,
- final String familyName, final String middleName, final String givenName) {
- return constructNameFromElements(vcardType, familyName, middleName, givenName,
- null, null);
- }
-
- public static String constructNameFromElements(final int vcardType,
- final String familyName, final String middleName, final String givenName,
- final String prefix, final String suffix) {
- final StringBuilder builder = new StringBuilder();
- final String[] nameList = sortNameElements(vcardType, familyName, middleName, givenName);
- boolean first = true;
- if (!TextUtils.isEmpty(prefix)) {
- first = false;
- builder.append(prefix);
- }
- for (final String namePart : nameList) {
- if (!TextUtils.isEmpty(namePart)) {
- if (first) {
- first = false;
- } else {
- builder.append(' ');
- }
- builder.append(namePart);
- }
- }
- if (!TextUtils.isEmpty(suffix)) {
- if (!first) {
- builder.append(' ');
- }
- builder.append(suffix);
- }
- return builder.toString();
- }
-
- public static List<String> constructListFromValue(final String value,
- final boolean isV30) {
- final List<String> list = new ArrayList<String>();
- StringBuilder builder = new StringBuilder();
- int length = value.length();
- for (int i = 0; i < length; i++) {
- char ch = value.charAt(i);
- if (ch == '\\' && i < length - 1) {
- char nextCh = value.charAt(i + 1);
- final String unescapedString =
- (isV30 ? VCardParser_V30.unescapeCharacter(nextCh) :
- VCardParser_V21.unescapeCharacter(nextCh));
- if (unescapedString != null) {
- builder.append(unescapedString);
- i++;
- } else {
- builder.append(ch);
- }
- } else if (ch == ';') {
- list.add(builder.toString());
- builder = new StringBuilder();
- } else {
- builder.append(ch);
- }
- }
- list.add(builder.toString());
- return list;
- }
-
- public static boolean containsOnlyPrintableAscii(final String...values) {
- if (values == null) {
- return true;
- }
- return containsOnlyPrintableAscii(Arrays.asList(values));
- }
-
- public static boolean containsOnlyPrintableAscii(final Collection<String> values) {
- if (values == null) {
- return true;
- }
- for (final String value : values) {
- if (TextUtils.isEmpty(value)) {
- continue;
- }
- if (!TextUtils.isPrintableAsciiOnly(value)) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * This is useful when checking the string should be encoded into quoted-printable
- * or not, which is required by vCard 2.1.
- * See the definition of "7bit" in vCard 2.1 spec for more information.
- */
- public static boolean containsOnlyNonCrLfPrintableAscii(final String...values) {
- if (values == null) {
- return true;
- }
- return containsOnlyNonCrLfPrintableAscii(Arrays.asList(values));
- }
-
- public static boolean containsOnlyNonCrLfPrintableAscii(final Collection<String> values) {
- if (values == null) {
- return true;
- }
- final int asciiFirst = 0x20;
- final int asciiLast = 0x7E; // included
- for (final String value : values) {
- if (TextUtils.isEmpty(value)) {
- continue;
- }
- final int length = value.length();
- for (int i = 0; i < length; i = value.offsetByCodePoints(i, 1)) {
- final int c = value.codePointAt(i);
- if (!(asciiFirst <= c && c <= asciiLast)) {
- return false;
- }
- }
- }
- return true;
- }
-
- private static final Set<Character> sUnAcceptableAsciiInV21WordSet =
- new HashSet<Character>(Arrays.asList('[', ']', '=', ':', '.', ',', ' '));
-
- /**
- * This is useful since vCard 3.0 often requires the ("X-") properties and groups
- * should contain only alphabets, digits, and hyphen.
- *
- * Note: It is already known some devices (wrongly) outputs properties with characters
- * which should not be in the field. One example is "X-GOOGLE TALK". We accept
- * such kind of input but must never output it unless the target is very specific
- * to the device which is able to parse the malformed input.
- */
- public static boolean containsOnlyAlphaDigitHyphen(final String...values) {
- if (values == null) {
- return true;
- }
- return containsOnlyAlphaDigitHyphen(Arrays.asList(values));
- }
-
- public static boolean containsOnlyAlphaDigitHyphen(final Collection<String> values) {
- if (values == null) {
- return true;
- }
- final int upperAlphabetFirst = 0x41; // A
- final int upperAlphabetAfterLast = 0x5b; // [
- final int lowerAlphabetFirst = 0x61; // a
- final int lowerAlphabetAfterLast = 0x7b; // {
- final int digitFirst = 0x30; // 0
- final int digitAfterLast = 0x3A; // :
- final int hyphen = '-';
- for (final String str : values) {
- if (TextUtils.isEmpty(str)) {
- continue;
- }
- final int length = str.length();
- for (int i = 0; i < length; i = str.offsetByCodePoints(i, 1)) {
- int codepoint = str.codePointAt(i);
- if (!((lowerAlphabetFirst <= codepoint && codepoint < lowerAlphabetAfterLast) ||
- (upperAlphabetFirst <= codepoint && codepoint < upperAlphabetAfterLast) ||
- (digitFirst <= codepoint && codepoint < digitAfterLast) ||
- (codepoint == hyphen))) {
- return false;
- }
- }
- }
- return true;
- }
-
- /**
- * <P>
- * Returns true when the given String is categorized as "word" specified in vCard spec 2.1.
- * </P>
- * <P>
- * vCard 2.1 specifies:<BR />
- * word = <any printable 7bit us-ascii except []=:., >
- * </P>
- */
- public static boolean isV21Word(final String value) {
- if (TextUtils.isEmpty(value)) {
- return true;
- }
- final int asciiFirst = 0x20;
- final int asciiLast = 0x7E; // included
- final int length = value.length();
- for (int i = 0; i < length; i = value.offsetByCodePoints(i, 1)) {
- final int c = value.codePointAt(i);
- if (!(asciiFirst <= c && c <= asciiLast) ||
- sUnAcceptableAsciiInV21WordSet.contains((char)c)) {
- return false;
- }
- }
- return true;
- }
-
- public static String toHalfWidthString(final String orgString) {
- if (TextUtils.isEmpty(orgString)) {
- return null;
- }
- final StringBuilder builder = new StringBuilder();
- final int length = orgString.length();
- for (int i = 0; i < length; i = orgString.offsetByCodePoints(i, 1)) {
- // All Japanese character is able to be expressed by char.
- // Do not need to use String#codepPointAt().
- final char ch = orgString.charAt(i);
- final String halfWidthText = JapaneseUtils.tryGetHalfWidthText(ch);
- if (halfWidthText != null) {
- builder.append(halfWidthText);
- } else {
- builder.append(ch);
- }
- }
- return builder.toString();
- }
-
- /**
- * Guesses the format of input image. Currently just the first few bytes are used.
- * The type "GIF", "PNG", or "JPEG" is returned when possible. Returns null when
- * the guess failed.
- * @param input Image as byte array.
- * @return The image type or null when the type cannot be determined.
- */
- public static String guessImageType(final byte[] input) {
- if (input == null) {
- return null;
- }
- if (input.length >= 3 && input[0] == 'G' && input[1] == 'I' && input[2] == 'F') {
- return "GIF";
- } else if (input.length >= 4 && input[0] == (byte) 0x89
- && input[1] == 'P' && input[2] == 'N' && input[3] == 'G') {
- // Note: vCard 2.1 officially does not support PNG, but we may have it and
- // using X- word like "X-PNG" may not let importers know it is PNG.
- // So we use the String "PNG" as is...
- return "PNG";
- } else if (input.length >= 2 && input[0] == (byte) 0xff
- && input[1] == (byte) 0xd8) {
- return "JPEG";
- } else {
- return null;
- }
- }
-
- /**
- * @return True when all the given values are null or empty Strings.
- */
- public static boolean areAllEmpty(final String...values) {
- if (values == null) {
- return true;
- }
-
- for (final String value : values) {
- if (!TextUtils.isEmpty(value)) {
- return false;
- }
- }
- return true;
- }
-
- private VCardUtils() {
- }
-}
diff --git a/core/java/android/pim/vcard/exception/VCardAgentNotSupportedException.java b/core/java/android/pim/vcard/exception/VCardAgentNotSupportedException.java
deleted file mode 100644
index e72c7df..0000000
--- a/core/java/android/pim/vcard/exception/VCardAgentNotSupportedException.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.pim.vcard.exception;
-
-public class VCardAgentNotSupportedException extends VCardNotSupportedException {
- public VCardAgentNotSupportedException() {
- super();
- }
-
- public VCardAgentNotSupportedException(String message) {
- super(message);
- }
-
-}
\ No newline at end of file
diff --git a/core/java/android/pim/vcard/exception/VCardException.java b/core/java/android/pim/vcard/exception/VCardException.java
deleted file mode 100644
index e557219..0000000
--- a/core/java/android/pim/vcard/exception/VCardException.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.pim.vcard.exception;
-
-public class VCardException extends java.lang.Exception {
- /**
- * Constructs a VCardException object
- */
- public VCardException() {
- super();
- }
-
- /**
- * Constructs a VCardException object
- *
- * @param message the error message
- */
- public VCardException(String message) {
- super(message);
- }
-
-}
diff --git a/core/java/android/pim/vcard/exception/VCardInvalidCommentLineException.java b/core/java/android/pim/vcard/exception/VCardInvalidCommentLineException.java
deleted file mode 100644
index 67db62c..0000000
--- a/core/java/android/pim/vcard/exception/VCardInvalidCommentLineException.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.pim.vcard.exception;
-
-/**
- * Thrown when the vCard has some line starting with '#'. In the specification,
- * both vCard 2.1 and vCard 3.0 does not allow such line, but some actual exporter emit
- * such lines.
- */
-public class VCardInvalidCommentLineException extends VCardInvalidLineException {
- public VCardInvalidCommentLineException() {
- super();
- }
-
- public VCardInvalidCommentLineException(final String message) {
- super(message);
- }
-}
diff --git a/core/java/android/pim/vcard/exception/VCardInvalidLineException.java b/core/java/android/pim/vcard/exception/VCardInvalidLineException.java
deleted file mode 100644
index 330153e..0000000
--- a/core/java/android/pim/vcard/exception/VCardInvalidLineException.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.pim.vcard.exception;
-
-/**
- * Thrown when the vCard has some line starting with '#'. In the specification,
- * both vCard 2.1 and vCard 3.0 does not allow such line, but some actual exporter emit
- * such lines.
- */
-public class VCardInvalidLineException extends VCardException {
- public VCardInvalidLineException() {
- super();
- }
-
- public VCardInvalidLineException(final String message) {
- super(message);
- }
-}
diff --git a/core/java/android/pim/vcard/exception/VCardNestedException.java b/core/java/android/pim/vcard/exception/VCardNestedException.java
deleted file mode 100644
index 503c2fb..0000000
--- a/core/java/android/pim/vcard/exception/VCardNestedException.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.pim.vcard.exception;
-
-/**
- * VCardException thrown when VCard is nested without VCardParser's being notified.
- */
-public class VCardNestedException extends VCardNotSupportedException {
- public VCardNestedException() {
- super();
- }
- public VCardNestedException(String message) {
- super(message);
- }
-}
diff --git a/core/java/android/pim/vcard/exception/VCardNotSupportedException.java b/core/java/android/pim/vcard/exception/VCardNotSupportedException.java
deleted file mode 100644
index 616aa7763..0000000
--- a/core/java/android/pim/vcard/exception/VCardNotSupportedException.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.pim.vcard.exception;
-
-/**
- * The exception which tells that the input VCard is probably valid from the view of
- * specification but not supported in the current framework for now.
- *
- * This is a kind of a good news from the view of development.
- * It may be good to ask users to send a report with the VCard example
- * for the future development.
- */
-public class VCardNotSupportedException extends VCardException {
- public VCardNotSupportedException() {
- super();
- }
- public VCardNotSupportedException(String message) {
- super(message);
- }
-}
\ No newline at end of file
diff --git a/core/java/android/pim/vcard/exception/VCardVersionException.java b/core/java/android/pim/vcard/exception/VCardVersionException.java
deleted file mode 100644
index 9fe8b7f..0000000
--- a/core/java/android/pim/vcard/exception/VCardVersionException.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.pim.vcard.exception;
-
-/**
- * VCardException used only when the version of the vCard is different.
- */
-public class VCardVersionException extends VCardException {
- public VCardVersionException() {
- super();
- }
- public VCardVersionException(String message) {
- super(message);
- }
-}
diff --git a/core/java/android/pim/vcard/exception/package.html b/core/java/android/pim/vcard/exception/package.html
deleted file mode 100644
index 26b8a32..0000000
--- a/core/java/android/pim/vcard/exception/package.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<HTML>
-<BODY>
-{@hide}
-</BODY>
-</HTML>
\ No newline at end of file
diff --git a/core/java/android/pim/vcard/package.html b/core/java/android/pim/vcard/package.html
deleted file mode 100644
index 26b8a32..0000000
--- a/core/java/android/pim/vcard/package.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<HTML>
-<BODY>
-{@hide}
-</BODY>
-</HTML>
\ No newline at end of file
diff --git a/core/java/android/preference/MultiSelectListPreference.java b/core/java/android/preference/MultiSelectListPreference.java
new file mode 100644
index 0000000..42d555cf
--- /dev/null
+++ b/core/java/android/preference/MultiSelectListPreference.java
@@ -0,0 +1,274 @@
+/*
+ * 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.preference;
+
+import android.app.AlertDialog.Builder;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.res.TypedArray;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.AttributeSet;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * A {@link Preference} that displays a list of entries as
+ * a dialog.
+ * <p>
+ * This preference will store a set of strings into the SharedPreferences.
+ * This set will contain one or more values from the
+ * {@link #setEntryValues(CharSequence[])} array.
+ *
+ * @attr ref android.R.styleable#MultiSelectListPreference_entries
+ * @attr ref android.R.styleable#MultiSelectListPreference_entryValues
+ */
+public class MultiSelectListPreference extends DialogPreference {
+ private CharSequence[] mEntries;
+ private CharSequence[] mEntryValues;
+ private Set<String> mValues = new HashSet<String>();
+ private Set<String> mNewValues = new HashSet<String>();
+ private boolean mPreferenceChanged;
+
+ public MultiSelectListPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+
+ TypedArray a = context.obtainStyledAttributes(attrs,
+ com.android.internal.R.styleable.MultiSelectListPreference, 0, 0);
+ mEntries = a.getTextArray(com.android.internal.R.styleable.MultiSelectListPreference_entries);
+ mEntryValues = a.getTextArray(com.android.internal.R.styleable.MultiSelectListPreference_entryValues);
+ a.recycle();
+ }
+
+ public MultiSelectListPreference(Context context) {
+ this(context, null);
+ }
+
+ /**
+ * Sets the human-readable entries to be shown in the list. This will be
+ * shown in subsequent dialogs.
+ * <p>
+ * Each entry must have a corresponding index in
+ * {@link #setEntryValues(CharSequence[])}.
+ *
+ * @param entries The entries.
+ * @see #setEntryValues(CharSequence[])
+ */
+ public void setEntries(CharSequence[] entries) {
+ mEntries = entries;
+ }
+
+ /**
+ * @see #setEntries(CharSequence[])
+ * @param entriesResId The entries array as a resource.
+ */
+ public void setEntries(int entriesResId) {
+ setEntries(getContext().getResources().getTextArray(entriesResId));
+ }
+
+ /**
+ * The list of entries to be shown in the list in subsequent dialogs.
+ *
+ * @return The list as an array.
+ */
+ public CharSequence[] getEntries() {
+ return mEntries;
+ }
+
+ /**
+ * The array to find the value to save for a preference when an entry from
+ * entries is selected. If a user clicks on the second item in entries, the
+ * second item in this array will be saved to the preference.
+ *
+ * @param entryValues The array to be used as values to save for the preference.
+ */
+ public void setEntryValues(CharSequence[] entryValues) {
+ mEntryValues = entryValues;
+ }
+
+ /**
+ * @see #setEntryValues(CharSequence[])
+ * @param entryValuesResId The entry values array as a resource.
+ */
+ public void setEntryValues(int entryValuesResId) {
+ setEntryValues(getContext().getResources().getTextArray(entryValuesResId));
+ }
+
+ /**
+ * Returns the array of values to be saved for the preference.
+ *
+ * @return The array of values.
+ */
+ public CharSequence[] getEntryValues() {
+ return mEntryValues;
+ }
+
+ /**
+ * Sets the value of the key. This should contain entries in
+ * {@link #getEntryValues()}.
+ *
+ * @param values The values to set for the key.
+ */
+ public void setValues(Set<String> values) {
+ mValues = values;
+
+ persistStringSet(values);
+ }
+
+ /**
+ * Retrieves the current value of the key.
+ */
+ public Set<String> getValues() {
+ return mValues;
+ }
+
+ /**
+ * Returns the index of the given value (in the entry values array).
+ *
+ * @param value The value whose index should be returned.
+ * @return The index of the value, or -1 if not found.
+ */
+ public int findIndexOfValue(String value) {
+ if (value != null && mEntryValues != null) {
+ for (int i = mEntryValues.length - 1; i >= 0; i--) {
+ if (mEntryValues[i].equals(value)) {
+ return i;
+ }
+ }
+ }
+ return -1;
+ }
+
+ @Override
+ protected void onPrepareDialogBuilder(Builder builder) {
+ super.onPrepareDialogBuilder(builder);
+
+ if (mEntries == null || mEntryValues == null) {
+ throw new IllegalStateException(
+ "MultiSelectListPreference requires an entries array and " +
+ "an entryValues array.");
+ }
+
+ boolean[] checkedItems = getSelectedItems();
+ builder.setMultiChoiceItems(mEntries, checkedItems,
+ new DialogInterface.OnMultiChoiceClickListener() {
+ public void onClick(DialogInterface dialog, int which, boolean isChecked) {
+ if (isChecked) {
+ mPreferenceChanged |= mNewValues.add(mEntries[which].toString());
+ } else {
+ mPreferenceChanged |= mNewValues.remove(mEntries[which].toString());
+ }
+ }
+ });
+ mNewValues.clear();
+ mNewValues.addAll(mValues);
+ }
+
+ private boolean[] getSelectedItems() {
+ final CharSequence[] entries = mEntries;
+ final int entryCount = entries.length;
+ final Set<String> values = mValues;
+ boolean[] result = new boolean[entryCount];
+
+ for (int i = 0; i < entryCount; i++) {
+ result[i] = values.contains(entries[i].toString());
+ }
+
+ return result;
+ }
+
+ @Override
+ protected void onDialogClosed(boolean positiveResult) {
+ super.onDialogClosed(positiveResult);
+
+ if (positiveResult && mPreferenceChanged) {
+ final Set<String> values = mNewValues;
+ if (callChangeListener(values)) {
+ setValues(values);
+ }
+ }
+ mPreferenceChanged = false;
+ }
+
+ @Override
+ protected Object onGetDefaultValue(TypedArray a, int index) {
+ final CharSequence[] defaultValues = a.getTextArray(index);
+ final int valueCount = defaultValues.length;
+ final Set<String> result = new HashSet<String>();
+
+ for (int i = 0; i < valueCount; i++) {
+ result.add(defaultValues[i].toString());
+ }
+
+ return result;
+ }
+
+ @Override
+ protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
+ setValues(restoreValue ? getPersistedStringSet(mValues) : (Set<String>) defaultValue);
+ }
+
+ @Override
+ protected Parcelable onSaveInstanceState() {
+ final Parcelable superState = super.onSaveInstanceState();
+ if (isPersistent()) {
+ // No need to save instance state
+ return superState;
+ }
+
+ final SavedState myState = new SavedState(superState);
+ myState.values = getValues();
+ return myState;
+ }
+
+ private static class SavedState extends BaseSavedState {
+ Set<String> values;
+
+ public SavedState(Parcel source) {
+ super(source);
+ values = new HashSet<String>();
+ String[] strings = source.readStringArray();
+
+ final int stringCount = strings.length;
+ for (int i = 0; i < stringCount; i++) {
+ values.add(strings[i]);
+ }
+ }
+
+ public SavedState(Parcelable superState) {
+ super(superState);
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ dest.writeStringArray(values.toArray(new String[0]));
+ }
+
+ public static final Parcelable.Creator<SavedState> CREATOR =
+ new Parcelable.Creator<SavedState>() {
+ public SavedState createFromParcel(Parcel in) {
+ return new SavedState(in);
+ }
+
+ public SavedState[] newArray(int size) {
+ return new SavedState[size];
+ }
+ };
+ }
+}
diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java
index 197d976..381f794 100644
--- a/core/java/android/preference/Preference.java
+++ b/core/java/android/preference/Preference.java
@@ -16,8 +16,7 @@
package android.preference;
-import java.util.ArrayList;
-import java.util.List;
+import com.android.internal.util.CharSequences;
import android.content.Context;
import android.content.Intent;
@@ -28,7 +27,6 @@
import android.os.Parcelable;
import android.text.TextUtils;
import android.util.AttributeSet;
-import com.android.internal.util.CharSequences;
import android.view.AbsSavedState;
import android.view.LayoutInflater;
import android.view.View;
@@ -36,6 +34,10 @@
import android.widget.ListView;
import android.widget.TextView;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
/**
* Represents the basic Preference UI building
* block displayed by a {@link PreferenceActivity} in the form of a
@@ -1250,6 +1252,61 @@
}
/**
+ * Attempts to persist a set of Strings to the {@link android.content.SharedPreferences}.
+ * <p>
+ * This will check if this Preference is persistent, get an editor from
+ * the {@link PreferenceManager}, put in the strings, and check if we should commit (and
+ * commit if so).
+ *
+ * @param values The values to persist.
+ * @return True if the Preference is persistent. (This is not whether the
+ * value was persisted, since we may not necessarily commit if there
+ * will be a batch commit later.)
+ * @see #getPersistedString(Set)
+ *
+ * @hide Pending API approval
+ */
+ protected boolean persistStringSet(Set<String> values) {
+ if (shouldPersist()) {
+ // Shouldn't store null
+ if (values.equals(getPersistedStringSet(null))) {
+ // It's already there, so the same as persisting
+ return true;
+ }
+
+ SharedPreferences.Editor editor = mPreferenceManager.getEditor();
+ editor.putStringSet(mKey, values);
+ tryCommit(editor);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Attempts to get a persisted set of Strings from the
+ * {@link android.content.SharedPreferences}.
+ * <p>
+ * This will check if this Preference is persistent, get the SharedPreferences
+ * from the {@link PreferenceManager}, and get the value.
+ *
+ * @param defaultReturnValue The default value to return if either the
+ * Preference is not persistent or the Preference is not in the
+ * shared preferences.
+ * @return The value from the SharedPreferences or the default return
+ * value.
+ * @see #persistStringSet(Set)
+ *
+ * @hide Pending API approval
+ */
+ protected Set<String> getPersistedStringSet(Set<String> defaultReturnValue) {
+ if (!shouldPersist()) {
+ return defaultReturnValue;
+ }
+
+ return mPreferenceManager.getSharedPreferences().getStringSet(mKey, defaultReturnValue);
+ }
+
+ /**
* Attempts to persist an int to the {@link android.content.SharedPreferences}.
*
* @param value The value to persist.
diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java
index 726793d..4686978 100644
--- a/core/java/android/preference/PreferenceActivity.java
+++ b/core/java/android/preference/PreferenceActivity.java
@@ -23,7 +23,10 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
+import android.text.TextUtils;
import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
/**
* Shows a hierarchy of {@link Preference} objects as
@@ -69,30 +72,43 @@
* As a convenience, this activity implements a click listener for any
* preference in the current hierarchy, see
* {@link #onPreferenceTreeClick(PreferenceScreen, Preference)}.
- *
+ *
* @see Preference
* @see PreferenceScreen
*/
public abstract class PreferenceActivity extends ListActivity implements
PreferenceManager.OnPreferenceTreeClickListener {
-
+
private static final String PREFERENCES_TAG = "android:preferences";
-
+
+ // extras that allow any preference activity to be launched as part of a wizard
+
+ // show Back and Next buttons? takes boolean parameter
+ // Back will then return RESULT_CANCELED and Next RESULT_OK
+ private static final String EXTRA_PREFS_SHOW_BUTTON_BAR = "extra_prefs_show_button_bar";
+
+ // specify custom text for the Back or Next buttons, or cause a button to not appear
+ // at all by setting it to null
+ private static final String EXTRA_PREFS_SET_NEXT_TEXT = "extra_prefs_set_next_text";
+ private static final String EXTRA_PREFS_SET_BACK_TEXT = "extra_prefs_set_back_text";
+
+ private Button mNextButton;
+
private PreferenceManager mPreferenceManager;
-
+
private Bundle mSavedInstanceState;
/**
* The starting request code given out to preference framework.
*/
private static final int FIRST_REQUEST_CODE = 100;
-
+
private static final int MSG_BIND_PREFERENCES = 0;
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
-
+
case MSG_BIND_PREFERENCES:
bindPreferences();
break;
@@ -105,7 +121,49 @@
super.onCreate(savedInstanceState);
setContentView(com.android.internal.R.layout.preference_list_content);
-
+
+ // see if we should show Back/Next buttons
+ Intent intent = getIntent();
+ if (intent.getBooleanExtra(EXTRA_PREFS_SHOW_BUTTON_BAR, false)) {
+
+ findViewById(com.android.internal.R.id.button_bar).setVisibility(View.VISIBLE);
+
+ Button backButton = (Button)findViewById(com.android.internal.R.id.back_button);
+ backButton.setOnClickListener(new OnClickListener() {
+ public void onClick(View v) {
+ setResult(RESULT_CANCELED);
+ finish();
+ }
+ });
+ mNextButton = (Button)findViewById(com.android.internal.R.id.next_button);
+ mNextButton.setOnClickListener(new OnClickListener() {
+ public void onClick(View v) {
+ setResult(RESULT_OK);
+ finish();
+ }
+ });
+
+ // set our various button parameters
+ if (intent.hasExtra(EXTRA_PREFS_SET_NEXT_TEXT)) {
+ String buttonText = intent.getStringExtra(EXTRA_PREFS_SET_NEXT_TEXT);
+ if (TextUtils.isEmpty(buttonText)) {
+ mNextButton.setVisibility(View.GONE);
+ }
+ else {
+ mNextButton.setText(buttonText);
+ }
+ }
+ if (intent.hasExtra(EXTRA_PREFS_SET_BACK_TEXT)) {
+ String buttonText = intent.getStringExtra(EXTRA_PREFS_SET_BACK_TEXT);
+ if (TextUtils.isEmpty(buttonText)) {
+ backButton.setVisibility(View.GONE);
+ }
+ else {
+ backButton.setText(buttonText);
+ }
+ }
+ }
+
mPreferenceManager = onCreatePreferenceManager();
getListView().setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
}
@@ -113,14 +171,13 @@
@Override
protected void onStop() {
super.onStop();
-
+
mPreferenceManager.dispatchActivityStop();
}
@Override
protected void onDestroy() {
super.onDestroy();
-
mPreferenceManager.dispatchActivityDestroy();
}
@@ -156,7 +213,7 @@
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
-
+
mPreferenceManager.dispatchActivityResult(requestCode, resultCode, data);
}
@@ -176,7 +233,7 @@
if (mHandler.hasMessages(MSG_BIND_PREFERENCES)) return;
mHandler.obtainMessage(MSG_BIND_PREFERENCES).sendToTarget();
}
-
+
private void bindPreferences() {
final PreferenceScreen preferenceScreen = getPreferenceScreen();
if (preferenceScreen != null) {
@@ -187,10 +244,10 @@
}
}
}
-
+
/**
* Creates the {@link PreferenceManager}.
- *
+ *
* @return The {@link PreferenceManager} used by this activity.
*/
private PreferenceManager onCreatePreferenceManager() {
@@ -198,7 +255,7 @@
preferenceManager.setOnPreferenceTreeClickListener(this);
return preferenceManager;
}
-
+
/**
* Returns the {@link PreferenceManager} used by this activity.
* @return The {@link PreferenceManager}.
@@ -206,7 +263,7 @@
public PreferenceManager getPreferenceManager() {
return mPreferenceManager;
}
-
+
private void requirePreferenceManager() {
if (mPreferenceManager == null) {
throw new RuntimeException("This should be called after super.onCreate.");
@@ -215,7 +272,7 @@
/**
* Sets the root of the preference hierarchy that this activity is showing.
- *
+ *
* @param preferenceScreen The root {@link PreferenceScreen} of the preference hierarchy.
*/
public void setPreferenceScreen(PreferenceScreen preferenceScreen) {
@@ -228,37 +285,37 @@
}
}
}
-
+
/**
* Gets the root of the preference hierarchy that this activity is showing.
- *
+ *
* @return The {@link PreferenceScreen} that is the root of the preference
* hierarchy.
*/
public PreferenceScreen getPreferenceScreen() {
return mPreferenceManager.getPreferenceScreen();
}
-
+
/**
* Adds preferences from activities that match the given {@link Intent}.
- *
+ *
* @param intent The {@link Intent} to query activities.
*/
public void addPreferencesFromIntent(Intent intent) {
requirePreferenceManager();
-
+
setPreferenceScreen(mPreferenceManager.inflateFromIntent(intent, getPreferenceScreen()));
}
-
+
/**
* Inflates the given XML resource and adds the preference hierarchy to the current
* preference hierarchy.
- *
+ *
* @param preferencesResId The XML resource ID to inflate.
*/
public void addPreferencesFromResource(int preferencesResId) {
requirePreferenceManager();
-
+
setPreferenceScreen(mPreferenceManager.inflateFromResource(this, preferencesResId,
getPreferenceScreen()));
}
@@ -269,20 +326,20 @@
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
return false;
}
-
+
/**
* Finds a {@link Preference} based on its key.
- *
+ *
* @param key The key of the preference to retrieve.
* @return The {@link Preference} with the key, or null.
* @see PreferenceGroup#findPreference(CharSequence)
*/
public Preference findPreference(CharSequence key) {
-
+
if (mPreferenceManager == null) {
return null;
}
-
+
return mPreferenceManager.findPreference(key);
}
@@ -292,5 +349,14 @@
mPreferenceManager.dispatchNewIntent(intent);
}
}
-
+
+ // give subclasses access to the Next button
+ /** @hide */
+ protected boolean hasNextButton() {
+ return mNextButton != null;
+ }
+ /** @hide */
+ protected Button getNextButton() {
+ return mNextButton;
+ }
}
diff --git a/core/java/android/provider/Calendar.java b/core/java/android/provider/Calendar.java
index 9a09805..8459b2d 100644
--- a/core/java/android/provider/Calendar.java
+++ b/core/java/android/provider/Calendar.java
@@ -438,6 +438,18 @@
public static final String DTEND = "dtend";
/**
+ * The time the event starts with allDay events in a local tz
+ * <P>Type: INTEGER (long; millis since epoch)</P>
+ */
+ public static final String DTSTART2 = "dtstart2";
+
+ /**
+ * The time the event ends with allDay events in a local tz
+ * <P>Type: INTEGER (long; millis since epoch)</P>
+ */
+ public static final String DTEND2 = "dtend2";
+
+ /**
* The duration of the event
* <P>Type: TEXT (duration in RFC2445 format)</P>
*/
@@ -450,6 +462,12 @@
public static final String EVENT_TIMEZONE = "eventTimezone";
/**
+ * The timezone for the event, allDay events will have a local tz instead of UTC
+ * <P>Type: TEXT
+ */
+ public static final String EVENT_TIMEZONE2 = "eventTimezone2";
+
+ /**
* Whether the event lasts all day or not
* <P>Type: INTEGER (boolean)</P>
*/
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 40a408a..218f21c 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -130,6 +130,17 @@
public static final String REQUESTING_PACKAGE_PARAM_KEY = "requesting_package";
/**
+ * Query parameter that should be used by the client to access a specific
+ * {@link Directory}. The parameter value should be the _ID of the corresponding
+ * directory, e.g.
+ * {@code content://com.android.contacts/data/emails/filter/acme?directory=3}
+ *
+ * @hide
+ */
+ public static final String DIRECTORY_PARAM_KEY = "directory";
+
+
+ /**
* @hide
*/
public static final class Preferences {
@@ -181,6 +192,227 @@
}
/**
+ * A Directory represents a contacts corpus, e.g. Local contacts,
+ * Google Apps Global Address List or Corporate Global Address List.
+ * <p>
+ * A Directory is implemented as a content provider with its unique authority and
+ * the same API as the main Contacts Provider. However, there is no expectation that
+ * every directory provider will implement this Contract in its entirety. If a
+ * directory provider does not have an implementation for a specific request, it
+ * should throw an UnsupportedOperationException.
+ * </p>
+ * <p>
+ * The most important use case for Directories is search. A Directory provider is
+ * expected to support at least {@link Contacts#CONTENT_FILTER_URI
+ * Contacts#CONTENT_FILTER_URI}. If a Directory provider wants to participate
+ * in email and phone lookup functionalities, it should also implement
+ * {@link CommonDataKinds.Email#CONTENT_FILTER_URI CommonDataKinds.Email.CONTENT_FILTER_URI}
+ * and
+ * {@link CommonDataKinds.Phone#CONTENT_FILTER_URI CommonDataKinds.Phone.CONTENT_FILTER_URI}.
+ * </p>
+ * <p>
+ * A directory provider should return NULL for every projection field it does not
+ * recognize, rather than throwing an exception. This way it will not be broken
+ * if ContactsContract is extended with new fields in the future.
+ * </p>
+ * <p>
+ * The client interacts with a directory via Contacts Provider by supplying an
+ * optional {@code directory=} query parameter.
+ * <p>
+ * <p>
+ * When the Contacts Provider receives the request, it transforms the URI and forwards
+ * the request to the corresponding directory content provider.
+ * The URI is transformed in the following fashion:
+ * <ul>
+ * <li>The URI authority is replaced with the corresponding {@link #DIRECTORY_AUTHORITY}.</li>
+ * <li>The {@code accountName=} and {@code accountType=} parameters are added or
+ * replaced using the corresponding {@link #ACCOUNT_TYPE} and {@link #ACCOUNT_NAME} values.</li>
+ * <li>If the URI is missing a {@link ContactsContract#REQUESTING_PACKAGE_PARAM_KEY}
+ * parameter, this parameter is added.</li>
+ * </ul>
+ * </p>
+ * <p>
+ * Clients should send directory requests to Contacts Provider and let it
+ * forward them to the respective providers rather than constructing directory provider
+ * URIs by themselves. This level of indirection allows Contacts Provider to
+ * implement additional system-level features and optimizations.
+ * Also, directory providers may reject requests coming from other
+ * clients than the Contacts Provider itself.
+ * </p>
+ * <p>
+ * The Directory table always has at least these two rows:
+ * <ul>
+ * <li>
+ * The local directory. It has {@link Directory#_ID Directory._ID} =
+ * {@link Directory#DEFAULT Directory.DEFAULT}. This directory can be used to access locally
+ * stored contacts. The same can be achieved by omitting the {@code directory=}
+ * parameter altogether.
+ * </li>
+ * <li>
+ * The local invisible contacts. The corresponding directory ID is
+ * {@link Directory#LOCAL_INVISIBLE Directory.LOCAL_INVISIBLE}.
+ * </li>
+ * </ul>
+ * </p>
+ * <p>
+ * Other directories should register themselves by explicitly adding rows to this table.
+ * </p>
+ * <p>
+ * When a row is inserted in this table, it is automatically associated with the package
+ * (apk) that made the request. If the package is later uninstalled, all directory rows
+ * it inserted are automatically removed.
+ * </p>
+ * <p>
+ * A directory row can be optionally associated with an account.
+ * If the account is later removed, the corresponding directory rows are
+ * automatically removed.
+ * </p>
+ *
+ * @hide
+ */
+ public static final class Directory implements BaseColumns {
+
+ /**
+ * Not instantiable.
+ */
+ private Directory() {
+ }
+
+ /**
+ * The content:// style URI for this table. Requests to this URI can be
+ * performed on the UI thread because they are always unblocking.
+ *
+ * @hide
+ */
+ public static final Uri CONTENT_URI =
+ Uri.withAppendedPath(AUTHORITY_URI, "directories");
+
+ /**
+ * The MIME-type of {@link #CONTENT_URI} providing a directory of
+ * contact directories.
+ *
+ * @hide
+ */
+ public static final String CONTENT_TYPE =
+ "vnd.android.cursor.dir/contact_directories";
+
+ /**
+ * The MIME type of a {@link #CONTENT_URI} item.
+ */
+ public static final String CONTENT_ITEM_TYPE =
+ "vnd.android.cursor.item/contact_directory";
+
+ /**
+ * The name of the package that owns this directory. This field is
+ * required in an insert request and must match the name of the package
+ * making the request. If the package is later uninstalled, the
+ * directories it owns are automatically removed from this table. Only
+ * the specified package is allowed to modify or delete this row later.
+ *
+ * <p>TYPE: TEXT</p>
+ *
+ * @hide
+ */
+ public static final String PACKAGE_NAME = "packageName";
+
+ /**
+ * The type of directory captured as a resource ID in the context of the
+ * package {@link #PACKAGE_NAME}, e.g. "Corporate Directory"
+ *
+ * <p>TYPE: INTEGER</p>
+ *
+ * @hide
+ */
+ public static final String TYPE_RESOURCE_ID = "typeResourceId";
+
+ /**
+ * An optional name that can be used in the UI to represent this directory,
+ * e.g. "Acme Corp"
+ * <p>TYPE: text</p>
+ *
+ * @hide
+ */
+ public static final String DISPLAY_NAME = "displayName";
+
+ /**
+ * The authority to which the request should forwarded in order to access
+ * this directory.
+ *
+ * <p>TYPE: text</p>
+ *
+ * @hide
+ */
+ public static final String DIRECTORY_AUTHORITY = "authority";
+
+ /**
+ * The account type which this directory is associated.
+ *
+ * <p>TYPE: text</p>
+ *
+ * @hide
+ */
+ public static final String ACCOUNT_TYPE = "accountType";
+
+ /**
+ * The account with which this directory is associated. If the account is later
+ * removed, the directories it owns are automatically removed from this table.
+ *
+ * <p>TYPE: text</p>
+ *
+ * @hide
+ */
+ public static final String ACCOUNT_NAME = "accountName";
+
+ /**
+ * One of {@link #EXPORT_SUPPORT_NONE}, {@link #EXPORT_SUPPORT_ANY_ACCOUNT},
+ * {@link #EXPORT_SUPPORT_SAME_ACCOUNT_ONLY}. This is the expectation the
+ * directory has for data exported from it. Clients must obey this setting.
+ *
+ * @hide
+ */
+ public static final String EXPORT_SUPPORT = "exportSupport";
+
+ /**
+ * An {@link #EXPORT_SUPPORT} setting that indicates that the directory
+ * does not allow any data to be copied out of it.
+ *
+ * @hide
+ */
+ public static final int EXPORT_SUPPORT_NONE = 0;
+
+ /**
+ * An {@link #EXPORT_SUPPORT} setting that indicates that the directory
+ * allow its data copied only to the account specified by
+ * {@link #ACCOUNT_TYPE}/{@link #ACCOUNT_NAME}.
+ *
+ * @hide
+ */
+ public static final int EXPORT_SUPPORT_SAME_ACCOUNT_ONLY = 1;
+
+ /**
+ * An {@link #EXPORT_SUPPORT} setting that indicates that the directory
+ * allow its data copied to any contacts account.
+ *
+ * @hide
+ */
+ public static final int EXPORT_SUPPORT_ANY_ACCOUNT = 2;
+
+ /**
+ * _ID of the default directory, which represents locally stored contacts.
+ *
+ * @hide
+ */
+ public static final long DEFAULT = 0;
+
+ /**
+ * _ID of the directory that represents locally stored invisible contacts.
+ *
+ * @hide
+ */
+ public static final long LOCAL_INVISIBLE = 1;
+ }
+
+ /**
* @hide should be removed when users are updated to refer to SyncState
* @deprecated use SyncState instead
*/
@@ -4902,6 +5134,23 @@
* Type: INTEGER (boolean)
*/
public static final String SHOULD_SYNC = "should_sync";
+
+ /**
+ * Any newly created contacts will automatically be added to groups that have this
+ * flag set to true.
+ * <p>
+ * Type: INTEGER (boolean)
+ */
+ public static final String AUTO_ADD = "auto_add";
+
+ /**
+ * When a contacts is marked as a favorites it will be automatically added
+ * to the groups that have this flag set, and when it is removed from favorites
+ * it will be removed from these groups.
+ * <p>
+ * Type: INTEGER (boolean)
+ */
+ public static final String FAVORITES = "favorites";
}
/**
@@ -5042,6 +5291,8 @@
DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, values, DELETED);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, NOTES);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, SHOULD_SYNC);
+ DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, FAVORITES);
+ DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, AUTO_ADD);
cursor.moveToNext();
return new Entity(values);
}
@@ -5558,6 +5809,28 @@
"com.android.contacts.action.SHOW_OR_CREATE_CONTACT";
/**
+ * Starts an Activity that lets the user select the multiple phones from a
+ * list of phone numbers which come from the contacts or
+ * {@link #EXTRA_PHONE_URIS}.
+ * <p>
+ * The phone numbers being passed in through {@link #EXTRA_PHONE_URIS}
+ * could belong to the contacts or not, and will be selected by default.
+ * <p>
+ * The user's selection will be returned from
+ * {@link android.app.Activity#onActivityResult(int, int, android.content.Intent)}
+ * if the resultCode is
+ * {@link android.app.Activity#RESULT_OK}, the array of picked phone
+ * numbers are in the Intent's
+ * {@link #EXTRA_PHONE_URIS}; otherwise, the
+ * {@link android.app.Activity#RESULT_CANCELED} is returned if the user
+ * left the Activity without changing the selection.
+ *
+ * @hide
+ */
+ public static final String ACTION_GET_MULTIPLE_PHONES =
+ "com.android.contacts.action.GET_MULTIPLE_PHONES";
+
+ /**
* Used with {@link #SHOW_OR_CREATE_CONTACT} to force creating a new
* contact if no matching contact found. Otherwise, default behavior is
* to prompt user with dialog before creating.
@@ -5578,6 +5851,23 @@
"com.android.contacts.action.CREATE_DESCRIPTION";
/**
+ * Used with {@link #ACTION_GET_MULTIPLE_PHONES} as the input or output value.
+ * <p>
+ * The phone numbers want to be picked by default should be passed in as
+ * input value. These phone numbers could belong to the contacts or not.
+ * <p>
+ * The phone numbers which were picked by the user are returned as output
+ * value.
+ * <p>
+ * Type: array of URIs, the tel URI is used for the phone numbers which don't
+ * belong to any contact, the content URI is used for phone id in contacts.
+ *
+ * @hide
+ */
+ public static final String EXTRA_PHONE_URIS =
+ "com.android.contacts.extra.PHONE_URIS";
+
+ /**
* Optional extra used with {@link #SHOW_OR_CREATE_CONTACT} to specify a
* dialog location using screen coordinates. When not specified, the
* dialog will be centered.
diff --git a/core/java/android/provider/Mtp.java b/core/java/android/provider/Mtp.java
new file mode 100644
index 0000000..ce2aa8d
--- /dev/null
+++ b/core/java/android/provider/Mtp.java
@@ -0,0 +1,100 @@
+/*
+ * 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.provider;
+
+import android.content.ContentUris;
+import android.net.Uri;
+import android.util.Log;
+
+
+/**
+ * The MTP provider supports accessing content on MTP and PTP devices.
+ * @hide
+ */
+public final class Mtp
+{
+ private final static String TAG = "Mtp";
+
+ public static final String AUTHORITY = "mtp";
+
+ private static final String CONTENT_AUTHORITY_SLASH = "content://" + AUTHORITY + "/";
+ private static final String CONTENT_AUTHORITY_DEVICE_SLASH = "content://" + AUTHORITY + "/device/";
+
+ /**
+ * Contains list of all MTP/PTP devices
+ */
+ public static final class Device implements BaseColumns {
+
+ public static final Uri CONTENT_URI = Uri.parse(CONTENT_AUTHORITY_SLASH + "device");
+
+ /**
+ * The manufacturer of the device
+ * <P>Type: TEXT</P>
+ */
+ public static final String MANUFACTURER = "manufacturer";
+
+ /**
+ * The model name of the device
+ * <P>Type: TEXT</P>
+ */
+ public static final String MODEL = "model";
+ }
+
+ /**
+ * Contains list of storage units for an MTP/PTP device
+ */
+ public static final class Storage implements BaseColumns {
+
+ public static Uri getContentUri(int deviceID) {
+ return Uri.parse(CONTENT_AUTHORITY_DEVICE_SLASH + deviceID + "/storage");
+ }
+
+ /**
+ * Storage unit identifier
+ * <P>Type: TEXT</P>
+ */
+ public static final String IDENTIFIER = "identifier";
+
+ /**
+ * Storage unit description
+ * <P>Type: TEXT</P>
+ */
+ public static final String DESCRIPTION = "description";
+ }
+
+ /**
+ * Contains list of objects on an MTP/PTP device
+ */
+ public static final class Object implements BaseColumns {
+
+ public static Uri getContentUriForObjectChildren(int deviceID, int objectID) {
+ return Uri.parse(CONTENT_AUTHORITY_DEVICE_SLASH + deviceID
+ + "/object/" + objectID + "/child");
+ }
+
+ public static Uri getContentUriForStorageChildren(int deviceID, int storageID) {
+ return Uri.parse(CONTENT_AUTHORITY_DEVICE_SLASH + deviceID
+ + "/storage/" + storageID + "/child");
+ }
+
+ /**
+ * Name of the object
+ * <P>Type: TEXT</P>
+ */
+ public static final String NAME = "name";
+ }
+}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 7bb89f5..9bc28e4 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3573,20 +3573,8 @@
// If a shortcut is supplied, and it is already defined for
// another bookmark, then remove the old definition.
if (shortcut != 0) {
- Cursor c = cr.query(CONTENT_URI,
- sShortcutProjection, sShortcutSelection,
- new String[] { String.valueOf((int) shortcut) }, null);
- try {
- if (c.moveToFirst()) {
- while (c.getCount() > 0) {
- if (!c.deleteRow()) {
- Log.w(TAG, "Could not delete existing shortcut row");
- }
- }
- }
- } finally {
- if (c != null) c.close();
- }
+ cr.delete(CONTENT_URI, sShortcutSelection,
+ new String[] { String.valueOf((int) shortcut) });
}
ContentValues values = new ContentValues();
diff --git a/core/java/android/text/AndroidBidi.java b/core/java/android/text/AndroidBidi.java
index e4f934e..eacd40d 100644
--- a/core/java/android/text/AndroidBidi.java
+++ b/core/java/android/text/AndroidBidi.java
@@ -16,6 +16,8 @@
package android.text;
+import android.text.Layout.Directions;
+
/**
* Access the ICU bidi implementation.
* @hide
@@ -44,5 +46,132 @@
return result;
}
+ /**
+ * Returns run direction information for a line within a paragraph.
+ *
+ * @param dir base line direction, either Layout.DIR_LEFT_TO_RIGHT or
+ * Layout.DIR_RIGHT_TO_LEFT
+ * @param levels levels as returned from {@link #bidi}
+ * @param lstart start of the line in the levels array
+ * @param chars the character array (used to determine whitespace)
+ * @param cstart the start of the line in the chars array
+ * @param len the length of the line
+ * @return the directions
+ */
+ public static Directions directions(int dir, byte[] levels, int lstart,
+ char[] chars, int cstart, int len) {
+
+ int baseLevel = dir == Layout.DIR_LEFT_TO_RIGHT ? 0 : 1;
+ int curLevel = levels[lstart];
+ int minLevel = curLevel;
+ int runCount = 1;
+ for (int i = lstart + 1, e = lstart + len; i < e; ++i) {
+ int level = levels[i];
+ if (level != curLevel) {
+ curLevel = level;
+ ++runCount;
+ }
+ }
+
+ // add final run for trailing counter-directional whitespace
+ int visLen = len;
+ if ((curLevel & 1) != (baseLevel & 1)) {
+ // look for visible end
+ while (--visLen >= 0) {
+ char ch = chars[cstart + visLen];
+
+ if (ch == '\n') {
+ --visLen;
+ break;
+ }
+
+ if (ch != ' ' && ch != '\t') {
+ break;
+ }
+ }
+ ++visLen;
+ if (visLen != len) {
+ ++runCount;
+ }
+ }
+
+ if (runCount == 1 && minLevel == baseLevel) {
+ // we're done, only one run on this line
+ if ((minLevel & 1) != 0) {
+ return Layout.DIRS_ALL_RIGHT_TO_LEFT;
+ }
+ return Layout.DIRS_ALL_LEFT_TO_RIGHT;
+ }
+
+ int[] ld = new int[runCount * 2];
+ int maxLevel = minLevel;
+ int levelBits = minLevel << Layout.RUN_LEVEL_SHIFT;
+ {
+ // Start of first pair is always 0, we write
+ // length then start at each new run, and the
+ // last run length after we're done.
+ int n = 1;
+ int prev = lstart;
+ curLevel = minLevel;
+ for (int i = lstart, e = lstart + visLen; i < e; ++i) {
+ int level = levels[i];
+ if (level != curLevel) {
+ curLevel = level;
+ if (level > maxLevel) {
+ maxLevel = level;
+ } else if (level < minLevel) {
+ minLevel = level;
+ }
+ // XXX ignore run length limit of 2^RUN_LEVEL_SHIFT
+ ld[n++] = (i - prev) | levelBits;
+ ld[n++] = i - lstart;
+ levelBits = curLevel << Layout.RUN_LEVEL_SHIFT;
+ prev = i;
+ }
+ }
+ ld[n] = (lstart + visLen - prev) | levelBits;
+ if (visLen < len) {
+ ld[++n] = visLen;
+ ld[++n] = (len - visLen) | (baseLevel << Layout.RUN_LEVEL_SHIFT);
+ }
+ }
+
+ // See if we need to swap any runs.
+ // If the min level run direction doesn't match the base
+ // direction, we always need to swap (at this point
+ // we have more than one run).
+ // Otherwise, we don't need to swap the lowest level.
+ // Since there are no logically adjacent runs at the same
+ // level, if the max level is the same as the (new) min
+ // level, we have a series of alternating levels that
+ // is already in order, so there's no more to do.
+ //
+ boolean swap;
+ if ((minLevel & 1) == baseLevel) {
+ minLevel += 1;
+ swap = maxLevel > minLevel;
+ } else {
+ swap = runCount > 1;
+ }
+ if (swap) {
+ for (int level = maxLevel - 1; level >= minLevel; --level) {
+ for (int i = 0; i < ld.length; i += 2) {
+ if (levels[ld[i]] >= level) {
+ int e = i + 2;
+ while (e < ld.length && levels[ld[e]] >= level) {
+ e += 2;
+ }
+ for (int low = i, hi = e - 2; low < hi; low += 2, hi -= 2) {
+ int x = ld[low]; ld[low] = ld[hi]; ld[hi] = x;
+ x = ld[low+1]; ld[low+1] = ld[hi+1]; ld[hi+1] = x;
+ }
+ i = e + 2;
+ }
+ }
+ }
+ }
+ return new Directions(ld);
+ }
+
private native static int runBidi(int dir, char[] chs, byte[] chInfo, int n, boolean haveInfo);
}
\ No newline at end of file
diff --git a/core/java/android/text/BoringLayout.java b/core/java/android/text/BoringLayout.java
index 944f735..9309b05 100644
--- a/core/java/android/text/BoringLayout.java
+++ b/core/java/android/text/BoringLayout.java
@@ -208,11 +208,11 @@
* width because the width that was passed in was for the
* full text, not the ellipsized form.
*/
- synchronized (sTemp) {
- mMax = (int) (FloatMath.ceil(Styled.measureText(paint, sTemp,
- source, 0, source.length(),
- null)));
- }
+ TextLine line = TextLine.obtain();
+ line.set(paint, source, 0, source.length(), Layout.DIR_LEFT_TO_RIGHT,
+ Layout.DIRS_ALL_LEFT_TO_RIGHT, false, null);
+ mMax = (int) FloatMath.ceil(line.metrics(null));
+ TextLine.recycle(line);
}
if (includepad) {
@@ -276,14 +276,13 @@
if (fm == null) {
fm = new Metrics();
}
-
- int wid;
- synchronized (sTemp) {
- wid = (int) (FloatMath.ceil(Styled.measureText(paint, sTemp,
- text, 0, text.length(), fm)));
- }
- fm.width = wid;
+ TextLine line = TextLine.obtain();
+ line.set(paint, text, 0, text.length(), Layout.DIR_LEFT_TO_RIGHT,
+ Layout.DIRS_ALL_LEFT_TO_RIGHT, false, null);
+ fm.width = (int) FloatMath.ceil(line.metrics(fm));
+ TextLine.recycle(line);
+
return fm;
} else {
return null;
@@ -389,7 +388,7 @@
public static class Metrics extends Paint.FontMetricsInt {
public int width;
-
+
@Override public String toString() {
return super.toString() + " width=" + width;
}
diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java
index 14e5655..b6aa03a 100644
--- a/core/java/android/text/DynamicLayout.java
+++ b/core/java/android/text/DynamicLayout.java
@@ -310,7 +310,6 @@
Directions[] objects = new Directions[1];
-
for (int i = 0; i < n; i++) {
ints[START] = reflowed.getLineStart(i) |
(reflowed.getParagraphDirection(i) << DIR_SHIFT) |
diff --git a/core/java/android/text/GraphicsOperations.java b/core/java/android/text/GraphicsOperations.java
index c3bd0ae..05697c6 100644
--- a/core/java/android/text/GraphicsOperations.java
+++ b/core/java/android/text/GraphicsOperations.java
@@ -34,6 +34,13 @@
float x, float y, Paint p);
/**
+ * Just like {@link Canvas#drawTextRun}.
+ * {@hide}
+ */
+ void drawTextRun(Canvas c, int start, int end,
+ float x, float y, int flags, Paint p);
+
+ /**
* Just like {@link Paint#measureText}.
*/
float measureText(int start, int end, Paint p);
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 38ac9b7..2f7720a 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -16,29 +16,33 @@
package android.text;
-import android.emoji.EmojiFactory;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.Path;
import com.android.internal.util.ArrayUtils;
-import junit.framework.Assert;
-import android.text.style.*;
+import android.emoji.EmojiFactory;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.Rect;
import android.text.method.TextKeyListener;
+import android.text.style.AlignmentSpan;
+import android.text.style.LeadingMarginSpan;
+import android.text.style.LineBackgroundSpan;
+import android.text.style.ParagraphStyle;
+import android.text.style.ReplacementSpan;
+import android.text.style.TabStopSpan;
+import android.text.style.LeadingMarginSpan.LeadingMarginSpan2;
import android.view.KeyEvent;
+import java.util.Arrays;
+
/**
- * A base class that manages text layout in visual elements on
- * the screen.
- * <p>For text that will be edited, use a {@link DynamicLayout},
- * which will be updated as the text changes.
+ * A base class that manages text layout in visual elements on
+ * the screen.
+ * <p>For text that will be edited, use a {@link DynamicLayout},
+ * which will be updated as the text changes.
* For text that will not change, use a {@link StaticLayout}.
*/
public abstract class Layout {
- private static final boolean DEBUG = false;
private static final ParagraphStyle[] NO_PARA_SPANS =
ArrayUtils.emptyArray(ParagraphStyle.class);
@@ -54,9 +58,7 @@
MIN_EMOJI = -1;
MAX_EMOJI = -1;
}
- };
-
- private RectF mEmojiRect;
+ }
/**
* Return how wide a layout must be in order to display the
@@ -66,7 +68,7 @@
TextPaint paint) {
return getDesiredWidth(source, 0, source.length(), paint);
}
-
+
/**
* Return how wide a layout must be in order to display the
* specified text slice with one line per paragraph.
@@ -85,8 +87,7 @@
next = end;
// note, omits trailing paragraph char
- float w = measureText(paint, workPaint,
- source, i, next, null, true, null);
+ float w = measurePara(paint, workPaint, source, i, next);
if (w > need)
need = w;
@@ -116,6 +117,15 @@
if (width < 0)
throw new IllegalArgumentException("Layout: " + width + " < 0");
+ // Ensure paint doesn't have baselineShift set.
+ // While normally we don't modify the paint the user passed in,
+ // we were already doing this in Styled.drawUniformRun with both
+ // baselineShift and bgColor. We probably should reevaluate bgColor.
+ if (paint != null) {
+ paint.bgColor = 0;
+ paint.baselineShift = 0;
+ }
+
mText = text;
mPaint = paint;
mWorkPaint = new TextPaint();
@@ -175,7 +185,6 @@
dbottom = sTempRect.bottom;
}
-
int top = 0;
int bottom = getLineTop(getLineCount());
@@ -185,26 +194,28 @@
if (dbottom < bottom) {
bottom = dbottom;
}
-
- int first = getLineForVertical(top);
+
+ int first = getLineForVertical(top);
int last = getLineForVertical(bottom);
-
+
int previousLineBottom = getLineTop(first);
int previousLineEnd = getLineStart(first);
-
+
TextPaint paint = mPaint;
CharSequence buf = mText;
int width = mWidth;
boolean spannedText = mSpannedText;
ParagraphStyle[] spans = NO_PARA_SPANS;
- int spanend = 0;
+ int spanEnd = 0;
int textLength = 0;
// First, draw LineBackgroundSpans.
- // LineBackgroundSpans know nothing about the alignment or direction of
- // the layout or line. XXX: Should they?
+ // LineBackgroundSpans know nothing about the alignment, margins, or
+ // direction of the layout or line. XXX: Should they?
+ // They are evaluated at each line.
if (spannedText) {
+ Spanned sp = (Spanned) buf;
textLength = buf.length();
for (int i = first; i <= last; i++) {
int start = previousLineEnd;
@@ -216,12 +227,14 @@
previousLineBottom = lbottom;
int lbaseline = lbottom - getLineDescent(i);
- if (start >= spanend) {
- Spanned sp = (Spanned) buf;
- spanend = sp.nextSpanTransition(start, textLength,
- LineBackgroundSpan.class);
- spans = sp.getSpans(start, spanend,
- LineBackgroundSpan.class);
+ if (start >= spanEnd) {
+ // These should be infrequent, so we'll use this so that
+ // we don't have to check as often.
+ spanEnd = sp.nextSpanTransition(start, textLength,
+ LineBackgroundSpan.class);
+ // All LineBackgroundSpans on a line contribute to its
+ // background.
+ spans = sp.getSpans(start, end, LineBackgroundSpan.class);
}
for (int n = 0; n < spans.length; n++) {
@@ -234,11 +247,11 @@
}
}
// reset to their original values
- spanend = 0;
+ spanEnd = 0;
previousLineBottom = getLineTop(first);
previousLineEnd = getLineStart(first);
spans = NO_PARA_SPANS;
- }
+ }
// There can be a highlight even without spans if we are drawing
// a non-spanned transformation of a spanned editing buffer.
@@ -255,7 +268,11 @@
}
Alignment align = mAlignment;
-
+ TabStops tabStops = null;
+ boolean tabStopsIsInitialized = false;
+
+ TextLine tl = TextLine.obtain();
+
// Next draw the lines, one at a time.
// the baseline is the top of the following line minus the current
// line's descent.
@@ -270,19 +287,30 @@
previousLineBottom = lbottom;
int lbaseline = lbottom - getLineDescent(i);
- boolean isFirstParaLine = false;
- if (spannedText) {
- if (start == 0 || buf.charAt(start - 1) == '\n') {
- isFirstParaLine = true;
- }
- // New batch of paragraph styles, compute the alignment.
- // Last alignment style wins.
- if (start >= spanend) {
- Spanned sp = (Spanned) buf;
- spanend = sp.nextSpanTransition(start, textLength,
+ int dir = getParagraphDirection(i);
+ int left = 0;
+ int right = mWidth;
+
+ if (spannedText) {
+ Spanned sp = (Spanned) buf;
+ boolean isFirstParaLine = (start == 0 ||
+ buf.charAt(start - 1) == '\n');
+
+ // New batch of paragraph styles, collect into spans array.
+ // Compute the alignment, last alignment style wins.
+ // Reset tabStops, we'll rebuild if we encounter a line with
+ // tabs.
+ // We expect paragraph spans to be relatively infrequent, use
+ // spanEnd so that we can check less frequently. Since
+ // paragraph styles ought to apply to entire paragraphs, we can
+ // just collect the ones present at the start of the paragraph.
+ // If spanEnd is before the end of the paragraph, that's not
+ // our problem.
+ if (start >= spanEnd && (i == first || isFirstParaLine)) {
+ spanEnd = sp.nextSpanTransition(start, textLength,
ParagraphStyle.class);
- spans = sp.getSpans(start, spanend, ParagraphStyle.class);
-
+ spans = sp.getSpans(start, spanEnd, ParagraphStyle.class);
+
align = mAlignment;
for (int n = spans.length-1; n >= 0; n--) {
if (spans[n] instanceof AlignmentSpan) {
@@ -290,45 +318,49 @@
break;
}
}
+
+ tabStopsIsInitialized = false;
}
- }
-
- int dir = getParagraphDirection(i);
- int left = 0;
- int right = mWidth;
- // Draw all leading margin spans. Adjust left or right according
- // to the paragraph direction of the line.
- if (spannedText) {
+ // Draw all leading margin spans. Adjust left or right according
+ // to the paragraph direction of the line.
final int length = spans.length;
for (int n = 0; n < length; n++) {
if (spans[n] instanceof LeadingMarginSpan) {
LeadingMarginSpan margin = (LeadingMarginSpan) spans[n];
+ boolean useFirstLineMargin = isFirstParaLine;
+ if (margin instanceof LeadingMarginSpan2) {
+ int count = ((LeadingMarginSpan2) margin).getLeadingMarginLineCount();
+ int startLine = getLineForOffset(sp.getSpanStart(margin));
+ useFirstLineMargin = i < startLine + count;
+ }
if (dir == DIR_RIGHT_TO_LEFT) {
margin.drawLeadingMargin(c, paint, right, dir, ltop,
lbaseline, lbottom, buf,
start, end, isFirstParaLine, this);
-
- right -= margin.getLeadingMargin(isFirstParaLine);
+ right -= margin.getLeadingMargin(useFirstLineMargin);
} else {
margin.drawLeadingMargin(c, paint, left, dir, ltop,
lbaseline, lbottom, buf,
start, end, isFirstParaLine, this);
-
- boolean useMargin = isFirstParaLine;
- if (margin instanceof LeadingMarginSpan.LeadingMarginSpan2) {
- int count = ((LeadingMarginSpan.LeadingMarginSpan2)margin).getLeadingMarginLineCount();
- useMargin = count > i;
- }
- left += margin.getLeadingMargin(useMargin);
+ left += margin.getLeadingMargin(useFirstLineMargin);
}
}
}
}
- // Adjust the point at which to start rendering depending on the
- // alignment of the paragraph.
+ boolean hasTabOrEmoji = getLineContainsTab(i);
+ // Can't tell if we have tabs for sure, currently
+ if (hasTabOrEmoji && !tabStopsIsInitialized) {
+ if (tabStops == null) {
+ tabStops = new TabStops(TAB_INCREMENT, spans);
+ } else {
+ tabStops.reset(TAB_INCREMENT, spans);
+ }
+ tabStopsIsInitialized = true;
+ }
+
int x;
if (align == Alignment.ALIGN_NORMAL) {
if (dir == DIR_LEFT_TO_RIGHT) {
@@ -337,41 +369,80 @@
x = right;
}
} else {
- int max = (int)getLineMax(i, spans, false);
+ int max = (int)getLineExtent(i, tabStops, false);
if (align == Alignment.ALIGN_OPPOSITE) {
- if (dir == DIR_RIGHT_TO_LEFT) {
- x = left + max;
- } else {
+ if (dir == DIR_LEFT_TO_RIGHT) {
x = right - max;
- }
- } else {
- // Alignment.ALIGN_CENTER
- max = max & ~1;
- int half = (right - left - max) >> 1;
- if (dir == DIR_RIGHT_TO_LEFT) {
- x = right - half;
} else {
- x = left + half;
+ x = left - max;
}
+ } else { // Alignment.ALIGN_CENTER
+ max = max & ~1;
+ x = (right + left - max) >> 1;
}
}
Directions directions = getLineDirections(i);
- boolean hasTab = getLineContainsTab(i);
if (directions == DIRS_ALL_LEFT_TO_RIGHT &&
- !spannedText && !hasTab) {
- if (DEBUG) {
- Assert.assertTrue(dir == DIR_LEFT_TO_RIGHT);
- Assert.assertNotNull(c);
- }
+ !spannedText && !hasTabOrEmoji) {
// XXX: assumes there's nothing additional to be done
c.drawText(buf, start, end, x, lbaseline, paint);
} else {
- drawText(c, buf, start, end, dir, directions,
- x, ltop, lbaseline, lbottom, paint, mWorkPaint,
- hasTab, spans);
+ tl.set(paint, buf, start, end, dir, directions, hasTabOrEmoji, tabStops);
+ tl.draw(c, x, ltop, lbaseline, lbottom);
}
}
+
+ TextLine.recycle(tl);
+ }
+
+ /**
+ * Return the start position of the line, given the left and right bounds
+ * of the margins.
+ *
+ * @param line the line index
+ * @param left the left bounds (0, or leading margin if ltr para)
+ * @param right the right bounds (width, minus leading margin if rtl para)
+ * @return the start position of the line (to right of line if rtl para)
+ */
+ private int getLineStartPos(int line, int left, int right) {
+ // Adjust the point at which to start rendering depending on the
+ // alignment of the paragraph.
+ Alignment align = getParagraphAlignment(line);
+ int dir = getParagraphDirection(line);
+
+ int x;
+ if (align == Alignment.ALIGN_NORMAL) {
+ if (dir == DIR_LEFT_TO_RIGHT) {
+ x = left;
+ } else {
+ x = right;
+ }
+ } else {
+ TabStops tabStops = null;
+ if (mSpannedText && getLineContainsTab(line)) {
+ Spanned spanned = (Spanned) mText;
+ int start = getLineStart(line);
+ int spanEnd = spanned.nextSpanTransition(start, spanned.length(),
+ TabStopSpan.class);
+ TabStopSpan[] tabSpans = spanned.getSpans(start, spanEnd, TabStopSpan.class);
+ if (tabSpans.length > 0) {
+ tabStops = new TabStops(TAB_INCREMENT, tabSpans);
+ }
+ }
+ int max = (int)getLineExtent(line, tabStops, false);
+ if (align == Alignment.ALIGN_OPPOSITE) {
+ if (dir == DIR_LEFT_TO_RIGHT) {
+ x = right - max;
+ } else {
+ x = left - max;
+ }
+ } else { // Alignment.ALIGN_CENTER
+ max = max & ~1;
+ x = (left + right - max) >> 1;
+ }
+ }
+ return x;
}
/**
@@ -417,7 +488,7 @@
mWidth = wid;
}
-
+
/**
* Return the total height of this layout.
*/
@@ -450,7 +521,7 @@
* Return the number of lines of text in this layout.
*/
public abstract int getLineCount();
-
+
/**
* Return the baseline for the specified line (0…getLineCount() - 1)
* If bounds is not null, return the top, left, right, bottom extents
@@ -524,13 +595,95 @@
*/
public abstract int getBottomPadding();
+
+ /**
+ * Returns true if the character at offset and the preceding character
+ * are at different run levels (and thus there's a split caret).
+ * @param offset the offset
+ * @return true if at a level boundary
+ */
+ private boolean isLevelBoundary(int offset) {
+ int line = getLineForOffset(offset);
+ Directions dirs = getLineDirections(line);
+ if (dirs == DIRS_ALL_LEFT_TO_RIGHT || dirs == DIRS_ALL_RIGHT_TO_LEFT) {
+ return false;
+ }
+
+ int[] runs = dirs.mDirections;
+ int lineStart = getLineStart(line);
+ int lineEnd = getLineEnd(line);
+ if (offset == lineStart || offset == lineEnd) {
+ int paraLevel = getParagraphDirection(line) == 1 ? 0 : 1;
+ int runIndex = offset == lineStart ? 0 : runs.length - 2;
+ return ((runs[runIndex + 1] >>> RUN_LEVEL_SHIFT) & RUN_LEVEL_MASK) != paraLevel;
+ }
+
+ offset -= lineStart;
+ for (int i = 0; i < runs.length; i += 2) {
+ if (offset == runs[i]) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean primaryIsTrailingPrevious(int offset) {
+ int line = getLineForOffset(offset);
+ int lineStart = getLineStart(line);
+ int lineEnd = getLineEnd(line);
+ int[] runs = getLineDirections(line).mDirections;
+
+ int levelAt = -1;
+ for (int i = 0; i < runs.length; i += 2) {
+ int start = lineStart + runs[i];
+ int limit = start + (runs[i+1] & RUN_LENGTH_MASK);
+ if (limit > lineEnd) {
+ limit = lineEnd;
+ }
+ if (offset >= start && offset < limit) {
+ if (offset > start) {
+ // Previous character is at same level, so don't use trailing.
+ return false;
+ }
+ levelAt = (runs[i+1] >>> RUN_LEVEL_SHIFT) & RUN_LEVEL_MASK;
+ break;
+ }
+ }
+ if (levelAt == -1) {
+ // Offset was limit of line.
+ levelAt = getParagraphDirection(line) == 1 ? 0 : 1;
+ }
+
+ // At level boundary, check previous level.
+ int levelBefore = -1;
+ if (offset == lineStart) {
+ levelBefore = getParagraphDirection(line) == 1 ? 0 : 1;
+ } else {
+ offset -= 1;
+ for (int i = 0; i < runs.length; i += 2) {
+ int start = lineStart + runs[i];
+ int limit = start + (runs[i+1] & RUN_LENGTH_MASK);
+ if (limit > lineEnd) {
+ limit = lineEnd;
+ }
+ if (offset >= start && offset < limit) {
+ levelBefore = (runs[i+1] >>> RUN_LEVEL_SHIFT) & RUN_LEVEL_MASK;
+ break;
+ }
+ }
+ }
+
+ return levelBefore < levelAt;
+ }
+
/**
* Get the primary horizontal position for the specified text offset.
* This is the location where a new character would be inserted in
* the paragraph's primary direction.
*/
public float getPrimaryHorizontal(int offset) {
- return getHorizontal(offset, false, true);
+ boolean trailing = primaryIsTrailingPrevious(offset);
+ return getHorizontal(offset, trailing);
}
/**
@@ -539,66 +692,42 @@
* the direction other than the paragraph's primary direction.
*/
public float getSecondaryHorizontal(int offset) {
- return getHorizontal(offset, true, true);
+ boolean trailing = primaryIsTrailingPrevious(offset);
+ return getHorizontal(offset, !trailing);
}
- private float getHorizontal(int offset, boolean trailing, boolean alt) {
+ private float getHorizontal(int offset, boolean trailing) {
int line = getLineForOffset(offset);
- return getHorizontal(offset, trailing, alt, line);
+ return getHorizontal(offset, trailing, line);
}
- private float getHorizontal(int offset, boolean trailing, boolean alt,
- int line) {
+ private float getHorizontal(int offset, boolean trailing, int line) {
int start = getLineStart(line);
- int end = getLineVisibleEnd(line);
+ int end = getLineEnd(line);
int dir = getParagraphDirection(line);
- boolean tab = getLineContainsTab(line);
+ boolean hasTabOrEmoji = getLineContainsTab(line);
Directions directions = getLineDirections(line);
- TabStopSpan[] tabs = null;
- if (tab && mText instanceof Spanned) {
- tabs = ((Spanned) mText).getSpans(start, end, TabStopSpan.class);
+ TabStops tabStops = null;
+ if (hasTabOrEmoji && mText instanceof Spanned) {
+ // Just checking this line should be good enough, tabs should be
+ // consistent across all lines in a paragraph.
+ TabStopSpan[] tabs = ((Spanned) mText).getSpans(start, end, TabStopSpan.class);
+ if (tabs.length > 0) {
+ tabStops = new TabStops(TAB_INCREMENT, tabs); // XXX should reuse
+ }
}
- float wid = measureText(mPaint, mWorkPaint, mText, start, offset, end,
- dir, directions, trailing, alt, tab, tabs);
+ TextLine tl = TextLine.obtain();
+ tl.set(mPaint, mText, start, end, dir, directions, hasTabOrEmoji, tabStops);
+ float wid = tl.measure(offset - start, trailing, null);
+ TextLine.recycle(tl);
- if (offset > end) {
- if (dir == DIR_RIGHT_TO_LEFT)
- wid -= measureText(mPaint, mWorkPaint,
- mText, end, offset, null, tab, tabs);
- else
- wid += measureText(mPaint, mWorkPaint,
- mText, end, offset, null, tab, tabs);
- }
-
- Alignment align = getParagraphAlignment(line);
int left = getParagraphLeft(line);
int right = getParagraphRight(line);
- if (align == Alignment.ALIGN_NORMAL) {
- if (dir == DIR_RIGHT_TO_LEFT)
- return right + wid;
- else
- return left + wid;
- }
-
- float max = getLineMax(line);
-
- if (align == Alignment.ALIGN_OPPOSITE) {
- if (dir == DIR_RIGHT_TO_LEFT)
- return left + max + wid;
- else
- return right - max + wid;
- } else { /* align == Alignment.ALIGN_CENTER */
- int imax = ((int) max) & ~1;
-
- if (dir == DIR_RIGHT_TO_LEFT)
- return right - (((right - left) - imax) / 2) + wid;
- else
- return left + ((right - left) - imax) / 2 + wid;
- }
+ return getLineStartPos(line, left, right) + wid;
}
/**
@@ -656,38 +785,76 @@
}
/**
- * Gets the horizontal extent of the specified line, excluding
- * trailing whitespace.
+ * Gets the unsigned horizontal extent of the specified line, including
+ * leading margin indent, but excluding trailing whitespace.
*/
public float getLineMax(int line) {
- return getLineMax(line, null, false);
+ float margin = getParagraphLeadingMargin(line);
+ float signedExtent = getLineExtent(line, false);
+ return margin + signedExtent >= 0 ? signedExtent : -signedExtent;
}
/**
- * Gets the horizontal extent of the specified line, including
- * trailing whitespace.
+ * Gets the unsigned horizontal extent of the specified line, including
+ * leading margin indent and trailing whitespace.
*/
public float getLineWidth(int line) {
- return getLineMax(line, null, true);
+ float margin = getParagraphLeadingMargin(line);
+ float signedExtent = getLineExtent(line, true);
+ return margin + signedExtent >= 0 ? signedExtent : -signedExtent;
}
- private float getLineMax(int line, Object[] tabs, boolean full) {
+ /**
+ * Like {@link #getLineExtent(int,TabStops,boolean)} but determines the
+ * tab stops instead of using the ones passed in.
+ * @param line the index of the line
+ * @param full whether to include trailing whitespace
+ * @return the extent of the line
+ */
+ private float getLineExtent(int line, boolean full) {
int start = getLineStart(line);
- int end;
+ int end = full ? getLineEnd(line) : getLineVisibleEnd(line);
- if (full) {
- end = getLineEnd(line);
- } else {
- end = getLineVisibleEnd(line);
- }
- boolean tab = getLineContainsTab(line);
-
- if (tabs == null && tab && mText instanceof Spanned) {
- tabs = ((Spanned) mText).getSpans(start, end, TabStopSpan.class);
+ boolean hasTabsOrEmoji = getLineContainsTab(line);
+ TabStops tabStops = null;
+ if (hasTabsOrEmoji && mText instanceof Spanned) {
+ // Just checking this line should be good enough, tabs should be
+ // consistent across all lines in a paragraph.
+ TabStopSpan[] tabs = ((Spanned) mText).getSpans(start, end, TabStopSpan.class);
+ if (tabs.length > 0) {
+ tabStops = new TabStops(TAB_INCREMENT, tabs); // XXX should reuse
+ }
}
+ Directions directions = getLineDirections(line);
+ int dir = getParagraphDirection(line);
- return measureText(mPaint, mWorkPaint,
- mText, start, end, null, tab, tabs);
+ TextLine tl = TextLine.obtain();
+ tl.set(mPaint, mText, start, end, dir, directions, hasTabsOrEmoji, tabStops);
+ float width = tl.metrics(null);
+ TextLine.recycle(tl);
+ return width;
+ }
+
+ /**
+ * Returns the signed horizontal extent of the specified line, excluding
+ * leading margin. If full is false, excludes trailing whitespace.
+ * @param line the index of the line
+ * @param tabStops the tab stops, can be null if we know they're not used.
+ * @param full whether to include trailing whitespace
+ * @return the extent of the text on this line
+ */
+ private float getLineExtent(int line, TabStops tabStops, boolean full) {
+ int start = getLineStart(line);
+ int end = full ? getLineEnd(line) : getLineVisibleEnd(line);
+ boolean hasTabsOrEmoji = getLineContainsTab(line);
+ Directions directions = getLineDirections(line);
+ int dir = getParagraphDirection(line);
+
+ TextLine tl = TextLine.obtain();
+ tl.set(mPaint, mText, start, end, dir, directions, hasTabsOrEmoji, tabStops);
+ float width = tl.metrics(null);
+ TextLine.recycle(tl);
+ return width;
}
/**
@@ -738,7 +905,7 @@
}
/**
- * Get the character offset on the specfied line whose position is
+ * Get the character offset on the specified line whose position is
* closest to the specified horizontal position.
*/
public int getOffsetForHorizontal(int line, float horiz) {
@@ -752,14 +919,13 @@
int best = min;
float bestdist = Math.abs(getPrimaryHorizontal(best) - horiz);
- int here = min;
- for (int i = 0; i < dirs.mDirections.length; i++) {
- int there = here + dirs.mDirections[i];
- int swap = ((i & 1) == 0) ? 1 : -1;
+ for (int i = 0; i < dirs.mDirections.length; i += 2) {
+ int here = min + dirs.mDirections[i];
+ int there = here + (dirs.mDirections[i+1] & RUN_LENGTH_MASK);
+ int swap = (dirs.mDirections[i+1] & RUN_RTL_FLAG) != 0 ? -1 : 1;
if (there > max)
there = max;
-
int high = there - 1 + 1, low = here + 1 - 1, guess;
while (high - low > 1) {
@@ -792,7 +958,7 @@
if (dist < bestdist) {
bestdist = dist;
- best = low;
+ best = low;
}
}
@@ -802,8 +968,6 @@
bestdist = dist;
best = here;
}
-
- here = there;
}
float dist = Math.abs(getPrimaryHorizontal(max) - horiz);
@@ -823,19 +987,15 @@
return getLineStart(line + 1);
}
- /**
+ /**
* Return the text offset after the last visible character (so whitespace
* is not counted) on the specified line.
*/
public int getLineVisibleEnd(int line) {
return getLineVisibleEnd(line, getLineStart(line), getLineStart(line+1));
}
-
- private int getLineVisibleEnd(int line, int start, int end) {
- if (DEBUG) {
- Assert.assertTrue(getLineStart(line) == start && getLineStart(line+1) == end);
- }
+ private int getLineVisibleEnd(int line, int start, int end) {
CharSequence text = mText;
char ch;
if (line == getLineCount() - 1) {
@@ -882,207 +1042,62 @@
return getLineTop(line) - (getLineTop(line+1) - getLineDescent(line));
}
- /**
- * Return the text offset that would be reached by moving left
- * (possibly onto another line) from the specified offset.
- */
public int getOffsetToLeftOf(int offset) {
- int line = getLineForOffset(offset);
- int start = getLineStart(line);
- int end = getLineEnd(line);
- Directions dirs = getLineDirections(line);
-
- if (line != getLineCount() - 1)
- end--;
-
- float horiz = getPrimaryHorizontal(offset);
-
- int best = offset;
- float besth = Integer.MIN_VALUE;
- int candidate;
-
- candidate = TextUtils.getOffsetBefore(mText, offset);
- if (candidate >= start && candidate <= end) {
- float h = getPrimaryHorizontal(candidate);
-
- if (h < horiz && h > besth) {
- best = candidate;
- besth = h;
- }
- }
-
- candidate = TextUtils.getOffsetAfter(mText, offset);
- if (candidate >= start && candidate <= end) {
- float h = getPrimaryHorizontal(candidate);
-
- if (h < horiz && h > besth) {
- best = candidate;
- besth = h;
- }
- }
-
- int here = start;
- for (int i = 0; i < dirs.mDirections.length; i++) {
- int there = here + dirs.mDirections[i];
- if (there > end)
- there = end;
-
- float h = getPrimaryHorizontal(here);
-
- if (h < horiz && h > besth) {
- best = here;
- besth = h;
- }
-
- candidate = TextUtils.getOffsetAfter(mText, here);
- if (candidate >= start && candidate <= end) {
- h = getPrimaryHorizontal(candidate);
-
- if (h < horiz && h > besth) {
- best = candidate;
- besth = h;
- }
- }
-
- candidate = TextUtils.getOffsetBefore(mText, there);
- if (candidate >= start && candidate <= end) {
- h = getPrimaryHorizontal(candidate);
-
- if (h < horiz && h > besth) {
- best = candidate;
- besth = h;
- }
- }
-
- here = there;
- }
-
- float h = getPrimaryHorizontal(end);
-
- if (h < horiz && h > besth) {
- best = end;
- besth = h;
- }
-
- if (best != offset)
- return best;
-
- int dir = getParagraphDirection(line);
-
- if (dir > 0) {
- if (line == 0)
- return best;
- else
- return getOffsetForHorizontal(line - 1, 10000);
- } else {
- if (line == getLineCount() - 1)
- return best;
- else
- return getOffsetForHorizontal(line + 1, 10000);
- }
+ return getOffsetToLeftRightOf(offset, true);
}
- /**
- * Return the text offset that would be reached by moving right
- * (possibly onto another line) from the specified offset.
- */
public int getOffsetToRightOf(int offset) {
- int line = getLineForOffset(offset);
- int start = getLineStart(line);
- int end = getLineEnd(line);
- Directions dirs = getLineDirections(line);
+ return getOffsetToLeftRightOf(offset, false);
+ }
- if (line != getLineCount() - 1)
- end--;
+ private int getOffsetToLeftRightOf(int caret, boolean toLeft) {
+ int line = getLineForOffset(caret);
+ int lineStart = getLineStart(line);
+ int lineEnd = getLineEnd(line);
+ int lineDir = getParagraphDirection(line);
- float horiz = getPrimaryHorizontal(offset);
-
- int best = offset;
- float besth = Integer.MAX_VALUE;
- int candidate;
-
- candidate = TextUtils.getOffsetBefore(mText, offset);
- if (candidate >= start && candidate <= end) {
- float h = getPrimaryHorizontal(candidate);
-
- if (h > horiz && h < besth) {
- best = candidate;
- besth = h;
- }
- }
-
- candidate = TextUtils.getOffsetAfter(mText, offset);
- if (candidate >= start && candidate <= end) {
- float h = getPrimaryHorizontal(candidate);
-
- if (h > horiz && h < besth) {
- best = candidate;
- besth = h;
- }
- }
-
- int here = start;
- for (int i = 0; i < dirs.mDirections.length; i++) {
- int there = here + dirs.mDirections[i];
- if (there > end)
- there = end;
-
- float h = getPrimaryHorizontal(here);
-
- if (h > horiz && h < besth) {
- best = here;
- besth = h;
- }
-
- candidate = TextUtils.getOffsetAfter(mText, here);
- if (candidate >= start && candidate <= end) {
- h = getPrimaryHorizontal(candidate);
-
- if (h > horiz && h < besth) {
- best = candidate;
- besth = h;
+ boolean advance = toLeft == (lineDir == DIR_RIGHT_TO_LEFT);
+ if (caret == (advance ? lineEnd : lineStart)) {
+ // walking off line, so look at the line we're headed to
+ if (caret == lineStart) {
+ if (line > 0) {
+ --line;
+ } else {
+ return caret; // at very start, don't move
+ }
+ } else {
+ if (line < getLineCount() - 1) {
+ ++line;
+ } else {
+ return caret; // at very end, don't move
}
}
- candidate = TextUtils.getOffsetBefore(mText, there);
- if (candidate >= start && candidate <= end) {
- h = getPrimaryHorizontal(candidate);
-
- if (h > horiz && h < besth) {
- best = candidate;
- besth = h;
- }
+ lineStart = getLineStart(line);
+ lineEnd = getLineEnd(line);
+ int newDir = getParagraphDirection(line);
+ if (newDir != lineDir) {
+ // unusual case. we want to walk onto the line, but it runs
+ // in a different direction than this one, so we fake movement
+ // in the opposite direction.
+ toLeft = !toLeft;
+ lineDir = newDir;
}
-
- here = there;
}
- float h = getPrimaryHorizontal(end);
+ Directions directions = getLineDirections(line);
- if (h > horiz && h < besth) {
- best = end;
- besth = h;
- }
-
- if (best != offset)
- return best;
-
- int dir = getParagraphDirection(line);
-
- if (dir > 0) {
- if (line == getLineCount() - 1)
- return best;
- else
- return getOffsetForHorizontal(line + 1, -10000);
- } else {
- if (line == 0)
- return best;
- else
- return getOffsetForHorizontal(line - 1, -10000);
- }
+ TextLine tl = TextLine.obtain();
+ // XXX: we don't care about tabs
+ tl.set(mPaint, mText, lineStart, lineEnd, lineDir, directions, false, null);
+ caret = lineStart + tl.getOffsetToLeftRightOf(caret - lineStart, toLeft);
+ tl = TextLine.recycle(tl);
+ return caret;
}
private int getOffsetAtStartOf(int offset) {
+ // XXX this probably should skip local reorderings and
+ // zero-width characters, look at callers
if (offset == 0)
return 0;
@@ -1115,7 +1130,7 @@
/**
* Fills in the specified Path with a representation of a cursor
* at the specified offset. This will often be a vertical line
- * but can be multiple discontinous lines in text with multiple
+ * but can be multiple discontinuous lines in text with multiple
* directionalities.
*/
public void getCursorPath(int point, Path dest,
@@ -1127,7 +1142,8 @@
int bottom = getLineTop(line+1);
float h1 = getPrimaryHorizontal(point) - 0.5f;
- float h2 = getSecondaryHorizontal(point) - 0.5f;
+ float h2 = isLevelBoundary(point) ?
+ getSecondaryHorizontal(point) - 0.5f : h1;
int caps = TextKeyListener.getMetaState(editingBuffer,
KeyEvent.META_SHIFT_ON) |
@@ -1204,9 +1220,10 @@
if (lineend > linestart && mText.charAt(lineend - 1) == '\n')
lineend--;
- int here = linestart;
- for (int i = 0; i < dirs.mDirections.length; i++) {
- int there = here + dirs.mDirections[i];
+ for (int i = 0; i < dirs.mDirections.length; i += 2) {
+ int here = linestart + dirs.mDirections[i];
+ int there = here + (dirs.mDirections[i+1] & RUN_LENGTH_MASK);
+
if (there > lineend)
there = lineend;
@@ -1215,14 +1232,12 @@
int en = Math.min(end, there);
if (st != en) {
- float h1 = getHorizontal(st, false, false, line);
- float h2 = getHorizontal(en, true, false, line);
+ float h1 = getHorizontal(st, false, line);
+ float h2 = getHorizontal(en, true, line);
dest.addRect(h1, top, h2, bottom, Path.Direction.CW);
}
}
-
- here = there;
}
}
@@ -1257,7 +1272,7 @@
addSelection(startline, start, getLineEnd(startline),
top, getLineBottom(startline), dest);
-
+
if (getParagraphDirection(startline) == DIR_RIGHT_TO_LEFT)
dest.addRect(getLineLeft(startline), top,
0, getLineBottom(startline), Path.Direction.CW);
@@ -1310,424 +1325,175 @@
* Get the left edge of the specified paragraph, inset by left margins.
*/
public final int getParagraphLeft(int line) {
- int dir = getParagraphDirection(line);
-
int left = 0;
-
- boolean par = false;
- int off = getLineStart(line);
- if (off == 0 || mText.charAt(off - 1) == '\n')
- par = true;
-
- if (dir == DIR_LEFT_TO_RIGHT) {
- if (mSpannedText) {
- Spanned sp = (Spanned) mText;
- LeadingMarginSpan[] spans = sp.getSpans(getLineStart(line),
- getLineEnd(line),
- LeadingMarginSpan.class);
-
- for (int i = 0; i < spans.length; i++) {
- boolean margin = par;
- LeadingMarginSpan span = spans[i];
- if (span instanceof LeadingMarginSpan.LeadingMarginSpan2) {
- int count = ((LeadingMarginSpan.LeadingMarginSpan2)span).getLeadingMarginLineCount();
- margin = count >= line;
- }
- left += span.getLeadingMargin(margin);
- }
- }
+ int dir = getParagraphDirection(line);
+ if (dir == DIR_RIGHT_TO_LEFT || !mSpannedText) {
+ return left; // leading margin has no impact, or no styles
}
-
- return left;
+ return getParagraphLeadingMargin(line);
}
/**
* Get the right edge of the specified paragraph, inset by right margins.
*/
public final int getParagraphRight(int line) {
- int dir = getParagraphDirection(line);
-
int right = mWidth;
-
- boolean par = false;
- int off = getLineStart(line);
- if (off == 0 || mText.charAt(off - 1) == '\n')
- par = true;
-
-
- if (dir == DIR_RIGHT_TO_LEFT) {
- if (mSpannedText) {
- Spanned sp = (Spanned) mText;
- LeadingMarginSpan[] spans = sp.getSpans(getLineStart(line),
- getLineEnd(line),
- LeadingMarginSpan.class);
-
- for (int i = 0; i < spans.length; i++) {
- right -= spans[i].getLeadingMargin(par);
- }
- }
+ int dir = getParagraphDirection(line);
+ if (dir == DIR_LEFT_TO_RIGHT || !mSpannedText) {
+ return right; // leading margin has no impact, or no styles
}
-
- return right;
- }
-
- private void drawText(Canvas canvas,
- CharSequence text, int start, int end,
- int dir, Directions directions,
- float x, int top, int y, int bottom,
- TextPaint paint,
- TextPaint workPaint,
- boolean hasTabs, Object[] parspans) {
- char[] buf;
- if (!hasTabs) {
- if (directions == DIRS_ALL_LEFT_TO_RIGHT) {
- if (DEBUG) {
- Assert.assertTrue(DIR_LEFT_TO_RIGHT == dir);
- }
- Styled.drawText(canvas, text, start, end, dir, false, x, top, y, bottom, paint, workPaint, false);
- return;
- }
- buf = null;
- } else {
- buf = TextUtils.obtain(end - start);
- TextUtils.getChars(text, start, end, buf, 0);
- }
-
- float h = 0;
-
- int here = 0;
- for (int i = 0; i < directions.mDirections.length; i++) {
- int there = here + directions.mDirections[i];
- if (there > end - start)
- there = end - start;
-
- int segstart = here;
- for (int j = hasTabs ? here : there; j <= there; j++) {
- if (j == there || buf[j] == '\t') {
- h += Styled.drawText(canvas, text,
- start + segstart, start + j,
- dir, (i & 1) != 0, x + h,
- top, y, bottom, paint, workPaint,
- start + j != end);
-
- if (j != there && buf[j] == '\t')
- h = dir * nextTab(text, start, end, h * dir, parspans);
-
- segstart = j + 1;
- } else if (hasTabs && buf[j] >= 0xD800 && buf[j] <= 0xDFFF && j + 1 < there) {
- int emoji = Character.codePointAt(buf, j);
-
- if (emoji >= MIN_EMOJI && emoji <= MAX_EMOJI) {
- Bitmap bm = EMOJI_FACTORY.
- getBitmapFromAndroidPua(emoji);
-
- if (bm != null) {
- h += Styled.drawText(canvas, text,
- start + segstart, start + j,
- dir, (i & 1) != 0, x + h,
- top, y, bottom, paint, workPaint,
- start + j != end);
-
- if (mEmojiRect == null) {
- mEmojiRect = new RectF();
- }
-
- workPaint.set(paint);
- Styled.measureText(paint, workPaint, text,
- start + j, start + j + 1,
- null);
-
- float bitmapHeight = bm.getHeight();
- float textHeight = -workPaint.ascent();
- float scale = textHeight / bitmapHeight;
- float width = bm.getWidth() * scale;
-
- mEmojiRect.set(x + h, y - textHeight,
- x + h + width, y);
-
- canvas.drawBitmap(bm, null, mEmojiRect, paint);
- h += width;
-
- j++;
- segstart = j + 1;
- }
- }
- }
- }
-
- here = there;
- }
-
- if (hasTabs)
- TextUtils.recycle(buf);
- }
-
- private static float measureText(TextPaint paint,
- TextPaint workPaint,
- CharSequence text,
- int start, int offset, int end,
- int dir, Directions directions,
- boolean trailing, boolean alt,
- boolean hasTabs, Object[] tabs) {
- char[] buf = null;
-
- if (hasTabs) {
- buf = TextUtils.obtain(end - start);
- TextUtils.getChars(text, start, end, buf, 0);
- }
-
- float h = 0;
-
- if (alt) {
- if (dir == DIR_RIGHT_TO_LEFT)
- trailing = !trailing;
- }
-
- int here = 0;
- for (int i = 0; i < directions.mDirections.length; i++) {
- if (alt)
- trailing = !trailing;
-
- int there = here + directions.mDirections[i];
- if (there > end - start)
- there = end - start;
-
- int segstart = here;
- for (int j = hasTabs ? here : there; j <= there; j++) {
- int codept = 0;
- Bitmap bm = null;
-
- if (hasTabs && j < there) {
- codept = buf[j];
- }
-
- if (codept >= 0xD800 && codept <= 0xDFFF && j + 1 < there) {
- codept = Character.codePointAt(buf, j);
-
- if (codept >= MIN_EMOJI && codept <= MAX_EMOJI) {
- bm = EMOJI_FACTORY.getBitmapFromAndroidPua(codept);
- }
- }
-
- if (j == there || codept == '\t' || bm != null) {
- float segw;
-
- if (offset < start + j ||
- (trailing && offset <= start + j)) {
- if (dir == DIR_LEFT_TO_RIGHT && (i & 1) == 0) {
- h += Styled.measureText(paint, workPaint, text,
- start + segstart, offset,
- null);
- return h;
- }
-
- if (dir == DIR_RIGHT_TO_LEFT && (i & 1) != 0) {
- h -= Styled.measureText(paint, workPaint, text,
- start + segstart, offset,
- null);
- return h;
- }
- }
-
- segw = Styled.measureText(paint, workPaint, text,
- start + segstart, start + j,
- null);
-
- if (offset < start + j ||
- (trailing && offset <= start + j)) {
- if (dir == DIR_LEFT_TO_RIGHT) {
- h += segw - Styled.measureText(paint, workPaint,
- text,
- start + segstart,
- offset, null);
- return h;
- }
-
- if (dir == DIR_RIGHT_TO_LEFT) {
- h -= segw - Styled.measureText(paint, workPaint,
- text,
- start + segstart,
- offset, null);
- return h;
- }
- }
-
- if (dir == DIR_RIGHT_TO_LEFT)
- h -= segw;
- else
- h += segw;
-
- if (j != there && buf[j] == '\t') {
- if (offset == start + j)
- return h;
-
- h = dir * nextTab(text, start, end, h * dir, tabs);
- }
-
- if (bm != null) {
- workPaint.set(paint);
- Styled.measureText(paint, workPaint, text,
- j, j + 2, null);
-
- float wid = (float) bm.getWidth() *
- -workPaint.ascent() / bm.getHeight();
-
- if (dir == DIR_RIGHT_TO_LEFT) {
- h -= wid;
- } else {
- h += wid;
- }
-
- j++;
- }
-
- segstart = j + 1;
- }
- }
-
- here = there;
- }
-
- if (hasTabs)
- TextUtils.recycle(buf);
-
- return h;
+ return right - getParagraphLeadingMargin(line);
}
/**
- * Measure width of a run of text on a single line that is known to all be
- * in the same direction as the paragraph base direction. Returns the width,
- * and the line metrics in fm if fm is not null.
- *
- * @param paint the paint for the text; will not be modified
- * @param workPaint paint available for modification
- * @param text text
- * @param start start of the line
- * @param end limit of the line
- * @param fm object to return integer metrics in, can be null
- * @param hasTabs true if it is known that the line has tabs
- * @param tabs tab position information
- * @return the width of the text from start to end
+ * Returns the effective leading margin (unsigned) for this line,
+ * taking into account LeadingMarginSpan and LeadingMarginSpan2.
+ * @param line the line index
+ * @return the leading margin of this line
*/
- /* package */ static float measureText(TextPaint paint,
- TextPaint workPaint,
- CharSequence text,
- int start, int end,
- Paint.FontMetricsInt fm,
- boolean hasTabs, Object[] tabs) {
- char[] buf = null;
-
- if (hasTabs) {
- buf = TextUtils.obtain(end - start);
- TextUtils.getChars(text, start, end, buf, 0);
+ private int getParagraphLeadingMargin(int line) {
+ if (!mSpannedText) {
+ return 0;
}
-
- int len = end - start;
-
- int lastPos = 0;
- float width = 0;
- int ascent = 0, descent = 0, top = 0, bottom = 0;
-
- if (fm != null) {
- fm.ascent = 0;
- fm.descent = 0;
+ Spanned spanned = (Spanned) mText;
+
+ int lineStart = getLineStart(line);
+ int lineEnd = getLineEnd(line);
+ int spanEnd = spanned.nextSpanTransition(lineStart, lineEnd,
+ LeadingMarginSpan.class);
+ LeadingMarginSpan[] spans = spanned.getSpans(lineStart, spanEnd,
+ LeadingMarginSpan.class);
+ if (spans.length == 0) {
+ return 0; // no leading margin span;
}
-
- for (int pos = hasTabs ? 0 : len; pos <= len; pos++) {
- int codept = 0;
- Bitmap bm = null;
-
- if (hasTabs && pos < len) {
- codept = buf[pos];
+
+ int margin = 0;
+
+ boolean isFirstParaLine = lineStart == 0 ||
+ spanned.charAt(lineStart - 1) == '\n';
+
+ for (int i = 0; i < spans.length; i++) {
+ LeadingMarginSpan span = spans[i];
+ boolean useFirstLineMargin = isFirstParaLine;
+ if (span instanceof LeadingMarginSpan2) {
+ int spStart = spanned.getSpanStart(span);
+ int spanLine = getLineForOffset(spStart);
+ int count = ((LeadingMarginSpan2)span).getLeadingMarginLineCount();
+ useFirstLineMargin = line < spanLine + count;
}
-
- if (codept >= 0xD800 && codept <= 0xDFFF && pos < len) {
- codept = Character.codePointAt(buf, pos);
-
- if (codept >= MIN_EMOJI && codept <= MAX_EMOJI) {
- bm = EMOJI_FACTORY.getBitmapFromAndroidPua(codept);
- }
- }
-
- if (pos == len || codept == '\t' || bm != null) {
- workPaint.baselineShift = 0;
-
- width += Styled.measureText(paint, workPaint, text,
- start + lastPos, start + pos,
- fm);
-
- if (fm != null) {
- if (workPaint.baselineShift < 0) {
- fm.ascent += workPaint.baselineShift;
- fm.top += workPaint.baselineShift;
- } else {
- fm.descent += workPaint.baselineShift;
- fm.bottom += workPaint.baselineShift;
- }
- }
-
- if (pos != len) {
- if (bm == null) {
- // no emoji, must have hit a tab
- width = nextTab(text, start, end, width, tabs);
- } else {
- // This sets up workPaint with the font on the emoji
- // text, so that we can extract the ascent and scale.
-
- // We can't use the result of the previous call to
- // measureText because the emoji might have its own style.
- // We have to initialize workPaint here because if the
- // text is unstyled measureText might not use workPaint
- // at all.
- workPaint.set(paint);
- Styled.measureText(paint, workPaint, text,
- start + pos, start + pos + 1, null);
-
- width += (float) bm.getWidth() *
- -workPaint.ascent() / bm.getHeight();
-
- // Since we had an emoji, we bump past the second half
- // of the surrogate pair.
- pos++;
- }
- }
-
- if (fm != null) {
- if (fm.ascent < ascent) {
- ascent = fm.ascent;
- }
- if (fm.descent > descent) {
- descent = fm.descent;
- }
-
- if (fm.top < top) {
- top = fm.top;
- }
- if (fm.bottom > bottom) {
- bottom = fm.bottom;
- }
-
- // No need to take bitmap height into account here,
- // since it is scaled to match the text height.
- }
-
- lastPos = pos + 1;
- }
+ margin += span.getLeadingMargin(useFirstLineMargin);
}
- if (fm != null) {
- fm.ascent = ascent;
- fm.descent = descent;
- fm.top = top;
- fm.bottom = bottom;
- }
-
- if (hasTabs)
- TextUtils.recycle(buf);
-
- return width;
+ return margin;
}
+ /* package */
+ static float measurePara(TextPaint paint, TextPaint workPaint,
+ CharSequence text, int start, int end) {
+
+ MeasuredText mt = MeasuredText.obtain();
+ TextLine tl = TextLine.obtain();
+ try {
+ mt.setPara(text, start, end, DIR_REQUEST_LTR);
+ Directions directions;
+ int dir;
+ if (mt.mEasy) {
+ directions = DIRS_ALL_LEFT_TO_RIGHT;
+ dir = Layout.DIR_LEFT_TO_RIGHT;
+ } else {
+ directions = AndroidBidi.directions(mt.mDir, mt.mLevels,
+ 0, mt.mChars, 0, mt.mLen);
+ dir = mt.mDir;
+ }
+ char[] chars = mt.mChars;
+ int len = mt.mLen;
+ boolean hasTabs = false;
+ TabStops tabStops = null;
+ for (int i = 0; i < len; ++i) {
+ if (chars[i] == '\t') {
+ hasTabs = true;
+ if (text instanceof Spanned) {
+ Spanned spanned = (Spanned) text;
+ int spanEnd = spanned.nextSpanTransition(start, end,
+ TabStopSpan.class);
+ TabStopSpan[] spans = spanned.getSpans(start, spanEnd,
+ TabStopSpan.class);
+ if (spans.length > 0) {
+ tabStops = new TabStops(TAB_INCREMENT, spans);
+ }
+ }
+ break;
+ }
+ }
+ tl.set(paint, text, start, end, dir, directions, hasTabs, tabStops);
+ return tl.metrics(null);
+ } finally {
+ TextLine.recycle(tl);
+ MeasuredText.recycle(mt);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ /* package */ static class TabStops {
+ private int[] mStops;
+ private int mNumStops;
+ private int mIncrement;
+
+ TabStops(int increment, Object[] spans) {
+ reset(increment, spans);
+ }
+
+ void reset(int increment, Object[] spans) {
+ this.mIncrement = increment;
+
+ int ns = 0;
+ if (spans != null) {
+ int[] stops = this.mStops;
+ for (Object o : spans) {
+ if (o instanceof TabStopSpan) {
+ if (stops == null) {
+ stops = new int[10];
+ } else if (ns == stops.length) {
+ int[] nstops = new int[ns * 2];
+ for (int i = 0; i < ns; ++i) {
+ nstops[i] = stops[i];
+ }
+ stops = nstops;
+ }
+ stops[ns++] = ((TabStopSpan) o).getTabStop();
+ }
+ }
+ if (ns > 1) {
+ Arrays.sort(stops, 0, ns);
+ }
+ if (stops != this.mStops) {
+ this.mStops = stops;
+ }
+ }
+ this.mNumStops = ns;
+ }
+
+ float nextTab(float h) {
+ int ns = this.mNumStops;
+ if (ns > 0) {
+ int[] stops = this.mStops;
+ for (int i = 0; i < ns; ++i) {
+ int stop = stops[i];
+ if (stop > h) {
+ return stop;
+ }
+ }
+ }
+ return nextDefaultStop(h, mIncrement);
+ }
+
+ public static float nextDefaultStop(float h, int inc) {
+ return ((int) ((h + inc) / inc)) * inc;
+ }
+ }
+
/**
* Returns the position of the next tab stop after h on the line.
*
@@ -1804,23 +1570,22 @@
/**
* Stores information about bidirectional (left-to-right or right-to-left)
- * text within the layout of a line. TODO: This work is not complete
- * or correct and will be fleshed out in a later revision.
+ * text within the layout of a line.
*/
public static class Directions {
- private short[] mDirections;
+ // Directions represents directional runs within a line of text.
+ // Runs are pairs of ints listed in visual order, starting from the
+ // leading margin. The first int of each pair is the offset from
+ // the first character of the line to the start of the run. The
+ // second int represents both the length and level of the run.
+ // The length is in the lower bits, accessed by masking with
+ // DIR_LENGTH_MASK. The level is in the higher bits, accessed
+ // by shifting by DIR_LEVEL_SHIFT and masking by DIR_LEVEL_MASK.
+ // To simply test for an RTL direction, test the bit using
+ // DIR_RTL_FLAG, if set then the direction is rtl.
- // The values in mDirections are the offsets from the first character
- // in the line to the next flip in direction. Runs at even indices
- // are left-to-right, the others are right-to-left. So, for example,
- // a line that starts with a right-to-left run has 0 at mDirections[0],
- // since the 'first' (ltr) run is zero length.
- //
- // The code currently assumes that each run is adjacent to the previous
- // one, progressing in the base line direction. This isn't sufficient
- // to handle nested runs, for example numeric text in an rtl context
- // in an ltr paragraph.
- /* package */ Directions(short[] dirs) {
+ /* package */ int[] mDirections;
+ /* package */ Directions(int[] dirs) {
mDirections = dirs;
}
}
@@ -1831,6 +1596,7 @@
* line is ellipsized, not getLineStart().)
*/
public abstract int getEllipsisStart(int line);
+
/**
* Returns the number of characters to be ellipsized away, or 0 if
* no ellipsis is to take place.
@@ -1870,7 +1636,7 @@
public int length() {
return mText.length();
}
-
+
public CharSequence subSequence(int start, int end) {
char[] s = new char[end - start];
getChars(start, end, s, 0);
@@ -1936,12 +1702,17 @@
public static final int DIR_LEFT_TO_RIGHT = 1;
public static final int DIR_RIGHT_TO_LEFT = -1;
-
+
/* package */ static final int DIR_REQUEST_LTR = 1;
/* package */ static final int DIR_REQUEST_RTL = -1;
/* package */ static final int DIR_REQUEST_DEFAULT_LTR = 2;
/* package */ static final int DIR_REQUEST_DEFAULT_RTL = -2;
+ /* package */ static final int RUN_LENGTH_MASK = 0x03ffffff;
+ /* package */ static final int RUN_LEVEL_SHIFT = 26;
+ /* package */ static final int RUN_LEVEL_MASK = 0x3f;
+ /* package */ static final int RUN_RTL_FLAG = 1 << RUN_LEVEL_SHIFT;
+
public enum Alignment {
ALIGN_NORMAL,
ALIGN_OPPOSITE,
@@ -1953,9 +1724,8 @@
private static final int TAB_INCREMENT = 20;
/* package */ static final Directions DIRS_ALL_LEFT_TO_RIGHT =
- new Directions(new short[] { 32767 });
+ new Directions(new int[] { 0, RUN_LENGTH_MASK });
/* package */ static final Directions DIRS_ALL_RIGHT_TO_LEFT =
- new Directions(new short[] { 0, 32767 });
-
+ new Directions(new int[] { 0, RUN_LENGTH_MASK | RUN_RTL_FLAG });
}
diff --git a/core/java/android/text/MeasuredText.java b/core/java/android/text/MeasuredText.java
new file mode 100644
index 0000000..e3a113d
--- /dev/null
+++ b/core/java/android/text/MeasuredText.java
@@ -0,0 +1,250 @@
+/*
+ * 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.text;
+
+import com.android.internal.util.ArrayUtils;
+
+import android.graphics.Paint;
+import android.icu.text.ArabicShaping;
+import android.text.style.MetricAffectingSpan;
+import android.text.style.ReplacementSpan;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+class MeasuredText {
+ /* package */ CharSequence mText;
+ /* package */ int mTextStart;
+ /* package */ float[] mWidths;
+ /* package */ char[] mChars;
+ /* package */ byte[] mLevels;
+ /* package */ int mDir;
+ /* package */ boolean mEasy;
+ /* package */ int mLen;
+ private int mPos;
+ private float[] mWorkWidths; // temp buffer for Paint.measureText, arrgh
+ private TextPaint mWorkPaint;
+
+ private MeasuredText() {
+ mWorkPaint = new TextPaint();
+ }
+
+ private static MeasuredText[] cached = new MeasuredText[3];
+
+ /* package */
+ static MeasuredText obtain() {
+ MeasuredText mt;
+ synchronized (cached) {
+ for (int i = cached.length; --i >= 0;) {
+ if (cached[i] != null) {
+ mt = cached[i];
+ cached[i] = null;
+ return mt;
+ }
+ }
+ }
+ mt = new MeasuredText();
+ Log.e("MEAS", "new: " + mt);
+ return mt;
+ }
+
+ /* package */
+ static MeasuredText recycle(MeasuredText mt) {
+ mt.mText = null;
+ if (mt.mLen < 1000) {
+ synchronized(cached) {
+ for (int i = 0; i < cached.length; ++i) {
+ if (cached[i] == null) {
+ cached[i] = mt;
+ break;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Analyzes text for
+ * bidirectional runs. Allocates working buffers.
+ */
+ /* package */
+ void setPara(CharSequence text, int start, int end, int bidiRequest) {
+ mText = text;
+ mTextStart = start;
+
+ int len = end - start;
+ mLen = len;
+ mPos = 0;
+
+ if (mWidths == null || mWidths.length < len) {
+ mWidths = new float[ArrayUtils.idealFloatArraySize(len)];
+ mWorkWidths = new float[mWidths.length];
+ }
+ if (mChars == null || mChars.length < len) {
+ mChars = new char[ArrayUtils.idealCharArraySize(len)];
+ }
+ TextUtils.getChars(text, start, end, mChars, 0);
+
+ if (text instanceof Spanned) {
+ Spanned spanned = (Spanned) text;
+ ReplacementSpan[] spans = spanned.getSpans(start, end,
+ ReplacementSpan.class);
+
+ for (int i = 0; i < spans.length; i++) {
+ int startInPara = spanned.getSpanStart(spans[i]) - start;
+ int endInPara = spanned.getSpanEnd(spans[i]) - start;
+ for (int j = startInPara; j < endInPara; j++) {
+ mChars[j] = '\uFFFC';
+ }
+ }
+ }
+
+ if (TextUtils.doesNotNeedBidi(mChars, 0, len)) {
+ mDir = 1;
+ mEasy = true;
+ } else {
+ if (mLevels == null || mLevels.length < len) {
+ mLevels = new byte[ArrayUtils.idealByteArraySize(len)];
+ }
+ mDir = AndroidBidi.bidi(bidiRequest, mChars, mLevels, len, false);
+ mEasy = false;
+
+ // shape
+ if (mLen > 0) {
+ byte[] levels = mLevels;
+ char[] chars = mChars;
+ byte level = levels[0];
+ int pi = 0;
+ for (int i = 1, e = mLen;; ++i) {
+ if (i == e || levels[i] != level) {
+ if ((level & 0x1) != 0) {
+ AndroidCharacter.mirror(chars, pi, i - pi);
+ ArabicShaping.SHAPER.shape(chars, pi, i - pi);
+ }
+ if (i == e) {
+ break;
+ }
+ pi = i;
+ level = levels[i];
+ }
+ }
+ }
+ }
+ }
+
+ float addStyleRun(TextPaint paint, int len, Paint.FontMetricsInt fm) {
+ int p = mPos;
+ float[] w = mWidths, ww = mWorkWidths;
+ int count = paint.getTextWidths(mChars, p, len, ww);
+ int width = 0;
+ if (count < len) {
+ // must have surrogate pairs in here, pad out the array with zero
+ // for the trailing surrogates
+ char[] chars = mChars;
+ for (int i = 0, e = mLen; i < count; ++i) {
+ width += (w[p++] = ww[i]);
+ if (p < e && chars[p] >= '\udc00' && chars[p] < '\ue000' &&
+ chars[p-1] >= '\ud800' && chars[p-1] < '\udc00') {
+ w[p++] = 0;
+ }
+ }
+ } else {
+ for (int i = 0; i < len; ++i) {
+ width += (w[p++] = ww[i]);
+ }
+ }
+ mPos = p;
+ if (fm != null) {
+ paint.getFontMetricsInt(fm);
+ }
+ return width;
+ }
+
+ float addStyleRun(TextPaint paint, MetricAffectingSpan[] spans, int len,
+ Paint.FontMetricsInt fm) {
+
+ TextPaint workPaint = mWorkPaint;
+ workPaint.set(paint);
+ // XXX paint should not have a baseline shift, but...
+ workPaint.baselineShift = 0;
+
+ ReplacementSpan replacement = null;
+ for (int i = 0; i < spans.length; i++) {
+ MetricAffectingSpan span = spans[i];
+ if (span instanceof ReplacementSpan) {
+ replacement = (ReplacementSpan)span;
+ } else {
+ span.updateMeasureState(workPaint);
+ }
+ }
+
+ float wid;
+ if (replacement == null) {
+ wid = addStyleRun(workPaint, len, fm);
+ } else {
+ // Use original text. Shouldn't matter.
+ wid = replacement.getSize(workPaint, mText, mTextStart + mPos,
+ mTextStart + mPos + len, fm);
+ float[] w = mWidths;
+ w[mPos] = wid;
+ for (int i = mPos + 1, e = mPos + len; i < e; i++)
+ w[i] = 0;
+ }
+
+ if (fm != null) {
+ if (workPaint.baselineShift < 0) {
+ fm.ascent += workPaint.baselineShift;
+ fm.top += workPaint.baselineShift;
+ } else {
+ fm.descent += workPaint.baselineShift;
+ fm.bottom += workPaint.baselineShift;
+ }
+ }
+
+ return wid;
+ }
+
+ int breakText(int start, int limit, boolean forwards, float width) {
+ float[] w = mWidths;
+ if (forwards) {
+ for (int i = start; i < limit; ++i) {
+ if ((width -= w[i]) < 0) {
+ return i - start;
+ }
+ }
+ } else {
+ for (int i = limit; --i >= start;) {
+ if ((width -= w[i]) < 0) {
+ return limit - i -1;
+ }
+ }
+ }
+
+ return limit - start;
+ }
+
+ float measure(int start, int limit) {
+ float width = 0;
+ float[] w = mWidths;
+ for (int i = start; i < limit; ++i) {
+ width += w[i];
+ }
+ return width;
+ }
+}
\ No newline at end of file
diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java
index caaafa1..7563179 100644
--- a/core/java/android/text/SpannableStringBuilder.java
+++ b/core/java/android/text/SpannableStringBuilder.java
@@ -17,8 +17,9 @@
package android.text;
import com.android.internal.util.ArrayUtils;
-import android.graphics.Paint;
+
import android.graphics.Canvas;
+import android.graphics.Paint;
import java.lang.reflect.Array;
@@ -780,7 +781,7 @@
}
if (count == 0) {
- return (T[]) ArrayUtils.emptyArray(kind);
+ return ArrayUtils.emptyArray(kind);
}
if (count == 1) {
ret = (Object[]) Array.newInstance(kind, 1);
@@ -1055,6 +1056,39 @@
}
/**
+ * Don't call this yourself -- exists for Canvas to use internally.
+ * {@hide}
+ */
+ public void drawTextRun(Canvas c, int start, int end,
+ float x, float y, int flags, Paint p) {
+ checkRange("drawTextRun", start, end);
+
+ // Assume context requires no more than 8 chars on either side.
+ // This is ample, only decomposed U+FDFA falls into this
+ // category, and no one should put a style break within it
+ // anyway.
+ int cstart = start - 8;
+ if (cstart < 0) {
+ cstart = 0;
+ }
+ int cend = end + 8;
+ int max = length();
+ if (cend > max) {
+ cend = max;
+ }
+ if (cend <= mGapStart) {
+ c.drawTextRun(mText, start, end - start, x, y, flags, p);
+ } else if (cstart >= mGapStart) {
+ c.drawTextRun(mText, start + mGapLength, end - start, x, y, flags, p);
+ } else {
+ char[] buf = TextUtils.obtain(cend - cstart);
+ getChars(cstart, cend, buf, 0);
+ c.drawTextRun(buf, start - cstart, end - start, x, y, flags, p);
+ TextUtils.recycle(buf);
+ }
+ }
+
+ /**
* Don't call this yourself -- exists for Paint to use internally.
* {@hide}
*/
diff --git a/core/java/android/text/Spanned.java b/core/java/android/text/Spanned.java
index 154497d..d14fcbc 100644
--- a/core/java/android/text/Spanned.java
+++ b/core/java/android/text/Spanned.java
@@ -91,7 +91,7 @@
public static final int SPAN_EXCLUSIVE_EXCLUSIVE = SPAN_POINT_MARK;
/**
- * Non-0-length spans of type SPAN_INCLUSIVE_EXCLUSIVE expand
+ * Non-0-length spans of type SPAN_EXCLUSIVE_INCLUSIVE expand
* to include text inserted at their ending point but not at their
* starting point. When 0-length, they behave like points.
*/
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index f02ad2a..1646b9e 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -16,14 +16,15 @@
package android.text;
+import com.android.internal.util.ArrayUtils;
+
import android.graphics.Bitmap;
import android.graphics.Paint;
-import com.android.internal.util.ArrayUtils;
-import android.util.Log;
import android.text.style.LeadingMarginSpan;
import android.text.style.LineHeightSpan;
import android.text.style.MetricAffectingSpan;
-import android.text.style.ReplacementSpan;
+import android.text.style.TabStopSpan;
+import android.text.style.LeadingMarginSpan.LeadingMarginSpan2;
/**
* StaticLayout is a Layout for text that will not be edited after it
@@ -31,8 +32,9 @@
* <p>This is used by widgets to control text layout. You should not need
* to use this class directly unless you are implementing your own widget
* or custom display object, or would be tempted to call
- * {@link android.graphics.Canvas#drawText(java.lang.CharSequence, int, int, float, float, android.graphics.Paint)
- * Canvas.drawText()} directly.</p>
+ * {@link android.graphics.Canvas#drawText(java.lang.CharSequence, int, int,
+ * float, float, android.graphics.Paint)
+ * Canvas.drawText()} directly.</p>
*/
public class
StaticLayout
@@ -62,7 +64,7 @@
boolean includepad,
TextUtils.TruncateAt ellipsize, int ellipsizedWidth) {
super((ellipsize == null)
- ? source
+ ? source
: (source instanceof Spanned)
? new SpannedEllipsizer(source)
: new Ellipsizer(source),
@@ -72,7 +74,7 @@
* This is annoying, but we can't refer to the layout until
* superclass construction is finished, and the superclass
* constructor wants the reference to the display text.
- *
+ *
* This will break if the superclass constructor ever actually
* cares about the content instead of just holding the reference.
*/
@@ -94,13 +96,13 @@
mLineDirections = new Directions[
ArrayUtils.idealIntArraySize(2 * mColumns)];
+ mMeasured = MeasuredText.obtain();
+
generate(source, bufstart, bufend, paint, outerwidth, align,
spacingmult, spacingadd, includepad, includepad,
ellipsize != null, ellipsizedWidth, ellipsize);
- mChdirs = null;
- mChs = null;
- mWidths = null;
+ mMeasured = MeasuredText.recycle(mMeasured);
mFontMetricsInt = null;
}
@@ -111,6 +113,7 @@
mLines = new int[ArrayUtils.idealIntArraySize(2 * mColumns)];
mLineDirections = new Directions[
ArrayUtils.idealIntArraySize(2 * mColumns)];
+ mMeasured = MeasuredText.obtain();
}
/* package */ void generate(CharSequence source, int bufstart, int bufend,
@@ -128,59 +131,50 @@
Paint.FontMetricsInt fm = mFontMetricsInt;
int[] choosehtv = null;
- int end = TextUtils.indexOf(source, '\n', bufstart, bufend);
- int bufsiz = end >= 0 ? end - bufstart : bufend - bufstart;
- boolean first = true;
+ MeasuredText measured = mMeasured;
- if (mChdirs == null) {
- mChdirs = new byte[ArrayUtils.idealByteArraySize(bufsiz + 1)];
- mChs = new char[ArrayUtils.idealCharArraySize(bufsiz + 1)];
- mWidths = new float[ArrayUtils.idealIntArraySize((bufsiz + 1) * 2)];
- }
-
- byte[] chdirs = mChdirs;
- char[] chs = mChs;
- float[] widths = mWidths;
-
- AlteredCharSequence alter = null;
Spanned spanned = null;
-
if (source instanceof Spanned)
spanned = (Spanned) source;
int DEFAULT_DIR = DIR_LEFT_TO_RIGHT; // XXX
- for (int start = bufstart; start <= bufend; start = end) {
- if (first)
- first = false;
+ int paraEnd;
+ for (int paraStart = bufstart; paraStart <= bufend; paraStart = paraEnd) {
+ paraEnd = TextUtils.indexOf(source, '\n', paraStart, bufend);
+ if (paraEnd < 0)
+ paraEnd = bufend;
else
- end = TextUtils.indexOf(source, '\n', start, bufend);
+ paraEnd++;
+ int paraLen = paraEnd - paraStart;
- if (end < 0)
- end = bufend;
- else
- end++;
-
- int firstWidthLineCount = 1;
+ int firstWidthLineLimit = mLineCount + 1;
int firstwidth = outerwidth;
int restwidth = outerwidth;
LineHeightSpan[] chooseht = null;
if (spanned != null) {
- LeadingMarginSpan[] sp;
-
- sp = spanned.getSpans(start, end, LeadingMarginSpan.class);
+ LeadingMarginSpan[] sp = spanned.getSpans(paraStart, paraEnd,
+ LeadingMarginSpan.class);
for (int i = 0; i < sp.length; i++) {
LeadingMarginSpan lms = sp[i];
firstwidth -= sp[i].getLeadingMargin(true);
restwidth -= sp[i].getLeadingMargin(false);
- if (lms instanceof LeadingMarginSpan.LeadingMarginSpan2) {
- firstWidthLineCount = ((LeadingMarginSpan.LeadingMarginSpan2)lms).getLeadingMarginLineCount();
+
+ // LeadingMarginSpan2 is odd. The count affects all
+ // leading margin spans, not just this particular one,
+ // and start from the top of the span, not the top of the
+ // paragraph.
+ if (lms instanceof LeadingMarginSpan2) {
+ LeadingMarginSpan2 lms2 = (LeadingMarginSpan2) lms;
+ int lmsFirstLine = getLineForOffset(spanned.getSpanStart(lms2));
+ firstWidthLineLimit = lmsFirstLine +
+ lms2.getLeadingMarginLineCount();
}
}
- chooseht = spanned.getSpans(start, end, LineHeightSpan.class);
+ chooseht = spanned.getSpans(paraStart, paraEnd, LineHeightSpan.class);
if (chooseht.length != 0) {
if (choosehtv == null ||
@@ -192,11 +186,11 @@
for (int i = 0; i < chooseht.length; i++) {
int o = spanned.getSpanStart(chooseht[i]);
- if (o < start) {
+ if (o < paraStart) {
// starts in this layout, before the
// current paragraph
- choosehtv[i] = getLineTop(getLineForOffset(o));
+ choosehtv[i] = getLineTop(getLineForOffset(o));
} else {
// starts in this paragraph
@@ -206,162 +200,85 @@
}
}
- if (end - start > chdirs.length) {
- chdirs = new byte[ArrayUtils.idealByteArraySize(end - start)];
- mChdirs = chdirs;
- }
- if (end - start > chs.length) {
- chs = new char[ArrayUtils.idealCharArraySize(end - start)];
- mChs = chs;
- }
- if ((end - start) * 2 > widths.length) {
- widths = new float[ArrayUtils.idealIntArraySize((end - start) * 2)];
- mWidths = widths;
- }
+ measured.setPara(source, paraStart, paraEnd, DIR_REQUEST_DEFAULT_LTR);
+ char[] chs = measured.mChars;
+ float[] widths = measured.mWidths;
+ byte[] chdirs = measured.mLevels;
+ int dir = measured.mDir;
+ boolean easy = measured.mEasy;
- TextUtils.getChars(source, start, end, chs, 0);
- final int n = end - start;
-
- boolean easy = true;
- boolean altered = false;
- int dir = DEFAULT_DIR; // XXX
-
- for (int i = 0; i < n; i++) {
- if (chs[i] >= FIRST_RIGHT_TO_LEFT) {
- easy = false;
- break;
- }
- }
-
- // Ensure that none of the underlying characters are treated
- // as viable breakpoints, and that the entire run gets the
- // same bidi direction.
-
- if (source instanceof Spanned) {
- Spanned sp = (Spanned) source;
- ReplacementSpan[] spans = sp.getSpans(start, end, ReplacementSpan.class);
-
- for (int y = 0; y < spans.length; y++) {
- int a = sp.getSpanStart(spans[y]);
- int b = sp.getSpanEnd(spans[y]);
-
- for (int x = a; x < b; x++) {
- chs[x - start] = '\uFFFC';
- }
- }
- }
-
- if (!easy) {
- // XXX put override flags, etc. into chdirs
- dir = bidi(dir, chs, chdirs, n, false);
-
- // Do mirroring for right-to-left segments
-
- for (int i = 0; i < n; i++) {
- if (chdirs[i] == Character.DIRECTIONALITY_RIGHT_TO_LEFT) {
- int j;
-
- for (j = i; j < n; j++) {
- if (chdirs[j] !=
- Character.DIRECTIONALITY_RIGHT_TO_LEFT)
- break;
- }
-
- if (AndroidCharacter.mirror(chs, i, j - i))
- altered = true;
-
- i = j - 1;
- }
- }
- }
-
- CharSequence sub;
-
- if (altered) {
- if (alter == null)
- alter = AlteredCharSequence.make(source, chs, start, end);
- else
- alter.update(chs, start, end);
-
- sub = alter;
- } else {
- sub = source;
- }
+ CharSequence sub = source;
int width = firstwidth;
float w = 0;
- int here = start;
+ int here = paraStart;
- int ok = start;
+ int ok = paraStart;
float okwidth = w;
int okascent = 0, okdescent = 0, oktop = 0, okbottom = 0;
- int fit = start;
+ int fit = paraStart;
float fitwidth = w;
int fitascent = 0, fitdescent = 0, fittop = 0, fitbottom = 0;
- boolean tab = false;
+ boolean hasTabOrEmoji = false;
+ boolean hasTab = false;
+ TabStops tabStops = null;
- int next;
- for (int i = start; i < end; i = next) {
- if (spanned == null)
- next = end;
- else
- next = spanned.nextSpanTransition(i, end,
- MetricAffectingSpan.
- class);
+ for (int spanStart = paraStart, spanEnd = spanStart, nextSpanStart;
+ spanStart < paraEnd; spanStart = nextSpanStart) {
- if (spanned == null) {
- paint.getTextWidths(sub, i, next, widths);
- System.arraycopy(widths, 0, widths,
- end - start + (i - start), next - i);
-
- paint.getFontMetricsInt(fm);
- } else {
- mWorkPaint.baselineShift = 0;
+ if (spanStart == spanEnd) {
+ if (spanned == null)
+ spanEnd = paraEnd;
+ else
+ spanEnd = spanned.nextSpanTransition(spanStart, paraEnd,
+ MetricAffectingSpan.class);
- Styled.getTextWidths(paint, mWorkPaint,
- spanned, i, next,
- widths, fm);
- System.arraycopy(widths, 0, widths,
- end - start + (i - start), next - i);
-
- if (mWorkPaint.baselineShift < 0) {
- fm.ascent += mWorkPaint.baselineShift;
- fm.top += mWorkPaint.baselineShift;
+ int spanLen = spanEnd - spanStart;
+ if (spanned == null) {
+ measured.addStyleRun(paint, spanLen, fm);
} else {
- fm.descent += mWorkPaint.baselineShift;
- fm.bottom += mWorkPaint.baselineShift;
+ MetricAffectingSpan[] spans =
+ spanned.getSpans(spanStart, spanEnd, MetricAffectingSpan.class);
+ measured.addStyleRun(paint, spans, spanLen, fm);
}
}
+ nextSpanStart = spanEnd;
+ int startInPara = spanStart - paraStart;
+ int endInPara = spanEnd - paraStart;
+
int fmtop = fm.top;
int fmbottom = fm.bottom;
int fmascent = fm.ascent;
int fmdescent = fm.descent;
- if (false) {
- StringBuilder sb = new StringBuilder();
- for (int j = i; j < next; j++) {
- sb.append(widths[j - start + (end - start)]);
- sb.append(' ');
- }
-
- Log.e("text", sb.toString());
- }
-
- for (int j = i; j < next; j++) {
- char c = chs[j - start];
+ for (int j = spanStart; j < spanEnd; j++) {
+ char c = chs[j - paraStart];
float before = w;
if (c == '\n') {
;
} else if (c == '\t') {
- w = Layout.nextTab(sub, start, end, w, null);
- tab = true;
- } else if (c >= 0xD800 && c <= 0xDFFF && j + 1 < next) {
- int emoji = Character.codePointAt(chs, j - start);
+ if (hasTab == false) {
+ hasTab = true;
+ hasTabOrEmoji = true;
+ // First tab this para, check for tabstops
+ TabStopSpan[] spans = spanned.getSpans(paraStart,
+ paraEnd, TabStopSpan.class);
+ if (spans.length > 0) {
+ tabStops = new TabStops(TAB_INCREMENT, spans);
+ }
+ }
+ if (tabStops != null) {
+ w = tabStops.nextTab(w);
+ } else {
+ w = TabStops.nextDefaultStop(w, TAB_INCREMENT);
+ }
+ } else if (c >= 0xD800 && c <= 0xDFFF && j + 1 < spanEnd) {
+ int emoji = Character.codePointAt(chs, j - paraStart);
if (emoji >= MIN_EMOJI && emoji <= MAX_EMOJI) {
Bitmap bm = EMOJI_FACTORY.
@@ -376,21 +293,21 @@
whichPaint = mWorkPaint;
}
- float wid = (float) bm.getWidth() *
+ float wid = bm.getWidth() *
-whichPaint.ascent() /
bm.getHeight();
w += wid;
- tab = true;
+ hasTabOrEmoji = true;
j++;
} else {
- w += widths[j - start + (end - start)];
+ w += widths[j - paraStart];
}
} else {
- w += widths[j - start + (end - start)];
+ w += widths[j - paraStart];
}
} else {
- w += widths[j - start + (end - start)];
+ w += widths[j - paraStart];
}
// Log.e("text", "was " + before + " now " + w + " after " + c + " within " + width);
@@ -411,7 +328,7 @@
/*
* From the Unicode Line Breaking Algorithm:
* (at least approximately)
- *
+ *
* .,:; are class IS: breakpoints
* except when adjacent to digits
* / is class SY: a breakpoint
@@ -426,12 +343,12 @@
if (c == ' ' || c == '\t' ||
((c == '.' || c == ',' || c == ':' || c == ';') &&
- (j - 1 < here || !Character.isDigit(chs[j - 1 - start])) &&
- (j + 1 >= next || !Character.isDigit(chs[j + 1 - start]))) ||
+ (j - 1 < here || !Character.isDigit(chs[j - 1 - paraStart])) &&
+ (j + 1 >= spanEnd || !Character.isDigit(chs[j + 1 - paraStart]))) ||
((c == '/' || c == '-') &&
- (j + 1 >= next || !Character.isDigit(chs[j + 1 - start]))) ||
+ (j + 1 >= spanEnd || !Character.isDigit(chs[j + 1 - paraStart]))) ||
(c >= FIRST_CJK && isIdeographic(c, true) &&
- j + 1 < next && isIdeographic(chs[j + 1 - start], false))) {
+ j + 1 < spanEnd && isIdeographic(chs[j + 1 - paraStart], false))) {
okwidth = w;
ok = j + 1;
@@ -448,7 +365,7 @@
if (ok != here) {
// Log.e("text", "output ok " + here + " to " +ok);
- while (ok < next && chs[ok - start] == ' ') {
+ while (ok < spanEnd && chs[ok - paraStart] == ' ') {
ok++;
}
@@ -457,10 +374,10 @@
okascent, okdescent, oktop, okbottom,
v,
spacingmult, spacingadd, chooseht,
- choosehtv, fm, tab,
- needMultiply, start, chdirs, dir, easy,
+ choosehtv, fm, hasTabOrEmoji,
+ needMultiply, paraStart, chdirs, dir, easy,
ok == bufend, includepad, trackpad,
- widths, start, end - start,
+ chs, widths, here - paraStart,
where, ellipsizedWidth, okwidth,
paint);
@@ -484,7 +401,7 @@
if (ok != here) {
// Log.e("text", "output ok " + here + " to " +ok);
- while (ok < next && chs[ok - start] == ' ') {
+ while (ok < spanEnd && chs[ok - paraStart] == ' ') {
ok++;
}
@@ -493,10 +410,10 @@
okascent, okdescent, oktop, okbottom,
v,
spacingmult, spacingadd, chooseht,
- choosehtv, fm, tab,
- needMultiply, start, chdirs, dir, easy,
+ choosehtv, fm, hasTabOrEmoji,
+ needMultiply, paraStart, chdirs, dir, easy,
ok == bufend, includepad, trackpad,
- widths, start, end - start,
+ chs, widths, here - paraStart,
where, ellipsizedWidth, okwidth,
paint);
@@ -509,19 +426,20 @@
fittop, fitbottom,
v,
spacingmult, spacingadd, chooseht,
- choosehtv, fm, tab,
- needMultiply, start, chdirs, dir, easy,
+ choosehtv, fm, hasTabOrEmoji,
+ needMultiply, paraStart, chdirs, dir, easy,
fit == bufend, includepad, trackpad,
- widths, start, end - start,
+ chs, widths, here - paraStart,
where, ellipsizedWidth, fitwidth,
paint);
here = fit;
} else {
// Log.e("text", "output one " + here + " to " +(here + 1));
- measureText(paint, mWorkPaint,
- source, here, here + 1, fm, tab,
- null);
+ // XXX not sure why the existing fm wasn't ok.
+ // measureText(paint, mWorkPaint,
+ // source, here, here + 1, fm, tab,
+ // null);
v = out(source,
here, here+1,
@@ -529,19 +447,22 @@
fm.top, fm.bottom,
v,
spacingmult, spacingadd, chooseht,
- choosehtv, fm, tab,
- needMultiply, start, chdirs, dir, easy,
+ choosehtv, fm, hasTabOrEmoji,
+ needMultiply, paraStart, chdirs, dir, easy,
here + 1 == bufend, includepad,
trackpad,
- widths, start, end - start,
+ chs, widths, here - paraStart,
where, ellipsizedWidth,
- widths[here - start], paint);
+ widths[here - paraStart], paint);
here = here + 1;
}
- if (here < i) {
- j = next = here; // must remeasure
+ if (here < spanStart) {
+ // didn't output all the text for this span
+ // we've measured the raw widths, though, so
+ // just reset the start point
+ j = nextSpanStart = here;
} else {
j = here - 1; // continue looping
}
@@ -551,14 +472,14 @@
fitascent = fitdescent = fittop = fitbottom = 0;
okascent = okdescent = oktop = okbottom = 0;
- if (--firstWidthLineCount <= 0) {
+ if (--firstWidthLineLimit <= 0) {
width = restwidth;
}
}
}
}
- if (end != here) {
+ if (paraEnd != here) {
if ((fittop | fitbottom | fitdescent | fitascent) == 0) {
paint.getFontMetricsInt(fm);
@@ -571,20 +492,20 @@
// Log.e("text", "output rest " + here + " to " + end);
v = out(source,
- here, end, fitascent, fitdescent,
+ here, paraEnd, fitascent, fitdescent,
fittop, fitbottom,
v,
spacingmult, spacingadd, chooseht,
- choosehtv, fm, tab,
- needMultiply, start, chdirs, dir, easy,
- end == bufend, includepad, trackpad,
- widths, start, end - start,
+ choosehtv, fm, hasTabOrEmoji,
+ needMultiply, paraStart, chdirs, dir, easy,
+ paraEnd == bufend, includepad, trackpad,
+ chs, widths, here - paraStart,
where, ellipsizedWidth, w, paint);
}
- start = end;
+ paraStart = paraEnd;
- if (end == bufend)
+ if (paraEnd == bufend)
break;
}
@@ -599,246 +520,13 @@
v,
spacingmult, spacingadd, null,
null, fm, false,
- needMultiply, bufend, chdirs, DEFAULT_DIR, true,
+ needMultiply, bufend, null, DEFAULT_DIR, true,
true, includepad, trackpad,
- widths, bufstart, 0,
+ null, null, bufstart,
where, ellipsizedWidth, 0, paint);
}
}
- /**
- * Runs the unicode bidi algorithm on the first n chars in chs, returning
- * the char dirs in chInfo and the base line direction of the first
- * paragraph.
- *
- * XXX change result from dirs to levels
- *
- * @param dir the direction flag, either DIR_REQUEST_LTR,
- * DIR_REQUEST_RTL, DIR_REQUEST_DEFAULT_LTR, or DIR_REQUEST_DEFAULT_RTL.
- * @param chs the text to examine
- * @param chInfo on input, if hasInfo is true, override and other flags
- * representing out-of-band embedding information. On output, the generated
- * dirs of the text.
- * @param n the length of the text/information in chs and chInfo
- * @param hasInfo true if chInfo has input information, otherwise the
- * input data in chInfo is ignored.
- * @return the resolved direction level of the first paragraph, either
- * DIR_LEFT_TO_RIGHT or DIR_RIGHT_TO_LEFT.
- */
- /* package */ static int bidi(int dir, char[] chs, byte[] chInfo, int n,
- boolean hasInfo) {
-
- AndroidCharacter.getDirectionalities(chs, chInfo, n);
-
- /*
- * Determine primary paragraph direction if not specified
- */
- if (dir != DIR_REQUEST_LTR && dir != DIR_REQUEST_RTL) {
- // set up default
- dir = dir >= 0 ? DIR_LEFT_TO_RIGHT : DIR_RIGHT_TO_LEFT;
- for (int j = 0; j < n; j++) {
- int d = chInfo[j];
-
- if (d == Character.DIRECTIONALITY_LEFT_TO_RIGHT) {
- dir = DIR_LEFT_TO_RIGHT;
- break;
- }
- if (d == Character.DIRECTIONALITY_RIGHT_TO_LEFT) {
- dir = DIR_RIGHT_TO_LEFT;
- break;
- }
- }
- }
-
- final byte SOR = dir == DIR_LEFT_TO_RIGHT ?
- Character.DIRECTIONALITY_LEFT_TO_RIGHT :
- Character.DIRECTIONALITY_RIGHT_TO_LEFT;
-
- /*
- * XXX Explicit overrides should go here
- */
-
- /*
- * Weak type resolution
- */
-
- // dump(chdirs, n, "initial");
-
- // W1 non spacing marks
- for (int j = 0; j < n; j++) {
- if (chInfo[j] == Character.NON_SPACING_MARK) {
- if (j == 0)
- chInfo[j] = SOR;
- else
- chInfo[j] = chInfo[j - 1];
- }
- }
-
- // dump(chdirs, n, "W1");
-
- // W2 european numbers
- byte cur = SOR;
- for (int j = 0; j < n; j++) {
- byte d = chInfo[j];
-
- if (d == Character.DIRECTIONALITY_LEFT_TO_RIGHT ||
- d == Character.DIRECTIONALITY_RIGHT_TO_LEFT ||
- d == Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC)
- cur = d;
- else if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER) {
- if (cur ==
- Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC)
- chInfo[j] = Character.DIRECTIONALITY_ARABIC_NUMBER;
- }
- }
-
- // dump(chdirs, n, "W2");
-
- // W3 arabic letters
- for (int j = 0; j < n; j++) {
- if (chInfo[j] == Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC)
- chInfo[j] = Character.DIRECTIONALITY_RIGHT_TO_LEFT;
- }
-
- // dump(chdirs, n, "W3");
-
- // W4 single separator between numbers
- for (int j = 1; j < n - 1; j++) {
- byte d = chInfo[j];
- byte prev = chInfo[j - 1];
- byte next = chInfo[j + 1];
-
- if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR) {
- if (prev == Character.DIRECTIONALITY_EUROPEAN_NUMBER &&
- next == Character.DIRECTIONALITY_EUROPEAN_NUMBER)
- chInfo[j] = Character.DIRECTIONALITY_EUROPEAN_NUMBER;
- } else if (d == Character.DIRECTIONALITY_COMMON_NUMBER_SEPARATOR) {
- if (prev == Character.DIRECTIONALITY_EUROPEAN_NUMBER &&
- next == Character.DIRECTIONALITY_EUROPEAN_NUMBER)
- chInfo[j] = Character.DIRECTIONALITY_EUROPEAN_NUMBER;
- if (prev == Character.DIRECTIONALITY_ARABIC_NUMBER &&
- next == Character.DIRECTIONALITY_ARABIC_NUMBER)
- chInfo[j] = Character.DIRECTIONALITY_ARABIC_NUMBER;
- }
- }
-
- // dump(chdirs, n, "W4");
-
- // W5 european number terminators
- boolean adjacent = false;
- for (int j = 0; j < n; j++) {
- byte d = chInfo[j];
-
- if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER)
- adjacent = true;
- else if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR && adjacent)
- chInfo[j] = Character.DIRECTIONALITY_EUROPEAN_NUMBER;
- else
- adjacent = false;
- }
-
- //dump(chdirs, n, "W5");
-
- // W5 european number terminators part 2,
- // W6 separators and terminators
- adjacent = false;
- for (int j = n - 1; j >= 0; j--) {
- byte d = chInfo[j];
-
- if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER)
- adjacent = true;
- else if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR) {
- if (adjacent)
- chInfo[j] = Character.DIRECTIONALITY_EUROPEAN_NUMBER;
- else
- chInfo[j] = Character.DIRECTIONALITY_OTHER_NEUTRALS;
- }
- else {
- adjacent = false;
-
- if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR ||
- d == Character.DIRECTIONALITY_COMMON_NUMBER_SEPARATOR ||
- d == Character.DIRECTIONALITY_PARAGRAPH_SEPARATOR ||
- d == Character.DIRECTIONALITY_SEGMENT_SEPARATOR)
- chInfo[j] = Character.DIRECTIONALITY_OTHER_NEUTRALS;
- }
- }
-
- // dump(chdirs, n, "W6");
-
- // W7 strong direction of european numbers
- cur = SOR;
- for (int j = 0; j < n; j++) {
- byte d = chInfo[j];
-
- if (d == SOR ||
- d == Character.DIRECTIONALITY_LEFT_TO_RIGHT ||
- d == Character.DIRECTIONALITY_RIGHT_TO_LEFT)
- cur = d;
-
- if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER)
- chInfo[j] = cur;
- }
-
- // dump(chdirs, n, "W7");
-
- // N1, N2 neutrals
- cur = SOR;
- for (int j = 0; j < n; j++) {
- byte d = chInfo[j];
-
- if (d == Character.DIRECTIONALITY_LEFT_TO_RIGHT ||
- d == Character.DIRECTIONALITY_RIGHT_TO_LEFT) {
- cur = d;
- } else if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER ||
- d == Character.DIRECTIONALITY_ARABIC_NUMBER) {
- cur = Character.DIRECTIONALITY_RIGHT_TO_LEFT;
- } else {
- byte dd = SOR;
- int k;
-
- for (k = j + 1; k < n; k++) {
- dd = chInfo[k];
-
- if (dd == Character.DIRECTIONALITY_LEFT_TO_RIGHT ||
- dd == Character.DIRECTIONALITY_RIGHT_TO_LEFT) {
- break;
- }
- if (dd == Character.DIRECTIONALITY_EUROPEAN_NUMBER ||
- dd == Character.DIRECTIONALITY_ARABIC_NUMBER) {
- dd = Character.DIRECTIONALITY_RIGHT_TO_LEFT;
- break;
- }
- }
-
- for (int y = j; y < k; y++) {
- if (dd == cur)
- chInfo[y] = cur;
- else
- chInfo[y] = SOR;
- }
-
- j = k - 1;
- }
- }
-
- // dump(chdirs, n, "final");
-
- // extra: enforce that all tabs and surrogate characters go the
- // primary direction
- // TODO: actually do directions right for surrogates
-
- for (int j = 0; j < n; j++) {
- char c = chs[j];
-
- if (c == '\t' || (c >= 0xD800 && c <= 0xDFFF)) {
- chInfo[j] = SOR;
- }
- }
-
- return dir;
- }
-
private static final char FIRST_CJK = '\u2E80';
/**
* Returns true if the specified character is one of those specified
@@ -944,37 +632,15 @@
}
*/
- private static int getFit(TextPaint paint,
- TextPaint workPaint,
- CharSequence text, int start, int end,
- float wid) {
- int high = end + 1, low = start - 1, guess;
-
- while (high - low > 1) {
- guess = (high + low) / 2;
-
- if (measureText(paint, workPaint,
- text, start, guess, null, true, null) > wid)
- high = guess;
- else
- low = guess;
- }
-
- if (low < start)
- return start;
- else
- return low;
- }
-
private int out(CharSequence text, int start, int end,
int above, int below, int top, int bottom, int v,
float spacingmult, float spacingadd,
LineHeightSpan[] chooseht, int[] choosehtv,
- Paint.FontMetricsInt fm, boolean tab,
+ Paint.FontMetricsInt fm, boolean hasTabOrEmoji,
boolean needMultiply, int pstart, byte[] chdirs,
int dir, boolean easy, boolean last,
boolean includepad, boolean trackpad,
- float[] widths, int widstart, int widoff,
+ char[] chs, float[] widths, int widstart,
TextUtils.TruncateAt ellipsize, float ellipsiswidth,
float textwidth, TextPaint paint) {
int j = mLineCount;
@@ -982,8 +648,6 @@
int want = off + mColumns + TOP;
int[] lines = mLines;
- // Log.e("text", "line " + start + " to " + end + (last ? "===" : ""));
-
if (want >= lines.length) {
int nlen = ArrayUtils.idealIntArraySize(want + 1);
int[] grow = new int[nlen];
@@ -1059,59 +723,23 @@
lines[off + mColumns + START] = end;
lines[off + mColumns + TOP] = v;
- if (tab)
+ if (hasTabOrEmoji)
lines[off + TAB] |= TAB_MASK;
- {
- lines[off + DIR] |= dir << DIR_SHIFT;
-
- int cur = Character.DIRECTIONALITY_LEFT_TO_RIGHT;
- int count = 0;
-
- if (!easy) {
- for (int k = start; k < end; k++) {
- if (chdirs[k - pstart] != cur) {
- count++;
- cur = chdirs[k - pstart];
- }
- }
- }
-
- Directions linedirs;
-
- if (count == 0) {
- linedirs = DIRS_ALL_LEFT_TO_RIGHT;
- } else {
- short[] ld = new short[count + 1];
-
- cur = Character.DIRECTIONALITY_LEFT_TO_RIGHT;
- count = 0;
- int here = start;
-
- for (int k = start; k < end; k++) {
- if (chdirs[k - pstart] != cur) {
- // XXX check to make sure we don't
- // overflow short
- ld[count++] = (short) (k - here);
- cur = chdirs[k - pstart];
- here = k;
- }
- }
-
- ld[count] = (short) (end - here);
-
- if (count == 1 && ld[0] == 0) {
- linedirs = DIRS_ALL_RIGHT_TO_LEFT;
- } else {
- linedirs = new Directions(ld);
- }
- }
-
+ lines[off + DIR] |= dir << DIR_SHIFT;
+ Directions linedirs = DIRS_ALL_LEFT_TO_RIGHT;
+ // easy means all chars < the first RTL, so no emoji, no nothing
+ // XXX a run with no text or all spaces is easy but might be an empty
+ // RTL paragraph. Make sure easy is false if this is the case.
+ if (easy) {
mLineDirections[j] = linedirs;
+ } else {
+ mLineDirections[j] = AndroidBidi.directions(dir, chdirs, widstart, chs,
+ widstart, end - start);
// If ellipsize is in marquee mode, do not apply ellipsis on the first line
if (ellipsize != null && (ellipsize != TextUtils.TruncateAt.MARQUEE || j != 0)) {
- calculateEllipsis(start, end, widths, widstart, widoff,
+ calculateEllipsis(start, end, widths, widstart,
ellipsiswidth, ellipsize, j,
textwidth, paint);
}
@@ -1122,7 +750,7 @@
}
private void calculateEllipsis(int linestart, int lineend,
- float[] widths, int widstart, int widoff,
+ float[] widths, int widstart,
float avail, TextUtils.TruncateAt where,
int line, float textwidth, TextPaint paint) {
int len = lineend - linestart;
@@ -1142,7 +770,7 @@
int i;
for (i = len; i >= 0; i--) {
- float w = widths[i - 1 + linestart - widstart + widoff];
+ float w = widths[i - 1 + linestart - widstart];
if (w + sum + ellipsiswid > avail) {
break;
@@ -1158,7 +786,7 @@
int i;
for (i = 0; i < len; i++) {
- float w = widths[i + linestart - widstart + widoff];
+ float w = widths[i + linestart - widstart];
if (w + sum + ellipsiswid > avail) {
break;
@@ -1175,7 +803,7 @@
float ravail = (avail - ellipsiswid) / 2;
for (right = len; right >= 0; right--) {
- float w = widths[right - 1 + linestart - widstart + widoff];
+ float w = widths[right - 1 + linestart - widstart];
if (w + rsum > ravail) {
break;
@@ -1186,7 +814,7 @@
float lavail = avail - ellipsiswid - rsum;
for (left = 0; left < right; left++) {
- float w = widths[left + linestart - widstart + widoff];
+ float w = widths[left + linestart - widstart];
if (w + lsum > lavail) {
break;
@@ -1203,7 +831,7 @@
mLines[mColumns * line + ELLIPSIS_COUNT] = ellipsisCount;
}
- // Override the baseclass so we can directly access our members,
+ // Override the base class so we can directly access our members,
// rather than relying on member functions.
// The logic mirrors that of Layout.getLineForVertical
// FIXME: It may be faster to do a linear search for layouts without many lines.
@@ -1232,11 +860,11 @@
}
public int getLineTop(int line) {
- return mLines[mColumns * line + TOP];
+ return mLines[mColumns * line + TOP];
}
public int getLineDescent(int line) {
- return mLines[mColumns * line + DESCENT];
+ return mLines[mColumns * line + DESCENT];
}
public int getLineStart(int line) {
@@ -1309,13 +937,11 @@
private static final int DIR_SHIFT = 30;
private static final int TAB_MASK = 0x20000000;
- private static final char FIRST_RIGHT_TO_LEFT = '\u0590';
+ private static final int TAB_INCREMENT = 20; // same as Layout, but that's private
/*
- * These are reused across calls to generate()
+ * This is reused across calls to generate()
*/
- private byte[] mChdirs;
- private char[] mChs;
- private float[] mWidths;
+ private MeasuredText mMeasured;
private Paint.FontMetricsInt mFontMetricsInt = new Paint.FontMetricsInt();
}
diff --git a/core/java/android/text/Styled.java b/core/java/android/text/Styled.java
deleted file mode 100644
index 513b2cd..0000000
--- a/core/java/android/text/Styled.java
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.text;
-
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.text.style.CharacterStyle;
-import android.text.style.MetricAffectingSpan;
-import android.text.style.ReplacementSpan;
-
-/**
- * This class provides static methods for drawing and measuring styled text,
- * like {@link android.text.Spanned} object with
- * {@link android.text.style.ReplacementSpan}.
- *
- * @hide
- */
-public class Styled
-{
- /**
- * Draws and/or measures a uniform run of text on a single line. No span of
- * interest should start or end in the middle of this run (if not
- * drawing, character spans that don't affect metrics can be ignored).
- * Neither should the run direction change in the middle of the run.
- *
- * <p>The x position is the leading edge of the text. In a right-to-left
- * paragraph, this will be to the right of the text to be drawn. Paint
- * should not have an Align value other than LEFT or positioning will get
- * confused.
- *
- * <p>On return, workPaint will reflect the original paint plus any
- * modifications made by character styles on the run.
- *
- * <p>The returned width is signed and will be < 0 if the paragraph
- * direction is right-to-left.
- */
- private static float drawUniformRun(Canvas canvas,
- Spanned text, int start, int end,
- int dir, boolean runIsRtl,
- float x, int top, int y, int bottom,
- Paint.FontMetricsInt fmi,
- TextPaint paint,
- TextPaint workPaint,
- boolean needWidth) {
-
- boolean haveWidth = false;
- float ret = 0;
- CharacterStyle[] spans = text.getSpans(start, end, CharacterStyle.class);
-
- ReplacementSpan replacement = null;
-
- // XXX: This shouldn't be modifying paint, only workPaint.
- // However, the members belonging to TextPaint should have default
- // values anyway. Better to ensure this in the Layout constructor.
- paint.bgColor = 0;
- paint.baselineShift = 0;
- workPaint.set(paint);
-
- if (spans.length > 0) {
- for (int i = 0; i < spans.length; i++) {
- CharacterStyle span = spans[i];
-
- if (span instanceof ReplacementSpan) {
- replacement = (ReplacementSpan)span;
- }
- else {
- span.updateDrawState(workPaint);
- }
- }
- }
-
- if (replacement == null) {
- CharSequence tmp;
- int tmpstart, tmpend;
-
- if (runIsRtl) {
- tmp = TextUtils.getReverse(text, start, end);
- tmpstart = 0;
- // XXX: assumes getReverse doesn't change the length of the text
- tmpend = end - start;
- } else {
- tmp = text;
- tmpstart = start;
- tmpend = end;
- }
-
- if (fmi != null) {
- workPaint.getFontMetricsInt(fmi);
- }
-
- if (canvas != null) {
- if (workPaint.bgColor != 0) {
- int c = workPaint.getColor();
- Paint.Style s = workPaint.getStyle();
- workPaint.setColor(workPaint.bgColor);
- workPaint.setStyle(Paint.Style.FILL);
-
- if (!haveWidth) {
- ret = workPaint.measureText(tmp, tmpstart, tmpend);
- haveWidth = true;
- }
-
- if (dir == Layout.DIR_RIGHT_TO_LEFT)
- canvas.drawRect(x - ret, top, x, bottom, workPaint);
- else
- canvas.drawRect(x, top, x + ret, bottom, workPaint);
-
- workPaint.setStyle(s);
- workPaint.setColor(c);
- }
-
- if (dir == Layout.DIR_RIGHT_TO_LEFT) {
- if (!haveWidth) {
- ret = workPaint.measureText(tmp, tmpstart, tmpend);
- haveWidth = true;
- }
-
- canvas.drawText(tmp, tmpstart, tmpend,
- x - ret, y + workPaint.baselineShift, workPaint);
- } else {
- if (needWidth) {
- if (!haveWidth) {
- ret = workPaint.measureText(tmp, tmpstart, tmpend);
- haveWidth = true;
- }
- }
-
- canvas.drawText(tmp, tmpstart, tmpend,
- x, y + workPaint.baselineShift, workPaint);
- }
- } else {
- if (needWidth && !haveWidth) {
- ret = workPaint.measureText(tmp, tmpstart, tmpend);
- haveWidth = true;
- }
- }
- } else {
- ret = replacement.getSize(workPaint, text, start, end, fmi);
-
- if (canvas != null) {
- if (dir == Layout.DIR_RIGHT_TO_LEFT)
- replacement.draw(canvas, text, start, end,
- x - ret, top, y, bottom, workPaint);
- else
- replacement.draw(canvas, text, start, end,
- x, top, y, bottom, workPaint);
- }
- }
-
- if (dir == Layout.DIR_RIGHT_TO_LEFT)
- return -ret;
- else
- return ret;
- }
-
- /**
- * Returns the advance widths for a uniform left-to-right run of text with
- * no style changes in the middle of the run. If any style is replacement
- * text, the first character will get the width of the replacement and the
- * remaining characters will get a width of 0.
- *
- * @param paint the paint, will not be modified
- * @param workPaint a paint to modify; on return will reflect the original
- * paint plus the effect of all spans on the run
- * @param text the text
- * @param start the start of the run
- * @param end the limit of the run
- * @param widths array to receive the advance widths of the characters. Must
- * be at least a large as (end - start).
- * @param fmi FontMetrics information; can be null
- * @return the actual number of widths returned
- */
- public static int getTextWidths(TextPaint paint,
- TextPaint workPaint,
- Spanned text, int start, int end,
- float[] widths, Paint.FontMetricsInt fmi) {
- MetricAffectingSpan[] spans =
- text.getSpans(start, end, MetricAffectingSpan.class);
-
- ReplacementSpan replacement = null;
- workPaint.set(paint);
-
- for (int i = 0; i < spans.length; i++) {
- MetricAffectingSpan span = spans[i];
- if (span instanceof ReplacementSpan) {
- replacement = (ReplacementSpan)span;
- }
- else {
- span.updateMeasureState(workPaint);
- }
- }
-
- if (replacement == null) {
- workPaint.getFontMetricsInt(fmi);
- workPaint.getTextWidths(text, start, end, widths);
- } else {
- int wid = replacement.getSize(workPaint, text, start, end, fmi);
-
- if (end > start) {
- widths[0] = wid;
- for (int i = start + 1; i < end; i++)
- widths[i - start] = 0;
- }
- }
- return end - start;
- }
-
- /**
- * Renders and/or measures a directional run of text on a single line.
- * Unlike {@link #drawUniformRun}, this can render runs that cross style
- * boundaries. Returns the signed advance width, if requested.
- *
- * <p>The x position is the leading edge of the text. In a right-to-left
- * paragraph, this will be to the right of the text to be drawn. Paint
- * should not have an Align value other than LEFT or positioning will get
- * confused.
- *
- * <p>This optimizes for unstyled text and so workPaint might not be
- * modified by this call.
- *
- * <p>The returned advance width will be < 0 if the paragraph
- * direction is right-to-left.
- */
- private static float drawDirectionalRun(Canvas canvas,
- CharSequence text, int start, int end,
- int dir, boolean runIsRtl,
- float x, int top, int y, int bottom,
- Paint.FontMetricsInt fmi,
- TextPaint paint,
- TextPaint workPaint,
- boolean needWidth) {
-
- // XXX: It looks like all calls to this API match dir and runIsRtl, so
- // having both parameters is redundant and confusing.
-
- // fast path for unstyled text
- if (!(text instanceof Spanned)) {
- float ret = 0;
-
- if (runIsRtl) {
- CharSequence tmp = TextUtils.getReverse(text, start, end);
- // XXX: this assumes getReverse doesn't tweak the length of
- // the text
- int tmpend = end - start;
-
- if (canvas != null || needWidth)
- ret = paint.measureText(tmp, 0, tmpend);
-
- if (canvas != null)
- canvas.drawText(tmp, 0, tmpend,
- x - ret, y, paint);
- } else {
- if (needWidth)
- ret = paint.measureText(text, start, end);
-
- if (canvas != null)
- canvas.drawText(text, start, end, x, y, paint);
- }
-
- if (fmi != null) {
- paint.getFontMetricsInt(fmi);
- }
-
- return ret * dir; // Layout.DIR_RIGHT_TO_LEFT == -1
- }
-
- float ox = x;
- int minAscent = 0, maxDescent = 0, minTop = 0, maxBottom = 0;
-
- Spanned sp = (Spanned) text;
- Class<?> division;
-
- if (canvas == null)
- division = MetricAffectingSpan.class;
- else
- division = CharacterStyle.class;
-
- int next;
- for (int i = start; i < end; i = next) {
- next = sp.nextSpanTransition(i, end, division);
-
- // XXX: if dir and runIsRtl were not the same, this would draw
- // spans in the wrong order, but no one appears to call it this
- // way.
- x += drawUniformRun(canvas, sp, i, next, dir, runIsRtl,
- x, top, y, bottom, fmi, paint, workPaint,
- needWidth || next != end);
-
- if (fmi != null) {
- if (fmi.ascent < minAscent)
- minAscent = fmi.ascent;
- if (fmi.descent > maxDescent)
- maxDescent = fmi.descent;
-
- if (fmi.top < minTop)
- minTop = fmi.top;
- if (fmi.bottom > maxBottom)
- maxBottom = fmi.bottom;
- }
- }
-
- if (fmi != null) {
- if (start == end) {
- paint.getFontMetricsInt(fmi);
- } else {
- fmi.ascent = minAscent;
- fmi.descent = maxDescent;
- fmi.top = minTop;
- fmi.bottom = maxBottom;
- }
- }
-
- return x - ox;
- }
-
- /**
- * Draws a unidirectional run of text on a single line, and optionally
- * returns the signed advance. Unlike drawDirectionalRun, the paragraph
- * direction and run direction can be different.
- */
- /* package */ static float drawText(Canvas canvas,
- CharSequence text, int start, int end,
- int dir, boolean runIsRtl,
- float x, int top, int y, int bottom,
- TextPaint paint,
- TextPaint workPaint,
- boolean needWidth) {
- // XXX this logic is (dir == DIR_LEFT_TO_RIGHT) == runIsRtl
- if ((dir == Layout.DIR_RIGHT_TO_LEFT && !runIsRtl) ||
- (runIsRtl && dir == Layout.DIR_LEFT_TO_RIGHT)) {
- // TODO: this needs the real direction
- float ch = drawDirectionalRun(null, text, start, end,
- Layout.DIR_LEFT_TO_RIGHT, false, 0, 0, 0, 0, null, paint,
- workPaint, true);
-
- ch *= dir; // DIR_RIGHT_TO_LEFT == -1
- drawDirectionalRun(canvas, text, start, end, -dir,
- runIsRtl, x + ch, top, y, bottom, null, paint,
- workPaint, true);
-
- return ch;
- }
-
- return drawDirectionalRun(canvas, text, start, end, dir, runIsRtl,
- x, top, y, bottom, null, paint, workPaint,
- needWidth);
- }
-
- /**
- * Draws a run of text on a single line, with its
- * origin at (x,y), in the specified Paint. The origin is interpreted based
- * on the Align setting in the Paint.
- *
- * This method considers style information in the text (e.g. even when text
- * is an instance of {@link android.text.Spanned}, this method correctly
- * draws the text). See also
- * {@link android.graphics.Canvas#drawText(CharSequence, int, int, float,
- * float, Paint)} and
- * {@link android.graphics.Canvas#drawRect(float, float, float, float,
- * Paint)}.
- *
- * @param canvas The target canvas
- * @param text The text to be drawn
- * @param start The index of the first character in text to draw
- * @param end (end - 1) is the index of the last character in text to draw
- * @param direction The direction of the text. This must be
- * {@link android.text.Layout#DIR_LEFT_TO_RIGHT} or
- * {@link android.text.Layout#DIR_RIGHT_TO_LEFT}.
- * @param x The x-coordinate of origin for where to draw the text
- * @param top The top side of the rectangle to be drawn
- * @param y The y-coordinate of origin for where to draw the text
- * @param bottom The bottom side of the rectangle to be drawn
- * @param paint The main {@link TextPaint} object.
- * @param workPaint The {@link TextPaint} object used for temporal
- * workspace.
- * @param needWidth If true, this method returns the width of drawn text
- * @return Width of the drawn text if needWidth is true
- */
- public static float drawText(Canvas canvas,
- CharSequence text, int start, int end,
- int direction,
- float x, int top, int y, int bottom,
- TextPaint paint,
- TextPaint workPaint,
- boolean needWidth) {
- // For safety.
- direction = direction >= 0 ? Layout.DIR_LEFT_TO_RIGHT
- : Layout.DIR_RIGHT_TO_LEFT;
-
- // Hide runIsRtl parameter since it is meaningless for external
- // developers.
- // XXX: the runIsRtl probably ought to be the same as direction, then
- // this could draw rtl text.
- return drawText(canvas, text, start, end, direction, false,
- x, top, y, bottom, paint, workPaint, needWidth);
- }
-
- /**
- * Returns the width of a run of left-to-right text on a single line,
- * considering style information in the text (e.g. even when text is an
- * instance of {@link android.text.Spanned}, this method correctly measures
- * the width of the text).
- *
- * @param paint the main {@link TextPaint} object; will not be modified
- * @param workPaint the {@link TextPaint} object available for modification;
- * will not necessarily be used
- * @param text the text to measure
- * @param start the index of the first character to start measuring
- * @param end 1 beyond the index of the last character to measure
- * @param fmi FontMetrics information; can be null
- * @return The width of the text
- */
- public static float measureText(TextPaint paint,
- TextPaint workPaint,
- CharSequence text, int start, int end,
- Paint.FontMetricsInt fmi) {
- return drawDirectionalRun(null, text, start, end,
- Layout.DIR_LEFT_TO_RIGHT, false,
- 0, 0, 0, 0, fmi, paint, workPaint, true);
- }
-}
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
new file mode 100644
index 0000000..bd410c8
--- /dev/null
+++ b/core/java/android/text/TextLine.java
@@ -0,0 +1,972 @@
+/*
+ * 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.text;
+
+import com.android.internal.util.ArrayUtils;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.RectF;
+import android.graphics.Paint.FontMetricsInt;
+import android.icu.text.ArabicShaping;
+import android.text.Layout.Directions;
+import android.text.Layout.TabStops;
+import android.text.style.CharacterStyle;
+import android.text.style.MetricAffectingSpan;
+import android.text.style.ReplacementSpan;
+import android.util.Log;
+
+/**
+ * Represents a line of styled text, for measuring in visual order and
+ * for rendering.
+ *
+ * <p>Get a new instance using obtain(), and when finished with it, return it
+ * to the pool using recycle().
+ *
+ * <p>Call set to prepare the instance for use, then either draw, measure,
+ * metrics, or caretToLeftRightOf.
+ *
+ * @hide
+ */
+class TextLine {
+ private TextPaint mPaint;
+ private CharSequence mText;
+ private int mStart;
+ private int mLen;
+ private int mDir;
+ private Directions mDirections;
+ private boolean mHasTabs;
+ private TabStops mTabs;
+
+ private char[] mChars;
+ private boolean mCharsValid;
+ private Spanned mSpanned;
+ private TextPaint mWorkPaint = new TextPaint();
+ private int mPreppedIndex;
+ private int mPreppedLimit;
+
+ private static TextLine[] cached = new TextLine[3];
+
+ /**
+ * Returns a new TextLine from the shared pool.
+ *
+ * @return an uninitialized TextLine
+ */
+ static TextLine obtain() {
+ TextLine tl;
+ synchronized (cached) {
+ for (int i = cached.length; --i >= 0;) {
+ if (cached[i] != null) {
+ tl = cached[i];
+ cached[i] = null;
+ return tl;
+ }
+ }
+ }
+ tl = new TextLine();
+ Log.e("TLINE", "new: " + tl);
+ return tl;
+ }
+
+ /**
+ * Puts a TextLine back into the shared pool. Do not use this TextLine once
+ * it has been returned.
+ * @param tl the textLine
+ * @return null, as a convenience from clearing references to the provided
+ * TextLine
+ */
+ static TextLine recycle(TextLine tl) {
+ tl.mText = null;
+ tl.mPaint = null;
+ tl.mDirections = null;
+ if (tl.mLen < 250) {
+ synchronized(cached) {
+ for (int i = 0; i < cached.length; ++i) {
+ if (cached[i] == null) {
+ cached[i] = tl;
+ break;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Initializes a TextLine and prepares it for use.
+ *
+ * @param paint the base paint for the line
+ * @param text the text, can be Styled
+ * @param start the start of the line relative to the text
+ * @param limit the limit of the line relative to the text
+ * @param dir the paragraph direction of this line
+ * @param directions the directions information of this line
+ * @param hasTabs true if the line might contain tabs or emoji
+ * @param tabStops the tabStops. Can be null.
+ */
+ void set(TextPaint paint, CharSequence text, int start, int limit, int dir,
+ Directions directions, boolean hasTabs, TabStops tabStops) {
+ mPaint = paint;
+ mText = text;
+ mStart = start;
+ mLen = limit - start;
+ mDir = dir;
+ mDirections = directions;
+ mHasTabs = hasTabs;
+ mSpanned = null;
+ mPreppedIndex = 0;
+ mPreppedLimit = 0;
+
+ boolean hasReplacement = false;
+ if (text instanceof Spanned) {
+ mSpanned = (Spanned) text;
+ hasReplacement = mSpanned.getSpans(start, limit,
+ ReplacementSpan.class).length > 0;
+ }
+
+ mCharsValid = hasReplacement || hasTabs ||
+ directions != Layout.DIRS_ALL_LEFT_TO_RIGHT;
+
+ if (mCharsValid) {
+ if (mChars == null || mChars.length < mLen) {
+ mChars = new char[ArrayUtils.idealCharArraySize(mLen)];
+ }
+ TextUtils.getChars(text, start, limit, mChars, 0);
+ }
+ mTabs = tabStops;
+ }
+
+ /**
+ * Renders the TextLine.
+ *
+ * @param c the canvas to render on
+ * @param x the leading margin position
+ * @param top the top of the line
+ * @param y the baseline
+ * @param bottom the bottom of the line
+ */
+ void draw(Canvas c, float x, int top, int y, int bottom) {
+ if (!mHasTabs) {
+ if (mDirections == Layout.DIRS_ALL_LEFT_TO_RIGHT) {
+ drawRun(c, 0, 0, mLen, false, x, top, y, bottom, false);
+ return;
+ }
+ if (mDirections == Layout.DIRS_ALL_RIGHT_TO_LEFT) {
+ drawRun(c, 0, 0, mLen, true, x, top, y, bottom, false);
+ return;
+ }
+ }
+
+ float h = 0;
+ int[] runs = mDirections.mDirections;
+ RectF emojiRect = null;
+
+ int lastRunIndex = runs.length - 2;
+ for (int i = 0; i < runs.length; i += 2) {
+ int runStart = runs[i];
+ int runLimit = runStart + (runs[i+1] & Layout.RUN_LENGTH_MASK);
+ if (runLimit > mLen) {
+ runLimit = mLen;
+ }
+ boolean runIsRtl = (runs[i+1] & Layout.RUN_RTL_FLAG) != 0;
+
+ int segstart = runStart;
+ char[] chars = mChars;
+ for (int j = mHasTabs ? runStart : runLimit; j <= runLimit; j++) {
+ int codept = 0;
+ Bitmap bm = null;
+
+ if (mHasTabs && j < runLimit) {
+ codept = mChars[j];
+ if (codept >= 0xd800 && codept < 0xdc00 && j + 1 < runLimit) {
+ codept = Character.codePointAt(mChars, j);
+ if (codept >= Layout.MIN_EMOJI && codept <= Layout.MAX_EMOJI) {
+ bm = Layout.EMOJI_FACTORY.getBitmapFromAndroidPua(codept);
+ } else if (codept > 0xffff) {
+ ++j;
+ continue;
+ }
+ }
+ }
+
+ if (j == runLimit || codept == '\t' || bm != null) {
+ h += drawRun(c, i, segstart, j, runIsRtl, x+h, top, y, bottom,
+ i != lastRunIndex || j != mLen);
+
+ if (codept == '\t') {
+ h = mDir * nextTab(h * mDir);
+ } else if (bm != null) {
+ float bmAscent = ascent(j);
+ float bitmapHeight = bm.getHeight();
+ float scale = -bmAscent / bitmapHeight;
+ float width = bm.getWidth() * scale;
+
+ if (emojiRect == null) {
+ emojiRect = new RectF();
+ }
+ emojiRect.set(x + h, y + bmAscent,
+ x + h + width, y);
+ c.drawBitmap(bm, null, emojiRect, mPaint);
+ h += width;
+ j++;
+ }
+ segstart = j + 1;
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns metrics information for the entire line.
+ *
+ * @param fmi receives font metrics information, can be null
+ * @return the signed width of the line
+ */
+ float metrics(FontMetricsInt fmi) {
+ return measure(mLen, false, fmi);
+ }
+
+ /**
+ * Returns information about a position on the line.
+ *
+ * @param offset the line-relative character offset, between 0 and the
+ * line length, inclusive
+ * @param trailing true to measure the trailing edge of the character
+ * before offset, false to measure the leading edge of the character
+ * at offset.
+ * @param fmi receives metrics information about the requested
+ * character, can be null.
+ * @return the signed offset from the leading margin to the requested
+ * character edge.
+ */
+ float measure(int offset, boolean trailing, FontMetricsInt fmi) {
+ int target = trailing ? offset - 1 : offset;
+ if (target < 0) {
+ return 0;
+ }
+
+ float h = 0;
+
+ if (!mHasTabs) {
+ if (mDirections == Layout.DIRS_ALL_LEFT_TO_RIGHT) {
+ return measureRun( 0, 0, offset, mLen, false, fmi);
+ }
+ if (mDirections == Layout.DIRS_ALL_RIGHT_TO_LEFT) {
+ return measureRun(0, 0, offset, mLen, true, fmi);
+ }
+ }
+
+ char[] chars = mChars;
+ int[] runs = mDirections.mDirections;
+ for (int i = 0; i < runs.length; i += 2) {
+ int runStart = runs[i];
+ int runLimit = runStart + (runs[i+1] & Layout.RUN_LENGTH_MASK);
+ if (runLimit > mLen) {
+ runLimit = mLen;
+ }
+ boolean runIsRtl = (runs[i+1] & Layout.RUN_RTL_FLAG) != 0;
+
+ int segstart = runStart;
+ for (int j = mHasTabs ? runStart : runLimit; j <= runLimit; j++) {
+ int codept = 0;
+ Bitmap bm = null;
+
+ if (mHasTabs && j < runLimit) {
+ codept = chars[j];
+ if (codept >= 0xd800 && codept < 0xdc00 && j + 1 < runLimit) {
+ codept = Character.codePointAt(chars, j);
+ if (codept >= Layout.MIN_EMOJI && codept <= Layout.MAX_EMOJI) {
+ bm = Layout.EMOJI_FACTORY.getBitmapFromAndroidPua(codept);
+ } else if (codept > 0xffff) {
+ ++j;
+ continue;
+ }
+ }
+ }
+
+ if (j == runLimit || codept == '\t' || bm != null) {
+ boolean inSegment = target >= segstart && target < j;
+
+ boolean advance = (mDir == Layout.DIR_RIGHT_TO_LEFT) == runIsRtl;
+ if (inSegment && advance) {
+ return h += measureRun(i, segstart, offset, j, runIsRtl, fmi);
+ }
+
+ float w = measureRun(i, segstart, j, j, runIsRtl, fmi);
+ h += advance ? w : -w;
+
+ if (inSegment) {
+ return h += measureRun(i, segstart, offset, j, runIsRtl, null);
+ }
+
+ if (codept == '\t') {
+ if (offset == j) {
+ return h;
+ }
+ h = mDir * nextTab(h * mDir);
+ if (target == j) {
+ return h;
+ }
+ }
+
+ if (bm != null) {
+ float bmAscent = ascent(j);
+ float wid = bm.getWidth() * -bmAscent / bm.getHeight();
+ h += mDir * wid;
+ j++;
+ }
+
+ segstart = j + 1;
+ }
+ }
+ }
+
+ return h;
+ }
+
+ /**
+ * Draws a unidirectional (but possibly multi-styled) run of text.
+ *
+ * @param c the canvas to draw on
+ * @param runIndex the index of this directional run
+ * @param start the line-relative start
+ * @param limit the line-relative limit
+ * @param runIsRtl true if the run is right-to-left
+ * @param x the position of the run that is closest to the leading margin
+ * @param top the top of the line
+ * @param y the baseline
+ * @param bottom the bottom of the line
+ * @param needWidth true if the width value is required.
+ * @return the signed width of the run, based on the paragraph direction.
+ * Only valid if needWidth is true.
+ */
+ private float drawRun(Canvas c, int runIndex, int start,
+ int limit, boolean runIsRtl, float x, int top, int y, int bottom,
+ boolean needWidth) {
+
+ if ((mDir == Layout.DIR_LEFT_TO_RIGHT) == runIsRtl) {
+ float w = -measureRun(runIndex, start, limit, limit, runIsRtl, null);
+ handleRun(runIndex, start, limit, limit, runIsRtl, c, x + w, top,
+ y, bottom, null, false, PREP_NONE);
+ return w;
+ }
+
+ return handleRun(runIndex, start, limit, limit, runIsRtl, c, x, top,
+ y, bottom, null, needWidth, PREP_NEEDED);
+ }
+
+ /**
+ * Measures a unidirectional (but possibly multi-styled) run of text.
+ *
+ * @param runIndex the run index
+ * @param start the line-relative start of the run
+ * @param offset the offset to measure to, between start and limit inclusive
+ * @param limit the line-relative limit of the run
+ * @param runIsRtl true if the run is right-to-left
+ * @param fmi receives metrics information about the requested
+ * run, can be null.
+ * @return the signed width from the start of the run to the leading edge
+ * of the character at offset, based on the run (not paragraph) direction
+ */
+ private float measureRun(int runIndex, int start,
+ int offset, int limit, boolean runIsRtl, FontMetricsInt fmi) {
+ return handleRun(runIndex, start, offset, limit, runIsRtl, null,
+ 0, 0, 0, 0, fmi, true, PREP_NEEDED);
+ }
+
+ /**
+ * Prepares a run for measurement or rendering. This ensures that any
+ * required shaping of the text in the run has been performed so that
+ * measurements reflect the shaped text.
+ *
+ * @param runIndex the run index
+ * @param start the line-relative start of the run
+ * @param limit the line-relative limit of the run
+ * @param runIsRtl true if the run is right-to-left
+ */
+ private void prepRun(int runIndex, int start, int limit,
+ boolean runIsRtl) {
+ handleRun(runIndex, start, limit, limit, runIsRtl, null, 0, 0, 0,
+ 0, null, false, PREP_ONLY);
+ }
+
+ /**
+ * Walk the cursor through this line, skipping conjuncts and
+ * zero-width characters.
+ *
+ * <p>This function cannot properly walk the cursor off the ends of the line
+ * since it does not know about any shaping on the previous/following line
+ * that might affect the cursor position. Callers must either avoid these
+ * situations or handle the result specially.
+ *
+ * <p>The paint is required because the region around the cursor might not
+ * have been formatted yet, and the valid positions can depend on the glyphs
+ * used to render the text, which in turn depends on the paint.
+ *
+ * @param paint the base paint of the line
+ * @param cursor the starting position of the cursor, between 0 and the
+ * length of the line, inclusive
+ * @param toLeft true if the caret is moving to the left.
+ * @return the new offset. If it is less than 0 or greater than the length
+ * of the line, the previous/following line should be examined to get the
+ * actual offset.
+ */
+ int getOffsetToLeftRightOf(int cursor, boolean toLeft) {
+ // 1) The caret marks the leading edge of a character. The character
+ // logically before it might be on a different level, and the active caret
+ // position is on the character at the lower level. If that character
+ // was the previous character, the caret is on its trailing edge.
+ // 2) Take this character/edge and move it in the indicated direction.
+ // This gives you a new character and a new edge.
+ // 3) This position is between two visually adjacent characters. One of
+ // these might be at a lower level. The active position is on the
+ // character at the lower level.
+ // 4) If the active position is on the trailing edge of the character,
+ // the new caret position is the following logical character, else it
+ // is the character.
+
+ int lineStart = 0;
+ int lineEnd = mLen;
+ boolean paraIsRtl = mDir == -1;
+ int[] runs = mDirections.mDirections;
+
+ int runIndex, runLevel = 0, runStart = lineStart, runLimit = lineEnd, newCaret = -1;
+ boolean trailing = false;
+
+ if (cursor == lineStart) {
+ runIndex = -2;
+ } else if (cursor == lineEnd) {
+ runIndex = runs.length;
+ } else {
+ // First, get information about the run containing the character with
+ // the active caret.
+ for (runIndex = 0; runIndex < runs.length; runIndex += 2) {
+ runStart = lineStart + runs[runIndex];
+ if (cursor >= runStart) {
+ runLimit = runStart + (runs[runIndex+1] & Layout.RUN_LENGTH_MASK);
+ if (runLimit > lineEnd) {
+ runLimit = lineEnd;
+ }
+ if (cursor < runLimit) {
+ runLevel = (runs[runIndex+1] >>> Layout.RUN_LEVEL_SHIFT) &
+ Layout.RUN_LEVEL_MASK;
+ if (cursor == runStart) {
+ // The caret is on a run boundary, see if we should
+ // use the position on the trailing edge of the previous
+ // logical character instead.
+ int prevRunIndex, prevRunLevel, prevRunStart, prevRunLimit;
+ int pos = cursor - 1;
+ for (prevRunIndex = 0; prevRunIndex < runs.length; prevRunIndex += 2) {
+ prevRunStart = lineStart + runs[prevRunIndex];
+ if (pos >= prevRunStart) {
+ prevRunLimit = prevRunStart +
+ (runs[prevRunIndex+1] & Layout.RUN_LENGTH_MASK);
+ if (prevRunLimit > lineEnd) {
+ prevRunLimit = lineEnd;
+ }
+ if (pos < prevRunLimit) {
+ prevRunLevel = (runs[prevRunIndex+1] >>> Layout.RUN_LEVEL_SHIFT)
+ & Layout.RUN_LEVEL_MASK;
+ if (prevRunLevel < runLevel) {
+ // Start from logically previous character.
+ runIndex = prevRunIndex;
+ runLevel = prevRunLevel;
+ runStart = prevRunStart;
+ runLimit = prevRunLimit;
+ trailing = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ // caret might be == lineEnd. This is generally a space or paragraph
+ // separator and has an associated run, but might be the end of
+ // text, in which case it doesn't. If that happens, we ran off the
+ // end of the run list, and runIndex == runs.length. In this case,
+ // we are at a run boundary so we skip the below test.
+ if (runIndex != runs.length) {
+ boolean runIsRtl = (runLevel & 0x1) != 0;
+ boolean advance = toLeft == runIsRtl;
+ if (cursor != (advance ? runLimit : runStart) || advance != trailing) {
+ // Moving within or into the run, so we can move logically.
+ prepRun(runIndex, runStart, runLimit, runIsRtl);
+ newCaret = getOffsetBeforeAfter(runIndex, cursor, advance);
+ // If the new position is internal to the run, we're at the strong
+ // position already so we're finished.
+ if (newCaret != (advance ? runLimit : runStart)) {
+ return newCaret;
+ }
+ }
+ }
+ }
+
+ // If newCaret is -1, we're starting at a run boundary and crossing
+ // into another run. Otherwise we've arrived at a run boundary, and
+ // need to figure out which character to attach to. Note we might
+ // need to run this twice, if we cross a run boundary and end up at
+ // another run boundary.
+ while (true) {
+ boolean advance = toLeft == paraIsRtl;
+ int otherRunIndex = runIndex + (advance ? 2 : -2);
+ if (otherRunIndex >= 0 && otherRunIndex < runs.length) {
+ int otherRunStart = lineStart + runs[otherRunIndex];
+ int otherRunLimit = otherRunStart +
+ (runs[otherRunIndex+1] & Layout.RUN_LENGTH_MASK);
+ if (otherRunLimit > lineEnd) {
+ otherRunLimit = lineEnd;
+ }
+ int otherRunLevel = (runs[otherRunIndex+1] >>> Layout.RUN_LEVEL_SHIFT) &
+ Layout.RUN_LEVEL_MASK;
+ boolean otherRunIsRtl = (otherRunLevel & 1) != 0;
+
+ advance = toLeft == otherRunIsRtl;
+ if (newCaret == -1) {
+ prepRun(otherRunIndex, otherRunStart, otherRunLimit,
+ otherRunIsRtl);
+ newCaret = getOffsetBeforeAfter(otherRunIndex,
+ advance ? otherRunStart : otherRunLimit, advance);
+ if (newCaret == (advance ? otherRunLimit : otherRunStart)) {
+ // Crossed and ended up at a new boundary,
+ // repeat a second and final time.
+ runIndex = otherRunIndex;
+ runLevel = otherRunLevel;
+ continue;
+ }
+ break;
+ }
+
+ // The new caret is at a boundary.
+ if (otherRunLevel < runLevel) {
+ // The strong character is in the other run.
+ newCaret = advance ? otherRunStart : otherRunLimit;
+ }
+ break;
+ }
+
+ if (newCaret == -1) {
+ // We're walking off the end of the line. The paragraph
+ // level is always equal to or lower than any internal level, so
+ // the boundaries get the strong caret.
+ newCaret = getOffsetBeforeAfter(-1, cursor, advance);
+ break;
+ }
+
+ // Else we've arrived at the end of the line. That's a strong position.
+ // We might have arrived here by crossing over a run with no internal
+ // breaks and dropping out of the above loop before advancing one final
+ // time, so reset the caret.
+ // Note, we use '<=' below to handle a situation where the only run
+ // on the line is a counter-directional run. If we're not advancing,
+ // we can end up at the 'lineEnd' position but the caret we want is at
+ // the lineStart.
+ if (newCaret <= lineEnd) {
+ newCaret = advance ? lineEnd : lineStart;
+ }
+ break;
+ }
+
+ return newCaret;
+ }
+
+ /**
+ * Returns the next valid offset within this directional run, skipping
+ * conjuncts and zero-width characters. This should not be called to walk
+ * off the end of the run.
+ *
+ * @param runIndex the run index
+ * @param offset the offset
+ * @param after true if the new offset should logically follow the provided
+ * offset
+ * @return the new offset
+ */
+ private int getOffsetBeforeAfter(int runIndex, int offset, boolean after) {
+ // XXX note currently there is no special handling of zero-width
+ // combining marks, since the only analysis involves mock shaping.
+
+ boolean offEnd = offset == (after ? mLen : 0);
+ if (runIndex >= 0 && !offEnd && mCharsValid) {
+ char[] chars = mChars;
+ if (after) {
+ int cp = Character.codePointAt(chars, offset, mLen);
+ if (cp >= 0x10000) {
+ ++offset;
+ }
+ while (++offset < mLen && chars[offset] == '\ufeff'){}
+ } else {
+ while (--offset >= 0 && chars[offset] == '\ufeff'){}
+ int cp = Character.codePointBefore(chars, offset + 1);
+ if (cp >= 0x10000) {
+ --offset;
+ }
+ }
+ return offset;
+ }
+
+ if (after) {
+ return TextUtils.getOffsetAfter(mText, offset + mStart) - mStart;
+ }
+ return TextUtils.getOffsetBefore(mText, offset + mStart) - mStart;
+ }
+
+ /**
+ * Utility function for measuring and rendering text. The text must
+ * not include a tab or emoji.
+ *
+ * @param wp the working paint
+ * @param start the start of the text
+ * @param limit the limit of the text
+ * @param runIsRtl true if the run is right-to-left
+ * @param c the canvas, can be null if rendering is not needed
+ * @param x the edge of the run closest to the leading margin
+ * @param top the top of the line
+ * @param y the baseline
+ * @param bottom the bottom of the line
+ * @param fmi receives metrics information, can be null
+ * @param needWidth true if the width of the run is needed
+ * @return the signed width of the run based on the run direction; only
+ * valid if needWidth is true
+ */
+ private float handleText(TextPaint wp, int start, int limit,
+ boolean runIsRtl, Canvas c, float x, int top, int y, int bottom,
+ FontMetricsInt fmi, boolean needWidth) {
+
+ float ret = 0;
+
+ int runLen = limit - start;
+ if (needWidth || (c != null && (wp.bgColor != 0 || runIsRtl))) {
+ if (mCharsValid) {
+ ret = wp.measureText(mChars, start, runLen);
+ } else {
+ ret = wp.measureText(mText, mStart + start,
+ mStart + start + runLen);
+ }
+ }
+
+ if (fmi != null) {
+ wp.getFontMetricsInt(fmi);
+ }
+
+ if (c != null) {
+ if (runIsRtl) {
+ x -= ret;
+ }
+
+ if (wp.bgColor != 0) {
+ int color = wp.getColor();
+ Paint.Style s = wp.getStyle();
+ wp.setColor(wp.bgColor);
+ wp.setStyle(Paint.Style.FILL);
+
+ c.drawRect(x, top, x + ret, bottom, wp);
+
+ wp.setStyle(s);
+ wp.setColor(color);
+ }
+
+ drawTextRun(c, wp, start, limit, runIsRtl, x, y + wp.baselineShift);
+ }
+
+ return runIsRtl ? -ret : ret;
+ }
+
+ /**
+ * Utility function for measuring and rendering a replacement.
+ *
+ * @param replacement the replacement
+ * @param wp the work paint
+ * @param runIndex the run index
+ * @param start the start of the run
+ * @param limit the limit of the run
+ * @param runIsRtl true if the run is right-to-left
+ * @param c the canvas, can be null if not rendering
+ * @param x the edge of the replacement closest to the leading margin
+ * @param top the top of the line
+ * @param y the baseline
+ * @param bottom the bottom of the line
+ * @param fmi receives metrics information, can be null
+ * @param needWidth true if the width of the replacement is needed
+ * @param prepFlags one of PREP_NONE, PREP_REQUIRED, or PREP_ONLY
+ * @return the signed width of the run based on the run direction; only
+ * valid if needWidth is true
+ */
+ private float handleReplacement(ReplacementSpan replacement, TextPaint wp,
+ int runIndex, int start, int limit, boolean runIsRtl, Canvas c,
+ float x, int top, int y, int bottom, FontMetricsInt fmi,
+ boolean needWidth, int prepFlags) {
+
+ float ret = 0;
+
+ // Preparation replaces the first character of the series with the
+ // object-replacement character and the remainder with zero width
+ // non-break space aka BOM. Cursor movement code skips over the BOMs
+ // so that the replacement character is the only character 'seen'.
+ if (prepFlags != PREP_NONE && limit > start &&
+ (runIndex > mPreppedIndex ||
+ (runIndex == mPreppedIndex && start >= mPreppedLimit))) {
+ char[] chars = mChars;
+ chars[start] = '\ufffc';
+ for (int i = start + 1; i < limit; ++i) {
+ chars[i] = '\ufeff'; // used as ZWNBS, marks positions to skip
+ }
+ mPreppedIndex = runIndex;
+ mPreppedLimit = limit;
+ }
+
+ if (prepFlags != PREP_ONLY) {
+ int textStart = mStart + start;
+ int textLimit = mStart + limit;
+
+ if (needWidth || (c != null && runIsRtl)) {
+ ret = replacement.getSize(wp, mText, textStart, textLimit, fmi);
+ }
+
+ if (c != null) {
+ if (runIsRtl) {
+ x -= ret;
+ }
+ replacement.draw(c, mText, textStart, textLimit,
+ x, top, y, bottom, wp);
+ }
+ }
+
+ return runIsRtl ? -ret : ret;
+ }
+
+ /**
+ * Utility function for handling a unidirectional run. The run must not
+ * contain tabs or emoji but can contain styles.
+ *
+ * @param p the base paint
+ * @param runIndex the run index
+ * @param start the line-relative start of the run
+ * @param offset the offset to measure to, between start and limit inclusive
+ * @param limit the limit of the run
+ * @param runIsRtl true if the run is right-to-left
+ * @param c the canvas, can be null
+ * @param x the end of the run closest to the leading margin
+ * @param top the top of the line
+ * @param y the baseline
+ * @param bottom the bottom of the line
+ * @param fmi receives metrics information, can be null
+ * @param needWidth true if the width is required
+ * @param prepFlags one of PREP_NONE, PREP_REQUIRED, or PREP_ONLY
+ * @return the signed width of the run based on the run direction; only
+ * valid if needWidth is true
+ */
+ private float handleRun(int runIndex, int start, int offset,
+ int limit, boolean runIsRtl, Canvas c, float x, int top, int y,
+ int bottom, FontMetricsInt fmi, boolean needWidth, int prepFlags) {
+
+ // Shaping needs to take into account context up to metric boundaries,
+ // but rendering needs to take into account character style boundaries.
+ // So we iterate through metric runs, shape using the initial
+ // paint (the same typeface is used up to the next metric boundary),
+ // then within each metric run iterate through character style runs.
+ float ox = x;
+ for (int i = start, inext; i < offset; i = inext) {
+ TextPaint wp = mWorkPaint;
+ wp.set(mPaint);
+
+ int mnext;
+ if (mSpanned == null) {
+ inext = limit;
+ mnext = offset;
+ } else {
+ inext = mSpanned.nextSpanTransition(mStart + i, mStart + limit,
+ MetricAffectingSpan.class) - mStart;
+
+ mnext = inext < offset ? inext : offset;
+ MetricAffectingSpan[] spans = mSpanned.getSpans(mStart + i,
+ mStart + mnext, MetricAffectingSpan.class);
+
+ if (spans.length > 0) {
+ ReplacementSpan replacement = null;
+ for (int j = 0; j < spans.length; j++) {
+ MetricAffectingSpan span = spans[j];
+ if (span instanceof ReplacementSpan) {
+ replacement = (ReplacementSpan)span;
+ } else {
+ span.updateDrawState(wp); // XXX or measureState?
+ }
+ }
+
+ if (replacement != null) {
+ x += handleReplacement(replacement, wp, runIndex, i,
+ mnext, runIsRtl, c, x, top, y, bottom, fmi,
+ needWidth || mnext < offset, prepFlags);
+ continue;
+ }
+ }
+ }
+
+ if (prepFlags != PREP_NONE) {
+ handlePrep(wp, runIndex, i, inext, runIsRtl);
+ }
+
+ if (prepFlags != PREP_ONLY) {
+ if (mSpanned == null || c == null) {
+ x += handleText(wp, i, mnext, runIsRtl, c, x, top,
+ y, bottom, fmi, needWidth || mnext < offset);
+ } else {
+ for (int j = i, jnext; j < mnext; j = jnext) {
+ jnext = mSpanned.nextSpanTransition(mStart + j,
+ mStart + mnext, CharacterStyle.class) - mStart;
+
+ CharacterStyle[] spans = mSpanned.getSpans(mStart + j,
+ mStart + jnext, CharacterStyle.class);
+
+ wp.set(mPaint);
+ for (int k = 0; k < spans.length; k++) {
+ CharacterStyle span = spans[k];
+ span.updateDrawState(wp);
+ }
+
+ x += handleText(wp, j, jnext, runIsRtl, c, x,
+ top, y, bottom, fmi, needWidth || jnext < offset);
+ }
+ }
+ }
+ }
+
+ return x - ox;
+ }
+
+ private static final int PREP_NONE = 0;
+ private static final int PREP_NEEDED = 1;
+ private static final int PREP_ONLY = 2;
+
+ /**
+ * Prepares text for measuring or rendering.
+ *
+ * @param paint the paint used to shape the text
+ * @param runIndex the run index
+ * @param start the start of the text to prepare
+ * @param limit the limit of the text to prepare
+ * @param runIsRtl true if the run is right-to-left
+ */
+ private void handlePrep(TextPaint paint, int runIndex, int start, int limit,
+ boolean runIsRtl) {
+
+ // The current implementation 'prepares' text by manipulating the
+ // character array. In order to keep track of what ranges have
+ // already been prepared, it uses the runIndex and the limit of
+ // the prepared text within that run. This index is required
+ // since operations that prepare the text always proceed in visual
+ // order and the limit itself does not let us know which runs have
+ // been processed and which have not.
+ //
+ // This bookkeeping is an attempt to let us process a line partially,
+ // for example, by only shaping up to the cursor position. This may
+ // not make sense if we can reuse the line, say by caching repeated
+ // accesses to the same line for both measuring and drawing, since in
+ // those cases we'd always prepare the entire line. At the
+ // opposite extreme, we might shape and then immediately discard only
+ // the run of text we're working with at the moment, instead of retaining
+ // the results of shaping (as the chars array is). In this case as well
+ // we would not need to do the index/limit bookkeeping.
+ //
+ // Technically, the only reason for bookkeeping is so that we don't
+ // re-mirror already-mirrored glyphs, since the shaping and object
+ // replacement operations will not change already-processed text.
+
+ if (runIndex > mPreppedIndex ||
+ (runIndex == mPreppedIndex && start >= mPreppedLimit)) {
+ if (runIsRtl) {
+ int runLen = limit - start;
+ AndroidCharacter.mirror(mChars, start, runLen);
+ ArabicShaping.SHAPER.shape(mChars, start, runLen);
+
+ // Note: tweaked MockShaper to put '\ufeff' in place of
+ // alef when it forms lam-alef ligatures, so no extra
+ // processing is necessary here.
+ }
+ mPreppedIndex = runIndex;
+ mPreppedLimit = limit;
+ }
+ }
+
+ /**
+ * Render a text run with the set-up paint.
+ *
+ * @param c the canvas
+ * @param wp the paint used to render the text
+ * @param start the run start
+ * @param limit the run limit
+ * @param runIsRtl true if the run is right-to-left
+ * @param x the x position of the left edge of the run
+ * @param y the baseline of the run
+ */
+ private void drawTextRun(Canvas c, TextPaint wp, int start, int limit,
+ boolean runIsRtl, float x, int y) {
+
+ int flags = runIsRtl ? Canvas.DIRECTION_RTL : Canvas.DIRECTION_LTR;
+ if (mCharsValid) {
+ c.drawTextRun(mChars, start, limit - start, x, y, flags, wp);
+ } else {
+ c.drawTextRun(mText, mStart + start, mStart + limit, x, y, flags, wp);
+ }
+ }
+
+ /**
+ * Returns the ascent of the text at start. This is used for scaling
+ * emoji.
+ *
+ * @param pos the line-relative position
+ * @return the ascent of the text at start
+ */
+ float ascent(int pos) {
+ if (mSpanned == null) {
+ return mPaint.ascent();
+ }
+
+ pos += mStart;
+ MetricAffectingSpan[] spans = mSpanned.getSpans(pos, pos + 1,
+ MetricAffectingSpan.class);
+ if (spans.length == 0) {
+ return mPaint.ascent();
+ }
+
+ TextPaint wp = mWorkPaint;
+ wp.set(mPaint);
+ for (MetricAffectingSpan span : spans) {
+ span.updateMeasureState(wp);
+ }
+ return wp.ascent();
+ }
+
+ /**
+ * Returns the next tab position.
+ *
+ * @param h the (unsigned) offset from the leading margin
+ * @return the (unsigned) tab position after this offset
+ */
+ float nextTab(float h) {
+ if (mTabs != null) {
+ return mTabs.nextTab(h);
+ }
+ return TabStops.nextDefaultStop(h, TAB_INCREMENT);
+ }
+
+ private static final int TAB_INCREMENT = 20;
+}
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 9589bf3..2d6c7b6 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -17,12 +17,11 @@
package android.text;
import com.android.internal.R;
+import com.android.internal.util.ArrayUtils;
-import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.os.Parcel;
import android.os.Parcelable;
-import android.text.method.TextKeyListener.Capitalize;
import android.text.style.AbsoluteSizeSpan;
import android.text.style.AlignmentSpan;
import android.text.style.BackgroundColorSpan;
@@ -45,10 +44,8 @@
import android.text.style.UnderlineSpan;
import android.util.Printer;
-import com.android.internal.util.ArrayUtils;
-
-import java.util.regex.Pattern;
import java.util.Iterator;
+import java.util.regex.Pattern;
public class TextUtils {
private TextUtils() { /* cannot be instantiated */ }
@@ -983,7 +980,7 @@
/**
* Returns the original text if it fits in the specified width
* given the properties of the specified Paint,
- * or, if it does not fit, a copy with ellipsis character added
+ * or, if it does not fit, a copy with ellipsis character added
* at the specified edge or center.
* If <code>preserveLength</code> is specified, the returned copy
* will be padded with zero-width spaces to preserve the original
@@ -992,7 +989,7 @@
* report the start and end of the ellipsized range.
*/
public static CharSequence ellipsize(CharSequence text,
- TextPaint p,
+ TextPaint paint,
float avail, TruncateAt where,
boolean preserveLength,
EllipsizeCallback callback) {
@@ -1003,13 +1000,12 @@
int len = text.length();
- // Use Paint.breakText() for the non-Spanned case to avoid having
- // to allocate memory and accumulate the character widths ourselves.
+ MeasuredText mt = MeasuredText.obtain();
+ try {
+ float width = setPara(mt, paint, text, 0, text.length(),
+ Layout.DIR_REQUEST_DEFAULT_LTR);
- if (!(text instanceof Spanned)) {
- float wid = p.measureText(text, 0, len);
-
- if (wid <= avail) {
+ if (width <= avail) {
if (callback != null) {
callback.ellipsized(0, 0);
}
@@ -1017,250 +1013,69 @@
return text;
}
- float ellipsiswid = p.measureText(sEllipsis);
+ // XXX assumes ellipsis string does not require shaping and
+ // is unaffected by style
+ float ellipsiswid = paint.measureText(sEllipsis);
+ avail -= ellipsiswid;
- if (ellipsiswid > avail) {
- if (callback != null) {
- callback.ellipsized(0, len);
- }
-
- if (preserveLength) {
- char[] buf = obtain(len);
- for (int i = 0; i < len; i++) {
- buf[i] = '\uFEFF';
- }
- String ret = new String(buf, 0, len);
- recycle(buf);
- return ret;
- } else {
- return "";
- }
- }
-
- if (where == TruncateAt.START) {
- int fit = p.breakText(text, 0, len, false,
- avail - ellipsiswid, null);
-
- if (callback != null) {
- callback.ellipsized(0, len - fit);
- }
-
- if (preserveLength) {
- return blank(text, 0, len - fit);
- } else {
- return sEllipsis + text.toString().substring(len - fit, len);
- }
+ int left = 0;
+ int right = len;
+ if (avail < 0) {
+ // it all goes
+ } else if (where == TruncateAt.START) {
+ right = len - mt.breakText(0, len, false, avail);
} else if (where == TruncateAt.END) {
- int fit = p.breakText(text, 0, len, true,
- avail - ellipsiswid, null);
-
- if (callback != null) {
- callback.ellipsized(fit, len);
- }
-
- if (preserveLength) {
- return blank(text, fit, len);
- } else {
- return text.toString().substring(0, fit) + sEllipsis;
- }
- } else /* where == TruncateAt.MIDDLE */ {
- int right = p.breakText(text, 0, len, false,
- (avail - ellipsiswid) / 2, null);
- float used = p.measureText(text, len - right, len);
- int left = p.breakText(text, 0, len - right, true,
- avail - ellipsiswid - used, null);
-
- if (callback != null) {
- callback.ellipsized(left, len - right);
- }
-
- if (preserveLength) {
- return blank(text, left, len - right);
- } else {
- String s = text.toString();
- return s.substring(0, left) + sEllipsis +
- s.substring(len - right, len);
- }
- }
- }
-
- // But do the Spanned cases by hand, because it's such a pain
- // to iterate the span transitions backwards and getTextWidths()
- // will give us the information we need.
-
- // getTextWidths() always writes into the start of the array,
- // so measure each span into the first half and then copy the
- // results into the second half to use later.
-
- float[] wid = new float[len * 2];
- TextPaint temppaint = new TextPaint();
- Spanned sp = (Spanned) text;
-
- int next;
- for (int i = 0; i < len; i = next) {
- next = sp.nextSpanTransition(i, len, MetricAffectingSpan.class);
-
- Styled.getTextWidths(p, temppaint, sp, i, next, wid, null);
- System.arraycopy(wid, 0, wid, len + i, next - i);
- }
-
- float sum = 0;
- for (int i = 0; i < len; i++) {
- sum += wid[len + i];
- }
-
- if (sum <= avail) {
- if (callback != null) {
- callback.ellipsized(0, 0);
- }
-
- return text;
- }
-
- float ellipsiswid = p.measureText(sEllipsis);
-
- if (ellipsiswid > avail) {
- if (callback != null) {
- callback.ellipsized(0, len);
- }
-
- if (preserveLength) {
- char[] buf = obtain(len);
- for (int i = 0; i < len; i++) {
- buf[i] = '\uFEFF';
- }
- SpannableString ss = new SpannableString(new String(buf, 0, len));
- recycle(buf);
- copySpansFrom(sp, 0, len, Object.class, ss, 0);
- return ss;
+ left = mt.breakText(0, len, true, avail);
} else {
- return "";
- }
- }
-
- if (where == TruncateAt.START) {
- sum = 0;
- int i;
-
- for (i = len; i >= 0; i--) {
- float w = wid[len + i - 1];
-
- if (w + sum + ellipsiswid > avail) {
- break;
- }
-
- sum += w;
- }
-
- if (callback != null) {
- callback.ellipsized(0, i);
- }
-
- if (preserveLength) {
- SpannableString ss = new SpannableString(blank(text, 0, i));
- copySpansFrom(sp, 0, len, Object.class, ss, 0);
- return ss;
- } else {
- SpannableStringBuilder out = new SpannableStringBuilder(sEllipsis);
- out.insert(1, text, i, len);
-
- return out;
- }
- } else if (where == TruncateAt.END) {
- sum = 0;
- int i;
-
- for (i = 0; i < len; i++) {
- float w = wid[len + i];
-
- if (w + sum + ellipsiswid > avail) {
- break;
- }
-
- sum += w;
- }
-
- if (callback != null) {
- callback.ellipsized(i, len);
- }
-
- if (preserveLength) {
- SpannableString ss = new SpannableString(blank(text, i, len));
- copySpansFrom(sp, 0, len, Object.class, ss, 0);
- return ss;
- } else {
- SpannableStringBuilder out = new SpannableStringBuilder(sEllipsis);
- out.insert(0, text, 0, i);
-
- return out;
- }
- } else /* where = TruncateAt.MIDDLE */ {
- float lsum = 0, rsum = 0;
- int left = 0, right = len;
-
- float ravail = (avail - ellipsiswid) / 2;
- for (right = len; right >= 0; right--) {
- float w = wid[len + right - 1];
-
- if (w + rsum > ravail) {
- break;
- }
-
- rsum += w;
- }
-
- float lavail = avail - ellipsiswid - rsum;
- for (left = 0; left < right; left++) {
- float w = wid[len + left];
-
- if (w + lsum > lavail) {
- break;
- }
-
- lsum += w;
+ right = len - mt.breakText(0, len, false, avail / 2);
+ avail -= mt.measure(right, len);
+ left = mt.breakText(0, right, true, avail);
}
if (callback != null) {
callback.ellipsized(left, right);
}
+ char[] buf = mt.mChars;
+ Spanned sp = text instanceof Spanned ? (Spanned) text : null;
+
+ int remaining = len - (right - left);
if (preserveLength) {
- SpannableString ss = new SpannableString(blank(text, left, right));
+ if (remaining > 0) { // else eliminate the ellipsis too
+ buf[left++] = '\u2026';
+ }
+ for (int i = left; i < right; i++) {
+ buf[i] = '\uFEFF';
+ }
+ String s = new String(buf, 0, len);
+ if (sp == null) {
+ return s;
+ }
+ SpannableString ss = new SpannableString(s);
copySpansFrom(sp, 0, len, Object.class, ss, 0);
return ss;
- } else {
- SpannableStringBuilder out = new SpannableStringBuilder(sEllipsis);
- out.insert(0, text, 0, left);
- out.insert(out.length(), text, right, len);
-
- return out;
}
- }
- }
- private static String blank(CharSequence source, int start, int end) {
- int len = source.length();
- char[] buf = obtain(len);
-
- if (start != 0) {
- getChars(source, 0, start, buf, 0);
- }
- if (end != len) {
- getChars(source, end, len, buf, end);
- }
-
- if (start != end) {
- buf[start] = '\u2026';
-
- for (int i = start + 1; i < end; i++) {
- buf[i] = '\uFEFF';
+ if (remaining == 0) {
+ return "";
}
- }
-
- String ret = new String(buf, 0, len);
- recycle(buf);
- return ret;
+ if (sp == null) {
+ StringBuilder sb = new StringBuilder(remaining + sEllipsis.length());
+ sb.append(buf, 0, left);
+ sb.append(sEllipsis);
+ sb.append(buf, right, len - right);
+ return sb.toString();
+ }
+
+ SpannableStringBuilder ssb = new SpannableStringBuilder();
+ ssb.append(text, 0, left);
+ ssb.append(sEllipsis);
+ ssb.append(text, right, len);
+ return ssb;
+ } finally {
+ MeasuredText.recycle(mt);
+ }
}
/**
@@ -1278,80 +1093,121 @@
TextPaint p, float avail,
String oneMore,
String more) {
- int len = text.length();
- char[] buf = new char[len];
- TextUtils.getChars(text, 0, len, buf, 0);
- int commaCount = 0;
- for (int i = 0; i < len; i++) {
- if (buf[i] == ',') {
- commaCount++;
- }
- }
-
- float[] wid;
-
- if (text instanceof Spanned) {
- Spanned sp = (Spanned) text;
- TextPaint temppaint = new TextPaint();
- wid = new float[len * 2];
-
- int next;
- for (int i = 0; i < len; i = next) {
- next = sp.nextSpanTransition(i, len, MetricAffectingSpan.class);
-
- Styled.getTextWidths(p, temppaint, sp, i, next, wid, null);
- System.arraycopy(wid, 0, wid, len + i, next - i);
+ MeasuredText mt = MeasuredText.obtain();
+ try {
+ int len = text.length();
+ float width = setPara(mt, p, text, 0, len, Layout.DIR_REQUEST_DEFAULT_LTR);
+ if (width <= avail) {
+ return text;
}
- System.arraycopy(wid, len, wid, 0, len);
- } else {
- wid = new float[len];
- p.getTextWidths(text, 0, len, wid);
- }
+ char[] buf = mt.mChars;
- int ok = 0;
- int okRemaining = commaCount + 1;
- String okFormat = "";
-
- int w = 0;
- int count = 0;
-
- for (int i = 0; i < len; i++) {
- w += wid[i];
-
- if (buf[i] == ',') {
- count++;
-
- int remaining = commaCount - count + 1;
- float moreWid;
- String format;
-
- if (remaining == 1) {
- format = " " + oneMore;
- } else {
- format = " " + String.format(more, remaining);
- }
-
- moreWid = p.measureText(format);
-
- if (w + moreWid <= avail) {
- ok = i + 1;
- okRemaining = remaining;
- okFormat = format;
+ int commaCount = 0;
+ for (int i = 0; i < len; i++) {
+ if (buf[i] == ',') {
+ commaCount++;
}
}
- }
- if (w <= avail) {
- return text;
- } else {
+ int remaining = commaCount + 1;
+
+ int ok = 0;
+ int okRemaining = remaining;
+ String okFormat = "";
+
+ int w = 0;
+ int count = 0;
+ float[] widths = mt.mWidths;
+
+ int request = mt.mDir == 1 ? Layout.DIR_REQUEST_LTR :
+ Layout.DIR_REQUEST_RTL;
+
+ MeasuredText tempMt = MeasuredText.obtain();
+ for (int i = 0; i < len; i++) {
+ w += widths[i];
+
+ if (buf[i] == ',') {
+ count++;
+
+ String format;
+ // XXX should not insert spaces, should be part of string
+ // XXX should use plural rules and not assume English plurals
+ if (--remaining == 1) {
+ format = " " + oneMore;
+ } else {
+ format = " " + String.format(more, remaining);
+ }
+
+ // XXX this is probably ok, but need to look at it more
+ tempMt.setPara(format, 0, format.length(), request);
+ float moreWid = mt.addStyleRun(p, mt.mLen, null);
+
+ if (w + moreWid <= avail) {
+ ok = i + 1;
+ okRemaining = remaining;
+ okFormat = format;
+ }
+ }
+ }
+ MeasuredText.recycle(tempMt);
+
SpannableStringBuilder out = new SpannableStringBuilder(okFormat);
out.insert(0, text, 0, ok);
return out;
+ } finally {
+ MeasuredText.recycle(mt);
}
}
+ private static float setPara(MeasuredText mt, TextPaint paint,
+ CharSequence text, int start, int end, int bidiRequest) {
+
+ mt.setPara(text, start, end, bidiRequest);
+
+ float width;
+ Spanned sp = text instanceof Spanned ? (Spanned) text : null;
+ int len = end - start;
+ if (sp == null) {
+ width = mt.addStyleRun(paint, len, null);
+ } else {
+ width = 0;
+ int spanEnd;
+ for (int spanStart = 0; spanStart < len; spanStart = spanEnd) {
+ spanEnd = sp.nextSpanTransition(spanStart, len,
+ MetricAffectingSpan.class);
+ MetricAffectingSpan[] spans = sp.getSpans(
+ spanStart, spanEnd, MetricAffectingSpan.class);
+ width += mt.addStyleRun(paint, spans, spanEnd - spanStart, null);
+ }
+ }
+
+ return width;
+ }
+
+ private static final char FIRST_RIGHT_TO_LEFT = '\u0590';
+
+ /* package */
+ static boolean doesNotNeedBidi(CharSequence s, int start, int end) {
+ for (int i = start; i < end; i++) {
+ if (s.charAt(i) >= FIRST_RIGHT_TO_LEFT) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /* package */
+ static boolean doesNotNeedBidi(char[] text, int start, int len) {
+ for (int i = start, e = i + len; i < e; i++) {
+ if (text[i] >= FIRST_RIGHT_TO_LEFT) {
+ return false;
+ }
+ }
+ return true;
+ }
+
/* package */ static char[] obtain(int len) {
char[] buf;
@@ -1529,7 +1385,7 @@
*/
public static final int CAP_MODE_CHARACTERS
= InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS;
-
+
/**
* Capitalization mode for {@link #getCapsMode}: capitalize the first
* character of all words. This value is explicitly defined to be the same as
@@ -1537,7 +1393,7 @@
*/
public static final int CAP_MODE_WORDS
= InputType.TYPE_TEXT_FLAG_CAP_WORDS;
-
+
/**
* Capitalization mode for {@link #getCapsMode}: capitalize the first
* character of each sentence. This value is explicitly defined to be the same as
@@ -1545,13 +1401,13 @@
*/
public static final int CAP_MODE_SENTENCES
= InputType.TYPE_TEXT_FLAG_CAP_SENTENCES;
-
+
/**
* Determine what caps mode should be in effect at the current offset in
* the text. Only the mode bits set in <var>reqModes</var> will be
* checked. Note that the caps mode flags here are explicitly defined
* to match those in {@link InputType}.
- *
+ *
* @param cs The text that should be checked for caps modes.
* @param off Location in the text at which to check.
* @param reqModes The modes to be checked: may be any combination of
@@ -1651,7 +1507,7 @@
return mode;
}
-
+
private static Object sLock = new Object();
private static char[] sTemp = null;
}
diff --git a/core/java/android/text/method/Touch.java b/core/java/android/text/method/Touch.java
index 42ad10e..c30db20 100644
--- a/core/java/android/text/method/Touch.java
+++ b/core/java/android/text/method/Touch.java
@@ -18,13 +18,12 @@
import android.text.Layout;
import android.text.NoCopySpan;
-import android.text.Layout.Alignment;
import android.text.Spannable;
-import android.util.Log;
+import android.text.Layout.Alignment;
+import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import android.widget.TextView;
-import android.view.KeyEvent;
public class Touch {
private Touch() { }
@@ -45,6 +44,7 @@
int left = Integer.MAX_VALUE;
int right = 0;
Alignment a = null;
+ boolean ltr = true;
for (int i = top; i <= bottom; i++) {
left = (int) Math.min(left, layout.getLineLeft(i));
@@ -52,6 +52,7 @@
if (a == null) {
a = layout.getParagraphAlignment(i);
+ ltr = layout.getParagraphDirection(i) > 0;
}
}
@@ -59,10 +60,12 @@
int width = widget.getWidth();
int diff = 0;
+ // align_opposite does NOT mean align_right, we need the paragraph
+ // direction to resolve it to left or right
if (right - left < width - padding) {
if (a == Alignment.ALIGN_CENTER) {
diff = (width - padding - (right - left)) / 2;
- } else if (a == Alignment.ALIGN_OPPOSITE) {
+ } else if (ltr == (a == Alignment.ALIGN_OPPOSITE)) {
diff = width - padding - (right - left);
}
}
diff --git a/core/java/android/util/CharsetUtils.java b/core/java/android/util/CharsetUtils.java
index 9d91aca..a763a69 100644
--- a/core/java/android/util/CharsetUtils.java
+++ b/core/java/android/util/CharsetUtils.java
@@ -17,36 +17,58 @@
package android.util;
import android.os.Build;
+import android.text.TextUtils;
import java.nio.charset.Charset;
import java.nio.charset.IllegalCharsetNameException;
import java.nio.charset.UnsupportedCharsetException;
+import java.util.HashMap;
+import java.util.Map;
/**
+ * <p>
* A class containing utility methods related to character sets. This
* class is primarily useful for code that wishes to be vendor-aware
- * in its interpretation of Japanese encoding names.
- *
- * <p>As of this writing, the only vendor that is recognized by this
- * class is Docomo (identified case-insensitively as {@code "docomo"}).</p>
- *
- * <b>Note:</b> This class is hidden in Cupcake, with a plan to
- * un-hide in Donut. This was done because the first deployment to use
- * this code is based on Cupcake, but the API had to be introduced
- * after the public API freeze for that release. The upshot is that
- * only system applications can safely use this class until Donut is
- * available.
- *
+ * in its interpretation of Japanese charset names (used in DoCoMo,
+ * KDDI, and SoftBank).
+ * </p>
+ *
+ * <p>
+ * <b>Note:</b> Developers will need to add an appropriate mapping for
+ * each vendor-specific charset. You may need to modify the C libraries
+ * like icu4c in order to let Android support an additional charset.
+ * </p>
+ *
* @hide
*/
public final class CharsetUtils {
/**
- * name of the vendor "Docomo". <b>Note:</b> This isn't a public
+ * name of the vendor "DoCoMo". <b>Note:</b> This isn't a public
* constant, in order to keep this class from becoming a de facto
* reference list of vendor names.
*/
private static final String VENDOR_DOCOMO = "docomo";
-
+ /**
+ * Name of the vendor "KDDI".
+ */
+ private static final String VENDOR_KDDI = "kddi";
+ /**
+ * Name of the vendor "SoftBank".
+ */
+ private static final String VENDOR_SOFTBANK = "softbank";
+
+ /**
+ * Represents one-to-one mapping from a vendor name to a charset specific to the vendor.
+ */
+ private static final Map<String, String> sVendorShiftJisMap = new HashMap<String, String>();
+
+ static {
+ // These variants of Shift_JIS come from icu's mapping data (convrtrs.txt)
+ sVendorShiftJisMap.put(VENDOR_DOCOMO, "docomo-shift_jis-2007");
+ sVendorShiftJisMap.put(VENDOR_KDDI, "kddi-shift_jis-2007");
+ sVendorShiftJisMap.put(VENDOR_SOFTBANK, "softbank-shift_jis-2007");
+ }
+
/**
* This class is uninstantiable.
*/
@@ -58,20 +80,22 @@
* Returns the name of the vendor-specific character set
* corresponding to the given original character set name and
* vendor. If there is no vendor-specific character set for the
- * given name/vendor pair, this returns the original character set
- * name. The vendor name is matched case-insensitively.
- *
+ * given name/vendor pair, this returns the original character set name.
+ *
* @param charsetName the base character set name
- * @param vendor the vendor to specialize for
+ * @param vendor the vendor to specialize for. All characters should be lower-cased.
* @return the specialized character set name, or {@code charsetName} if
* there is no specialized name
*/
public static String nameForVendor(String charsetName, String vendor) {
- // TODO: Eventually, this may want to be table-driven.
-
- if (vendor.equalsIgnoreCase(VENDOR_DOCOMO)
- && isShiftJis(charsetName)) {
- return "docomo-shift_jis-2007";
+ if (!TextUtils.isEmpty(charsetName) && !TextUtils.isEmpty(vendor)) {
+ // You can add your own mapping here.
+ if (isShiftJis(charsetName)) {
+ final String vendorShiftJis = sVendorShiftJisMap.get(vendor);
+ if (vendorShiftJis != null) {
+ return vendorShiftJis;
+ }
+ }
}
return charsetName;
diff --git a/core/java/android/util/Patterns.java b/core/java/android/util/Patterns.java
index 5cbfd29..3bcd266 100644
--- a/core/java/android/util/Patterns.java
+++ b/core/java/android/util/Patterns.java
@@ -25,7 +25,7 @@
public class Patterns {
/**
* Regular expression to match all IANA top-level domains.
- * List accurate as of 2010/02/05. List taken from:
+ * List accurate as of 2010/05/06. List taken from:
* http://data.iana.org/TLD/tlds-alpha-by-domain.txt
* This pattern is auto-generated by frameworks/base/common/tools/make-iana-tld-pattern.py
*/
@@ -53,8 +53,8 @@
+ "|u[agksyz]"
+ "|v[aceginu]"
+ "|w[fs]"
- + "|(xn\\-\\-0zwm56d|xn\\-\\-11b5bs3a9aj6g|xn\\-\\-80akhbyknj4f|xn\\-\\-9t4b11yi5a|xn\\-\\-deba0ad|xn\\-\\-g6w251d|xn\\-\\-hgbk6aj7f53bba|xn\\-\\-hlcj6aya9esc7a|xn\\-\\-jxalpdlp|xn\\-\\-kgbechtv|xn\\-\\-zckzah)"
- + "|y[etu]"
+ + "|(xn\\-\\-0zwm56d|xn\\-\\-11b5bs3a9aj6g|xn\\-\\-80akhbyknj4f|xn\\-\\-9t4b11yi5a|xn\\-\\-deba0ad|xn\\-\\-g6w251d|xn\\-\\-hgbk6aj7f53bba|xn\\-\\-hlcj6aya9esc7a|xn\\-\\-jxalpdlp|xn\\-\\-kgbechtv|xn\\-\\-mgbaam7a8h|xn\\-\\-mgberp4a5d4ar|xn\\-\\-wgbh1c|xn\\-\\-zckzah)"
+ + "|y[et]"
+ "|z[amw])";
/**
@@ -65,7 +65,7 @@
/**
* Regular expression to match all IANA top-level domains for WEB_URL.
- * List accurate as of 2010/02/05. List taken from:
+ * List accurate as of 2010/05/06. List taken from:
* http://data.iana.org/TLD/tlds-alpha-by-domain.txt
* This pattern is auto-generated by frameworks/base/common/tools/make-iana-tld-pattern.py
*/
@@ -94,8 +94,8 @@
+ "|u[agksyz]"
+ "|v[aceginu]"
+ "|w[fs]"
- + "|(?:xn\\-\\-0zwm56d|xn\\-\\-11b5bs3a9aj6g|xn\\-\\-80akhbyknj4f|xn\\-\\-9t4b11yi5a|xn\\-\\-deba0ad|xn\\-\\-g6w251d|xn\\-\\-hgbk6aj7f53bba|xn\\-\\-hlcj6aya9esc7a|xn\\-\\-jxalpdlp|xn\\-\\-kgbechtv|xn\\-\\-zckzah)"
- + "|y[etu]"
+ + "|(?:xn\\-\\-0zwm56d|xn\\-\\-11b5bs3a9aj6g|xn\\-\\-80akhbyknj4f|xn\\-\\-9t4b11yi5a|xn\\-\\-deba0ad|xn\\-\\-g6w251d|xn\\-\\-hgbk6aj7f53bba|xn\\-\\-hlcj6aya9esc7a|xn\\-\\-jxalpdlp|xn\\-\\-kgbechtv|xn\\-\\-mgbaam7a8h|xn\\-\\-mgberp4a5d4ar|xn\\-\\-wgbh1c|xn\\-\\-zckzah)"
+ + "|y[et]"
+ "|z[amw]))";
/**
diff --git a/core/java/android/view/ActionBarView.java b/core/java/android/view/ActionBarView.java
new file mode 100644
index 0000000..3ed345e4
--- /dev/null
+++ b/core/java/android/view/ActionBarView.java
@@ -0,0 +1,702 @@
+/*
+ * 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.view;
+
+import java.util.ArrayList;
+
+import android.app.ActionBar;
+import android.app.Activity;
+import android.app.ActionBar.Callback;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.res.TypedArray;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.SparseArray;
+import android.widget.AdapterView;
+import android.widget.ImageView;
+import android.widget.Spinner;
+import android.widget.SpinnerAdapter;
+import android.widget.TextView;
+
+import com.android.internal.R;
+import com.android.internal.view.menu.ActionMenu;
+import com.android.internal.view.menu.ActionMenuItem;
+
+/**
+ * @hide
+ */
+public class ActionBarView extends ViewGroup {
+ private static final String TAG = "ActionBarView";
+
+ // TODO: This must be defined in the default theme
+ private static final int CONTENT_HEIGHT_DIP = 50;
+ private static final int CONTENT_PADDING_DIP = 3;
+ private static final int CONTENT_SPACING_DIP = 6;
+ private static final int CONTENT_ACTION_SPACING_DIP = 12;
+
+ /**
+ * Display options applied by default
+ */
+ public static final int DISPLAY_DEFAULT = 0;
+
+ /**
+ * Display options that require re-layout as opposed to a simple invalidate
+ */
+ private static final int DISPLAY_RELAYOUT_MASK =
+ ActionBar.DISPLAY_HIDE_HOME |
+ ActionBar.DISPLAY_USE_LOGO;
+
+ private final int mContentHeight;
+
+ private int mNavigationMode;
+ private int mDisplayOptions;
+ private int mSpacing;
+ private int mActionSpacing;
+ private CharSequence mTitle;
+ private CharSequence mSubtitle;
+ private Drawable mIcon;
+ private Drawable mLogo;
+ private Drawable mDivider;
+
+ private ImageView mIconView;
+ private ImageView mLogoView;
+ private TextView mTitleView;
+ private TextView mSubtitleView;
+ private Spinner mSpinner;
+ private View mCustomNavView;
+
+ private boolean mShowMenu;
+
+ private ActionMenuItem mLogoNavItem;
+ private ActionMenu mActionMenu;
+ private ActionMenu mOptionsMenu;
+
+ private SparseArray<ActionMenu> mContextMenus;
+
+ private Callback mCallback;
+
+ private final ArrayList<ActionView> mActions = new ArrayList<ActionView>();
+ private final OnClickListener mActionClickHandler = new OnClickListener() {
+ public void onClick(View v) {
+ ActionView av = (ActionView) v;
+ ActionMenuItem item = (ActionMenuItem) av.menuItem;
+
+ if (mCallback == null || !mCallback.onActionItemClicked(item)) {
+ item.invoke();
+ }
+ }
+ };
+
+ private final AdapterView.OnItemSelectedListener mNavItemSelectedListener =
+ new AdapterView.OnItemSelectedListener() {
+ public void onItemSelected(AdapterView parent, View view, int position, long id) {
+ if (mCallback != null) {
+ mCallback.onNavigationItemSelected(position, id);
+ }
+ }
+ public void onNothingSelected(AdapterView parent) {
+ // Do nothing
+ }
+ };
+
+ private OnClickListener mHomeClickListener = null;
+
+ public ActionBarView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+
+ final DisplayMetrics metrics = context.getResources().getDisplayMetrics();
+ mContentHeight = (int) (CONTENT_HEIGHT_DIP * metrics.density + 0.5f);
+
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ActionBar);
+
+ final int colorFilter = a.getColor(R.styleable.ActionBar_colorFilter, 0);
+
+ if (colorFilter != 0) {
+ final Drawable d = getBackground();
+ d.setDither(true);
+ d.setColorFilter(new PorterDuffColorFilter(colorFilter, PorterDuff.Mode.OVERLAY));
+ }
+
+ ApplicationInfo info = context.getApplicationInfo();
+ PackageManager pm = context.getPackageManager();
+ mNavigationMode = a.getInt(R.styleable.ActionBar_navigationMode, ActionBar.NAVIGATION_MODE_STANDARD);
+ mTitle = a.getText(R.styleable.ActionBar_title);
+ mSubtitle = a.getText(R.styleable.ActionBar_subtitle);
+ mDisplayOptions = a.getInt(R.styleable.ActionBar_displayOptions, DISPLAY_DEFAULT);
+
+ mLogo = a.getDrawable(R.styleable.ActionBar_logo);
+ if (mLogo == null) {
+ mLogo = info.loadLogo(pm);
+ }
+ mIcon = a.getDrawable(R.styleable.ActionBar_icon);
+ if (mIcon == null) {
+ mIcon = info.loadIcon(pm);
+ }
+ mDivider = a.getDrawable(R.styleable.ActionBar_divider);
+
+ Drawable background = a.getDrawable(R.styleable.ActionBar_background);
+ if (background != null) {
+ setBackgroundDrawable(background);
+ }
+
+ final int customNavId = a.getResourceId(R.styleable.ActionBar_customNavigationLayout, 0);
+ if (customNavId != 0) {
+ LayoutInflater inflater = LayoutInflater.from(context);
+ mCustomNavView = (View) inflater.inflate(customNavId, null);
+ mNavigationMode = ActionBar.NAVIGATION_MODE_CUSTOM;
+ }
+
+ a.recycle();
+
+ // TODO: Set this in the theme
+ int padding = (int) (CONTENT_PADDING_DIP * metrics.density + 0.5f);
+ setPadding(padding, padding, padding, padding);
+
+ mSpacing = (int) (CONTENT_SPACING_DIP * metrics.density + 0.5f);
+ mActionSpacing = (int) (CONTENT_ACTION_SPACING_DIP * metrics.density + 0.5f);
+
+ if (mLogo != null || mIcon != null || mTitle != null) {
+ mLogoNavItem = new ActionMenuItem(context, 0, android.R.id.home, 0, 0, mTitle);
+ mHomeClickListener = new OnClickListener() {
+ public void onClick(View v) {
+ if (mCallback != null) {
+ mCallback.onActionItemClicked(mLogoNavItem);
+ }
+ }
+ };
+ }
+
+ mContextMenus = new SparseArray<ActionMenu>();
+ }
+
+ private boolean initOptionsMenu() {
+ final Context context = getContext();
+ if (!(context instanceof Activity)) {
+ return false;
+ }
+
+ final Activity activity = (Activity) context;
+ ActionMenu optionsMenu = new ActionMenu(context);
+ if (activity.onCreateOptionsMenu(optionsMenu)) {
+ mOptionsMenu = optionsMenu;
+ return true;
+ }
+
+ return false;
+ }
+
+ public void setCallback(Callback callback) {
+ final Context context = getContext();
+ mCallback = callback;
+
+ ActionMenu actionMenu = new ActionMenu(context);
+ if (callback.onCreateActionMenu(actionMenu)) {
+ mActionMenu = actionMenu;
+ performUpdateActionMenu();
+ }
+ }
+
+ public void setCustomNavigationView(View view) {
+ mCustomNavView = view;
+ if (view != null) {
+ setNavigationMode(ActionBar.NAVIGATION_MODE_CUSTOM);
+ }
+ }
+
+ public void setDividerDrawable(Drawable d) {
+ mDivider = d;
+ }
+
+ public CharSequence getTitle() {
+ return mTitle;
+ }
+
+ public void setTitle(CharSequence title) {
+ mTitle = title;
+ if (mTitleView != null) {
+ mTitleView.setText(title);
+ }
+ if (mLogoNavItem != null) {
+ mLogoNavItem.setTitle(title);
+ }
+ }
+
+ public CharSequence getSubtitle() {
+ return mSubtitle;
+ }
+
+ public void setSubtitle(CharSequence subtitle) {
+ mSubtitle = subtitle;
+ if (mSubtitleView != null) {
+ mSubtitleView.setText(subtitle);
+ }
+ }
+
+ public void setDisplayOptions(int options) {
+ final int flagsChanged = options ^ mDisplayOptions;
+ mDisplayOptions = options;
+ if ((flagsChanged & DISPLAY_RELAYOUT_MASK) != 0) {
+ final int vis = (options & ActionBar.DISPLAY_HIDE_HOME) != 0 ? GONE : VISIBLE;
+ if (mLogoView != null) {
+ mLogoView.setVisibility(vis);
+ }
+ if (mIconView != null) {
+ mIconView.setVisibility(vis);
+ }
+
+ requestLayout();
+ } else {
+ invalidate();
+ }
+ }
+
+ public void setNavigationMode(int mode) {
+ final int oldMode = mNavigationMode;
+ if (mode != oldMode) {
+ switch (oldMode) {
+ case ActionBar.NAVIGATION_MODE_STANDARD:
+ if (mTitleView != null) {
+ removeView(mTitleView);
+ mTitleView = null;
+ }
+ break;
+ case ActionBar.NAVIGATION_MODE_DROPDOWN_LIST:
+ if (mSpinner != null) {
+ removeView(mSpinner);
+ mSpinner = null;
+ }
+ break;
+ case ActionBar.NAVIGATION_MODE_CUSTOM:
+ if (mCustomNavView != null) {
+ removeView(mCustomNavView);
+ mCustomNavView = null;
+ }
+ break;
+ }
+
+ switch (mode) {
+ case ActionBar.NAVIGATION_MODE_STANDARD:
+ initTitle();
+ break;
+ case ActionBar.NAVIGATION_MODE_DROPDOWN_LIST:
+ mSpinner = new Spinner(mContext, null,
+ com.android.internal.R.attr.dropDownSpinnerStyle);
+ mSpinner.setOnItemSelectedListener(mNavItemSelectedListener);
+ addView(mSpinner);
+ break;
+ case ActionBar.NAVIGATION_MODE_CUSTOM:
+ addView(mCustomNavView);
+ break;
+ }
+ mNavigationMode = mode;
+ requestLayout();
+ }
+ }
+
+ public void setDropdownAdapter(SpinnerAdapter adapter) {
+ mSpinner.setAdapter(adapter);
+ }
+
+ public View getCustomNavigationView() {
+ return mCustomNavView;
+ }
+
+ public int getNavigationMode() {
+ return mNavigationMode;
+ }
+
+ public int getDisplayOptions() {
+ return mDisplayOptions;
+ }
+
+ private ActionView findActionViewForItem(MenuItem item) {
+ final ArrayList<ActionView> actions = mActions;
+ final int actionCount = actions.size();
+ for (int i = 0; i < actionCount; i++) {
+ ActionView av = actions.get(i);
+ if (av.menuItem.equals(item)) {
+ return av;
+ }
+ }
+ return null;
+ }
+
+ public void setContextMode(int mode) {
+ Callback callback = mCallback;
+ if (callback == null) {
+ throw new IllegalStateException(
+ "Attempted to set ActionBar context mode with no callback");
+ }
+
+ ActionMenu menu = mContextMenus.get(mode);
+ if (menu == null) {
+ // Initialize the new mode
+ menu = new ActionMenu(getContext());
+
+ if (!callback.onCreateContextMode(mode, menu)) {
+ throw new IllegalArgumentException(
+ "ActionBar callback does not know how to create context mode " + mode);
+ }
+ mContextMenus.put(mode, menu);
+ }
+
+ if (callback.onPrepareContextMode(mode, menu)) {
+ // TODO Set mode, animate, etc.
+ }
+ }
+
+ public void exitContextMode() {
+ // TODO Turn off context mode; go back to normal.
+ }
+
+ public void updateActionMenu() {
+ final ActionMenu menu = mActionMenu;
+ if (menu == null || mCallback == null || !mCallback.onUpdateActionMenu(menu)) {
+ return;
+ }
+ performUpdateActionMenu();
+ }
+
+ private void performUpdateActionMenu() {
+ final ActionMenu menu = mActionMenu;
+ if (menu == null) {
+ return;
+ }
+ final Context context = getContext();
+
+ int childCount = getChildCount();
+ int childIndex = 0;
+ while (childIndex < childCount) {
+ View v = getChildAt(childIndex);
+ if (v instanceof ActionView) {
+ detachViewFromParent(childIndex);
+ childCount--;
+ } else {
+ childIndex++;
+ }
+ }
+
+ ArrayList<ActionView> detachedViews = new ArrayList<ActionView>(mActions);
+ final int itemCount = menu.size();
+ for (int i = 0; i < itemCount; i++) {
+ final MenuItem item = menu.getItem(i);
+
+ boolean newView = false;
+ ActionView actionView = findActionViewForItem(item);
+ if (actionView == null) {
+ actionView = new ActionView(context);
+ newView = true;
+ }
+ actionView.actionId = item.getItemId();
+ actionView.menuItem = item;
+ actionView.actionLabel = item.getTitle();
+ actionView.setAdjustViewBounds(true);
+ actionView.setImageDrawable(item.getIcon());
+ actionView.setFocusable(true);
+ actionView.setOnClickListener(mActionClickHandler);
+
+ LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
+ LayoutParams.MATCH_PARENT, LayoutParams.ITEM_TYPE_ACTION);
+ actionView.setLayoutParams(layoutParams);
+
+ if (newView) {
+ addView(actionView);
+ mActions.add(actionView);
+ } else {
+ attachViewToParent(actionView, -1, layoutParams);
+ detachedViews.remove(actionView);
+ actionView.invalidate();
+ }
+ }
+
+ final int detachedCount = detachedViews.size();
+ for (int i = 0; i < detachedCount; i++) {
+ removeDetachedView(detachedViews.get(i), false);
+ }
+
+ requestLayout();
+ }
+
+ public void addAction(int id, Drawable icon, CharSequence label, OnActionListener listener) {
+ ActionView actionView = new ActionView(getContext());
+ actionView.actionId = id;
+ actionView.actionLabel = label;
+ actionView.actionListener = listener;
+ actionView.setAdjustViewBounds(true);
+ actionView.setImageDrawable(icon);
+ actionView.setOnClickListener(mActionClickHandler);
+
+ actionView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
+ LayoutParams.MATCH_PARENT, LayoutParams.ITEM_TYPE_ACTION));
+
+ addView(actionView);
+ mActions.add(actionView);
+
+ requestLayout();
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+
+ if ((mDisplayOptions & ActionBar.DISPLAY_HIDE_HOME) == 0) {
+ if (mLogo != null && (mDisplayOptions & ActionBar.DISPLAY_USE_LOGO) != 0) {
+ mLogoView = new ImageView(getContext());
+ mLogoView.setAdjustViewBounds(true);
+ mLogoView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
+ LayoutParams.MATCH_PARENT, LayoutParams.ITEM_TYPE_ICON));
+ mLogoView.setImageDrawable(mLogo);
+ mLogoView.setClickable(true);
+ mLogoView.setFocusable(true);
+ mLogoView.setOnClickListener(mHomeClickListener);
+ addView(mLogoView);
+ } else if (mIcon != null) {
+ mIconView = new ImageView(getContext());
+ mIconView.setAdjustViewBounds(true);
+ mIconView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
+ LayoutParams.MATCH_PARENT, LayoutParams.ITEM_TYPE_ICON));
+ mIconView.setImageDrawable(mIcon);
+ mIconView.setClickable(true);
+ mIconView.setFocusable(true);
+ mIconView.setOnClickListener(mHomeClickListener);
+ addView(mIconView);
+ }
+ }
+
+ switch (mNavigationMode) {
+ case ActionBar.NAVIGATION_MODE_STANDARD:
+ if (mLogoView == null) {
+ initTitle();
+ }
+ break;
+
+ case ActionBar.NAVIGATION_MODE_DROPDOWN_LIST:
+ throw new UnsupportedOperationException(
+ "Inflating dropdown list navigation isn't supported yet!");
+
+ case ActionBar.NAVIGATION_MODE_TABS:
+ throw new UnsupportedOperationException(
+ "Tab navigation isn't supported yet!");
+
+ case ActionBar.NAVIGATION_MODE_CUSTOM:
+ if (mCustomNavView != null) {
+ addView(mCustomNavView);
+ }
+ break;
+ }
+ }
+
+ private void initTitle() {
+ LayoutInflater inflater = LayoutInflater.from(getContext());
+ mTitleView = (TextView) inflater.inflate(R.layout.action_bar_title_item, null);
+ mTitleView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
+ LayoutParams.WRAP_CONTENT, LayoutParams.ITEM_TYPE_TITLE));
+ if (mTitle != null) {
+ mTitleView.setText(mTitle);
+ }
+ addView(mTitleView);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+ if (widthMode != MeasureSpec.EXACTLY) {
+ throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
+ "with android:layout_width=\"match_parent\" (or fill_parent)");
+ }
+
+ int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+ if (heightMode != MeasureSpec.AT_MOST) {
+ throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
+ "with android:layout_height=\"wrap_content\"");
+ }
+
+ int contentWidth = MeasureSpec.getSize(widthMeasureSpec);
+
+ int availableWidth = contentWidth - getPaddingLeft() - getPaddingRight();
+ final int height = mContentHeight - getPaddingTop() - getPaddingBottom();
+ final int childSpecHeight = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
+
+ if (mLogoView != null && mLogoView.getVisibility() != GONE) {
+ availableWidth = measureChildView(mLogoView, availableWidth, childSpecHeight, mSpacing);
+ }
+ if (mIconView != null && mIconView.getVisibility() != GONE) {
+ availableWidth = measureChildView(mIconView, availableWidth, childSpecHeight, mSpacing);
+ }
+
+ final ArrayList<ActionView> actions = mActions;
+ final int actionCount = actions.size();
+ for (int i = 0; i < actionCount; i++) {
+ ActionView action = actions.get(i);
+ availableWidth = measureChildView(action, availableWidth,
+ childSpecHeight, mActionSpacing);
+ }
+
+ switch (mNavigationMode) {
+ case ActionBar.NAVIGATION_MODE_STANDARD:
+ if (mTitleView != null) {
+ measureChildView(mTitleView, availableWidth, childSpecHeight, mSpacing);
+ }
+ break;
+ case ActionBar.NAVIGATION_MODE_DROPDOWN_LIST:
+ if (mSpinner != null) {
+ mSpinner.measure(
+ MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
+ }
+ break;
+ case ActionBar.NAVIGATION_MODE_CUSTOM:
+ if (mCustomNavView != null) {
+ mCustomNavView.measure(
+ MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
+ }
+ break;
+ }
+
+ setMeasuredDimension(contentWidth, mContentHeight);
+ }
+
+ private int measureChildView(View child, int availableWidth, int childSpecHeight, int spacing) {
+ child.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST),
+ childSpecHeight);
+
+ availableWidth -= child.getMeasuredWidth();
+ availableWidth -= spacing;
+
+ return availableWidth;
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ int x = getPaddingLeft();
+ final int y = getPaddingTop();
+ final int contentHeight = b - t - getPaddingTop() - getPaddingBottom();
+
+ if (mLogoView != null && mLogoView.getVisibility() != GONE) {
+ x += positionChild(mLogoView, x, y, contentHeight) + mSpacing;
+ }
+ if (mIconView != null && mIconView.getVisibility() != GONE) {
+ x += positionChild(mIconView, x, y, contentHeight) + mSpacing;
+ }
+
+ switch (mNavigationMode) {
+ case ActionBar.NAVIGATION_MODE_STANDARD:
+ if (mTitleView != null) {
+ x += positionChild(mTitleView, x, y, contentHeight) + mSpacing;
+ }
+ break;
+ case ActionBar.NAVIGATION_MODE_DROPDOWN_LIST:
+ if (mSpinner != null) {
+ x += positionChild(mSpinner, x, y, contentHeight) + mSpacing;
+ }
+ break;
+ case ActionBar.NAVIGATION_MODE_CUSTOM:
+ if (mCustomNavView != null) {
+ x += positionChild(mCustomNavView, x, y, contentHeight) + mSpacing;
+ }
+ break;
+ }
+
+ x = r - l - getPaddingRight();
+
+ final int count = mActions.size();
+ for (int i = count - 1; i >= 0; i--) {
+ ActionView action = mActions.get(i);
+ x -= (positionChildInverse(action, x, y, contentHeight) + mActionSpacing);
+ }
+ }
+
+ private int positionChild(View child, int x, int y, int contentHeight) {
+ int childWidth = child.getMeasuredWidth();
+ int childHeight = child.getMeasuredHeight();
+ int childTop = y + (contentHeight - childHeight) / 2;
+
+ child.layout(x, childTop, x + childWidth, childTop + childHeight);
+
+ return childWidth;
+ }
+
+ private int positionChildInverse(View child, int x, int y, int contentHeight) {
+ int childWidth = child.getMeasuredWidth();
+ int childHeight = child.getMeasuredHeight();
+ int childTop = y + (contentHeight - childHeight) / 2;
+
+ child.layout(x - childWidth, childTop, x, childTop + childHeight);
+
+ return childWidth;
+ }
+
+ @Override
+ public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
+ return new ViewGroup.LayoutParams(getContext(), attrs);
+ }
+
+ @Override
+ protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
+ return p != null && p instanceof LayoutParams;
+ }
+
+ private static class LayoutParams extends ViewGroup.LayoutParams {
+ static final int ITEM_TYPE_UNKNOWN = -1;
+ static final int ITEM_TYPE_ICON = 0;
+ static final int ITEM_TYPE_TITLE = 1;
+ static final int ITEM_TYPE_CUSTOM_NAV = 2;
+ static final int ITEM_TYPE_ACTION = 3;
+ static final int ITEM_TYPE_MORE = 4;
+
+ int type = ITEM_TYPE_UNKNOWN;
+
+ public LayoutParams(Context c, AttributeSet attrs) {
+ super(c, attrs);
+ }
+
+ public LayoutParams(int width, int height) {
+ super(width, height);
+ }
+
+ public LayoutParams(int width, int height, int type) {
+ this(width, height);
+ this.type = type;
+ }
+
+
+ public LayoutParams(ViewGroup.LayoutParams source) {
+ super(source);
+ }
+ }
+
+ public interface OnActionListener {
+ void onAction(int id);
+ }
+
+ private static class ActionView extends ImageView {
+ int actionId;
+ CharSequence actionLabel;
+ OnActionListener actionListener;
+ MenuItem menuItem;
+
+ public ActionView(Context context) {
+ super(context);
+ }
+ }
+}
diff --git a/core/java/android/view/MenuInflater.java b/core/java/android/view/MenuInflater.java
index 46c805c..a37d83d 100644
--- a/core/java/android/view/MenuInflater.java
+++ b/core/java/android/view/MenuInflater.java
@@ -16,9 +16,8 @@
package android.view;
-import com.android.internal.view.menu.MenuItemImpl;
-
import java.io.IOException;
+import java.lang.reflect.Method;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -30,6 +29,8 @@
import android.util.AttributeSet;
import android.util.Xml;
+import com.android.internal.view.menu.MenuItemImpl;
+
/**
* This class is used to instantiate menu XML files into Menu objects.
* <p>
@@ -166,6 +167,41 @@
}
}
+ private static class InflatedOnMenuItemClickListener
+ implements MenuItem.OnMenuItemClickListener {
+ private static final Class[] PARAM_TYPES = new Class[] { MenuItem.class };
+
+ private Context mContext;
+ private Method mMethod;
+
+ public InflatedOnMenuItemClickListener(Context context, String methodName) {
+ mContext = context;
+ Class c = context.getClass();
+ try {
+ mMethod = c.getMethod(methodName, PARAM_TYPES);
+ } catch (Exception e) {
+ InflateException ex = new InflateException(
+ "Couldn't resolve menu item onClick handler " + methodName +
+ " in class " + c.getName());
+ ex.initCause(e);
+ throw ex;
+ }
+ }
+
+ public boolean onMenuItemClick(MenuItem item) {
+ try {
+ if (mMethod.getReturnType() == Boolean.TYPE) {
+ return (Boolean) mMethod.invoke(mContext, item);
+ } else {
+ mMethod.invoke(mContext, item);
+ return true;
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
/**
* State for the current menu.
* <p>
@@ -205,6 +241,8 @@
private boolean itemVisible;
private boolean itemEnabled;
+ private String itemListenerMethodName;
+
private static final int defaultGroupId = NO_ID;
private static final int defaultItemId = NO_ID;
private static final int defaultItemCategory = 0;
@@ -276,6 +314,7 @@
itemChecked = a.getBoolean(com.android.internal.R.styleable.MenuItem_checked, defaultItemChecked);
itemVisible = a.getBoolean(com.android.internal.R.styleable.MenuItem_visible, groupVisible);
itemEnabled = a.getBoolean(com.android.internal.R.styleable.MenuItem_enabled, groupEnabled);
+ itemListenerMethodName = a.getString(com.android.internal.R.styleable.MenuItem_onClick);
a.recycle();
@@ -299,8 +338,13 @@
.setIcon(itemIconResId)
.setAlphabeticShortcut(itemAlphabeticShortcut)
.setNumericShortcut(itemNumericShortcut);
+
+ if (itemListenerMethodName != null) {
+ item.setOnMenuItemClickListener(
+ new InflatedOnMenuItemClickListener(mContext, itemListenerMethodName));
+ }
- if (itemCheckable >= 2) {
+ if (itemCheckable >= 2 && item instanceof MenuItemImpl) {
((MenuItemImpl) item).setExclusiveCheckable(true);
}
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 11e5ad1..3461cbf 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -887,6 +887,20 @@
public static final int HAPTIC_FEEDBACK_ENABLED = 0x10000000;
/**
+ * <p>Indicates that the view hierarchy should stop saving state when
+ * it reaches this view. If state saving is initiated immediately at
+ * the view, it will be allowed.
+ * {@hide}
+ */
+ static final int PARENT_SAVE_DISABLED = 0x20000000;
+
+ /**
+ * <p>Mask for use with setFlags indicating bits used for PARENT_SAVE_DISABLED.</p>
+ * {@hide}
+ */
+ static final int PARENT_SAVE_DISABLED_MASK = 0x20000000;
+
+ /**
* View flag indicating whether {@link #addFocusables(ArrayList, int, int)}
* should add all focusable Views regardless if they are focusable in touch mode.
*/
@@ -3342,6 +3356,38 @@
/**
+ * Indicates whether the entire hierarchy under this view will save its
+ * state when a state saving traversal occurs from its parent. The default
+ * is true; if false, these views will not be saved unless
+ * {@link #saveHierarchyState(SparseArray)} is called directly on this view.
+ *
+ * @return Returns true if the view state saving from parent is enabled, else false.
+ *
+ * @see #setSaveFromParentEnabled(boolean)
+ */
+ public boolean isSaveFromParentEnabled() {
+ return (mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED;
+ }
+
+ /**
+ * Controls whether the entire hierarchy under this view will save its
+ * state when a state saving traversal occurs from its parent. The default
+ * is true; if false, these views will not be saved unless
+ * {@link #saveHierarchyState(SparseArray)} is called directly on this view.
+ *
+ * @param enabled Set to false to <em>disable</em> state saving, or true
+ * (the default) to allow it.
+ *
+ * @see #isSaveFromParentEnabled()
+ * @see #setId(int)
+ * @see #onSaveInstanceState()
+ */
+ public void setSaveFromParentEnabled(boolean enabled) {
+ setFlags(enabled ? 0 : PARENT_SAVE_DISABLED, PARENT_SAVE_DISABLED_MASK);
+ }
+
+
+ /**
* Returns whether this View is able to take focus.
*
* @return True if this view can take focus, or false otherwise.
@@ -8548,13 +8594,12 @@
if (mAttachInfo == null) {
return false;
}
- if ((flags&HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING) == 0
+ if ((flags & HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING) == 0
&& !isHapticFeedbackEnabled()) {
return false;
}
- return mAttachInfo.mRootCallbacks.performHapticFeedback(
- feedbackConstant,
- (flags&HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0);
+ return mAttachInfo.mRootCallbacks.performHapticFeedback(feedbackConstant,
+ (flags & HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0);
}
/**
@@ -8625,8 +8670,7 @@
ViewConfiguration.getLongPressTimeout() - delayOffset);
}
- private static int[] stateSetUnion(final int[] stateSet1,
- final int[] stateSet2) {
+ private static int[] stateSetUnion(final int[] stateSet1, final int[] stateSet2) {
final int stateSet1Length = stateSet1.length;
final int stateSet2Length = stateSet2.length;
final int[] newSet = new int[stateSet1Length + stateSet2Length];
@@ -8664,7 +8708,7 @@
LayoutInflater factory = LayoutInflater.from(context);
return factory.inflate(resource, root);
}
-
+
/**
* A MeasureSpec encapsulates the layout requirements passed from parent to child.
* Each MeasureSpec represents a requirement for either the width or the height.
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index eca583f..1fc0251 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -1181,7 +1181,10 @@
final int count = mChildrenCount;
final View[] children = mChildren;
for (int i = 0; i < count; i++) {
- children[i].dispatchSaveInstanceState(container);
+ View c = children[i];
+ if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) {
+ c.dispatchSaveInstanceState(container);
+ }
}
}
@@ -1206,7 +1209,10 @@
final int count = mChildrenCount;
final View[] children = mChildren;
for (int i = 0; i < count; i++) {
- children[i].dispatchRestoreInstanceState(container);
+ View c = children[i];
+ if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) {
+ c.dispatchRestoreInstanceState(container);
+ }
}
}
@@ -1560,7 +1566,8 @@
boolean scalingRequired = false;
Bitmap cache = null;
- if ((flags & FLAG_CHILDREN_DRAWN_WITH_CACHE) == FLAG_CHILDREN_DRAWN_WITH_CACHE ||
+ if (canvas.getGL() == null &&
+ (flags & FLAG_CHILDREN_DRAWN_WITH_CACHE) == FLAG_CHILDREN_DRAWN_WITH_CACHE ||
(flags & FLAG_ALWAYS_DRAWN_WITH_CACHE) == FLAG_ALWAYS_DRAWN_WITH_CACHE) {
cache = child.getDrawingCache(true);
if (mAttachInfo != null) scalingRequired = mAttachInfo.mScalingRequired;
@@ -2869,7 +2876,7 @@
*/
@ViewDebug.ExportedProperty(mapping = {
@ViewDebug.IntToString(from = PERSISTENT_NO_CACHE, to = "NONE"),
- @ViewDebug.IntToString(from = PERSISTENT_ALL_CACHES, to = "ANIMATION"),
+ @ViewDebug.IntToString(from = PERSISTENT_ANIMATION_CACHE, to = "ANIMATION"),
@ViewDebug.IntToString(from = PERSISTENT_SCROLLING_CACHE, to = "SCROLLING"),
@ViewDebug.IntToString(from = PERSISTENT_ALL_CACHES, to = "ALL")
})
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index aa124e6..15c6910 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -16,6 +16,7 @@
package android.view;
+import android.content.pm.ApplicationInfo;
import com.android.internal.view.BaseSurfaceHolder;
import com.android.internal.view.IInputMethodCallback;
import com.android.internal.view.IInputMethodSession;
@@ -33,7 +34,6 @@
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.EventLog;
-import android.util.Slog;
import android.util.SparseArray;
import android.view.View.MeasureSpec;
import android.view.accessibility.AccessibilityEvent;
@@ -52,7 +52,6 @@
import android.media.AudioManager;
import java.lang.ref.WeakReference;
-import java.io.FileDescriptor;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
@@ -68,14 +67,12 @@
*
* {@hide}
*/
-@SuppressWarnings({"EmptyCatchBlock"})
-public final class ViewRoot extends Handler implements ViewParent,
- View.AttachInfo.Callbacks {
+@SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"})
+public final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Callbacks {
private static final String TAG = "ViewRoot";
private static final boolean DBG = false;
private static final boolean SHOW_FPS = false;
- @SuppressWarnings({"ConstantConditionalExpression"})
- private static final boolean LOCAL_LOGV = false ? Config.LOGD : Config.LOGV;
+ private static final boolean LOCAL_LOGV = false;
/** @noinspection PointlessBooleanExpression*/
private static final boolean DEBUG_DRAW = false || LOCAL_LOGV;
private static final boolean DEBUG_LAYOUT = false || LOCAL_LOGV;
@@ -202,14 +199,7 @@
int mCurScrollY;
Scroller mScroller;
- EGL10 mEgl;
- EGLDisplay mEglDisplay;
- EGLContext mEglContext;
- EGLSurface mEglSurface;
- GL11 mGL;
- Canvas mGlCanvas;
- boolean mUseGL;
- boolean mGlWanted;
+ HardwareRenderer mHwRenderer;
final ViewConfiguration mViewConfiguration;
@@ -239,8 +229,10 @@
public ViewRoot(Context context) {
super();
- if (MEASURE_LATENCY && lt == null) {
- lt = new LatencyTimer(100, 1000);
+ if (MEASURE_LATENCY) {
+ if (lt == null) {
+ lt = new LatencyTimer(100, 1000);
+ }
}
// For debug only
@@ -270,6 +262,12 @@
mAttachInfo = new View.AttachInfo(sWindowSession, mWindow, this, this);
mViewConfiguration = ViewConfiguration.get(context);
mDensity = context.getResources().getDisplayMetrics().densityDpi;
+
+ // Try to enable hardware acceleration if requested
+ if ((context.getApplicationInfo().flags &
+ ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
+ mHwRenderer = new HardwareRenderer();
+ }
}
// For debug only
@@ -328,112 +326,6 @@
return false;
}
- private void initializeGL() {
- initializeGLInner();
- int err = mEgl.eglGetError();
- if (err != EGL10.EGL_SUCCESS) {
- // give-up on using GL
- destroyGL();
- mGlWanted = false;
- }
- }
-
- private void initializeGLInner() {
- final EGL10 egl = (EGL10) EGLContext.getEGL();
- mEgl = egl;
-
- /*
- * Get to the default display.
- */
- final EGLDisplay eglDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
- mEglDisplay = eglDisplay;
-
- /*
- * We can now initialize EGL for that display
- */
- int[] version = new int[2];
- egl.eglInitialize(eglDisplay, version);
-
- /*
- * Specify a configuration for our opengl session
- * and grab the first configuration that matches is
- */
- final int[] configSpec = {
- EGL10.EGL_RED_SIZE, 5,
- EGL10.EGL_GREEN_SIZE, 6,
- EGL10.EGL_BLUE_SIZE, 5,
- EGL10.EGL_DEPTH_SIZE, 0,
- EGL10.EGL_NONE
- };
- final EGLConfig[] configs = new EGLConfig[1];
- final int[] num_config = new int[1];
- egl.eglChooseConfig(eglDisplay, configSpec, configs, 1, num_config);
- final EGLConfig config = configs[0];
-
- /*
- * Create an OpenGL ES context. This must be done only once, an
- * OpenGL context is a somewhat heavy object.
- */
- final EGLContext context = egl.eglCreateContext(eglDisplay, config,
- EGL10.EGL_NO_CONTEXT, null);
- mEglContext = context;
-
- /*
- * Create an EGL surface we can render into.
- */
- final EGLSurface surface = egl.eglCreateWindowSurface(eglDisplay, config, mHolder, null);
- mEglSurface = surface;
-
- /*
- * Before we can issue GL commands, we need to make sure
- * the context is current and bound to a surface.
- */
- egl.eglMakeCurrent(eglDisplay, surface, surface, context);
-
- /*
- * Get to the appropriate GL interface.
- * This is simply done by casting the GL context to either
- * GL10 or GL11.
- */
- final GL11 gl = (GL11) context.getGL();
- mGL = gl;
- mGlCanvas = new Canvas(gl);
- mUseGL = true;
- }
-
- private void destroyGL() {
- // inform skia that the context is gone
- nativeAbandonGlCaches();
-
- mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
- EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
- mEgl.eglDestroyContext(mEglDisplay, mEglContext);
- mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
- mEgl.eglTerminate(mEglDisplay);
- mEglContext = null;
- mEglSurface = null;
- mEglDisplay = null;
- mEgl = null;
- mGlCanvas = null;
- mGL = null;
- mUseGL = false;
- }
-
- private void checkEglErrors() {
- if (mUseGL) {
- int err = mEgl.eglGetError();
- if (err != EGL10.EGL_SUCCESS) {
- // something bad has happened revert to
- // normal rendering.
- destroyGL();
- if (err != EGL11.EGL_CONTEXT_LOST) {
- // we'll try again if it was context lost
- mGlWanted = false;
- }
- }
- }
- }
-
// fd [0] is the receiver, [1] is the sender
private native int[] makeInputChannel();
@@ -490,10 +382,10 @@
// Set up the input event channel
if (false) {
- int[] fds = makeInputChannel();
- if (DEBUG_INPUT) {
- Log.v(TAG, "makeInputChannel() returned " + fds);
- }
+ int[] fds = makeInputChannel();
+ if (DEBUG_INPUT) {
+ Log.v(TAG, "makeInputChannel() returned " + java.util.Arrays.toString(fds));
+ }
}
// Schedule the first layout -before- adding to the window
@@ -772,8 +664,8 @@
attachInfo.mWindowVisibility = viewVisibility;
host.dispatchWindowVisibilityChanged(viewVisibility);
if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) {
- if (mUseGL) {
- destroyGL();
+ if (mHwRenderer != null) {
+ mHwRenderer.destroyGL();
}
}
if (viewVisibility == View.GONE) {
@@ -889,10 +781,12 @@
final boolean computesInternalInsets =
attachInfo.mTreeObserver.hasComputeInternalInsetsListeners();
+
boolean insetsPending = false;
int relayoutResult = 0;
- if (mFirst || windowShouldResize || insetsChanged
- || viewVisibilityChanged || params != null) {
+
+ if (mFirst || windowShouldResize || insetsChanged ||
+ viewVisibilityChanged || params != null) {
if (viewVisibility == View.VISIBLE) {
// If this window is giving internal insets to the window
@@ -904,15 +798,7 @@
// window, waiting until we can finish laying out this window
// and get back to the window manager with the ultimately
// computed insets.
- insetsPending = computesInternalInsets
- && (mFirst || viewVisibilityChanged);
-
- if (mWindowAttributes.memoryType == WindowManager.LayoutParams.MEMORY_TYPE_GPU) {
- if (params == null) {
- params = mWindowAttributes;
- }
- mGlWanted = true;
- }
+ insetsPending = computesInternalInsets && (mFirst || viewVisibilityChanged);
}
if (mSurfaceHolder != null) {
@@ -921,11 +807,12 @@
lp.format = mSurfaceHolder.getRequestedFormat();
lp.type = mSurfaceHolder.getRequestedType();
}
-
- boolean initialized = false;
+
+ boolean hwIntialized = false;
boolean contentInsetsChanged = false;
boolean visibleInsetsChanged;
boolean hadSurface = mSurface.isValid();
+
try {
int fl = 0;
if (params != null) {
@@ -985,9 +872,8 @@
fullRedrawNeeded = true;
mPreviousTransparentRegion.setEmpty();
- if (mGlWanted && !mUseGL) {
- initializeGL();
- initialized = mGlCanvas != null;
+ if (mHwRenderer != null) {
+ hwIntialized = mHwRenderer.initialize();
}
}
} else if (!mSurface.isValid()) {
@@ -1065,9 +951,8 @@
}
}
- if (initialized) {
- mGlCanvas.setViewport((int) (mWidth * appScale + 0.5f),
- (int) (mHeight * appScale + 0.5f));
+ if (hwIntialized) {
+ mHwRenderer.setup(appScale);
}
boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
@@ -1328,7 +1213,8 @@
if (!sFirstDrawComplete) {
synchronized (sFirstDrawHandlers) {
sFirstDrawComplete = true;
- for (int i=0; i<sFirstDrawHandlers.size(); i++) {
+ final int count = sFirstDrawHandlers.size();
+ for (int i = 0; i< count; i++) {
post(sFirstDrawHandlers.get(i));
}
}
@@ -1362,53 +1248,16 @@
return;
}
- if (mUseGL) {
+ if (mHwRenderer != null && mHwRenderer.mEnabled) {
if (!dirty.isEmpty()) {
- Canvas canvas = mGlCanvas;
- if (mGL != null && canvas != null) {
- mGL.glDisable(GL_SCISSOR_TEST);
- mGL.glClearColor(0, 0, 0, 0);
- mGL.glClear(GL_COLOR_BUFFER_BIT);
- mGL.glEnable(GL_SCISSOR_TEST);
-
- mAttachInfo.mDrawingTime = SystemClock.uptimeMillis();
- mAttachInfo.mIgnoreDirtyState = true;
- mView.mPrivateFlags |= View.DRAWN;
-
- int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
- try {
- canvas.translate(0, -yoff);
- if (mTranslator != null) {
- mTranslator.translateCanvas(canvas);
- }
- canvas.setScreenDensity(scalingRequired
- ? DisplayMetrics.DENSITY_DEVICE : 0);
- mView.draw(canvas);
- if (Config.DEBUG && ViewDebug.consistencyCheckEnabled) {
- mView.dispatchConsistencyCheck(ViewDebug.CONSISTENCY_DRAWING);
- }
- } finally {
- canvas.restoreToCount(saveCount);
- }
-
- mAttachInfo.mIgnoreDirtyState = false;
-
- mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);
- checkEglErrors();
-
- if (SHOW_FPS || Config.DEBUG && ViewDebug.showFps) {
- int now = (int)SystemClock.elapsedRealtime();
- if (sDrawTime != 0) {
- nativeShowFPS(canvas, now - sDrawTime);
- }
- sDrawTime = now;
- }
- }
+ mHwRenderer.draw(yoff, scalingRequired);
}
+
if (scrolling) {
mFullRedrawNeeded = true;
scheduleTraversals();
}
+
return;
}
@@ -1720,8 +1569,6 @@
}
void dispatchDetachedFromWindow() {
- if (Config.LOGV) Log.v("ViewRoot", "Detaching in " + this + " of " + mSurface);
-
if (mView != null) {
mView.dispatchDetachedFromWindow();
}
@@ -1730,8 +1577,8 @@
mAttachInfo.mRootView = null;
mAttachInfo.mSurface = null;
- if (mUseGL) {
- destroyGL();
+ if (mHwRenderer != null) {
+ mHwRenderer.destroyGL();
}
mSurface.release();
@@ -1850,8 +1697,10 @@
event = sWindowSession.getPendingPointerMove(mWindow);
if (MEASURE_LATENCY && event != null) {
- lt.sample("9 Client got events ", System.nanoTime() - event.getEventTimeNano());
- lt.sample("8 Client getting events ", timeBeforeGettingEvents - event.getEventTimeNano());
+ lt.sample("9 Client got events ",
+ System.nanoTime() - event.getEventTimeNano());
+ lt.sample("8 Client getting events ",
+ timeBeforeGettingEvents - event.getEventTimeNano());
}
} catch (RemoteException e) {
}
@@ -1876,11 +1725,13 @@
event.offsetLocation(0, mCurScrollY);
}
if (MEASURE_LATENCY) {
- lt.sample("A Dispatching TouchEvents", System.nanoTime() - event.getEventTimeNano());
+ lt.sample("A Dispatching TouchEvents",
+ System.nanoTime() - event.getEventTimeNano());
}
handled = mView.dispatchTouchEvent(event);
if (MEASURE_LATENCY) {
- lt.sample("B Dispatched TouchEvents ", System.nanoTime() - event.getEventTimeNano());
+ lt.sample("B Dispatched TouchEvents ",
+ System.nanoTime() - event.getEventTimeNano());
}
if (!handled && isDown) {
int edgeSlop = mViewConfiguration.getScaledEdgeSlop();
@@ -1990,18 +1841,8 @@
boolean inTouchMode = msg.arg2 != 0;
ensureTouchModeLocally(inTouchMode);
- if (mGlWanted) {
- checkEglErrors();
- // we lost the gl context, so recreate it.
- if (mGlWanted && !mUseGL) {
- initializeGL();
- if (mGlCanvas != null) {
- float appScale = mAttachInfo.mApplicationScale;
- mGlCanvas.setViewport(
- (int) (mWidth * appScale + 0.5f),
- (int) (mHeight * appScale + 0.5f));
- }
- }
+ if (mHwRenderer != null) {
+ mHwRenderer.initializeAndSetup();
}
}
@@ -2051,8 +1892,7 @@
if ((event.getFlags()&KeyEvent.FLAG_FROM_SYSTEM) != 0) {
// The IME is trying to say this event is from the
// system! Bad bad bad!
- event = KeyEvent.changeFlags(event,
- event.getFlags()&~KeyEvent.FLAG_FROM_SYSTEM);
+ event = KeyEvent.changeFlags(event, event.getFlags() & ~KeyEvent.FLAG_FROM_SYSTEM);
}
deliverKeyEventToViewHierarchy((KeyEvent)msg.obj, false);
} break;
@@ -2497,8 +2337,7 @@
private void deliverKeyEvent(KeyEvent event, boolean sendDone) {
// If mView is null, we just consume the key event because it doesn't
// make sense to do anything else with it.
- boolean handled = mView != null
- ? mView.dispatchKeyEventPreIme(event) : true;
+ boolean handled = mView == null || mView.dispatchKeyEventPreIme(event);
if (handled) {
if (sendDone) {
if (LOCAL_LOGV) Log.v(
@@ -2535,7 +2374,6 @@
final boolean sendDone = seq >= 0;
if (!handled) {
deliverKeyEventToViewHierarchy(event, sendDone);
- return;
} else if (sendDone) {
if (LOCAL_LOGV) Log.v(
"ViewRoot", "Telling window manager key is finished");
@@ -2742,7 +2580,7 @@
void doDie() {
checkThread();
- if (Config.LOGV) Log.v("ViewRoot", "DIE in " + this + " of " + mSurface);
+ if (LOCAL_LOGV) Log.v("ViewRoot", "DIE in " + this + " of " + mSurface);
synchronized (this) {
if (mAdded && !mFirst) {
int viewVisibility = mView.getVisibility();
@@ -2803,13 +2641,12 @@
if (event.getAction() == KeyEvent.ACTION_DOWN) {
//noinspection ConstantConditions
if (false && event.getKeyCode() == KeyEvent.KEYCODE_CAMERA) {
- if (Config.LOGD) Log.d("keydisp",
- "===================================================");
- if (Config.LOGD) Log.d("keydisp", "Focused view Hierarchy is:");
+ if (DBG) Log.d("keydisp", "===================================================");
+ if (DBG) Log.d("keydisp", "Focused view Hierarchy is:");
+
debug();
- if (Config.LOGD) Log.d("keydisp",
- "===================================================");
+ if (DBG) Log.d("keydisp", "===================================================");
}
}
@@ -3476,6 +3313,180 @@
}
}
+ class HardwareRenderer {
+ private EGL10 mEgl;
+ private EGLDisplay mEglDisplay;
+ private EGLContext mEglContext;
+ private EGLSurface mEglSurface;
+ private GL11 mGL;
+
+ private Canvas mGlCanvas;
+
+ boolean mEnabled;
+ boolean mRequested = true;
+
+ private void initializeGL() {
+ initializeGLInner();
+ int err = mEgl.eglGetError();
+ if (err != EGL10.EGL_SUCCESS) {
+ destroyGL();
+ mRequested = false;
+ }
+ }
+
+ private void initializeGLInner() {
+ final EGL10 egl = (EGL10) EGLContext.getEGL();
+ mEgl = egl;
+
+ final EGLDisplay eglDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
+ mEglDisplay = eglDisplay;
+
+ int[] version = new int[2];
+ egl.eglInitialize(eglDisplay, version);
+
+ final int[] configSpec = {
+ EGL10.EGL_RED_SIZE, 8,
+ EGL10.EGL_GREEN_SIZE, 8,
+ EGL10.EGL_BLUE_SIZE, 8,
+ EGL10.EGL_DEPTH_SIZE, 0,
+ EGL10.EGL_NONE
+ };
+ final EGLConfig[] configs = new EGLConfig[1];
+ final int[] numConfig = new int[1];
+ egl.eglChooseConfig(eglDisplay, configSpec, configs, 1, numConfig);
+ final EGLConfig config = configs[0];
+
+ /*
+ * Create an OpenGL ES context. This must be done only once, an
+ * OpenGL context is a somewhat heavy object.
+ */
+ final EGLContext context = egl.eglCreateContext(eglDisplay, config,
+ EGL10.EGL_NO_CONTEXT, null);
+ mEglContext = context;
+
+ /*
+ * Create an EGL surface we can render into.
+ */
+ EGLSurface surface = egl.eglCreateWindowSurface(eglDisplay, config, mHolder, null);
+ mEglSurface = surface;
+
+ /*
+ * Before we can issue GL commands, we need to make sure
+ * the context is current and bound to a surface.
+ */
+ egl.eglMakeCurrent(eglDisplay, surface, surface, context);
+
+ /*
+ * Get to the appropriate GL interface.
+ * This is simply done by casting the GL context to either
+ * GL10 or GL11.
+ */
+ final GL11 gl = (GL11) context.getGL();
+ mGL = gl;
+ mGlCanvas = new Canvas(gl);
+ mEnabled = true;
+ }
+
+ void destroyGL() {
+ if (!mEnabled) return;
+
+ // inform skia that the context is gone
+ nativeAbandonGlCaches();
+
+ mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
+ EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
+ mEgl.eglDestroyContext(mEglDisplay, mEglContext);
+ mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
+ mEgl.eglTerminate(mEglDisplay);
+
+ mEglContext = null;
+ mEglSurface = null;
+ mEglDisplay = null;
+ mEgl = null;
+ mGlCanvas = null;
+ mGL = null;
+
+ mEnabled = false;
+ }
+
+ private void checkErrors() {
+ if (mEnabled) {
+ int err = mEgl.eglGetError();
+ if (err != EGL10.EGL_SUCCESS) {
+ // something bad has happened revert to
+ // normal rendering.
+ destroyGL();
+ if (err != EGL11.EGL_CONTEXT_LOST) {
+ // we'll try again if it was context lost
+ mRequested = false;
+ }
+ }
+ }
+ }
+
+ boolean initialize() {
+ if (mRequested && !mEnabled) {
+ initializeGL();
+ return mGlCanvas != null;
+ }
+ return false;
+ }
+
+ void setup(float appScale) {
+ mGlCanvas.setViewport((int) (mWidth * appScale + 0.5f),
+ (int) (mHeight * appScale + 0.5f));
+ }
+
+ void draw(int yoff, boolean scalingRequired) {
+ Canvas canvas = mGlCanvas;
+ if (mGL != null && canvas != null) {
+ mGL.glDisable(GL_SCISSOR_TEST);
+ mGL.glClearColor(0, 0, 0, 0);
+ mGL.glClear(GL_COLOR_BUFFER_BIT);
+ mGL.glEnable(GL_SCISSOR_TEST);
+
+ mAttachInfo.mDrawingTime = SystemClock.uptimeMillis();
+ mAttachInfo.mIgnoreDirtyState = true;
+ mView.mPrivateFlags |= View.DRAWN;
+
+ int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
+ try {
+ canvas.translate(0, -yoff);
+ if (mTranslator != null) {
+ mTranslator.translateCanvas(canvas);
+ }
+ canvas.setScreenDensity(scalingRequired ?
+ DisplayMetrics.DENSITY_DEVICE : 0);
+
+ mView.draw(canvas);
+
+ } finally {
+ canvas.restoreToCount(saveCount);
+ }
+
+ mAttachInfo.mIgnoreDirtyState = false;
+
+ mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);
+ checkErrors();
+ }
+ }
+
+ void initializeAndSetup() {
+ if (mRequested) {
+ checkErrors();
+ // we lost the gl context, so recreate it.
+ if (mRequested && !mEnabled) {
+ initializeGL();
+ if (mGlCanvas != null) {
+ float appScale = mAttachInfo.mApplicationScale;
+ mGlCanvas.setViewport((int) (mWidth * appScale + 0.5f),
+ (int) (mHeight * appScale + 0.5f));
+ }
+ }
+ }
+ }
+ }
+
private static native void nativeShowFPS(Canvas canvas, int durationMillis);
// inform skia to just abandon its texture cache IDs
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 234deba..bbd9f04 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -61,6 +61,13 @@
@hide
*/
public static final int FEATURE_OPENGL = 8;
+ /**
+ * Flag for enabling the Action Bar.
+ * This is enabled by default for some devices. The Action Bar
+ * replaces the title bar and provides an alternate location
+ * for an on-screen menu button on some devices.
+ */
+ public static final int FEATURE_ACTION_BAR = 9;
/** Flag for setting the progress bar's visibility to VISIBLE */
public static final int PROGRESS_VISIBILITY_ON = -1;
/** Flag for setting the progress bar's visibility to GONE */
@@ -989,6 +996,16 @@
{
return mFeatures;
}
+
+ /**
+ * Query for the availability of a certain feature.
+ *
+ * @param feature The feature ID to check
+ * @return true if the feature is enabled, false otherwise.
+ */
+ public boolean hasFeature(int feature) {
+ return (getFeatures() & (1 << feature)) != 0;
+ }
/**
* Return the feature bits that are being implemented by this Window.
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index c22f991..fc61700 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -622,6 +622,7 @@
mPackageName = null;
mContentDescription = null;
mBeforeText = null;
+ mParcelableData = null;
mText.clear();
}
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 0186270..f406da9 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -94,7 +94,9 @@
public static AccessibilityManager getInstance(Context context) {
synchronized (sInstanceSync) {
if (sInstance == null) {
- sInstance = new AccessibilityManager(context);
+ IBinder iBinder = ServiceManager.getService(Context.ACCESSIBILITY_SERVICE);
+ IAccessibilityManager service = IAccessibilityManager.Stub.asInterface(iBinder);
+ sInstance = new AccessibilityManager(context, service);
}
}
return sInstance;
@@ -104,13 +106,16 @@
* Create an instance.
*
* @param context A {@link Context}.
+ * @param service An interface to the backing service.
+ *
+ * @hide
*/
- private AccessibilityManager(Context context) {
+ public AccessibilityManager(Context context, IAccessibilityManager service) {
mHandler = new MyHandler(context.getMainLooper());
- IBinder iBinder = ServiceManager.getService(Context.ACCESSIBILITY_SERVICE);
- mService = IAccessibilityManager.Stub.asInterface(iBinder);
+ mService = service;
+
try {
- mService.addClient(mClient);
+ mIsEnabled = mService.addClient(mClient);
} catch (RemoteException re) {
Log.e(LOG_TAG, "AccessibilityManagerService is dead", re);
}
@@ -128,6 +133,18 @@
}
/**
+ * Returns the client interface this instance registers in
+ * the centralized accessibility manager service.
+ *
+ * @return The client.
+ *
+ * @hide
+ */
+ public IAccessibilityManagerClient getClient() {
+ return (IAccessibilityManagerClient) mClient.asBinder();
+ }
+
+ /**
* Sends an {@link AccessibilityEvent}. If this {@link AccessibilityManager} is not
* enabled the call is a NOOP.
*
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index 32788be..7633569 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -29,7 +29,7 @@
*/
interface IAccessibilityManager {
- void addClient(IAccessibilityManagerClient client);
+ boolean addClient(IAccessibilityManagerClient client);
boolean sendAccessibilityEvent(in AccessibilityEvent uiEvent);
diff --git a/core/java/android/webkit/AccessibilityInjector.java b/core/java/android/webkit/AccessibilityInjector.java
new file mode 100644
index 0000000..49ddc19
--- /dev/null
+++ b/core/java/android/webkit/AccessibilityInjector.java
@@ -0,0 +1,99 @@
+/*
+ * 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.webkit;
+
+import android.view.KeyEvent;
+import android.view.accessibility.AccessibilityEvent;
+import android.webkit.WebViewCore.EventHub;
+
+/**
+ * This class injects accessibility into WebViews with disabled JavaScript or
+ * WebViews with enabled JavaScript but for which we have no accessibility
+ * script to inject.
+ */
+class AccessibilityInjector {
+
+ // Handle to the WebView this injector is associated with.
+ private final WebView mWebView;
+
+ /**
+ * Creates a new injector associated with a given VwebView.
+ *
+ * @param webView The associated WebView.
+ */
+ public AccessibilityInjector(WebView webView) {
+ mWebView = webView;
+ }
+
+ /**
+ * Processes a key down <code>event</code>.
+ *
+ * @return True if the event was processed.
+ */
+ public boolean onKeyEvent(KeyEvent event) {
+
+ // as a proof of concept let us do the simplest example
+
+ if (event.getAction() != KeyEvent.ACTION_UP) {
+ return false;
+ }
+
+ int keyCode = event.getKeyCode();
+
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_N:
+ modifySelection("extend", "forward", "sentence");
+ break;
+ case KeyEvent.KEYCODE_P:
+ modifySelection("extend", "backward", "sentence");
+ break;
+ }
+
+ return false;
+ }
+
+ /**
+ * Called when the <code>selectionString</code> has changed.
+ */
+ public void onSelectionStringChange(String selectionString) {
+ // put the selection string in an AccessibilityEvent and send it
+ AccessibilityEvent event = AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_FOCUSED);
+ event.getText().add(selectionString);
+ mWebView.sendAccessibilityEventUnchecked(event);
+ }
+
+ /**
+ * Modifies the current selection.
+ *
+ * @param alter Specifies how to alter the selection.
+ * @param direction The direction in which to alter the selection.
+ * @param granularity The granularity of the selection modification.
+ */
+ private void modifySelection(String alter, String direction, String granularity) {
+ WebViewCore webViewCore = mWebView.getWebViewCore();
+
+ if (webViewCore == null) {
+ return;
+ }
+
+ WebViewCore.ModifySelectionData data = new WebViewCore.ModifySelectionData();
+ data.mAlter = alter;
+ data.mDirection = direction;
+ data.mGranularity = granularity;
+ webViewCore.sendMessage(EventHub.MODIFY_SELECTION, data);
+ }
+}
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index 219a469..6ec43f1 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -846,6 +846,7 @@
private static final int FILE_UPLOAD_LABEL = 4;
private static final int RESET_LABEL = 5;
private static final int SUBMIT_LABEL = 6;
+ private static final int FILE_UPLOAD_NO_FILE_CHOSEN = 7;
String getRawResFilename(int id) {
int resid;
@@ -875,6 +876,10 @@
return mContext.getResources().getString(
com.android.internal.R.string.submit);
+ case FILE_UPLOAD_NO_FILE_CHOSEN:
+ return mContext.getResources().getString(
+ com.android.internal.R.string.no_file_chosen);
+
default:
Log.e(LOGTAG, "getRawResFilename got incompatible resource ID");
return "";
diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java
index 0e0e032..6357671 100644
--- a/core/java/android/webkit/CallbackProxy.java
+++ b/core/java/android/webkit/CallbackProxy.java
@@ -16,6 +16,7 @@
package android.webkit;
+import android.app.Activity;
import android.app.AlertDialog;
import android.content.ActivityNotFoundException;
import android.content.Context;
@@ -41,6 +42,7 @@
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
+import java.util.Map;
/**
* This class is a proxy class for handling WebCore -> UI thread messaging. All
@@ -500,18 +502,32 @@
String url = msg.getData().getString("url");
if (!mWebChromeClient.onJsAlert(mWebView, url, message,
res)) {
+ // only display the alert dialog if the mContext is
+ // Activity and its window has the focus.
+ if (!(mContext instanceof Activity)
+ || !((Activity) mContext).hasWindowFocus()) {
+ res.cancel();
+ res.setReady();
+ break;
+ }
new AlertDialog.Builder(mContext)
.setTitle(getJsDialogTitle(url))
.setMessage(message)
.setPositiveButton(R.string.ok,
- new AlertDialog.OnClickListener() {
+ new DialogInterface.OnClickListener() {
public void onClick(
DialogInterface dialog,
int which) {
res.confirm();
}
})
- .setCancelable(false)
+ .setOnCancelListener(
+ new DialogInterface.OnCancelListener() {
+ public void onCancel(
+ DialogInterface dialog) {
+ res.cancel();
+ }
+ })
.show();
}
res.setReady();
@@ -525,6 +541,14 @@
String url = msg.getData().getString("url");
if (!mWebChromeClient.onJsConfirm(mWebView, url, message,
res)) {
+ // only display the alert dialog if the mContext is
+ // Activity and its window has the focus.
+ if (!(mContext instanceof Activity)
+ || !((Activity) mContext).hasWindowFocus()) {
+ res.cancel();
+ res.setReady();
+ break;
+ }
new AlertDialog.Builder(mContext)
.setTitle(getJsDialogTitle(url))
.setMessage(message)
@@ -565,6 +589,14 @@
String url = msg.getData().getString("url");
if (!mWebChromeClient.onJsPrompt(mWebView, url, message,
defaultVal, res)) {
+ // only display the alert dialog if the mContext is
+ // Activity and its window has the focus.
+ if (!(mContext instanceof Activity)
+ || !((Activity) mContext).hasWindowFocus()) {
+ res.cancel();
+ res.setReady();
+ break;
+ }
final LayoutInflater factory = LayoutInflater
.from(mContext);
final View view = factory.inflate(R.layout.js_prompt,
@@ -616,6 +648,14 @@
String url = msg.getData().getString("url");
if (!mWebChromeClient.onJsBeforeUnload(mWebView, url,
message, res)) {
+ // only display the alert dialog if the mContext is
+ // Activity and its window has the focus.
+ if (!(mContext instanceof Activity)
+ || !((Activity) mContext).hasWindowFocus()) {
+ res.cancel();
+ res.setReady();
+ break;
+ }
final String m = mContext.getString(
R.string.js_dialog_before_unload, message);
new AlertDialog.Builder(mContext)
@@ -725,7 +765,8 @@
case OPEN_FILE_CHOOSER:
if (mWebChromeClient != null) {
- mWebChromeClient.openFileChooser((UploadFile) msg.obj);
+ UploadFileMessageData data = (UploadFileMessageData)msg.obj;
+ mWebChromeClient.openFileChooser(data.getUploadFile(), data.getAcceptType());
}
break;
@@ -1087,10 +1128,15 @@
public void onProgressChanged(int newProgress) {
// Synchronize so that mLatestProgress is up-to-date.
synchronized (this) {
- if (mWebChromeClient == null || mLatestProgress == newProgress) {
+ // update mLatestProgress even mWebChromeClient is null as
+ // WebView.getProgress() needs it
+ if (mLatestProgress == newProgress) {
return;
}
mLatestProgress = newProgress;
+ if (mWebChromeClient == null) {
+ return;
+ }
if (!mProgressUpdatePending) {
sendEmptyMessage(PROGRESS);
mProgressUpdatePending = true;
@@ -1426,6 +1472,24 @@
sendMessage(msg);
}
+ private static class UploadFileMessageData {
+ private UploadFile mCallback;
+ private String mAcceptType;
+
+ public UploadFileMessageData(UploadFile uploadFile, String acceptType) {
+ mCallback = uploadFile;
+ mAcceptType = acceptType;
+ }
+
+ public UploadFile getUploadFile() {
+ return mCallback;
+ }
+
+ public String getAcceptType() {
+ return mAcceptType;
+ }
+ }
+
private class UploadFile implements ValueCallback<Uri> {
private Uri mValue;
public void onReceiveValue(Uri value) {
@@ -1442,13 +1506,14 @@
/**
* Called by WebViewCore to open a file chooser.
*/
- /* package */ Uri openFileChooser() {
+ /* package */ Uri openFileChooser(String acceptType) {
if (mWebChromeClient == null) {
return null;
}
Message myMessage = obtainMessage(OPEN_FILE_CHOOSER);
UploadFile uploadFile = new UploadFile();
- myMessage.obj = uploadFile;
+ UploadFileMessageData data = new UploadFileMessageData(uploadFile, acceptType);
+ myMessage.obj = data;
synchronized (this) {
sendMessage(myMessage);
try {
diff --git a/core/java/android/webkit/GeolocationService.java b/core/java/android/webkit/GeolocationService.java
index 24306f4..183b3c0 100755
--- a/core/java/android/webkit/GeolocationService.java
+++ b/core/java/android/webkit/GeolocationService.java
@@ -62,9 +62,10 @@
/**
* Start listening for location updates.
*/
- public void start() {
+ public boolean start() {
registerForLocationUpdates();
mIsRunning = true;
+ return mIsNetworkProviderAvailable || mIsGpsProviderAvailable;
}
/**
@@ -87,6 +88,8 @@
// only unregister from all, then reregister with all but the GPS.
unregisterFromLocationUpdates();
registerForLocationUpdates();
+ // Check that the providers are still available after we re-register.
+ maybeReportError("The last location provider is no longer available");
}
}
}
@@ -156,11 +159,16 @@
*/
private void registerForLocationUpdates() {
try {
- mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this);
- mIsNetworkProviderAvailable = true;
+ // Registration may fail if providers are not present on the device.
+ try {
+ mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this);
+ mIsNetworkProviderAvailable = true;
+ } catch(IllegalArgumentException e) { }
if (mIsGpsEnabled) {
- mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
- mIsGpsProviderAvailable = true;
+ try {
+ mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
+ mIsGpsProviderAvailable = true;
+ } catch(IllegalArgumentException e) { }
}
} catch(SecurityException e) {
Log.e(TAG, "Caught security exception registering for location updates from system. " +
@@ -173,6 +181,8 @@
*/
private void unregisterFromLocationUpdates() {
mLocationManager.removeUpdates(this);
+ mIsNetworkProviderAvailable = false;
+ mIsGpsProviderAvailable = false;
}
/**
diff --git a/core/java/android/webkit/HTML5Audio.java b/core/java/android/webkit/HTML5Audio.java
new file mode 100644
index 0000000..d292881
--- /dev/null
+++ b/core/java/android/webkit/HTML5Audio.java
@@ -0,0 +1,224 @@
+/*
+ * 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.webkit;
+
+import android.media.MediaPlayer;
+import android.media.MediaPlayer.OnBufferingUpdateListener;
+import android.media.MediaPlayer.OnCompletionListener;
+import android.media.MediaPlayer.OnErrorListener;
+import android.media.MediaPlayer.OnPreparedListener;
+import android.media.MediaPlayer.OnSeekCompleteListener;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+
+import java.io.IOException;
+import java.util.Timer;
+import java.util.TimerTask;
+
+/**
+ * <p>HTML5 support class for Audio.
+ */
+class HTML5Audio extends Handler
+ implements MediaPlayer.OnBufferingUpdateListener,
+ MediaPlayer.OnCompletionListener,
+ MediaPlayer.OnErrorListener,
+ MediaPlayer.OnPreparedListener,
+ MediaPlayer.OnSeekCompleteListener {
+ // Logging tag.
+ private static final String LOGTAG = "HTML5Audio";
+
+ private MediaPlayer mMediaPlayer;
+
+ // The C++ MediaPlayerPrivateAndroid object.
+ private int mNativePointer;
+
+ private static int IDLE = 0;
+ private static int INITIALIZED = 1;
+ private static int PREPARED = 2;
+ private static int STARTED = 4;
+ private static int COMPLETE = 5;
+ private static int PAUSED = 6;
+ private static int STOPPED = -2;
+ private static int ERROR = -1;
+
+ private int mState = IDLE;
+
+ private String mUrl;
+ private boolean mAskToPlay = false;
+
+ // Timer thread -> UI thread
+ private static final int TIMEUPDATE = 100;
+
+ // The spec says the timer should fire every 250 ms or less.
+ private static final int TIMEUPDATE_PERIOD = 250; // ms
+ // The timer for timeupate events.
+ // See http://www.whatwg.org/specs/web-apps/current-work/#event-media-timeupdate
+ private Timer mTimer;
+ private final class TimeupdateTask extends TimerTask {
+ public void run() {
+ HTML5Audio.this.obtainMessage(TIMEUPDATE).sendToTarget();
+ }
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case TIMEUPDATE: {
+ try {
+ if (mState != ERROR && mMediaPlayer.isPlaying()) {
+ int position = mMediaPlayer.getCurrentPosition();
+ nativeOnTimeupdate(position, mNativePointer);
+ }
+ } catch (IllegalStateException e) {
+ mState = ERROR;
+ }
+ }
+ }
+ }
+
+ // event listeners for MediaPlayer
+ // Those are called from the same thread we created the MediaPlayer
+ // (i.e. the webviewcore thread here)
+
+ // MediaPlayer.OnBufferingUpdateListener
+ public void onBufferingUpdate(MediaPlayer mp, int percent) {
+ nativeOnBuffering(percent, mNativePointer);
+ }
+
+ // MediaPlayer.OnCompletionListener;
+ public void onCompletion(MediaPlayer mp) {
+ resetMediaPlayer();
+ mState = IDLE;
+ nativeOnEnded(mNativePointer);
+ }
+
+ // MediaPlayer.OnErrorListener
+ public boolean onError(MediaPlayer mp, int what, int extra) {
+ mState = ERROR;
+ resetMediaPlayer();
+ mState = IDLE;
+ return false;
+ }
+
+ // MediaPlayer.OnPreparedListener
+ public void onPrepared(MediaPlayer mp) {
+ mState = PREPARED;
+ if (mTimer != null) {
+ mTimer.schedule(new TimeupdateTask(),
+ TIMEUPDATE_PERIOD, TIMEUPDATE_PERIOD);
+ }
+ nativeOnPrepared(mp.getDuration(), 0, 0, mNativePointer);
+ if (mAskToPlay) {
+ mAskToPlay = false;
+ play();
+ }
+ }
+
+ // MediaPlayer.OnSeekCompleteListener
+ public void onSeekComplete(MediaPlayer mp) {
+ nativeOnTimeupdate(mp.getCurrentPosition(), mNativePointer);
+ }
+
+
+ /**
+ * @param nativePtr is the C++ pointer to the MediaPlayerPrivate object.
+ */
+ public HTML5Audio(int nativePtr) {
+ // Save the native ptr
+ mNativePointer = nativePtr;
+ resetMediaPlayer();
+ }
+
+ private void resetMediaPlayer() {
+ if (mMediaPlayer == null) {
+ mMediaPlayer = new MediaPlayer();
+ } else {
+ mMediaPlayer.reset();
+ }
+ mMediaPlayer.setOnBufferingUpdateListener(this);
+ mMediaPlayer.setOnCompletionListener(this);
+ mMediaPlayer.setOnErrorListener(this);
+ mMediaPlayer.setOnPreparedListener(this);
+ mMediaPlayer.setOnSeekCompleteListener(this);
+
+ if (mTimer != null) {
+ mTimer.cancel();
+ }
+ mTimer = new Timer();
+ mState = IDLE;
+ }
+
+ private void setDataSource(String url) {
+ mUrl = url;
+ try {
+ if (mState != IDLE) {
+ resetMediaPlayer();
+ }
+ mMediaPlayer.setDataSource(url);
+ mState = INITIALIZED;
+ mMediaPlayer.prepareAsync();
+ } catch (IOException e) {
+ Log.e(LOGTAG, "couldn't load the resource: " + url + " exc: " + e);
+ resetMediaPlayer();
+ }
+ }
+
+ private void play() {
+ if ((mState == ERROR || mState == IDLE) && mUrl != null) {
+ resetMediaPlayer();
+ setDataSource(mUrl);
+ mAskToPlay = true;
+ }
+
+ if (mState >= PREPARED) {
+ mMediaPlayer.start();
+ mState = STARTED;
+ }
+ }
+
+ private void pause() {
+ if (mState == STARTED) {
+ if (mTimer != null) {
+ mTimer.purge();
+ }
+ mMediaPlayer.pause();
+ mState = PAUSED;
+ }
+ }
+
+ private void seek(int msec) {
+ if (mState >= PREPARED) {
+ mMediaPlayer.seekTo(msec);
+ }
+ }
+
+ private void teardown() {
+ mMediaPlayer.release();
+ mState = ERROR;
+ mNativePointer = 0;
+ }
+
+ private float getMaxTimeSeekable() {
+ return mMediaPlayer.getDuration() / 1000.0f;
+ }
+
+ private native void nativeOnBuffering(int percent, int nativePointer);
+ private native void nativeOnEnded(int nativePointer);
+ private native void nativeOnPrepared(int duration, int width, int height, int nativePointer);
+ private native void nativeOnTimeupdate(int position, int nativePointer);
+}
diff --git a/core/java/android/webkit/JWebCoreJavaBridge.java b/core/java/android/webkit/JWebCoreJavaBridge.java
index e766693..ecad261 100644
--- a/core/java/android/webkit/JWebCoreJavaBridge.java
+++ b/core/java/android/webkit/JWebCoreJavaBridge.java
@@ -16,10 +16,12 @@
package android.webkit;
+import android.net.Uri;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
+import java.util.HashMap;
import java.util.Set;
final class JWebCoreJavaBridge extends Handler {
@@ -49,12 +51,15 @@
/* package */
static final int REFRESH_PLUGINS = 100;
+ private HashMap<String, String> mContentUriToFilePathMap;
+
/**
* Construct a new JWebCoreJavaBridge to interface with
* WebCore timers and cookies.
*/
public JWebCoreJavaBridge() {
nativeConstructor();
+
}
@Override
@@ -267,6 +272,28 @@
}
}
+ // Called on the WebCore thread through JNI.
+ private String resolveFilePathForContentUri(String uri) {
+ if (mContentUriToFilePathMap != null) {
+ String fileName = mContentUriToFilePathMap.get(uri);
+ if (fileName != null) {
+ return fileName;
+ }
+ }
+
+ // Failsafe fallback to just use the last path segment.
+ // (See OpenableColumns documentation in the SDK)
+ Uri jUri = Uri.parse(uri);
+ return jUri.getLastPathSegment();
+ }
+
+ public void storeFilePathForContentUri(String path, String contentUri) {
+ if (mContentUriToFilePathMap == null) {
+ mContentUriToFilePathMap = new HashMap<String, String>();
+ }
+ mContentUriToFilePathMap.put(contentUri, path);
+ }
+
private native void nativeConstructor();
private native void nativeFinalize();
private native void sharedTimerFired();
diff --git a/core/java/android/webkit/Network.java b/core/java/android/webkit/Network.java
index 598f20d..0f03258 100644
--- a/core/java/android/webkit/Network.java
+++ b/core/java/android/webkit/Network.java
@@ -16,7 +16,12 @@
package android.webkit;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
import android.net.http.*;
import android.os.*;
import android.util.Log;
@@ -76,6 +81,19 @@
*/
private HttpAuthHandler mHttpAuthHandler;
+ private Context mContext;
+
+ /**
+ * True if the currently used network connection is a roaming phone
+ * connection.
+ */
+ private boolean mRoaming;
+
+ /**
+ * Tracks if we are roaming.
+ */
+ private RoamingMonitor mRoamingMonitor;
+
/**
* @return The singleton instance of the network.
*/
@@ -107,6 +125,7 @@
if (++sPlatformNotificationEnableRefCount == 1) {
if (sNetwork != null) {
sNetwork.mRequestQueue.enablePlatformNotifications();
+ sNetwork.monitorRoaming();
} else {
sPlatformNotifications = true;
}
@@ -121,6 +140,7 @@
if (--sPlatformNotificationEnableRefCount == 0) {
if (sNetwork != null) {
sNetwork.mRequestQueue.disablePlatformNotifications();
+ sNetwork.stopMonitoringRoaming();
} else {
sPlatformNotifications = false;
}
@@ -136,12 +156,39 @@
Assert.assertTrue(Thread.currentThread().
getName().equals(WebViewCore.THREAD_NAME));
}
+ mContext = context;
mSslErrorHandler = new SslErrorHandler();
mHttpAuthHandler = new HttpAuthHandler(this);
mRequestQueue = new RequestQueue(context);
}
+ private class RoamingMonitor extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (!ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction()))
+ return;
+
+ NetworkInfo info = (NetworkInfo)intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
+ if (info != null)
+ mRoaming = info.isRoaming();
+ };
+ };
+
+ private void monitorRoaming() {
+ mRoamingMonitor = new RoamingMonitor();
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+ mContext.registerReceiver(sNetwork.mRoamingMonitor, filter);
+ }
+
+ private void stopMonitoringRoaming() {
+ if (mRoamingMonitor != null) {
+ mContext.unregisterReceiver(mRoamingMonitor);
+ mRoamingMonitor = null;
+ }
+ }
+
/**
* Request a url from either the network or the file system.
* @param url The url to load.
@@ -170,6 +217,11 @@
return false;
}
+ // If this is a prefetch, abort it if we're roaming.
+ if (mRoaming && headers.containsKey("X-Moz") && "prefetch".equals(headers.get("X-Moz"))) {
+ return false;
+ }
+
/* FIXME: this is lame. Pass an InputStream in, rather than
making this lame one here */
InputStream bodyProvider = null;
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index 1d5aac7..ad53508 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -314,10 +314,12 @@
/**
* Tell the client to open a file chooser.
* @param uploadFile A ValueCallback to set the URI of the file to upload.
- * onReceiveValue must be called to wake up the thread.
+ * onReceiveValue must be called to wake up the thread.a
+ * @param acceptType The value of the 'accept' attribute of the input tag
+ * associated with this file picker.
* @hide
*/
- public void openFileChooser(ValueCallback<Uri> uploadFile) {
+ public void openFileChooser(ValueCallback<Uri> uploadFile, String acceptType) {
uploadFile.onReceiveValue(null);
}
}
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index b767f11..64f43bb 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -296,13 +296,13 @@
"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_7; en-us)"
+ " AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0"
+ " Safari/530.17";
- private static final String IPHONE_USERAGENT =
+ private static final String IPHONE_USERAGENT =
"Mozilla/5.0 (iPhone; U; CPU iPhone OS 3_0 like Mac OS X; en-us)"
+ " AppleWebKit/528.18 (KHTML, like Gecko) Version/4.0"
+ " Mobile/7A341 Safari/528.16";
private static Locale sLocale;
private static Object sLockForLocaleSettings;
-
+
/**
* Package constructor to prevent clients from creating a new settings
* instance.
@@ -327,6 +327,8 @@
android.os.Process.myUid()) != PackageManager.PERMISSION_GRANTED;
}
+ private static final String ACCEPT_LANG_FOR_US_LOCALE = "en-US";
+
/**
* Looks at sLocale and returns current AcceptLanguage String.
* @return Current AcceptLanguage String.
@@ -336,32 +338,53 @@
synchronized(sLockForLocaleSettings) {
locale = sLocale;
}
- StringBuffer buffer = new StringBuffer();
- final String language = locale.getLanguage();
- if (language != null) {
- buffer.append(language);
- final String country = locale.getCountry();
- if (country != null) {
- buffer.append("-");
- buffer.append(country);
+ StringBuilder buffer = new StringBuilder();
+ addLocaleToHttpAcceptLanguage(buffer, locale);
+
+ if (!Locale.US.equals(locale)) {
+ if (buffer.length() > 0) {
+ buffer.append(", ");
}
- }
- if (!locale.equals(Locale.US)) {
- buffer.append(", ");
- java.util.Locale us = Locale.US;
- if (us.getLanguage() != null) {
- buffer.append(us.getLanguage());
- final String country = us.getCountry();
- if (country != null) {
- buffer.append("-");
- buffer.append(country);
- }
- }
+ buffer.append(ACCEPT_LANG_FOR_US_LOCALE);
}
return buffer.toString();
}
-
+
+ /**
+ * Convert obsolete language codes, including Hebrew/Indonesian/Yiddish,
+ * to new standard.
+ */
+ private static String convertObsoleteLanguageCodeToNew(String langCode) {
+ if (langCode == null) {
+ return null;
+ }
+ if ("iw".equals(langCode)) {
+ // Hebrew
+ return "he";
+ } else if ("in".equals(langCode)) {
+ // Indonesian
+ return "id";
+ } else if ("ji".equals(langCode)) {
+ // Yiddish
+ return "yi";
+ }
+ return langCode;
+ }
+
+ private static void addLocaleToHttpAcceptLanguage(StringBuilder builder,
+ Locale locale) {
+ String language = convertObsoleteLanguageCodeToNew(locale.getLanguage());
+ if (language != null) {
+ builder.append(language);
+ String country = locale.getCountry();
+ if (country != null) {
+ builder.append("-");
+ builder.append(country);
+ }
+ }
+ }
+
/**
* Looks at sLocale and mContext and returns current UserAgent String.
* @return Current UserAgent String.
@@ -379,11 +402,11 @@
} else {
// default to "1.0"
buffer.append("1.0");
- }
+ }
buffer.append("; ");
final String language = locale.getLanguage();
if (language != null) {
- buffer.append(language.toLowerCase());
+ buffer.append(convertObsoleteLanguageCodeToNew(language));
final String country = locale.getCountry();
if (country != null) {
buffer.append("-");
@@ -426,6 +449,21 @@
}
/**
+ * If WebView only supports touch, a different navigation model will be
+ * applied. Otherwise, the navigation to support both touch and keyboard
+ * will be used.
+ * @hide
+ public void setSupportTouchOnly(boolean touchOnly) {
+ mSupportTounchOnly = touchOnly;
+ }
+ */
+
+ boolean supportTouchOnly() {
+ // for debug only, use mLightTouchEnabled for mSupportTounchOnly
+ return mLightTouchEnabled;
+ }
+
+ /**
* Set whether the WebView supports zoom
*/
public void setSupportZoom(boolean support) {
diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java
index 19abec1..eb36b5d 100644
--- a/core/java/android/webkit/WebTextView.java
+++ b/core/java/android/webkit/WebTextView.java
@@ -28,6 +28,7 @@
import android.graphics.drawable.Drawable;
import android.text.Editable;
import android.text.InputFilter;
+import android.text.Layout;
import android.text.Selection;
import android.text.Spannable;
import android.text.TextPaint;
@@ -300,6 +301,33 @@
return connection;
}
+ /**
+ * In general, TextView makes a call to InputMethodManager.updateSelection
+ * in onDraw. However, in the general case of WebTextView, we do not draw.
+ * This method is called by WebView.onDraw to take care of the part that
+ * needs to be called.
+ */
+ /* package */ void onDrawSubstitute() {
+ if (!willNotDraw()) {
+ // If the WebTextView is set to draw, such as in the case of a
+ // password, onDraw calls updateSelection(), so this code path is
+ // unnecessary.
+ return;
+ }
+ // This code is copied from TextView.onDraw(). That code does not get
+ // executed, however, because the WebTextView does not draw, allowing
+ // webkit's drawing to show through.
+ InputMethodManager imm = InputMethodManager.peekInstance();
+ if (imm != null && imm.isActive(this)) {
+ Spannable sp = (Spannable) getText();
+ int selStart = Selection.getSelectionStart(sp);
+ int selEnd = Selection.getSelectionEnd(sp);
+ int candStart = EditableInputConnection.getComposingSpanStart(sp);
+ int candEnd = EditableInputConnection.getComposingSpanEnd(sp);
+ imm.updateSelection(this, selStart, selEnd, candStart, candEnd);
+ }
+ }
+
@Override
protected void onDraw(Canvas canvas) {
// onDraw should only be called for password fields. If WebTextView is
@@ -360,19 +388,8 @@
@Override
protected void onSelectionChanged(int selStart, int selEnd) {
- if (mInSetTextAndKeepSelection) return;
- // This code is copied from TextView.onDraw(). That code does not get
- // executed, however, because the WebTextView does not draw, allowing
- // webkit's drawing to show through.
- InputMethodManager imm = InputMethodManager.peekInstance();
- if (imm != null && imm.isActive(this)) {
- Spannable sp = (Spannable) getText();
- int candStart = EditableInputConnection.getComposingSpanStart(sp);
- int candEnd = EditableInputConnection.getComposingSpanEnd(sp);
- imm.updateSelection(this, selStart, selEnd, candStart, candEnd);
- }
if (!mFromWebKit && !mFromFocusChange && !mFromSetInputType
- && mWebView != null) {
+ && mWebView != null && !mInSetTextAndKeepSelection) {
if (DebugFlags.WEB_TEXT_VIEW) {
Log.v(LOGTAG, "onSelectionChanged selStart=" + selStart
+ " selEnd=" + selEnd);
@@ -481,9 +498,10 @@
// to big for the case of a small textfield.
int smallerSlop = slop/2;
if (dx > smallerSlop || dy > smallerSlop) {
- if (mWebView != null) {
- float maxScrollX = (float) Touch.getMaxScrollX(this,
- getLayout(), mScrollY);
+ Layout layout = getLayout();
+ if (mWebView != null && layout != null) {
+ float maxScrollX = (float) Touch.getMaxScrollX(this, layout,
+ mScrollY);
if (DebugFlags.WEB_TEXT_VIEW) {
Log.v(LOGTAG, "onTouchEvent x=" + mScrollX + " y="
+ mScrollY + " maxX=" + maxScrollX);
@@ -667,6 +685,7 @@
} else {
Selection.setSelection(text, selection, selection);
}
+ if (mWebView != null) mWebView.incrementTextGeneration();
}
/**
@@ -919,14 +938,4 @@
/* package */ void updateCachedTextfield() {
mWebView.updateCachedTextfield(getText().toString());
}
-
- @Override
- public boolean requestRectangleOnScreen(Rect rectangle) {
- // don't scroll while in zoom animation. When it is done, we will adjust
- // the WebTextView if it is in editing mode.
- if (!mWebView.inAnimateZoom()) {
- return super.requestRectangleOnScreen(rectangle);
- }
- return false;
- }
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index ac23832..8a8df5a 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -25,19 +25,16 @@
import android.content.pm.PackageManager;
import android.database.DataSetObserver;
import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.CornerPathEffect;
import android.graphics.Interpolator;
-import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Picture;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
-import android.graphics.Shader;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.net.http.SslCertificate;
@@ -46,6 +43,7 @@
import android.os.Message;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.speech.tts.TextToSpeech;
import android.text.IClipboard;
import android.text.Selection;
import android.text.Spannable;
@@ -64,32 +62,29 @@
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
-import android.view.animation.AlphaAnimation;
+import android.view.accessibility.AccessibilityManager;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
import android.webkit.WebTextView.AutoCompleteAdapter;
import android.webkit.WebViewCore.EventHub;
import android.webkit.WebViewCore.TouchEventData;
+import android.webkit.WebViewCore.TouchHighlightData;
import android.widget.AbsoluteLayout;
import android.widget.Adapter;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.CheckedTextView;
-import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.Scroller;
import android.widget.Toast;
-import android.widget.ZoomButtonsController;
-import android.widget.ZoomControls;
import android.widget.AdapterView.OnItemClickListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
-import java.io.IOException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.HashMap;
@@ -238,7 +233,7 @@
*
* <p>The screen density of a device is based on the screen resolution. A screen with low density
* has fewer available pixels per inch, where a screen with high density
- * has more — sometimes significantly more — pixels per inch. The density of a
+ * has more - sometimes significantly more - pixels per inch. The density of a
* screen is important because, other things being equal, a UI element (such as a button) whose
* height and width are defined in terms of screen pixels will appear larger on the lower density
* screen and smaller on the higher density screen.
@@ -310,49 +305,7 @@
static final String LOGTAG = "webview";
- private static class ExtendedZoomControls extends FrameLayout {
- public ExtendedZoomControls(Context context, AttributeSet attrs) {
- super(context, attrs);
- LayoutInflater inflater = (LayoutInflater)
- context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- inflater.inflate(com.android.internal.R.layout.zoom_magnify, this, true);
- mPlusMinusZoomControls = (ZoomControls) findViewById(
- com.android.internal.R.id.zoomControls);
- findViewById(com.android.internal.R.id.zoomMagnify).setVisibility(
- View.GONE);
- }
-
- public void show(boolean showZoom, boolean canZoomOut) {
- mPlusMinusZoomControls.setVisibility(
- showZoom ? View.VISIBLE : View.GONE);
- fade(View.VISIBLE, 0.0f, 1.0f);
- }
-
- public void hide() {
- fade(View.GONE, 1.0f, 0.0f);
- }
-
- private void fade(int visibility, float startAlpha, float endAlpha) {
- AlphaAnimation anim = new AlphaAnimation(startAlpha, endAlpha);
- anim.setDuration(500);
- startAnimation(anim);
- setVisibility(visibility);
- }
-
- public boolean hasFocus() {
- return mPlusMinusZoomControls.hasFocus();
- }
-
- public void setOnZoomInClickListener(OnClickListener listener) {
- mPlusMinusZoomControls.setOnZoomInClickListener(listener);
- }
-
- public void setOnZoomOutClickListener(OnClickListener listener) {
- mPlusMinusZoomControls.setOnZoomOutClickListener(listener);
- }
-
- ZoomControls mPlusMinusZoomControls;
- }
+ private ZoomManager mZoomManager;
/**
* Transportation object for returning WebView across thread boundaries.
@@ -398,6 +351,8 @@
// more key events.
private int mTextGeneration;
+ /* package */ void incrementTextGeneration() { mTextGeneration++; }
+
// Used by WebViewCore to create child views.
/* package */ final ViewManager mViewManager;
@@ -445,6 +400,10 @@
private float mLastVelX;
private float mLastVelY;
+ // only trigger accelerated fling if the new velocity is at least
+ // MINIMUM_VELOCITY_RATIO_FOR_ACCELERATION times of the previous velocity
+ private static final float MINIMUM_VELOCITY_RATIO_FOR_ACCELERATION = 0.2f;
+
/**
* Touch mode
*/
@@ -521,9 +480,6 @@
private static final int MIN_FLING_TIME = 250;
// draw unfiltered after drag is held without movement
private static final int MOTIONLESS_TIME = 100;
- // The time that the Zoom Controls are visible before fading away
- private static final long ZOOM_CONTROLS_TIMEOUT =
- ViewConfiguration.getZoomControlsTimeout();
// The amount of content to overlap between two screens when going through
// pages with the space bar, in pixels.
private static final int PAGE_SCROLL_OVERLAP = 24;
@@ -564,16 +520,30 @@
private static final int MOTIONLESS_IGNORE = 3;
private int mHeldMotionless;
- // whether support multi-touch
- private boolean mSupportMultiTouch;
- // use the framework's ScaleGestureDetector to handle multi-touch
- private ScaleGestureDetector mScaleDetector;
+ // An instance for injecting accessibility in WebViews with disabled
+ // JavaScript or ones for which no accessibility script exists
+ private AccessibilityInjector mAccessibilityInjector;
// the anchor point in the document space where VIEW_SIZE_CHANGED should
// apply to
private int mAnchorX;
private int mAnchorY;
+ // the color used to highlight the touch rectangles
+ private static final int mHightlightColor = 0x33000000;
+ // the round corner for the highlight path
+ private static final float TOUCH_HIGHLIGHT_ARC = 5.0f;
+ // the region indicating where the user touched on the screen
+ private Region mTouchHighlightRegion = new Region();
+ // the paint for the touch highlight
+ private Paint mTouchHightlightPaint;
+ // debug only
+ private static final boolean DEBUG_TOUCH_HIGHLIGHT = true;
+ private static final int TOUCH_HIGHLIGHT_ELAPSE_TIME = 2000;
+ private Paint mTouchCrossHairColor;
+ private int mTouchHighlightX;
+ private int mTouchHighlightY;
+
/*
* Private message ids
*/
@@ -606,7 +576,7 @@
static final int WEBCORE_INITIALIZED_MSG_ID = 107;
static final int UPDATE_TEXTFIELD_TEXT_MSG_ID = 108;
static final int UPDATE_ZOOM_RANGE = 109;
- static final int MOVE_OUT_OF_PLUGIN = 110;
+ static final int UNHANDLED_NAV_KEY = 110;
static final int CLEAR_TEXT_ENTRY = 111;
static final int UPDATE_TEXT_SELECTION_MSG_ID = 112;
static final int SHOW_RECT_MSG_ID = 113;
@@ -627,9 +597,11 @@
static final int CENTER_FIT_RECT = 127;
static final int REQUEST_KEYBOARD_WITH_SELECTION_MSG_ID = 128;
static final int SET_SCROLLBAR_MODES = 129;
+ static final int SELECTION_STRING_CHANGED = 130;
+ static final int SET_TOUCH_HIGHLIGHT_RECTS = 131;
private static final int FIRST_PACKAGE_MSG_ID = SCROLL_TO_MSG_ID;
- private static final int LAST_PACKAGE_MSG_ID = SET_SCROLLBAR_MODES;
+ private static final int LAST_PACKAGE_MSG_ID = SET_TOUCH_HIGHLIGHT_RECTS;
static final String[] HandlerPrivateDebugString = {
"REMEMBER_PASSWORD", // = 1;
@@ -654,7 +626,7 @@
"WEBCORE_INITIALIZED_MSG_ID", // = 107;
"UPDATE_TEXTFIELD_TEXT_MSG_ID", // = 108;
"UPDATE_ZOOM_RANGE", // = 109;
- "MOVE_OUT_OF_PLUGIN", // = 110;
+ "UNHANDLED_NAV_KEY", // = 110;
"CLEAR_TEXT_ENTRY", // = 111;
"UPDATE_TEXT_SELECTION_MSG_ID", // = 112;
"SHOW_RECT_MSG_ID", // = 113;
@@ -673,7 +645,9 @@
"FIND_AGAIN", // = 126;
"CENTER_FIT_RECT", // = 127;
"REQUEST_KEYBOARD_WITH_SELECTION_MSG_ID", // = 128;
- "SET_SCROLLBAR_MODES" // = 129;
+ "SET_SCROLLBAR_MODES", // = 129;
+ "SELECTION_STRING_CHANGED", // = 130;
+ "SET_TOUCH_HIGHLIGHT_RECTS" // = 131;
};
// If the site doesn't use the viewport meta tag to specify the viewport,
@@ -686,49 +660,9 @@
// the minimum preferred width is huge, an upper limit is needed.
static int sMaxViewportWidth = DEFAULT_VIEWPORT_WIDTH;
- // default scale limit. Depending on the display density
- private static float DEFAULT_MAX_ZOOM_SCALE;
- private static float DEFAULT_MIN_ZOOM_SCALE;
- // scale limit, which can be set through viewport meta tag in the web page
- private float mMaxZoomScale;
- private float mMinZoomScale;
- private boolean mMinZoomScaleFixed = true;
-
// initial scale in percent. 0 means using default.
private int mInitialScaleInPercent = 0;
- // while in the zoom overview mode, the page's width is fully fit to the
- // current window. The page is alive, in another words, you can click to
- // follow the links. Double tap will toggle between zoom overview mode and
- // the last zoom scale.
- boolean mInZoomOverview = false;
-
- // ideally mZoomOverviewWidth should be mContentWidth. But sites like espn,
- // engadget always have wider mContentWidth no matter what viewport size is.
- int mZoomOverviewWidth = DEFAULT_VIEWPORT_WIDTH;
- float mTextWrapScale;
-
- // default scale. Depending on the display density.
- static int DEFAULT_SCALE_PERCENT;
- private float mDefaultScale;
-
- private static float MINIMUM_SCALE_INCREMENT = 0.01f;
-
- // set to true temporarily during ScaleGesture triggered zoom
- private boolean mPreviewZoomOnly = false;
-
- // computed scale and inverse, from mZoomWidth.
- private float mActualScale;
- private float mInvActualScale;
- // if this is non-zero, it is used on drawing rather than mActualScale
- private float mZoomScale;
- private float mInvInitialZoomScale;
- private float mInvFinalZoomScale;
- private int mInitialScrollX;
- private int mInitialScrollY;
- private long mZoomStart;
- private static final int ZOOM_ANIMATION_LENGTH = 500;
-
private boolean mUserScroll = false;
private int mSnapScrollMode = SNAP_NONE;
@@ -752,6 +686,19 @@
private int mHorizontalScrollBarMode = SCROLLBAR_AUTO;
private int mVerticalScrollBarMode = SCROLLBAR_AUTO;
+ // the alias via which accessibility JavaScript interface is exposed
+ private static final String ALIAS_ACCESSIBILITY_JS_INTERFACE = "accessibility";
+
+ // JavaScript to inject the script chooser which will
+ // pick the right script for the current URL
+ private static final String ACCESSIBILITY_SCRIPT_CHOOSER_JAVASCRIPT =
+ "javascript:(function() {" +
+ " var chooser = document.createElement('script');" +
+ " chooser.type = 'text/javascript';" +
+ " chooser.src = 'https://ssl.gstatic.com/accessibility/javascript/android/AndroidScriptChooser.user.js';" +
+ " document.getElementsByTagName('head')[0].appendChild(chooser);" +
+ " })();";
+
// Used to match key downs and key ups
private boolean mGotKeyDown;
@@ -856,43 +803,6 @@
}
}
- // The View containing the zoom controls
- private ExtendedZoomControls mZoomControls;
- private Runnable mZoomControlRunnable;
-
- // mZoomButtonsController will be lazy initialized in
- // getZoomButtonsController() to get better performance.
- private ZoomButtonsController mZoomButtonsController;
-
- // These keep track of the center point of the zoom. They are used to
- // determine the point around which we should zoom.
- private float mZoomCenterX;
- private float mZoomCenterY;
-
- private ZoomButtonsController.OnZoomListener mZoomListener =
- new ZoomButtonsController.OnZoomListener() {
-
- public void onVisibilityChanged(boolean visible) {
- if (visible) {
- switchOutDrawHistory();
- // Bring back the hidden zoom controls.
- mZoomButtonsController.getZoomControls().setVisibility(
- View.VISIBLE);
- updateZoomButtonsEnabled();
- }
- }
-
- public void onZoom(boolean zoomIn) {
- if (zoomIn) {
- zoomIn();
- } else {
- zoomOut();
- }
-
- updateZoomButtonsEnabled();
- }
- };
-
/**
* Construct a new WebView with a Context object.
* @param context A Context object used to access application assets.
@@ -928,51 +838,37 @@
* @param context A Context object used to access application assets.
* @param attrs An AttributeSet passed to our parent.
* @param defStyle The default style resource ID.
- * @param javascriptInterfaces is a Map of intareface names, as keys, and
+ * @param javascriptInterfaces is a Map of interface names, as keys, and
* object implementing those interfaces, as values.
* @hide pending API council approval.
*/
protected WebView(Context context, AttributeSet attrs, int defStyle,
Map<String, Object> javascriptInterfaces) {
super(context, attrs, defStyle);
- init();
+
+ if (AccessibilityManager.getInstance(context).isEnabled()) {
+ if (javascriptInterfaces == null) {
+ javascriptInterfaces = new HashMap<String, Object>();
+ }
+ exposeAccessibilityJavaScriptApi(javascriptInterfaces);
+ }
mCallbackProxy = new CallbackProxy(context, this);
mViewManager = new ViewManager(this);
mWebViewCore = new WebViewCore(context, this, mCallbackProxy, javascriptInterfaces);
mDatabase = WebViewDatabase.getInstance(context);
mScroller = new Scroller(context);
+ mZoomManager = new ZoomManager(this, mCallbackProxy);
+ /* The init method must follow the creation of certain member variables,
+ * such as the mZoomManager.
+ */
+ init();
updateMultiTouchSupport(context);
}
void updateMultiTouchSupport(Context context) {
- WebSettings settings = getSettings();
- mSupportMultiTouch = context.getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH)
- && settings.supportZoom() && settings.getBuiltInZoomControls();
- if (mSupportMultiTouch && (mScaleDetector == null)) {
- mScaleDetector = new ScaleGestureDetector(context,
- new ScaleDetectorListener());
- } else if (!mSupportMultiTouch && (mScaleDetector != null)) {
- mScaleDetector = null;
- }
- }
-
- private void updateZoomButtonsEnabled() {
- if (mZoomButtonsController == null) return;
- boolean canZoomIn = mActualScale < mMaxZoomScale;
- boolean canZoomOut = mActualScale > mMinZoomScale && !mInZoomOverview;
- if (!canZoomIn && !canZoomOut) {
- // Hide the zoom in and out buttons, as well as the fit to page
- // button, if the page cannot zoom
- mZoomButtonsController.getZoomControls().setVisibility(View.GONE);
- } else {
- // Set each one individually, as a page may be able to zoom in
- // or out.
- mZoomButtonsController.setZoomInEnabled(canZoomIn);
- mZoomButtonsController.setZoomOutEnabled(canZoomOut);
- }
+ mZoomManager.updateMultiTouchSupport(context);
}
private void init() {
@@ -992,34 +888,35 @@
// use one line height, 16 based on our current default font, for how
// far we allow a touch be away from the edge of a link
mNavSlop = (int) (16 * density);
- // density adjusted scale factors
- DEFAULT_SCALE_PERCENT = (int) (100 * density);
- mDefaultScale = density;
- mActualScale = density;
- mInvActualScale = 1 / density;
- mTextWrapScale = density;
- DEFAULT_MAX_ZOOM_SCALE = 4.0f * density;
- DEFAULT_MIN_ZOOM_SCALE = 0.25f * density;
- mMaxZoomScale = DEFAULT_MAX_ZOOM_SCALE;
- mMinZoomScale = DEFAULT_MIN_ZOOM_SCALE;
+ mZoomManager.init(density);
mMaximumFling = configuration.getScaledMaximumFlingVelocity();
}
- /* package */void updateDefaultZoomDensity(int zoomDensity) {
- final float density = getContext().getResources().getDisplayMetrics().density
- * 100 / zoomDensity;
- if (Math.abs(density - mDefaultScale) > 0.01) {
- float scaleFactor = density / mDefaultScale;
- // adjust the limits
- mNavSlop = (int) (16 * density);
- DEFAULT_SCALE_PERCENT = (int) (100 * density);
- DEFAULT_MAX_ZOOM_SCALE = 4.0f * density;
- DEFAULT_MIN_ZOOM_SCALE = 0.25f * density;
- mDefaultScale = density;
- mMaxZoomScale *= scaleFactor;
- mMinZoomScale *= scaleFactor;
- setNewZoomScale(mActualScale * scaleFactor, true, false);
+ /**
+ * Exposes accessibility APIs to JavaScript by appending them to the JavaScript
+ * interfaces map provided by the WebView client. In case of conflicting
+ * alias with the one of the accessibility API the user specified one wins.
+ *
+ * @param javascriptInterfaces A map with interfaces to be exposed to JavaScript.
+ */
+ private void exposeAccessibilityJavaScriptApi(Map<String, Object> javascriptInterfaces) {
+ if (javascriptInterfaces.containsKey(ALIAS_ACCESSIBILITY_JS_INTERFACE)) {
+ Log.w(LOGTAG, "JavaScript interface mapped to \"" + ALIAS_ACCESSIBILITY_JS_INTERFACE
+ + "\" overrides the accessibility API JavaScript interface. No accessibility"
+ + "API will be exposed to JavaScript!");
+ return;
}
+
+ // expose the TTS for now ...
+ javascriptInterfaces.put(ALIAS_ACCESSIBILITY_JS_INTERFACE,
+ new TextToSpeech(getContext(), null));
+ }
+
+ /* package */void updateDefaultZoomDensity(int zoomDensity) {
+ final float density = mContext.getResources().getDisplayMetrics().density
+ * 100 / zoomDensity;
+ mNavSlop = (int) (16 * density);
+ mZoomManager.updateDefaultZoomDensity(density);
}
/* package */ boolean onSavePassword(String schemePlusHost, String username,
@@ -1136,14 +1033,14 @@
* returns the height of the titlebarview (if any). Does not care about
* scrolling
*/
- private int getTitleHeight() {
+ int getTitleHeight() {
return mTitleBar != null ? mTitleBar.getHeight() : 0;
}
/*
* Return the amount of the titlebarview (if any) that is visible
*/
- private int getVisibleTitleHeight() {
+ int getVisibleTitleHeight() {
return Math.max(getTitleHeight() - mScrollY, 0);
}
@@ -1404,9 +1301,9 @@
// now update the bundle
b.putInt("scrollX", mScrollX);
b.putInt("scrollY", mScrollY);
- b.putFloat("scale", mActualScale);
- b.putFloat("textwrapScale", mTextWrapScale);
- b.putBoolean("overview", mInZoomOverview);
+ b.putFloat("scale", mZoomManager.mActualScale);
+ b.putFloat("textwrapScale", mZoomManager.mTextWrapScale);
+ b.putBoolean("overview", mZoomManager.mInZoomOverview);
return true;
}
@@ -1423,10 +1320,10 @@
// as getWidth() / getHeight() of the view are not available yet, set up
// mActualScale, so that when onSizeChanged() is called, the rest will
// be set correctly
- mActualScale = scale;
- mInvActualScale = 1 / scale;
- mTextWrapScale = b.getFloat("textwrapScale", scale);
- mInZoomOverview = b.getBoolean("overview");
+ mZoomManager.mActualScale = scale;
+ mZoomManager.mInvActualScale = 1 / scale;
+ mZoomManager.mTextWrapScale = b.getFloat("textwrapScale", scale);
+ mZoomManager.mInZoomOverview = b.getBoolean("overview");
invalidate();
}
@@ -1849,7 +1746,7 @@
* @return The current scale.
*/
public float getScale() {
- return mActualScale;
+ return mZoomManager.mActualScale;
}
/**
@@ -1861,7 +1758,7 @@
* @param scaleInPercent The initial scale in percent.
*/
public void setInitialScale(int scaleInPercent) {
- mInitialScaleInPercent = scaleInPercent;
+ mZoomManager.setInitialScaleInPercent(scaleInPercent);
}
/**
@@ -1875,13 +1772,7 @@
return;
}
clearTextEntry(false);
- if (getSettings().getBuiltInZoomControls()) {
- getZoomButtonsController().setVisible(true);
- } else {
- mPrivateHandler.removeCallbacks(mZoomControlRunnable);
- mPrivateHandler.postDelayed(mZoomControlRunnable,
- ZOOM_CONTROLS_TIMEOUT);
- }
+ mZoomManager.invokeZoomPicker();
}
/**
@@ -1996,7 +1887,7 @@
msg.sendToTarget();
}
- private static int pinLoc(int x, int viewMax, int docMax) {
+ static int pinLoc(int x, int viewMax, int docMax) {
// Log.d(LOGTAG, "-- pinLoc " + x + " " + viewMax + " " + docMax);
if (docMax < viewMax) { // the doc has room on the sides for "blank"
// pin the short document to the top/left of the screen
@@ -2013,12 +1904,12 @@
}
// Expects x in view coordinates
- private int pinLocX(int x) {
+ int pinLocX(int x) {
return pinLoc(x, getViewWidth(), computeHorizontalScrollRange());
}
// Expects y in view coordinates
- private int pinLocY(int y) {
+ int pinLocY(int y) {
return pinLoc(y, getViewHeightWithTitle(),
computeVerticalScrollRange() + getTitleHeight());
}
@@ -2068,7 +1959,7 @@
* height.
*/
private int viewToContentDimension(int d) {
- return Math.round(d * mInvActualScale);
+ return Math.round(d * mZoomManager.mInvActualScale);
}
/**
@@ -2094,7 +1985,7 @@
* Returns the result as a float.
*/
private float viewToContentXf(int x) {
- return x * mInvActualScale;
+ return x * mZoomManager.mInvActualScale;
}
/**
@@ -2103,7 +1994,7 @@
* embedded into the WebView. Returns the result as a float.
*/
private float viewToContentYf(int y) {
- return (y - getTitleHeight()) * mInvActualScale;
+ return (y - getTitleHeight()) * mZoomManager.mInvActualScale;
}
/**
@@ -2113,7 +2004,7 @@
* height.
*/
/*package*/ int contentToViewDimension(int d) {
- return Math.round(d * mActualScale);
+ return Math.round(d * mZoomManager.mActualScale);
}
/**
@@ -2154,7 +2045,7 @@
// Called by JNI to invalidate the View, given rectangle coordinates in
// content space
private void viewInvalidate(int l, int t, int r, int b) {
- final float scale = mActualScale;
+ final float scale = mZoomManager.mActualScale;
final int dy = getTitleHeight();
invalidate((int)Math.floor(l * scale),
(int)Math.floor(t * scale) + dy,
@@ -2165,7 +2056,7 @@
// Called by JNI to invalidate the View after a delay, given rectangle
// coordinates in content space
private void viewInvalidateDelayed(long delay, int l, int t, int r, int b) {
- final float scale = mActualScale;
+ final float scale = mZoomManager.mActualScale;
final int dy = getTitleHeight();
postInvalidateDelayed(delay,
(int)Math.floor(l * scale),
@@ -2203,13 +2094,7 @@
// updated when we get out of that mode.
if (!mDrawHistory) {
// repin our scroll, taking into account the new content size
- int oldX = mScrollX;
- int oldY = mScrollY;
- mScrollX = pinLocX(mScrollX);
- mScrollY = pinLocY(mScrollY);
- if (oldX != mScrollX || oldY != mScrollY) {
- onScrollChanged(mScrollX, mScrollY, oldX, oldY);
- }
+ updateScrollCoordinates(pinLocX(mScrollX), pinLocY(mScrollY));
if (!mScroller.isFinished()) {
// We are in the middle of a scroll. Repin the final scroll
// position.
@@ -2221,77 +2106,12 @@
contentSizeChanged(updateLayout);
}
- private void setNewZoomScale(float scale, boolean updateTextWrapScale,
- boolean force) {
- if (scale < mMinZoomScale) {
- scale = mMinZoomScale;
- // set mInZoomOverview for non mobile sites
- if (scale < mDefaultScale) mInZoomOverview = true;
- } else if (scale > mMaxZoomScale) {
- scale = mMaxZoomScale;
- }
- if (updateTextWrapScale) {
- mTextWrapScale = scale;
- // reset mLastHeightSent to force VIEW_SIZE_CHANGED sent to WebKit
- mLastHeightSent = 0;
- }
- if (scale != mActualScale || force) {
- if (mDrawHistory) {
- // If history Picture is drawn, don't update scroll. They will
- // be updated when we get out of that mode.
- if (scale != mActualScale && !mPreviewZoomOnly) {
- mCallbackProxy.onScaleChanged(mActualScale, scale);
- }
- mActualScale = scale;
- mInvActualScale = 1 / scale;
- sendViewSizeZoom();
- } else {
- // update our scroll so we don't appear to jump
- // i.e. keep the center of the doc in the center of the view
-
- int oldX = mScrollX;
- int oldY = mScrollY;
- float ratio = scale * mInvActualScale; // old inverse
- float sx = ratio * oldX + (ratio - 1) * mZoomCenterX;
- float sy = ratio * oldY + (ratio - 1)
- * (mZoomCenterY - getTitleHeight());
-
- // now update our new scale and inverse
- if (scale != mActualScale && !mPreviewZoomOnly) {
- mCallbackProxy.onScaleChanged(mActualScale, scale);
- }
- mActualScale = scale;
- mInvActualScale = 1 / scale;
-
- // Scale all the child views
- mViewManager.scaleAll();
-
- // as we don't have animation for scaling, don't do animation
- // for scrolling, as it causes weird intermediate state
- // pinScrollTo(Math.round(sx), Math.round(sy));
- mScrollX = pinLocX(Math.round(sx));
- mScrollY = pinLocY(Math.round(sy));
-
- // update webkit
- if (oldX != mScrollX || oldY != mScrollY) {
- onScrollChanged(mScrollX, mScrollY, oldX, oldY);
- } else {
- // the scroll position is adjusted at the beginning of the
- // zoom animation. But we want to update the WebKit at the
- // end of the zoom animation. See comments in onScaleEnd().
- sendOurVisibleRect();
- }
- sendViewSizeZoom();
- }
- }
- }
-
// Used to avoid sending many visible rect messages.
private Rect mLastVisibleRectSent;
private Rect mLastGlobalRect;
- private Rect sendOurVisibleRect() {
- if (mPreviewZoomOnly) return mLastVisibleRectSent;
+ Rect sendOurVisibleRect() {
+ if (mZoomManager.isPreventingWebkitUpdates()) return mLastVisibleRectSent;
Rect rect = new Rect();
calcOurContentVisibleRect(rect);
@@ -2324,9 +2144,6 @@
Point p = new Point();
getGlobalVisibleRect(r, p);
r.offset(-p.x, -p.y);
- if (mFindIsUp) {
- r.bottom -= mFindHeight;
- }
}
// Sets r to be our visible rectangle in content coordinates
@@ -2361,6 +2178,11 @@
r.bottom = Math.min(viewToContentYf(ri.bottom), (float)mContentHeight);
}
+ void setViewSizeAnchor(int x, int y) {
+ mAnchorX = x;
+ mAnchorY = y;
+ }
+
static class ViewSizeData {
int mWidth;
int mHeight;
@@ -2373,16 +2195,19 @@
/**
* Compute unzoomed width and height, and if they differ from the last
- * values we sent, send them to webkit (to be used has new viewport)
+ * values we sent, send them to webkit (to be used as new viewport)
+ *
+ * @param force ensures that the message is sent to webkit even if the width
+ * or height has not changed since the last message
*
* @return true if new values were sent
*/
- private boolean sendViewSizeZoom() {
- if (mPreviewZoomOnly) return false;
+ boolean sendViewSizeZoom(boolean force) {
+ if (mZoomManager.isPreventingWebkitUpdates()) return false;
int viewWidth = getViewWidth();
- int newWidth = Math.round(viewWidth * mInvActualScale);
- int newHeight = Math.round(getViewHeight() * mInvActualScale);
+ int newWidth = Math.round(viewWidth * mZoomManager.mInvActualScale);
+ int newHeight = Math.round(getViewHeight() * mZoomManager.mInvActualScale);
/*
* Because the native side may have already done a layout before the
* View system was able to measure us, we have to send a height of 0 to
@@ -2395,13 +2220,14 @@
newHeight = 0;
}
// Avoid sending another message if the dimensions have not changed.
- if (newWidth != mLastWidthSent || newHeight != mLastHeightSent) {
+ if (newWidth != mLastWidthSent || newHeight != mLastHeightSent || force) {
ViewSizeData data = new ViewSizeData();
data.mWidth = newWidth;
data.mHeight = newHeight;
- data.mTextWrapWidth = Math.round(viewWidth / mTextWrapScale);;
- data.mScale = mActualScale;
- data.mIgnoreHeight = mZoomScale != 0 && !mHeightCanMeasure;
+ data.mTextWrapWidth = Math.round(viewWidth / mZoomManager.mTextWrapScale);
+ data.mScale = mZoomManager.mActualScale;
+ data.mIgnoreHeight = mZoomManager.isFixedLengthAnimationInProgress()
+ && !mHeightCanMeasure;
data.mAnchorX = mAnchorX;
data.mAnchorY = mAnchorY;
mWebViewCore.sendMessage(EventHub.VIEW_SIZE_CHANGED, data);
@@ -2418,12 +2244,12 @@
if (mDrawHistory) {
return mHistoryWidth;
} else if (mHorizontalScrollBarMode == SCROLLBAR_ALWAYSOFF
- && (mActualScale - mMinZoomScale <= MINIMUM_SCALE_INCREMENT)) {
+ && !mZoomManager.canZoomOut()) {
// only honor the scrollbar mode when it is at minimum zoom level
return computeHorizontalScrollExtent();
} else {
// to avoid rounding error caused unnecessary scrollbar, use floor
- return (int) Math.floor(mContentWidth * mActualScale);
+ return (int) Math.floor(mContentWidth * mZoomManager.mActualScale);
}
}
@@ -2432,12 +2258,12 @@
if (mDrawHistory) {
return mHistoryHeight;
} else if (mVerticalScrollBarMode == SCROLLBAR_ALWAYSOFF
- && (mActualScale - mMinZoomScale <= MINIMUM_SCALE_INCREMENT)) {
+ && !mZoomManager.canZoomOut()) {
// only honor the scrollbar mode when it is at minimum zoom level
return computeVerticalScrollExtent();
} else {
// to avoid rounding error caused unnecessary scrollbar, use floor
- return (int) Math.floor(mContentHeight * mActualScale);
+ return (int) Math.floor(mContentHeight * mZoomManager.mActualScale);
}
}
@@ -2682,19 +2508,27 @@
*/
public void setFindIsUp(boolean isUp) {
mFindIsUp = isUp;
- if (isUp) {
- recordNewContentSize(mContentWidth, mContentHeight + mFindHeight,
- false);
- }
if (0 == mNativeClass) return; // client isn't initialized
nativeSetFindIsUp(isUp);
}
+ /**
+ * @hide
+ */
+ public int findIndex() {
+ if (0 == mNativeClass) return -1;
+ return nativeFindIndex();
+ }
+
+ /**
+ * @hide
+ */
+ public boolean getFindIsUp() { return mFindIsUp; }
+
// Used to know whether the find dialog is open. Affects whether
// or not we draw the highlights for matches.
private boolean mFindIsUp;
- private int mFindHeight;
// Keep track of the last string sent, so we can search again after an
// orientation change or the dismissal of the soft keyboard.
private String mLastFind;
@@ -2769,8 +2603,6 @@
}
clearMatches();
setFindIsUp(false);
- recordNewContentSize(mContentWidth, mContentHeight - mFindHeight,
- false);
// Now that the dialog has been removed, ensure that we scroll to a
// location that is not beyond the end of the page.
pinScrollTo(mScrollX, mScrollY, false, 0);
@@ -2778,16 +2610,6 @@
}
/**
- * @hide
- */
- public void setFindDialogHeight(int height) {
- if (DebugFlags.WEB_VIEW) {
- Log.v(LOGTAG, "setFindDialogHeight height=" + height);
- }
- mFindHeight = height;
- }
-
- /**
* Query the document to see if it contains any image references. The
* message object will be dispatched with arg1 being set to 1 if images
* were found and 0 if the document does not reference any images.
@@ -2810,6 +2632,11 @@
postInvalidate(); // So we draw again
if (oldX != mScrollX || oldY != mScrollY) {
onScrollChanged(mScrollX, mScrollY, oldX, oldY);
+ } else {
+ abortAnimation();
+ mPrivateHandler.removeMessages(RESUME_WEBCORE_PRIORITY);
+ WebViewCore.resumePriority();
+ WebViewCore.resumeUpdatePicture(mWebViewCore);
}
} else {
super.computeScroll();
@@ -2898,6 +2725,29 @@
}
mPageThatNeedsToSlideTitleBarOffScreen = null;
}
+
+ injectAccessibilityForUrl(url);
+ }
+
+ /**
+ * This method injects accessibility in the loaded document if accessibility
+ * is enabled. If JavaScript is enabled we try to inject a URL specific script.
+ * If no URL specific script is found or JavaScript is disabled we fallback to
+ * the default {@link AccessibilityInjector} implementation.
+ *
+ * @param url The URL loaded by this {@link WebView}.
+ */
+ private void injectAccessibilityForUrl(String url) {
+ if (AccessibilityManager.getInstance(mContext).isEnabled()) {
+ if (getSettings().getJavaScriptEnabled()) {
+ loadUrl(ACCESSIBILITY_SCRIPT_CHOOSER_JAVASCRIPT);
+ } else if (mAccessibilityInjector == null) {
+ mAccessibilityInjector = new AccessibilityInjector(this);
+ }
+ } else {
+ // it is possible that accessibility was turned off between reloads
+ mAccessibilityInjector = null;
+ }
}
/**
@@ -3014,7 +2864,7 @@
} else {
// If we don't request a layout, try to send our view size to the
// native side to ensure that WebCore has the correct dimensions.
- sendViewSizeZoom();
+ sendViewSizeZoom(false);
}
}
@@ -3144,7 +2994,7 @@
* settings.
*/
public WebSettings getSettings() {
- return mWebViewCore.getSettings();
+ return (mWebViewCore != null) ? mWebViewCore.getSettings() : null;
}
/**
@@ -3285,7 +3135,47 @@
if (AUTO_REDRAW_HACK && mAutoRedraw) {
invalidate();
}
+ if (inEditingMode()) mWebTextView.onDrawSubstitute();
mWebViewCore.signalRepaintDone();
+
+ // paint the highlight in the end
+ if (!mTouchHighlightRegion.isEmpty()) {
+ if (mTouchHightlightPaint == null) {
+ mTouchHightlightPaint = new Paint();
+ mTouchHightlightPaint.setColor(mHightlightColor);
+ mTouchHightlightPaint.setAntiAlias(true);
+ mTouchHightlightPaint.setPathEffect(new CornerPathEffect(
+ TOUCH_HIGHLIGHT_ARC));
+ }
+ canvas.drawPath(mTouchHighlightRegion.getBoundaryPath(),
+ mTouchHightlightPaint);
+ }
+ if (DEBUG_TOUCH_HIGHLIGHT) {
+ if (getSettings().getNavDump()) {
+ if ((mTouchHighlightX | mTouchHighlightY) != 0) {
+ if (mTouchCrossHairColor == null) {
+ mTouchCrossHairColor = new Paint();
+ mTouchCrossHairColor.setColor(Color.RED);
+ }
+ canvas.drawLine(mTouchHighlightX - mNavSlop,
+ mTouchHighlightY - mNavSlop, mTouchHighlightX
+ + mNavSlop + 1, mTouchHighlightY + mNavSlop
+ + 1, mTouchCrossHairColor);
+ canvas.drawLine(mTouchHighlightX + mNavSlop + 1,
+ mTouchHighlightY - mNavSlop, mTouchHighlightX
+ - mNavSlop,
+ mTouchHighlightY + mNavSlop + 1,
+ mTouchCrossHairColor);
+ }
+ }
+ }
+ }
+
+ private void removeTouchHighlight(boolean removePendingMessage) {
+ if (removePendingMessage) {
+ mWebViewCore.removeMessages(EventHub.GET_TOUCH_HIGHLIGHT_RECTS);
+ }
+ mWebViewCore.sendMessage(EventHub.REMOVE_TOUCH_HIGHLIGHT_RECTS);
}
@Override
@@ -3306,6 +3196,8 @@
// Send the click so that the textfield is in focus
centerKeyPressOnTextField();
rebuildWebTextView();
+ } else {
+ clearTextEntry(true);
}
if (inEditingMode()) {
return mWebTextView.performLongClick();
@@ -3314,19 +3206,6 @@
}
}
- boolean inAnimateZoom() {
- return mZoomScale != 0;
- }
-
- /**
- * Need to adjust the WebTextView after a change in zoom, since mActualScale
- * has changed. This is especially important for password fields, which are
- * drawn by the WebTextView, since it conveys more information than what
- * webkit draws. Thus we need to reposition it to show in the correct
- * place.
- */
- private boolean mNeedToAdjustWebTextView;
-
private boolean didUpdateTextViewBounds(boolean allowIntersect) {
Rect contentBounds = nativeFocusCandidateNodeBounds();
Rect vBox = contentToViewRect(contentBounds);
@@ -3364,15 +3243,41 @@
canvas.setDrawFilter(null);
}
+ private void onZoomAnimationStart() {
+ // If it is in password mode, turn it off so it does not draw misplaced.
+ if (inEditingMode() && nativeFocusCandidateIsPassword()) {
+ mWebTextView.setInPassword(false);
+ }
+ }
+
+ private void onZoomAnimationEnd() {
+ // adjust the edit text view if needed
+ if (inEditingMode() && didUpdateTextViewBounds(false) && nativeFocusCandidateIsPassword()) {
+ // If it is a password field, start drawing the WebTextView once
+ // again.
+ mWebTextView.setInPassword(true);
+ }
+ }
+
+ void onFixedLengthZoomAnimationStart() {
+ WebViewCore.pauseUpdatePicture(getWebViewCore());
+ onZoomAnimationStart();
+ }
+
+ void onFixedLengthZoomAnimationEnd() {
+ WebViewCore.resumeUpdatePicture(mWebViewCore);
+ onZoomAnimationEnd();
+ }
+
private void drawCoreAndCursorRing(Canvas canvas, int color,
boolean drawCursorRing) {
if (mDrawHistory) {
- canvas.scale(mActualScale, mActualScale);
+ canvas.scale(mZoomManager.mActualScale, mZoomManager.mActualScale);
canvas.drawPicture(mHistoryPicture);
return;
}
- boolean animateZoom = mZoomScale != 0;
+ boolean animateZoom = mZoomManager.isFixedLengthAnimationInProgress();
boolean animateScroll = ((!mScroller.isFinished()
|| mVelocityTracker != null)
&& (mTouchMode != TOUCH_DRAG_MODE ||
@@ -3391,59 +3296,9 @@
}
}
if (animateZoom) {
- float zoomScale;
- int interval = (int) (SystemClock.uptimeMillis() - mZoomStart);
- if (interval < ZOOM_ANIMATION_LENGTH) {
- float ratio = (float) interval / ZOOM_ANIMATION_LENGTH;
- zoomScale = 1.0f / (mInvInitialZoomScale
- + (mInvFinalZoomScale - mInvInitialZoomScale) * ratio);
- invalidate();
- } else {
- zoomScale = mZoomScale;
- // set mZoomScale to be 0 as we have done animation
- mZoomScale = 0;
- WebViewCore.resumeUpdatePicture(mWebViewCore);
- // call invalidate() again to draw with the final filters
- invalidate();
- if (mNeedToAdjustWebTextView) {
- mNeedToAdjustWebTextView = false;
- if (didUpdateTextViewBounds(false)
- && nativeFocusCandidateIsPassword()) {
- // If it is a password field, start drawing the
- // WebTextView once again.
- mWebTextView.setInPassword(true);
- }
- }
- }
- // calculate the intermediate scroll position. As we need to use
- // zoomScale, we can't use pinLocX/Y directly. Copy the logic here.
- float scale = zoomScale * mInvInitialZoomScale;
- int tx = Math.round(scale * (mInitialScrollX + mZoomCenterX)
- - mZoomCenterX);
- tx = -pinLoc(tx, getViewWidth(), Math.round(mContentWidth
- * zoomScale)) + mScrollX;
- int titleHeight = getTitleHeight();
- int ty = Math.round(scale
- * (mInitialScrollY + mZoomCenterY - titleHeight)
- - (mZoomCenterY - titleHeight));
- ty = -(ty <= titleHeight ? Math.max(ty, 0) : pinLoc(ty
- - titleHeight, getViewHeight(), Math.round(mContentHeight
- * zoomScale)) + titleHeight) + mScrollY;
- canvas.translate(tx, ty);
- canvas.scale(zoomScale, zoomScale);
- if (inEditingMode() && !mNeedToAdjustWebTextView
- && mZoomScale != 0) {
- // The WebTextView is up. Keep track of this so we can adjust
- // its size and placement when we finish zooming
- mNeedToAdjustWebTextView = true;
- // If it is in password mode, turn it off so it does not draw
- // misplaced.
- if (nativeFocusCandidateIsPassword()) {
- mWebTextView.setInPassword(false);
- }
- }
+ mZoomManager.animateZoom(canvas);
} else {
- canvas.scale(mActualScale, mActualScale);
+ canvas.scale(mZoomManager.mActualScale, mZoomManager.mActualScale);
}
boolean UIAnimationsRunning = false;
@@ -3456,7 +3311,7 @@
invalidate();
}
mWebViewCore.drawContentPicture(canvas, color,
- (animateZoom || mPreviewZoomOnly || UIAnimationsRunning),
+ (mZoomManager.isZoomAnimating() || UIAnimationsRunning),
animateScroll);
if (mNativeClass == 0) return;
// decide which adornments to draw
@@ -3467,11 +3322,11 @@
if (!animateScroll) {
extras = DRAW_EXTRAS_FIND;
}
- } else if (mShiftIsPressed && !nativeFocusIsPlugin()) {
- if (!animateZoom && !mPreviewZoomOnly) {
+ } else if (mShiftIsPressed && !nativePageShouldHandleShiftAndArrows()) {
+ if (!mZoomManager.isZoomAnimating()) {
extras = DRAW_EXTRAS_SELECTION;
nativeSetSelectionRegion(mTouchSelection || mExtendSelection);
- nativeSetSelectionPointer(!mTouchSelection, mInvActualScale,
+ nativeSetSelectionPointer(!mTouchSelection, mZoomManager.mInvActualScale,
mSelectX, mSelectY - getTitleHeight(),
mExtendSelection);
}
@@ -3512,6 +3367,10 @@
return mDrawHistory;
}
+ int getHistoryPictureWidth() {
+ return (mHistoryPicture != null) ? mHistoryPicture.getWidth() : 0;
+ }
+
// Should only be called in UI thread
void switchOutDrawHistory() {
if (null == mWebViewCore) return; // CallbackProxy may trigger this
@@ -3566,7 +3425,9 @@
* @param end End of selection.
*/
/* package */ void setSelection(int start, int end) {
- mWebViewCore.sendMessage(EventHub.SET_SELECTION, start, end);
+ if (mWebViewCore != null) {
+ mWebViewCore.sendMessage(EventHub.SET_SELECTION, start, end);
+ }
}
@Override
@@ -3585,13 +3446,11 @@
getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
// bring it back to the default scale so that user can enter text
- boolean zoom = mActualScale < mDefaultScale;
+ boolean zoom = mZoomManager.mActualScale < mZoomManager.getDefaultScale();
if (zoom) {
- mInZoomOverview = false;
- mZoomCenterX = mLastTouchX;
- mZoomCenterY = mLastTouchY;
- // do not change text wrap scale so that there is no reflow
- setNewZoomScale(mDefaultScale, false, false);
+ mZoomManager.setZoomCenter(mLastTouchX, mLastTouchY);
+ mZoomManager.mInZoomOverview = false;
+ mZoomManager.setZoomScale(mZoomManager.getDefaultScale(), false);
}
if (isTextView) {
rebuildWebTextView();
@@ -3817,14 +3676,16 @@
// Bubble up the key event if
// 1. it is a system key; or
// 2. the host application wants to handle it;
+ // 3. the accessibility injector is present and wants to handle it;
if (event.isSystem()
- || mCallbackProxy.uiOverrideKeyEvent(event)) {
+ || mCallbackProxy.uiOverrideKeyEvent(event)
+ || (mAccessibilityInjector != null && mAccessibilityInjector.onKeyEvent(event))) {
return false;
}
if (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT
|| keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT) {
- if (nativeFocusIsPlugin()) {
+ if (nativePageShouldHandleShiftAndArrows()) {
mShiftIsPressed = true;
} else if (!nativeCursorWantsKeyEvents() && !mShiftIsPressed) {
setUpSelectXY();
@@ -3834,8 +3695,8 @@
if (keyCode >= KeyEvent.KEYCODE_DPAD_UP
&& keyCode <= KeyEvent.KEYCODE_DPAD_RIGHT) {
switchOutDrawHistory();
- if (nativeFocusIsPlugin()) {
- letPluginHandleNavKey(keyCode, event.getEventTime(), true);
+ if (nativePageShouldHandleShiftAndArrows()) {
+ letPageHandleNavKey(keyCode, event.getEventTime(), true);
return true;
}
if (mShiftIsPressed) {
@@ -3858,7 +3719,8 @@
if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
switchOutDrawHistory();
if (event.getRepeatCount() == 0) {
- if (mShiftIsPressed && !nativeFocusIsPlugin()) {
+ if (mShiftIsPressed
+ && !nativePageShouldHandleShiftAndArrows()) {
return true; // discard press if copy in progress
}
mGotCenterDown = true;
@@ -3961,13 +3823,16 @@
// Bubble up the key event if
// 1. it is a system key; or
// 2. the host application wants to handle it;
- if (event.isSystem() || mCallbackProxy.uiOverrideKeyEvent(event)) {
+ // 3. the accessibility injector is present and wants to handle it;
+ if (event.isSystem()
+ || mCallbackProxy.uiOverrideKeyEvent(event)
+ || (mAccessibilityInjector != null && mAccessibilityInjector.onKeyEvent(event))) {
return false;
}
if (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT
|| keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT) {
- if (nativeFocusIsPlugin()) {
+ if (nativePageShouldHandleShiftAndArrows()) {
mShiftIsPressed = false;
} else if (commitCopy()) {
return true;
@@ -3976,8 +3841,8 @@
if (keyCode >= KeyEvent.KEYCODE_DPAD_UP
&& keyCode <= KeyEvent.KEYCODE_DPAD_RIGHT) {
- if (nativeFocusIsPlugin()) {
- letPluginHandleNavKey(keyCode, event.getEventTime(), false);
+ if (nativePageShouldHandleShiftAndArrows()) {
+ letPageHandleNavKey(keyCode, event.getEventTime(), false);
return true;
}
// always handle the navigation keys in the UI thread
@@ -3990,7 +3855,7 @@
mPrivateHandler.removeMessages(LONG_PRESS_CENTER);
mGotCenterDown = false;
- if (mShiftIsPressed && !nativeFocusIsPlugin()) {
+ if (mShiftIsPressed && !nativePageShouldHandleShiftAndArrows()) {
if (mExtendSelection) {
commitCopy();
} else {
@@ -4104,11 +3969,19 @@
@Override
protected void onDetachedFromWindow() {
clearTextEntry(false);
- dismissZoomControl();
+ mZoomManager.dismissZoomPicker();
if (hasWindowFocus()) setActive(false);
super.onDetachedFromWindow();
}
+ @Override
+ protected void onVisibilityChanged(View changedView, int visibility) {
+ super.onVisibilityChanged(changedView, visibility);
+ if (visibility != View.VISIBLE) {
+ mZoomManager.dismissZoomPicker();
+ }
+ }
+
/**
* @deprecated WebView no longer needs to implement
* ViewGroup.OnHierarchyChangeListener. This method does nothing now.
@@ -4153,17 +4026,14 @@
// false for the first parameter
}
} else {
- if (mWebViewCore != null && getSettings().getBuiltInZoomControls()
- && (mZoomButtonsController == null ||
- !mZoomButtonsController.isVisible())) {
+ if (!mZoomManager.isZoomPickerVisible()) {
/*
- * The zoom controls come in their own window, so our window
- * loses focus. Our policy is to not draw the cursor ring if
- * our window is not focused, but this is an exception since
+ * The external zoom controls come in their own window, so our
+ * window loses focus. Our policy is to not draw the cursor ring
+ * if our window is not focused, but this is an exception since
* the user can still navigate the web page with the zoom
* controls showing.
*/
- // If our window has lost focus, stop drawing the cursor ring
mDrawCursorRing = false;
}
mGotKeyDown = false;
@@ -4252,81 +4122,24 @@
// system won't call onSizeChanged if the dimension is not changed.
// In this case, we need to call sendViewSizeZoom() explicitly to
// notify the WebKit about the new dimensions.
- sendViewSizeZoom();
+ sendViewSizeZoom(false);
}
return changed;
}
- private static class PostScale implements Runnable {
- final WebView mWebView;
- final boolean mUpdateTextWrap;
-
- public PostScale(WebView webView, boolean updateTextWrap) {
- mWebView = webView;
- mUpdateTextWrap = updateTextWrap;
- }
-
- public void run() {
- if (mWebView.mWebViewCore != null) {
- // we always force, in case our height changed, in which case we
- // still want to send the notification over to webkit.
- mWebView.setNewZoomScale(mWebView.mActualScale,
- mUpdateTextWrap, true);
- // update the zoom buttons as the scale can be changed
- if (mWebView.getSettings().getBuiltInZoomControls()) {
- mWebView.updateZoomButtonsEnabled();
- }
- }
- }
- }
-
@Override
protected void onSizeChanged(int w, int h, int ow, int oh) {
super.onSizeChanged(w, h, ow, oh);
- // Center zooming to the center of the screen.
- if (mZoomScale == 0) { // unless we're already zooming
- // To anchor at top left corner.
- mZoomCenterX = 0;
- mZoomCenterY = getVisibleTitleHeight();
- mAnchorX = viewToContentX((int) mZoomCenterX + mScrollX);
- mAnchorY = viewToContentY((int) mZoomCenterY + mScrollY);
- }
// adjust the max viewport width depending on the view dimensions. This
// is to ensure the scaling is not going insane. So do not shrink it if
// the view size is temporarily smaller, e.g. when soft keyboard is up.
- int newMaxViewportWidth = (int) (Math.max(w, h) / DEFAULT_MIN_ZOOM_SCALE);
+ int newMaxViewportWidth = (int) (Math.max(w, h) / ZoomManager.DEFAULT_MIN_ZOOM_SCALE);
if (newMaxViewportWidth > sMaxViewportWidth) {
sMaxViewportWidth = newMaxViewportWidth;
}
- // update mMinZoomScale if the minimum zoom scale is not fixed
- if (!mMinZoomScaleFixed) {
- // when change from narrow screen to wide screen, the new viewWidth
- // can be wider than the old content width. We limit the minimum
- // scale to 1.0f. The proper minimum scale will be calculated when
- // the new picture shows up.
- mMinZoomScale = Math.min(1.0f, (float) getViewWidth()
- / (mDrawHistory ? mHistoryPicture.getWidth()
- : mZoomOverviewWidth));
- if (mInitialScaleInPercent > 0) {
- // limit the minZoomScale to the initialScale if it is set
- float initialScale = mInitialScaleInPercent / 100.0f;
- if (mMinZoomScale > initialScale) {
- mMinZoomScale = initialScale;
- }
- }
- }
-
- dismissZoomControl();
-
- // onSizeChanged() is called during WebView layout. And any
- // requestLayout() is blocked during layout. As setNewZoomScale() will
- // call its child View to reposition itself through ViewManager's
- // scaleAll(), we need to post a Runnable to ensure requestLayout().
- // <b/>
- // only update the text wrap scale if width changed.
- post(new PostScale(this, w != ow));
+ mZoomManager.onSizeChanged(w, h, ow, oh);
}
@Override
@@ -4337,7 +4150,7 @@
// as getVisibleTitleHeight.
int titleHeight = getTitleHeight();
if (Math.max(titleHeight - t, 0) != Math.max(titleHeight - oldt, 0)) {
- sendViewSizeZoom();
+ sendViewSizeZoom(false);
}
}
@@ -4345,9 +4158,11 @@
public boolean dispatchKeyEvent(KeyEvent event) {
boolean dispatch = true;
- // Textfields and plugins need to receive the shift up key even if
- // another key was released while the shift key was held down.
- if (!inEditingMode() && (mNativeClass == 0 || !nativeFocusIsPlugin())) {
+ // Textfields, plugins, and contentEditable nodes need to receive the
+ // shift up key even if another key was released while the shift key
+ // was held down.
+ if (!inEditingMode() && (mNativeClass == 0
+ || !nativePageShouldHandleShiftAndArrows())) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
mGotKeyDown = true;
} else {
@@ -4581,81 +4396,6 @@
private DragTracker mDragTracker;
private DragTrackerHandler mDragTrackerHandler;
- private class ScaleDetectorListener implements
- ScaleGestureDetector.OnScaleGestureListener {
-
- public boolean onScaleBegin(ScaleGestureDetector detector) {
- // cancel the single touch handling
- cancelTouch();
- dismissZoomControl();
- // reset the zoom overview mode so that the page won't auto grow
- mInZoomOverview = false;
- // If it is in password mode, turn it off so it does not draw
- // misplaced.
- if (inEditingMode() && nativeFocusCandidateIsPassword()) {
- mWebTextView.setInPassword(false);
- }
-
- mViewManager.startZoom();
-
- return true;
- }
-
- public void onScaleEnd(ScaleGestureDetector detector) {
- if (mPreviewZoomOnly) {
- mPreviewZoomOnly = false;
- mAnchorX = viewToContentX((int) mZoomCenterX + mScrollX);
- mAnchorY = viewToContentY((int) mZoomCenterY + mScrollY);
- // don't reflow when zoom in; when zoom out, do reflow if the
- // new scale is almost minimum scale;
- boolean reflowNow = (mActualScale - mMinZoomScale
- <= MINIMUM_SCALE_INCREMENT)
- || ((mActualScale <= 0.8 * mTextWrapScale));
- // force zoom after mPreviewZoomOnly is set to false so that the
- // new view size will be passed to the WebKit
- setNewZoomScale(mActualScale, reflowNow, true);
- // call invalidate() to draw without zoom filter
- invalidate();
- }
- // adjust the edit text view if needed
- if (inEditingMode() && didUpdateTextViewBounds(false)
- && nativeFocusCandidateIsPassword()) {
- // If it is a password field, start drawing the
- // WebTextView once again.
- mWebTextView.setInPassword(true);
- }
- // start a drag, TOUCH_PINCH_DRAG, can't use TOUCH_INIT_MODE as it
- // may trigger the unwanted click, can't use TOUCH_DRAG_MODE as it
- // may trigger the unwanted fling.
- mTouchMode = TOUCH_PINCH_DRAG;
- mConfirmMove = true;
- startTouch(detector.getFocusX(), detector.getFocusY(),
- mLastTouchTime);
-
- mViewManager.endZoom();
- }
-
- public boolean onScale(ScaleGestureDetector detector) {
- float scale = (float) (Math.round(detector.getScaleFactor()
- * mActualScale * 100) / 100.0);
- if (Math.abs(scale - mActualScale) >= MINIMUM_SCALE_INCREMENT) {
- mPreviewZoomOnly = true;
- // limit the scale change per step
- if (scale > mActualScale) {
- scale = Math.min(scale, mActualScale * 1.25f);
- } else {
- scale = Math.max(scale, mActualScale * 0.8f);
- }
- mZoomCenterX = detector.getFocusX();
- mZoomCenterY = detector.getFocusY();
- setNewZoomScale(scale, false, false);
- invalidate();
- return true;
- }
- return false;
- }
- }
-
private boolean hitFocusedPlugin(int contentX, int contentY) {
if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "nativeFocusIsPlugin()=" + nativeFocusIsPlugin());
@@ -4677,6 +4417,22 @@
return mFullScreenHolder != null;
}
+ void onPinchToZoomAnimationStart() {
+ // cancel the single touch handling
+ cancelTouch();
+ onZoomAnimationStart();
+ }
+
+ void onPinchToZoomAnimationEnd(ScaleGestureDetector detector) {
+ onZoomAnimationEnd();
+ // start a drag, TOUCH_PINCH_DRAG, can't use TOUCH_INIT_MODE as
+ // it may trigger the unwanted click, can't use TOUCH_DRAG_MODE
+ // as it may trigger the unwanted fling.
+ mTouchMode = TOUCH_PINCH_DRAG;
+ mConfirmMove = true;
+ startTouch(detector.getFocusX(), detector.getFocusY(), mLastTouchTime);
+ }
+
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (mNativeClass == 0 || !isClickable() || !isLongClickable()) {
@@ -4694,32 +4450,36 @@
// FIXME: we may consider to give WebKit an option to handle multi-touch
// events later.
- if (mSupportMultiTouch && ev.getPointerCount() > 1) {
- if (mMinZoomScale < mMaxZoomScale) {
- mScaleDetector.onTouchEvent(ev);
- if (mScaleDetector.isInProgress()) {
- mLastTouchTime = eventTime;
+ if (mZoomManager.supportsMultiTouchZoom() && ev.getPointerCount() > 1) {
+
+ // if the page disallows zoom, then skip multi-pointer action
+ if (mZoomManager.isZoomScaleFixed()) {
+ return true;
+ }
+
+ ScaleGestureDetector detector = mZoomManager.getMultiTouchGestureDetector();
+ detector.onTouchEvent(ev);
+
+ if (detector.isInProgress()) {
+ mLastTouchTime = eventTime;
+ return true;
+ }
+
+ x = detector.getFocusX();
+ y = detector.getFocusY();
+ action = ev.getAction() & MotionEvent.ACTION_MASK;
+ if (action == MotionEvent.ACTION_POINTER_DOWN) {
+ cancelTouch();
+ action = MotionEvent.ACTION_DOWN;
+ } else if (action == MotionEvent.ACTION_POINTER_UP) {
+ // set mLastTouchX/Y to the remaining point
+ mLastTouchX = x;
+ mLastTouchY = y;
+ } else if (action == MotionEvent.ACTION_MOVE) {
+ // negative x or y indicate it is on the edge, skip it.
+ if (x < 0 || y < 0) {
return true;
}
- x = mScaleDetector.getFocusX();
- y = mScaleDetector.getFocusY();
- action = ev.getAction() & MotionEvent.ACTION_MASK;
- if (action == MotionEvent.ACTION_POINTER_DOWN) {
- cancelTouch();
- action = MotionEvent.ACTION_DOWN;
- } else if (action == MotionEvent.ACTION_POINTER_UP) {
- // set mLastTouchX/Y to the remaining point
- mLastTouchX = x;
- mLastTouchY = y;
- } else if (action == MotionEvent.ACTION_MOVE) {
- // negative x or y indicate it is on the edge, skip it.
- if (x < 0 || y < 0) {
- return true;
- }
- }
- } else {
- // if the page disallow zoom, skip multi-pointer action
- return true;
}
} else {
action = ev.getAction();
@@ -4769,6 +4529,9 @@
invalidate(); // draw the i-beam instead of the arrow
} else if (mPrivateHandler.hasMessages(RELEASE_SINGLE_TAP)) {
mPrivateHandler.removeMessages(RELEASE_SINGLE_TAP);
+ if (getSettings().supportTouchOnly()) {
+ removeTouchHighlight(true);
+ }
if (deltaX * deltaX + deltaY * deltaY < mDoubleTapSlopSquare) {
mTouchMode = TOUCH_DOUBLE_TAP_MODE;
} else {
@@ -4780,13 +4543,33 @@
contentX, contentY) : false;
}
} else { // the normal case
- mPreviewZoomOnly = false;
mTouchMode = TOUCH_INIT_MODE;
mDeferTouchProcess = (!inFullScreenMode()
&& mForwardTouchEvents) ? hitFocusedPlugin(
contentX, contentY) : false;
mWebViewCore.sendMessage(
EventHub.UPDATE_FRAME_CACHE_IF_LOADING);
+ if (getSettings().supportTouchOnly()) {
+ TouchHighlightData data = new TouchHighlightData();
+ data.mX = contentX;
+ data.mY = contentY;
+ data.mSlop = viewToContentDimension(mNavSlop);
+ mWebViewCore.sendMessageDelayed(
+ EventHub.GET_TOUCH_HIGHLIGHT_RECTS, data,
+ ViewConfiguration.getTapTimeout());
+ if (DEBUG_TOUCH_HIGHLIGHT) {
+ if (getSettings().getNavDump()) {
+ mTouchHighlightX = (int) x + mScrollX;
+ mTouchHighlightY = (int) y + mScrollY;
+ mPrivateHandler.postDelayed(new Runnable() {
+ public void run() {
+ mTouchHighlightX = mTouchHighlightY = 0;
+ invalidate();
+ }
+ }, TOUCH_HIGHLIGHT_ELAPSE_TIME);
+ }
+ }
+ }
if (mLogEvent && eventTime - mLastTouchUpTime < 1000) {
EventLog.writeEvent(EventLogTags.BROWSER_DOUBLE_TAP_DURATION,
(eventTime - mLastTouchUpTime), eventTime);
@@ -4814,17 +4597,15 @@
ted.mY = contentY;
ted.mMetaState = ev.getMetaState();
ted.mReprocess = mDeferTouchProcess;
+ mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
if (mDeferTouchProcess) {
// still needs to set them for compute deltaX/Y
mLastTouchX = x;
mLastTouchY = y;
- ted.mViewX = x;
- ted.mViewY = y;
- mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
break;
}
- mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
if (!inFullScreenMode()) {
+ mPrivateHandler.removeMessages(PREVENT_DEFAULT_TIMEOUT);
mPrivateHandler.sendMessageDelayed(mPrivateHandler
.obtainMessage(PREVENT_DEFAULT_TIMEOUT,
action, 0), TAP_TIMEOUT);
@@ -4845,24 +4626,24 @@
if (mTouchMode == TOUCH_DOUBLE_TAP_MODE) {
mTouchMode = TOUCH_INIT_MODE;
}
+ if (getSettings().supportTouchOnly()) {
+ removeTouchHighlight(true);
+ }
}
// pass the touch events from UI thread to WebCore thread
if (shouldForwardTouchEvent() && mConfirmMove && (firstMove
|| eventTime - mLastSentTouchTime > mCurrentTouchInterval)) {
- mLastSentTouchTime = eventTime;
TouchEventData ted = new TouchEventData();
ted.mAction = action;
ted.mX = contentX;
ted.mY = contentY;
ted.mMetaState = ev.getMetaState();
ted.mReprocess = mDeferTouchProcess;
+ mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
+ mLastSentTouchTime = eventTime;
if (mDeferTouchProcess) {
- ted.mViewX = x;
- ted.mViewY = y;
- mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
break;
}
- mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
if (firstMove && !inFullScreenMode()) {
mPrivateHandler.sendMessageDelayed(mPrivateHandler
.obtainMessage(PREVENT_DEFAULT_TIMEOUT,
@@ -4893,9 +4674,11 @@
invalidate();
break;
}
+
if (!mConfirmMove) {
break;
}
+
if (mPreventDefault == PREVENT_DEFAULT_MAYBE_YES
|| mPreventDefault == PREVENT_DEFAULT_NO_FROM_TOUCH_DOWN) {
// track mLastTouchTime as we may need to do fling at
@@ -5023,6 +4806,7 @@
break;
}
case MotionEvent.ACTION_UP: {
+ if (!isFocused()) requestFocus();
// pass the touch events from UI thread to WebCore thread
if (shouldForwardTouchEvent()) {
TouchEventData ted = new TouchEventData();
@@ -5031,10 +4815,6 @@
ted.mY = contentY;
ted.mMetaState = ev.getMetaState();
ted.mReprocess = mDeferTouchProcess;
- if (mDeferTouchProcess) {
- ted.mViewX = x;
- ted.mViewY = y;
- }
mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
}
mLastTouchUpTime = eventTime;
@@ -5049,10 +4829,6 @@
ted.mY = contentY;
ted.mMetaState = ev.getMetaState();
ted.mReprocess = mDeferTouchProcess;
- if (mDeferTouchProcess) {
- ted.mViewX = x;
- ted.mViewY = y;
- }
mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
} else if (mPreventDefault != PREVENT_DEFAULT_YES){
doDoubleTap();
@@ -5074,9 +4850,17 @@
if (mPreventDefault != PREVENT_DEFAULT_YES
&& (computeMaxScrollX() > 0
|| computeMaxScrollY() > 0)) {
- // UI takes control back, cancel WebCore touch
- cancelWebCoreTouchEvent(contentX, contentY,
- true);
+ // If the user has performed a very quick touch
+ // sequence it is possible that we may get here
+ // before WebCore has had a chance to process the events.
+ // In this case, any call to preventDefault in the
+ // JS touch handler will not have been executed yet.
+ // Hence we will see both the UI (now) and WebCore
+ // (when context switches) handling the event,
+ // regardless of whether the web developer actually
+ // doeses preventDefault in their touch handler. This
+ // is the nature of our asynchronous touch model.
+
// we will not rewrite drag code here, but we
// will try fling if it applies.
WebViewCore.reducePriority();
@@ -5093,7 +4877,10 @@
break;
}
} else {
- if (mTouchMode == TOUCH_INIT_MODE) {
+ // only trigger double tap if the WebView is
+ // scalable
+ if (mTouchMode == TOUCH_INIT_MODE
+ && (canZoomIn() || canZoomOut())) {
mPrivateHandler.sendEmptyMessageDelayed(
RELEASE_SINGLE_TAP, ViewConfiguration
.getDoubleTapTimeout());
@@ -5184,21 +4971,10 @@
if (!mDragFromTextInput) {
nativeHideCursor();
}
- WebSettings settings = getSettings();
- if (settings.supportZoom()
- && settings.getBuiltInZoomControls()
- && !getZoomButtonsController().isVisible()
- && mMinZoomScale < mMaxZoomScale
- && (mHorizontalScrollBarMode != SCROLLBAR_ALWAYSOFF
- || mVerticalScrollBarMode != SCROLLBAR_ALWAYSOFF)) {
- mZoomButtonsController.setVisible(true);
- int count = settings.getDoubleTapToastCount();
- if (mInZoomOverview && count > 0) {
- settings.setDoubleTapToastCount(--count);
- Toast.makeText(mContext,
- com.android.internal.R.string.double_tap_toast,
- Toast.LENGTH_LONG).show();
- }
+
+ if (mHorizontalScrollBarMode != SCROLLBAR_ALWAYSOFF
+ || mVerticalScrollBarMode != SCROLLBAR_ALWAYSOFF) {
+ mZoomManager.invokeZoomPicker();
}
}
@@ -5206,18 +4982,7 @@
if ((deltaX | deltaY) != 0) {
scrollBy(deltaX, deltaY);
}
- if (!getSettings().getBuiltInZoomControls()) {
- boolean showPlusMinus = mMinZoomScale < mMaxZoomScale;
- if (mZoomControls != null && showPlusMinus) {
- if (mZoomControls.getVisibility() == View.VISIBLE) {
- mPrivateHandler.removeCallbacks(mZoomControlRunnable);
- } else {
- mZoomControls.show(showPlusMinus, false);
- }
- mPrivateHandler.postDelayed(mZoomControlRunnable,
- ZOOM_CONTROLS_TIMEOUT);
- }
- }
+ mZoomManager.keepZoomPickerVisible();
}
private void stopTouch() {
@@ -5252,6 +5017,9 @@
mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
mPrivateHandler.removeMessages(DRAG_HELD_MOTIONLESS);
mPrivateHandler.removeMessages(AWAKEN_SCROLL_BARS);
+ if (getSettings().supportTouchOnly()) {
+ removeTouchHighlight(true);
+ }
mHeldMotionless = MOTIONLESS_TRUE;
mTouchMode = TOUCH_DONE_MODE;
nativeHideCursor();
@@ -5304,7 +5072,7 @@
return true;
}
boolean shiftPressed = mShiftIsPressed && (mNativeClass == 0
- || !nativeFocusIsPlugin());
+ || !nativePageShouldHandleShiftAndArrows());
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
if (shiftPressed) {
return true; // discard press if copy in progress
@@ -5469,7 +5237,8 @@
float yRate = mTrackballRemainsY * 1000 / elapsed;
int viewWidth = getViewWidth();
int viewHeight = getViewHeight();
- if (mShiftIsPressed && (mNativeClass == 0 || !nativeFocusIsPlugin())) {
+ if (mShiftIsPressed && (mNativeClass == 0
+ || !nativePageShouldHandleShiftAndArrows())) {
moveSelection(scaleTrackballX(xRate, viewWidth),
scaleTrackballY(yRate, viewHeight));
mTrackballRemainsX = mTrackballRemainsY = 0;
@@ -5507,11 +5276,11 @@
+ " mTrackballRemainsX=" + mTrackballRemainsX
+ " mTrackballRemainsY=" + mTrackballRemainsY);
}
- if (mNativeClass != 0 && nativeFocusIsPlugin()) {
+ if (mNativeClass != 0 && nativePageShouldHandleShiftAndArrows()) {
for (int i = 0; i < count; i++) {
- letPluginHandleNavKey(selectKeyCode, time, true);
+ letPageHandleNavKey(selectKeyCode, time, true);
}
- letPluginHandleNavKey(selectKeyCode, time, false);
+ letPageHandleNavKey(selectKeyCode, time, false);
} else if (navHandledKey(selectKeyCode, count, false, time)) {
playSoundEffect(keyCodeToSoundsEffect(selectKeyCode));
}
@@ -5550,6 +5319,19 @@
- getViewHeightWithTitle(), 0);
}
+ boolean updateScrollCoordinates(int x, int y) {
+ int oldX = mScrollX;
+ int oldY = mScrollY;
+ mScrollX = x;
+ mScrollY = y;
+ if (oldX != mScrollX || oldY != mScrollY) {
+ onScrollChanged(mScrollX, mScrollY, oldX, oldY);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
public void flingScroll(int vx, int vy) {
mScroller.fling(mScrollX, mScrollY, vx, vy, 0, computeMaxScrollX(), 0,
computeMaxScrollY());
@@ -5585,13 +5367,16 @@
return;
}
float currentVelocity = mScroller.getCurrVelocity();
- if (mLastVelocity > 0 && currentVelocity > 0) {
+ float velocity = (float) Math.hypot(vx, vy);
+ if (mLastVelocity > 0 && currentVelocity > 0 && velocity
+ > mLastVelocity * MINIMUM_VELOCITY_RATIO_FOR_ACCELERATION) {
float deltaR = (float) (Math.abs(Math.atan2(mLastVelY, mLastVelX)
- Math.atan2(vy, vx)));
final float circle = (float) (Math.PI) * 2.0f;
if (deltaR > circle * 0.9f || deltaR < circle * 0.1f) {
vx += currentVelocity * mLastVelX / mLastVelocity;
vy += currentVelocity * mLastVelY / mLastVelocity;
+ velocity = (float) Math.hypot(vx, vy);
if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "doFling vx= " + vx + " vy=" + vy);
}
@@ -5607,7 +5392,7 @@
}
mLastVelX = vx;
mLastVelY = vy;
- mLastVelocity = (float) Math.hypot(vx, vy);
+ mLastVelocity = velocity;
mScroller.fling(mScrollX, mScrollY, -vx, -vy, 0, maxX, 0, maxY);
// TODO: duration is calculated based on velocity, if the range is
@@ -5620,32 +5405,6 @@
invalidate();
}
- private boolean zoomWithPreview(float scale, boolean updateTextWrapScale) {
- float oldScale = mActualScale;
- mInitialScrollX = mScrollX;
- mInitialScrollY = mScrollY;
-
- // snap to DEFAULT_SCALE if it is close
- if (Math.abs(scale - mDefaultScale) < MINIMUM_SCALE_INCREMENT) {
- scale = mDefaultScale;
- }
-
- setNewZoomScale(scale, updateTextWrapScale, false);
-
- if (oldScale != mActualScale) {
- // use mZoomPickerScale to see zoom preview first
- mZoomStart = SystemClock.uptimeMillis();
- mInvInitialZoomScale = 1.0f / oldScale;
- mInvFinalZoomScale = 1.0f / mActualScale;
- mZoomScale = mActualScale;
- WebViewCore.pauseUpdatePicture(mWebViewCore);
- invalidate();
- return true;
- } else {
- return false;
- }
- }
-
/**
* Returns a view containing zoom controls i.e. +/- buttons. The caller is
* in charge of installing this view to the view hierarchy. This view will
@@ -5665,81 +5424,29 @@
Log.w(LOGTAG, "This WebView doesn't support zoom.");
return null;
}
- if (mZoomControls == null) {
- mZoomControls = createZoomControls();
-
- /*
- * need to be set to VISIBLE first so that getMeasuredHeight() in
- * {@link #onSizeChanged()} can return the measured value for proper
- * layout.
- */
- mZoomControls.setVisibility(View.VISIBLE);
- mZoomControlRunnable = new Runnable() {
- public void run() {
-
- /* Don't dismiss the controls if the user has
- * focus on them. Wait and check again later.
- */
- if (!mZoomControls.hasFocus()) {
- mZoomControls.hide();
- } else {
- mPrivateHandler.removeCallbacks(mZoomControlRunnable);
- mPrivateHandler.postDelayed(mZoomControlRunnable,
- ZOOM_CONTROLS_TIMEOUT);
- }
- }
- };
- }
- return mZoomControls;
+ return mZoomManager.getExternalZoomPicker();
}
- private ExtendedZoomControls createZoomControls() {
- ExtendedZoomControls zoomControls = new ExtendedZoomControls(mContext
- , null);
- zoomControls.setOnZoomInClickListener(new OnClickListener() {
- public void onClick(View v) {
- // reset time out
- mPrivateHandler.removeCallbacks(mZoomControlRunnable);
- mPrivateHandler.postDelayed(mZoomControlRunnable,
- ZOOM_CONTROLS_TIMEOUT);
- zoomIn();
- }
- });
- zoomControls.setOnZoomOutClickListener(new OnClickListener() {
- public void onClick(View v) {
- // reset time out
- mPrivateHandler.removeCallbacks(mZoomControlRunnable);
- mPrivateHandler.postDelayed(mZoomControlRunnable,
- ZOOM_CONTROLS_TIMEOUT);
- zoomOut();
- }
- });
- return zoomControls;
+ void dismissZoomControl() {
+ mZoomManager.dismissZoomPicker();
+ }
+
+ float getDefaultZoomScale() {
+ return mZoomManager.getDefaultScale();
}
/**
- * Gets the {@link ZoomButtonsController} which can be used to add
- * additional buttons to the zoom controls window.
- *
- * @return The instance of {@link ZoomButtonsController} used by this class,
- * or null if it is unavailable.
- * @hide
+ * @return TRUE if the WebView can be zoomed in.
*/
- public ZoomButtonsController getZoomButtonsController() {
- if (mZoomButtonsController == null) {
- mZoomButtonsController = new ZoomButtonsController(this);
- mZoomButtonsController.setOnZoomListener(mZoomListener);
- // ZoomButtonsController positions the buttons at the bottom, but in
- // the middle. Change their layout parameters so they appear on the
- // right.
- View controls = mZoomButtonsController.getZoomControls();
- ViewGroup.LayoutParams params = controls.getLayoutParams();
- if (params instanceof FrameLayout.LayoutParams) {
- FrameLayout.LayoutParams frameParams = (FrameLayout.LayoutParams) params;
- frameParams.gravity = Gravity.RIGHT;
- }
- }
- return mZoomButtonsController;
+ public boolean canZoomIn() {
+ return mZoomManager.canZoomIn();
+ }
+
+ /**
+ * @return TRUE if the WebView can be zoomed out.
+ */
+ public boolean canZoomOut() {
+ return mZoomManager.canZoomOut();
}
/**
@@ -5747,15 +5454,7 @@
* @return TRUE if zoom in succeeds. FALSE if no zoom changes.
*/
public boolean zoomIn() {
- // TODO: alternatively we can disallow this during draw history mode
- switchOutDrawHistory();
- mInZoomOverview = false;
- // Center zooming to the center of the screen.
- mZoomCenterX = getViewWidth() * .5f;
- mZoomCenterY = getViewHeight() * .5f;
- mAnchorX = viewToContentX((int) mZoomCenterX + mScrollX);
- mAnchorY = viewToContentY((int) mZoomCenterY + mScrollY);
- return zoomWithPreview(mActualScale * 1.25f, true);
+ return mZoomManager.zoomIn();
}
/**
@@ -5763,14 +5462,7 @@
* @return TRUE if zoom out succeeds. FALSE if no zoom changes.
*/
public boolean zoomOut() {
- // TODO: alternatively we can disallow this during draw history mode
- switchOutDrawHistory();
- // Center zooming to the center of the screen.
- mZoomCenterX = getViewWidth() * .5f;
- mZoomCenterY = getViewHeight() * .5f;
- mAnchorX = viewToContentX((int) mZoomCenterX + mScrollX);
- mAnchorY = viewToContentY((int) mZoomCenterY + mScrollY);
- return zoomWithPreview(mActualScale * 0.8f, true);
+ return mZoomManager.zoomOut();
}
private void updateSelection() {
@@ -5871,7 +5563,14 @@
// mLastTouchX and mLastTouchY are the point in the current viewport
int contentX = viewToContentX((int) mLastTouchX + mScrollX);
int contentY = viewToContentY((int) mLastTouchY + mScrollY);
- if (nativePointInNavCache(contentX, contentY, mNavSlop)) {
+ if (getSettings().supportTouchOnly()) {
+ removeTouchHighlight(false);
+ WebViewCore.TouchUpData touchUpData = new WebViewCore.TouchUpData();
+ // use "0" as generation id to inform WebKit to use the same x/y as
+ // it used when processing GET_TOUCH_HIGHLIGHT_RECTS
+ touchUpData.mMoveGeneration = 0;
+ mWebViewCore.sendMessage(EventHub.TOUCH_UP, touchUpData);
+ } else if (nativePointInNavCache(contentX, contentY, mNavSlop)) {
WebViewCore.MotionUpData motionUpData = new WebViewCore
.MotionUpData();
motionUpData.mFrame = nativeCacheHitFramePointer();
@@ -5904,12 +5603,8 @@
int viewHeight = getViewHeightWithTitle();
float scale = Math.min((float) viewWidth / view.width,
(float) viewHeight / view.height);
- if (scale < mMinZoomScale) {
- scale = mMinZoomScale;
- } else if (scale > mMaxZoomScale) {
- scale = mMaxZoomScale;
- }
- if (Math.abs(scale - mActualScale) < MINIMUM_SCALE_INCREMENT) {
+ scale = mZoomManager.computeScaleWithLimits(scale);
+ if (!mZoomManager.willScaleTriggerZoom(scale)) {
if (contentToViewX(view.x) >= mScrollX
&& contentToViewX(view.x + view.width) <= mScrollX
+ viewWidth
@@ -5933,17 +5628,14 @@
int viewHeight = getViewHeightWithTitle();
float scale = Math.min((float) viewWidth / docWidth, (float) viewHeight
/ docHeight);
- if (scale < mMinZoomScale) {
- scale = mMinZoomScale;
- } else if (scale > mMaxZoomScale) {
- scale = mMaxZoomScale;
- }
- if (Math.abs(scale - mActualScale) < MINIMUM_SCALE_INCREMENT) {
+ scale = mZoomManager.computeScaleWithLimits(scale);
+ if (!mZoomManager.willScaleTriggerZoom(scale)) {
pinScrollTo(contentToViewX(docX + docWidth / 2) - viewWidth / 2,
contentToViewY(docY + docHeight / 2) - viewHeight / 2,
true, 0);
} else {
- float oldScreenX = docX * mActualScale - mScrollX;
+ float actualScale = mZoomManager.mActualScale;
+ float oldScreenX = docX * actualScale - mScrollX;
float rectViewX = docX * scale;
float rectViewWidth = docWidth * scale;
float newMaxWidth = mContentWidth * scale;
@@ -5954,9 +5646,9 @@
} else if (newScreenX > (newMaxWidth - rectViewX - rectViewWidth)) {
newScreenX = viewWidth - (newMaxWidth - rectViewX);
}
- mZoomCenterX = (oldScreenX * scale - newScreenX * mActualScale)
- / (scale - mActualScale);
- float oldScreenY = docY * mActualScale + getTitleHeight()
+ float zoomCenterX = (oldScreenX * scale - newScreenX * actualScale)
+ / (scale - actualScale);
+ float oldScreenY = docY * actualScale + getTitleHeight()
- mScrollY;
float rectViewY = docY * scale + getTitleHeight();
float rectViewHeight = docHeight * scale;
@@ -5968,36 +5660,10 @@
} else if (newScreenY > (newMaxHeight - rectViewY - rectViewHeight)) {
newScreenY = viewHeight - (newMaxHeight - rectViewY);
}
- mZoomCenterY = (oldScreenY * scale - newScreenY * mActualScale)
- / (scale - mActualScale);
- zoomWithPreview(scale, false);
- }
- }
-
- void dismissZoomControl() {
- if (mWebViewCore == null) {
- // maybe called after WebView's destroy(). As we can't get settings,
- // just hide zoom control for both styles.
- if (mZoomButtonsController != null) {
- mZoomButtonsController.setVisible(false);
- }
- if (mZoomControls != null) {
- mZoomControls.hide();
- }
- return;
- }
- WebSettings settings = getSettings();
- if (settings.getBuiltInZoomControls()) {
- if (mZoomButtonsController != null) {
- mZoomButtonsController.setVisible(false);
- }
- } else {
- if (mZoomControlRunnable != null) {
- mPrivateHandler.removeCallbacks(mZoomControlRunnable);
- }
- if (mZoomControls != null) {
- mZoomControls.hide();
- }
+ float zoomCenterY = (oldScreenY * scale - newScreenY * actualScale)
+ / (scale - actualScale);
+ mZoomManager.setZoomCenter(zoomCenterX, zoomCenterY);
+ mZoomManager.startZoomAnimation(scale, false);
}
}
@@ -6010,52 +5676,43 @@
if (mWebViewCore.getSettings().getUseWideViewPort() == false) {
return;
}
- mZoomCenterX = mLastTouchX;
- mZoomCenterY = mLastTouchY;
- mAnchorX = viewToContentX((int) mZoomCenterX + mScrollX);
- mAnchorY = viewToContentY((int) mZoomCenterY + mScrollY);
+ mZoomManager.setZoomCenter(mLastTouchX, mLastTouchY);
+ mAnchorX = viewToContentX((int) mLastTouchX + mScrollX);
+ mAnchorY = viewToContentY((int) mLastTouchX + mScrollY);
WebSettings settings = getSettings();
settings.setDoubleTapToastCount(0);
// remove the zoom control after double tap
- dismissZoomControl();
+ mZoomManager.dismissZoomPicker();
ViewManager.ChildView plugin = mViewManager.hitTest(mAnchorX, mAnchorY);
if (plugin != null) {
if (isPluginFitOnScreen(plugin)) {
- mInZoomOverview = true;
- // Force the titlebar fully reveal in overview mode
- if (mScrollY < getTitleHeight()) mScrollY = 0;
- zoomWithPreview((float) getViewWidth() / mZoomOverviewWidth,
- true);
+ mZoomManager.zoomToOverview();
} else {
- mInZoomOverview = false;
+ mZoomManager.mInZoomOverview = false;
centerFitRect(plugin.x, plugin.y, plugin.width, plugin.height);
}
return;
}
boolean zoomToDefault = false;
if ((settings.getLayoutAlgorithm() == WebSettings.LayoutAlgorithm.NARROW_COLUMNS)
- && (Math.abs(mActualScale - mTextWrapScale) >= MINIMUM_SCALE_INCREMENT)) {
- setNewZoomScale(mActualScale, true, true);
- float overviewScale = (float) getViewWidth() / mZoomOverviewWidth;
- if (Math.abs(mActualScale - overviewScale) < MINIMUM_SCALE_INCREMENT) {
- mInZoomOverview = true;
+ && mZoomManager.willScaleTriggerZoom(mZoomManager.mTextWrapScale)) {
+ mZoomManager.refreshZoomScale(true);
+ float overviewScale = (float) getViewWidth() / mZoomManager.mZoomOverviewWidth;
+ if (!mZoomManager.willScaleTriggerZoom(overviewScale)) {
+ mZoomManager.mInZoomOverview = true;
}
- } else if (!mInZoomOverview) {
- float newScale = (float) getViewWidth() / mZoomOverviewWidth;
- if (Math.abs(mActualScale - newScale) >= MINIMUM_SCALE_INCREMENT) {
- mInZoomOverview = true;
- // Force the titlebar fully reveal in overview mode
- if (mScrollY < getTitleHeight()) mScrollY = 0;
- zoomWithPreview(newScale, true);
- } else if (Math.abs(mActualScale - mDefaultScale) >= MINIMUM_SCALE_INCREMENT) {
+ } else if (!mZoomManager.mInZoomOverview) {
+ float newScale = (float) getViewWidth() / mZoomManager.mZoomOverviewWidth;
+ if (mZoomManager.willScaleTriggerZoom(newScale)) {
+ mZoomManager.zoomToOverview();
+ } else if (mZoomManager.willScaleTriggerZoom(mZoomManager.getDefaultScale())) {
zoomToDefault = true;
}
} else {
zoomToDefault = true;
}
if (zoomToDefault) {
- mInZoomOverview = false;
- int left = nativeGetBlockLeftEdge(mAnchorX, mAnchorY, mActualScale);
+ int left = nativeGetBlockLeftEdge(mAnchorX, mAnchorY, mZoomManager.mActualScale);
if (left != NO_LEFTEDGE) {
// add a 5pt padding to the left edge.
int viewLeft = contentToViewX(left < 5 ? 0 : (left - 5))
@@ -6063,14 +5720,14 @@
// Re-calculate the zoom center so that the new scroll x will be
// on the left edge.
if (viewLeft > 0) {
- mZoomCenterX = viewLeft * mDefaultScale
- / (mDefaultScale - mActualScale);
+ mZoomManager.mZoomCenterX = viewLeft * mZoomManager.getDefaultScale()
+ / (mZoomManager.getDefaultScale() - mZoomManager.mActualScale);
} else {
scrollBy(viewLeft, 0);
- mZoomCenterX = 0;
+ mZoomManager.mZoomCenterX = 0;
}
}
- zoomWithPreview(mDefaultScale, true);
+ mZoomManager.zoomToDefaultLevel(true);
}
}
@@ -6082,6 +5739,9 @@
@Override
public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
+ // FIXME: If a subwindow is showing find, and the user touches the
+ // background window, it can steal focus.
+ if (mFindIsUp) return false;
boolean result = false;
if (inEditingMode()) {
result = mWebTextView.requestFocus(direction,
@@ -6169,6 +5829,12 @@
public boolean requestChildRectangleOnScreen(View child,
Rect rect,
boolean immediate) {
+ // don't scroll while in zoom animation. When it is done, we will adjust
+ // the necessary components (e.g., WebTextView if it is in editing mode)
+ if (mZoomManager.isFixedLengthAnimationInProgress()) {
+ return false;
+ }
+
rect.offset(child.getLeft() - child.getScrollX(),
child.getTop() - child.getScrollY());
@@ -6311,7 +5977,8 @@
}
case SWITCH_TO_SHORTPRESS: {
if (mTouchMode == TOUCH_INIT_MODE) {
- if (mPreventDefault != PREVENT_DEFAULT_YES) {
+ if (!getSettings().supportTouchOnly()
+ && mPreventDefault != PREVENT_DEFAULT_YES) {
mTouchMode = TOUCH_SHORTPRESS_START_MODE;
updateSelection();
} else {
@@ -6325,6 +5992,9 @@
break;
}
case SWITCH_TO_LONGPRESS: {
+ if (getSettings().supportTouchOnly()) {
+ removeTouchHighlight(false);
+ }
if (inFullScreenMode() || mDeferTouchProcess) {
TouchEventData ted = new TouchEventData();
ted.mAction = WebViewCore.ACTION_LONGPRESS;
@@ -6336,15 +6006,10 @@
// simplicity for now, we don't set it.
ted.mMetaState = 0;
ted.mReprocess = mDeferTouchProcess;
- if (mDeferTouchProcess) {
- ted.mViewX = mLastTouchX;
- ted.mViewY = mLastTouchY;
- }
mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
} else if (mPreventDefault != PREVENT_DEFAULT_YES) {
mTouchMode = TOUCH_DONE_MODE;
performLongClick();
- rebuildWebTextView();
}
break;
}
@@ -6380,7 +6045,7 @@
WebViewCore.RestoreState restoreState
= (WebViewCore.RestoreState) msg.obj;
// mScrollX contains the new minPrefWidth
- updateZoomRange(restoreState, getViewWidth(),
+ mZoomManager.updateZoomRange(restoreState, getViewWidth(),
restoreState.mScrollX, false);
break;
}
@@ -6391,56 +6056,24 @@
mDelayedDeleteRootLayer = false;
nativeSetRootLayer(0);
}
- WebSettings settings = mWebViewCore.getSettings();
// called for new content
- final int viewWidth = getViewWidth();
- final WebViewCore.DrawData draw =
- (WebViewCore.DrawData) msg.obj;
+ final WebViewCore.DrawData draw = (WebViewCore.DrawData) msg.obj;
+
final Point viewSize = draw.mViewPoint;
- boolean useWideViewport = settings.getUseWideViewPort();
WebViewCore.RestoreState restoreState = draw.mRestoreState;
boolean hasRestoreState = restoreState != null;
if (hasRestoreState) {
- updateZoomRange(restoreState, viewSize.x,
- draw.mMinPrefWidth, true);
+ mZoomManager.restoreZoomState(draw);
if (!mDrawHistory) {
- mInZoomOverview = false;
-
- if (mInitialScaleInPercent > 0) {
- setNewZoomScale(mInitialScaleInPercent / 100.0f,
- mInitialScaleInPercent != mTextWrapScale * 100,
- false);
- } else if (restoreState.mViewScale > 0) {
- mTextWrapScale = restoreState.mTextWrapScale;
- setNewZoomScale(restoreState.mViewScale, false,
- false);
- } else {
- mInZoomOverview = useWideViewport
- && settings.getLoadWithOverviewMode();
- float scale;
- if (mInZoomOverview) {
- scale = (float) viewWidth
- / DEFAULT_VIEWPORT_WIDTH;
- } else {
- scale = restoreState.mTextWrapScale;
- }
- setNewZoomScale(scale, Math.abs(scale
- - mTextWrapScale) >= MINIMUM_SCALE_INCREMENT,
- false);
- }
- setContentScrollTo(restoreState.mScrollX,
- restoreState.mScrollY);
+ setContentScrollTo(restoreState.mScrollX, restoreState.mScrollY);
// As we are on a new page, remove the WebTextView. This
// is necessary for page loads driven by webkit, and in
// particular when the user was on a password field, so
// the WebTextView was visible.
clearTextEntry(false);
- // update the zoom buttons as the scale can be changed
- if (getSettings().getBuiltInZoomControls()) {
- updateZoomButtonsEnabled();
- }
}
}
+
// We update the layout (i.e. request a layout from the
// view system) if the last view size that we sent to
// WebCore matches the view size of the picture we just
@@ -6448,41 +6081,21 @@
final boolean updateLayout = viewSize.x == mLastWidthSent
&& viewSize.y == mLastHeightSent;
recordNewContentSize(draw.mWidthHeight.x,
- draw.mWidthHeight.y
- + (mFindIsUp ? mFindHeight : 0), updateLayout);
+ draw.mWidthHeight.y, updateLayout);
if (DebugFlags.WEB_VIEW) {
Rect b = draw.mInvalRegion.getBounds();
Log.v(LOGTAG, "NEW_PICTURE_MSG_ID {" +
b.left+","+b.top+","+b.right+","+b.bottom+"}");
}
invalidateContentRect(draw.mInvalRegion.getBounds());
+
if (mPictureListener != null) {
mPictureListener.onNewPicture(WebView.this, capturePicture());
}
- if (useWideViewport) {
- // limit mZoomOverviewWidth upper bound to
- // sMaxViewportWidth so that if the page doesn't behave
- // well, the WebView won't go insane. limit the lower
- // bound to match the default scale for mobile sites.
- mZoomOverviewWidth = Math.min(sMaxViewportWidth, Math
- .max((int) (viewWidth / mDefaultScale), Math
- .max(draw.mMinPrefWidth,
- draw.mViewPoint.x)));
- }
- if (!mMinZoomScaleFixed) {
- mMinZoomScale = (float) viewWidth / mZoomOverviewWidth;
- }
- if (!mDrawHistory && mInZoomOverview) {
- // fit the content width to the current view. Ignore
- // the rounding error case.
- if (Math.abs((viewWidth * mInvActualScale)
- - mZoomOverviewWidth) > 1) {
- setNewZoomScale((float) viewWidth
- / mZoomOverviewWidth, Math.abs(mActualScale
- - mTextWrapScale) < MINIMUM_SCALE_INCREMENT,
- false);
- }
- }
+
+ // update the zoom information based on the new picture
+ mZoomManager.onNewPicture(draw);
+
if (draw.mFocusSizeChanged && inEditingMode()) {
mFocusSizeChanged = true;
}
@@ -6520,14 +6133,8 @@
break;
case REQUEST_KEYBOARD_WITH_SELECTION_MSG_ID:
displaySoftKeyboard(true);
- updateTextSelectionFromMessage(msg.arg1, msg.arg2,
- (WebViewCore.TextSelectionData) msg.obj);
- break;
+ // fall through to UPDATE_TEXT_SELECTION_MSG_ID
case UPDATE_TEXT_SELECTION_MSG_ID:
- // If no textfield was in focus, and the user touched one,
- // causing it to send this message, then WebTextView has not
- // been set up yet. Rebuild it so it can set its selection.
- rebuildWebTextView();
updateTextSelectionFromMessage(msg.arg1, msg.arg2,
(WebViewCore.TextSelectionData) msg.obj);
break;
@@ -6545,7 +6152,7 @@
}
}
break;
- case MOVE_OUT_OF_PLUGIN:
+ case UNHANDLED_NAV_KEY:
navHandledKey(msg.arg1, 1, false, 0);
break;
case UPDATE_TEXT_ENTRY_MSG_ID:
@@ -6630,33 +6237,40 @@
mPreventDefault = msg.arg2 == 1 ? PREVENT_DEFAULT_YES
: PREVENT_DEFAULT_NO;
}
+ if (mPreventDefault == PREVENT_DEFAULT_YES) {
+ mTouchHighlightRegion.setEmpty();
+ }
} else if (msg.arg2 == 0) {
// prevent default is not called in WebCore, so the
// message needs to be reprocessed in UI
TouchEventData ted = (TouchEventData) msg.obj;
switch (ted.mAction) {
case MotionEvent.ACTION_DOWN:
- mLastDeferTouchX = ted.mViewX;
- mLastDeferTouchY = ted.mViewY;
+ mLastDeferTouchX = contentToViewX(ted.mX)
+ - mScrollX;
+ mLastDeferTouchY = contentToViewY(ted.mY)
+ - mScrollY;
mDeferTouchMode = TOUCH_INIT_MODE;
break;
case MotionEvent.ACTION_MOVE: {
// no snapping in defer process
+ int x = contentToViewX(ted.mX) - mScrollX;
+ int y = contentToViewY(ted.mY) - mScrollY;
if (mDeferTouchMode != TOUCH_DRAG_MODE) {
mDeferTouchMode = TOUCH_DRAG_MODE;
- mLastDeferTouchX = ted.mViewX;
- mLastDeferTouchY = ted.mViewY;
+ mLastDeferTouchX = x;
+ mLastDeferTouchY = y;
startDrag();
}
int deltaX = pinLocX((int) (mScrollX
- + mLastDeferTouchX - ted.mViewX))
+ + mLastDeferTouchX - x))
- mScrollX;
int deltaY = pinLocY((int) (mScrollY
- + mLastDeferTouchY - ted.mViewY))
+ + mLastDeferTouchY - y))
- mScrollY;
doDrag(deltaX, deltaY);
- if (deltaX != 0) mLastDeferTouchX = ted.mViewX;
- if (deltaY != 0) mLastDeferTouchY = ted.mViewY;
+ if (deltaX != 0) mLastDeferTouchX = x;
+ if (deltaY != 0) mLastDeferTouchY = y;
break;
}
case MotionEvent.ACTION_UP:
@@ -6670,8 +6284,8 @@
break;
case WebViewCore.ACTION_DOUBLETAP:
// doDoubleTap() needs mLastTouchX/Y as anchor
- mLastTouchX = ted.mViewX;
- mLastTouchY = ted.mViewY;
+ mLastTouchX = contentToViewX(ted.mX) - mScrollX;
+ mLastTouchY = contentToViewY(ted.mY) - mScrollY;
doDoubleTap();
mDeferTouchMode = TOUCH_DONE_MODE;
break;
@@ -6680,7 +6294,6 @@
if (hitTest != null && hitTest.mType
!= HitTestResult.UNKNOWN_TYPE) {
performLongClick();
- rebuildWebTextView();
}
mDeferTouchMode = TOUCH_DONE_MODE;
break;
@@ -6804,7 +6417,7 @@
case CENTER_FIT_RECT:
Rect r = (Rect)msg.obj;
- mInZoomOverview = false;
+ mZoomManager.mInZoomOverview = false;
centerFitRect(r.left, r.top, r.width(), r.height());
break;
@@ -6813,6 +6426,36 @@
mVerticalScrollBarMode = msg.arg2;
break;
+ case SELECTION_STRING_CHANGED:
+ if (mAccessibilityInjector != null) {
+ String selectionString = (String) msg.obj;
+ mAccessibilityInjector.onSelectionStringChange(selectionString);
+ }
+ break;
+
+ case SET_TOUCH_HIGHLIGHT_RECTS:
+ invalidate(mTouchHighlightRegion.getBounds());
+ mTouchHighlightRegion.setEmpty();
+ if (msg.obj != null) {
+ ArrayList<Rect> rects = (ArrayList<Rect>) msg.obj;
+ for (Rect rect : rects) {
+ Rect viewRect = contentToViewRect(rect);
+ // some sites, like stories in nytimes.com, set
+ // mouse event handler in the top div. It is not
+ // user friendly to highlight the div if it covers
+ // more than half of the screen.
+ if (viewRect.width() < getWidth() >> 1
+ || viewRect.height() < getHeight() >> 1) {
+ mTouchHighlightRegion.union(viewRect);
+ invalidate(viewRect);
+ } else {
+ Log.w(LOGTAG, "Skip the huge selection rect:"
+ + viewRect);
+ }
+ }
+ }
+ break;
+
default:
super.handleMessage(msg);
break;
@@ -7120,37 +6763,6 @@
new InvokeListBox(array, enabledArray, selectedArray));
}
- private void updateZoomRange(WebViewCore.RestoreState restoreState,
- int viewWidth, int minPrefWidth, boolean updateZoomOverview) {
- if (restoreState.mMinScale == 0) {
- if (restoreState.mMobileSite) {
- if (minPrefWidth > Math.max(0, viewWidth)) {
- mMinZoomScale = (float) viewWidth / minPrefWidth;
- mMinZoomScaleFixed = false;
- if (updateZoomOverview) {
- WebSettings settings = getSettings();
- mInZoomOverview = settings.getUseWideViewPort() &&
- settings.getLoadWithOverviewMode();
- }
- } else {
- mMinZoomScale = restoreState.mDefaultScale;
- mMinZoomScaleFixed = true;
- }
- } else {
- mMinZoomScale = DEFAULT_MIN_ZOOM_SCALE;
- mMinZoomScaleFixed = false;
- }
- } else {
- mMinZoomScale = restoreState.mMinScale;
- mMinZoomScaleFixed = true;
- }
- if (restoreState.mMaxScale == 0) {
- mMaxZoomScale = DEFAULT_MAX_ZOOM_SCALE;
- } else {
- mMaxZoomScale = restoreState.mMaxScale;
- }
- }
-
/*
* Request a dropdown menu for a listbox with single selection or a single
* <select> element.
@@ -7233,7 +6845,7 @@
// FIXME the divisor should be retrieved from somewhere
// the closest thing today is hard-coded into ScrollView.java
// (from ScrollView.java, line 363) int maxJump = height/2;
- return Math.round(height * mInvActualScale);
+ return Math.round(height * mZoomManager.mInvActualScale);
}
/**
@@ -7244,10 +6856,10 @@
}
/**
- * Pass the key to the plugin. This assumes that nativeFocusIsPlugin()
- * returned true.
+ * Pass the key directly to the page. This assumes that
+ * nativePageShouldHandleShiftAndArrows() returned true.
*/
- private void letPluginHandleNavKey(int keyCode, long time, boolean down) {
+ private void letPageHandleNavKey(int keyCode, long time, boolean down) {
int keyEventAction;
int eventHubAction;
if (down) {
@@ -7428,12 +7040,21 @@
private native int nativeMoveGeneration();
private native void nativeMoveSelection(int x, int y,
boolean extendSelection);
+ /**
+ * @return true if the page should get the shift and arrow keys, rather
+ * than select text/navigation.
+ *
+ * If the focus is a plugin, or if the focus and cursor match and are
+ * a contentEditable element, then the page should handle these keys.
+ */
+ private native boolean nativePageShouldHandleShiftAndArrows();
private native boolean nativePointInNavCache(int x, int y, int slop);
// Like many other of our native methods, you must make sure that
// mNativeClass is not null before calling this method.
private native void nativeRecordButtons(boolean focused,
boolean pressed, boolean invalidate);
private native void nativeSelectBestAt(Rect rect);
+ private native int nativeFindIndex();
private native void nativeSetFindIsEmpty();
private native void nativeSetFindIsUp(boolean isUp);
private native void nativeSetFollowedLink(boolean followed);
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 4118119..5139ae8 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -17,7 +17,6 @@
package android.webkit;
import android.content.Context;
-import android.content.Intent;
import android.content.pm.PackageManager.NameNotFoundException;
import android.database.Cursor;
import android.graphics.Canvas;
@@ -33,12 +32,11 @@
import android.os.Looper;
import android.os.Message;
import android.os.Process;
-import android.provider.Browser;
-import android.provider.OpenableColumns;
+import android.provider.MediaStore;
+import android.provider.MediaStore.Images.Media;
import android.util.Log;
import android.util.SparseBooleanArray;
import android.view.KeyEvent;
-import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
@@ -117,7 +115,7 @@
private int mViewportDensityDpi = -1;
private int mRestoredScale = 0;
- private int mRestoredScreenWidthScale = 0;
+ private int mRestoredTextWrapScale = 0;
private int mRestoredX = 0;
private int mRestoredY = 0;
@@ -279,34 +277,36 @@
/**
* Called by JNI. Open a file chooser to upload a file.
- * @return String version of the URI plus the name of the file.
- * FIXME: Just return the URI here, and in FileSystem::pathGetFileName, call
- * into Java to get the filename.
+ * @param acceptType The value of the 'accept' attribute of the
+ * input tag associated with this file picker.
+ * @return String version of the URI.
*/
- private String openFileChooser() {
- Uri uri = mCallbackProxy.openFileChooser();
- if (uri == null) return "";
- // Find out the name, and append it to the URI.
- // Webkit will treat the name as the filename, and
- // the URI as the path. The URI will be used
- // in BrowserFrame to get the actual data.
- Cursor cursor = mContext.getContentResolver().query(
- uri,
- new String[] { OpenableColumns.DISPLAY_NAME },
- null,
- null,
- null);
- String name = "";
- if (cursor != null) {
- try {
- if (cursor.moveToNext()) {
- name = cursor.getString(0);
+ private String openFileChooser(String acceptType) {
+ Uri uri = mCallbackProxy.openFileChooser(acceptType);
+ if (uri != null) {
+ String filePath = "";
+ // Note - querying for MediaStore.Images.Media.DATA
+ // seems to work for all content URIs, not just images
+ Cursor cursor = mContext.getContentResolver().query(
+ uri,
+ new String[] { MediaStore.Images.Media.DATA },
+ null, null, null);
+ if (cursor != null) {
+ try {
+ if (cursor.moveToNext()) {
+ filePath = cursor.getString(0);
+ }
+ } finally {
+ cursor.close();
}
- } finally {
- cursor.close();
+ } else {
+ filePath = uri.getLastPathSegment();
}
+ String uriString = uri.toString();
+ BrowserFrame.sJavaBridge.storeFilePathForContentUri(filePath, uriString);
+ return uriString;
}
- return uri.toString() + "/" + name;
+ return "";
}
/**
@@ -480,12 +480,12 @@
of layout/line-breaking. These coordinates are in document space,
which is the same as View coords unless we have zoomed the document
(see nativeSetZoom).
- screenWidth is used by layout to wrap column around. If viewport uses
- fixed size, screenWidth can be different from width with zooming.
+ textWrapWidth is used by layout to wrap column around. If viewport uses
+ fixed size, textWrapWidth can be different from width with zooming.
should this be called nativeSetViewPortSize?
*/
- private native void nativeSetSize(int width, int height, int screenWidth,
- float scale, int realScreenWidth, int screenHeight, int anchorX,
+ private native void nativeSetSize(int width, int height, int textWrapWidth,
+ float scale, int screenWidth, int screenHeight, int anchorX,
int anchorY, boolean ignoreHeight);
private native int nativeGetContentMinPrefWidth();
@@ -576,7 +576,18 @@
/**
* Provide WebCore with the previously visted links from the history database
*/
- private native void nativeProvideVisitedHistory(String[] history);
+ private native void nativeProvideVisitedHistory(String[] history);
+
+ /**
+ * Modifies the current selection.
+ *
+ * @param alter Specifies how to alter the selection.
+ * @param direction The direction in which to alter the selection.
+ * @param granularity The granularity of the selection modification.
+ *
+ * @return The selection string.
+ */
+ private native String nativeModifySelection(String alter, String direction, String granularity);
// EventHub for processing messages
private final EventHub mEventHub;
@@ -697,6 +708,12 @@
int mY;
}
+ static class TouchHighlightData {
+ int mX;
+ int mY;
+ int mSlop;
+ }
+
// mAction of TouchEventData can be MotionEvent.getAction() which uses the
// last two bytes or one of the following values
static final int ACTION_LONGPRESS = 0x100;
@@ -708,8 +725,6 @@
int mY;
int mMetaState;
boolean mReprocess;
- float mViewX;
- float mViewY;
}
static class GeolocationPermissionsData {
@@ -718,7 +733,11 @@
boolean mRemember;
}
-
+ static class ModifySelectionData {
+ String mAlter;
+ String mDirection;
+ String mGranularity;
+ }
static final String[] HandlerDebugString = {
"REQUEST_LABEL", // 97
@@ -865,6 +884,12 @@
static final int ADD_PACKAGE_NAME = 185;
static final int REMOVE_PACKAGE_NAME = 186;
+ static final int GET_TOUCH_HIGHLIGHT_RECTS = 187;
+ static final int REMOVE_TOUCH_HIGHLIGHT_RECTS = 188;
+
+ // accessibility support
+ static final int MODIFY_SELECTION = 190;
+
// private message ids
private static final int DESTROY = 200;
@@ -1238,6 +1263,19 @@
nativeSetSelection(msg.arg1, msg.arg2);
break;
+ case MODIFY_SELECTION:
+ ModifySelectionData modifySelectionData =
+ (ModifySelectionData) msg.obj;
+ String selectionString = nativeModifySelection(
+ modifySelectionData.mAlter,
+ modifySelectionData.mDirection,
+ modifySelectionData.mGranularity);
+
+ mWebView.mPrivateHandler.obtainMessage(
+ WebView.SELECTION_STRING_CHANGED, selectionString)
+ .sendToTarget();
+ break;
+
case LISTBOX_CHOICES:
SparseBooleanArray choices = (SparseBooleanArray)
msg.obj;
@@ -1357,6 +1395,21 @@
BrowserFrame.sJavaBridge.removePackageName(
(String) msg.obj);
break;
+
+ case GET_TOUCH_HIGHLIGHT_RECTS:
+ TouchHighlightData d = (TouchHighlightData) msg.obj;
+ ArrayList<Rect> rects = nativeGetTouchHighlightRects
+ (d.mX, d.mY, d.mSlop);
+ mWebView.mPrivateHandler.obtainMessage(
+ WebView.SET_TOUCH_HIGHLIGHT_RECTS, rects)
+ .sendToTarget();
+ break;
+
+ case REMOVE_TOUCH_HIGHLIGHT_RECTS:
+ mWebView.mPrivateHandler.obtainMessage(
+ WebView.SET_TOUCH_HIGHLIGHT_RECTS, null)
+ .sendToTarget();
+ break;
}
}
};
@@ -1575,11 +1628,12 @@
if (keyCode >= KeyEvent.KEYCODE_DPAD_UP
&& keyCode <= KeyEvent.KEYCODE_DPAD_RIGHT) {
if (DebugFlags.WEB_VIEW_CORE) {
- Log.v(LOGTAG, "key: arrow unused by plugin: " + keyCode);
+ Log.v(LOGTAG, "key: arrow unused by page: " + keyCode);
}
if (mWebView != null && evt.isDown()) {
Message.obtain(mWebView.mPrivateHandler,
- WebView.MOVE_OUT_OF_PLUGIN, keyCode).sendToTarget();
+ WebView.UNHANDLED_NAV_KEY, keyCode,
+ 0).sendToTarget();
}
return;
}
@@ -2014,9 +2068,15 @@
mWebView.mViewManager.postReadyToDrawAll();
}
+ // remove the touch highlight when moving to a new page
+ if (getSettings().supportTouchOnly()) {
+ mEventHub.sendMessage(Message.obtain(null,
+ EventHub.REMOVE_TOUCH_HIGHLIGHT_RECTS));
+ }
+
// reset the scroll position, the restored offset and scales
mWebkitScrollX = mWebkitScrollY = mRestoredX = mRestoredY
- = mRestoredScale = mRestoredScreenWidthScale = 0;
+ = mRestoredScale = mRestoredTextWrapScale = 0;
}
// called by JNI
@@ -2037,8 +2097,10 @@
// adjust the default scale to match the densityDpi
float adjust = 1.0f;
if (mViewportDensityDpi == -1) {
- if (WebView.DEFAULT_SCALE_PERCENT != 100) {
- adjust = WebView.DEFAULT_SCALE_PERCENT / 100.0f;
+ // convert default zoom scale to a integer (percentage) to avoid any
+ // issues with floating point comparisons
+ if (mWebView != null && (int)(mWebView.getDefaultZoomScale() * 100) != 100) {
+ adjust = mWebView.getDefaultZoomScale();
}
} else if (mViewportDensityDpi > 0) {
adjust = (float) mContext.getResources().getDisplayMetrics().densityDpi
@@ -2120,9 +2182,9 @@
mRestoreState.mMobileSite = (0 == mViewportWidth);
if (mRestoredScale > 0) {
mRestoreState.mViewScale = mRestoredScale / 100.0f;
- if (mRestoredScreenWidthScale > 0) {
+ if (mRestoredTextWrapScale > 0) {
mRestoreState.mTextWrapScale =
- mRestoredScreenWidthScale / 100.0f;
+ mRestoredTextWrapScale / 100.0f;
} else {
mRestoreState.mTextWrapScale = mRestoreState.mViewScale;
}
@@ -2211,20 +2273,12 @@
}
// called by JNI
- private void restoreScale(int scale) {
+ private void restoreScale(int scale, int textWrapScale) {
if (mBrowserFrame.firstLayoutDone() == false) {
mRestoredScale = scale;
- }
- }
-
- // called by JNI
- private void restoreScreenWidthScale(int scale) {
- if (!mSettings.getUseWideViewPort()) {
- return;
- }
-
- if (mBrowserFrame.firstLayoutDone() == false) {
- mRestoredScreenWidthScale = scale;
+ if (mSettings.getUseWideViewPort()) {
+ mRestoredTextWrapScale = textWrapScale;
+ }
}
}
@@ -2469,4 +2523,6 @@
private native boolean nativeValidNodeAndBounds(int frame, int node,
Rect bounds);
+ private native ArrayList<Rect> nativeGetTouchHighlightRects(int x, int y,
+ int slop);
}
diff --git a/core/java/android/webkit/ZoomControlBase.java b/core/java/android/webkit/ZoomControlBase.java
new file mode 100644
index 0000000..be9e8f3
--- /dev/null
+++ b/core/java/android/webkit/ZoomControlBase.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.webkit;
+
+interface ZoomControlBase {
+
+ /**
+ * Causes the on-screen zoom control to be made visible
+ */
+ public void show();
+
+ /**
+ * Causes the on-screen zoom control to disappear
+ */
+ public void hide();
+
+ /**
+ * Enables the control to update its state if necessary in response to a
+ * change in the pages zoom level. For example, if the max zoom level is
+ * reached then the control can disable the button for zooming in.
+ */
+ public void update();
+
+ /**
+ * Checks to see if the control is currently visible to the user.
+ */
+ public boolean isVisible();
+}
diff --git a/core/java/android/webkit/ZoomControlEmbedded.java b/core/java/android/webkit/ZoomControlEmbedded.java
new file mode 100644
index 0000000..6e07ada
--- /dev/null
+++ b/core/java/android/webkit/ZoomControlEmbedded.java
@@ -0,0 +1,117 @@
+/*
+ * 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.webkit;
+
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.Toast;
+import android.widget.ZoomButtonsController;
+
+class ZoomControlEmbedded implements ZoomControlBase {
+
+ private final ZoomManager mZoomManager;
+ private final WebView mWebView;
+
+ // The controller is lazily initialized in getControls() for performance.
+ private ZoomButtonsController mZoomButtonsController;
+
+ public ZoomControlEmbedded(ZoomManager zoomManager, WebView webView) {
+ mZoomManager = zoomManager;
+ mWebView = webView;
+ }
+
+ public void show() {
+ if (!getControls().isVisible() && !mZoomManager.isZoomScaleFixed()) {
+
+ mZoomButtonsController.setVisible(true);
+
+ WebSettings settings = mWebView.getSettings();
+ int count = settings.getDoubleTapToastCount();
+ if (mZoomManager.mInZoomOverview && count > 0) {
+ settings.setDoubleTapToastCount(--count);
+ Toast.makeText(mWebView.getContext(),
+ com.android.internal.R.string.double_tap_toast,
+ Toast.LENGTH_LONG).show();
+ }
+ }
+ }
+
+ public void hide() {
+ if (mZoomButtonsController != null) {
+ mZoomButtonsController.setVisible(false);
+ }
+ }
+
+ public boolean isVisible() {
+ return mZoomButtonsController != null && mZoomButtonsController.isVisible();
+ }
+
+ public void update() {
+ if (mZoomButtonsController == null) {
+ return;
+ }
+
+ boolean canZoomIn = mZoomManager.canZoomIn();
+ boolean canZoomOut = mZoomManager.canZoomOut() && !mZoomManager.mInZoomOverview;
+ if (!canZoomIn && !canZoomOut) {
+ // Hide the zoom in and out buttons if the page cannot zoom
+ mZoomButtonsController.getZoomControls().setVisibility(View.GONE);
+ } else {
+ // Set each one individually, as a page may be able to zoom in or out
+ mZoomButtonsController.setZoomInEnabled(canZoomIn);
+ mZoomButtonsController.setZoomOutEnabled(canZoomOut);
+ }
+ }
+
+ private ZoomButtonsController getControls() {
+ if (mZoomButtonsController == null) {
+ mZoomButtonsController = new ZoomButtonsController(mWebView);
+ mZoomButtonsController.setOnZoomListener(new ZoomListener());
+ // ZoomButtonsController positions the buttons at the bottom, but in
+ // the middle. Change their layout parameters so they appear on the
+ // right.
+ View controls = mZoomButtonsController.getZoomControls();
+ ViewGroup.LayoutParams params = controls.getLayoutParams();
+ if (params instanceof FrameLayout.LayoutParams) {
+ ((FrameLayout.LayoutParams) params).gravity = Gravity.RIGHT;
+ }
+ }
+ return mZoomButtonsController;
+ }
+
+ private class ZoomListener implements ZoomButtonsController.OnZoomListener {
+
+ public void onVisibilityChanged(boolean visible) {
+ if (visible) {
+ mWebView.switchOutDrawHistory();
+ // Bring back the hidden zoom controls.
+ mZoomButtonsController.getZoomControls().setVisibility(View.VISIBLE);
+ update();
+ }
+ }
+
+ public void onZoom(boolean zoomIn) {
+ if (zoomIn) {
+ mWebView.zoomIn();
+ } else {
+ mWebView.zoomOut();
+ }
+ update();
+ }
+ }
+}
diff --git a/core/java/android/webkit/ZoomControlExternal.java b/core/java/android/webkit/ZoomControlExternal.java
new file mode 100644
index 0000000..d75313e
--- /dev/null
+++ b/core/java/android/webkit/ZoomControlExternal.java
@@ -0,0 +1,159 @@
+/*
+ * 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.webkit;
+
+import android.content.Context;
+import android.os.Handler;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.View.OnClickListener;
+import android.view.animation.AlphaAnimation;
+import android.widget.FrameLayout;
+
+@Deprecated
+class ZoomControlExternal implements ZoomControlBase {
+
+ // The time that the external controls are visible before fading away
+ private static final long ZOOM_CONTROLS_TIMEOUT =
+ ViewConfiguration.getZoomControlsTimeout();
+ // The view containing the external zoom controls
+ private ExtendedZoomControls mZoomControls;
+ private Runnable mZoomControlRunnable;
+ private final Handler mPrivateHandler = new Handler();
+
+ private final WebView mWebView;
+
+ public ZoomControlExternal(WebView webView) {
+ mWebView = webView;
+ }
+
+ public void show() {
+ if(mZoomControlRunnable != null) {
+ mPrivateHandler.removeCallbacks(mZoomControlRunnable);
+ }
+ getControls().show(true);
+ mPrivateHandler.postDelayed(mZoomControlRunnable, ZOOM_CONTROLS_TIMEOUT);
+ }
+
+ public void hide() {
+ if (mZoomControlRunnable != null) {
+ mPrivateHandler.removeCallbacks(mZoomControlRunnable);
+ }
+ if (mZoomControls != null) {
+ mZoomControls.hide();
+ }
+ }
+
+ public boolean isVisible() {
+ return mZoomControls != null && mZoomControls.isShown();
+ }
+
+ public void update() { }
+
+ public ExtendedZoomControls getControls() {
+ if (mZoomControls == null) {
+ mZoomControls = createZoomControls();
+
+ /*
+ * need to be set to VISIBLE first so that getMeasuredHeight() in
+ * {@link #onSizeChanged()} can return the measured value for proper
+ * layout.
+ */
+ mZoomControls.setVisibility(View.VISIBLE);
+ mZoomControlRunnable = new Runnable() {
+ public void run() {
+ /* Don't dismiss the controls if the user has
+ * focus on them. Wait and check again later.
+ */
+ if (!mZoomControls.hasFocus()) {
+ mZoomControls.hide();
+ } else {
+ mPrivateHandler.removeCallbacks(mZoomControlRunnable);
+ mPrivateHandler.postDelayed(mZoomControlRunnable,
+ ZOOM_CONTROLS_TIMEOUT);
+ }
+ }
+ };
+ }
+ return mZoomControls;
+ }
+
+ private ExtendedZoomControls createZoomControls() {
+ ExtendedZoomControls zoomControls = new ExtendedZoomControls(mWebView.getContext());
+ zoomControls.setOnZoomInClickListener(new OnClickListener() {
+ public void onClick(View v) {
+ // reset time out
+ mPrivateHandler.removeCallbacks(mZoomControlRunnable);
+ mPrivateHandler.postDelayed(mZoomControlRunnable, ZOOM_CONTROLS_TIMEOUT);
+ mWebView.zoomIn();
+ }
+ });
+ zoomControls.setOnZoomOutClickListener(new OnClickListener() {
+ public void onClick(View v) {
+ // reset time out
+ mPrivateHandler.removeCallbacks(mZoomControlRunnable);
+ mPrivateHandler.postDelayed(mZoomControlRunnable, ZOOM_CONTROLS_TIMEOUT);
+ mWebView.zoomOut();
+ }
+ });
+ return zoomControls;
+ }
+
+ private static class ExtendedZoomControls extends FrameLayout {
+
+ private android.widget.ZoomControls mPlusMinusZoomControls;
+
+ public ExtendedZoomControls(Context context) {
+ super(context, null);
+ LayoutInflater inflater = (LayoutInflater)
+ context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ inflater.inflate(com.android.internal.R.layout.zoom_magnify, this, true);
+ mPlusMinusZoomControls = (android.widget.ZoomControls) findViewById(
+ com.android.internal.R.id.zoomControls);
+ findViewById(com.android.internal.R.id.zoomMagnify).setVisibility(
+ View.GONE);
+ }
+
+ public void show(boolean showZoom) {
+ mPlusMinusZoomControls.setVisibility(showZoom ? View.VISIBLE : View.GONE);
+ fade(View.VISIBLE, 0.0f, 1.0f);
+ }
+
+ public void hide() {
+ fade(View.GONE, 1.0f, 0.0f);
+ }
+
+ private void fade(int visibility, float startAlpha, float endAlpha) {
+ AlphaAnimation anim = new AlphaAnimation(startAlpha, endAlpha);
+ anim.setDuration(500);
+ startAnimation(anim);
+ setVisibility(visibility);
+ }
+
+ public boolean hasFocus() {
+ return mPlusMinusZoomControls.hasFocus();
+ }
+
+ public void setOnZoomInClickListener(OnClickListener listener) {
+ mPlusMinusZoomControls.setOnZoomInClickListener(listener);
+ }
+
+ public void setOnZoomOutClickListener(OnClickListener listener) {
+ mPlusMinusZoomControls.setOnZoomOutClickListener(listener);
+ }
+ }
+}
diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java
new file mode 100644
index 0000000..5ae5a6a4
--- /dev/null
+++ b/core/java/android/webkit/ZoomManager.java
@@ -0,0 +1,717 @@
+/*
+ * 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.webkit;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.graphics.Canvas;
+import android.graphics.Point;
+import android.os.SystemClock;
+import android.util.Log;
+import android.view.ScaleGestureDetector;
+import android.view.View;
+
+/**
+ * The ZoomManager is responsible for maintaining the WebView's current zoom
+ * level state. It is also responsible for managing the on-screen zoom controls
+ * as well as any animation of the WebView due to zooming.
+ *
+ * Currently, there are two methods for animating the zoom of a WebView.
+ *
+ * (1) The first method is triggered by startZoomAnimation(...) and is a fixed
+ * length animation where the final zoom scale is known at startup. This type of
+ * animation notifies webkit of the final scale BEFORE it animates. The animation
+ * is then done by scaling the CANVAS incrementally based on a stepping function.
+ *
+ * (2) The second method is triggered by a multi-touch pinch and the new scale
+ * is determined dynamically based on the user's gesture. This type of animation
+ * only notifies webkit of new scale AFTER the gesture is complete. The animation
+ * effect is achieved by scaling the VIEWS (both WebView and ViewManager.ChildView)
+ * to the new scale in response to events related to the user's gesture.
+ */
+class ZoomManager {
+
+ static final String LOGTAG = "webviewZoom";
+
+ private final WebView mWebView;
+ private final CallbackProxy mCallbackProxy;
+
+ // manages the on-screen zoom functions of the WebView
+ private ZoomControlEmbedded mEmbeddedZoomControl;
+
+ private ZoomControlExternal mExternalZoomControl;
+
+ /*
+ * TODO: clean up the visibility of the class variables when the zoom
+ * refactoring is complete
+ */
+
+ // default scale limits, which are dependent on the display density
+ static float DEFAULT_MAX_ZOOM_SCALE;
+ static float DEFAULT_MIN_ZOOM_SCALE;
+
+ // actual scale limits, which can be set through a webpage viewport meta tag
+ private float mMaxZoomScale;
+ private float mMinZoomScale;
+
+ // locks the minimum ZoomScale to the value currently set in mMinZoomScale
+ private boolean mMinZoomScaleFixed = true;
+
+ // while in the zoom overview mode, the page's width is fully fit to the
+ // current window. The page is alive, in another words, you can click to
+ // follow the links. Double tap will toggle between zoom overview mode and
+ // the last zoom scale.
+ boolean mInZoomOverview = false;
+
+ // These keep track of the center point of the zoom and they are used to
+ // determine the point around which we should zoom. They are stored in view
+ // coordinates.
+ float mZoomCenterX;
+ float mZoomCenterY;
+
+ // ideally mZoomOverviewWidth should be mContentWidth. But sites like espn,
+ // engadget always have wider mContentWidth no matter what viewport size is.
+ int mZoomOverviewWidth = WebView.DEFAULT_VIEWPORT_WIDTH;
+ float mTextWrapScale;
+
+ // the default zoom scale. This value will is initially set based on the
+ // display density, but can be changed at any time via the WebSettings.
+ private float mDefaultScale;
+ private float mInvDefaultScale;
+
+ private static float MINIMUM_SCALE_INCREMENT = 0.01f;
+
+ // the current computed zoom scale and its inverse.
+ float mActualScale;
+ float mInvActualScale;
+
+ /*
+ * The initial scale for the WebView. 0 means default. If initial scale is
+ * greater than 0 the WebView starts with this value as its initial scale. The
+ * value is converted from an integer percentage so it is guarenteed to have
+ * no more than 2 significant digits after the decimal. This restriction
+ * allows us to convert the scale back to the original percentage by simply
+ * multiplying the value by 100.
+ */
+ private float mInitialScale;
+
+ /*
+ * The following member variables are only to be used for animating zoom. If
+ * mZoomScale is non-zero then we are in the middle of a zoom animation. The
+ * other variables are used as a cache (e.g. inverse) or as a way to store
+ * the state of the view prior to animating (e.g. initial scroll coords).
+ */
+ private float mZoomScale;
+ private float mInvInitialZoomScale;
+ private float mInvFinalZoomScale;
+ private int mInitialScrollX;
+ private int mInitialScrollY;
+ private long mZoomStart;
+ static final int ZOOM_ANIMATION_LENGTH = 500;
+
+ // whether support multi-touch
+ private boolean mSupportMultiTouch;
+
+ // use the framework's ScaleGestureDetector to handle multi-touch
+ private ScaleGestureDetector mScaleDetector;
+ private boolean mPinchToZoomAnimating = false;
+
+ public ZoomManager(WebView webView, CallbackProxy callbackProxy) {
+ mWebView = webView;
+ mCallbackProxy = callbackProxy;
+ }
+
+ public void init(float density) {
+ setDefaultZoomScale(density);
+ mMaxZoomScale = DEFAULT_MAX_ZOOM_SCALE;
+ mMinZoomScale = DEFAULT_MIN_ZOOM_SCALE;
+ mActualScale = density;
+ mInvActualScale = 1 / density;
+ mTextWrapScale = density;
+ }
+
+ public void updateDefaultZoomDensity(float density) {
+ if (Math.abs(density - mDefaultScale) > MINIMUM_SCALE_INCREMENT) {
+ float scaleFactor = density * mInvDefaultScale;
+ // set the new default density
+ setDefaultZoomScale(density);
+ // adjust the limits
+ mMaxZoomScale *= scaleFactor;
+ mMinZoomScale *= scaleFactor;
+ setZoomScale(mActualScale * scaleFactor, true);
+ }
+ }
+
+ private void setDefaultZoomScale(float defaultScale) {
+ mDefaultScale = defaultScale;
+ mInvDefaultScale = 1 / defaultScale;
+ DEFAULT_MAX_ZOOM_SCALE = 4.0f * defaultScale;
+ DEFAULT_MIN_ZOOM_SCALE = 0.25f * defaultScale;
+ }
+
+ public float getDefaultScale() {
+ return mDefaultScale;
+ }
+
+ public void setZoomCenter(float x, float y) {
+ mZoomCenterX = x;
+ mZoomCenterY = y;
+ }
+
+ public void setInitialScaleInPercent(int scaleInPercent) {
+ mInitialScale = scaleInPercent * 0.01f;
+ }
+
+ public float computeScaleWithLimits(float scale) {
+ if (scale < mMinZoomScale) {
+ scale = mMinZoomScale;
+ } else if (scale > mMaxZoomScale) {
+ scale = mMaxZoomScale;
+ }
+ return scale;
+ }
+
+ public boolean isZoomScaleFixed() {
+ return mMinZoomScale >= mMaxZoomScale;
+ }
+
+ public static final boolean exceedsMinScaleIncrement(float scaleA, float scaleB) {
+ return Math.abs(scaleA - scaleB) >= MINIMUM_SCALE_INCREMENT;
+ }
+
+ public boolean willScaleTriggerZoom(float scale) {
+ return exceedsMinScaleIncrement(scale, mActualScale);
+ }
+
+ public boolean canZoomIn() {
+ return mMaxZoomScale - mActualScale > MINIMUM_SCALE_INCREMENT;
+ }
+
+ public boolean canZoomOut() {
+ return mActualScale - mMinZoomScale > MINIMUM_SCALE_INCREMENT;
+ }
+
+ public boolean zoomIn() {
+ mInZoomOverview = false;
+ return zoom(1.25f);
+ }
+
+ public boolean zoomOut() {
+ return zoom(0.8f);
+ }
+
+ // returns TRUE if zoom out succeeds and FALSE if no zoom changes.
+ private boolean zoom(float zoomMultiplier) {
+ // TODO: alternatively we can disallow this during draw history mode
+ mWebView.switchOutDrawHistory();
+ // Center zooming to the center of the screen.
+ mZoomCenterX = mWebView.getViewWidth() * .5f;
+ mZoomCenterY = mWebView.getViewHeight() * .5f;
+ int anchorX = mWebView.viewToContentX((int) mZoomCenterX + mWebView.getScrollX());
+ int anchorY = mWebView.viewToContentY((int) mZoomCenterY + mWebView.getScrollY());
+ mWebView.setViewSizeAnchor(anchorX, anchorY);
+ return startZoomAnimation(mActualScale * zoomMultiplier, true);
+ }
+
+ public void zoomToOverview() {
+ mInZoomOverview = true;
+ // Force the titlebar fully reveal in overview mode
+ int scrollY = mWebView.getScrollY();
+ if (scrollY < mWebView.getTitleHeight()) {
+ mWebView.updateScrollCoordinates(mWebView.getScrollX(), 0);
+ }
+ startZoomAnimation((float) mWebView.getViewWidth() / mZoomOverviewWidth, true);
+ }
+
+ public void zoomToDefaultLevel(boolean reflowText) {
+ mInZoomOverview = false;
+ startZoomAnimation(mDefaultScale, reflowText);
+ }
+
+ /**
+ * Initiates an animated zoom of the WebView.
+ *
+ * @return true if the new scale triggered an animation and false otherwise.
+ */
+ public boolean startZoomAnimation(float scale, boolean reflowText) {
+ float oldScale = mActualScale;
+ mInitialScrollX = mWebView.getScrollX();
+ mInitialScrollY = mWebView.getScrollY();
+
+ // snap to DEFAULT_SCALE if it is close
+ if (!exceedsMinScaleIncrement(scale, mDefaultScale)) {
+ scale = mDefaultScale;
+ }
+
+ setZoomScale(scale, reflowText);
+
+ if (oldScale != mActualScale) {
+ // use mZoomPickerScale to see zoom preview first
+ mZoomStart = SystemClock.uptimeMillis();
+ mInvInitialZoomScale = 1.0f / oldScale;
+ mInvFinalZoomScale = 1.0f / mActualScale;
+ mZoomScale = mActualScale;
+ mWebView.onFixedLengthZoomAnimationStart();
+ mWebView.invalidate();
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * This method is called by the WebView's drawing code when a fixed length zoom
+ * animation is occurring. Its purpose is to animate the zooming of the canvas
+ * to the desired scale which was specified in startZoomAnimation(...).
+ *
+ * A fixed length animation begins when startZoomAnimation(...) is called and
+ * continues until the ZOOM_ANIMATION_LENGTH time has elapsed. During that
+ * interval each time the WebView draws it calls this function which is
+ * responsible for generating the animation.
+ *
+ * Additionally, the WebView can check to see if such an animation is currently
+ * in progress by calling isFixedLengthAnimationInProgress().
+ */
+ public void animateZoom(Canvas canvas) {
+ if (mZoomScale == 0) {
+ Log.w(LOGTAG, "A WebView is attempting to perform a fixed length "
+ + "zoom animation when no zoom is in progress");
+ return;
+ }
+
+ float zoomScale;
+ int interval = (int) (SystemClock.uptimeMillis() - mZoomStart);
+ if (interval < ZOOM_ANIMATION_LENGTH) {
+ float ratio = (float) interval / ZOOM_ANIMATION_LENGTH;
+ zoomScale = 1.0f / (mInvInitialZoomScale
+ + (mInvFinalZoomScale - mInvInitialZoomScale) * ratio);
+ mWebView.invalidate();
+ } else {
+ zoomScale = mZoomScale;
+ // set mZoomScale to be 0 as we have finished animating
+ mZoomScale = 0;
+ mWebView.onFixedLengthZoomAnimationEnd();
+ }
+ // calculate the intermediate scroll position. Since we need to use
+ // zoomScale, we can't use the WebView's pinLocX/Y functions directly.
+ float scale = zoomScale * mInvInitialZoomScale;
+ int tx = Math.round(scale * (mInitialScrollX + mZoomCenterX) - mZoomCenterX);
+ tx = -WebView.pinLoc(tx, mWebView.getViewWidth(), Math.round(mWebView.getContentWidth()
+ * zoomScale)) + mWebView.getScrollX();
+ int titleHeight = mWebView.getTitleHeight();
+ int ty = Math.round(scale
+ * (mInitialScrollY + mZoomCenterY - titleHeight)
+ - (mZoomCenterY - titleHeight));
+ ty = -(ty <= titleHeight ? Math.max(ty, 0) : WebView.pinLoc(ty
+ - titleHeight, mWebView.getViewHeight(), Math.round(mWebView.getContentHeight()
+ * zoomScale)) + titleHeight) + mWebView.getScrollY();
+
+ canvas.translate(tx, ty);
+ canvas.scale(zoomScale, zoomScale);
+ }
+
+ public boolean isZoomAnimating() {
+ return isFixedLengthAnimationInProgress() || mPinchToZoomAnimating;
+ }
+
+ public boolean isFixedLengthAnimationInProgress() {
+ return mZoomScale != 0;
+ }
+
+ public void refreshZoomScale(boolean reflowText) {
+ setZoomScale(mActualScale, reflowText, true);
+ }
+
+ public void setZoomScale(float scale, boolean reflowText) {
+ setZoomScale(scale, reflowText, false);
+ }
+
+ private void setZoomScale(float scale, boolean reflowText, boolean force) {
+ if (scale < mMinZoomScale) {
+ scale = mMinZoomScale;
+ // set mInZoomOverview for non mobile sites
+ if (scale < mDefaultScale) {
+ mInZoomOverview = true;
+ }
+ } else if (scale > mMaxZoomScale) {
+ scale = mMaxZoomScale;
+ }
+
+ if (reflowText) {
+ mTextWrapScale = scale;
+ }
+
+ if (scale != mActualScale || force) {
+ float oldScale = mActualScale;
+ float oldInvScale = mInvActualScale;
+
+ if (scale != mActualScale && !mPinchToZoomAnimating) {
+ mCallbackProxy.onScaleChanged(mActualScale, scale);
+ }
+
+ mActualScale = scale;
+ mInvActualScale = 1 / scale;
+
+ if (!mWebView.drawHistory()) {
+
+ // If history Picture is drawn, don't update scroll. They will
+ // be updated when we get out of that mode.
+ // update our scroll so we don't appear to jump
+ // i.e. keep the center of the doc in the center of the view
+ int oldX = mWebView.getScrollX();
+ int oldY = mWebView.getScrollY();
+ float ratio = scale * oldInvScale;
+ float sx = ratio * oldX + (ratio - 1) * mZoomCenterX;
+ float sy = ratio * oldY + (ratio - 1)
+ * (mZoomCenterY - mWebView.getTitleHeight());
+
+ // Scale all the child views
+ mWebView.mViewManager.scaleAll();
+
+ // as we don't have animation for scaling, don't do animation
+ // for scrolling, as it causes weird intermediate state
+ int scrollX = mWebView.pinLocX(Math.round(sx));
+ int scrollY = mWebView.pinLocY(Math.round(sy));
+ if(!mWebView.updateScrollCoordinates(scrollX, scrollY)) {
+ // the scroll position is adjusted at the beginning of the
+ // zoom animation. But we want to update the WebKit at the
+ // end of the zoom animation. See comments in onScaleEnd().
+ mWebView.sendOurVisibleRect();
+ }
+ }
+
+ // if the we need to reflow the text then force the VIEW_SIZE_CHANGED
+ // event to be sent to WebKit
+ mWebView.sendViewSizeZoom(reflowText);
+ }
+ }
+
+ public void updateMultiTouchSupport(Context context) {
+ // check the preconditions
+ assert mWebView.getSettings() != null;
+
+ WebSettings settings = mWebView.getSettings();
+ mSupportMultiTouch = context.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH)
+ && settings.supportZoom() && settings.getBuiltInZoomControls();
+ if (mSupportMultiTouch && (mScaleDetector == null)) {
+ mScaleDetector = new ScaleGestureDetector(context, new ScaleDetectorListener());
+ } else if (!mSupportMultiTouch && (mScaleDetector != null)) {
+ mScaleDetector = null;
+ }
+ }
+
+ public boolean supportsMultiTouchZoom() {
+ return mSupportMultiTouch;
+ }
+
+ /**
+ * Notifies the caller that the ZoomManager is requesting that scale related
+ * updates should not be sent to webkit. This can occur in cases where the
+ * ZoomManager is performing an animation and does not want webkit to update
+ * until the animation is complete.
+ *
+ * @return true if scale related updates should not be sent to webkit and
+ * false otherwise.
+ */
+ public boolean isPreventingWebkitUpdates() {
+ // currently only animating a multi-touch zoom prevents updates, but
+ // others can add their own conditions to this method if necessary.
+ return mPinchToZoomAnimating;
+ }
+
+ public ScaleGestureDetector getMultiTouchGestureDetector() {
+ return mScaleDetector;
+ }
+
+ private class ScaleDetectorListener implements ScaleGestureDetector.OnScaleGestureListener {
+
+ public boolean onScaleBegin(ScaleGestureDetector detector) {
+ dismissZoomPicker();
+ // reset the zoom overview mode so that the page won't auto grow
+ mInZoomOverview = false;
+ mWebView.mViewManager.startZoom();
+ mWebView.onPinchToZoomAnimationStart();
+ return true;
+ }
+
+ public boolean onScale(ScaleGestureDetector detector) {
+ float scale = Math.round(detector.getScaleFactor() * mActualScale * 100) * 0.01f;
+ if (willScaleTriggerZoom(scale)) {
+ mPinchToZoomAnimating = true;
+ // limit the scale change per step
+ if (scale > mActualScale) {
+ scale = Math.min(scale, mActualScale * 1.25f);
+ } else {
+ scale = Math.max(scale, mActualScale * 0.8f);
+ }
+ setZoomCenter(detector.getFocusX(), detector.getFocusY());
+ setZoomScale(scale, false);
+ mWebView.invalidate();
+ return true;
+ }
+ return false;
+ }
+
+ public void onScaleEnd(ScaleGestureDetector detector) {
+ if (mPinchToZoomAnimating) {
+ mPinchToZoomAnimating = false;
+ mWebView.setViewSizeAnchor(mWebView.viewToContentX((int) mZoomCenterX
+ + mWebView.getScrollX()), mWebView.viewToContentY((int) mZoomCenterY
+ + mWebView.getScrollY()));
+ // don't reflow when zoom in; when zoom out, do reflow if the
+ // new scale is almost minimum scale;
+ boolean reflowNow = !canZoomOut() || (mActualScale <= 0.8 * mTextWrapScale);
+ // force zoom after mPreviewZoomOnly is set to false so that the
+ // new view size will be passed to the WebKit
+ refreshZoomScale(reflowNow);
+ // call invalidate() to draw without zoom filter
+ mWebView.invalidate();
+ }
+
+ mWebView.mViewManager.endZoom();
+ mWebView.onPinchToZoomAnimationEnd(detector);
+ }
+ }
+
+ public void onSizeChanged(int w, int h, int ow, int oh) {
+ // reset zoom and anchor to the top left corner of the screen
+ // unless we are already zooming
+ if (!isFixedLengthAnimationInProgress()) {
+ int visibleTitleHeight = mWebView.getVisibleTitleHeight();
+ mZoomCenterX = 0;
+ mZoomCenterY = visibleTitleHeight;
+ int anchorX = mWebView.viewToContentX(mWebView.getScrollX());
+ int anchorY = mWebView.viewToContentY(visibleTitleHeight + mWebView.getScrollY());
+ mWebView.setViewSizeAnchor(anchorX, anchorY);
+
+ }
+
+ // update mMinZoomScale if the minimum zoom scale is not fixed
+ if (!mMinZoomScaleFixed) {
+ // when change from narrow screen to wide screen, the new viewWidth
+ // can be wider than the old content width. We limit the minimum
+ // scale to 1.0f. The proper minimum scale will be calculated when
+ // the new picture shows up.
+ mMinZoomScale = Math.min(1.0f, (float) mWebView.getViewWidth()
+ / (mWebView.drawHistory() ? mWebView.getHistoryPictureWidth()
+ : mZoomOverviewWidth));
+ // limit the minZoomScale to the initialScale if it is set
+ if (mInitialScale > 0 && mInitialScale < mMinZoomScale) {
+ mMinZoomScale = mInitialScale;
+ }
+ }
+
+ dismissZoomPicker();
+
+ // onSizeChanged() is called during WebView layout. And any
+ // requestLayout() is blocked during layout. As refreshZoomScale() will
+ // cause its child View to reposition itself through ViewManager's
+ // scaleAll(), we need to post a Runnable to ensure requestLayout().
+ // Additionally, only update the text wrap scale if the width changed.
+ mWebView.post(new PostScale(w != ow));
+ }
+
+ private class PostScale implements Runnable {
+ final boolean mUpdateTextWrap;
+
+ public PostScale(boolean updateTextWrap) {
+ mUpdateTextWrap = updateTextWrap;
+ }
+
+ public void run() {
+ if (mWebView.getWebViewCore() != null) {
+ // we always force, in case our height changed, in which case we
+ // still want to send the notification over to webkit.
+ refreshZoomScale(mUpdateTextWrap);
+ // update the zoom buttons as the scale can be changed
+ updateZoomPicker();
+ }
+ }
+ }
+
+ public void updateZoomRange(WebViewCore.RestoreState restoreState,
+ int viewWidth, int minPrefWidth, boolean updateZoomOverview) {
+ if (restoreState.mMinScale == 0) {
+ if (restoreState.mMobileSite) {
+ if (minPrefWidth > Math.max(0, viewWidth)) {
+ mMinZoomScale = (float) viewWidth / minPrefWidth;
+ mMinZoomScaleFixed = false;
+ if (updateZoomOverview) {
+ WebSettings settings = mWebView.getSettings();
+ mInZoomOverview = settings.getUseWideViewPort() &&
+ settings.getLoadWithOverviewMode();
+ }
+ } else {
+ mMinZoomScale = restoreState.mDefaultScale;
+ mMinZoomScaleFixed = true;
+ }
+ } else {
+ mMinZoomScale = DEFAULT_MIN_ZOOM_SCALE;
+ mMinZoomScaleFixed = false;
+ }
+ } else {
+ mMinZoomScale = restoreState.mMinScale;
+ mMinZoomScaleFixed = true;
+ }
+ if (restoreState.mMaxScale == 0) {
+ mMaxZoomScale = DEFAULT_MAX_ZOOM_SCALE;
+ } else {
+ mMaxZoomScale = restoreState.mMaxScale;
+ }
+ }
+
+ /**
+ * Updates zoom values when Webkit produces a new picture. This method
+ * should only be called from the UI thread's message handler.
+ */
+ public void onNewPicture(WebViewCore.DrawData drawData) {
+
+ final int viewWidth = mWebView.getViewWidth();
+
+ if (mWebView.getSettings().getUseWideViewPort()) {
+ // limit mZoomOverviewWidth upper bound to
+ // sMaxViewportWidth so that if the page doesn't behave
+ // well, the WebView won't go insane. limit the lower
+ // bound to match the default scale for mobile sites.
+ mZoomOverviewWidth = Math.min(WebView.sMaxViewportWidth,
+ Math.max((int) (viewWidth * mInvDefaultScale),
+ Math.max(drawData.mMinPrefWidth,
+ drawData.mViewPoint.x)));
+ }
+ if (!mMinZoomScaleFixed) {
+ mMinZoomScale = (float) viewWidth / mZoomOverviewWidth;
+ }
+ if (!mWebView.drawHistory() && mInZoomOverview) {
+ // fit the content width to the current view. Ignore
+ // the rounding error case.
+ if (Math.abs((viewWidth * mInvActualScale) - mZoomOverviewWidth) > 1) {
+ setZoomScale((float) viewWidth / mZoomOverviewWidth,
+ !willScaleTriggerZoom(mTextWrapScale));
+ }
+ }
+ }
+
+ /**
+ * Updates zoom values when Webkit restores a old picture. This method
+ * should only be called from the UI thread's message handler.
+ */
+ public void restoreZoomState(WebViewCore.DrawData drawData) {
+ // precondition check
+ assert drawData != null;
+ assert drawData.mRestoreState != null;
+ assert mWebView.getSettings() != null;
+
+ WebViewCore.RestoreState restoreState = drawData.mRestoreState;
+ final Point viewSize = drawData.mViewPoint;
+ updateZoomRange(restoreState, viewSize.x, drawData.mMinPrefWidth, true);
+
+ if (!mWebView.drawHistory()) {
+ mInZoomOverview = false;
+
+ final float scale;
+ final boolean reflowText;
+
+ if (mInitialScale > 0) {
+ scale = mInitialScale;
+ reflowText = exceedsMinScaleIncrement(mTextWrapScale, scale);
+ } else if (restoreState.mViewScale > 0) {
+ mTextWrapScale = restoreState.mTextWrapScale;
+ scale = restoreState.mViewScale;
+ reflowText = false;
+ } else {
+ WebSettings settings = mWebView.getSettings();
+ mInZoomOverview = settings.getUseWideViewPort() &&
+ settings.getLoadWithOverviewMode();
+ if (mInZoomOverview) {
+ scale = (float) mWebView.getViewWidth() / WebView.DEFAULT_VIEWPORT_WIDTH;
+ } else {
+ scale = restoreState.mTextWrapScale;
+ }
+ reflowText = exceedsMinScaleIncrement(mTextWrapScale, scale);
+ }
+ setZoomScale(scale, reflowText);
+
+ // update the zoom buttons as the scale can be changed
+ updateZoomPicker();
+ }
+ }
+
+ private ZoomControlBase getCurrentZoomControl() {
+ if (mWebView.getSettings() != null && mWebView.getSettings().supportZoom()) {
+ if (mWebView.getSettings().getBuiltInZoomControls()) {
+ if (mEmbeddedZoomControl == null) {
+ mEmbeddedZoomControl = new ZoomControlEmbedded(this, mWebView);
+ }
+ return mEmbeddedZoomControl;
+ } else {
+ if (mExternalZoomControl == null) {
+ mExternalZoomControl = new ZoomControlExternal(mWebView);
+ }
+ return mExternalZoomControl;
+ }
+ }
+ return null;
+ }
+
+ public void invokeZoomPicker() {
+ ZoomControlBase control = getCurrentZoomControl();
+ if (control != null) {
+ control.show();
+ }
+ }
+
+ public void dismissZoomPicker() {
+ ZoomControlBase control = getCurrentZoomControl();
+ if (control != null) {
+ control.hide();
+ }
+ }
+
+ public boolean isZoomPickerVisible() {
+ ZoomControlBase control = getCurrentZoomControl();
+ return (control != null) ? control.isVisible() : false;
+ }
+
+ public void updateZoomPicker() {
+ ZoomControlBase control = getCurrentZoomControl();
+ if (control != null) {
+ control.update();
+ }
+ }
+
+ /**
+ * The embedded zoom control intercepts touch events and automatically stays
+ * visible. The external control needs to constantly refresh its internal
+ * timer to stay visible.
+ */
+ public void keepZoomPickerVisible() {
+ ZoomControlBase control = getCurrentZoomControl();
+ if (control != null && control == mExternalZoomControl) {
+ control.show();
+ }
+ }
+
+ public View getExternalZoomPicker() {
+ ZoomControlBase control = getCurrentZoomControl();
+ if (control != null && control == mExternalZoomControl) {
+ return mExternalZoomControl.getControls();
+ } else {
+ return null;
+ }
+ }
+}
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index fcfecb3..c11c7e1 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -559,6 +559,16 @@
boolean smoothScrollbar = a.getBoolean(R.styleable.AbsListView_smoothScrollbar, true);
setSmoothScrollbarEnabled(smoothScrollbar);
+
+ final int adapterId = a.getResourceId(R.styleable.AbsListView_adapter, 0);
+ if (adapterId != 0) {
+ final Context c = context;
+ post(new Runnable() {
+ public void run() {
+ setAdapter(Adapters.loadAdapter(c, adapterId));
+ }
+ });
+ }
a.recycle();
}
@@ -1575,6 +1585,11 @@
treeObserver.addOnGlobalLayoutListener(this);
}
}
+
+ if (mAdapter != null && mDataSetObserver == null) {
+ mDataSetObserver = new AdapterDataSetObserver();
+ mAdapter.registerDataSetObserver(mDataSetObserver);
+ }
}
@Override
@@ -1595,6 +1610,11 @@
mGlobalLayoutListenerAddedFilter = false;
}
}
+
+ if (mAdapter != null) {
+ mAdapter.unregisterDataSetObserver(mDataSetObserver);
+ mDataSetObserver = null;
+ }
}
@Override
diff --git a/core/java/android/widget/Adapters.java b/core/java/android/widget/Adapters.java
new file mode 100644
index 0000000..05e501a
--- /dev/null
+++ b/core/java/android/widget/Adapters.java
@@ -0,0 +1,1191 @@
+/*
+ * 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.widget;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.database.Cursor;
+import android.graphics.BitmapFactory;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.util.AttributeSet;
+import android.util.Xml;
+import android.view.View;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import static com.android.internal.R.*;
+
+/**
+ * <p>This class can be used to load {@link android.widget.Adapter adapters} defined in
+ * XML resources. XML-defined adapters can be used to easily create adapters in your
+ * own application or to pass adapters to other processes.</p>
+ *
+ * <h2>Types of adapters</h2>
+ * <p>Adapters defined using XML resources can only be one of the following supported
+ * types. Arbitrary adapters are not supported to guarantee the safety of the loaded
+ * code when adapters are loaded across packages.</p>
+ * <ul>
+ * <li><a href="#xml-cursor-adapter">Cursor adapter</a>: a cursor adapter can be used
+ * to display the content of a cursor, most often coming from a content provider</li>
+ * </ul>
+ * <p>The complete XML format definition of each adapter type is available below.</p>
+ *
+ * <a name="xml-cursor-adapter" />
+ * <h2>Cursor adapter</h2>
+ * <p>A cursor adapter XML definition starts with the
+ * <a href="#xml-cursor-adapter-tag"><code><cursor-adapter /></code></a>
+ * tag and may contain one or more instances of the following tags:</p>
+ * <ul>
+ * <li><a href="#xml-cursor-adapter-select-tag"><code><select /></code></a></li>
+ * <li><a href="#xml-cursor-adapter-bind-tag"><code><bind /></code></a></li>
+ * </ul>
+ *
+ * <a name="xml-cursor-adapter-tag" />
+ * <h3><cursor-adapter /></h3>
+ * <p>The <code><cursor-adapter /></code> element defines the beginning of the
+ * document and supports the following attributes:</p>
+ * <ul>
+ * <li><code>android:layout</code>: Reference to the XML layout to be inflated for
+ * each item of the adapter. This attribute is mandatory.</li>
+ * <li><code>android:selection</code>: Selection expression, used when the
+ * <code>android:uri</code> attribute is defined or when the adapter is loaded with
+ * {@link android.widget.Adapters#loadCursorAdapter(android.content.Context, int, String, Object[])}.
+ * This attribute is optional.</li>
+ * <li><code>android:sortOrder</code>: Sort expression, used when the
+ * <code>android:uri</code> attribute is defined or when the adapter is loaded with
+ * {@link android.widget.Adapters#loadCursorAdapter(android.content.Context, int, String, Object[])}.
+ * This attribute is optional.</li>
+ * <li><code>android:uri</code>: URI of the content provider to query to retrieve a cursor.
+ * Specifying this attribute is equivalent to calling {@link android.widget.Adapters#loadCursorAdapter(android.content.Context, int, String, Object[])}.
+ * If you call this method, the value of the XML attribute is ignored. This attribute is
+ * optional.</li>
+ * </ul>
+ * <p>In addition, you can specify one or more instances of
+ * <a href="#xml-cursor-adapter-select-tag"><code><select /></code></a> and
+ * <a href="#xml-cursor-adapter-bind-tag"><code><bind /></code></a> tags as children
+ * of <code><cursor-adapter /></code>.</p>
+ *
+ * <a name="xml-cursor-adapter-select-tag" />
+ * <h3><select /></h3>
+ * <p>The <code><select /></code> tag is used to select columns from the cursor
+ * when doing the query. This can be very useful when using transformations in the
+ * <code><bind /></code> elements. It can also be very useful if you are providing
+ * your own <a href="#xml-cursor-adapter-bind-data-types">binder</a> or
+ * <a href="#xml-cursor-adapter-bind-data-types">transformation</a> classes.
+ * <code><select /></code> elements are ignored if you supply the cursor yourself.</p>
+ * <p>The <code><select /></code> supports the following attributes:</p>
+ * <ul>
+ * <li><code>android:column</code>: Name of the column to select in the cursor during the
+ * query operation</li>
+ * </ul>
+ * <p><strong>Note:</strong> The column named <code>_id</code> is always implicitely
+ * selected.</p>
+ *
+ * <a name="xml-cursor-adapter-bind-tag" />
+ * <h3><bind /></h3>
+ * <p>The <code><bind /></code> tag is used to bind a column from the cursor to
+ * a {@link android.view.View}. A column bound using this tag is automatically selected
+ * during the query and a matching
+ * <a href="#xml-cursor-adapter-select-tag"><code><select /></code> tag is therefore
+ * not required.</p>
+ *
+ * <p>Each binding is declared as a one to one matching but
+ * custom binder classes or special
+ * <a href="#xml-cursor-adapter-bind-data-transformation">data transformations</a> can
+ * allow you to bind several columns to a single view. In this case you must use the
+ * <a href="#xml-cursor-adapter-select-tag"><code><select /></code> tag to make
+ * sure any required column is part of the query.</p>
+ *
+ * <p>The <code><bind /></code> tag supports the following attributes:</p>
+ * <ul>
+ * <li><code>android:from</code>: The name of the column to bind from.
+ * This attribute is mandatory.</li>
+ * <li><code>android:to</code>: The id of the view to bind to. This attribute is mandatory.</li>
+ * <li><code>android:as</code>: The <a href="#xml-cursor-adapter-bind-data-types">data type</a>
+ * of the binding. This attribute is mandatory.</li>
+ * </ul>
+ *
+ * <p>In addition, a <code><bind /></code> can contain zero or more instances of
+ * <a href="#xml-cursor-adapter-bind-data-transformation">data transformations</a> chilren
+ * tags.</p>
+ *
+ * <a name="xml-cursor-adapter-bind-data-types" />
+ * <h4>Binding data types</h4>
+ * <p>For a binding to occur the data type of the bound column/view pair must be specified.
+ * The following data types are currently supported:</p>
+ * <ul>
+ * <li><code>string</code>: The content of the column is interpreted as a string and must be
+ * bound to a {@link android.widget.TextView}</li>
+ * <li><code>image</code>: The content of the column is interpreted as a blob describing an
+ * image and must be bound to an {@link android.widget.ImageView}</li>
+ * <li><code>image-uri</code>: The content of the column is interpreted as a URI to an image
+ * and must be bound to an {@link android.widget.ImageView}</li>
+ * <li><code>drawable</code>: The content of the column is interpreted as a resource id to a
+ * drawable and must be bound to an {@link android.widget.ImageView}</li>
+ * <li>A fully qualified class name: The name of a class corresponding to an implementation of
+ * {@link android.widget.Adapters.CursorBinder}. Cursor binders can be used to provide
+ * bindings not supported by default. Custom binders cannot be used with
+ * {@link android.content.Context#isRestricted() restricted contexts}, for instance in an
+ * app widget</li>
+ * </ul>
+ *
+ * <a name="xml-cursor-adapter-bind-transformation" />
+ * <h4>Binding transformations</h4>
+ * <p>When defining a data binding you can specify an optional transformation by using one
+ * of the following tags as a child of a <code><bind /></code> elements:</p>
+ * <ul>
+ * <li><code><map /></code>: Maps a constant string to a string or a resource. Use
+ * one instance of this tag per value you want to map</li>
+ * <li><code><transform /></code>: Transforms a column's value using an expression
+ * or an instance of {@link android.widget.Adapters.CursorTransformation}</li>
+ * </ul>
+ * <p>While several <code><map /></code> tags can be used at the same time, you cannot
+ * mix <code><map /></code> and <code><transform /></code> tags. If several
+ * <code><transform /></code> tags are specified, only the last one is retained.</p>
+ *
+ * <a name="xml-cursor-adapter-bind-transformation-map" />
+ * <p><strong><map /></strong></p>
+ * <p>A map element simply specifies a value to match from and a value to match to. When
+ * a column's value equals the value to match from, it is replaced with the value to match
+ * to. The following attributes are supported:</p>
+ * <ul>
+ * <li><code>android:fromValue</code>: The value to match from. This attribute is mandatory</li>
+ * <li><code>android:toValue</code>: The value to match to. This value can be either a string
+ * or a resource identifier. This value is interpreted as a resource identifier when the
+ * data binding is of type <code>drawable</code>. This attribute is mandatory</li>
+ * </ul>
+ *
+ * <a name="xml-cursor-adapter-bind-transformation-transform" />
+ * <p><strong><transform /></strong></p>
+ * <p>A simple transform that occurs either by calling a specified class or by performing
+ * simple text substitution. The following attributes are supported:</p>
+ * <ul>
+ * <li><code>android:withExpression</code>: The transformation expression. The expression is
+ * a string containing column names surrounded with curly braces { and }. During the
+ * transformation each column name is replaced by its value. All columns must have been
+ * selected in the query. An example of expression is <code>"First name: {first_name},
+ * last name: {last_name}"</code>. This attribute is mandatory
+ * if <code>android:withClass</code> is not specified and ignored if <code>android:withClass</code>
+ * is specified</li>
+ * <li><code>android:withClass</code>: A fully qualified class name corresponding to an
+ * implementation of {@link android.widget.Adapters.CursorTransformation}. Custom
+ * transformationscannot be used with
+ * {@link android.content.Context#isRestricted() restricted contexts}, for instance in
+ * an app widget This attribute is mandatory if <code>android:withExpression</code> is
+ * not specified</li>
+ * </ul>
+ *
+ * <h3>Example</h3>
+ * <p>The following example defines a cursor adapter that queries all the contacts with
+ * a phone number using the contacts content provider. Each contact is displayed with
+ * its display name, its favorite status and its photo. To display photos, a custom data
+ * binder is declared:</p>
+ *
+ * <pre class="prettyprint">
+ * <cursor-adapter xmlns:android="http://schemas.android.com/apk/res/android"
+ * android:uri="content://com.android.contacts/contacts"
+ * android:selection="has_phone_number=1"
+ * android:layout="@layout/contact_item">
+ *
+ * <bind android:from="display_name" android:to="@id/name" android:as="string" />
+ * <bind android:from="starred" android:to="@id/star" android:as="drawable">
+ * <map android:fromValue="0" android:toValue="@android:drawable/star_big_off" />
+ * <map android:fromValue="1" android:toValue="@android:drawable/star_big_on" />
+ * </bind>
+ * <bind android:from="_id" android:to="@id/name"
+ * android:as="com.google.android.test.adapters.ContactPhotoBinder" />
+ *
+ * </cursor-adapter>
+ * </pre>
+ *
+ * <h3>Related APIs</h3>
+ * <ul>
+ * <li>{@link android.widget.Adapters#loadAdapter(android.content.Context, int, Object[])}</li>
+ * <li>{@link android.widget.Adapters#loadCursorAdapter(android.content.Context, int, android.database.Cursor, Object[])}</li>
+ * <li>{@link android.widget.Adapters#loadCursorAdapter(android.content.Context, int, String, Object[])}</li>
+ * <li>{@link android.widget.Adapters.CursorBinder}</li>
+ * <li>{@link android.widget.Adapters.CursorTransformation}</li>
+ * <li>{@link android.widget.CursorAdapter}</li>
+ * </ul>
+ *
+ * @see android.widget.Adapter
+ * @see android.content.ContentProvider
+ *
+ * @attr ref android.R.styleable#CursorAdapter_layout
+ * @attr ref android.R.styleable#CursorAdapter_selection
+ * @attr ref android.R.styleable#CursorAdapter_sortOrder
+ * @attr ref android.R.styleable#CursorAdapter_uri
+ * @attr ref android.R.styleable#CursorAdapter_BindItem_as
+ * @attr ref android.R.styleable#CursorAdapter_BindItem_from
+ * @attr ref android.R.styleable#CursorAdapter_BindItem_to
+ * @attr ref android.R.styleable#CursorAdapter_MapItem_fromValue
+ * @attr ref android.R.styleable#CursorAdapter_MapItem_toValue
+ * @attr ref android.R.styleable#CursorAdapter_SelectItem_column
+ * @attr ref android.R.styleable#CursorAdapter_TransformItem_withClass
+ * @attr ref android.R.styleable#CursorAdapter_TransformItem_withExpression
+ */
+@SuppressWarnings({"JavadocReference"})
+public class Adapters {
+ private static final String ADAPTER_CURSOR = "cursor-adapter";
+
+ /**
+ * <p>Interface used to bind a {@link android.database.Cursor} column to a View. This
+ * interface can be used to provide bindings for data types not supported by the
+ * standard implementation of {@link android.widget.Adapters}.</p>
+ *
+ * <p>A binder is provided with a cursor transformation which may or may not be used
+ * to transform the value retrieved from the cursor. The transformation is guaranteed
+ * to never be null so it's always safe to apply the transformation.</p>
+ *
+ * <p>The binder is associated with a Context but can be re-used with multiple cursors.
+ * As such, the implementation should make no assumption about the Cursor in use.</p>
+ *
+ * @see android.view.View
+ * @see android.database.Cursor
+ * @see android.widget.Adapters.CursorTransformation
+ */
+ public static abstract class CursorBinder {
+ /**
+ * <p>The context associated with this binder.</p>
+ */
+ protected final Context mContext;
+
+ /**
+ * <p>The transformation associated with this binder. This transformation is never
+ * null and may or may not be applied to the Cursor data during the
+ * {@link #bind(android.view.View, android.database.Cursor, int)} operation.</p>
+ *
+ * @see #bind(android.view.View, android.database.Cursor, int)
+ */
+ protected final CursorTransformation mTransformation;
+
+ /**
+ * <p>Creates a new Cursor binder.</p>
+ *
+ * @param context The context associated with this binder.
+ * @param transformation The transformation associated with this binder. This
+ * transformation may or may not be applied by the binder and is guaranteed
+ * to not be null.
+ */
+ public CursorBinder(Context context, CursorTransformation transformation) {
+ mContext = context;
+ mTransformation = transformation;
+ }
+
+ /**
+ * <p>Binds the specified Cursor column to the supplied View. The binding operation
+ * can query other Cursor columns as needed. During the binding operation, values
+ * retrieved from the Cursor may or may not be transformed using this binder's
+ * cursor transformation.</p>
+ *
+ * @param view The view to bind data to.
+ * @param cursor The cursor to bind data from.
+ * @param columnIndex The column index in the cursor where the data to bind resides.
+ *
+ * @see #mTransformation
+ *
+ * @return True if the column was successfully bound to the View, false otherwise.
+ */
+ public abstract boolean bind(View view, Cursor cursor, int columnIndex);
+ }
+
+ /**
+ * <p>Interface used to transform data coming out of a {@link android.database.Cursor}
+ * before it is bound to a {@link android.view.View}.</p>
+ *
+ * <p>Transformations are used to transform text-based data (in the form of a String),
+ * or to transform data into a resource identifier. A default implementation is provided
+ * to generate resource identifiers.</p>
+ *
+ * @see android.database.Cursor
+ * @see android.widget.Adapters.CursorBinder
+ */
+ public static abstract class CursorTransformation {
+ /**
+ * <p>The context associated with this transformation.</p>
+ */
+ protected final Context mContext;
+
+ /**
+ * <p>Creates a new Cursor transformation.</p>
+ *
+ * @param context The context associated with this transformation.
+ */
+ public CursorTransformation(Context context) {
+ mContext = context;
+ }
+
+ /**
+ * <p>Transforms the specified Cursor column into a String. The transformation
+ * can simply return the content of the column as a String (this is known
+ * as the identity transformation) or manipulate the content. For instance,
+ * a transformation can perform text substitutions or concatenate other
+ * columns with the specified column.</p>
+ *
+ * @param cursor The cursor that contains the data to transform.
+ * @param columnIndex The index of the column to transform.
+ *
+ * @return A String containing the transformed value of the column.
+ */
+ public abstract String transform(Cursor cursor, int columnIndex);
+
+ /**
+ * <p>Transforms the specified Cursor column into a resource identifier.
+ * The default implementation simply interprets the content of the column
+ * as an integer.</p>
+ *
+ * @param cursor The cursor that contains the data to transform.
+ * @param columnIndex The index of the column to transform.
+ *
+ * @return A resource identifier.
+ */
+ public int transformToResource(Cursor cursor, int columnIndex) {
+ return cursor.getInt(columnIndex);
+ }
+ }
+
+ /**
+ * <p>Loads the {@link android.widget.CursorAdapter} defined in the specified
+ * XML resource. The content of the adapter is loaded from the content provider
+ * identified by the supplied URI.</p>
+ *
+ * <p><strong>Note:</strong> If the supplied {@link android.content.Context} is
+ * an {@link android.app.Activity}, the cursor returned by the content provider
+ * will be automatically managed. Otherwise, you are responsible for managing the
+ * cursor yourself.</p>
+ *
+ * <p>The format of the XML definition of the cursor adapter is documented at
+ * the top of this page.</p>
+ *
+ * @param context The context to load the XML resource from.
+ * @param id The identifier of the XML resource declaring the adapter.
+ * @param uri The URI of the content provider.
+ * @param parameters Optional parameters to pass to the CursorAdapter, used
+ * to substitute values in the selection expression.
+ *
+ * @return A {@link android.widget.CursorAdapter}
+ *
+ * @throws IllegalArgumentException If the XML resource does not contain
+ * a valid <cursor-adapter /> definition.
+ *
+ * @see android.content.ContentProvider
+ * @see android.widget.CursorAdapter
+ * @see #loadAdapter(android.content.Context, int, Object[])
+ */
+ public static CursorAdapter loadCursorAdapter(Context context, int id, String uri,
+ Object... parameters) {
+
+ XmlCursorAdapter adapter = (XmlCursorAdapter) loadAdapter(context, id, ADAPTER_CURSOR,
+ parameters);
+
+ if (uri != null) {
+ adapter.setUri(uri);
+ }
+ adapter.load();
+
+ return adapter;
+ }
+
+ /**
+ * <p>Loads the {@link android.widget.CursorAdapter} defined in the specified
+ * XML resource. The content of the adapter is loaded from the specified cursor.
+ * You are responsible for managing the supplied cursor.</p>
+ *
+ * <p>The format of the XML definition of the cursor adapter is documented at
+ * the top of this page.</p>
+ *
+ * @param context The context to load the XML resource from.
+ * @param id The identifier of the XML resource declaring the adapter.
+ * @param cursor The cursor containing the data for the adapter.
+ * @param parameters Optional parameters to pass to the CursorAdapter, used
+ * to substitute values in the selection expression.
+ *
+ * @return A {@link android.widget.CursorAdapter}
+ *
+ * @throws IllegalArgumentException If the XML resource does not contain
+ * a valid <cursor-adapter /> definition.
+ *
+ * @see android.content.ContentProvider
+ * @see android.widget.CursorAdapter
+ * @see android.database.Cursor
+ * @see #loadAdapter(android.content.Context, int, Object[])
+ */
+ public static CursorAdapter loadCursorAdapter(Context context, int id, Cursor cursor,
+ Object... parameters) {
+
+ XmlCursorAdapter adapter = (XmlCursorAdapter) loadAdapter(context, id, ADAPTER_CURSOR,
+ parameters);
+
+ if (cursor != null) {
+ adapter.changeCursor(cursor);
+ }
+
+ return adapter;
+ }
+
+ /**
+ * <p>Loads the adapter defined in the specified XML resource. The XML definition of
+ * the adapter must follow the format definition of one of the supported adapter
+ * types described at the top of this page.</p>
+ *
+ * <p><strong>Note:</strong> If the loaded adapter is a {@link android.widget.CursorAdapter}
+ * and the supplied {@link android.content.Context} is an {@link android.app.Activity},
+ * the cursor returned by the content provider will be automatically managed. Otherwise,
+ * you are responsible for managing the cursor yourself.</p>
+ *
+ * @param context The context to load the XML resource from.
+ * @param id The identifier of the XML resource declaring the adapter.
+ * @param parameters Optional parameters to pass to the adapter.
+ *
+ * @return An adapter instance.
+ *
+ * @see #loadCursorAdapter(android.content.Context, int, android.database.Cursor, Object[])
+ * @see #loadCursorAdapter(android.content.Context, int, String, Object[])
+ */
+ public static BaseAdapter loadAdapter(Context context, int id, Object... parameters) {
+ final BaseAdapter adapter = loadAdapter(context, id, null, parameters);
+ if (adapter instanceof ManagedAdapter) {
+ ((ManagedAdapter) adapter).load();
+ }
+ return adapter;
+ }
+
+ /**
+ * Loads an adapter from the specified XML resource. The optional assertName can
+ * be used to exit early if the adapter defined in the XML resource is not of the
+ * expected type.
+ *
+ * @param context The context to associate with the adapter.
+ * @param id The resource id of the XML document defining the adapter.
+ * @param assertName The mandatory name of the adapter in the XML document.
+ * Ignored if null.
+ * @param parameters Optional parameters passed to the adapter.
+ *
+ * @return An instance of {@link android.widget.BaseAdapter}.
+ */
+ private static BaseAdapter loadAdapter(Context context, int id, String assertName,
+ Object... parameters) {
+
+ XmlResourceParser parser = null;
+ try {
+ parser = context.getResources().getXml(id);
+ return createAdapterFromXml(context, parser, Xml.asAttributeSet(parser),
+ id, parameters, assertName);
+ } catch (XmlPullParserException ex) {
+ Resources.NotFoundException rnf = new Resources.NotFoundException(
+ "Can't load adapter resource ID " +
+ context.getResources().getResourceEntryName(id));
+ rnf.initCause(ex);
+ throw rnf;
+ } catch (IOException ex) {
+ Resources.NotFoundException rnf = new Resources.NotFoundException(
+ "Can't load adapter resource ID " +
+ context.getResources().getResourceEntryName(id));
+ rnf.initCause(ex);
+ throw rnf;
+ } finally {
+ if (parser != null) parser.close();
+ }
+ }
+
+ /**
+ * Generates an adapter using the specified XML parser. This method is responsible
+ * for choosing the type of the adapter to create based on the content of the
+ * XML parser.
+ *
+ * This method will generate an {@link IllegalArgumentException} if
+ * <code>assertName</code> is not null and does not match the root tag of the XML
+ * document.
+ */
+ private static BaseAdapter createAdapterFromXml(Context c,
+ XmlPullParser parser, AttributeSet attrs, int id, Object[] parameters,
+ String assertName) throws XmlPullParserException, IOException {
+
+ BaseAdapter adapter = null;
+
+ // Make sure we are on a start tag.
+ int type;
+ int depth = parser.getDepth();
+
+ while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) &&
+ type != XmlPullParser.END_DOCUMENT) {
+
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+
+ String name = parser.getName();
+ if (assertName != null && !assertName.equals(name)) {
+ throw new IllegalArgumentException("The adapter defined in " +
+ c.getResources().getResourceEntryName(id) + " must be a <" + name + " />");
+ }
+
+ if (ADAPTER_CURSOR.equals(name)) {
+ adapter = createCursorAdapter(c, parser, attrs, id, parameters);
+ } else {
+ throw new IllegalArgumentException("Unknown adapter name " + parser.getName() +
+ " in " + c.getResources().getResourceEntryName(id));
+ }
+ }
+
+ return adapter;
+
+ }
+
+ /**
+ * Creates an XmlCursorAdapter using an XmlCursorAdapterParser.
+ */
+ private static XmlCursorAdapter createCursorAdapter(Context c, XmlPullParser parser,
+ AttributeSet attrs, int id, Object[] parameters)
+ throws IOException, XmlPullParserException {
+
+ return new XmlCursorAdapterParser(c, parser, attrs, id).parse(parameters);
+ }
+
+ /**
+ * Parser that can generate XmlCursorAdapter instances. This parser is responsible for
+ * handling all the attributes and child nodes for a <cursor-adapter />.
+ */
+ private static class XmlCursorAdapterParser {
+ private static final String ADAPTER_CURSOR_BIND = "bind";
+ private static final String ADAPTER_CURSOR_SELECT = "select";
+ private static final String ADAPTER_CURSOR_AS_STRING = "string";
+ private static final String ADAPTER_CURSOR_AS_IMAGE = "image";
+ private static final String ADAPTER_CURSOR_AS_IMAGE_URI = "image-uri";
+ private static final String ADAPTER_CURSOR_AS_DRAWABLE = "drawable";
+ private static final String ADAPTER_CURSOR_MAP = "map";
+ private static final String ADAPTER_CURSOR_TRANSFORM = "transform";
+
+ private final Context mContext;
+ private final XmlPullParser mParser;
+ private final AttributeSet mAttrs;
+ private final int mId;
+
+ private final HashMap<String, CursorBinder> mBinders;
+ private final ArrayList<String> mFrom;
+ private final ArrayList<Integer> mTo;
+ private final CursorTransformation mIdentity;
+ private final Resources mResources;
+
+ public XmlCursorAdapterParser(Context c, XmlPullParser parser, AttributeSet attrs, int id) {
+ mContext = c;
+ mParser = parser;
+ mAttrs = attrs;
+ mId = id;
+
+ mResources = mContext.getResources();
+ mBinders = new HashMap<String, CursorBinder>();
+ mFrom = new ArrayList<String>();
+ mTo = new ArrayList<Integer>();
+ mIdentity = new IdentityTransformation(mContext);
+ }
+
+ public XmlCursorAdapter parse(Object[] parameters)
+ throws IOException, XmlPullParserException {
+
+ Resources resources = mResources;
+ TypedArray a = resources.obtainAttributes(mAttrs, styleable.CursorAdapter);
+
+ String uri = a.getString(styleable.CursorAdapter_uri);
+ String selection = a.getString(styleable.CursorAdapter_selection);
+ String sortOrder = a.getString(styleable.CursorAdapter_sortOrder);
+ int layout = a.getResourceId(styleable.CursorAdapter_layout, 0);
+ if (layout == 0) {
+ throw new IllegalArgumentException("The layout specified in " +
+ resources.getResourceEntryName(mId) + " does not exist");
+ }
+
+ a.recycle();
+
+ XmlPullParser parser = mParser;
+ int type;
+ int depth = parser.getDepth();
+
+ while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) &&
+ type != XmlPullParser.END_DOCUMENT) {
+
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+
+ String name = parser.getName();
+
+ if (ADAPTER_CURSOR_BIND.equals(name)) {
+ parseBindTag();
+ } else if (ADAPTER_CURSOR_SELECT.equals(name)) {
+ parseSelectTag();
+ } else {
+ throw new RuntimeException("Unknown tag name " + parser.getName() + " in " +
+ resources.getResourceEntryName(mId));
+ }
+ }
+
+ String[] fromArray = mFrom.toArray(new String[mFrom.size()]);
+ int[] toArray = new int[mTo.size()];
+ for (int i = 0; i < toArray.length; i++) {
+ toArray[i] = mTo.get(i);
+ }
+
+ String[] selectionArgs = null;
+ if (parameters != null) {
+ selectionArgs = new String[parameters.length];
+ for (int i = 0; i < selectionArgs.length; i++) {
+ selectionArgs[i] = (String) parameters[i];
+ }
+ }
+
+ return new XmlCursorAdapter(mContext, layout, uri, fromArray, toArray, selection,
+ selectionArgs, sortOrder, mBinders);
+ }
+
+ private void parseSelectTag() {
+ TypedArray a = mResources.obtainAttributes(mAttrs, styleable.CursorAdapter_SelectItem);
+
+ String fromName = a.getString(styleable.CursorAdapter_SelectItem_column);
+ if (fromName == null) {
+ throw new IllegalArgumentException("A select item in " +
+ mResources.getResourceEntryName(mId) + " does not have a 'column' attribute");
+ }
+
+ a.recycle();
+
+ mFrom.add(fromName);
+ mTo.add(View.NO_ID);
+ }
+
+ private void parseBindTag() throws IOException, XmlPullParserException {
+ Resources resources = mResources;
+ TypedArray a = resources.obtainAttributes(mAttrs, styleable.CursorAdapter_BindItem);
+
+ String fromName = a.getString(styleable.CursorAdapter_BindItem_from);
+ if (fromName == null) {
+ throw new IllegalArgumentException("A bind item in " +
+ resources.getResourceEntryName(mId) + " does not have a 'from' attribute");
+ }
+
+ int toName = a.getResourceId(styleable.CursorAdapter_BindItem_to, 0);
+ if (toName == 0) {
+ throw new IllegalArgumentException("A bind item in " +
+ resources.getResourceEntryName(mId) + " does not have a 'to' attribute");
+ }
+
+ String asType = a.getString(styleable.CursorAdapter_BindItem_as);
+ if (asType == null) {
+ throw new IllegalArgumentException("A bind item in " +
+ resources.getResourceEntryName(mId) + " does not have an 'as' attribute");
+ }
+
+ mFrom.add(fromName);
+ mTo.add(toName);
+ mBinders.put(fromName, findBinder(asType));
+
+ a.recycle();
+ }
+
+ private CursorBinder findBinder(String type) throws IOException, XmlPullParserException {
+ final XmlPullParser parser = mParser;
+ final Context context = mContext;
+ CursorTransformation transformation = mIdentity;
+
+ int tagType;
+ int depth = parser.getDepth();
+
+ final boolean isDrawable = ADAPTER_CURSOR_AS_DRAWABLE.equals(type);
+
+ while (((tagType = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
+ && tagType != XmlPullParser.END_DOCUMENT) {
+
+ if (tagType != XmlPullParser.START_TAG) {
+ continue;
+ }
+
+ String name = parser.getName();
+
+ if (ADAPTER_CURSOR_TRANSFORM.equals(name)) {
+ transformation = findTransformation();
+ } else if (ADAPTER_CURSOR_MAP.equals(name)) {
+ if (!(transformation instanceof MapTransformation)) {
+ transformation = new MapTransformation(context);
+ }
+ findMap(((MapTransformation) transformation), isDrawable);
+ } else {
+ throw new RuntimeException("Unknown tag name " + parser.getName() + " in " +
+ context.getResources().getResourceEntryName(mId));
+ }
+ }
+
+ if (ADAPTER_CURSOR_AS_STRING.equals(type)) {
+ return new StringBinder(context, transformation);
+ } else if (ADAPTER_CURSOR_AS_IMAGE.equals(type)) {
+ return new ImageBinder(context, transformation);
+ } else if (ADAPTER_CURSOR_AS_IMAGE_URI.equals(type)) {
+ return new ImageUriBinder(context, transformation);
+ } else if (isDrawable) {
+ return new DrawableBinder(context, transformation);
+ } else {
+ return createBinder(type, transformation);
+ }
+ }
+
+ private CursorBinder createBinder(String type, CursorTransformation transformation) {
+ if (mContext.isRestricted()) return null;
+
+ try {
+ final Class<?> klass = Class.forName(type, true, mContext.getClassLoader());
+ if (CursorBinder.class.isAssignableFrom(klass)) {
+ final Constructor<?> c = klass.getDeclaredConstructor(
+ Context.class, CursorTransformation.class);
+ return (CursorBinder) c.newInstance(mContext, transformation);
+ }
+ } catch (ClassNotFoundException e) {
+ throw new IllegalArgumentException("Cannot instanciate binder type in " +
+ mContext.getResources().getResourceEntryName(mId) + ": " + type, e);
+ } catch (NoSuchMethodException e) {
+ throw new IllegalArgumentException("Cannot instanciate binder type in " +
+ mContext.getResources().getResourceEntryName(mId) + ": " + type, e);
+ } catch (InvocationTargetException e) {
+ throw new IllegalArgumentException("Cannot instanciate binder type in " +
+ mContext.getResources().getResourceEntryName(mId) + ": " + type, e);
+ } catch (InstantiationException e) {
+ throw new IllegalArgumentException("Cannot instanciate binder type in " +
+ mContext.getResources().getResourceEntryName(mId) + ": " + type, e);
+ } catch (IllegalAccessException e) {
+ throw new IllegalArgumentException("Cannot instanciate binder type in " +
+ mContext.getResources().getResourceEntryName(mId) + ": " + type, e);
+ }
+
+ return null;
+ }
+
+ private void findMap(MapTransformation transformation, boolean drawable) {
+ Resources resources = mResources;
+
+ TypedArray a = resources.obtainAttributes(mAttrs, styleable.CursorAdapter_MapItem);
+
+ String from = a.getString(styleable.CursorAdapter_MapItem_fromValue);
+ if (from == null) {
+ throw new IllegalArgumentException("A map item in " +
+ resources.getResourceEntryName(mId) + " does not have a 'fromValue' attribute");
+ }
+
+ if (!drawable) {
+ String to = a.getString(styleable.CursorAdapter_MapItem_toValue);
+ if (to == null) {
+ throw new IllegalArgumentException("A map item in " +
+ resources.getResourceEntryName(mId) + " does not have a 'toValue' attribute");
+ }
+ transformation.addStringMapping(from, to);
+ } else {
+ int to = a.getResourceId(styleable.CursorAdapter_MapItem_toValue, 0);
+ if (to == 0) {
+ throw new IllegalArgumentException("A map item in " +
+ resources.getResourceEntryName(mId) + " does not have a 'toValue' attribute");
+ }
+ transformation.addResourceMapping(from, to);
+ }
+
+ a.recycle();
+ }
+
+ private CursorTransformation findTransformation() {
+ Resources resources = mResources;
+ CursorTransformation transformation = null;
+ TypedArray a = resources.obtainAttributes(mAttrs, styleable.CursorAdapter_TransformItem);
+
+ String className = a.getString(styleable.CursorAdapter_TransformItem_withClass);
+ if (className == null) {
+ String expression = a.getString(
+ styleable.CursorAdapter_TransformItem_withExpression);
+ transformation = createExpressionTransformation(expression);
+ } else if (!mContext.isRestricted()) {
+ try {
+ final Class<?> klass = Class.forName(className, true, mContext.getClassLoader());
+ if (CursorTransformation.class.isAssignableFrom(klass)) {
+ final Constructor<?> c = klass.getDeclaredConstructor(Context.class);
+ transformation = (CursorTransformation) c.newInstance(mContext);
+ }
+ } catch (ClassNotFoundException e) {
+ throw new IllegalArgumentException("Cannot instanciate transform type in " +
+ mContext.getResources().getResourceEntryName(mId) + ": " + className, e);
+ } catch (NoSuchMethodException e) {
+ throw new IllegalArgumentException("Cannot instanciate transform type in " +
+ mContext.getResources().getResourceEntryName(mId) + ": " + className, e);
+ } catch (InvocationTargetException e) {
+ throw new IllegalArgumentException("Cannot instanciate transform type in " +
+ mContext.getResources().getResourceEntryName(mId) + ": " + className, e);
+ } catch (InstantiationException e) {
+ throw new IllegalArgumentException("Cannot instanciate transform type in " +
+ mContext.getResources().getResourceEntryName(mId) + ": " + className, e);
+ } catch (IllegalAccessException e) {
+ throw new IllegalArgumentException("Cannot instanciate transform type in " +
+ mContext.getResources().getResourceEntryName(mId) + ": " + className, e);
+ }
+ }
+
+ a.recycle();
+
+ if (transformation == null) {
+ throw new IllegalArgumentException("A transform item in " +
+ resources.getResourceEntryName(mId) + " must have a 'withClass' or " +
+ "'withExpression' attribute");
+ }
+
+ return transformation;
+ }
+
+ private CursorTransformation createExpressionTransformation(String expression) {
+ return new ExpressionTransformation(mContext, expression);
+ }
+ }
+
+ /**
+ * Interface used by adapters that require to be loaded after creation.
+ */
+ private static interface ManagedAdapter {
+ /**
+ * Loads the content of the adapter, asynchronously.
+ */
+ void load();
+ }
+
+ /**
+ * Implementation of a Cursor adapter defined in XML. This class is a thin wrapper
+ * of a SimpleCursorAdapter. The main difference is the ability to handle CursorBinders.
+ */
+ private static class XmlCursorAdapter extends SimpleCursorAdapter implements ManagedAdapter {
+ private final Context mContext;
+ private String mUri;
+ private final String mSelection;
+ private final String[] mSelectionArgs;
+ private final String mSortOrder;
+ private final String[] mColumns;
+ private final CursorBinder[] mBinders;
+ private AsyncTask<Void,Void,Cursor> mLoadTask;
+
+ XmlCursorAdapter(Context context, int layout, String uri, String[] from, int[] to,
+ String selection, String[] selectionArgs, String sortOrder,
+ HashMap<String, CursorBinder> binders) {
+
+ super(context, layout, null, from, to);
+ mContext = context;
+ mUri = uri;
+ mSelection = selection;
+ mSelectionArgs = selectionArgs;
+ mSortOrder = sortOrder;
+ mColumns = new String[from.length + 1];
+ // This is mandatory in CursorAdapter
+ mColumns[0] = "_id";
+ System.arraycopy(from, 0, mColumns, 1, from.length);
+
+ CursorBinder basic = new StringBinder(context, new IdentityTransformation(context));
+ final int count = from.length;
+ mBinders = new CursorBinder[count];
+
+ for (int i = 0; i < count; i++) {
+ CursorBinder binder = binders.get(from[i]);
+ if (binder == null) binder = basic;
+ mBinders[i] = binder;
+ }
+ }
+
+ @Override
+ public void bindView(View view, Context context, Cursor cursor) {
+ final int count = mTo.length;
+ final int[] from = mFrom;
+ final int[] to = mTo;
+ final CursorBinder[] binders = mBinders;
+
+ for (int i = 0; i < count; i++) {
+ final View v = view.findViewById(to[i]);
+ if (v != null) {
+ binders[i].bind(v, cursor, from[i]);
+ }
+ }
+ }
+
+ public void load() {
+ if (mUri != null) {
+ mLoadTask = new QueryTask().execute();
+ }
+ }
+
+ void setUri(String uri) {
+ mUri = uri;
+ }
+
+ @Override
+ public void changeCursor(Cursor c) {
+ if (mLoadTask != null && mLoadTask.getStatus() != QueryTask.Status.FINISHED) {
+ mLoadTask.cancel(true);
+ mLoadTask = null;
+ }
+ super.changeCursor(c);
+ }
+
+ class QueryTask extends AsyncTask<Void, Void, Cursor> {
+ @Override
+ protected Cursor doInBackground(Void... params) {
+ if (mContext instanceof Activity) {
+ return ((Activity) mContext).managedQuery(
+ Uri.parse(mUri), mColumns, mSelection, mSelectionArgs, mSortOrder);
+ } else {
+ return mContext.getContentResolver().query(
+ Uri.parse(mUri), mColumns, mSelection, mSelectionArgs, mSortOrder);
+ }
+ }
+
+ @Override
+ protected void onPostExecute(Cursor cursor) {
+ if (!isCancelled()) {
+ XmlCursorAdapter.super.changeCursor(cursor);
+ }
+ }
+ }
+ }
+
+ /**
+ * Identity transformation, returns the content of the specified column as a String,
+ * without performing any manipulation. This is used when no transformation is specified.
+ */
+ private static class IdentityTransformation extends CursorTransformation {
+ public IdentityTransformation(Context context) {
+ super(context);
+ }
+
+ @Override
+ public String transform(Cursor cursor, int columnIndex) {
+ return cursor.getString(columnIndex);
+ }
+ }
+
+ /**
+ * An expression transformation is a simple template based replacement utility.
+ * In an expression, each segment of the form <code>{(^[}]+)}</code> is replaced
+ * with the value of the column of name $1.
+ */
+ private static class ExpressionTransformation extends CursorTransformation {
+ private final ExpressionNode mFirstNode = new ConstantExpressionNode("");
+ private final StringBuilder mBuilder = new StringBuilder();
+
+ public ExpressionTransformation(Context context, String expression) {
+ super(context);
+
+ parse(expression);
+ }
+
+ private void parse(String expression) {
+ ExpressionNode node = mFirstNode;
+ int segmentStart;
+ int count = expression.length();
+
+ for (int i = 0; i < count; i++) {
+ char c = expression.charAt(i);
+ // Start a column name segment
+ segmentStart = i;
+ if (c == '{') {
+ while (i < count && (c = expression.charAt(i)) != '}') {
+ i++;
+ }
+ // We've reached the end, but the expression didn't close
+ if (c != '}') {
+ throw new IllegalStateException("The transform expression contains a " +
+ "non-closed column name: " +
+ expression.substring(segmentStart + 1, i));
+ }
+ node.next = new ColumnExpressionNode(expression.substring(segmentStart + 1, i));
+ } else {
+ while (i < count && (c = expression.charAt(i)) != '{') {
+ i++;
+ }
+ node.next = new ConstantExpressionNode(expression.substring(segmentStart, i));
+ // Rewind if we've reached a column expression
+ if (c == '{') i--;
+ }
+ node = node.next;
+ }
+ }
+
+ @Override
+ public String transform(Cursor cursor, int columnIndex) {
+ final StringBuilder builder = mBuilder;
+ builder.delete(0, builder.length());
+
+ ExpressionNode node = mFirstNode;
+ // Skip the first node
+ while ((node = node.next) != null) {
+ builder.append(node.asString(cursor));
+ }
+
+ return builder.toString();
+ }
+
+ static abstract class ExpressionNode {
+ public ExpressionNode next;
+
+ public abstract String asString(Cursor cursor);
+ }
+
+ static class ConstantExpressionNode extends ExpressionNode {
+ private final String mConstant;
+
+ ConstantExpressionNode(String constant) {
+ mConstant = constant;
+ }
+
+ @Override
+ public String asString(Cursor cursor) {
+ return mConstant;
+ }
+ }
+
+ static class ColumnExpressionNode extends ExpressionNode {
+ private final String mColumnName;
+ private Cursor mSignature;
+ private int mColumnIndex = -1;
+
+ ColumnExpressionNode(String columnName) {
+ mColumnName = columnName;
+ }
+
+ @Override
+ public String asString(Cursor cursor) {
+ if (cursor != mSignature || mColumnIndex == -1) {
+ mColumnIndex = cursor.getColumnIndex(mColumnName);
+ mSignature = cursor;
+ }
+
+ return cursor.getString(mColumnIndex);
+ }
+ }
+ }
+
+ /**
+ * A map transformation offers a simple mapping between specified String values
+ * to Strings or integers.
+ */
+ private static class MapTransformation extends CursorTransformation {
+ private final HashMap<String, String> mStringMappings;
+ private final HashMap<String, Integer> mResourceMappings;
+
+ public MapTransformation(Context context) {
+ super(context);
+ mStringMappings = new HashMap<String, String>();
+ mResourceMappings = new HashMap<String, Integer>();
+ }
+
+ void addStringMapping(String from, String to) {
+ mStringMappings.put(from, to);
+ }
+
+ void addResourceMapping(String from, int to) {
+ mResourceMappings.put(from, to);
+ }
+
+ @Override
+ public String transform(Cursor cursor, int columnIndex) {
+ final String value = cursor.getString(columnIndex);
+ final String transformed = mStringMappings.get(value);
+ return transformed == null ? value : transformed;
+ }
+
+ @Override
+ public int transformToResource(Cursor cursor, int columnIndex) {
+ final String value = cursor.getString(columnIndex);
+ final Integer transformed = mResourceMappings.get(value);
+ try {
+ return transformed == null ? Integer.parseInt(value) : transformed;
+ } catch (NumberFormatException e) {
+ return 0;
+ }
+ }
+ }
+
+ /**
+ * Binds a String to a TextView.
+ */
+ private static class StringBinder extends CursorBinder {
+ public StringBinder(Context context, CursorTransformation transformation) {
+ super(context, transformation);
+ }
+
+ @Override
+ public boolean bind(View view, Cursor cursor, int columnIndex) {
+ ((TextView) view).setText(mTransformation.transform(cursor, columnIndex));
+ return true;
+ }
+ }
+
+ /**
+ * Binds an image blob to an ImageView.
+ */
+ private static class ImageBinder extends CursorBinder {
+ public ImageBinder(Context context, CursorTransformation transformation) {
+ super(context, transformation);
+ }
+
+ @Override
+ public boolean bind(View view, Cursor cursor, int columnIndex) {
+ final byte[] data = cursor.getBlob(columnIndex);
+ ((ImageView) view).setImageBitmap(BitmapFactory.decodeByteArray(data, 0, data.length));
+ return true;
+ }
+ }
+
+ /**
+ * Binds an image URI to an ImageView.
+ */
+ private static class ImageUriBinder extends CursorBinder {
+ public ImageUriBinder(Context context, CursorTransformation transformation) {
+ super(context, transformation);
+ }
+
+ @Override
+ public boolean bind(View view, Cursor cursor, int columnIndex) {
+ ((ImageView) view).setImageURI(Uri.parse(
+ mTransformation.transform(cursor, columnIndex)));
+ return true;
+ }
+ }
+
+ /**
+ * Binds a drawable resource identifier to an ImageView.
+ */
+ private static class DrawableBinder extends CursorBinder {
+ public DrawableBinder(Context context, CursorTransformation transformation) {
+ super(context, transformation);
+ }
+
+ @Override
+ public boolean bind(View view, Cursor cursor, int columnIndex) {
+ final int resource = mTransformation.transformToResource(cursor, columnIndex);
+ if (resource == 0) return false;
+
+ ((ImageView) view).setImageResource(resource);
+ return true;
+ }
+ }
+}
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index e15a520..34aef99 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -29,13 +29,12 @@
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
-import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.inputmethod.CompletionInfo;
-import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
import com.android.internal.R;
@@ -90,45 +89,21 @@
static final boolean DEBUG = false;
static final String TAG = "AutoCompleteTextView";
- private static final int HINT_VIEW_ID = 0x17;
-
- /**
- * This value controls the length of time that the user
- * must leave a pointer down without scrolling to expand
- * the autocomplete dropdown list to cover the IME.
- */
- private static final int EXPAND_LIST_TIMEOUT = 250;
-
private CharSequence mHintText;
+ private TextView mHintView;
private int mHintResource;
private ListAdapter mAdapter;
private Filter mFilter;
private int mThreshold;
- private PopupWindow mPopup;
- private DropDownListView mDropDownList;
- private int mDropDownVerticalOffset;
- private int mDropDownHorizontalOffset;
+ private ListPopupWindow mPopup;
private int mDropDownAnchorId;
- private View mDropDownAnchorView; // view is retrieved lazily from id once needed
- private int mDropDownWidth;
- private int mDropDownHeight;
- private final Rect mTempRect = new Rect();
-
- private Drawable mDropDownListHighlight;
private AdapterView.OnItemClickListener mItemClickListener;
private AdapterView.OnItemSelectedListener mItemSelectedListener;
- private final DropDownItemClickListener mDropDownItemClickListener =
- new DropDownItemClickListener();
-
- private boolean mDropDownAlwaysVisible = false;
-
private boolean mDropDownDismissedOnCompletion = true;
-
- private boolean mForceIgnoreOutsideTouch = false;
private int mLastKeyCode = KeyEvent.KEYCODE_UNKNOWN;
private boolean mOpenBefore;
@@ -137,10 +112,6 @@
private boolean mBlockCompletion;
- private ListSelectorHider mHideSelector;
- private Runnable mShowDropDownRunnable;
- private Runnable mResizePopupRunnable = new ResizePopupRunnable();
-
private PassThroughClickListener mPassThroughClickListener;
private PopupDataSetObserver mObserver;
@@ -155,9 +126,10 @@
public AutoCompleteTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
- mPopup = new PopupWindow(context, attrs,
+ mPopup = new ListPopupWindow(context, attrs,
com.android.internal.R.attr.autoCompleteTextViewStyle);
mPopup.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
+ mPopup.setPromptPosition(ListPopupWindow.POSITION_PROMPT_BELOW);
TypedArray a =
context.obtainStyledAttributes(
@@ -166,14 +138,11 @@
mThreshold = a.getInt(
R.styleable.AutoCompleteTextView_completionThreshold, 2);
- mHintText = a.getText(R.styleable.AutoCompleteTextView_completionHint);
-
- mDropDownListHighlight = a.getDrawable(
- R.styleable.AutoCompleteTextView_dropDownSelector);
- mDropDownVerticalOffset = (int)
- a.getDimension(R.styleable.AutoCompleteTextView_dropDownVerticalOffset, 0.0f);
- mDropDownHorizontalOffset = (int)
- a.getDimension(R.styleable.AutoCompleteTextView_dropDownHorizontalOffset, 0.0f);
+ mPopup.setListSelector(a.getDrawable(R.styleable.AutoCompleteTextView_dropDownSelector));
+ mPopup.setVerticalOffset((int)
+ a.getDimension(R.styleable.AutoCompleteTextView_dropDownVerticalOffset, 0.0f));
+ mPopup.setHorizontalOffset((int)
+ a.getDimension(R.styleable.AutoCompleteTextView_dropDownHorizontalOffset, 0.0f));
// Get the anchor's id now, but the view won't be ready, so wait to actually get the
// view and store it in mDropDownAnchorView lazily in getDropDownAnchorView later.
@@ -184,13 +153,18 @@
// For dropdown width, the developer can specify a specific width, or MATCH_PARENT
// (for full screen width) or WRAP_CONTENT (to match the width of the anchored view).
- mDropDownWidth = a.getLayoutDimension(R.styleable.AutoCompleteTextView_dropDownWidth,
- ViewGroup.LayoutParams.WRAP_CONTENT);
- mDropDownHeight = a.getLayoutDimension(R.styleable.AutoCompleteTextView_dropDownHeight,
- ViewGroup.LayoutParams.WRAP_CONTENT);
+ mPopup.setWidth(a.getLayoutDimension(
+ R.styleable.AutoCompleteTextView_dropDownWidth,
+ ViewGroup.LayoutParams.WRAP_CONTENT));
+ mPopup.setHeight(a.getLayoutDimension(
+ R.styleable.AutoCompleteTextView_dropDownHeight,
+ ViewGroup.LayoutParams.WRAP_CONTENT));
mHintResource = a.getResourceId(R.styleable.AutoCompleteTextView_completionHintView,
R.layout.simple_dropdown_hint);
+
+ mPopup.setOnItemClickListener(new DropDownItemClickListener());
+ setCompletionHint(a.getText(R.styleable.AutoCompleteTextView_completionHint));
// Always turn on the auto complete input type flag, since it
// makes no sense to use this widget without it.
@@ -238,6 +212,20 @@
*/
public void setCompletionHint(CharSequence hint) {
mHintText = hint;
+ if (hint != null) {
+ if (mHintView == null) {
+ final TextView hintView = (TextView) LayoutInflater.from(getContext()).inflate(
+ mHintResource, null).findViewById(com.android.internal.R.id.text1);
+ hintView.setText(mHintText);
+ mHintView = hintView;
+ mPopup.setPromptView(hintView);
+ } else {
+ mHintView.setText(hint);
+ }
+ } else {
+ mPopup.setPromptView(null);
+ mHintView = null;
+ }
}
/**
@@ -250,7 +238,7 @@
* @attr ref android.R.styleable#AutoCompleteTextView_dropDownWidth
*/
public int getDropDownWidth() {
- return mDropDownWidth;
+ return mPopup.getWidth();
}
/**
@@ -263,7 +251,7 @@
* @attr ref android.R.styleable#AutoCompleteTextView_dropDownWidth
*/
public void setDropDownWidth(int width) {
- mDropDownWidth = width;
+ mPopup.setWidth(width);
}
/**
@@ -277,7 +265,7 @@
* @attr ref android.R.styleable#AutoCompleteTextView_dropDownHeight
*/
public int getDropDownHeight() {
- return mDropDownHeight;
+ return mPopup.getHeight();
}
/**
@@ -291,7 +279,7 @@
* @attr ref android.R.styleable#AutoCompleteTextView_dropDownHeight
*/
public void setDropDownHeight(int height) {
- mDropDownHeight = height;
+ mPopup.setHeight(height);
}
/**
@@ -316,7 +304,7 @@
*/
public void setDropDownAnchor(int id) {
mDropDownAnchorId = id;
- mDropDownAnchorView = null;
+ mPopup.setAnchorView(null);
}
/**
@@ -358,7 +346,7 @@
* @param offset the vertical offset
*/
public void setDropDownVerticalOffset(int offset) {
- mDropDownVerticalOffset = offset;
+ mPopup.setVerticalOffset(offset);
}
/**
@@ -367,7 +355,7 @@
* @return the vertical offset
*/
public int getDropDownVerticalOffset() {
- return mDropDownVerticalOffset;
+ return mPopup.getVerticalOffset();
}
/**
@@ -376,7 +364,7 @@
* @param offset the horizontal offset
*/
public void setDropDownHorizontalOffset(int offset) {
- mDropDownHorizontalOffset = offset;
+ mPopup.setHorizontalOffset(offset);
}
/**
@@ -385,7 +373,7 @@
* @return the horizontal offset
*/
public int getDropDownHorizontalOffset() {
- return mDropDownHorizontalOffset;
+ return mPopup.getHorizontalOffset();
}
/**
@@ -422,7 +410,7 @@
* @hide Pending API council approval
*/
public boolean isDropDownAlwaysVisible() {
- return mDropDownAlwaysVisible;
+ return mPopup.isDropDownAlwaysVisible();
}
/**
@@ -439,7 +427,7 @@
* @hide Pending API council approval
*/
public void setDropDownAlwaysVisible(boolean dropDownAlwaysVisible) {
- mDropDownAlwaysVisible = dropDownAlwaysVisible;
+ mPopup.setDropDownAlwaysVisible(dropDownAlwaysVisible);
}
/**
@@ -606,15 +594,13 @@
mFilter = null;
}
- if (mDropDownList != null) {
- mDropDownList.setAdapter(mAdapter);
- }
+ mPopup.setAdapter(mAdapter);
}
@Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && isPopupShowing()
- && !mDropDownAlwaysVisible) {
+ && !mPopup.isDropDownAlwaysVisible()) {
// special case for the back key, we do not even try to send it
// to the drop down list but instead, consume it immediately
if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
@@ -633,18 +619,16 @@
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
- if (isPopupShowing() && mDropDownList.getSelectedItemPosition() >= 0) {
- boolean consumed = mDropDownList.onKeyUp(keyCode, event);
- if (consumed) {
- switch (keyCode) {
- // if the list accepts the key events and the key event
- // was a click, the text view gets the selected item
- // from the drop down as its content
- case KeyEvent.KEYCODE_ENTER:
- case KeyEvent.KEYCODE_DPAD_CENTER:
- performCompletion();
- return true;
- }
+ boolean consumed = mPopup.onKeyUp(keyCode, event);
+ if (consumed) {
+ switch (keyCode) {
+ // if the list accepts the key events and the key event
+ // was a click, the text view gets the selected item
+ // from the drop down as its content
+ case KeyEvent.KEYCODE_ENTER:
+ case KeyEvent.KEYCODE_DPAD_CENTER:
+ performCompletion();
+ return true;
}
}
return super.onKeyUp(keyCode, event);
@@ -652,87 +636,11 @@
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
- // when the drop down is shown, we drive it directly
- if (isPopupShowing()) {
- // the key events are forwarded to the list in the drop down view
- // note that ListView handles space but we don't want that to happen
- // also if selection is not currently in the drop down, then don't
- // let center or enter presses go there since that would cause it
- // to select one of its items
- if (keyCode != KeyEvent.KEYCODE_SPACE
- && (mDropDownList.getSelectedItemPosition() >= 0
- || (keyCode != KeyEvent.KEYCODE_ENTER
- && keyCode != KeyEvent.KEYCODE_DPAD_CENTER))) {
- int curIndex = mDropDownList.getSelectedItemPosition();
- boolean consumed;
-
- final boolean below = !mPopup.isAboveAnchor();
-
- final ListAdapter adapter = mAdapter;
-
- boolean allEnabled;
- int firstItem = Integer.MAX_VALUE;
- int lastItem = Integer.MIN_VALUE;
-
- if (adapter != null) {
- allEnabled = adapter.areAllItemsEnabled();
- firstItem = allEnabled ? 0 :
- mDropDownList.lookForSelectablePosition(0, true);
- lastItem = allEnabled ? adapter.getCount() - 1 :
- mDropDownList.lookForSelectablePosition(adapter.getCount() - 1, false);
- }
-
- if ((below && keyCode == KeyEvent.KEYCODE_DPAD_UP && curIndex <= firstItem) ||
- (!below && keyCode == KeyEvent.KEYCODE_DPAD_DOWN && curIndex >= lastItem)) {
- // When the selection is at the top, we block the key
- // event to prevent focus from moving.
- clearListSelection();
- mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
- showDropDown();
- return true;
- } else {
- // WARNING: Please read the comment where mListSelectionHidden
- // is declared
- mDropDownList.mListSelectionHidden = false;
- }
-
- consumed = mDropDownList.onKeyDown(keyCode, event);
- if (DEBUG) Log.v(TAG, "Key down: code=" + keyCode + " list consumed=" + consumed);
-
- if (consumed) {
- // If it handled the key event, then the user is
- // navigating in the list, so we should put it in front.
- mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
- // Here's a little trick we need to do to make sure that
- // the list view is actually showing its focus indicator,
- // by ensuring it has focus and getting its window out
- // of touch mode.
- mDropDownList.requestFocusFromTouch();
- showDropDown();
-
- switch (keyCode) {
- // avoid passing the focus from the text view to the
- // next component
- case KeyEvent.KEYCODE_ENTER:
- case KeyEvent.KEYCODE_DPAD_CENTER:
- case KeyEvent.KEYCODE_DPAD_DOWN:
- case KeyEvent.KEYCODE_DPAD_UP:
- return true;
- }
- } else {
- if (below && keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
- // when the selection is at the bottom, we block the
- // event to avoid going to the next focusable widget
- if (curIndex == lastItem) {
- return true;
- }
- } else if (!below && keyCode == KeyEvent.KEYCODE_DPAD_UP &&
- curIndex == firstItem) {
- return true;
- }
- }
- }
- } else {
+ if (mPopup.onKeyDown(keyCode, event)) {
+ return true;
+ }
+
+ if (!isPopupShowing()) {
switch(keyCode) {
case KeyEvent.KEYCODE_DPAD_DOWN:
performValidation();
@@ -743,7 +651,7 @@
boolean handled = super.onKeyDown(keyCode, event);
mLastKeyCode = KeyEvent.KEYCODE_UNKNOWN;
- if (handled && isPopupShowing() && mDropDownList != null) {
+ if (handled && isPopupShowing()) {
clearListSelection();
}
@@ -804,11 +712,12 @@
if (enoughToFilter()) {
if (mFilter != null) {
performFiltering(getText(), mLastKeyCode);
+ buildImeCompletions();
}
} else {
// drop down is automatically dismissed when enough characters
// are deleted from the text view
- if (!mDropDownAlwaysVisible) dismissDropDown();
+ if (!mPopup.isDropDownAlwaysVisible()) dismissDropDown();
if (mFilter != null) {
mFilter.filter(null);
}
@@ -841,13 +750,7 @@
* it back.
*/
public void clearListSelection() {
- final DropDownListView list = mDropDownList;
- if (list != null) {
- // WARNING: Please read the comment where mListSelectionHidden is declared
- list.mListSelectionHidden = true;
- list.hideSelector();
- list.requestLayout();
- }
+ mPopup.clearListSelection();
}
/**
@@ -856,11 +759,7 @@
* @param position The position to move the selector to.
*/
public void setListSelection(int position) {
- if (mPopup.isShowing() && (mDropDownList != null)) {
- mDropDownList.mListSelectionHidden = false;
- mDropDownList.setSelection(position);
- // ListView.setSelection() will call requestLayout()
- }
+ mPopup.setSelection(position);
}
/**
@@ -874,10 +773,7 @@
* @see ListView#getSelectedItemPosition()
*/
public int getListSelection() {
- if (mPopup.isShowing() && (mDropDownList != null)) {
- return mDropDownList.getSelectedItemPosition();
- }
- return ListView.INVALID_POSITION;
+ return mPopup.getSelectedItemPosition();
}
/**
@@ -911,13 +807,7 @@
replaceText(completion.getText());
mBlockCompletion = false;
- if (mItemClickListener != null) {
- final DropDownListView list = mDropDownList;
- // Note that we don't have a View here, so we will need to
- // supply null. Hopefully no existing apps crash...
- mItemClickListener.onItemClick(list, null, completion.getPosition(),
- completion.getId());
- }
+ mPopup.performItemClick(completion.getPosition());
}
}
@@ -925,7 +815,7 @@
if (isPopupShowing()) {
Object selectedItem;
if (position < 0) {
- selectedItem = mDropDownList.getSelectedItem();
+ selectedItem = mPopup.getSelectedItem();
} else {
selectedItem = mAdapter.getItem(position);
}
@@ -939,18 +829,18 @@
mBlockCompletion = false;
if (mItemClickListener != null) {
- final DropDownListView list = mDropDownList;
+ final ListPopupWindow list = mPopup;
if (selectedView == null || position < 0) {
selectedView = list.getSelectedView();
position = list.getSelectedItemPosition();
id = list.getSelectedItemId();
}
- mItemClickListener.onItemClick(list, selectedView, position, id);
+ mItemClickListener.onItemClick(list.getListView(), selectedView, position, id);
}
}
- if (mDropDownDismissedOnCompletion && !mDropDownAlwaysVisible) {
+ if (mDropDownDismissedOnCompletion && !mPopup.isDropDownAlwaysVisible()) {
dismissDropDown();
}
}
@@ -1000,7 +890,6 @@
/** {@inheritDoc} */
public void onFilterComplete(int count) {
updateDropDownForFilter(count);
-
}
private void updateDropDownForFilter(int count) {
@@ -1014,11 +903,12 @@
* to filter.
*/
- if ((count > 0 || mDropDownAlwaysVisible) && enoughToFilter()) {
+ final boolean dropDownAlwaysVisible = mPopup.isDropDownAlwaysVisible();
+ if ((count > 0 || dropDownAlwaysVisible) && enoughToFilter()) {
if (hasFocus() && hasWindowFocus()) {
showDropDown();
}
- } else if (!mDropDownAlwaysVisible) {
+ } else if (!dropDownAlwaysVisible) {
dismissDropDown();
}
}
@@ -1026,7 +916,7 @@
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
- if (!hasWindowFocus && !mDropDownAlwaysVisible) {
+ if (!hasWindowFocus && !mPopup.isDropDownAlwaysVisible()) {
dismissDropDown();
}
}
@@ -1036,7 +926,7 @@
super.onDisplayHint(hint);
switch (hint) {
case INVISIBLE:
- if (!mDropDownAlwaysVisible) {
+ if (!mPopup.isDropDownAlwaysVisible()) {
dismissDropDown();
}
break;
@@ -1050,7 +940,7 @@
if (!focused) {
performValidation();
}
- if (!focused && !mDropDownAlwaysVisible) {
+ if (!focused && !mPopup.isDropDownAlwaysVisible()) {
dismissDropDown();
}
}
@@ -1075,8 +965,6 @@
imm.displayCompletions(this, null);
}
mPopup.dismiss();
- mPopup.setContentView(null);
- mDropDownList = null;
}
@Override
@@ -1089,18 +977,6 @@
return result;
}
-
- /**
- * <p>Used for lazy instantiation of the anchor view from the id we have. If the value of
- * the id is NO_ID or we can't find a view for the given id, we return this TextView as
- * the default anchoring point.</p>
- */
- private View getDropDownAnchorView() {
- if (mDropDownAnchorView == null && mDropDownAnchorId != View.NO_ID) {
- mDropDownAnchorView = getRootView().findViewById(mDropDownAnchorId);
- }
- return mDropDownAnchorView == null ? this : mDropDownAnchorView;
- }
/**
* Issues a runnable to show the dropdown as soon as possible.
@@ -1108,7 +984,7 @@
* @hide internal used only by SearchDialog
*/
public void showDropDownAfterLayout() {
- post(mShowDropDownRunnable);
+ mPopup.postShow();
}
/**
@@ -1119,7 +995,7 @@
*/
public void ensureImeVisible(boolean visible) {
mPopup.setInputMethodMode(visible
- ? PopupWindow.INPUT_METHOD_NEEDED : PopupWindow.INPUT_METHOD_NOT_NEEDED);
+ ? ListPopupWindow.INPUT_METHOD_NEEDED : ListPopupWindow.INPUT_METHOD_NOT_NEEDED);
showDropDown();
}
@@ -1127,89 +1003,21 @@
* @hide internal used only here and SearchDialog
*/
public boolean isInputMethodNotNeeded() {
- return mPopup.getInputMethodMode() == PopupWindow.INPUT_METHOD_NOT_NEEDED;
+ return mPopup.getInputMethodMode() == ListPopupWindow.INPUT_METHOD_NOT_NEEDED;
}
/**
* <p>Displays the drop down on screen.</p>
*/
public void showDropDown() {
- int height = buildDropDown();
-
- int widthSpec = 0;
- int heightSpec = 0;
-
- boolean noInputMethod = isInputMethodNotNeeded();
-
- if (mPopup.isShowing()) {
- if (mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT) {
- // The call to PopupWindow's update method below can accept -1 for any
- // value you do not want to update.
- widthSpec = -1;
- } else if (mDropDownWidth == ViewGroup.LayoutParams.WRAP_CONTENT) {
- widthSpec = getDropDownAnchorView().getWidth();
+ if (mPopup.getAnchorView() == null) {
+ if (mDropDownAnchorId != View.NO_ID) {
+ mPopup.setAnchorView(getRootView().findViewById(mDropDownAnchorId));
} else {
- widthSpec = mDropDownWidth;
+ mPopup.setAnchorView(this);
}
-
- if (mDropDownHeight == ViewGroup.LayoutParams.MATCH_PARENT) {
- // The call to PopupWindow's update method below can accept -1 for any
- // value you do not want to update.
- heightSpec = noInputMethod ? height : ViewGroup.LayoutParams.MATCH_PARENT;
- if (noInputMethod) {
- mPopup.setWindowLayoutMode(
- mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT ?
- ViewGroup.LayoutParams.MATCH_PARENT : 0, 0);
- } else {
- mPopup.setWindowLayoutMode(
- mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT ?
- ViewGroup.LayoutParams.MATCH_PARENT : 0,
- ViewGroup.LayoutParams.MATCH_PARENT);
- }
- } else if (mDropDownHeight == ViewGroup.LayoutParams.WRAP_CONTENT) {
- heightSpec = height;
- } else {
- heightSpec = mDropDownHeight;
- }
-
- mPopup.setOutsideTouchable(!mForceIgnoreOutsideTouch && !mDropDownAlwaysVisible);
-
- mPopup.update(getDropDownAnchorView(), mDropDownHorizontalOffset,
- mDropDownVerticalOffset, widthSpec, heightSpec);
- } else {
- if (mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT) {
- widthSpec = ViewGroup.LayoutParams.MATCH_PARENT;
- } else {
- if (mDropDownWidth == ViewGroup.LayoutParams.WRAP_CONTENT) {
- mPopup.setWidth(getDropDownAnchorView().getWidth());
- } else {
- mPopup.setWidth(mDropDownWidth);
- }
- }
-
- if (mDropDownHeight == ViewGroup.LayoutParams.MATCH_PARENT) {
- heightSpec = ViewGroup.LayoutParams.MATCH_PARENT;
- } else {
- if (mDropDownHeight == ViewGroup.LayoutParams.WRAP_CONTENT) {
- mPopup.setHeight(height);
- } else {
- mPopup.setHeight(mDropDownHeight);
- }
- }
-
- mPopup.setWindowLayoutMode(widthSpec, heightSpec);
- mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
-
- // use outside touchable to dismiss drop down when touching outside of it, so
- // only set this if the dropdown is not always visible
- mPopup.setOutsideTouchable(!mForceIgnoreOutsideTouch && !mDropDownAlwaysVisible);
- mPopup.setTouchInterceptor(new PopupTouchInterceptor());
- mPopup.showAsDropDown(getDropDownAnchorView(),
- mDropDownHorizontalOffset, mDropDownVerticalOffset);
- mDropDownList.setSelection(ListView.INVALID_POSITION);
- clearListSelection();
- post(mHideSelector);
}
+ mPopup.show();
}
/**
@@ -1220,19 +1028,10 @@
* @hide used only by SearchDialog
*/
public void setForceIgnoreOutsideTouch(boolean forceIgnoreOutsideTouch) {
- mForceIgnoreOutsideTouch = forceIgnoreOutsideTouch;
+ mPopup.setForceIgnoreOutsideTouch(forceIgnoreOutsideTouch);
}
-
- /**
- * <p>Builds the popup window's content and returns the height the popup
- * should have. Returns -1 when the content already exists.</p>
- *
- * @return the content's height or -1 if content already exists
- */
- private int buildDropDown() {
- ViewGroup dropDownView;
- int otherHeights = 0;
-
+
+ private void buildImeCompletions() {
final ListAdapter adapter = mAdapter;
if (adapter != null) {
InputMethodManager imm = InputMethodManager.peekInstance();
@@ -1260,135 +1059,6 @@
imm.displayCompletions(this, completions);
}
}
-
- if (mDropDownList == null) {
- Context context = getContext();
-
- mHideSelector = new ListSelectorHider();
-
- /**
- * This Runnable exists for the sole purpose of checking if the view layout has got
- * completed and if so call showDropDown to display the drop down. This is used to show
- * the drop down as soon as possible after user opens up the search dialog, without
- * waiting for the normal UI pipeline to do it's job which is slower than this method.
- */
- mShowDropDownRunnable = new Runnable() {
- public void run() {
- // View layout should be all done before displaying the drop down.
- View view = getDropDownAnchorView();
- if (view != null && view.getWindowToken() != null) {
- showDropDown();
- }
- }
- };
-
- mDropDownList = new DropDownListView(context);
- mDropDownList.setSelector(mDropDownListHighlight);
- mDropDownList.setAdapter(adapter);
- mDropDownList.setVerticalFadingEdgeEnabled(true);
- mDropDownList.setOnItemClickListener(mDropDownItemClickListener);
- mDropDownList.setFocusable(true);
- mDropDownList.setFocusableInTouchMode(true);
- mDropDownList.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
- public void onItemSelected(AdapterView<?> parent, View view,
- int position, long id) {
-
- if (position != -1) {
- DropDownListView dropDownList = mDropDownList;
-
- if (dropDownList != null) {
- dropDownList.mListSelectionHidden = false;
- }
- }
- }
-
- public void onNothingSelected(AdapterView<?> parent) {
- }
- });
- mDropDownList.setOnScrollListener(new PopupScrollListener());
-
- if (mItemSelectedListener != null) {
- mDropDownList.setOnItemSelectedListener(mItemSelectedListener);
- }
-
- dropDownView = mDropDownList;
-
- View hintView = getHintView(context);
- if (hintView != null) {
- // if an hint has been specified, we accomodate more space for it and
- // add a text view in the drop down menu, at the bottom of the list
- LinearLayout hintContainer = new LinearLayout(context);
- hintContainer.setOrientation(LinearLayout.VERTICAL);
-
- LinearLayout.LayoutParams hintParams = new LinearLayout.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT, 0, 1.0f
- );
- hintContainer.addView(dropDownView, hintParams);
- hintContainer.addView(hintView);
-
- // measure the hint's height to find how much more vertical space
- // we need to add to the drop down's height
- int widthSpec = MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.AT_MOST);
- int heightSpec = MeasureSpec.UNSPECIFIED;
- hintView.measure(widthSpec, heightSpec);
-
- hintParams = (LinearLayout.LayoutParams) hintView.getLayoutParams();
- otherHeights = hintView.getMeasuredHeight() + hintParams.topMargin
- + hintParams.bottomMargin;
-
- dropDownView = hintContainer;
- }
-
- mPopup.setContentView(dropDownView);
- } else {
- dropDownView = (ViewGroup) mPopup.getContentView();
- final View view = dropDownView.findViewById(HINT_VIEW_ID);
- if (view != null) {
- LinearLayout.LayoutParams hintParams =
- (LinearLayout.LayoutParams) view.getLayoutParams();
- otherHeights = view.getMeasuredHeight() + hintParams.topMargin
- + hintParams.bottomMargin;
- }
- }
-
- // Max height available on the screen for a popup.
- boolean ignoreBottomDecorations =
- mPopup.getInputMethodMode() == PopupWindow.INPUT_METHOD_NOT_NEEDED;
- final int maxHeight = mPopup.getMaxAvailableHeight(
- getDropDownAnchorView(), mDropDownVerticalOffset, ignoreBottomDecorations);
-
- // getMaxAvailableHeight() subtracts the padding, so we put it back,
- // to get the available height for the whole window
- int padding = 0;
- Drawable background = mPopup.getBackground();
- if (background != null) {
- background.getPadding(mTempRect);
- padding = mTempRect.top + mTempRect.bottom;
- }
-
- if (mDropDownAlwaysVisible || mDropDownHeight == ViewGroup.LayoutParams.MATCH_PARENT) {
- return maxHeight + padding;
- }
-
- final int listContent = mDropDownList.measureHeightOfChildren(MeasureSpec.UNSPECIFIED,
- 0, ListView.NO_POSITION, maxHeight - otherHeights, 2);
- // add padding only if the list has items in it, that way we don't show
- // the popup if it is not needed
- if (listContent > 0) otherHeights += padding;
-
- return listContent + otherHeights;
- }
-
- private View getHintView(Context context) {
- if (mHintText != null && mHintText.length() > 0) {
- final TextView hintView = (TextView) LayoutInflater.from(context).inflate(
- mHintResource, null).findViewById(com.android.internal.R.id.text1);
- hintView.setText(mHintText);
- hintView.setId(HINT_VIEW_ID);
- return hintView;
- } else {
- return null;
- }
}
/**
@@ -1440,47 +1110,6 @@
return mFilter;
}
- private class ListSelectorHider implements Runnable {
- public void run() {
- clearListSelection();
- }
- }
-
- private class ResizePopupRunnable implements Runnable {
- public void run() {
- mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
- showDropDown();
- }
- }
-
- private class PopupTouchInterceptor implements OnTouchListener {
- public boolean onTouch(View v, MotionEvent event) {
- final int action = event.getAction();
- if (action == MotionEvent.ACTION_DOWN &&
- mPopup != null && mPopup.isShowing()) {
- postDelayed(mResizePopupRunnable, EXPAND_LIST_TIMEOUT);
- } else if (action == MotionEvent.ACTION_UP) {
- removeCallbacks(mResizePopupRunnable);
- }
- return false;
- }
- }
-
- private class PopupScrollListener implements ListView.OnScrollListener {
- public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
- int totalItemCount) {
-
- }
-
- public void onScrollStateChanged(AbsListView view, int scrollState) {
- if (scrollState == SCROLL_STATE_TOUCH_SCROLL &&
- !isInputMethodNotNeeded() && mPopup.getContentView() != null) {
- removeCallbacks(mResizePopupRunnable);
- mResizePopupRunnable.run();
- }
- }
- }
-
private class DropDownItemClickListener implements AdapterView.OnItemClickListener {
public void onItemClick(AdapterView parent, View v, int position, long id) {
performCompletion(v, position, id);
@@ -1488,123 +1117,6 @@
}
/**
- * <p>Wrapper class for a ListView. This wrapper hijacks the focus to
- * make sure the list uses the appropriate drawables and states when
- * displayed on screen within a drop down. The focus is never actually
- * passed to the drop down; the list only looks focused.</p>
- */
- private static class DropDownListView extends ListView {
- /*
- * WARNING: This is a workaround for a touch mode issue.
- *
- * Touch mode is propagated lazily to windows. This causes problems in
- * the following scenario:
- * - Type something in the AutoCompleteTextView and get some results
- * - Move down with the d-pad to select an item in the list
- * - Move up with the d-pad until the selection disappears
- * - Type more text in the AutoCompleteTextView *using the soft keyboard*
- * and get new results; you are now in touch mode
- * - The selection comes back on the first item in the list, even though
- * the list is supposed to be in touch mode
- *
- * Using the soft keyboard triggers the touch mode change but that change
- * is propagated to our window only after the first list layout, therefore
- * after the list attempts to resurrect the selection.
- *
- * The trick to work around this issue is to pretend the list is in touch
- * mode when we know that the selection should not appear, that is when
- * we know the user moved the selection away from the list.
- *
- * This boolean is set to true whenever we explicitely hide the list's
- * selection and reset to false whenver we know the user moved the
- * selection back to the list.
- *
- * When this boolean is true, isInTouchMode() returns true, otherwise it
- * returns super.isInTouchMode().
- */
- private boolean mListSelectionHidden;
-
- /**
- * <p>Creates a new list view wrapper.</p>
- *
- * @param context this view's context
- */
- public DropDownListView(Context context) {
- super(context, null, com.android.internal.R.attr.dropDownListViewStyle);
- }
-
- /**
- * <p>Avoids jarring scrolling effect by ensuring that list elements
- * made of a text view fit on a single line.</p>
- *
- * @param position the item index in the list to get a view for
- * @return the view for the specified item
- */
- @Override
- View obtainView(int position, boolean[] isScrap) {
- View view = super.obtainView(position, isScrap);
-
- if (view instanceof TextView) {
- ((TextView) view).setHorizontallyScrolling(true);
- }
-
- return view;
- }
-
- @Override
- public boolean isInTouchMode() {
- // WARNING: Please read the comment where mListSelectionHidden is declared
- return mListSelectionHidden || super.isInTouchMode();
- }
-
- /**
- * <p>Returns the focus state in the drop down.</p>
- *
- * @return true always
- */
- @Override
- public boolean hasWindowFocus() {
- return true;
- }
-
- /**
- * <p>Returns the focus state in the drop down.</p>
- *
- * @return true always
- */
- @Override
- public boolean isFocused() {
- return true;
- }
-
- /**
- * <p>Returns the focus state in the drop down.</p>
- *
- * @return true always
- */
- @Override
- public boolean hasFocus() {
- return true;
- }
-
- protected int[] onCreateDrawableState(int extraSpace) {
- int[] res = super.onCreateDrawableState(extraSpace);
- //noinspection ConstantIfStatement
- if (false) {
- StringBuilder sb = new StringBuilder("Created drawable state: [");
- for (int i=0; i<res.length; i++) {
- if (i > 0) sb.append(", ");
- sb.append("0x");
- sb.append(Integer.toHexString(res[i]));
- }
- sb.append("]");
- Log.i(TAG, sb.toString());
- }
- return res;
- }
- }
-
- /**
* This interface is used to make sure that the text entered in this TextView complies to
* a certain format. Since there is no foolproof way to prevent the user from leaving
* this View with an incorrect value in it, all we can do is try to fix it ourselves
@@ -1652,10 +1164,7 @@
private class PopupDataSetObserver extends DataSetObserver {
@Override
public void onChanged() {
- if (isPopupShowing()) {
- // This will resize the popup to fit the new adapter's content
- showDropDown();
- } else if (mAdapter != null) {
+ if (mAdapter != null) {
// If the popup is not showing already, showing it will cause
// the list of data set observers attached to the adapter to
// change. We can't do it from here, because we are in the middle
@@ -1670,14 +1179,5 @@
});
}
}
-
- @Override
- public void onInvalidated() {
- if (!mDropDownAlwaysVisible) {
- // There's no data to display so make sure we're not showing
- // the drop down and its list
- dismissDropDown();
- }
- }
}
}
diff --git a/core/java/android/widget/CursorAdapter.java b/core/java/android/widget/CursorAdapter.java
index baa6833..4cf8785 100644
--- a/core/java/android/widget/CursorAdapter.java
+++ b/core/java/android/widget/CursorAdapter.java
@@ -80,6 +80,18 @@
protected FilterQueryProvider mFilterQueryProvider;
/**
+ * If set the adapter will call requery() on the cursor whenever a content change
+ * notification is delivered. Implies {@link #FLAG_REGISTER_CONTENT_OBSERVER}
+ */
+ public static final int FLAG_AUTO_REQUERY = 0x01;
+
+ /**
+ * If set the adapter will register a content observer on the cursor and will call
+ * {@link #onContentChanged()} when a notification comes in.
+ */
+ public static final int FLAG_REGISTER_CONTENT_OBSERVER = 0x02;
+
+ /**
* Constructor. The adapter will call requery() on the cursor whenever
* it changes so that the most recent data is always displayed.
*
@@ -87,7 +99,7 @@
* @param context The context
*/
public CursorAdapter(Context context, Cursor c) {
- init(context, c, true);
+ init(context, c, FLAG_AUTO_REQUERY);
}
/**
@@ -99,19 +111,43 @@
* data is always displayed.
*/
public CursorAdapter(Context context, Cursor c, boolean autoRequery) {
- init(context, c, autoRequery);
+ init(context, c, autoRequery ? FLAG_AUTO_REQUERY : FLAG_REGISTER_CONTENT_OBSERVER);
+ }
+
+ /**
+ * Constructor
+ * @param c The cursor from which to get the data.
+ * @param context The context
+ * @param flags flags used to determine the behavior of the adapter
+ */
+ public CursorAdapter(Context context, Cursor c, int flags) {
+ init(context, c, flags);
}
protected void init(Context context, Cursor c, boolean autoRequery) {
+ init(context, c, autoRequery ? FLAG_AUTO_REQUERY : FLAG_REGISTER_CONTENT_OBSERVER);
+ }
+
+ protected void init(Context context, Cursor c, int flags) {
+ if ((flags & FLAG_AUTO_REQUERY) == FLAG_AUTO_REQUERY) {
+ flags |= FLAG_REGISTER_CONTENT_OBSERVER;
+ mAutoRequery = true;
+ } else {
+ mAutoRequery = false;
+ }
boolean cursorPresent = c != null;
- mAutoRequery = autoRequery;
mCursor = c;
mDataValid = cursorPresent;
mContext = context;
mRowIDColumn = cursorPresent ? c.getColumnIndexOrThrow("_id") : -1;
- mChangeObserver = new ChangeObserver();
+ if ((flags & FLAG_REGISTER_CONTENT_OBSERVER) == FLAG_REGISTER_CONTENT_OBSERVER) {
+ mChangeObserver = new ChangeObserver();
+ } else {
+ mChangeObserver = null;
+ }
+
if (cursorPresent) {
- c.registerContentObserver(mChangeObserver);
+ if (mChangeObserver != null) c.registerContentObserver(mChangeObserver);
c.registerDataSetObserver(mDataSetObserver);
}
}
@@ -246,13 +282,13 @@
return;
}
if (mCursor != null) {
- mCursor.unregisterContentObserver(mChangeObserver);
+ if (mChangeObserver != null) mCursor.unregisterContentObserver(mChangeObserver);
mCursor.unregisterDataSetObserver(mDataSetObserver);
mCursor.close();
}
mCursor = cursor;
if (cursor != null) {
- cursor.registerContentObserver(mChangeObserver);
+ if (mChangeObserver != null) cursor.registerContentObserver(mChangeObserver);
cursor.registerDataSetObserver(mDataSetObserver);
mRowIDColumn = cursor.getColumnIndexOrThrow("_id");
mDataValid = true;
diff --git a/core/java/android/widget/Gallery.java b/core/java/android/widget/Gallery.java
index 1ed6b16..c47292f 100644
--- a/core/java/android/widget/Gallery.java
+++ b/core/java/android/widget/Gallery.java
@@ -1207,7 +1207,7 @@
// We unfocus the old child down here so the above hasFocus check
// returns true
- if (oldSelectedChild != null) {
+ if (oldSelectedChild != null && oldSelectedChild != child) {
// Make sure its drawable state doesn't contain 'selected'
oldSelectedChild.setSelected(false);
@@ -1263,6 +1263,7 @@
*/
if (gainFocus && mSelectedChild != null) {
mSelectedChild.requestFocus(direction);
+ mSelectedChild.setSelected(true);
}
}
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index d2829db..fe69a13 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -23,6 +23,7 @@
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.View;
+import android.view.ViewDebug;
import android.view.ViewGroup;
import android.view.SoundEffectConstants;
import android.view.animation.GridLayoutAnimationController;
@@ -112,7 +113,7 @@
*/
@Override
public void setAdapter(ListAdapter adapter) {
- if (null != mAdapter) {
+ if (mAdapter != null && mDataSetObserver != null) {
mAdapter.unregisterDataSetObserver(mDataSetObserver);
}
@@ -1774,6 +1775,19 @@
requestLayoutIfNecessary();
}
}
+
+ /**
+ * Get the number of columns in the grid.
+ * Returns {@link #AUTO_FIT} if the Grid has never been laid out.
+ *
+ * @attr ref android.R.styleable#GridView_numColumns
+ *
+ * @see #setNumColumns(int)
+ */
+ @ViewDebug.ExportedProperty
+ public int getNumColumns() {
+ return mNumColumns;
+ }
/**
* Make sure views are touching the top or bottom edge, as appropriate for
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
new file mode 100644
index 0000000..aaf299b
--- /dev/null
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -0,0 +1,1215 @@
+/*
+ * 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.widget;
+
+import android.content.Context;
+import android.database.DataSetObserver;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.view.View.MeasureSpec;
+import android.view.View.OnTouchListener;
+
+/**
+ * A ListPopupWindow anchors itself to a host view and displays a
+ * list of choices. When one is selected, the popup is dismissed.
+ *
+ * <p>ListPopupWindow contains a number of tricky behaviors surrounding
+ * positioning, scrolling parents to fit the dropdown, interacting
+ * sanely with the IME if present, and others.
+ *
+ * @see android.widget.AutoCompleteTextView
+ * @see android.widget.Spinner
+ */
+public class ListPopupWindow {
+ private static final String TAG = "ListPopupWindow";
+ private static final boolean DEBUG = false;
+
+ /**
+ * This value controls the length of time that the user
+ * must leave a pointer down without scrolling to expand
+ * the autocomplete dropdown list to cover the IME.
+ */
+ private static final int EXPAND_LIST_TIMEOUT = 250;
+
+ private Context mContext;
+ private PopupWindow mPopup;
+ private ListAdapter mAdapter;
+ private DropDownListView mDropDownList;
+
+ private int mDropDownHeight = ViewGroup.LayoutParams.WRAP_CONTENT;
+ private int mDropDownWidth = ViewGroup.LayoutParams.WRAP_CONTENT;
+ private int mDropDownHorizontalOffset;
+ private int mDropDownVerticalOffset;
+
+ private boolean mDropDownAlwaysVisible = false;
+ private boolean mForceIgnoreOutsideTouch = false;
+
+ private View mPromptView;
+ private int mPromptPosition = POSITION_PROMPT_ABOVE;
+
+ private DataSetObserver mObserver;
+
+ private View mDropDownAnchorView;
+
+ private Drawable mDropDownListHighlight;
+
+ private AdapterView.OnItemClickListener mItemClickListener;
+ private AdapterView.OnItemSelectedListener mItemSelectedListener;
+
+ private final ResizePopupRunnable mResizePopupRunnable = new ResizePopupRunnable();
+ private final PopupTouchInterceptor mTouchInterceptor = new PopupTouchInterceptor();
+ private final PopupScrollListener mScrollListener = new PopupScrollListener();
+ private final ListSelectorHider mHideSelector = new ListSelectorHider();
+ private Runnable mShowDropDownRunnable;
+
+ private Handler mHandler = new Handler();
+
+ private Rect mTempRect = new Rect();
+
+ private boolean mModal;
+
+ /**
+ * The provided prompt view should appear above list content.
+ *
+ * @see #setPromptPosition(int)
+ * @see #getPromptPosition()
+ * @see #setPromptView(View)
+ */
+ public static final int POSITION_PROMPT_ABOVE = 0;
+
+ /**
+ * The provided prompt view should appear below list content.
+ *
+ * @see #setPromptPosition(int)
+ * @see #getPromptPosition()
+ * @see #setPromptView(View)
+ */
+ public static final int POSITION_PROMPT_BELOW = 1;
+
+ /**
+ * Alias for {@link ViewGroup.LayoutParams#MATCH_PARENT}.
+ * If used to specify a popup width, the popup will match the width of the anchor view.
+ * If used to specify a popup height, the popup will fill available space.
+ */
+ public static final int MATCH_PARENT = ViewGroup.LayoutParams.MATCH_PARENT;
+
+ /**
+ * Alias for {@link ViewGroup.LayoutParams#WRAP_CONTENT}.
+ * If used to specify a popup width, the popup will use the width of its content.
+ */
+ public static final int WRAP_CONTENT = ViewGroup.LayoutParams.WRAP_CONTENT;
+
+ /**
+ * Mode for {@link #setInputMethodMode(int)}: the requirements for the
+ * input method should be based on the focusability of the popup. That is
+ * if it is focusable than it needs to work with the input method, else
+ * it doesn't.
+ */
+ public static final int INPUT_METHOD_FROM_FOCUSABLE = PopupWindow.INPUT_METHOD_FROM_FOCUSABLE;
+
+ /**
+ * Mode for {@link #setInputMethodMode(int)}: this popup always needs to
+ * work with an input method, regardless of whether it is focusable. This
+ * means that it will always be displayed so that the user can also operate
+ * the input method while it is shown.
+ */
+ public static final int INPUT_METHOD_NEEDED = PopupWindow.INPUT_METHOD_NEEDED;
+
+ /**
+ * Mode for {@link #setInputMethodMode(int)}: this popup never needs to
+ * work with an input method, regardless of whether it is focusable. This
+ * means that it will always be displayed to use as much space on the
+ * screen as needed, regardless of whether this covers the input method.
+ */
+ public static final int INPUT_METHOD_NOT_NEEDED = PopupWindow.INPUT_METHOD_NOT_NEEDED;
+
+ /**
+ * Create a new, empty popup window capable of displaying items from a ListAdapter.
+ * Backgrounds should be set using {@link #setBackgroundDrawable(Drawable)}.
+ *
+ * @param context Context used for contained views.
+ */
+ public ListPopupWindow(Context context) {
+ this(context, null, 0, 0);
+ }
+
+ /**
+ * Create a new, empty popup window capable of displaying items from a ListAdapter.
+ * Backgrounds should be set using {@link #setBackgroundDrawable(Drawable)}.
+ *
+ * @param context Context used for contained views.
+ * @param attrs Attributes from inflating parent views used to style the popup.
+ */
+ public ListPopupWindow(Context context, AttributeSet attrs) {
+ this(context, attrs, 0, 0);
+ }
+
+ /**
+ * Create a new, empty popup window capable of displaying items from a ListAdapter.
+ * Backgrounds should be set using {@link #setBackgroundDrawable(Drawable)}.
+ *
+ * @param context Context used for contained views.
+ * @param attrs Attributes from inflating parent views used to style the popup.
+ * @param defStyleAttr Default style attribute to use for popup content.
+ */
+ public ListPopupWindow(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ /**
+ * Create a new, empty popup window capable of displaying items from a ListAdapter.
+ * Backgrounds should be set using {@link #setBackgroundDrawable(Drawable)}.
+ *
+ * @param context Context used for contained views.
+ * @param attrs Attributes from inflating parent views used to style the popup.
+ * @param defStyleAttr Style attribute to read for default styling of popup content.
+ * @param defStyleRes Style resource ID to use for default styling of popup content.
+ */
+ public ListPopupWindow(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ mContext = context;
+ mPopup = new PopupWindow(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ /**
+ * Sets the adapter that provides the data and the views to represent the data
+ * in this popup window.
+ *
+ * @param adapter The adapter to use to create this window's content.
+ */
+ public void setAdapter(ListAdapter adapter) {
+ if (mObserver == null) {
+ mObserver = new PopupDataSetObserver();
+ } else if (mAdapter != null) {
+ adapter.unregisterDataSetObserver(mObserver);
+ }
+ mAdapter = adapter;
+ if (mAdapter != null) {
+ adapter.registerDataSetObserver(mObserver);
+ }
+
+ if (mDropDownList != null) {
+ mDropDownList.setAdapter(mAdapter);
+ }
+ }
+
+ /**
+ * Set where the optional prompt view should appear. The default is
+ * {@link #POSITION_PROMPT_ABOVE}.
+ *
+ * @param position A position constant declaring where the prompt should be displayed.
+ *
+ * @see #POSITION_PROMPT_ABOVE
+ * @see #POSITION_PROMPT_BELOW
+ */
+ public void setPromptPosition(int position) {
+ mPromptPosition = position;
+ }
+
+ /**
+ * @return Where the optional prompt view should appear.
+ *
+ * @see #POSITION_PROMPT_ABOVE
+ * @see #POSITION_PROMPT_BELOW
+ */
+ public int getPromptPosition() {
+ return mPromptPosition;
+ }
+
+ /**
+ * Set whether this window should be modal when shown.
+ *
+ * <p>If a popup window is modal, it will receive all touch and key input.
+ * If the user touches outside the popup window's content area the popup window
+ * will be dismissed.
+ *
+ * @param modal {@code true} if the popup window should be modal, {@code false} otherwise.
+ */
+ public void setModal(boolean modal) {
+ mModal = true;
+ mPopup.setFocusable(modal);
+ }
+
+ /**
+ * Returns whether the popup window will be modal when shown.
+ *
+ * @return {@code true} if the popup window will be modal, {@code false} otherwise.
+ */
+ public boolean isModal() {
+ return mModal;
+ }
+
+ /**
+ * Forces outside touches to be ignored. Normally if {@link #isDropDownAlwaysVisible()} is
+ * false, we allow outside touch to dismiss the dropdown. If this is set to true, then we
+ * ignore outside touch even when the drop down is not set to always visible.
+ *
+ * @hide Used only by AutoCompleteTextView to handle some internal special cases.
+ */
+ public void setForceIgnoreOutsideTouch(boolean forceIgnoreOutsideTouch) {
+ mForceIgnoreOutsideTouch = forceIgnoreOutsideTouch;
+ }
+
+ /**
+ * Sets whether the drop-down should remain visible under certain conditions.
+ *
+ * The drop-down will occupy the entire screen below {@link #getAnchorView} regardless
+ * of the size or content of the list. {@link #getBackground()} will fill any space
+ * that is not used by the list.
+ *
+ * @param dropDownAlwaysVisible Whether to keep the drop-down visible.
+ *
+ * @hide Only used by AutoCompleteTextView under special conditions.
+ */
+ public void setDropDownAlwaysVisible(boolean dropDownAlwaysVisible) {
+ mDropDownAlwaysVisible = dropDownAlwaysVisible;
+ }
+
+ /**
+ * @return Whether the drop-down is visible under special conditions.
+ *
+ * @hide Only used by AutoCompleteTextView under special conditions.
+ */
+ public boolean isDropDownAlwaysVisible() {
+ return mDropDownAlwaysVisible;
+ }
+
+ /**
+ * Sets the operating mode for the soft input area.
+ *
+ * @param mode The desired mode, see
+ * {@link android.view.WindowManager.LayoutParams#softInputMode}
+ * for the full list
+ *
+ * @see android.view.WindowManager.LayoutParams#softInputMode
+ * @see #getSoftInputMode()
+ */
+ public void setSoftInputMode(int mode) {
+ mPopup.setSoftInputMode(mode);
+ }
+
+ /**
+ * Returns the current value in {@link #setSoftInputMode(int)}.
+ *
+ * @see #setSoftInputMode(int)
+ * @see android.view.WindowManager.LayoutParams#softInputMode
+ */
+ public int getSoftInputMode() {
+ return mPopup.getSoftInputMode();
+ }
+
+ /**
+ * Sets a drawable to use as the list item selector.
+ *
+ * @param selector List selector drawable to use in the popup.
+ */
+ public void setListSelector(Drawable selector) {
+ mDropDownListHighlight = selector;
+ }
+
+ /**
+ * @return The background drawable for the popup window.
+ */
+ public Drawable getBackground() {
+ return mPopup.getBackground();
+ }
+
+ /**
+ * Sets a drawable to be the background for the popup window.
+ *
+ * @param d A drawable to set as the background.
+ */
+ public void setBackgroundDrawable(Drawable d) {
+ mPopup.setBackgroundDrawable(d);
+ }
+
+ /**
+ * Set an animation style to use when the popup window is shown or dismissed.
+ *
+ * @param animationStyle Animation style to use.
+ */
+ public void setAnimationStyle(int animationStyle) {
+ mPopup.setAnimationStyle(animationStyle);
+ }
+
+ /**
+ * Returns the animation style that will be used when the popup window is
+ * shown or dismissed.
+ *
+ * @return Animation style that will be used.
+ */
+ public int getAnimationStyle() {
+ return mPopup.getAnimationStyle();
+ }
+
+ /**
+ * Returns the view that will be used to anchor this popup.
+ *
+ * @return The popup's anchor view
+ */
+ public View getAnchorView() {
+ return mDropDownAnchorView;
+ }
+
+ /**
+ * Sets the popup's anchor view. This popup will always be positioned relative to
+ * the anchor view when shown.
+ *
+ * @param anchor The view to use as an anchor.
+ */
+ public void setAnchorView(View anchor) {
+ mDropDownAnchorView = anchor;
+ }
+
+ /**
+ * @return The horizontal offset of the popup from its anchor in pixels.
+ */
+ public int getHorizontalOffset() {
+ return mDropDownHorizontalOffset;
+ }
+
+ /**
+ * Set the horizontal offset of this popup from its anchor view in pixels.
+ *
+ * @param offset The horizontal offset of the popup from its anchor.
+ */
+ public void setHorizontalOffset(int offset) {
+ mDropDownHorizontalOffset = offset;
+ }
+
+ /**
+ * @return The vertical offset of the popup from its anchor in pixels.
+ */
+ public int getVerticalOffset() {
+ return mDropDownVerticalOffset;
+ }
+
+ /**
+ * Set the vertical offset of this popup from its anchor view in pixels.
+ *
+ * @param offset The vertical offset of the popup from its anchor.
+ */
+ public void setVerticalOffset(int offset) {
+ mDropDownVerticalOffset = offset;
+ }
+
+ /**
+ * @return The width of the popup window in pixels.
+ */
+ public int getWidth() {
+ return mDropDownWidth;
+ }
+
+ /**
+ * Sets the width of the popup window in pixels. Can also be {@link #MATCH_PARENT}
+ * or {@link #WRAP_CONTENT}.
+ *
+ * @param width Width of the popup window.
+ */
+ public void setWidth(int width) {
+ mDropDownWidth = width;
+ }
+
+ /**
+ * @return The height of the popup window in pixels.
+ */
+ public int getHeight() {
+ return mDropDownHeight;
+ }
+
+ /**
+ * Sets the height of the popup window in pixels. Can also be {@link #MATCH_PARENT}.
+ *
+ * @param height Height of the popup window.
+ */
+ public void setHeight(int height) {
+ mDropDownHeight = height;
+ }
+
+ /**
+ * Sets a listener to receive events when a list item is clicked.
+ *
+ * @param clickListener Listener to register
+ *
+ * @see ListView#setOnItemClickListener(android.widget.AdapterView.OnItemClickListener)
+ */
+ public void setOnItemClickListener(AdapterView.OnItemClickListener clickListener) {
+ mItemClickListener = clickListener;
+ }
+
+ /**
+ * Sets a listener to receive events when a list item is selected.
+ *
+ * @param selectedListener Listener to register.
+ *
+ * @see ListView#setOnItemSelectedListener(android.widget.AdapterView.OnItemSelectedListener)
+ */
+ public void setOnItemSelectedListener(AdapterView.OnItemSelectedListener selectedListener) {
+ mItemSelectedListener = selectedListener;
+ }
+
+ /**
+ * Set a view to act as a user prompt for this popup window. Where the prompt view will appear
+ * is controlled by {@link #setPromptPosition(int)}.
+ *
+ * @param prompt View to use as an informational prompt.
+ */
+ public void setPromptView(View prompt) {
+ boolean showing = isShowing();
+ if (showing) {
+ removePromptView();
+ }
+ mPromptView = prompt;
+ if (showing) {
+ show();
+ }
+ }
+
+ /**
+ * Post a {@link #show()} call to the UI thread.
+ */
+ public void postShow() {
+ mHandler.post(mShowDropDownRunnable);
+ }
+
+ /**
+ * Show the popup list. If the list is already showing, this method
+ * will recalculate the popup's size and position.
+ */
+ public void show() {
+ int height = buildDropDown();
+
+ int widthSpec = 0;
+ int heightSpec = 0;
+
+ boolean noInputMethod = isInputMethodNotNeeded();
+
+ if (mPopup.isShowing()) {
+ if (mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT) {
+ // The call to PopupWindow's update method below can accept -1 for any
+ // value you do not want to update.
+ widthSpec = -1;
+ } else if (mDropDownWidth == ViewGroup.LayoutParams.WRAP_CONTENT) {
+ widthSpec = getAnchorView().getWidth();
+ } else {
+ widthSpec = mDropDownWidth;
+ }
+
+ if (mDropDownHeight == ViewGroup.LayoutParams.MATCH_PARENT) {
+ // The call to PopupWindow's update method below can accept -1 for any
+ // value you do not want to update.
+ heightSpec = noInputMethod ? height : ViewGroup.LayoutParams.MATCH_PARENT;
+ if (noInputMethod) {
+ mPopup.setWindowLayoutMode(
+ mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT ?
+ ViewGroup.LayoutParams.MATCH_PARENT : 0, 0);
+ } else {
+ mPopup.setWindowLayoutMode(
+ mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT ?
+ ViewGroup.LayoutParams.MATCH_PARENT : 0,
+ ViewGroup.LayoutParams.MATCH_PARENT);
+ }
+ } else if (mDropDownHeight == ViewGroup.LayoutParams.WRAP_CONTENT) {
+ heightSpec = height;
+ } else {
+ heightSpec = mDropDownHeight;
+ }
+
+ mPopup.setOutsideTouchable(!mForceIgnoreOutsideTouch && !mDropDownAlwaysVisible);
+
+ mPopup.update(getAnchorView(), mDropDownHorizontalOffset,
+ mDropDownVerticalOffset, widthSpec, heightSpec);
+ } else {
+ if (mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT) {
+ widthSpec = ViewGroup.LayoutParams.MATCH_PARENT;
+ } else {
+ if (mDropDownWidth == ViewGroup.LayoutParams.WRAP_CONTENT) {
+ mPopup.setWidth(getAnchorView().getWidth());
+ } else {
+ mPopup.setWidth(mDropDownWidth);
+ }
+ }
+
+ if (mDropDownHeight == ViewGroup.LayoutParams.MATCH_PARENT) {
+ heightSpec = ViewGroup.LayoutParams.MATCH_PARENT;
+ } else {
+ if (mDropDownHeight == ViewGroup.LayoutParams.WRAP_CONTENT) {
+ mPopup.setHeight(height);
+ } else {
+ mPopup.setHeight(mDropDownHeight);
+ }
+ }
+
+ mPopup.setWindowLayoutMode(widthSpec, heightSpec);
+ mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
+
+ // use outside touchable to dismiss drop down when touching outside of it, so
+ // only set this if the dropdown is not always visible
+ mPopup.setOutsideTouchable(!mForceIgnoreOutsideTouch && !mDropDownAlwaysVisible);
+ mPopup.setTouchInterceptor(mTouchInterceptor);
+ mPopup.showAsDropDown(getAnchorView(),
+ mDropDownHorizontalOffset, mDropDownVerticalOffset);
+ mDropDownList.setSelection(ListView.INVALID_POSITION);
+
+ if (!mModal || mDropDownList.isInTouchMode()) {
+ clearListSelection();
+ }
+ if (!mModal) {
+ mHandler.post(mHideSelector);
+ }
+ }
+ }
+
+ /**
+ * Dismiss the popup window.
+ */
+ public void dismiss() {
+ mPopup.dismiss();
+ removePromptView();
+ mPopup.setContentView(null);
+ mDropDownList = null;
+ }
+
+ private void removePromptView() {
+ if (mPromptView != null) {
+ final ViewParent parent = mPromptView.getParent();
+ if (parent instanceof ViewGroup) {
+ final ViewGroup group = (ViewGroup) parent;
+ group.removeView(mPromptView);
+ }
+ }
+ }
+
+ /**
+ * Control how the popup operates with an input method: one of
+ * {@link #INPUT_METHOD_FROM_FOCUSABLE}, {@link #INPUT_METHOD_NEEDED},
+ * or {@link #INPUT_METHOD_NOT_NEEDED}.
+ *
+ * <p>If the popup is showing, calling this method will take effect only
+ * the next time the popup is shown or through a manual call to the {@link #show()}
+ * method.</p>
+ *
+ * @see #getInputMethodMode()
+ * @see #show()
+ */
+ public void setInputMethodMode(int mode) {
+ mPopup.setInputMethodMode(mode);
+ }
+
+ /**
+ * Return the current value in {@link #setInputMethodMode(int)}.
+ *
+ * @see #setInputMethodMode(int)
+ */
+ public int getInputMethodMode() {
+ return mPopup.getInputMethodMode();
+ }
+
+ /**
+ * Set the selected position of the list.
+ * Only valid when {@link #isShowing()} == {@code true}.
+ *
+ * @param position List position to set as selected.
+ */
+ public void setSelection(int position) {
+ DropDownListView list = mDropDownList;
+ if (isShowing() && list != null) {
+ list.mListSelectionHidden = false;
+ list.setSelection(position);
+ if (list.getChoiceMode() != ListView.CHOICE_MODE_NONE) {
+ list.setItemChecked(position, true);
+ }
+ }
+ }
+
+ /**
+ * Clear any current list selection.
+ * Only valid when {@link #isShowing()} == {@code true}.
+ */
+ public void clearListSelection() {
+ final DropDownListView list = mDropDownList;
+ if (list != null) {
+ // WARNING: Please read the comment where mListSelectionHidden is declared
+ list.mListSelectionHidden = true;
+ list.hideSelector();
+ list.requestLayout();
+ }
+ }
+
+ /**
+ * @return {@code true} if the popup is currently showing, {@code false} otherwise.
+ */
+ public boolean isShowing() {
+ return mPopup.isShowing();
+ }
+
+ /**
+ * @return {@code true} if this popup is configured to assume the user does not need
+ * to interact with the IME while it is showing, {@code false} otherwise.
+ */
+ public boolean isInputMethodNotNeeded() {
+ return mPopup.getInputMethodMode() == INPUT_METHOD_NOT_NEEDED;
+ }
+
+ /**
+ * Perform an item click operation on the specified list adapter position.
+ *
+ * @param position Adapter position for performing the click
+ * @return true if the click action could be performed, false if not.
+ * (e.g. if the popup was not showing, this method would return false.)
+ */
+ public boolean performItemClick(int position) {
+ if (isShowing()) {
+ if (mItemClickListener != null) {
+ final DropDownListView list = mDropDownList;
+ final View child = list.getChildAt(position - list.getFirstVisiblePosition());
+ mItemClickListener.onItemClick(list, child, position, child.getId());
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * @return The currently selected item or null if the popup is not showing.
+ */
+ public Object getSelectedItem() {
+ if (!isShowing()) {
+ return null;
+ }
+ return mDropDownList.getSelectedItem();
+ }
+
+ /**
+ * @return The position of the currently selected item or {@link ListView#INVALID_POSITION}
+ * if {@link #isShowing()} == {@code false}.
+ *
+ * @see ListView#getSelectedItemPosition()
+ */
+ public int getSelectedItemPosition() {
+ if (!isShowing()) {
+ return ListView.INVALID_POSITION;
+ }
+ return mDropDownList.getSelectedItemPosition();
+ }
+
+ /**
+ * @return The ID of the currently selected item or {@link ListView#INVALID_ROW_ID}
+ * if {@link #isShowing()} == {@code false}.
+ *
+ * @see ListView#getSelectedItemId()
+ */
+ public long getSelectedItemId() {
+ if (!isShowing()) {
+ return ListView.INVALID_ROW_ID;
+ }
+ return mDropDownList.getSelectedItemId();
+ }
+
+ /**
+ * @return The View for the currently selected item or null if
+ * {@link #isShowing()} == {@code false}.
+ *
+ * @see ListView#getSelectedView()
+ */
+ public View getSelectedView() {
+ if (!isShowing()) {
+ return null;
+ }
+ return mDropDownList.getSelectedView();
+ }
+
+ /**
+ * @return The {@link ListView} displayed within the popup window.
+ * Only valid when {@link #isShowing()} == {@code true}.
+ */
+ public ListView getListView() {
+ return mDropDownList;
+ }
+
+ /**
+ * Filter key down events. By forwarding key up events to this function,
+ * views using non-modal ListPopupWindow can have it handle key selection of items.
+ *
+ * @param keyCode keyCode param passed to the host view's onKeyDown
+ * @param event event param passed to the host view's onKeyDown
+ * @return true if the event was handled, false if it was ignored.
+ *
+ * @see #setModal(boolean)
+ */
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ // when the drop down is shown, we drive it directly
+ if (isShowing()) {
+ // the key events are forwarded to the list in the drop down view
+ // note that ListView handles space but we don't want that to happen
+ // also if selection is not currently in the drop down, then don't
+ // let center or enter presses go there since that would cause it
+ // to select one of its items
+ if (keyCode != KeyEvent.KEYCODE_SPACE
+ && (mDropDownList.getSelectedItemPosition() >= 0
+ || (keyCode != KeyEvent.KEYCODE_ENTER
+ && keyCode != KeyEvent.KEYCODE_DPAD_CENTER))) {
+ int curIndex = mDropDownList.getSelectedItemPosition();
+ boolean consumed;
+
+ final boolean below = !mPopup.isAboveAnchor();
+
+ final ListAdapter adapter = mAdapter;
+
+ boolean allEnabled;
+ int firstItem = Integer.MAX_VALUE;
+ int lastItem = Integer.MIN_VALUE;
+
+ if (adapter != null) {
+ allEnabled = adapter.areAllItemsEnabled();
+ firstItem = allEnabled ? 0 :
+ mDropDownList.lookForSelectablePosition(0, true);
+ lastItem = allEnabled ? adapter.getCount() - 1 :
+ mDropDownList.lookForSelectablePosition(adapter.getCount() - 1, false);
+ }
+
+ if ((below && keyCode == KeyEvent.KEYCODE_DPAD_UP && curIndex <= firstItem) ||
+ (!below && keyCode == KeyEvent.KEYCODE_DPAD_DOWN && curIndex >= lastItem)) {
+ // When the selection is at the top, we block the key
+ // event to prevent focus from moving.
+ clearListSelection();
+ mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
+ show();
+ return true;
+ } else {
+ // WARNING: Please read the comment where mListSelectionHidden
+ // is declared
+ mDropDownList.mListSelectionHidden = false;
+ }
+
+ consumed = mDropDownList.onKeyDown(keyCode, event);
+ if (DEBUG) Log.v(TAG, "Key down: code=" + keyCode + " list consumed=" + consumed);
+
+ if (consumed) {
+ // If it handled the key event, then the user is
+ // navigating in the list, so we should put it in front.
+ mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
+ // Here's a little trick we need to do to make sure that
+ // the list view is actually showing its focus indicator,
+ // by ensuring it has focus and getting its window out
+ // of touch mode.
+ mDropDownList.requestFocusFromTouch();
+ show();
+
+ switch (keyCode) {
+ // avoid passing the focus from the text view to the
+ // next component
+ case KeyEvent.KEYCODE_ENTER:
+ case KeyEvent.KEYCODE_DPAD_CENTER:
+ case KeyEvent.KEYCODE_DPAD_DOWN:
+ case KeyEvent.KEYCODE_DPAD_UP:
+ return true;
+ }
+ } else {
+ if (below && keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
+ // when the selection is at the bottom, we block the
+ // event to avoid going to the next focusable widget
+ if (curIndex == lastItem) {
+ return true;
+ }
+ } else if (!below && keyCode == KeyEvent.KEYCODE_DPAD_UP &&
+ curIndex == firstItem) {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Filter key down events. By forwarding key up events to this function,
+ * views using non-modal ListPopupWindow can have it handle key selection of items.
+ *
+ * @param keyCode keyCode param passed to the host view's onKeyUp
+ * @param event event param passed to the host view's onKeyUp
+ * @return true if the event was handled, false if it was ignored.
+ *
+ * @see #setModal(boolean)
+ */
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ if (isShowing() && mDropDownList.getSelectedItemPosition() >= 0) {
+ boolean consumed = mDropDownList.onKeyUp(keyCode, event);
+ if (consumed) {
+ switch (keyCode) {
+ // if the list accepts the key events and the key event
+ // was a click, the text view gets the selected item
+ // from the drop down as its content
+ case KeyEvent.KEYCODE_ENTER:
+ case KeyEvent.KEYCODE_DPAD_CENTER:
+ dismiss();
+ break;
+ }
+ }
+ return consumed;
+ }
+ return false;
+ }
+
+ /**
+ * Filter pre-IME key events. By forwarding {@link View#onKeyPreIme(int, KeyEvent)}
+ * events to this function, views using ListPopupWindow can have it dismiss the popup
+ * when the back key is pressed.
+ *
+ * @param keyCode keyCode param passed to the host view's onKeyPreIme
+ * @param event event param passed to the host view's onKeyPreIme
+ * @return true if the event was handled, false if it was ignored.
+ *
+ * @see #setModal(boolean)
+ */
+ public boolean onKeyPreIme(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_BACK && isShowing()) {
+ // special case for the back key, we do not even try to send it
+ // to the drop down list but instead, consume it immediately
+ final View anchorView = mDropDownAnchorView;
+ if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
+ anchorView.getKeyDispatcherState().startTracking(event, this);
+ return true;
+ } else if (event.getAction() == KeyEvent.ACTION_UP) {
+ anchorView.getKeyDispatcherState().handleUpEvent(event);
+ if (event.isTracking() && !event.isCanceled()) {
+ dismiss();
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * <p>Builds the popup window's content and returns the height the popup
+ * should have. Returns -1 when the content already exists.</p>
+ *
+ * @return the content's height or -1 if content already exists
+ */
+ private int buildDropDown() {
+ ViewGroup dropDownView;
+ int otherHeights = 0;
+
+ if (mDropDownList == null) {
+ Context context = mContext;
+
+ /**
+ * This Runnable exists for the sole purpose of checking if the view layout has got
+ * completed and if so call showDropDown to display the drop down. This is used to show
+ * the drop down as soon as possible after user opens up the search dialog, without
+ * waiting for the normal UI pipeline to do it's job which is slower than this method.
+ */
+ mShowDropDownRunnable = new Runnable() {
+ public void run() {
+ // View layout should be all done before displaying the drop down.
+ View view = getAnchorView();
+ if (view != null && view.getWindowToken() != null) {
+ show();
+ }
+ }
+ };
+
+ mDropDownList = new DropDownListView(context, !mModal);
+ if (mDropDownListHighlight != null) {
+ mDropDownList.setSelector(mDropDownListHighlight);
+ }
+ mDropDownList.setAdapter(mAdapter);
+ mDropDownList.setVerticalFadingEdgeEnabled(true);
+ mDropDownList.setOnItemClickListener(mItemClickListener);
+ mDropDownList.setFocusable(true);
+ mDropDownList.setFocusableInTouchMode(true);
+ mDropDownList.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ public void onItemSelected(AdapterView<?> parent, View view,
+ int position, long id) {
+
+ if (position != -1) {
+ DropDownListView dropDownList = mDropDownList;
+
+ if (dropDownList != null) {
+ dropDownList.mListSelectionHidden = false;
+ }
+ }
+ }
+
+ public void onNothingSelected(AdapterView<?> parent) {
+ }
+ });
+ mDropDownList.setOnScrollListener(mScrollListener);
+
+ if (mItemSelectedListener != null) {
+ mDropDownList.setOnItemSelectedListener(mItemSelectedListener);
+ }
+
+ dropDownView = mDropDownList;
+
+ View hintView = mPromptView;
+ if (hintView != null) {
+ // if an hint has been specified, we accomodate more space for it and
+ // add a text view in the drop down menu, at the bottom of the list
+ LinearLayout hintContainer = new LinearLayout(context);
+ hintContainer.setOrientation(LinearLayout.VERTICAL);
+
+ LinearLayout.LayoutParams hintParams = new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT, 0, 1.0f
+ );
+
+ switch (mPromptPosition) {
+ case POSITION_PROMPT_BELOW:
+ hintContainer.addView(dropDownView, hintParams);
+ hintContainer.addView(hintView);
+ break;
+
+ case POSITION_PROMPT_ABOVE:
+ hintContainer.addView(hintView);
+ hintContainer.addView(dropDownView, hintParams);
+ break;
+
+ default:
+ Log.e(TAG, "Invalid hint position " + mPromptPosition);
+ break;
+ }
+
+ // measure the hint's height to find how much more vertical space
+ // we need to add to the drop down's height
+ int widthSpec = MeasureSpec.makeMeasureSpec(mDropDownWidth, MeasureSpec.AT_MOST);
+ int heightSpec = MeasureSpec.UNSPECIFIED;
+ hintView.measure(widthSpec, heightSpec);
+
+ hintParams = (LinearLayout.LayoutParams) hintView.getLayoutParams();
+ otherHeights = hintView.getMeasuredHeight() + hintParams.topMargin
+ + hintParams.bottomMargin;
+
+ dropDownView = hintContainer;
+ }
+
+ mPopup.setContentView(dropDownView);
+ } else {
+ dropDownView = (ViewGroup) mPopup.getContentView();
+ final View view = mPromptView;
+ if (view != null) {
+ LinearLayout.LayoutParams hintParams =
+ (LinearLayout.LayoutParams) view.getLayoutParams();
+ otherHeights = view.getMeasuredHeight() + hintParams.topMargin
+ + hintParams.bottomMargin;
+ }
+ }
+
+ // Max height available on the screen for a popup.
+ boolean ignoreBottomDecorations =
+ mPopup.getInputMethodMode() == PopupWindow.INPUT_METHOD_NOT_NEEDED;
+ final int maxHeight = mPopup.getMaxAvailableHeight(
+ getAnchorView(), mDropDownVerticalOffset, ignoreBottomDecorations);
+
+ // getMaxAvailableHeight() subtracts the padding, so we put it back,
+ // to get the available height for the whole window
+ int padding = 0;
+ Drawable background = mPopup.getBackground();
+ if (background != null) {
+ background.getPadding(mTempRect);
+ padding = mTempRect.top + mTempRect.bottom;
+ }
+
+ if (mDropDownAlwaysVisible || mDropDownHeight == ViewGroup.LayoutParams.MATCH_PARENT) {
+ return maxHeight + padding;
+ }
+
+ final int listContent = mDropDownList.measureHeightOfChildren(MeasureSpec.UNSPECIFIED,
+ 0, ListView.NO_POSITION, maxHeight - otherHeights, 2);
+ // add padding only if the list has items in it, that way we don't show
+ // the popup if it is not needed
+ if (listContent > 0) otherHeights += padding;
+
+ return listContent + otherHeights;
+ }
+
+ /**
+ * <p>Wrapper class for a ListView. This wrapper can hijack the focus to
+ * make sure the list uses the appropriate drawables and states when
+ * displayed on screen within a drop down. The focus is never actually
+ * passed to the drop down in this mode; the list only looks focused.</p>
+ */
+ private static class DropDownListView extends ListView {
+ private static final String TAG = ListPopupWindow.TAG + ".DropDownListView";
+ /*
+ * WARNING: This is a workaround for a touch mode issue.
+ *
+ * Touch mode is propagated lazily to windows. This causes problems in
+ * the following scenario:
+ * - Type something in the AutoCompleteTextView and get some results
+ * - Move down with the d-pad to select an item in the list
+ * - Move up with the d-pad until the selection disappears
+ * - Type more text in the AutoCompleteTextView *using the soft keyboard*
+ * and get new results; you are now in touch mode
+ * - The selection comes back on the first item in the list, even though
+ * the list is supposed to be in touch mode
+ *
+ * Using the soft keyboard triggers the touch mode change but that change
+ * is propagated to our window only after the first list layout, therefore
+ * after the list attempts to resurrect the selection.
+ *
+ * The trick to work around this issue is to pretend the list is in touch
+ * mode when we know that the selection should not appear, that is when
+ * we know the user moved the selection away from the list.
+ *
+ * This boolean is set to true whenever we explicitly hide the list's
+ * selection and reset to false whenever we know the user moved the
+ * selection back to the list.
+ *
+ * When this boolean is true, isInTouchMode() returns true, otherwise it
+ * returns super.isInTouchMode().
+ */
+ private boolean mListSelectionHidden;
+
+ /**
+ * True if this wrapper should fake focus.
+ */
+ private boolean mHijackFocus;
+
+ /**
+ * <p>Creates a new list view wrapper.</p>
+ *
+ * @param context this view's context
+ */
+ public DropDownListView(Context context, boolean hijackFocus) {
+ super(context, null, com.android.internal.R.attr.dropDownListViewStyle);
+ mHijackFocus = hijackFocus;
+ }
+
+ /**
+ * <p>Avoids jarring scrolling effect by ensuring that list elements
+ * made of a text view fit on a single line.</p>
+ *
+ * @param position the item index in the list to get a view for
+ * @return the view for the specified item
+ */
+ @Override
+ View obtainView(int position, boolean[] isScrap) {
+ View view = super.obtainView(position, isScrap);
+
+ if (view instanceof TextView) {
+ ((TextView) view).setHorizontallyScrolling(true);
+ }
+
+ return view;
+ }
+
+ @Override
+ public boolean isInTouchMode() {
+ // WARNING: Please read the comment where mListSelectionHidden is declared
+ return (mHijackFocus && mListSelectionHidden) || super.isInTouchMode();
+ }
+
+ /**
+ * <p>Returns the focus state in the drop down.</p>
+ *
+ * @return true always if hijacking focus
+ */
+ @Override
+ public boolean hasWindowFocus() {
+ return mHijackFocus || super.hasWindowFocus();
+ }
+
+ /**
+ * <p>Returns the focus state in the drop down.</p>
+ *
+ * @return true always if hijacking focus
+ */
+ @Override
+ public boolean isFocused() {
+ return mHijackFocus || super.isFocused();
+ }
+
+ /**
+ * <p>Returns the focus state in the drop down.</p>
+ *
+ * @return true always if hijacking focus
+ */
+ @Override
+ public boolean hasFocus() {
+ return mHijackFocus || super.hasFocus();
+ }
+ }
+
+ private class PopupDataSetObserver extends DataSetObserver {
+ @Override
+ public void onChanged() {
+ if (isShowing()) {
+ // Resize the popup to fit new content
+ show();
+ }
+ }
+
+ @Override
+ public void onInvalidated() {
+ dismiss();
+ }
+ }
+
+ private class ListSelectorHider implements Runnable {
+ public void run() {
+ clearListSelection();
+ }
+ }
+
+ private class ResizePopupRunnable implements Runnable {
+ public void run() {
+ mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
+ show();
+ }
+ }
+
+ private class PopupTouchInterceptor implements OnTouchListener {
+ public boolean onTouch(View v, MotionEvent event) {
+ final int action = event.getAction();
+ final int x = (int) event.getX();
+ final int y = (int) event.getY();
+
+ if (action == MotionEvent.ACTION_DOWN &&
+ mPopup != null && mPopup.isShowing() &&
+ (x >= 0 && x < getWidth() && y >= 0 && y < getHeight())) {
+ mHandler.postDelayed(mResizePopupRunnable, EXPAND_LIST_TIMEOUT);
+ } else if (action == MotionEvent.ACTION_UP) {
+ mHandler.removeCallbacks(mResizePopupRunnable);
+ }
+ return false;
+ }
+ }
+
+ private class PopupScrollListener implements ListView.OnScrollListener {
+ public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
+ int totalItemCount) {
+
+ }
+
+ public void onScrollStateChanged(AbsListView view, int scrollState) {
+ if (scrollState == SCROLL_STATE_TOUCH_SCROLL &&
+ !isInputMethodNotNeeded() && mPopup.getContentView() != null) {
+ mHandler.removeCallbacks(mResizePopupRunnable);
+ mResizePopupRunnable.run();
+ }
+ }
+ }
+}
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 892c44a..91f4946 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -415,7 +415,7 @@
*/
@Override
public void setAdapter(ListAdapter adapter) {
- if (null != mAdapter) {
+ if (mAdapter != null && mDataSetObserver != null) {
mAdapter.unregisterDataSetObserver(mDataSetObserver);
}
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 0378328..d404ce7 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -16,27 +16,28 @@
package android.widget;
-import com.android.internal.R;
+import java.lang.ref.WeakReference;
import android.content.Context;
import android.content.res.TypedArray;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.WindowManager;
-import android.view.Gravity;
-import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
-import android.view.ViewTreeObserver.OnScrollChangedListener;
-import android.view.View.OnTouchListener;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.StateListDrawable;
import android.os.IBinder;
import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.view.WindowManager;
+import android.view.View.OnTouchListener;
+import android.view.ViewTreeObserver.OnScrollChangedListener;
-import java.lang.ref.WeakReference;
+import com.android.internal.R;
/**
* <p>A popup window that can be used to display an arbitrary view. The popup
@@ -157,12 +158,21 @@
* <p>The popup does provide a background.</p>
*/
public PopupWindow(Context context, AttributeSet attrs, int defStyle) {
+ this(context, attrs, defStyle, 0);
+ }
+
+ /**
+ * <p>Create a new, empty, non focusable popup window of dimension (0,0).</p>
+ *
+ * <p>The popup does not provide a background.</p>
+ */
+ public PopupWindow(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
mContext = context;
mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
TypedArray a =
context.obtainStyledAttributes(
- attrs, com.android.internal.R.styleable.PopupWindow, defStyle, 0);
+ attrs, com.android.internal.R.styleable.PopupWindow, defStyleAttr, defStyleRes);
mBackground = a.getDrawable(R.styleable.PopupWindow_popupBackground);
@@ -1315,6 +1325,7 @@
}
private class PopupViewContainer extends FrameLayout {
+ private static final String TAG = "PopupWindow.PopupViewContainer";
public PopupViewContainer(Context context) {
super(context);
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index 8e9eb05..71f0c2f 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -715,8 +715,8 @@
mAnimation.setDuration(mDuration);
mAnimation.setInterpolator(mInterpolator);
mAnimation.setStartTime(Animation.START_ON_FIRST_FRAME);
- postInvalidate();
}
+ postInvalidate();
}
/**
@@ -729,6 +729,7 @@
((Animatable) mIndeterminateDrawable).stop();
mShouldStartAnimationDrawable = false;
}
+ postInvalidate();
}
/**
diff --git a/core/java/android/widget/QuickContactBadge.java b/core/java/android/widget/QuickContactBadge.java
index 07c3e4b..50fbb6b 100644
--- a/core/java/android/widget/QuickContactBadge.java
+++ b/core/java/android/widget/QuickContactBadge.java
@@ -48,6 +48,7 @@
private QueryHandler mQueryHandler;
private Drawable mBadgeBackground;
private Drawable mNoBadgeBackground;
+ private Drawable mDefaultAvatar;
protected String[] mExcludeMimes = null;
@@ -117,6 +118,16 @@
public void setMode(int size) {
mMode = size;
}
+
+ /**
+ * Resets the contact photo to the default state.
+ */
+ public void setImageToDefault() {
+ if (mDefaultAvatar == null) {
+ mDefaultAvatar = getResources().getDrawable(R.drawable.ic_contact_picture);
+ }
+ setImageDrawable(mDefaultAvatar);
+ }
/**
* Assign the contact uri that this QuickContactBadge should be associated
diff --git a/core/java/android/widget/SimpleCursorAdapter.java b/core/java/android/widget/SimpleCursorAdapter.java
index 7d3459e..d1c2270 100644
--- a/core/java/android/widget/SimpleCursorAdapter.java
+++ b/core/java/android/widget/SimpleCursorAdapter.java
@@ -62,7 +62,8 @@
private int mStringConversionColumn = -1;
private CursorToStringConverter mCursorToStringConverter;
private ViewBinder mViewBinder;
- private String[] mOriginalFrom;
+
+ String[] mOriginalFrom;
/**
* Constructor.
diff --git a/core/java/android/widget/Spinner.java b/core/java/android/widget/Spinner.java
index 2f6dd1e..60e8568 100644
--- a/core/java/android/widget/Spinner.java
+++ b/core/java/android/widget/Spinner.java
@@ -24,6 +24,7 @@
import android.content.res.TypedArray;
import android.database.DataSetObserver;
import android.util.AttributeSet;
+import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -37,10 +38,21 @@
*/
@Widget
public class Spinner extends AbsSpinner implements OnClickListener {
+ private static final String TAG = "Spinner";
- private CharSequence mPrompt;
- private AlertDialog mPopup;
-
+ /**
+ * Use a dialog window for selecting spinner options.
+ */
+ public static final int MODE_DIALOG = 0;
+
+ /**
+ * Use a dropdown anchored to the Spinner for selecting spinner options.
+ */
+ public static final int MODE_DROPDOWN = 1;
+
+ private SpinnerPopup mPopup;
+ private DropDownAdapter mTempAdapter;
+
public Spinner(Context context) {
this(context, null);
}
@@ -55,9 +67,54 @@
TypedArray a = context.obtainStyledAttributes(attrs,
com.android.internal.R.styleable.Spinner, defStyle, 0);
- mPrompt = a.getString(com.android.internal.R.styleable.Spinner_prompt);
+ final int mode = a.getInt(com.android.internal.R.styleable.Spinner_spinnerMode,
+ MODE_DIALOG);
+
+ switch (mode) {
+ case MODE_DIALOG: {
+ mPopup = new DialogPopup();
+ break;
+ }
+
+ case MODE_DROPDOWN: {
+ final int hintResource = a.getResourceId(
+ com.android.internal.R.styleable.Spinner_popupPromptView, 0);
+
+ DropdownPopup popup = new DropdownPopup(context, attrs, defStyle, hintResource);
+
+ popup.setBackgroundDrawable(a.getDrawable(
+ com.android.internal.R.styleable.Spinner_popupBackground));
+ popup.setVerticalOffset(a.getDimensionPixelOffset(
+ com.android.internal.R.styleable.Spinner_dropDownVerticalOffset, 0));
+ popup.setHorizontalOffset(a.getDimensionPixelOffset(
+ com.android.internal.R.styleable.Spinner_dropDownHorizontalOffset, 0));
+
+ mPopup = popup;
+ break;
+ }
+ }
+
+ mPopup.setPromptText(a.getString(com.android.internal.R.styleable.Spinner_prompt));
a.recycle();
+
+ // Base constructor can call setAdapter before we initialize mPopup.
+ // Finish setting things up if this happened.
+ if (mTempAdapter != null) {
+ mPopup.setAdapter(mTempAdapter);
+ mTempAdapter = null;
+ }
+ }
+
+ @Override
+ public void setAdapter(SpinnerAdapter adapter) {
+ super.setAdapter(adapter);
+
+ if (mPopup != null) {
+ mPopup.setAdapter(new DropDownAdapter(adapter));
+ } else {
+ mTempAdapter = new DropDownAdapter(adapter);
+ }
}
@Override
@@ -194,8 +251,6 @@
return child;
}
-
-
/**
* Helper for makeAndAddView to set the position of a view
* and fill out its layout paramters.
@@ -246,15 +301,10 @@
if (!handled) {
handled = true;
- Context context = getContext();
-
- final DropDownAdapter adapter = new DropDownAdapter(getAdapter());
- AlertDialog.Builder builder = new AlertDialog.Builder(context);
- if (mPrompt != null) {
- builder.setTitle(mPrompt);
+ if (!mPopup.isShowing()) {
+ mPopup.show();
}
- mPopup = builder.setSingleChoiceItems(adapter, getSelectedItemPosition(), this).show();
}
return handled;
@@ -271,7 +321,7 @@
* @param prompt the prompt to set
*/
public void setPrompt(CharSequence prompt) {
- mPrompt = prompt;
+ mPopup.setPromptText(prompt);
}
/**
@@ -279,14 +329,14 @@
* @param promptId the resource ID of the prompt to display when the dialog is shown
*/
public void setPromptId(int promptId) {
- mPrompt = getContext().getText(promptId);
+ setPrompt(getContext().getText(promptId));
}
/**
* @return The prompt to display when the dialog is shown
*/
public CharSequence getPrompt() {
- return mPrompt;
+ return mPopup.getHintText();
}
/**
@@ -384,4 +434,123 @@
return getCount() == 0;
}
}
+
+ /**
+ * Implements some sort of popup selection interface for selecting a spinner option.
+ * Allows for different spinner modes.
+ */
+ private interface SpinnerPopup {
+ public void setAdapter(ListAdapter adapter);
+
+ /**
+ * Show the popup
+ */
+ public void show();
+
+ /**
+ * Dismiss the popup
+ */
+ public void dismiss();
+
+ /**
+ * @return true if the popup is showing, false otherwise.
+ */
+ public boolean isShowing();
+
+ /**
+ * Set hint text to be displayed to the user. This should provide
+ * a description of the choice being made.
+ * @param hintText Hint text to set.
+ */
+ public void setPromptText(CharSequence hintText);
+ public CharSequence getHintText();
+ }
+
+ private class DialogPopup implements SpinnerPopup, DialogInterface.OnClickListener {
+ private AlertDialog mPopup;
+ private ListAdapter mListAdapter;
+ private CharSequence mPrompt;
+
+ public void dismiss() {
+ mPopup.dismiss();
+ mPopup = null;
+ }
+
+ public boolean isShowing() {
+ return mPopup != null ? mPopup.isShowing() : false;
+ }
+
+ public void setAdapter(ListAdapter adapter) {
+ mListAdapter = adapter;
+ }
+
+ public void setPromptText(CharSequence hintText) {
+ mPrompt = hintText;
+ }
+
+ public CharSequence getHintText() {
+ return mPrompt;
+ }
+
+ public void show() {
+ AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
+ if (mPrompt != null) {
+ builder.setTitle(mPrompt);
+ }
+ mPopup = builder.setSingleChoiceItems(mListAdapter,
+ getSelectedItemPosition(), this).show();
+ }
+
+ public void onClick(DialogInterface dialog, int which) {
+ setSelection(which);
+ dismiss();
+ }
+ }
+
+ private class DropdownPopup extends ListPopupWindow implements SpinnerPopup {
+ private CharSequence mHintText;
+ private TextView mHintView;
+ private int mHintResource;
+
+ public DropdownPopup(Context context, AttributeSet attrs,
+ int defStyleRes, int hintResource) {
+ super(context, attrs, 0, defStyleRes);
+
+ mHintResource = hintResource;
+
+ setAnchorView(Spinner.this);
+ setModal(true);
+ setPromptPosition(POSITION_PROMPT_BELOW);
+ setOnItemClickListener(new OnItemClickListener() {
+ public void onItemClick(AdapterView parent, View v, int position, long id) {
+ Spinner.this.setSelection(position);
+ dismiss();
+ }
+ });
+ }
+
+ public CharSequence getHintText() {
+ return mHintText;
+ }
+
+ public void setPromptText(CharSequence hintText) {
+ mHintText = hintText;
+ if (mHintView != null) {
+ mHintView.setText(hintText);
+ }
+ }
+
+ public void show() {
+ if (mHintView == null) {
+ final TextView textView = (TextView) LayoutInflater.from(getContext()).inflate(
+ mHintResource, null).findViewById(com.android.internal.R.id.text1);
+ textView.setText(mHintText);
+ setPromptView(textView);
+ mHintView = textView;
+ }
+ super.show();
+ getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
+ setSelection(Spinner.this.getSelectedItemPosition());
+ }
+ }
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 950012c..0de4f4e 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -2781,6 +2781,11 @@
c.drawText(mChars, start + mStart, end - start, x, y, p);
}
+ public void drawTextRun(Canvas c, int start, int end,
+ float x, float y, int flags, Paint p) {
+ c.drawTextRun(mChars, start + mStart, end - start, x, y, flags, p);
+ }
+
public float measureText(int start, int end, Paint p) {
return p.measureText(mChars, start + mStart, end - start);
}
@@ -4842,6 +4847,8 @@
break;
case Gravity.RIGHT:
+ // Note, Layout resolves ALIGN_OPPOSITE to left or
+ // right based on the paragraph direction.
alignment = Layout.Alignment.ALIGN_OPPOSITE;
break;
@@ -5663,11 +5670,15 @@
final int leftChar = mLayout.getOffsetForHorizontal(line, hs);
final int rightChar = mLayout.getOffsetForHorizontal(line, hspace+hs);
+ // line might contain bidirectional text
+ final int lowChar = leftChar < rightChar ? leftChar : rightChar;
+ final int highChar = leftChar > rightChar ? leftChar : rightChar;
+
int newStart = start;
- if (newStart < leftChar) {
- newStart = leftChar;
- } else if (newStart > rightChar) {
- newStart = rightChar;
+ if (newStart < lowChar) {
+ newStart = lowChar;
+ } else if (newStart > highChar) {
+ newStart = highChar;
}
if (newStart != start) {
diff --git a/core/java/android/widget/ZoomButtonsController.java b/core/java/android/widget/ZoomButtonsController.java
index 3df419a..450c966 100644
--- a/core/java/android/widget/ZoomButtonsController.java
+++ b/core/java/android/widget/ZoomButtonsController.java
@@ -66,8 +66,9 @@
* {@link #setZoomInEnabled(boolean)} and {@link #setZoomOutEnabled(boolean)}.
* <p>
* If you are using this with a custom View, please call
- * {@link #setVisible(boolean) setVisible(false)} from the
- * {@link View#onDetachedFromWindow}.
+ * {@link #setVisible(boolean) setVisible(false)} from
+ * {@link View#onDetachedFromWindow} and from {@link View#onVisibilityChanged}
+ * when <code>visibility != View.VISIBLE</code>.
*
*/
public class ZoomButtonsController implements View.OnTouchListener {
diff --git a/core/java/com/android/internal/app/SplitActionBar.java b/core/java/com/android/internal/app/SplitActionBar.java
new file mode 100644
index 0000000..8129492
--- /dev/null
+++ b/core/java/com/android/internal/app/SplitActionBar.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.app;
+
+import android.app.ActionBar;
+import android.graphics.drawable.Drawable;
+import android.view.ActionBarView;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.SpinnerAdapter;
+
+/**
+ * SplitActionBar is the ActionBar implementation used
+ * by small-screen devices. It expects to split contextual
+ * modes across both the ActionBarView at the top of the screen
+ * and a horizontal LinearLayout at the bottom which is normally
+ * hidden.
+ */
+public class SplitActionBar extends ActionBar {
+ private ActionBarView mActionView;
+ private LinearLayout mContextView;
+
+ public SplitActionBar(ActionBarView view, LinearLayout contextView) {
+ mActionView = view;
+ mContextView = contextView;
+ }
+
+ public void setCallback(Callback callback) {
+ mActionView.setCallback(callback);
+ }
+
+ public void setCustomNavigationMode(View view) {
+ mActionView.setCustomNavigationView(view);
+ }
+
+ public void setDropdownNavigationMode(SpinnerAdapter adapter) {
+ mActionView.setNavigationMode(NAVIGATION_MODE_DROPDOWN_LIST);
+ mActionView.setDropdownAdapter(adapter);
+ }
+
+ public void setStandardNavigationMode(CharSequence title) {
+ setStandardNavigationMode(title, null);
+ }
+
+ public void setStandardNavigationMode(CharSequence title, CharSequence subtitle) {
+ mActionView.setNavigationMode(NAVIGATION_MODE_STANDARD);
+ mActionView.setTitle(title);
+ mActionView.setSubtitle(subtitle);
+ }
+
+ public void setTitle(CharSequence title) {
+ mActionView.setTitle(title);
+ }
+
+ public void setSubtitle(CharSequence subtitle) {
+ mActionView.setSubtitle(subtitle);
+ }
+
+ public void setDisplayOptions(int options) {
+ mActionView.setDisplayOptions(options);
+ }
+
+ public void setDisplayOptions(int options, int mask) {
+ final int current = mActionView.getDisplayOptions();
+ mActionView.setDisplayOptions((options & mask) | (current & ~mask));
+ }
+
+ public void setBackgroundDrawable(Drawable d) {
+ mActionView.setBackgroundDrawable(d);
+ }
+
+ public void setDividerDrawable(Drawable d) {
+ mActionView.setDividerDrawable(d);
+ }
+
+ public View getCustomNavigationView() {
+ return mActionView.getCustomNavigationView();
+ }
+
+ public CharSequence getTitle() {
+ return mActionView.getTitle();
+ }
+
+ public CharSequence getSubtitle() {
+ return mActionView.getSubtitle();
+ }
+
+ public int getNavigationMode() {
+ return mActionView.getNavigationMode();
+ }
+
+ public int getDisplayOptions() {
+ return mActionView.getDisplayOptions();
+ }
+
+ public void updateActionMenu() {
+ mActionView.updateActionMenu();
+ }
+
+}
diff --git a/core/java/com/android/internal/database/SortCursor.java b/core/java/com/android/internal/database/SortCursor.java
index 99410bc..0025512 100644
--- a/core/java/com/android/internal/database/SortCursor.java
+++ b/core/java/com/android/internal/database/SortCursor.java
@@ -182,24 +182,6 @@
}
@Override
- public boolean deleteRow()
- {
- return mCursor.deleteRow();
- }
-
- @Override
- public boolean commitUpdates() {
- int length = mCursors.length;
- for (int i = 0 ; i < length ; i++) {
- if (mCursors[i] != null) {
- mCursors[i].commitUpdates();
- }
- }
- onChange(true);
- return true;
- }
-
- @Override
public String getString(int column)
{
return mCursor.getString(column);
@@ -236,6 +218,11 @@
}
@Override
+ public int getType(int column) {
+ return mCursor.getType(column);
+ }
+
+ @Override
public boolean isNull(int column)
{
return mCursor.isNull(column);
diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java
index 2369d25..127ed68 100644
--- a/core/java/com/android/internal/os/PowerProfile.java
+++ b/core/java/com/android/internal/os/PowerProfile.java
@@ -126,6 +126,11 @@
public static final String POWER_CPU_SPEEDS = "cpu.speeds";
+ /**
+ * Battery capacity in milliAmpHour (mAh).
+ */
+ public static final String POWER_BATTERY_CAPACITY = "battery.capacity";
+
static final HashMap<String, Object> sPowerMap = new HashMap<String, Object>();
private static final String TAG_DEVICE = "device";
@@ -243,6 +248,19 @@
}
}
+ /**
+ * Returns the battery capacity, if available, in milli Amp Hours. If not available,
+ * it returns zero.
+ * @return the battery capacity in mAh
+ */
+ public double getBatteryCapacity() {
+ return getAveragePower(POWER_BATTERY_CAPACITY);
+ }
+
+ /**
+ * Returns the number of speeds that the CPU can be run at.
+ * @return
+ */
public int getNumSpeedSteps() {
Object value = sPowerMap.get(POWER_CPU_SPEEDS);
if (value != null && value instanceof Double[]) {
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index b677b1e..9fcd3f5 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -66,10 +66,6 @@
/** when preloading, GC after allocating this many bytes */
private static final int PRELOAD_GC_THRESHOLD = 50000;
- /** throw on missing preload, only if this looks like a developer */
- private static final boolean THROW_ON_MISSING_PRELOAD =
- "1".equals(SystemProperties.get("persist.service.adb.enable"));
-
public static final String USAGE_STRING =
" <\"true\"|\"false\" for startSystemServer>";
@@ -287,7 +283,6 @@
int count = 0;
String line;
- String missingClasses = null;
while ((line = br.readLine()) != null) {
// Skip comments and blank lines.
line = line.trim();
@@ -311,12 +306,7 @@
}
count++;
} catch (ClassNotFoundException e) {
- Log.e(TAG, "Class not found for preloading: " + line);
- if (missingClasses == null) {
- missingClasses = line;
- } else {
- missingClasses += " " + line;
- }
+ Log.w(TAG, "Class not found for preloading: " + line);
} catch (Throwable t) {
Log.e(TAG, "Error preloading " + line + ".", t);
if (t instanceof Error) {
@@ -329,13 +319,6 @@
}
}
- if (THROW_ON_MISSING_PRELOAD &&
- missingClasses != null) {
- throw new IllegalStateException(
- "Missing class(es) for preloading, update preloaded-classes ["
- + missingClasses + "]");
- }
-
Log.i(TAG, "...preloaded " + count + " classes in "
+ (SystemClock.uptimeMillis()-startTime) + "ms.");
} catch (IOException e) {
diff --git a/core/java/com/android/internal/util/XmlUtils.java b/core/java/com/android/internal/util/XmlUtils.java
index 8d8df16..e00a853 100644
--- a/core/java/com/android/internal/util/XmlUtils.java
+++ b/core/java/com/android/internal/util/XmlUtils.java
@@ -26,6 +26,7 @@
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -284,6 +285,26 @@
out.endTag(null, "list");
}
+
+ public static final void writeSetXml(Set val, String name, XmlSerializer out)
+ throws XmlPullParserException, java.io.IOException {
+ if (val == null) {
+ out.startTag(null, "null");
+ out.endTag(null, "null");
+ return;
+ }
+
+ out.startTag(null, "set");
+ if (name != null) {
+ out.attribute(null, "name", name);
+ }
+
+ for (Object v : val) {
+ writeValueXml(v, null, out);
+ }
+
+ out.endTag(null, "set");
+ }
/**
* Flatten a byte[] into an XmlSerializer. The list can later be read back
@@ -426,6 +447,9 @@
} else if (v instanceof List) {
writeListXml((List)v, name, out);
return;
+ } else if (v instanceof Set) {
+ writeSetXml((Set)v, name, out);
+ return;
} else if (v instanceof CharSequence) {
// XXX This is to allow us to at least write something if
// we encounter styled text... but it means we will drop all
@@ -476,7 +500,7 @@
*
* @param in The InputStream from which to read.
*
- * @return HashMap The resulting list.
+ * @return ArrayList The resulting list.
*
* @see #readMapXml
* @see #readValueXml
@@ -490,6 +514,29 @@
parser.setInput(in, null);
return (ArrayList)readValueXml(parser, new String[1]);
}
+
+
+ /**
+ * Read a HashSet from an InputStream containing XML. The stream can
+ * previously have been written by writeSetXml().
+ *
+ * @param in The InputStream from which to read.
+ *
+ * @return HashSet The resulting set.
+ *
+ * @throws XmlPullParserException
+ * @throws java.io.IOException
+ *
+ * @see #readValueXml
+ * @see #readThisSetXml
+ * @see #writeSetXml
+ */
+ public static final HashSet readSetXml(InputStream in)
+ throws XmlPullParserException, java.io.IOException {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(in, null);
+ return (HashSet) readValueXml(parser, new String[1]);
+ }
/**
* Read a HashMap object from an XmlPullParser. The XML data could
@@ -573,6 +620,47 @@
throw new XmlPullParserException(
"Document ended before " + endTag + " end tag");
}
+
+ /**
+ * Read a HashSet object from an XmlPullParser. The XML data could previously
+ * have been generated by writeSetXml(). The XmlPullParser must be positioned
+ * <em>after</em> the tag that begins the set.
+ *
+ * @param parser The XmlPullParser from which to read the set data.
+ * @param endTag Name of the tag that will end the set, usually "set".
+ * @param name An array of one string, used to return the name attribute
+ * of the set's tag.
+ *
+ * @return HashSet The newly generated set.
+ *
+ * @throws XmlPullParserException
+ * @throws java.io.IOException
+ *
+ * @see #readSetXml
+ */
+ public static final HashSet readThisSetXml(XmlPullParser parser, String endTag, String[] name)
+ throws XmlPullParserException, java.io.IOException {
+ HashSet set = new HashSet();
+
+ int eventType = parser.getEventType();
+ do {
+ if (eventType == parser.START_TAG) {
+ Object val = readThisValueXml(parser, name);
+ set.add(val);
+ //System.out.println("Adding to set: " + val);
+ } else if (eventType == parser.END_TAG) {
+ if (parser.getName().equals(endTag)) {
+ return set;
+ }
+ throw new XmlPullParserException(
+ "Expected " + endTag + " end tag at: " + parser.getName());
+ }
+ eventType = parser.next();
+ } while (eventType != parser.END_DOCUMENT);
+
+ throw new XmlPullParserException(
+ "Document ended before " + endTag + " end tag");
+ }
/**
* Read an int[] object from an XmlPullParser. The XML data could
@@ -740,6 +828,12 @@
name[0] = valueName;
//System.out.println("Returning value for " + valueName + ": " + res);
return res;
+ } else if (tagName.equals("set")) {
+ parser.next();
+ res = readThisSetXml(parser, "set", name);
+ name[0] = valueName;
+ //System.out.println("Returning value for " + valueName + ": " + res);
+ return res;
} else {
throw new XmlPullParserException(
"Unknown tag: " + tagName);
diff --git a/core/java/com/android/internal/view/menu/ActionMenu.java b/core/java/com/android/internal/view/menu/ActionMenu.java
new file mode 100644
index 0000000..3d44ebc
--- /dev/null
+++ b/core/java/com/android/internal/view/menu/ActionMenu.java
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.view.menu;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.SubMenu;
+
+/**
+ * @hide
+ */
+public class ActionMenu implements Menu {
+ private Context mContext;
+
+ private boolean mIsQwerty;
+
+ private ArrayList<ActionMenuItem> mItems;
+
+ public ActionMenu(Context context) {
+ mContext = context;
+ mItems = new ArrayList<ActionMenuItem>();
+ }
+
+ public Context getContext() {
+ return mContext;
+ }
+
+ public MenuItem add(CharSequence title) {
+ return add(0, 0, 0, title);
+ }
+
+ public MenuItem add(int titleRes) {
+ return add(0, 0, 0, titleRes);
+ }
+
+ public MenuItem add(int groupId, int itemId, int order, int titleRes) {
+ return add(groupId, itemId, order, mContext.getResources().getString(titleRes));
+ }
+
+ public MenuItem add(int groupId, int itemId, int order, CharSequence title) {
+ ActionMenuItem item = new ActionMenuItem(getContext(),
+ groupId, itemId, 0, order, title);
+ mItems.add(order, item);
+ return item;
+ }
+
+ public int addIntentOptions(int groupId, int itemId, int order,
+ ComponentName caller, Intent[] specifics, Intent intent, int flags,
+ MenuItem[] outSpecificItems) {
+ PackageManager pm = mContext.getPackageManager();
+ final List<ResolveInfo> lri =
+ pm.queryIntentActivityOptions(caller, specifics, intent, 0);
+ final int N = lri != null ? lri.size() : 0;
+
+ if ((flags & FLAG_APPEND_TO_GROUP) == 0) {
+ removeGroup(groupId);
+ }
+
+ for (int i=0; i<N; i++) {
+ final ResolveInfo ri = lri.get(i);
+ Intent rintent = new Intent(
+ ri.specificIndex < 0 ? intent : specifics[ri.specificIndex]);
+ rintent.setComponent(new ComponentName(
+ ri.activityInfo.applicationInfo.packageName,
+ ri.activityInfo.name));
+ final MenuItem item = add(groupId, itemId, order, ri.loadLabel(pm))
+ .setIcon(ri.loadIcon(pm))
+ .setIntent(rintent);
+ if (outSpecificItems != null && ri.specificIndex >= 0) {
+ outSpecificItems[ri.specificIndex] = item;
+ }
+ }
+
+ return N;
+ }
+
+ public SubMenu addSubMenu(CharSequence title) {
+ // TODO Implement submenus
+ return null;
+ }
+
+ public SubMenu addSubMenu(int titleRes) {
+ // TODO Implement submenus
+ return null;
+ }
+
+ public SubMenu addSubMenu(int groupId, int itemId, int order,
+ CharSequence title) {
+ // TODO Implement submenus
+ return null;
+ }
+
+ public SubMenu addSubMenu(int groupId, int itemId, int order, int titleRes) {
+ // TODO Implement submenus
+ return null;
+ }
+
+ public void clear() {
+ mItems.clear();
+ }
+
+ public void close() {
+ }
+
+ private int findItemIndex(int id) {
+ final ArrayList<ActionMenuItem> items = mItems;
+ final int itemCount = items.size();
+ for (int i = 0; i < itemCount; i++) {
+ if (items.get(i).getItemId() == id) {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ public MenuItem findItem(int id) {
+ return mItems.get(findItemIndex(id));
+ }
+
+ public MenuItem getItem(int index) {
+ return mItems.get(index);
+ }
+
+ public boolean hasVisibleItems() {
+ final ArrayList<ActionMenuItem> items = mItems;
+ final int itemCount = items.size();
+
+ for (int i = 0; i < itemCount; i++) {
+ if (items.get(i).isVisible()) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private ActionMenuItem findItemWithShortcut(int keyCode, KeyEvent event) {
+ // TODO Make this smarter.
+ final boolean qwerty = mIsQwerty;
+ final ArrayList<ActionMenuItem> items = mItems;
+ final int itemCount = items.size();
+
+ for (int i = 0; i < itemCount; i++) {
+ ActionMenuItem item = items.get(i);
+ final char shortcut = qwerty ? item.getAlphabeticShortcut() :
+ item.getNumericShortcut();
+ if (keyCode == shortcut) {
+ return item;
+ }
+ }
+ return null;
+ }
+
+ public boolean isShortcutKey(int keyCode, KeyEvent event) {
+ return findItemWithShortcut(keyCode, event) != null;
+ }
+
+ public boolean performIdentifierAction(int id, int flags) {
+ final int index = findItemIndex(id);
+ if (index < 0) {
+ return false;
+ }
+
+ return mItems.get(index).invoke();
+ }
+
+ public boolean performShortcut(int keyCode, KeyEvent event, int flags) {
+ ActionMenuItem item = findItemWithShortcut(keyCode, event);
+ if (item == null) {
+ return false;
+ }
+
+ return item.invoke();
+ }
+
+ public void removeGroup(int groupId) {
+ final ArrayList<ActionMenuItem> items = mItems;
+ int itemCount = items.size();
+ int i = 0;
+ while (i < itemCount) {
+ if (items.get(i).getGroupId() == groupId) {
+ items.remove(i);
+ itemCount--;
+ } else {
+ i++;
+ }
+ }
+ }
+
+ public void removeItem(int id) {
+ mItems.remove(findItemIndex(id));
+ }
+
+ public void setGroupCheckable(int group, boolean checkable,
+ boolean exclusive) {
+ final ArrayList<ActionMenuItem> items = mItems;
+ final int itemCount = items.size();
+
+ for (int i = 0; i < itemCount; i++) {
+ ActionMenuItem item = items.get(i);
+ if (item.getGroupId() == group) {
+ item.setCheckable(checkable);
+ item.setExclusiveCheckable(exclusive);
+ }
+ }
+ }
+
+ public void setGroupEnabled(int group, boolean enabled) {
+ final ArrayList<ActionMenuItem> items = mItems;
+ final int itemCount = items.size();
+
+ for (int i = 0; i < itemCount; i++) {
+ ActionMenuItem item = items.get(i);
+ if (item.getGroupId() == group) {
+ item.setEnabled(enabled);
+ }
+ }
+ }
+
+ public void setGroupVisible(int group, boolean visible) {
+ final ArrayList<ActionMenuItem> items = mItems;
+ final int itemCount = items.size();
+
+ for (int i = 0; i < itemCount; i++) {
+ ActionMenuItem item = items.get(i);
+ if (item.getGroupId() == group) {
+ item.setVisible(visible);
+ }
+ }
+ }
+
+ public void setQwertyMode(boolean isQwerty) {
+ mIsQwerty = isQwerty;
+ }
+
+ public int size() {
+ return mItems.size();
+ }
+}
diff --git a/core/java/com/android/internal/view/menu/ActionMenuItem.java b/core/java/com/android/internal/view/menu/ActionMenuItem.java
new file mode 100644
index 0000000..47d5fb9
--- /dev/null
+++ b/core/java/com/android/internal/view/menu/ActionMenuItem.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.view.menu;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.view.MenuItem;
+import android.view.SubMenu;
+import android.view.ContextMenu.ContextMenuInfo;
+
+/**
+ * @hide
+ */
+public class ActionMenuItem implements MenuItem {
+ private final int mId;
+ private final int mGroup;
+ private final int mCategoryOrder;
+ private final int mOrdering;
+
+ private CharSequence mTitle;
+ private CharSequence mTitleCondensed;
+ private Intent mIntent;
+ private char mShortcutNumericChar;
+ private char mShortcutAlphabeticChar;
+
+ private Drawable mIconDrawable;
+ private int mIconResId = NO_ICON;
+
+ private Context mContext;
+
+ private MenuItem.OnMenuItemClickListener mClickListener;
+
+ private static final int NO_ICON = 0;
+
+ private int mFlags = ENABLED;
+ private static final int CHECKABLE = 0x00000001;
+ private static final int CHECKED = 0x00000002;
+ private static final int EXCLUSIVE = 0x00000004;
+ private static final int HIDDEN = 0x00000008;
+ private static final int ENABLED = 0x00000010;
+
+ public ActionMenuItem(Context context, int group, int id, int categoryOrder, int ordering,
+ CharSequence title) {
+ mContext = context;
+ mId = id;
+ mGroup = group;
+ mCategoryOrder = categoryOrder;
+ mOrdering = ordering;
+ mTitle = title;
+ }
+
+ public char getAlphabeticShortcut() {
+ return mShortcutAlphabeticChar;
+ }
+
+ public int getGroupId() {
+ return mGroup;
+ }
+
+ public Drawable getIcon() {
+ return mIconDrawable;
+ }
+
+ public Intent getIntent() {
+ return mIntent;
+ }
+
+ public int getItemId() {
+ return mId;
+ }
+
+ public ContextMenuInfo getMenuInfo() {
+ return null;
+ }
+
+ public char getNumericShortcut() {
+ return mShortcutNumericChar;
+ }
+
+ public int getOrder() {
+ return mOrdering;
+ }
+
+ public SubMenu getSubMenu() {
+ return null;
+ }
+
+ public CharSequence getTitle() {
+ return mTitle;
+ }
+
+ public CharSequence getTitleCondensed() {
+ return mTitleCondensed;
+ }
+
+ public boolean hasSubMenu() {
+ return false;
+ }
+
+ public boolean isCheckable() {
+ return (mFlags & CHECKABLE) != 0;
+ }
+
+ public boolean isChecked() {
+ return (mFlags & CHECKED) != 0;
+ }
+
+ public boolean isEnabled() {
+ return (mFlags & ENABLED) != 0;
+ }
+
+ public boolean isVisible() {
+ return (mFlags & HIDDEN) == 0;
+ }
+
+ public MenuItem setAlphabeticShortcut(char alphaChar) {
+ mShortcutAlphabeticChar = alphaChar;
+ return this;
+ }
+
+ public MenuItem setCheckable(boolean checkable) {
+ mFlags = (mFlags & ~CHECKABLE) | (checkable ? CHECKABLE : 0);
+ return this;
+ }
+
+ public ActionMenuItem setExclusiveCheckable(boolean exclusive) {
+ mFlags = (mFlags & ~EXCLUSIVE) | (exclusive ? EXCLUSIVE : 0);
+ return this;
+ }
+
+ public MenuItem setChecked(boolean checked) {
+ mFlags = (mFlags & ~CHECKED) | (checked ? CHECKED : 0);
+ return this;
+ }
+
+ public MenuItem setEnabled(boolean enabled) {
+ mFlags = (mFlags & ~ENABLED) | (enabled ? ENABLED : 0);
+ return this;
+ }
+
+ public MenuItem setIcon(Drawable icon) {
+ mIconDrawable = icon;
+ mIconResId = NO_ICON;
+ return this;
+ }
+
+ public MenuItem setIcon(int iconRes) {
+ mIconResId = iconRes;
+ mIconDrawable = mContext.getResources().getDrawable(iconRes);
+ return this;
+ }
+
+ public MenuItem setIntent(Intent intent) {
+ mIntent = intent;
+ return this;
+ }
+
+ public MenuItem setNumericShortcut(char numericChar) {
+ mShortcutNumericChar = numericChar;
+ return this;
+ }
+
+ public MenuItem setOnMenuItemClickListener(OnMenuItemClickListener menuItemClickListener) {
+ mClickListener = menuItemClickListener;
+ return this;
+ }
+
+ public MenuItem setShortcut(char numericChar, char alphaChar) {
+ mShortcutNumericChar = numericChar;
+ mShortcutAlphabeticChar = alphaChar;
+ return this;
+ }
+
+ public MenuItem setTitle(CharSequence title) {
+ mTitle = title;
+ return this;
+ }
+
+ public MenuItem setTitle(int title) {
+ mTitle = mContext.getResources().getString(title);
+ return this;
+ }
+
+ public MenuItem setTitleCondensed(CharSequence title) {
+ mTitleCondensed = title;
+ return this;
+ }
+
+ public MenuItem setVisible(boolean visible) {
+ mFlags = (mFlags & HIDDEN) | (visible ? 0 : HIDDEN);
+ return this;
+ }
+
+ public boolean invoke() {
+ if (mClickListener != null && mClickListener.onMenuItemClick(this)) {
+ return true;
+ }
+
+ if (mIntent != null) {
+ mContext.startActivity(mIntent);
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/core/java/com/android/internal/widget/ContactHeaderWidget.java b/core/java/com/android/internal/widget/ContactHeaderWidget.java
index f421466..a514089 100644
--- a/core/java/com/android/internal/widget/ContactHeaderWidget.java
+++ b/core/java/com/android/internal/widget/ContactHeaderWidget.java
@@ -55,7 +55,7 @@
/**
* Header used across system for displaying a title bar with contact info. You
* can bind specific values on the header, or use helper methods like
- * {@link #bindFromContactId(long)} to populate asynchronously.
+ * {@link #bindFromContactLookupUri(Uri)} to populate asynchronously.
* <p>
* The parent must request the {@link Manifest.permission#READ_CONTACTS}
* permission to access contact data.
@@ -257,7 +257,7 @@
if (photoBitmap == null) {
photoBitmap = loadPlaceholderPhoto(null);
}
- mPhotoView.setImageBitmap(photoBitmap);
+ setPhoto(photoBitmap);
if (cookie != null && cookie instanceof Uri) {
mPhotoView.assignContactUri((Uri) cookie);
}
@@ -267,21 +267,13 @@
case TOKEN_CONTACT_INFO: {
if (cursor != null && cursor.moveToFirst()) {
bindContactInfo(cursor);
- Uri lookupUri = Contacts.getLookupUri(cursor.getLong(ContactQuery._ID),
+ final Uri lookupUri = Contacts.getLookupUri(
+ cursor.getLong(ContactQuery._ID),
cursor.getString(ContactQuery.LOOKUP_KEY));
final long photoId = cursor.getLong(ContactQuery.PHOTO_ID);
- if (photoId == 0) {
- mPhotoView.setImageBitmap(loadPlaceholderPhoto(null));
- if (cookie != null && cookie instanceof Uri) {
- mPhotoView.assignContactUri((Uri) cookie);
- }
- invalidate();
- } else {
- startPhotoQuery(photoId, lookupUri,
- false /* don't reset query handler */);
- }
+ setPhotoId(photoId, lookupUri);
} else {
// shouldn't really happen
setDisplayName(null, null);
@@ -361,18 +353,40 @@
}
/**
- * Manually set the contact uri
+ * Manually set the presence. If presence is null, it is hidden.
+ * This doesn't change the underlying {@link Contacts} value, only the UI state.
+ * @hide
+ */
+ public void setPresence(Integer presence) {
+ if (presence == null) {
+ showPresence(false);
+ } else {
+ showPresence(true);
+ setPresence(presence.intValue());
+ }
+ }
+
+ /**
+ * Turn on/off showing the presence.
+ * @hide this is here for consistency with setStared/showStar and should be public
+ */
+ public void showPresence(boolean showPresence) {
+ mPresenceView.setVisibility(showPresence ? View.VISIBLE : View.GONE);
+ }
+
+ /**
+ * Manually set the contact uri without loading any data
*/
public void setContactUri(Uri uri) {
setContactUri(uri, true);
}
/**
- * Manually set the contact uri
+ * Manually set the contact uri without loading any data
*/
- public void setContactUri(Uri uri, boolean sendToFastrack) {
+ public void setContactUri(Uri uri, boolean sendToQuickContact) {
mContactUri = uri;
- if (sendToFastrack) {
+ if (sendToQuickContact) {
mPhotoView.assignContactUri(uri);
}
}
@@ -386,6 +400,22 @@
}
/**
+ * Manually set the photo given its id. If the id is 0, a placeholder picture will
+ * be loaded. For any other Id, an async query is started
+ * @hide
+ */
+ public void setPhotoId(final long photoId, final Uri lookupUri) {
+ if (photoId == 0) {
+ setPhoto(loadPlaceholderPhoto(null));
+ mPhotoView.assignContactUri(lookupUri);
+ invalidate();
+ } else {
+ startPhotoQuery(photoId, lookupUri,
+ false /* don't reset query handler */);
+ }
+ }
+
+ /**
* Manually set the display name and phonetic name to show in the header.
* This doesn't change the underlying {@link Contacts}, only the UI state.
*/
@@ -400,7 +430,8 @@
}
/**
- * Manually set the social snippet text to display in the header.
+ * Manually set the social snippet text to display in the header. This doesn't change the
+ * underlying {@link Contacts}, only the UI state.
*/
public void setSocialSnippet(CharSequence snippet) {
if (snippet == null) {
@@ -413,6 +444,20 @@
}
/**
+ * Manually set the status attribution text to display in the header.
+ * This doesn't change the underlying {@link Contacts}, only the UI state.
+ * @hide
+ */
+ public void setStatusAttribution(CharSequence attribution) {
+ if (attribution != null) {
+ mStatusAttributionView.setText(attribution);
+ mStatusAttributionView.setVisibility(View.VISIBLE);
+ } else {
+ mStatusAttributionView.setVisibility(View.GONE);
+ }
+ }
+
+ /**
* Set a list of specific MIME-types to exclude and not display. For
* example, this can be used to hide the {@link Contacts#CONTENT_ITEM_TYPE}
* profile icon.
@@ -423,6 +468,88 @@
}
/**
+ * Manually set all the status values to display in the header.
+ * This doesn't change the underlying {@link Contacts}, only the UI state.
+ * @hide
+ * @param status The status of the contact. If this is either null or empty,
+ * the status is cleared and the other parameters are ignored.
+ * @param statusTimestamp The timestamp (retrieved via a call to
+ * {@link System#currentTimeMillis()}) of the last status update.
+ * This value can be null if it is not known.
+ * @param statusLabel The id of a resource string that specifies the current
+ * status. This value can be null if no Label should be used.
+ * @param statusResPackage The name of the resource package containing the resource string
+ * referenced in the parameter statusLabel.
+ */
+ public void setStatus(final String status, final Long statusTimestamp,
+ final Integer statusLabel, final String statusResPackage) {
+ if (TextUtils.isEmpty(status)) {
+ setSocialSnippet(null);
+ return;
+ }
+
+ setSocialSnippet(status);
+
+ final CharSequence timestampDisplayValue;
+
+ if (statusTimestamp != null) {
+ // Set the date/time field by mixing relative and absolute
+ // times.
+ int flags = DateUtils.FORMAT_ABBREV_RELATIVE;
+
+ timestampDisplayValue = DateUtils.getRelativeTimeSpanString(
+ statusTimestamp.longValue(), System.currentTimeMillis(),
+ DateUtils.MINUTE_IN_MILLIS, flags);
+ } else {
+ timestampDisplayValue = null;
+ }
+
+
+ String labelDisplayValue = null;
+
+ if (statusLabel != null) {
+ Resources resources;
+ if (TextUtils.isEmpty(statusResPackage)) {
+ resources = getResources();
+ } else {
+ PackageManager pm = getContext().getPackageManager();
+ try {
+ resources = pm.getResourcesForApplication(statusResPackage);
+ } catch (NameNotFoundException e) {
+ Log.w(TAG, "Contact status update resource package not found: "
+ + statusResPackage);
+ resources = null;
+ }
+ }
+
+ if (resources != null) {
+ try {
+ labelDisplayValue = resources.getString(statusLabel.intValue());
+ } catch (NotFoundException e) {
+ Log.w(TAG, "Contact status update resource not found: " + statusResPackage + "@"
+ + statusLabel.intValue());
+ }
+ }
+ }
+
+ final CharSequence attribution;
+ if (timestampDisplayValue != null && labelDisplayValue != null) {
+ attribution = getContext().getString(
+ R.string.contact_status_update_attribution_with_date,
+ timestampDisplayValue, labelDisplayValue);
+ } else if (timestampDisplayValue == null && labelDisplayValue != null) {
+ attribution = getContext().getString(
+ R.string.contact_status_update_attribution,
+ labelDisplayValue);
+ } else if (timestampDisplayValue != null) {
+ attribution = timestampDisplayValue;
+ } else {
+ attribution = null;
+ }
+ setStatusAttribution(attribution);
+ }
+
+ /**
* Convenience method for binding all available data from an existing
* contact.
*
@@ -543,89 +670,28 @@
this.setDisplayName(displayName, phoneticName);
final boolean starred = c.getInt(ContactQuery.STARRED) != 0;
- mStarredView.setChecked(starred);
+ setStared(starred);
//Set the presence status
if (!c.isNull(ContactQuery.CONTACT_PRESENCE_STATUS)) {
int presence = c.getInt(ContactQuery.CONTACT_PRESENCE_STATUS);
- mPresenceView.setImageResource(StatusUpdates.getPresenceIconResourceId(presence));
- mPresenceView.setVisibility(View.VISIBLE);
+ setPresence(presence);
+ showPresence(true);
} else {
- mPresenceView.setVisibility(View.GONE);
+ showPresence(false);
}
//Set the status update
- String status = c.getString(ContactQuery.CONTACT_STATUS);
- if (!TextUtils.isEmpty(status)) {
- mStatusView.setText(status);
- mStatusView.setVisibility(View.VISIBLE);
+ final String status = c.getString(ContactQuery.CONTACT_STATUS);
+ final Long statusTimestamp = c.isNull(ContactQuery.CONTACT_STATUS_TIMESTAMP)
+ ? null
+ : c.getLong(ContactQuery.CONTACT_STATUS_TIMESTAMP);
+ final Integer statusLabel = c.isNull(ContactQuery.CONTACT_STATUS_LABEL)
+ ? null
+ : c.getInt(ContactQuery.CONTACT_STATUS_LABEL);
+ final String statusResPackage = c.getString(ContactQuery.CONTACT_STATUS_RES_PACKAGE);
- CharSequence timestamp = null;
-
- if (!c.isNull(ContactQuery.CONTACT_STATUS_TIMESTAMP)) {
- long date = c.getLong(ContactQuery.CONTACT_STATUS_TIMESTAMP);
-
- // Set the date/time field by mixing relative and absolute
- // times.
- int flags = DateUtils.FORMAT_ABBREV_RELATIVE;
-
- timestamp = DateUtils.getRelativeTimeSpanString(date,
- System.currentTimeMillis(), DateUtils.MINUTE_IN_MILLIS, flags);
- }
-
- String label = null;
-
- if (!c.isNull(ContactQuery.CONTACT_STATUS_LABEL)) {
- String resPackage = c.getString(ContactQuery.CONTACT_STATUS_RES_PACKAGE);
- int labelResource = c.getInt(ContactQuery.CONTACT_STATUS_LABEL);
- Resources resources;
- if (TextUtils.isEmpty(resPackage)) {
- resources = getResources();
- } else {
- PackageManager pm = getContext().getPackageManager();
- try {
- resources = pm.getResourcesForApplication(resPackage);
- } catch (NameNotFoundException e) {
- Log.w(TAG, "Contact status update resource package not found: "
- + resPackage);
- resources = null;
- }
- }
-
- if (resources != null) {
- try {
- label = resources.getString(labelResource);
- } catch (NotFoundException e) {
- Log.w(TAG, "Contact status update resource not found: " + resPackage + "@"
- + labelResource);
- }
- }
- }
-
- CharSequence attribution;
- if (timestamp != null && label != null) {
- attribution = getContext().getString(
- R.string.contact_status_update_attribution_with_date,
- timestamp, label);
- } else if (timestamp == null && label != null) {
- attribution = getContext().getString(
- R.string.contact_status_update_attribution,
- label);
- } else if (timestamp != null) {
- attribution = timestamp;
- } else {
- attribution = null;
- }
- if (attribution != null) {
- mStatusAttributionView.setText(attribution);
- mStatusAttributionView.setVisibility(View.VISIBLE);
- } else {
- mStatusAttributionView.setVisibility(View.GONE);
- }
- } else {
- mStatusView.setVisibility(View.GONE);
- mStatusAttributionView.setVisibility(View.GONE);
- }
+ setStatus(status, statusTimestamp, statusLabel, statusResPackage);
}
public void onClick(View view) {
diff --git a/core/java/com/android/internal/widget/DigitalClock.java b/core/java/com/android/internal/widget/DigitalClock.java
index fa47ff6..23e2277 100644
--- a/core/java/com/android/internal/widget/DigitalClock.java
+++ b/core/java/com/android/internal/widget/DigitalClock.java
@@ -30,7 +30,7 @@
import android.text.format.DateFormat;
import android.util.AttributeSet;
import android.view.View;
-import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
import android.widget.TextView;
import java.text.DateFormatSymbols;
@@ -39,7 +39,7 @@
/**
* Displays the time
*/
-public class DigitalClock extends LinearLayout {
+public class DigitalClock extends RelativeLayout {
private final static String M12 = "h:mm";
private final static String M24 = "kk:mm";
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index dbbd286..0b62a67 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -92,6 +92,8 @@
public final static String PASSWORD_TYPE_KEY = "lockscreen.password_type";
private final static String LOCK_PASSWORD_SALT_KEY = "lockscreen.password_salt";
+ private final static String PASSWORD_HISTORY_KEY = "lockscreen.passwordhistory";
+
private final Context mContext;
private final ContentResolver mContentResolver;
private DevicePolicyManager mDevicePolicyManager;
@@ -138,6 +140,33 @@
return getDevicePolicyManager().getPasswordQuality(null);
}
+ public int getRequestedPasswordHistoryLength() {
+ return getDevicePolicyManager().getPasswordHistoryLength(null);
+ }
+
+ public int getRequestedPasswordMinimumLetters() {
+ return getDevicePolicyManager().getPasswordMinimumLetters(null);
+ }
+
+ public int getRequestedPasswordMinimumUpperCase() {
+ return getDevicePolicyManager().getPasswordMinimumUpperCase(null);
+ }
+
+ public int getRequestedPasswordMinimumLowerCase() {
+ return getDevicePolicyManager().getPasswordMinimumLowerCase(null);
+ }
+
+ public int getRequestedPasswordMinimumNumeric() {
+ return getDevicePolicyManager().getPasswordMinimumNumeric(null);
+ }
+
+ public int getRequestedPasswordMinimumSymbols() {
+ return getDevicePolicyManager().getPasswordMinimumSymbols(null);
+ }
+
+ public int getRequestedPasswordMinimumNonLetter() {
+ return getDevicePolicyManager().getPasswordMinimumNonLetter(null);
+ }
/**
* Returns the actual password mode, as set by keyguard after updating the password.
*
@@ -202,8 +231,36 @@
}
/**
- * Checks to see if the given file exists and contains any data. Returns true if it does,
- * false otherwise.
+ * Check to see if a password matches any of the passwords stored in the
+ * password history.
+ *
+ * @param password The password to check.
+ * @return Whether the password matches any in the history.
+ */
+ public boolean checkPasswordHistory(String password) {
+ String passwordHashString = new String(passwordToHash(password));
+ String passwordHistory = getString(PASSWORD_HISTORY_KEY);
+ if (passwordHistory == null) {
+ return false;
+ }
+ // Password History may be too long...
+ int passwordHashLength = passwordHashString.length();
+ int passwordHistoryLength = getRequestedPasswordHistoryLength();
+ if(passwordHistoryLength == 0) {
+ return false;
+ }
+ int neededPasswordHistoryLength = passwordHashLength * passwordHistoryLength
+ + passwordHistoryLength - 1;
+ if (passwordHistory.length() > neededPasswordHistoryLength) {
+ passwordHistory = passwordHistory.substring(0, neededPasswordHistoryLength);
+ }
+ return passwordHistory.contains(passwordHashString);
+ }
+
+ /**
+ * Checks to see if the given file exists and contains any data. Returns
+ * true if it does, false otherwise.
+ *
* @param filename
* @return true if file exists and is non-empty.
*/
@@ -274,6 +331,11 @@
activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
}
break;
+ case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
+ if (isLockPasswordEnabled()) {
+ activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
+ }
+ break;
}
return activePasswordQuality;
}
@@ -282,8 +344,6 @@
* Clear any lock pattern or password.
*/
public void clearLock() {
- getDevicePolicyManager().setActivePasswordState(
- DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0);
saveLockPassword(null, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
setLockPatternEnabled(false);
saveLockPattern(null);
@@ -296,7 +356,7 @@
*/
public void saveLockPattern(List<LockPatternView.Cell> pattern) {
// Compute the hash
- final byte[] hash = LockPatternUtils.patternToHash(pattern);
+ final byte[] hash = LockPatternUtils.patternToHash(pattern);
try {
// Write the hash to file
RandomAccessFile raf = new RandomAccessFile(sLockPatternFilename, "rw");
@@ -311,14 +371,15 @@
if (pattern != null) {
setBoolean(PATTERN_EVER_CHOSEN_KEY, true);
setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
- dpm.setActivePasswordState(
- DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, pattern.size());
+ dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, pattern
+ .size(), 0, 0, 0, 0, 0, 0);
} else {
- dpm.setActivePasswordState(
- DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0);
+ dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0,
+ 0, 0, 0, 0, 0);
}
} catch (FileNotFoundException fnfe) {
- // Cant do much, unless we want to fail over to using the settings provider
+ // Cant do much, unless we want to fail over to using the settings
+ // provider
Log.e(TAG, "Unable to save lock pattern to " + sLockPatternFilename);
} catch (IOException ioe) {
// Cant do much
@@ -376,17 +437,59 @@
DevicePolicyManager dpm = getDevicePolicyManager();
if (password != null) {
int computedQuality = computePasswordQuality(password);
- setLong(PASSWORD_TYPE_KEY, computedQuality);
+ setLong(PASSWORD_TYPE_KEY, Math.max(quality, computedQuality));
if (computedQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
- dpm.setActivePasswordState(computedQuality, password.length());
+ int letters = 0;
+ int uppercase = 0;
+ int lowercase = 0;
+ int numbers = 0;
+ int symbols = 0;
+ int nonletter = 0;
+ for (int i = 0; i < password.length(); i++) {
+ char c = password.charAt(i);
+ if (c >= 'A' && c <= 'Z') {
+ letters++;
+ uppercase++;
+ } else if (c >= 'a' && c <= 'z') {
+ letters++;
+ lowercase++;
+ } else if (c >= '0' && c <= '9') {
+ numbers++;
+ nonletter++;
+ } else {
+ symbols++;
+ nonletter++;
+ }
+ }
+ dpm.setActivePasswordState(Math.max(quality, computedQuality), password
+ .length(), letters, uppercase, lowercase, numbers, symbols, nonletter);
} else {
// The password is not anything.
dpm.setActivePasswordState(
- DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0);
+ DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0);
}
+ // Add the password to the password history. We assume all
+ // password
+ // hashes have the same length for simplicity of implementation.
+ String passwordHistory = getString(PASSWORD_HISTORY_KEY);
+ if (passwordHistory == null) {
+ passwordHistory = new String();
+ }
+ int passwordHistoryLength = getRequestedPasswordHistoryLength();
+ if (passwordHistoryLength == 0) {
+ passwordHistory = "";
+ } else {
+ passwordHistory = new String(hash) + "," + passwordHistory;
+ // Cut it to contain passwordHistoryLength hashes
+ // and passwordHistoryLength -1 commas.
+ passwordHistory = passwordHistory.substring(0, Math.min(hash.length
+ * passwordHistoryLength + passwordHistoryLength - 1, passwordHistory
+ .length()));
+ }
+ setString(PASSWORD_HISTORY_KEY, passwordHistory);
} else {
dpm.setActivePasswordState(
- DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0);
+ DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0);
}
} catch (FileNotFoundException fnfe) {
// Cant do much, unless we want to fail over to using the settings provider
@@ -526,7 +629,8 @@
return savedPasswordExists() &&
(mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
|| mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
- || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC);
+ || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
+ || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX);
}
/**
@@ -650,12 +754,21 @@
android.provider.Settings.Secure.putLong(mContentResolver, secureSettingKey, value);
}
+ private String getString(String secureSettingKey) {
+ return android.provider.Settings.Secure.getString(mContentResolver, secureSettingKey);
+ }
+
+ private void setString(String secureSettingKey, String value) {
+ android.provider.Settings.Secure.putString(mContentResolver, secureSettingKey, value);
+ }
+
public boolean isSecure() {
long mode = getKeyguardStoredPasswordQuality();
final boolean isPattern = mode == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
final boolean isPassword = mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
|| mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
- || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
+ || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
+ || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
final boolean secure = isPattern && isLockPatternEnabled() && savedPatternExists()
|| isPassword && savedPasswordExists();
return secure;
diff --git a/core/java/com/android/internal/widget/SlidingTab.java b/core/java/com/android/internal/widget/SlidingTab.java
index 9152729..3218ba8 100644
--- a/core/java/com/android/internal/widget/SlidingTab.java
+++ b/core/java/com/android/internal/widget/SlidingTab.java
@@ -17,10 +17,8 @@
package com.android.internal.widget;
import android.content.Context;
-import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
-import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Vibrator;
@@ -38,6 +36,7 @@
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.ImageView.ScaleType;
+
import com.android.internal.R;
/**
@@ -69,21 +68,21 @@
private int mGrabbedState = OnTriggerListener.NO_HANDLE;
private boolean mTriggered = false;
private Vibrator mVibrator;
- private float mDensity; // used to scale dimensions for bitmaps.
+ private final float mDensity; // used to scale dimensions for bitmaps.
/**
* Either {@link #HORIZONTAL} or {@link #VERTICAL}.
*/
- private int mOrientation;
+ private final int mOrientation;
- private Slider mLeftSlider;
- private Slider mRightSlider;
+ private final Slider mLeftSlider;
+ private final Slider mRightSlider;
private Slider mCurrentSlider;
private boolean mTracking;
private float mThreshold;
private Slider mOtherSlider;
private boolean mAnimating;
- private Rect mTmpRect;
+ private final Rect mTmpRect;
/**
* Listener used to reset the view when the current animation completes.
@@ -608,14 +607,7 @@
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
- mTracking = false;
- mTriggered = false;
- mOtherSlider.show(true);
- mCurrentSlider.reset(false);
- mCurrentSlider.hideTarget();
- mCurrentSlider = null;
- mOtherSlider = null;
- setGrabbedState(OnTriggerListener.NO_HANDLE);
+ cancelGrab();
break;
}
}
@@ -623,6 +615,17 @@
return mTracking || super.onTouchEvent(event);
}
+ private void cancelGrab() {
+ mTracking = false;
+ mTriggered = false;
+ mOtherSlider.show(true);
+ mCurrentSlider.reset(false);
+ mCurrentSlider.hideTarget();
+ mCurrentSlider = null;
+ mOtherSlider = null;
+ setGrabbedState(OnTriggerListener.NO_HANDLE);
+ }
+
void startAnimating(final boolean holdAfter) {
mAnimating = true;
final Animation trans1;
@@ -832,6 +835,17 @@
}
}
+ @Override
+ protected void onVisibilityChanged(View changedView, int visibility) {
+ super.onVisibilityChanged(changedView, visibility);
+ // When visibility changes and the user has a tab selected, unselect it and
+ // make sure their callback gets called.
+ if (changedView == this && visibility != VISIBLE
+ && mGrabbedState != OnTriggerListener.NO_HANDLE) {
+ cancelGrab();
+ }
+ }
+
/**
* Sets the current grabbed state, and dispatches a grabbed state change
* event to our listener.
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index d4545d7..03989fd 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -24,7 +24,6 @@
LOCAL_SRC_FILES:= \
ActivityManager.cpp \
AndroidRuntime.cpp \
- CursorWindow.cpp \
Time.cpp \
com_google_android_gles_jni_EGLImpl.cpp \
com_google_android_gles_jni_GLImpl.cpp.arm \
@@ -107,6 +106,8 @@
android_media_AudioSystem.cpp \
android_media_AudioTrack.cpp \
android_media_JetPlayer.cpp \
+ android_media_MtpClient.cpp \
+ android_media_MtpCursor.cpp \
android_media_ToneGenerator.cpp \
android_hardware_Camera.cpp \
android_hardware_SensorManager.cpp \
@@ -140,6 +141,7 @@
$(call include-path-for, libhardware_legacy)/hardware_legacy \
$(LOCAL_PATH)/../../include/ui \
$(LOCAL_PATH)/../../include/utils \
+ $(LOCAL_PATH)/../../media/mtp \
external/skia/include/core \
external/skia/include/effects \
external/skia/include/images \
@@ -185,6 +187,8 @@
libwpa_client \
libjpeg
+LOCAL_STATIC_LIBRARIES := libmtphost libusbhost
+
ifeq ($(BOARD_HAVE_BLUETOOTH),true)
LOCAL_C_INCLUDES += \
external/dbus \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index f66ed83..8bf693d 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -124,6 +124,8 @@
extern int register_android_database_SQLiteQuery(JNIEnv* env);
extern int register_android_database_SQLiteStatement(JNIEnv* env);
extern int register_android_debug_JNITest(JNIEnv* env);
+extern int register_android_media_MtpClient(JNIEnv *env);
+extern int register_android_media_MtpCursor(JNIEnv *env);
extern int register_android_nio_utils(JNIEnv* env);
extern int register_android_pim_EventRecurrence(JNIEnv* env);
extern int register_android_text_format_Time(JNIEnv* env);
@@ -1269,6 +1271,8 @@
REG_JNI(register_android_media_AudioSystem),
REG_JNI(register_android_media_AudioTrack),
REG_JNI(register_android_media_JetPlayer),
+ REG_JNI(register_android_media_MtpClient),
+ REG_JNI(register_android_media_MtpCursor),
REG_JNI(register_android_media_ToneGenerator),
REG_JNI(register_android_opengl_classes),
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index e1e9536..4c7e762 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -30,6 +30,8 @@
#include "SkBoundaryPatch.h"
#include "SkMeshUtils.h"
+#include "unicode/ubidi.h"
+
#define TIME_DRAWx
static uint32_t get_thread_msec() {
@@ -52,6 +54,24 @@
class SkCanvasGlue {
public:
+ enum {
+ kDirection_LTR = 0,
+ kDirection_RTL = 1
+ };
+
+ enum {
+ kDirection_Mask = 0x1
+ };
+
+ enum {
+ kBidi_LTR = 0,
+ kBidi_RTL = 1,
+ kBidi_Default_LTR = 2,
+ kBidi_Default_RTL = 3,
+ kBidi_Force_LTR = 4,
+ kBidi_Force_RTL = 5
+ };
+
static void finalizer(JNIEnv* env, jobject clazz, SkCanvas* canvas) {
canvas->unref();
}
@@ -743,45 +763,206 @@
canvas->drawVertices(mode, ptCount, verts, texs, colors, NULL,
indices, indexCount, *paint);
}
-
- static void drawText___CIIFFPaint(JNIEnv* env, jobject, SkCanvas* canvas,
- jcharArray text, int index, int count,
- jfloat x, jfloat y, SkPaint* paint) {
- jchar* textArray = env->GetCharArrayElements(text, NULL);
- jsize textCount = env->GetArrayLength(text);
+
+ static void shapeRtlText__(const jchar* text, jsize len, jsize start, jsize count, jchar* shaped) {
+ // fake shaping, just reverse the text
+ for (int i = 0; i < count; ++i) {
+ shaped[i] = text[start + count - 1 - i];
+ }
+ // fix surrogate pairs, if any
+ for (int i = 1; i < count; ++i) {
+ if (shaped[i] >= 0xd800 && shaped[i] < 0xdc00 &&
+ shaped[i-1] >= 0xdc00 && shaped[i-1] < 0xe000) {
+ jchar c = shaped[i]; shaped[i] = shaped[i-1]; shaped[i-1] = c;
+ i += 1;
+ }
+ }
+ }
+
+ static void drawText__(JNIEnv* env, SkCanvas* canvas, const jchar* text, jsize len,
+ jfloat x, jfloat y, int flags, SkPaint* paint) {
SkScalar x_ = SkFloatToScalar(x);
SkScalar y_ = SkFloatToScalar(y);
- canvas->drawText(textArray + index, count << 1, x_, y_, *paint);
- env->ReleaseCharArrayElements(text, textArray, 0);
+
+ SkPaint::Align horiz = paint->getTextAlign();
+
+ bool needBidi = (flags == kBidi_RTL) || (flags == kBidi_Default_RTL);
+ if (!needBidi && flags < kBidi_Force_LTR) {
+ for (int i = 0; i < len; ++i) {
+ if (text[i] >= 0x0590) {
+ needBidi = TRUE;
+ break;
+ }
+ }
+ }
+
+ int dir = (flags == kBidi_Force_RTL) ? kDirection_RTL : kDirection_LTR; // will be reset if we run bidi
+ UErrorCode status = U_ZERO_ERROR;
+ jchar *shaped = NULL;
+ int32_t slen = 0;
+ if (needBidi || (flags == kBidi_Force_RTL)) {
+ shaped = (jchar *)malloc(len * sizeof(jchar));
+ if (!shaped) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ } else {
+ if (needBidi) {
+ static int RTL_OPTS = UBIDI_DO_MIRRORING | UBIDI_KEEP_BASE_COMBINING |
+ UBIDI_REMOVE_BIDI_CONTROLS | UBIDI_OUTPUT_REVERSE;
+ jint lineDir = 0;
+ switch (flags) {
+ case kBidi_LTR: lineDir = 0; break; // no ICU constant, canonical LTR level
+ case kBidi_RTL: lineDir = 1; break; // no ICU constant, canonical RTL level
+ case kBidi_Default_LTR: lineDir = UBIDI_DEFAULT_LTR; break;
+ case kBidi_Default_RTL: lineDir = UBIDI_DEFAULT_RTL; break;
+ }
+
+ UBiDi* bidi = ubidi_open();
+ ubidi_setPara(bidi, text, len, lineDir, NULL, &status);
+ if (U_SUCCESS(status)) {
+ dir = ubidi_getParaLevel(bidi) & 0x1;
+
+ int rc = ubidi_countRuns(bidi, &status);
+ if (U_SUCCESS(status)) {
+ int32_t start;
+ int32_t length;
+ UBiDiDirection dir;
+ jchar *buffer = NULL;
+ for (int i = 0; i < rc; ++i) {
+ dir = ubidi_getVisualRun(bidi, i, &start, &length);
+ // fake shaping, except it doesn't shape, just mirrors and reverses
+ // use harfbuzz when available
+ if (dir == UBIDI_RTL) {
+ slen += ubidi_writeReverse(text + start, length, shaped + slen,
+ length, RTL_OPTS, &status);
+ } else {
+ for (int i = 0; i < length; ++i) {
+ shaped[slen + i] = text[start + i];
+ }
+ slen += length;
+ }
+ }
+ }
+ ubidi_close(bidi);
+ }
+ } else {
+ shapeRtlText__(text, len, 0, len, shaped);
+ }
+ }
+ }
+
+ if (!U_SUCCESS(status)) {
+ char buffer[35];
+ sprintf(buffer, "DrawText bidi error %d", status);
+ doThrowIAE(env, buffer);
+ } else {
+ bool trimLeft = false;
+ bool trimRight = false;
+
+ switch (horiz) {
+ case SkPaint::kLeft_Align: trimLeft = dir & kDirection_Mask; break;
+ case SkPaint::kCenter_Align: trimLeft = trimRight = true; break;
+ case SkPaint::kRight_Align: trimRight = !(dir & kDirection_Mask);
+ default: break;
+ }
+ const jchar* workText = shaped ? shaped : text;
+ const jchar* workLimit = workText + len;
+
+ if (trimLeft) {
+ while (workText < workLimit && *workText == ' ') {
+ ++workText;
+ }
+ }
+ if (trimRight) {
+ while (workLimit > workText && *(workLimit - 1) == ' ') {
+ --workLimit;
+ }
+ }
+ int32_t workBytes = (workLimit - workText) << 1;
+
+ canvas->drawText(workText, workBytes, x_, y_, *paint);
+ }
+
+ if (shaped) {
+ free(shaped);
+ }
+ }
+
+ static void drawText___CIIFFIPaint(JNIEnv* env, jobject, SkCanvas* canvas,
+ jcharArray text, int index, int count,
+ jfloat x, jfloat y, int flags, SkPaint* paint) {
+ jchar* textArray = env->GetCharArrayElements(text, NULL);
+ drawText__(env, canvas, textArray + index, count, x, y, flags, paint);
+ env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
}
- static void drawText__StringIIFFPaint(JNIEnv* env, jobject,
- SkCanvas* canvas, jstring text, int start, int end,
- jfloat x, jfloat y, SkPaint* paint) {
- const void* text_ = env->GetStringChars(text, NULL);
+ static void drawText__StringIIFFIPaint(JNIEnv* env, jobject,
+ SkCanvas* canvas, jstring text,
+ int start, int end,
+ jfloat x, jfloat y, int flags, SkPaint* paint) {
+ const jchar* textArray = env->GetStringChars(text, NULL);
+ drawText__(env, canvas, textArray + start, end - start, x, y, flags, paint);
+ env->ReleaseStringChars(text, textArray);
+ }
+
+ // Draws a unidirectional run of text. Does not run bidi, but does reorder the
+ // text and run shaping (or will, when we have harfbuzz support).
+ static void drawTextRun__(JNIEnv* env, SkCanvas* canvas, const jchar* chars, int len,
+ int start, int count,
+ jfloat x, jfloat y, int flags, SkPaint* paint) {
+
SkScalar x_ = SkFloatToScalar(x);
SkScalar y_ = SkFloatToScalar(y);
- canvas->drawText((const uint16_t*)text_ + start, (end - start) << 1,
- x_, y_, *paint);
- env->ReleaseStringChars(text, (const jchar*) text_);
- }
-
- static void drawString(JNIEnv* env, jobject canvas, jstring text,
- jfloat x, jfloat y, jobject paint) {
- NPE_CHECK_RETURN_VOID(env, canvas);
- NPE_CHECK_RETURN_VOID(env, paint);
- NPE_CHECK_RETURN_VOID(env, text);
- size_t count = env->GetStringLength(text);
- if (0 == count) {
- return;
+
+ uint8_t rtl = flags & 0x1;
+
+ UErrorCode status = U_ZERO_ERROR;
+ jchar *shaped = NULL;
+ if (rtl) {
+ shaped = (jchar *)malloc(count * sizeof(jchar));
+ if (!shaped) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ } else {
+ shapeRtlText__(chars, len, start, count, shaped);
+ }
}
- const jchar* text_ = env->GetStringChars(text, NULL);
- SkCanvas* c = GraphicsJNI::getNativeCanvas(env, canvas);
- c->drawText(text_, count << 1, SkFloatToScalar(x), SkFloatToScalar(y),
- *GraphicsJNI::getNativePaint(env, paint));
- env->ReleaseStringChars(text, text_);
+
+ if (!U_SUCCESS(status)) {
+ char buffer[30];
+ sprintf(buffer, "DrawTextRun error %d", status);
+ doThrowIAE(env, buffer);
+ } else {
+ if (shaped) {
+ canvas->drawText(shaped, count << 1, x_, y_, *paint);
+ } else {
+ canvas->drawText(chars + start, count << 1, x_, y_, *paint);
+ }
+ }
+
+ if (shaped) {
+ free(shaped);
+ }
}
-
+
+ static void drawTextRun___CIIFFIPaint(
+ JNIEnv* env, jobject, SkCanvas* canvas, jcharArray text, int index,
+ int count, jfloat x, jfloat y, int flags, SkPaint* paint) {
+
+ jint len = env->GetArrayLength(text);
+ jchar* chars = env->GetCharArrayElements(text, NULL);
+ drawTextRun__(env, canvas, chars, len, index, count, x, y, flags, paint);
+ env->ReleaseCharArrayElements(text, chars, JNI_ABORT);
+ }
+
+ static void drawTextRun__StringIIFFIPaint(
+ JNIEnv* env, jobject obj, SkCanvas* canvas, jstring text, int start,
+ int end, jfloat x, jfloat y, int flags, SkPaint* paint) {
+
+ jint len = env->GetStringLength(text);
+ const jchar* chars = env->GetStringChars(text, NULL);
+ drawTextRun__(env, canvas, chars, len, start, end - start, x, y, flags, paint);
+ env->ReleaseStringChars(text, chars);
+ }
+
static void drawPosText___CII_FPaint(JNIEnv* env, jobject, SkCanvas* canvas,
jcharArray text, int index, int count,
jfloatArray pos, SkPaint* paint) {
@@ -947,12 +1128,14 @@
(void*)SkCanvasGlue::drawBitmapMesh},
{"nativeDrawVertices", "(III[FI[FI[II[SIII)V",
(void*)SkCanvasGlue::drawVertices},
- {"native_drawText","(I[CIIFFI)V",
- (void*) SkCanvasGlue::drawText___CIIFFPaint},
- {"native_drawText","(ILjava/lang/String;IIFFI)V",
- (void*) SkCanvasGlue::drawText__StringIIFFPaint},
- {"drawText","(Ljava/lang/String;FFLandroid/graphics/Paint;)V",
- (void*) SkCanvasGlue::drawString},
+ {"native_drawText","(I[CIIFFII)V",
+ (void*) SkCanvasGlue::drawText___CIIFFIPaint},
+ {"native_drawText","(ILjava/lang/String;IIFFII)V",
+ (void*) SkCanvasGlue::drawText__StringIIFFIPaint},
+ {"native_drawTextRun","(I[CIIFFII)V",
+ (void*) SkCanvasGlue::drawTextRun___CIIFFIPaint},
+ {"native_drawTextRun","(ILjava/lang/String;IIFFII)V",
+ (void*) SkCanvasGlue::drawTextRun__StringIIFFIPaint},
{"native_drawPosText","(I[CII[FI)V",
(void*) SkCanvasGlue::drawPosText___CII_FPaint},
{"native_drawPosText","(ILjava/lang/String;[FI)V",
diff --git a/core/jni/android_database_CursorWindow.cpp b/core/jni/android_database_CursorWindow.cpp
index 91449bc..55f5252 100644
--- a/core/jni/android_database_CursorWindow.cpp
+++ b/core/jni/android_database_CursorWindow.cpp
@@ -29,7 +29,7 @@
#include <string.h>
#include <unistd.h>
-#include "CursorWindow.h"
+#include "binder/CursorWindow.h"
#include "sqlite3_exception.h"
#include "android_util_Binder.h"
@@ -652,6 +652,22 @@
window->freeLastRow();
}
+static jint getType_native(JNIEnv* env, jobject object, jint row, jint column)
+{
+ int32_t err;
+ CursorWindow * window = GET_WINDOW(env, object);
+ LOG_WINDOW("returning column type affinity for %d,%d from %p", row, column, window);
+
+ field_slot_t field;
+ err = window->read_field_slot(row, column, &field);
+ if (err != 0) {
+ throwExceptionWithRowCol(env, row, column);
+ return NULL;
+ }
+
+ return field.type;
+}
+
static JNINativeMethod sMethods[] =
{
/* name, signature, funcPtr */
@@ -679,6 +695,7 @@
{"isString_native", "(II)Z", (void *)isString_native},
{"isFloat_native", "(II)Z", (void *)isFloat_native},
{"isInteger_native", "(II)Z", (void *)isInteger_native},
+ {"getType_native", "(II)I", (void *)getType_native},
};
int register_android_database_CursorWindow(JNIEnv * env)
diff --git a/core/jni/android_database_SQLiteCompiledSql.cpp b/core/jni/android_database_SQLiteCompiledSql.cpp
index 8d1c39e..de4c5c8 100644
--- a/core/jni/android_database_SQLiteCompiledSql.cpp
+++ b/core/jni/android_database_SQLiteCompiledSql.cpp
@@ -91,22 +91,11 @@
compile(env, object, GET_HANDLE(env, object), sqlString);
}
-static void native_finalize(JNIEnv* env, jobject object)
-{
- int err;
- sqlite3_stmt * statement = GET_STATEMENT(env, object);
-
- if (statement != NULL) {
- sqlite3_finalize(statement);
- env->SetIntField(object, gStatementField, 0);
- }
-}
static JNINativeMethod sMethods[] =
{
/* name, signature, funcPtr */
{"native_compile", "(Ljava/lang/String;)V", (void *)native_compile},
- {"native_finalize", "()V", (void *)native_finalize},
};
int register_android_database_SQLiteCompiledSql(JNIEnv * env)
diff --git a/core/jni/android_database_SQLiteDatabase.cpp b/core/jni/android_database_SQLiteDatabase.cpp
index 36234a9..0c50c54 100644
--- a/core/jni/android_database_SQLiteDatabase.cpp
+++ b/core/jni/android_database_SQLiteDatabase.cpp
@@ -443,6 +443,13 @@
return sqlite3_release_memory(SQLITE_SOFT_HEAP_LIMIT);
}
+static void native_finalize(JNIEnv* env, jobject object, jint statementId)
+{
+ if (statementId > 0) {
+ sqlite3_finalize((sqlite3_stmt *)statementId);
+ }
+}
+
static JNINativeMethod sMethods[] =
{
/* name, signature, funcPtr */
@@ -456,6 +463,7 @@
{"native_setLocale", "(Ljava/lang/String;I)V", (void *)native_setLocale},
{"native_getDbLookaside", "()I", (void *)native_getDbLookaside},
{"releaseMemory", "()I", (void *)native_releaseMemory},
+ {"native_finalize", "(I)V", (void *)native_finalize},
};
int register_android_database_SQLiteDatabase(JNIEnv *env)
diff --git a/core/jni/android_database_SQLiteQuery.cpp b/core/jni/android_database_SQLiteQuery.cpp
index 44271683..747ee50 100644
--- a/core/jni/android_database_SQLiteQuery.cpp
+++ b/core/jni/android_database_SQLiteQuery.cpp
@@ -29,7 +29,7 @@
#include <string.h>
#include <unistd.h>
-#include "CursorWindow.h"
+#include "binder/CursorWindow.h"
#include "sqlite3_exception.h"
diff --git a/core/jni/android_database_SQLiteStatement.cpp b/core/jni/android_database_SQLiteStatement.cpp
index ff2ed5d..0341e0b 100644
--- a/core/jni/android_database_SQLiteStatement.cpp
+++ b/core/jni/android_database_SQLiteStatement.cpp
@@ -58,7 +58,9 @@
err = sqlite3_step(statement);
// Throw an exception if an error occured
- if (err != SQLITE_DONE) {
+ if (err == SQLITE_ROW) {
+ LOGV("Queries cannot be performed using execute(). use SQLiteDatabase.query() instead.");
+ } else if (err != SQLITE_DONE) {
throw_sqlite3_exception_errcode(env, err, sqlite3_errmsg(handle));
}
diff --git a/core/jni/android_media_MtpClient.cpp b/core/jni/android_media_MtpClient.cpp
new file mode 100644
index 0000000..0c04255
--- /dev/null
+++ b/core/jni/android_media_MtpClient.cpp
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "MtpClientJNI"
+#include "utils/Log.h"
+
+#include <stdio.h>
+#include <assert.h>
+#include <limits.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <utils/threads.h>
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+
+#include "MtpClient.h"
+#include "MtpDevice.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+static jmethodID method_deviceAdded;
+static jmethodID method_deviceRemoved;
+static jfieldID field_context;
+
+class MyClient : public MtpClient {
+private:
+
+ enum {
+ kDeviceAdded = 1,
+ kDeviceRemoved,
+ };
+
+ virtual void deviceAdded(MtpDevice *device);
+ virtual void deviceRemoved(MtpDevice *device);
+
+ bool reportDeviceAdded(JNIEnv *env, MtpDevice *device);
+ bool reportDeviceRemoved(JNIEnv *env, MtpDevice *device);
+
+ JNIEnv* mEnv;
+ jobject mClient;
+ Mutex mEventLock;
+ Condition mEventCondition;
+ Mutex mAckLock;
+ Condition mAckCondition;
+ int mEvent;
+ MtpDevice* mEventDevice;
+
+public:
+ MyClient(JNIEnv *env, jobject client);
+ virtual ~MyClient();
+ void waitForEvent(JNIEnv *env);
+
+};
+
+MtpClient* get_client_from_object(JNIEnv* env, jobject javaClient)
+{
+ return (MtpClient*)env->GetIntField(javaClient, field_context);
+}
+
+
+MyClient::MyClient(JNIEnv *env, jobject client)
+ : mEnv(env),
+ mClient(env->NewGlobalRef(client)),
+ mEvent(0),
+ mEventDevice(NULL)
+{
+}
+
+MyClient::~MyClient() {
+ mEnv->DeleteGlobalRef(mClient);
+}
+
+
+void MyClient::deviceAdded(MtpDevice *device) {
+ LOGD("MyClient::deviceAdded\n");
+ mAckLock.lock();
+ mEventLock.lock();
+ mEvent = kDeviceAdded;
+ mEventDevice = device;
+ mEventCondition.signal();
+ mEventLock.unlock();
+ mAckCondition.wait(mAckLock);
+ mAckLock.unlock();
+}
+
+void MyClient::deviceRemoved(MtpDevice *device) {
+ LOGD("MyClient::deviceRemoved\n");
+ mAckLock.lock();
+ mEventLock.lock();
+ mEvent = kDeviceRemoved;
+ mEventDevice = device;
+ mEventCondition.signal();
+ mEventLock.unlock();
+ mAckCondition.wait(mAckLock);
+ mAckLock.unlock();
+}
+
+bool MyClient::reportDeviceAdded(JNIEnv *env, MtpDevice *device) {
+ const char* name = device->getDeviceName();
+ LOGD("MyClient::reportDeviceAdded %s\n", name);
+
+ env->CallVoidMethod(mClient, method_deviceAdded, device->getID());
+
+ return (!env->ExceptionCheck());
+}
+
+bool MyClient::reportDeviceRemoved(JNIEnv *env, MtpDevice *device) {
+ const char* name = device->getDeviceName();
+ LOGD("MyClient::reportDeviceRemoved %s\n", name);
+
+ env->CallVoidMethod(mClient, method_deviceRemoved, device->getID());
+
+ return (!env->ExceptionCheck());
+}
+
+void MyClient::waitForEvent(JNIEnv *env) {
+ mEventLock.lock();
+ mEventCondition.wait(mEventLock);
+ mEventLock.unlock();
+
+ switch (mEvent) {
+ case kDeviceAdded:
+ reportDeviceAdded(env, mEventDevice);
+ break;
+ case kDeviceRemoved:
+ reportDeviceRemoved(env, mEventDevice);
+ break;
+ }
+
+ mAckLock.lock();
+ mAckCondition.signal();
+ mAckLock.unlock();
+}
+
+
+// ----------------------------------------------------------------------------
+
+static bool ExceptionCheck(void* env)
+{
+ return ((JNIEnv *)env)->ExceptionCheck();
+}
+
+static void
+android_media_MtpClient_setup(JNIEnv *env, jobject thiz)
+{
+ LOGD("setup\n");
+ MyClient* client = new MyClient(env, thiz);
+ client->start();
+ env->SetIntField(thiz, field_context, (int)client);
+}
+
+static void
+android_media_MtpClient_finalize(JNIEnv *env, jobject thiz)
+{
+ LOGD("finalize\n");
+ MyClient *client = (MyClient *)env->GetIntField(thiz, field_context);
+ delete client;
+}
+
+static void
+android_media_MtpClient_wait_for_event(JNIEnv *env, jobject thiz)
+{
+ LOGD("wait_for_event\n");
+ MyClient *client = (MyClient *)env->GetIntField(thiz, field_context);
+ client->waitForEvent(env);
+}
+
+// ----------------------------------------------------------------------------
+
+static JNINativeMethod gMethods[] = {
+ {"native_setup", "()V", (void *)android_media_MtpClient_setup},
+ {"native_finalize", "()V", (void *)android_media_MtpClient_finalize},
+ {"native_wait_for_event", "()V", (void *)android_media_MtpClient_wait_for_event},
+
+};
+
+static const char* const kClassPathName = "android/media/MtpClient";
+
+int register_android_media_MtpClient(JNIEnv *env)
+{
+ jclass clazz;
+
+ LOGD("register_android_media_MtpClient\n");
+
+ clazz = env->FindClass("android/media/MtpClient");
+ if (clazz == NULL) {
+ LOGE("Can't find android/media/MtpClient");
+ return -1;
+ }
+ method_deviceAdded = env->GetMethodID(clazz, "deviceAdded", "(I)V");
+ if (method_deviceAdded == NULL) {
+ LOGE("Can't find deviceAdded");
+ return -1;
+ }
+ method_deviceRemoved = env->GetMethodID(clazz, "deviceRemoved", "(I)V");
+ if (method_deviceRemoved == NULL) {
+ LOGE("Can't find deviceRemoved");
+ return -1;
+ }
+ field_context = env->GetFieldID(clazz, "mNativeContext", "I");
+ if (field_context == NULL) {
+ LOGE("Can't find MtpClient.mNativeContext");
+ return -1;
+ }
+
+ return AndroidRuntime::registerNativeMethods(env,
+ "android/media/MtpClient", gMethods, NELEM(gMethods));
+}
+
+} // namespace android
diff --git a/core/jni/android_media_MtpCursor.cpp b/core/jni/android_media_MtpCursor.cpp
new file mode 100644
index 0000000..7b0b7b7
--- /dev/null
+++ b/core/jni/android_media_MtpCursor.cpp
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "MtpCursorJNI"
+#include "utils/Log.h"
+
+#include <stdio.h>
+#include <assert.h>
+#include <limits.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+#include "binder/CursorWindow.h"
+
+#include "MtpClient.h"
+#include "MtpCursor.h"
+
+namespace android {
+
+static jfieldID field_context;
+
+// From android_database_CursorWindow.cpp
+CursorWindow * get_window_from_object(JNIEnv * env, jobject javaWindow);
+
+// From android_media_MtpClient.cpp
+MtpClient * get_client_from_object(JNIEnv * env, jobject javaClient);
+
+// ----------------------------------------------------------------------------
+
+static bool ExceptionCheck(void* env)
+{
+ return ((JNIEnv *)env)->ExceptionCheck();
+}
+
+static void
+android_media_MtpCursor_setup(JNIEnv *env, jobject thiz, jobject javaClient,
+ jint queryType, jint deviceID, jint storageID, jint objectID, jintArray javaColumns)
+{
+ LOGD("android_media_MtpCursor_setup queryType: %d deviceID: %d storageID: %d objectID: %d\n",
+ queryType, deviceID, storageID, objectID);
+
+ int* columns = NULL;
+ int columnCount = 0;
+ if (javaColumns) {
+ columns = env->GetIntArrayElements(javaColumns, 0);
+ columnCount = env->GetArrayLength(javaColumns);
+ }
+
+ MtpClient* client = get_client_from_object(env, javaClient);
+ MtpCursor* cursor = new MtpCursor(client, queryType,
+ deviceID, storageID, objectID, columnCount, columns);
+
+ if (columns)
+ env->ReleaseIntArrayElements(javaColumns, columns, 0);
+ env->SetIntField(thiz, field_context, (int)cursor);
+}
+
+static void
+android_media_MtpCursor_finalize(JNIEnv *env, jobject thiz)
+{
+ LOGD("finalize\n");
+ MtpCursor *cursor = (MtpCursor *)env->GetIntField(thiz, field_context);
+ delete cursor;
+}
+
+static jint
+android_media_MtpCursor_fill_window(JNIEnv *env, jobject thiz, jobject javaWindow, jint startPos)
+{
+ CursorWindow* window = get_window_from_object(env, javaWindow);
+ if (!window) {
+ LOGE("Invalid CursorWindow");
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "Bad CursorWindow");
+ return 0;
+ }
+ MtpCursor *cursor = (MtpCursor *)env->GetIntField(thiz, field_context);
+
+ return cursor->fillWindow(window, startPos);
+}
+
+// ----------------------------------------------------------------------------
+
+static JNINativeMethod gMethods[] = {
+ {"native_setup", "(Landroid/media/MtpClient;IIII[I)V",
+ (void *)android_media_MtpCursor_setup},
+ {"native_finalize", "()V", (void *)android_media_MtpCursor_finalize},
+ {"native_fill_window", "(Landroid/database/CursorWindow;I)I",
+ (void *)android_media_MtpCursor_fill_window},
+
+};
+
+static const char* const kClassPathName = "android/media/MtpCursor";
+
+int register_android_media_MtpCursor(JNIEnv *env)
+{
+ jclass clazz;
+
+ LOGD("register_android_media_MtpCursor\n");
+
+ clazz = env->FindClass("android/media/MtpCursor");
+ if (clazz == NULL) {
+ LOGE("Can't find android/media/MtpCursor");
+ return -1;
+ }
+ field_context = env->GetFieldID(clazz, "mNativeContext", "I");
+ if (field_context == NULL) {
+ LOGE("Can't find MtpCursor.mNativeContext");
+ return -1;
+ }
+
+ return AndroidRuntime::registerNativeMethods(env,
+ "android/media/MtpCursor", gMethods, NELEM(gMethods));
+}
+
+} // namespace android
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 1fcf186..4aff76f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -436,6 +436,14 @@
android:label="@string/permlab_flashlight"
android:description="@string/permdesc_flashlight" />
+ <!-- Allows an application to access USB devices
+ @hide -->
+ <permission android:name="android.permission.ACCESS_USB"
+ android:permissionGroup="android.permission-group.HARDWARE_CONTROLS"
+ android:protectionLevel="signatureOrSystem"
+ android:label="@string/permlab_accessUsb"
+ android:description="@string/permdesc_accessUsb" />
+
<!-- Allows access to hardware peripherals. Intended only for hardware testing -->
<permission android:name="android.permission.HARDWARE_TEST"
android:permissionGroup="android.permission-group.HARDWARE_CONTROLS"
diff --git a/core/res/assets/images/combobox-disabled.png b/core/res/assets/images/combobox-disabled.png
deleted file mode 100644
index fe220e4..0000000
--- a/core/res/assets/images/combobox-disabled.png
+++ /dev/null
Binary files differ
diff --git a/core/res/assets/images/combobox-noHighlight.png b/core/res/assets/images/combobox-noHighlight.png
deleted file mode 100644
index abcdf72..0000000
--- a/core/res/assets/images/combobox-noHighlight.png
+++ /dev/null
Binary files differ
diff --git a/core/res/assets/webkit/hyph_en_US.dic b/core/res/assets/webkit/hyph_en_US.dic
new file mode 100644
index 0000000..d91204b
--- /dev/null
+++ b/core/res/assets/webkit/hyph_en_US.dic
@@ -0,0 +1,9784 @@
+ISO8859-1
+LEFTHYPHENMIN 2
+RIGHTHYPHENMIN 3
+.a2ch4
+.ad4der
+.a2d
+.ad1d4
+.a2f1t
+.a2f
+.a4l3t
+.am5at
+.4a1ma
+.an5c
+.a2n
+.2ang4
+.an1i5m
+.an1t4
+.an3te
+.anti5s
+.ant2i
+.a4r5s2
+.2a2r
+.ar4t2ie4
+.ar1ti
+.ar4ty
+.as3c
+.as1p
+.a2s1s
+.aster5
+.a2tom5
+.a1to
+.au1d
+.av4i
+.awn4
+.ba4g
+.ba5na
+.ba2n
+.bas4e
+.ber4
+.be5r1a
+.be3s1m
+.4bes4
+.b4e5s2to
+.bri2
+.but4ti
+.bu4t3t2
+.cam4pe
+.1ca
+.ca4m1p
+.can5c
+.ca2n
+.capa5b
+.ca1pa
+.car5ol
+.c2a2r
+.ca4t
+.ce4la
+.2ch4
+.chill5i
+.ch4il2
+.chil1l
+.1ci2
+.cit5r
+.2c1it
+.co3e2
+.1co
+.co4r
+.cor5n1er
+.corn2e
+.de4moi2
+.d4em
+.de1mo
+.de3o
+.de3r1a
+.de3r1i
+.de1s4c
+.des2
+.dic1t2io5
+.3di2c1t
+.do4t
+.1do
+.du4c
+.1du
+.du4m1b5
+.earth5
+.ear2t
+.e2a2r
+.eas3i
+.2e1b4
+.eer4
+.eg2
+.e2l5d
+.el3em
+.enam3
+.e1na
+.en3g
+.e2n3s2
+.eq5ui5t
+.e1q
+.equ2
+.eq2ui2
+.er4ri
+.er1r4
+.es3
+.4eu3
+.eye5
+.fes3
+.for5mer
+.1fo
+.fo2r
+.for1m
+.for2me
+.1ga2
+.ge2
+.gen3t4
+.1gen
+.ge5o2g
+.1geo
+.1g2i5a
+.gi4b
+.go4r
+.1go
+.hand5i
+.ha2n
+.h4and
+.ha4n5k2
+.he2
+.hero5i2
+.h2ero
+.h1es3
+.he4t3
+.hi3b
+.hi3er
+.h2ie4
+.hon5ey
+.ho2n
+.hon3o
+.hov5
+.id4l
+.2id
+.idol3
+.i1do
+.im3m
+.im5p1i2n
+.i4m1p
+.im2pi
+.in1
+.in3ci
+.2ine2
+.4i4n2k2
+.2i2n3s2
+.ir5r4
+.4ir
+.is4i
+.ju3r
+.la4cy
+.la4m
+.lat5er
+.l4ath5
+.le2
+.leg5e
+.len4
+.lep5
+.lev1
+.l2i4g
+.li1g5a
+.li2n
+.l2i3o
+.l1i4t
+.ma1g5a5
+.1ma
+.mal5o
+.ma1n5a
+.ma2n
+.mar5ti
+.m2a2r
+.me2
+.mer3c
+.me5ter
+.me1te
+.m2is1
+.mis4t5i
+.mon3e
+.1mo
+.mo2n
+.mo3ro
+.mo2r
+.mu5ta
+.1mu
+.mu2ta5b
+.ni4c
+.od2
+.od1d5
+.of5te
+.o2ft
+.or5a1to
+.o1ra
+.or3c
+.or1d
+.or3t
+.os3
+.os4tl
+.4oth3
+.out3
+.ou2
+.ped5al
+.2p2ed
+.p2e2d2a
+.pe5te
+.pe2t
+.pe5tit
+.p2i4e4
+.pio5n4
+.3p2i1o
+.pi2t
+.pre3m
+.pr2
+.ra4c
+.ran4t
+.ra2n
+.ratio5n1a
+.ratio2n4
+.ra1t2io
+.ree2
+.re5mit
+.res2
+.re5stat
+.res2t
+.res1ta
+.r2i4g
+.ri2t5u
+.ro4q
+.ros5t
+.row5d
+.ru4d
+.3s4c2i3e4
+.s1ci
+.5se2l2f5
+.sel1l5
+.se2n
+.se5r2ie4
+.ser1i
+.s2h2
+.si2
+.s3ing4
+.2s1in
+.st4
+.sta5b2l2
+.s1ta
+.s2tab
+.s4y2
+.1ta4
+.te4
+.3ten5a2n
+.te1na
+.th2
+.ti2
+.til4
+.ti1m5o5
+.1tim
+.ting4
+.2t1in
+.t4i4n5k2
+.to1n4a
+.1to
+.to2n
+.to4p
+.top5i
+.to2u5s
+.tou2
+.trib5ut
+.tr4ib
+.u1n1a
+.un3ce
+.under5
+.un1de
+.u2n1e
+.u4n5k2
+.un5o
+.un3u4
+.up3
+.ure3
+.us5a2
+.2us
+.ven4de
+.ve5r1a
+.wil5i
+.wi2
+.wil2
+.ye4
+4ab.
+a5bal
+a5ba2n
+abe2
+ab5erd
+ab2i5a
+ab5i2t5ab
+abi2t
+abi1ta
+ab5lat
+ab2l2
+ab5o5l1iz
+abol2i
+4abr
+ab5rog
+ab3ul
+a4c2a2r
+a1ca
+ac5ard
+ac5aro
+a5ceou2
+ac1er
+a5che4t
+a2ch
+ache2
+4a2ci
+a3c2ie4
+a2c1in
+a3c2io
+ac5rob
+act5if2
+a2c1t
+ac3ul
+ac4um
+a2d
+ad4d1in
+ad1d4
+ad5er.
+2adi
+a3d4i3a
+ad3i1ca
+adi4er
+ad2ie4
+a3d2io
+a3dit
+a5di1u
+ad4le
+ad3ow
+a1do
+ad5ra2n
+a1dr
+ad4su
+a2d1s2
+4a1du
+a3du2c
+ad5um
+ae4r
+aer2i4e4
+aer1i
+a2f
+a4f1f4
+a4gab
+a1ga
+aga4n
+ag5el1l
+a1ge4o
+4ag4eu
+ag1i
+4ag4l2
+ag1n
+a2go
+3a3g4o4g
+ag3o3ni
+ago2n2
+a5guer
+a2gue
+ag5ul
+a4gy
+a3ha
+a3he
+a4h4l4
+a3ho
+ai2
+a5i1a
+a3ic.
+ai5ly
+a4i4n
+ain5in
+a2ini
+a2i1n5o
+ait5en
+a2ite
+a1j
+ak1en
+al5ab
+al3a2d
+a4l2a2r
+4aldi4
+a2ld
+2ale
+al3end
+a4lent2i
+a1len1t
+a5le5o
+al1i
+al4ia.
+al2i1a
+al2i4e4
+al5lev
+al1l
+al2le
+4allic
+all2i
+4a2lm
+a5log.
+a4ly.
+a1ly
+4a2lys4
+5a5lys1t
+5alyt
+3alyz
+4a1ma
+a2m5ab
+am3ag
+ama5ra
+am2a2r
+am5asc
+a4ma3tis
+a4m5a1to
+am5er1a
+am3ic
+am5if
+am5i1ly
+am1in
+am2i4no
+a2mo
+a5mo2n
+amor5i
+amo2r
+amp5en
+a4m1p
+a2n
+an3age
+a1na
+3ana1ly
+a3n2a2r
+an3ar3c
+anar4i
+a3nati
+an2at
+4and
+ande4s2
+an1de
+an3dis1
+an1dl
+an4dow
+an1do
+a5nee
+a3nen
+an5e2st.
+a1nes
+a2nest
+a3n4eu
+2ang
+ang5ie4
+an1gl2
+a4n1ic
+a3nies
+an2ie4
+an3i3f
+an4ime
+an1im
+a5nim1i
+a5n2ine
+an1in
+an3i4o
+a3n2ip
+an3is2h
+an3it
+a3ni1u
+an4kli
+a4nk2
+an1k1l
+5anniz
+a4n1n2
+ano4
+an5ot
+an4oth5
+an2sa2
+a2n1s2
+an4s1co
+ans4c
+an4s1n4
+an2sp
+ans3po
+an4st
+an4su2r
+an1su
+anta2l4
+an1t
+an1ta
+an4t2ie4
+ant2i
+4an1to
+an2tr
+an4tw4
+an3u1a
+an3ul
+a5nur
+4ao
+ap2a2r4
+a1pa
+ap5at
+ap5er3o
+a3ph4er
+4aphi
+a4pilla
+apil1l
+ap5ill2a2r
+ap3i2n
+ap3i1ta
+a3pi2tu
+a2p2l2
+apo4c5
+ap5o1la
+apor5i
+a1p4or
+apos3t
+a1pos
+aps5e4s
+a2p1s2
+ap2se
+a3pu
+aque5
+aqu2
+2a2r
+ar3a2c1t
+a5rade
+ara2d
+ar5adis1
+ar2adi
+ar3al
+a5rame1te
+aram3et
+ar2an4g
+ara2n
+ara3p
+ar4at
+a5ra1t2io
+ar5a1t2iv
+a5rau
+ar5av4
+araw4
+arbal4
+ar1b
+ar4cha2n
+ar1c
+ar3cha
+ar2ch
+ar5d2ine
+ard2i
+ard1in4
+ar4dr
+ar5eas
+a3ree
+ar3en1t
+a5r2e2ss
+ar4fi
+ar1f
+ar4f4l2
+ar1i
+ar5i2al
+ar2i3a
+ar3i2a2n
+a3ri5et
+ar2ie4
+ar4im
+ar5in2at
+ar2i1na
+ar3i1o
+ar2iz
+ar2mi
+ar1m
+ar5o5d
+a5roni
+aro2n
+a3roo2
+ar2p
+ar3q
+arre4
+ar1r4
+ar4sa2
+a4rs2
+ar2s2h
+4as.
+a2s4ab
+asa2
+as3an1t
+asa2n
+ashi4
+as2h
+a5sia.
+as2i1a
+a3si1b
+a3sic
+5a5si4t
+ask3i
+ask2
+as4l2
+a4soc
+a1so
+as5ph
+as4s2h
+a2ss
+as3ten
+as1t4r
+asu1r5a
+a1su
+asu2r
+a2ta
+at3ab2l2
+a2tab
+at5ac
+at3alo
+ata2l
+at5ap
+ate5c
+at5e2ch
+at3e1go
+ateg4
+at3en.
+at3er1a
+ater5n
+a5ter1na
+at3est
+at5ev
+4ath
+ath5em
+ath2e
+a5the2n
+at4ho
+ath5om
+4ati.
+a5t2i1a
+a2t5i5b
+at1ic
+at3if2
+ation5a2r
+a1t2io
+atio2n
+atio1n1a
+at3i1tu
+a4tog
+a1to
+a2tom
+at5om2iz
+a4top
+a4tos2
+a1tr
+at5rop
+at4sk2
+a4t1s2
+at4tag
+a4t3t2
+at1ta
+at5te
+at4th
+a2tu
+at5u1a
+a4t5ue
+at3ul
+at3u1ra
+a2ty
+au4b
+augh3
+au3gu
+au4l2
+aun5d
+au3r
+au5si1b
+a2us
+a4ut5en
+au1th
+a2va
+av3ag4
+a5va2n
+av4e4no
+av3er1a
+av5ern
+av5ery
+av1i
+avi4er
+av2ie4
+av3ig
+av5oc
+a1vor
+3away
+aw3i2
+aw4ly
+aws4
+ax4i5c
+ax3i
+ax4id
+ay5al
+aye4
+ays4
+azi4er
+a2z1i
+az2ie4
+az2z5i
+a4z1z2
+5ba.
+bad5ger
+ba2d
+ba4ge
+bal1a
+ban5dag
+ba2n
+b4and
+ban1d2a
+ban4e
+ban3i
+barbi5
+b2a2r
+bar1b
+bar2i4a
+bar1i
+bas4si
+ba2ss
+1bat
+ba4z
+2b1b
+b2be
+b3ber
+bbi4na
+4b1d
+4be.
+beak4
+bea2t3
+4be2d
+b2e3d2a
+be3de
+b4e3di
+be3gi
+be5gu
+1bel
+be1l2i
+be3lo
+4be5m
+be5n2ig
+be5nu
+4bes4
+be3sp
+b2e5st4r
+3bet
+be1t5iz
+be5tr
+be3tw4
+be3w
+be5y1o4
+2bf
+4b3h
+bi2b
+b2i4d
+3b2ie4
+bi5en
+bi4er
+2b3if
+1bil
+bi3l2iz
+bil1i
+bin2a5r4
+bi1na
+b4in4d
+bi5net
+b2ine
+bi3o2gr
+b2io
+bi5ou2
+bi2t
+3b2i3t2io
+bi1ti
+bi3tr
+3bit5u1a
+bi1tu
+b5i4tz
+b1j
+bk4
+b2l2
+bl4ath5
+b4le.
+blen4
+5ble1sp
+bles2
+b3lis
+b4lo
+blun4t
+4b1m
+4b3n
+bne5g
+3bod
+bod3i
+bo4e
+bol3ic
+bol2i
+bom4bi
+bo4m1b
+bo1n4a
+bo2n
+bon5at
+3boo2
+5bor.
+4b1o1ra
+bor5d
+5bore
+5bori
+5bos4
+b5o1ta
+b4oth5
+bo4to
+boun2d3
+bou2
+4bp
+4brit
+br4oth3
+2b5s2
+bsor4
+b1so
+2bt
+b2t4l
+b4to
+b3tr
+buf4fer1
+bu4f1f
+bu4ga
+bu3l2i
+bu1mi4
+bu4n
+bunt4i
+bun1t
+bu3re
+bus5ie4
+b2us
+buss4e
+bu2ss
+5bust
+4bu1ta
+3bu1t2io
+b4u1t2i
+b5u1to
+b1v
+4b5w
+5by.
+bys4
+1ca
+cab3in
+ca1b2l2
+ca2ch4
+ca5den
+ca2d
+4cag4
+2c5ah
+ca3lat
+cal4la
+cal1l
+cal2l5in4
+call2i
+4calo
+c4an5d
+ca2n
+can4e
+ca4n4ic
+can5is
+can3iz
+can4ty
+can1t
+cany4
+ca5per
+car5om
+c2a2r
+cast5er
+cas5t2ig
+cast2i
+4cas4y
+c4a4th
+4ca1t2iv
+cav5al
+ca2va
+c3c
+ccha5
+c2ch
+c3c2i4a
+c1ci
+ccom1pa5
+c1co
+cco4m1p
+cco2n4
+ccou3t
+ccou2
+2ce.
+4ced.
+4ce1den
+3cei2
+5cel.
+3cel1l
+1cen
+3cenc
+2cen4e
+4ceni
+3cen1t
+3cep
+ce5ram
+cer1a
+4ce1s4a2
+3ces1si
+c2e2ss
+ces5si5b
+ces5t
+cet4
+c5e4ta
+cew4
+2ch
+4ch.
+4ch3ab
+5cha4n1ic
+cha2n
+ch5a5nis
+che2
+cheap3
+4ch4ed
+ch5e5lo
+3chemi
+ch5ene
+che2n
+ch3er.
+ch3e4r1s2
+4ch1in
+5chi2ne.
+ch2ine
+ch5i5n2e2ss
+chi1nes
+5ch2ini
+5ch2io
+3chit
+chi2z
+3cho2
+ch4ti
+1ci
+3c2i1a
+ci2a5b
+ci2a5r
+ci5c
+4cier
+c2ie4
+5c4i2f3ic.
+ci1fi
+4c4i5i4
+ci4la
+3cil1i
+2cim
+2cin
+c4i1na
+3cin2at
+cin3em
+c2ine
+c1ing
+c5ing.
+5c2i1no
+cio2n4
+c2io
+4cipe4
+c2ip
+ci3ph
+4cip4ic
+cip3i
+4cis1ta
+4cis1t2i
+2c1it
+ci1t3iz
+ci1ti
+5ciz
+ck1
+ck3i
+1c4l4
+4cl2a2r
+c5la5ra1t2io
+clar4at
+5clare
+cle4m
+4clic
+clim4
+c1ly4
+c5n
+1co
+co5ag
+c4oa
+coe2
+2cog
+co4gr
+coi4
+co3inc
+col5i
+5colo
+col3o4r
+com5er
+co2me
+co1n4a
+co2n
+c4one
+con3g
+con5t
+co3pa
+cop3ic
+co4p2l2
+4cor1b
+coro3n
+cos4e
+cov1
+cove4
+cow5a
+co2z5e
+co5z1i
+c1q
+cras5t
+cr2as
+5crat.
+5crat1ic
+cre3a2t
+5c2r2ed
+4c3re1ta
+cre4v2
+cri2
+cri5f
+c4rin
+cr2is4
+5cri1ti
+cro4p2l2
+crop5o
+cros4e
+cru4d
+4c3s2
+2c1t
+c2ta4b
+c1ta
+ct5ang
+cta2n
+c5tan1t
+c2te
+c3ter
+c4t4ic1u
+ctim3i
+c1tim
+ctu4r
+c1tu
+c4tw4
+cud5
+c4uf
+c4ui2
+cu5i1ty
+5cul2i
+cul4tis4
+cul1ti
+cu4lt
+3c4ul1tu2
+cu2ma
+c3ume
+cu4mi
+3cun
+cu3pi
+cu5py
+cu2r5a4b
+cu1ra
+cu5r2i3a
+1c2us
+cus1s4i
+cu2ss
+3c4ut
+cu4t2ie4
+c4u1t2i
+4c5u1t2iv
+4cutr
+1cy
+c2ze4
+1d2a
+5da.
+2d3a4b
+da2ch4
+4da2f
+2dag
+da2m2
+d2an3g
+da2n
+dard5
+d2a2r
+dark5
+4dary
+3dat
+4da1t2iv
+4da1to
+5dav4
+dav5e
+5day
+d1b
+d5c
+d1d4
+2de.
+dea2f5
+de4b5i2t
+d2e1b
+de4bo2n
+deca2n4
+de1ca
+de4cil
+de1c2i
+de5com
+de1co
+2d1ed
+4dee.
+de5if
+dei2
+del2i4e4
+del2i
+de4l5i5q
+de5lo
+d4em
+5dem.
+3demic
+dem5ic.
+de5mil
+de4mo2n3s2
+de1mo
+demo2n
+demo2r5
+1den
+de4n2a2r
+de1na
+d4e3no
+denti5f2
+den1t
+dent2i
+de3nu
+de1p
+de3pa
+depi4
+de2pu
+d3e1q
+d4er1h4
+5der3m4
+d5ern5iz
+de4r5s2
+des2
+d2es.
+de1s2c
+de2s5o
+des3t2i
+d2e3st4r
+de4su
+de1t
+de2to
+de1v
+de2v3i4l
+de1vi
+4dey
+4d1f
+d4ga
+d3ge4t
+dg1i
+d2gy
+d1h2
+5di.
+1d4i3a
+dia5b
+d4i4cam
+di1ca
+d4ice
+3di2c1t
+3d2id
+5di3en
+d2ie4
+d1if
+di3ge
+d2ig
+di4la1to
+di1la
+d1in
+1di1na
+3di2ne.
+d2ine
+5d2ini
+di5niz
+1d2io
+dio5g
+di4p2l2
+d2ip
+d4ir2
+di1re
+dir1t5i
+dis1
+5disi
+d4is3t
+d2i1ti
+1d2i1v
+d1j
+d5k2
+4d5la
+3dle.
+3dled
+3dles.
+dles2
+4d3l2e2ss
+2d3lo
+4d5lu
+2d1ly
+d1m
+4d1n4
+1do
+3do.
+do5de
+5doe
+2d5of
+d4og
+do4la
+dol2i4
+do5lo4r
+dom5iz
+do3n2at
+do2n
+do1n1a
+doni4
+doo3d
+doo2
+do4p4p
+d4or
+3dos
+4d5out
+dou2
+do4v
+3dox
+d1p
+1dr
+drag5o2n2
+dra2go
+4dr2ai2
+dre4
+dre2a5r
+5dren
+dr4i4b
+dril4
+dro4p
+4drow
+5drupli
+dru3p2l2
+4dry
+2d1s2
+ds4p
+d4sw2
+d4s4y
+d2th
+1du
+d1u1a
+du2c
+d1u3ca
+duc5er
+4duct.
+du2c1t
+4duc4t1s2
+du5el
+du4g
+d3ul4e
+dum4be
+du4m1b
+du4n
+4dup
+du4pe
+d1v
+d1w
+d2y
+5dyn
+dy4s2e
+dys5p
+e1a4b
+e3a2c1t
+ea2d1
+ead5ie4
+e2adi
+ea4ge
+ea5ger
+ea4l
+eal5er
+e2ale
+eal3ou2
+eam3er
+e5and
+ea2n
+ear3a
+e2a2r
+ear4c
+ear5es
+ear4ic
+ear1i
+ear4il
+ear5k
+ear2t
+eart3e
+ea5sp
+e3a2ss
+east3
+ea2t
+eat5en
+eath3i
+e4ath
+e5at3if2
+e4a3tu
+ea2v
+eav3en
+eav5i
+eav5o
+2e1b
+e4bel.
+e1bel
+e4be2l1s2
+e4ben
+e4bi2t
+e3br
+e4ca2d
+e1ca
+ecan5c
+eca2n
+ec1ca5
+ec3c
+e1ce
+ec5es1sa2
+ec2e2ss
+e1c2i
+e4cib
+ec5ificat
+eci1fi
+ecifi1ca
+ec5i3f2ie4
+ec5i1fy
+e2c3im
+e2c1i4t
+e5c2ite
+e4clam
+e1c4l4
+e4cl2us
+e2col
+e1co
+e4com1m
+e4compe
+eco4m1p
+e4con1c
+eco2n
+e2cor
+ec3o1ra
+eco5ro
+e1cr
+e4crem
+ec4ta2n
+e2c1t
+ec1ta
+ec4te
+e1cu
+e4cul
+ec3u1la
+2e2d2a
+4ed3d4
+e4d1er
+ede4s2
+4edi
+e3d4i3a
+ed3ib
+ed3i1ca
+ed3im
+ed1it
+edi5z
+4e1do
+e4dol
+edo2n2
+e4dri
+e1dr
+e4dul
+e1du
+ed5u1l4o
+ee2c
+e4ed3i
+ee2f
+eel3i
+ee4ly
+ee2m
+ee4na
+ee4p1
+ee2s4
+eest4
+ee4ty
+e5ex
+e1f
+e4f3ere
+efer1
+1e4f1f
+e4fic
+e1fi
+5ef2i1c4i
+efil4
+e3f2i2ne
+e2fin
+ef5i5n2ite
+ef2ini
+efin2it
+3efit
+efor5es
+e1fo
+efo2r
+e4fu4se.
+e3fu
+ef2us
+4egal
+e1ga
+eger4
+eg5ib
+eg4ic
+eg5ing
+e5git5
+eg5n
+e4go.
+e1go
+e4gos
+eg1ul
+e5gur
+5e1gy
+e1h4
+eher4
+ei2
+e5ic
+e2i5d
+e2ig2
+ei5g4l2
+e3i4m1b
+e3in3f
+e1ing
+e5inst
+e2i2n1s2
+eir4d
+e4ir
+e2it3e
+e2i3th
+e5i1ty
+e1j
+e4jud
+ej5udi
+eki4n
+ek1i
+ek4la
+ek1l
+e1la
+e4la.
+e4lac
+e3l4an4d
+ela2n
+e4l5a1t2iv
+e4law
+elax1a4
+e3le2a
+el5ebra
+el2e1b
+ele3br
+5elec
+e4led
+el3e1ga
+e5len
+e4l1er
+e1les2
+e2l2f
+el2i
+e3libe4
+e4l5ic.
+el3i1ca
+e3lier
+el2ie4
+el5i3gib
+el2ig
+el4igi
+e5lim
+e4l3ing
+e3l2io
+e2lis
+el5is2h
+e3l2iv3
+4ella
+el1l
+el4lab
+ell4o4
+e5loc
+el5og
+el3op.
+el2s2h
+e2l1s2
+el4ta
+e4lt
+e5lud
+el5ug
+e4mac
+e1ma
+e4mag
+e5ma2n
+em5a1na
+e4m5b
+e1me
+e2mel
+e4met
+em3i1ca
+em2i4e4
+em5igra
+em2ig4
+emi1gr
+em1in2
+em5ine
+em3i3ni
+e4m2is
+em5is2h
+e5m4i2s1s
+em3iz
+5emniz
+e4m1n
+emo4g
+e1mo
+emo3n2i5o
+emo2n
+em3pi
+e4m1p
+e4mul
+e1mu
+em5u1la
+emu3n2
+e3my
+en5a2mo
+e1na
+e4nan1t
+en2a2n
+ench4er
+en2ch
+enche2
+en3dic
+e5nea
+e5nee
+en3em
+en5ero
+en1er
+en5e1si
+e1nes
+e2n5est
+en3etr
+e3ne4w
+en5i4c3s2
+e5n2ie4
+e5nil
+e3n2i4o
+en3is2h
+en3it
+e5ni1u
+5eniz
+4e4n1n2
+4eno
+e4no4g
+e4nos
+en3ov
+en4sw2
+e2n1s2
+ent5age
+en1t
+en1ta
+4enth1es
+enth2e
+en3u1a
+en5uf
+e3ny.
+4e4n3z
+e5of
+eo2g
+e4oi4
+e3ol
+eop3a2r
+eo2pa
+e1or
+eo3re
+eo5rol
+eos4
+e4ot
+eo4to
+e5out
+eou2
+e5ow
+e2pa
+e3p4ai2
+ep5anc
+epa2n
+e5pel
+e3pen1t
+ep5e5t2i1t2io
+epe2t
+epeti1ti
+ephe4
+e4pli
+e1p2l2
+e1po
+e4prec
+epr2
+ep5re1ca
+e4p2r2ed
+ep3re1h4
+e3pro
+e4prob
+ep4s4h
+e2p1s2
+ep5ti5b
+e2p1t
+e4pu2t
+ep5u1ta
+e1q
+equi3l
+equ2
+eq2ui2
+e4q3ui3s
+er1a
+e2ra4b
+4er4and
+era2n
+er3a2r
+4er4ati.
+2er1b
+er4b2l2
+er3ch
+er1c
+er4che2
+2e2re.
+e3re1a4l
+ere5co
+ere3in
+erei2
+er5el.
+er3e1mo
+er5e1na
+er5ence
+4erene
+er3en1t
+ere4q
+er5e2ss
+er3es2t
+eret4
+er1h4
+er1i
+e1r2i3a4
+5erick1
+e3rien
+er2ie4
+eri4er
+er3in4e
+e1r2i1o
+4erit
+er4i1u
+er2i4v
+e4ri1va
+er3m4
+er4nis4
+4er3n2it
+5erniz
+er3no4
+2ero
+er5ob
+e5r2oc
+ero4r
+er1ou2
+e4r1s2
+er3set
+er2se
+ert3er
+4er2tl
+er3tw4
+4eru
+eru4t
+5erwau
+er1w
+e1s4a2
+e4sa2ge.
+e4sages
+es2c
+e2s1ca
+es5ca2n
+e3scr
+es5cu
+e1s2e
+e2sec
+es5e1cr
+e4s5enc
+e4sert.
+e4ser4t1s2
+e4ser1va
+4es2h
+e3sha
+esh5e2n
+e1si
+e2sic
+e2s2id
+es5i1den
+e4s5ig1n4a
+es2ig
+e2s5im
+e2s4i4n
+esis4te
+e1sis
+e5si4u
+e5skin
+esk2
+esk1i
+es4mi
+e2s1m
+e2sol
+e1so
+es3olu
+e2so2n
+es5o1n1a4
+e1sp
+e2s3per
+es5pi1ra
+esp4ir
+es4pre
+espr2
+2e2ss
+es4si4b
+es1si
+esta2n4
+es1ta
+es3t2ig
+est2i
+es5tim
+4es2to
+e3sto2n
+2est4r
+e5stro
+estruc5
+e2su2r
+e1su
+es5ur1r4
+es4w2
+e2ta4b
+e1ta
+e3ten4d
+e3teo
+ethod3
+et1ic
+e5tide
+et2id
+e2t1in4
+et2i4no
+e5t4ir
+e5t2i1t2io
+eti1ti
+et5i1t2iv
+4e2t1n2
+et5o1n1a
+e1to
+eto2n
+e3tra
+e3tre
+et3ric
+et5rif
+et3rog
+et5ros
+et3u1a
+e1tu
+et5ym
+e1ty
+e4t5z
+4eu
+e5un
+e3up
+eu3ro
+e2us4
+eute4
+euti5l
+e4u1t2i
+eu5tr
+eva2p5
+e1va
+e2vas
+ev5ast
+e5vea
+ev3el1l
+eve4l3o
+e5veng
+even4i
+ev1er
+e5v2er1b
+e1vi
+ev3id
+e2vi4l
+e4v1in
+e3v2i4v
+e5voc
+e5vu
+e1wa
+e4wag
+e5wee
+e3wh
+ewil5
+ewi2
+ew3in4g
+e3wit
+1ex3p
+5ey1c
+5eye.
+eys4
+1fa
+fa3b2l2
+f4ab3r
+fa4ce
+4fag
+fa4i4n4
+fai2
+fal2l5e
+fal1l
+4f4a4ma
+fam5is
+5f2a2r
+far5th
+fa3ta
+fa3th2e
+f4ath
+4fa1to
+fau4lt5
+fau4l2
+4f5b
+4fd
+4fe.
+feas4
+fe4ath3
+fea2t
+f2e4b
+4fe1ca
+5fe2c1t
+2fed
+fe3l2i
+fe4mo
+fen2d
+fen1d5e
+fer1
+5fer1r4
+fev4
+4f1f
+f4fes
+f4f2ie4
+f1fi
+f5f2in.
+f2fin
+f2f5is
+f4f2ly5
+ff4l2
+f2fy
+4fh
+1fi
+f2i3a
+2f3ic.
+4f3ical
+fi1ca
+f3ica2n
+4ficate
+f3i1cen
+fi3cer
+f2i1c4i
+5fi3c2i1a
+5fic2ie4
+4fi4c3s2
+fi3cu
+fi5del
+f2id
+fight5
+f2ig
+fil5i
+fil2l5in4
+fil1l
+fill2i
+4fi1ly
+2fin
+5fi1na
+f4in2d5
+f2i2ne
+f1in3g
+f2i4n4n2
+fis4t2i
+f4l2
+f5l2e2ss
+fles2
+flin4
+flo3re
+f2ly5
+4fm
+4fn
+1fo
+5fo2n
+fon4de
+f2ond
+fon4t
+fo2r
+fo5rat
+fo1ra
+for5ay
+fore5t
+for4i
+for1t5a
+fos5
+4f5p
+fra4t
+f5rea
+fres5c
+fri2
+fril4
+frol5
+2f3s
+2ft
+f4to
+f2ty
+3fu
+fu5el
+4fug
+fu4min
+fu1mi
+fu5ne
+fu3ri
+fusi4
+f2us
+fu2s4s
+4fu1ta
+1fy
+1ga
+ga2f4
+5gal.
+3gal1i
+ga3lo
+2gam
+ga5met
+g5a2mo
+gan5is
+ga2n
+ga3niz
+gani5za1
+4gano4
+gar5n4
+g2a2r
+ga2ss4
+g4ath3
+4ga1t2iv
+4gaz
+g3b
+gd4
+2ge.
+2ged
+geez4
+gel4in
+gel2i
+ge5lis
+ge5l1iz
+4ge1ly
+1gen
+ge4n2at
+ge1na
+g5e5niz
+4g4eno
+4geny
+1geo
+ge3om
+g4ery
+5ge1si
+geth5
+4ge1to
+ge4ty
+ge4v
+4g1g2
+g2ge
+g3ger
+gglu5
+ggl2
+g1go4
+gh3in
+gh5out
+ghou2
+gh4to
+5gi.
+1g2i4a
+gi2a5r
+g1ic
+5gi3c2i1a
+g2i1ci
+g4i1co
+gien5
+g2ie4
+5gies.
+gil4
+g3i1men
+3g4in.
+g4in5ge
+5g4i2n1s2
+5g2io
+3g4ir
+gir4l
+g3is1l2
+gi4u
+5g2iv
+3giz
+gl2
+gla4
+gl2ad5i
+gla2d
+5glas
+1gle
+gli4b
+g3l2ig
+3glo
+glo3r
+g1m
+g4my
+g1n4a
+g4na.
+gne4t4t2
+g1ni
+g2n1in
+g4n2i4o
+g1no
+g4no4n
+1go
+3go.
+gob5
+5goe
+3g4o4g
+go3is
+goi2
+go2n2
+4g3o3n1a
+gon5do5
+g2ond
+go3ni
+5goo2
+go5riz
+gor5ou2
+5gos.
+gov1
+g3p
+1gr
+4gra1d2a
+gra2d
+g4r2ai2
+gra2n2
+5gra4ph.
+g5ra3ph4er
+5graph1ic
+gr4aphi
+4g3ra1phy
+4gray
+gre4n
+4gress.
+gr2e2ss
+4grit
+g4ro
+gruf4
+gs2
+g5ste
+gth3
+gu4a
+3guar2d
+gu2a2r
+2gue
+5gui5t
+g2ui2
+3gun
+3g2us
+4gu4t
+g3w
+1gy
+2g5y3n
+gy5ra
+h3ab4l2
+ha2ch4
+hae4m
+hae4t
+h5agu
+ha3la
+hala3m
+ha4m
+han4ci
+ha2n
+han4cy
+5hand.
+h4and
+h2an4g
+hang5er
+han1g5o
+h5a5niz
+ha4n4k2
+han4te
+han1t
+ha2p3l2
+ha2p5t
+ha3ra2n
+h2a2r
+ha5r2as
+har2d
+hard3e
+har4le4
+har1l
+harp5en
+har2p
+har5ter
+ha2s5s
+haun4
+5haz
+haz3a1
+h1b
+1hea2d1
+3he2a2r
+he4ca2n
+he1ca
+h5ecat
+h4ed
+h4e5do5
+he3l4i
+hel4lis
+hel1l
+hell2i
+hel4ly
+h5elo
+he4m4p
+he2n
+he1na4
+hen5at
+he1o5r
+hep5
+h4er1a
+hera3p
+her4ba
+h2er1b
+here5a
+h3ern
+h5er1ou2
+h2ero
+h3ery
+h1es
+he2s5p
+he4t
+he2t4ed
+h4eu4
+h1f
+h1h
+hi5a2n
+h2i1a
+hi4co
+high5
+h2ig
+h4il2
+himer4
+h4i1na
+hion4e
+h2io
+hio2n
+h2i4p
+hir4l
+h4ir
+hi3ro
+hir4p
+hir4r4
+his3el
+h4ise
+h4i2s4s
+hith5er
+h2ith
+hith2e
+h2i2v
+4hk
+4h1l4
+hla2n4
+h2lo
+hlo3ri
+4h1m
+hmet4
+2h1n
+h5odiz
+h5o2d1s2
+ho4g
+ho1ge4
+hol5a2r
+ho1la
+3hol4e
+ho4ma
+ho2me3
+ho1n4a
+ho2n
+ho5ny
+3hood
+hoo2
+hoo2n4
+hor5at
+ho1ra
+ho5r2is
+hort3e
+ho5ru
+hos4e
+ho5sen
+hos1p
+1ho2us
+hou2
+house3
+hov5el
+4h5p
+4hr4
+hree5
+hro5niz
+hro2n
+hro3po
+4h1s2
+h4s2h
+h4t2a2r
+h1ta
+ht1en
+ht5es
+h4ty
+hu4g
+hu4min
+hu1mi
+hun5ke
+hu4nk2
+hun4t
+hus3t4
+h2us
+hu4t
+h1w
+h4war4t
+hw2a2r
+hy3pe
+hy3ph
+hy2s
+2i1a
+i2al
+iam4
+iam5e1te
+i2a2n
+4ianc
+ian3i
+4ian4t
+ia5pe
+ia2ss4
+i4a1t2iv
+ia4tric
+ia1tr
+i4a2tu
+ibe4
+ib3er1a
+ib5ert
+ib5i1a
+ib3in
+ib5it.
+ibi2t
+ib5ite
+i1b2l2
+ib3li
+i5bo
+i1br
+i2b5ri
+i5bu4n
+4icam
+i1ca
+5icap
+4ic2a2r
+i4car.
+i4cara
+icas5
+i4cay
+iccu4
+ic3c
+4iceo
+4i2ch
+2i1ci
+i5c2id
+ic5i1na
+i2cin
+i2c2ip
+ic3i1pa
+i4c1ly4
+i1c4l4
+i2c5oc
+i1co
+4i1cr
+5icra
+i4cry
+ic4te
+i2c1t
+ic1tu2
+ic4t3u1a
+ic3u1la
+ic4um
+ic5uo
+i3cur
+2id
+i4dai2
+i1d2a
+id5anc
+ida2n
+id5d4
+ide3a4l
+ide4s2
+i2di
+id5i2a2n
+i1d4i3a
+idi4a2r
+i5d2ie4
+i1d3io
+idi5ou2
+id1it
+id5i1u
+i3dle
+i4dom
+i1do
+id3ow
+i4dr
+i2du
+id5uo
+2ie4
+ied4e
+5ie5ga
+ie2ld3
+ie1n5a4
+ien4e
+i5e4n1n2
+i3ent2i
+ien1t
+i1er.
+i3es2c
+i1est
+i3et
+4if.
+if5ero
+ifer1
+iff5en
+i4f1f
+if4fr
+4i2f3ic.
+i1fi
+i3f2ie4
+i3f4l2
+4i2ft
+2ig
+iga5b
+i1ga
+ig3er1a
+ight3i
+4igi
+i3gib
+ig3il4
+ig3in
+ig3it
+i4g4l2
+i2go
+ig3or
+ig5ot
+i5gre
+i1gr
+ig2u5i2
+ig1ur
+i3h
+4i5i4
+i3j
+4ik
+i1la
+il3a4b
+i4l4ade
+ila2d
+i2l5am
+ila5ra
+il2a2r
+i3leg
+il1er
+ilev4
+i2l5f
+il1i
+il3i1a
+il2ib
+il3io
+il4ist
+2il1it
+il2iz
+ill5ab
+il1l
+4i2l1n2
+il3o1q
+il4ty
+i4lt
+il5ur
+il3v
+i4mag
+i1ma
+im3age
+ima5ry
+im2a2r
+iment2a5r
+i1men
+i3men1t
+imen1ta
+4imet
+im1i
+im5i1d4a
+im2id
+imi5le
+i5m2ini
+4imit
+im4ni
+i4m1n
+i3mo2n
+i1mo
+i2mu
+im3u1la
+2in.
+i4n3au
+i1na
+4inav
+incel4
+in3cer
+4ind
+in5dling
+2ine
+i3nee
+in4er4a2r
+in1er
+iner1a
+i5n2e2ss
+i1nes
+4in1ga
+4inge
+in5gen
+4ingi
+in5gling
+ingl2
+4in1go
+4in1gu
+2ini
+i5ni.
+i4n4i1a
+in3i4o
+in1is
+i5ni4te.
+in2it
+in2ite
+5i3n2i1t2io
+ini1ti
+in3i1ty
+4i4nk2
+4i4n1l
+2i4n1n2
+2i1no
+i4no4c
+ino4s
+i4not
+2i2n1s2
+in3se
+insu1r5a
+in1su
+insu2r
+2int.
+in1t
+2in4th
+in1u
+i5n2us
+4iny
+2io
+4io.
+io1ge4
+io2gr
+i1ol
+io4m
+ion3at
+io2n
+io1n1a
+ion4ery
+ion1er
+ion3i
+i2o5ph
+ior3i
+i4os
+i4o5th
+i5oti
+io4to
+i4our
+iou2
+2ip
+ipe4
+iphr2as4
+ip4hr4
+ip3i
+ip4ic
+ip4re4
+ipr2
+ip3ul
+i3qua
+iqu2
+iq5ue1f
+iq3u2id
+iq2ui2
+iq3ui3t
+4ir
+i1ra
+i2ra4b
+i4rac
+ird5e
+ire4de
+i2r2ed
+i4re1f
+i4rel4
+i4res
+ir5gi
+irg2
+ir1i
+iri5de
+ir2id
+ir4is
+iri3tu
+5i5r2iz
+ir4min
+ir1m
+iro4g
+5iron.
+iro2n
+ir5ul
+2is.
+is5ag
+isa2
+is3a2r
+isas5
+2is1c
+is3ch2
+4ise
+is3er
+3i4s3f
+is5ha2n
+is2h
+is3ho2n3
+isho4
+ish5op
+is3i1b
+is2i4d
+i5sis
+is5i1t2iv
+isi1ti
+4is4k2
+isla2n4
+is1l2
+4is4m1s2
+i2s1m
+i2so
+iso5mer
+i3som
+iso2me
+is1p
+is2pi
+is4py
+4i2s1s
+is4sal
+is1sa2
+issen4
+is4s1e4s
+is4ta.
+is1ta
+is1te
+is1t2i
+ist4ly
+is2tl
+4istral
+ist4r
+is1tra
+i2su
+is5us
+4i3ta.
+i1ta
+ita4bi
+i2tab
+i4tag
+4ita5m
+i3ta2n
+i3tat
+2ite
+it3er1a
+i5ter1i
+it4es
+2ith
+i1ti
+4i1t2i1a
+4i2tic
+it3i1ca
+5i5tick1
+i2t3ig
+it5il1l
+i2tim
+2i1t2io
+4itis
+i4ti2s4m
+i2t5o5m
+i1to
+4ito2n
+i4tram
+i1tra
+it5ry
+4i4t3t2
+it3u1at
+i1tu
+itu1a
+i5tud2
+it3ul
+4itz.
+i4tz
+i1u
+2iv
+iv3el1l
+iv3en.
+i4v3er.
+i4vers.
+ive4r1s2
+iv5il.
+i2vil
+iv5io
+iv1it
+i5vore
+iv3o3ro
+i4v3ot
+4i5w
+ix4o
+4iy
+4iz2a2r2
+iza1
+i2z1i4
+5izon1t
+i1zo
+izo2n
+5ja
+jac4q
+ja4p
+1je
+je4r5s2
+4jes4t2ie4
+jest2i
+4jes2ty
+jew3
+jo4p
+5judg
+3ka.
+k3ab
+k5ag
+kais4
+kai2
+kal4
+k1b
+k2ed
+1kee
+ke4g
+ke5l2i
+k3en4d
+k1er
+kes4
+k3e2st.
+ke4ty
+k3f
+kh4
+k1i
+5ki.
+5k2ic
+k4il1l
+kilo5
+k4im
+k4in.
+kin4de
+k4ind
+k5i5n2e2ss
+k2ine
+ki1nes
+kin4g
+k2i4p
+kis4
+k5is2h
+kk4
+k1l
+4k3ley
+4k1ly
+k1m
+k5nes
+1k2no
+ko5r
+kos2h4
+k3ou2
+kro5n
+4k1s2
+k4sc
+ks4l2
+k4s4y
+k5t
+k1w
+lab3ic
+l4abo
+l4a2ci4
+l4ade
+la2d
+la3d2y
+lag4n
+la2m3o
+3l4and
+la2n
+lan4dl
+lan5et
+lan4te
+lan1t
+lar4g2
+l2a2r
+lar3i
+las4e
+la5ta2n
+la2ta
+4latel2i4
+4la1t2iv
+4lav
+la4v4a
+2l1b
+lbin4
+4l1c2
+lce4
+l3ci
+2ld
+l2de
+ld4ere
+ld4er1i
+ldi4
+ld5is1
+l3dr
+l4dri
+le2a
+le4bi
+l2e1b
+le2ft5
+le1f
+5leg.
+5le4g1g2
+le4mat
+le1ma
+lem5at1ic
+4len.
+3lenc
+5le2ne.
+1len1t
+le3ph
+le4pr2
+le2ra5b
+ler1a
+ler4e
+3lerg2
+3l4er1i
+l4ero
+les2
+le5s1co
+les2c
+5lesq
+3l2e2ss
+5less.
+l3e1va
+lev4er.
+lev1er
+lev4er1a
+lev4e4r1s2
+3ley
+4leye
+2lf
+l5fr
+4l1g4
+l5ga
+lg2a2r3
+l4ges
+l1go3
+2l3h
+li4ag
+l2i1a
+li2am4
+liar5iz
+li2a2r
+liar1i
+li4as
+li4a1to
+li5bi
+5lic2io
+l2i1ci
+li4cor
+li1co
+4li4c3s2
+4lict.
+li2c1t
+l4icu
+l3i1cy
+l3i1d2a
+l2id
+lid5er
+3li2di
+lif3er1
+l4i4f1f
+li4f4l2
+5ligate
+l2ig
+li1ga
+3ligh
+li4gra
+li1gr
+3l4ik
+4l4i4l
+lim4b2l2
+li4m1b
+lim3i
+li4mo
+l4i4m4p
+l4i1na
+1l4ine
+lin3ea
+l2in3i
+link5er
+l4i4nk2
+li5og
+l2io
+4l4iq
+lis4p
+l1it
+l2it.
+5lit3i1ca
+li1ti
+l4i2tic
+l5i5ti4c3s2
+liv3er
+l2iv
+l1iz
+4lj
+lka3
+l3kal4
+lka4t
+l1l
+l4law
+l2le
+l5le2a
+l3lec
+l3leg
+l3lel
+l3le4n
+l3le4t
+ll2i
+l2lin4
+l5l4i1na
+ll4o
+lloq2ui5
+llo1q
+lloqu2
+l2l5out
+llou2
+l5low
+2lm
+l5met
+lm3ing
+l4mo2d1
+l1mo
+lmo2n4
+2l1n2
+3lo.
+lob5al
+lo4ci
+4lof
+3log1ic
+l5o1go
+3logu
+lom3er
+lo2me
+5long
+lo2n
+lon4i
+l3o3niz
+lood5
+loo2
+5lo4pe.
+lop3i
+l3o4p1m
+lo1ra4
+lo4ra1to
+lo5r2ie4
+lor5ou2
+5los.
+los5et
+5los5o3phiz
+lo2so
+los4op
+los2oph
+5los5o1phy
+los4t
+lo4ta
+loun5d
+lou2
+2lout
+4lov
+2lp
+lpa5b
+l1pa
+l3pha
+l5phi
+lp5ing
+lpi2n
+l3pit
+l4p2l2
+l5pr2
+4l1r
+2l1s2
+l4sc
+l2se
+l4s2ie4
+4lt
+lt5ag
+l1ta
+ltane5
+lta2n
+l1te
+lten4
+lter1a4
+lth3i
+l5ties.
+lt2ie4
+ltis4
+l1tr
+l1tu2
+ltu1r3a
+lu5a
+lu3br
+lu2ch4
+lu3ci
+lu3en
+luf4
+lu5id
+l2ui2
+lu4ma
+5lu1mi
+l5umn.
+lu4m1n
+5lum3n4i1a
+lu3o
+luo3r
+4lup
+lu2ss4
+l2us
+lus3te
+1lut
+l5ven
+l5vet4
+2l1w
+1ly
+4lya
+4ly1b
+ly5me4
+ly3no
+2lys4
+l5y3s2e
+1ma
+2mab
+ma2ca
+ma5ch2ine
+ma2ch
+ma4ch1in
+ma4c4l4
+mag5in
+mag1i
+5mag1n
+2mah
+ma2id5
+mai2
+4ma2ld
+ma3l2ig
+mal1i
+ma5lin
+mal4l2i
+mal1l
+mal4ty
+ma4lt
+5ma3n4i1a
+ma2n
+man5is
+man3iz
+4map
+ma5ri2ne.
+m2a2r
+mar1i
+mar2in4e
+ma5r2iz
+mar4ly
+mar1l
+mar3v
+ma5sce
+mas4e
+mas1t
+5mate
+m4ath3
+ma3tis
+4mati3za1
+ma1tiz
+4m1b
+m1ba4t5
+m5bil
+m4b3ing
+mb2i4v
+4m5c
+4me.
+2med
+4med.
+5me3d4i3a
+m4edi
+me3d2ie4
+m5e5d2y
+me2g
+mel5o2n
+me4l4t
+me2m
+me1m1o3
+1men
+me1n4a
+men5ac
+men4de
+4mene
+men4i
+me2n1s4
+men1su5
+3men1t
+men4te
+me5o2n
+m5er1sa2
+me4r1s2
+2mes
+3mest2i
+me4ta
+met3a2l
+me1te
+me5thi
+m4etr
+5met3ric
+me5tr2ie4
+me3try
+me4v
+4m1f
+2mh
+5mi.
+m2i3a
+mi1d4a
+m2id
+mid4g
+m2ig4
+3mil3i1a
+mil1i
+m5i5l2ie4
+m4il1l
+mi1n4a
+3m4ind
+m5i3nee
+m2ine
+m4ingl2
+min5gli
+m5ing1ly
+min4t
+m4in1u
+miot4
+m2io
+m2is
+mi4s4er.
+m4ise
+mis3er
+mis5l2
+mis4t2i
+m5i4stry
+mist4r
+4m2ith
+m2iz
+4mk
+4m1l
+m1m
+mma5ry
+m1ma
+mm2a2r
+4m1n
+m1n4a
+m4n1in
+mn4o
+1mo
+4mocr
+5moc5ra1tiz
+mo2d1
+mo4go
+mois2
+moi2
+mo4i5se
+4m2ok
+mo5lest
+moles2
+mo3me
+mon5et
+mo2n
+mon5ge
+mo3n4i3a
+mon4i2s1m
+mon1is
+mon4ist
+mo3niz
+monol4
+mo3ny.
+mo2r
+4mo5ra.
+mo1ra
+mos2
+mo5sey
+mo3sp
+m4oth3
+m5ouf
+mou2
+3mo2us
+mo2v
+4m1p
+mpara5
+m1pa
+mp2a2r
+mpa5rab
+mp4a4r5i
+m3pe2t
+mphas4
+m2pi
+mp2i4a
+mp5ies
+mp2ie4
+m4p1i2n
+m5p4ir
+mp5is
+mpo3ri
+m1p4or
+mpos5ite
+m1pos
+m4po2us
+mpou2
+mpov5
+mp4tr
+m2p1t
+m2py
+4m3r
+4m1s2
+m4s2h
+m5si
+4mt
+1mu
+mul2a5r4
+mu1la
+5mu4lt
+mul1ti3
+3mum
+mun2
+4mup
+mu4u
+4mw
+1na
+2n1a2b
+n4abu
+4nac.
+na4ca
+n5a2c1t
+nag5er.
+nak4
+na4l1i
+na5l2i1a
+4na4lt
+na5mit
+n2a2n
+nan1ci4
+nan4it
+na4nk4
+nar3c
+n2a2r
+4nare
+nar3i
+nar4l
+n5ar1m
+n4as
+nas4c
+nas5t2i
+n2at
+na3ta2l
+na2ta
+nat5o5m2iz
+na2tom
+na1to
+n2au
+nau3se
+na2us
+3naut
+nav4e
+4n1b4
+nc2a2r5
+n1ca
+n4ces.
+n3cha
+n2ch
+n5cheo
+nche2
+n5ch4il2
+n3chis
+n2c1in
+n1ci
+n2c4it
+ncou1r5a
+n1co
+ncou2
+n1cr
+n1cu
+n4dai2
+n1d2a
+n5da2n
+n1de
+nd5e2st.
+ndes2
+ndi4b
+n5d2if
+n1dit
+n3diz
+n5du2c
+n1du
+ndu4r
+nd2we
+nd1w
+2ne.
+n3e2a2r
+n2e2b
+neb3u
+ne2c
+5neck1
+2ned
+ne4gat
+ne1ga
+ne4g5a1t2iv
+5nege
+ne4la
+nel5iz
+nel2i
+ne5mi
+ne4mo
+1nen
+4nene
+3neo
+ne4po
+ne2q
+n1er
+ne2ra5b
+ner1a
+n4er3a2r
+n2ere
+n4er5i
+ner4r4
+1nes
+2nes.
+4ne1sp
+2nest
+4nes4w2
+3net1ic
+ne4v
+n5eve
+ne4w
+n3f
+n4gab
+n1ga
+n3gel
+nge4n4e
+n1gen
+n5gere
+n3ger1i
+ng5ha
+n3gib
+ng1in
+n5git
+n4gla4
+ngl2
+ngov4
+n1go
+ng5s2h
+ngs2
+n1gu
+n4gum
+n2gy
+4n1h4
+nha4
+nhab3
+nhe4
+3n4i1a
+ni3a2n
+ni4ap
+ni3ba
+ni4b2l2
+n2i4d
+ni5di
+ni4er
+n2ie4
+ni2fi
+ni5ficat
+nifi1ca
+n5i1gr
+n2ig
+n4ik4
+n1im
+ni3m2iz
+nim1i
+n1in
+5ni2ne.
+n2ine
+nin4g
+n2i4o
+5n2is.
+nis4ta
+n2it
+n4ith
+3n2i1t2io
+ni1ti
+n3itor
+ni1to
+ni3tr
+n1j
+4nk2
+n5k2ero
+nk1er
+n3ket
+nk3in
+nk1i
+n1k1l
+4n1l
+n5m
+nme4
+nmet4
+4n1n2
+nne4
+nni3al
+n3n4i1a
+nn2i4v
+nob4l2
+no3ble
+n5o1c4l4
+4n3o2d
+3noe
+4nog
+no1ge4
+nois5i
+noi2
+no5l4i
+5nol1o1gis
+3nomic
+n5o5m2iz
+no4mo
+no3my
+no4n
+non4ag
+no1n1a
+non5i
+n5oniz
+4nop
+5nop5o5l2i
+no2r5ab
+no1ra
+no4rary
+nor2a2r
+4nos2c
+nos4e
+nos5t
+no5ta
+1nou2
+3noun
+nov3el3
+nowl3
+n1p4
+npi4
+npre4c
+npr2
+n1q
+n1r
+nru4
+2n1s2
+n2s5ab
+nsa2
+nsati4
+ns4c
+n2se
+n4s3e4s
+ns2id1
+ns2ig4
+n2s1l2
+n2s3m
+n4soc
+n1so
+ns4pe
+n5spi
+nsta5b2l2
+ns1ta
+ns2tab
+n1t
+n2ta4b
+n1ta
+nte4r3s2
+nt2i
+n5ti2b
+nti4er
+nt2ie4
+nti2f2
+n3t2ine
+n2t1in
+n4t3ing
+nt2i4p
+ntrol5l2i
+ntrol1l
+n4t4s2
+ntu3me
+n1tu
+n3tum
+nu1a
+nu4d
+nu5en
+nuf4fe
+nu4f1f
+n3ui4n
+n2ui2
+3nu3it
+n4um
+nu1me
+n5u1mi
+3nu4n
+n3uo
+nu3tr
+n1v2
+n1w4
+nym4
+nyp4
+4nz
+n3za1
+4oa
+oa2d3
+o5a5les2
+o2ale
+oard3
+o2a2r
+oas4e
+oast5e
+oat5i
+ob3a3b
+o5b2a2r
+o1be4l
+o1bi
+o2bin
+ob5ing
+o3br
+ob3ul
+o1ce
+o2ch4
+o3che4t
+oche2
+ocif3
+o1ci
+o4cil
+o4clam
+o1c4l4
+o4cod
+o1co
+oc3rac
+oc5ra1tiz
+ocre3
+5ocrit
+ocri2
+octo2r5a
+o2c1t
+oc1to
+oc3u1la
+o5cure
+od5d1ed
+od1d4
+od3ic
+o1d2i3o
+o2do4
+od4or3
+o4d5uct.
+o1du
+odu2c
+odu2c1t
+o4d5uc4t1s2
+o4el
+o5eng
+o3er
+oe4ta
+o3ev
+o2fi
+of5ite
+of4i4t4t2
+o2g5a5r
+o1ga
+o4g5a1t2iv
+o4ga1to
+o1ge
+o5gene
+o1gen
+o5geo
+o4ger
+o3g2ie4
+1o1gis
+og3it
+o4gl2
+o5g2ly
+3ogniz
+og1ni
+o4g4ro
+o1gr
+og2u5i2
+1o1gy
+2o2g5y3n
+o1h2
+ohab5
+oi2
+oic3es
+oi3der
+o2id
+oi4f1f4
+o2ig4
+oi5let
+o3ing
+oint5er
+oin1t
+o5i2s1m
+oi5so2n
+oi2so
+oist5en
+ois1te
+oi3ter
+o2ite
+o5j
+2ok
+o3ken
+ok5ie4
+ok1i
+o1la
+o4la2n
+ola2ss4
+o2l2d
+ol2d1e
+ol3er
+o3les2c
+oles2
+o3let
+ol4fi
+o2lf
+ol2i
+o3l2i1a
+o3lice
+ol5id.
+ol2id
+o3li4f
+o5l4i4l
+ol3ing
+o5l2io
+o5l2is.
+ol3is2h
+o5l2ite
+ol1it
+o5l2i1t2io
+oli1ti
+o5l2iv
+oll2i4e4
+ol1l
+oll2i
+ol5o3giz
+olo4r
+ol5p2l2
+o2lp
+o4l2t
+ol3ub
+ol3ume
+ol3un
+o5l2us
+ol2v
+o2ly
+o2m5ah
+o1ma
+oma5l
+om5a1tiz
+om2be
+o4m1b
+om4b2l2
+o2me
+om3e1n4a
+o1men
+om5er2se
+ome4r1s2
+o4met
+om5e3try
+om4etr
+o3m2i3a
+om3ic.
+om3i1ca
+o5m2id
+om1in
+o5m2ini
+5ommend
+om1m
+om1men
+omo4ge
+o1mo
+o4mo2n
+om3pi
+o4m1p
+ompro5
+ompr2
+o2n
+o1n1a
+on4ac
+o3n2a2n
+on1c
+3oncil
+on1ci
+2ond
+on5do
+o3nen
+o2n5est
+o1nes
+on4gu
+on1ic
+o3n2i4o
+on1is
+o5ni1u
+on3key
+o4nk2
+on4odi
+o4n3o2d
+on3o3my
+o2n3s2
+on5spi4
+onspi1r5a
+onsp4ir
+on1su4
+onten4
+on1t
+on3t4i
+onti2f5
+on5um
+on1va5
+on1v2
+oo2
+ood5e
+ood5i
+o2o4k
+oop3i
+o3ord
+oost5
+o2pa
+o2p2e5d
+op1er
+3oper1a
+4op4erag
+2oph
+o5pha2n
+o5ph4er
+op3ing
+opi2n
+o3pit
+o5po2n
+o4posi
+o1pos
+o1pr2
+op1u
+opy5
+o1q
+o1ra
+o5ra.
+o4r3ag
+or5al1iz
+oral1i
+or5an4ge
+ora2n
+or2ang
+ore5a
+o5re1a4l
+or3ei2
+or4e5s2h
+or5e2st.
+ores2t
+orew4
+or4gu
+org2
+4o5r2i3a
+or3i1ca
+o5ril
+or1in
+o1r2i1o
+or3i1ty
+o3ri1u
+or2mi
+or1m
+orn2e
+o5rof
+or3oug
+orou2
+or5pe
+or1p
+3orrh4
+or1r4
+or4se
+o4rs2
+ors5en
+orst4
+or3thi
+or3thy
+or4ty
+o5rum
+o1ry
+os3al
+osa2
+os2c
+os4ce
+o3scop
+os1co
+4oscopi
+o5scr
+os4i4e4
+os5i1t2iv
+osi1ti
+os3i1to
+os3i1ty
+o5si4u
+os4l2
+o2so
+o2s4pa
+os4po
+os2ta
+o5stati
+os5til
+ost2i
+os5tit
+o4ta2n
+o1ta
+otele4g
+ot3er.
+ot5e4r1s2
+o4tes
+4oth
+oth5e1si
+oth2e
+oth1es
+oth3i4
+ot3ic.
+ot5i1ca
+o3tice
+o3tif2
+o3tis
+oto5s2
+o1to
+ou2
+ou3b2l2
+ouch5i
+ou2ch
+ou5et
+ou4l
+ounc5er
+oun2d
+ou5v2
+ov4en
+over4ne
+ove4r3s2
+ov4ert
+o3vis
+o4vi1ti4
+o5v4ol
+ow3der
+ow3el
+ow5est3
+ow1i2
+own5i
+o4wo2
+oy1a
+1pa
+pa4ca
+pa4ce
+pa2c4t
+p4a2d
+5paga4n
+pa1ga
+p3agat
+p4ai2
+pa4i4n4
+p4al
+pa1n4a
+pa2n
+pan3el
+pan4ty
+pan1t
+pa3ny
+pa1p
+pa4pu
+para5b2l2
+p2a2r
+pa2rab
+par5age
+par5d2i
+3pare
+par5el
+p4a4r1i
+par4is
+pa2te
+pa5ter
+5pathic
+p4ath
+pa5thy
+pa4tric
+pa1tr
+pav4
+3pay
+4p1b
+pd4
+4pe.
+3pe4a
+pear4l
+pe2a2r
+pe2c
+2p2ed
+3pede
+3p4edi
+pe3d4i3a4
+ped4ic
+p4ee
+pee4d
+pek4
+pe4la
+pel2i4e4
+pel2i
+pe4n2a2n
+pe1na
+p4enc
+pen4th
+pen1t
+pe5o2n
+p4era.
+per1a
+pera5b2l2
+pe2ra4b
+p4erag
+p4er1i
+peri5st
+per2is
+per4mal
+per3m4
+per1ma
+per2me5
+p4ern
+p2er3o
+per3ti
+p4e5ru
+per1v
+pe2t
+pe5ten
+pe5tiz
+4pf
+4pg
+4ph.
+phar5i
+ph2a2r
+ph4e3no
+phe2n
+ph4er
+ph4es.
+ph1es
+ph1ic
+5ph2ie4
+ph5ing
+5phis1t2i
+3phiz
+p4h2l4
+3phob
+3phone
+pho2n
+5phoni
+pho4r
+4p4h1s2
+ph3t
+5phu
+1phy
+p2i3a
+pi2a2n4
+pi4c2ie4
+p2i1ci
+pi4cy
+p4id
+p5i1d2a
+pi3de
+5pi2di
+3piec
+p2ie4
+pi3en
+pi4grap
+p2ig
+pi1gr
+pi3lo
+pi2n
+p4in.
+p4ind4
+p4i1no
+3p2i1o
+pio2n4
+p3ith
+pi5tha
+pi2tu
+2p3k2
+1p2l2
+3pla2n
+plas5t
+pl2i3a
+pli5er
+pl2ie4
+4pl2ig
+pli4n
+ploi4
+plu4m
+plu4m4b
+4p1m
+2p3n
+po4c
+5pod.
+po5em
+po3et5
+5po4g
+poin2
+poi2
+5poin1t
+poly5t
+po2ly
+po4ni
+po2n
+po4p
+1p4or
+po4ry
+1pos
+po2s1s
+p4ot
+po4ta
+5poun
+pou2
+4p1p
+ppa5ra
+p1pa
+pp2a2r
+p2pe
+p4p2ed
+p5pel
+p3pen
+p3per
+p3pe2t
+ppo5s2ite
+p1pos
+pr2
+pray4e4
+5pre1c2i
+pre5co
+pre3e2m
+pre4f5ac
+pre1f
+pre1fa
+pre4la
+pr1e3r4
+p3re1s2e
+3pr2e2ss
+pre5ten
+pre3v2
+5pr2i4e4
+prin4t3
+pr2i4s
+pri2s3o
+p3ro1ca
+pr2oc
+prof5it
+pro2fi
+pro3l
+pros3e
+pro1t
+2p1s2
+p2se
+ps4h
+p4si1b
+2p1t
+p2t5a4b
+p1ta
+p2te
+p2th
+p1ti3m
+ptu4r
+p1tu
+p4tw4
+pub3
+pue4
+puf4
+pu4l3c2
+pu4m
+pu2n
+pur4r4
+5p2us
+pu2t
+5pute
+put3er
+pu3tr
+put4t1ed
+pu4t3t2
+put4t1in
+p3w
+qu2
+qua5v4
+2que.
+3quer
+3quet
+2rab
+ra3bi
+rach4e2
+ra2ch
+r5a1c4l4
+raf5fi
+ra2f
+ra4f1f4
+ra2f4t
+r2ai2
+ra4lo
+ram3et
+r2ami
+ra3ne5o
+ra2n
+ran4ge
+r2ang
+r4ani
+ra5no4
+rap3er
+3ra1phy
+rar5c
+r2a2r
+rare4
+rar5e1f
+4raril
+rar1i
+r2as
+ratio2n4
+ra1t2io
+rau4t
+ra5vai2
+ra2va
+rav3el
+ra5z2ie4
+ra2z1i
+r1b
+r4bab
+r4bag
+rbi2
+r2b3i4f
+r2bin
+r5b2ine
+rb5ing.
+rb4o
+r1c
+r2ce
+r1cen4
+r3cha
+r2ch
+rch4er
+rche2
+r4ci4b
+r1ci
+r2c4it
+rcum3
+r4dal
+r1d2a
+rd2i
+r1d4i4a
+rdi4er
+rd2ie4
+rd1in4
+rd3ing
+2re.
+re1a4l
+re3a2n
+re5ar1r4
+re2a2r
+5rea2v
+re4aw
+r5ebrat
+r2e1b
+re3br
+rec5ol1l
+re2col
+re1co
+re4c5ompe
+reco4m1p
+re4cre
+re1cr
+2r2ed
+re1de
+re3dis1
+r4edi
+red5it
+re4fac
+re1f
+re1fa
+re2fe
+re5fer.
+refer1
+re3fi
+re4fy
+reg3is
+re5it
+rei2
+re1l2i
+re5lu
+r4en4ta
+ren1t
+ren4te
+re1o
+re5pi2n
+re4posi
+re1po
+re1pos
+re1pu
+r1er4
+r4er1i
+r2ero4
+r4e5ru
+r4es.
+re4spi
+re1sp
+res4s5i4b
+r2e2ss
+res1si
+res2t
+re5s2ta2l
+res1ta
+r2e3st4r
+re4ter
+re4ti4z
+re3tri
+r4eu2
+re5u1t2i
+rev2
+re4val
+re1va
+rev3el
+r5ev5er.
+rev1er
+re5ve4r1s2
+re5vert
+re5vi4l
+re1vi
+rev5olu
+re4wh
+r1f
+r3fu4
+r4fy
+rg2
+rg3er
+r3get
+r3g1ic
+rgi4n
+rg3ing
+r5gis
+r5git
+r1gl2
+rgo4n2
+r1go
+r3gu
+rh4
+4rh.
+4rhal
+r2i3a
+ria4b
+ri4ag
+r4ib
+rib3a
+ric5as5
+ri1ca
+r4ice
+4r2i1ci
+5ri5c2id
+ri4c2ie4
+r4i1co
+rid5er
+r2id
+ri3enc
+r2ie4
+ri3en1t
+ri1er
+ri5et
+rig5a2n
+r2ig
+ri1ga
+5r4igi
+ril3iz
+ril1i
+5rima2n
+ri1ma
+rim5i
+3ri1mo
+rim4pe
+ri4m1p
+r2i1na
+5rina.
+r4in4d
+r2in4e
+rin4g
+r2i1o
+5riph
+r2ip
+riph5e
+ri2p2l2
+rip5lic
+r4iq
+r2is
+r4is.
+r2is4c
+r3is2h
+ris4p
+ri3ta3b
+ri1ta
+r5ited.
+r2ite
+ri2t1ed
+rit5er.
+rit5e4r1s2
+r4i2t3ic
+ri1ti
+ri2tu
+rit5ur
+riv5el
+r2iv
+riv3et
+riv3i
+r3j
+r3ket
+rk4le
+rk1l
+rk4lin
+r1l
+rle4
+r2led
+r4l2ig
+r4lis
+rl5is2h
+r3lo4
+r1m
+rma5c
+r1ma
+r2me
+r3men
+rm5e4r1s2
+rm3ing
+r4ming.
+r4m2io
+r3mit
+r4my
+r4n2a2r
+r1na
+r3nel
+r4n1er
+r5net
+r3ney
+r5nic
+r1nis4
+r3n2it
+r3n2iv
+rno4
+r4nou2
+r3nu
+rob3l2
+r2oc
+ro3cr
+ro4e
+ro1fe
+ro5fil
+ro2fi
+r2ok2
+ro5k1er
+5role.
+rom5e1te
+ro2me
+ro4met
+rom4i
+ro4m4p
+ron4al
+ro2n
+ro1n1a
+ron4e
+ro5n4is
+ron4ta
+ron1t
+1room
+roo2
+5root
+ro3pel
+rop3ic
+ror3i
+ro5ro
+ro2s5per
+ro2s4s
+ro4th2e
+r4oth
+ro4ty
+ro4va
+rov5el
+rox5
+r1p
+r4pe4a
+r5pen1t
+rp5er.
+r3pe2t
+rp4h4
+rp3ing
+rpi2n
+r3po
+r1r4
+rre4c
+rre4f
+r4re1o
+rre4s2t
+rr2i4o
+rr2i4v
+rro2n4
+rros4
+rrys4
+4rs2
+r1sa2
+rsa5ti
+rs4c
+r2se
+r3sec
+rse4cr
+r4s5er.
+rs3e4s
+r5se5v2
+r1s2h
+r5sha
+r1si
+r4si4b
+rso2n3
+r1so
+r1sp
+r5sw2
+rta2ch4
+r1ta
+r4tag
+r3t2e1b
+r3ten4d
+r1te5o
+r1ti
+r2t5i2b
+rt2i4d
+r4tier
+rt2ie4
+r3t2ig
+rtil3i
+rtil4l
+r4ti1ly
+r4tist
+r4t2iv
+r3tri
+rtr2oph4
+rt4s2h4
+r4t1s2
+ru3a
+ru3e4l
+ru3en
+ru4gl2
+ru3i4n
+r2ui2
+rum3p2l2
+ru4m2p
+ru2n
+ru4nk5
+run4ty
+run1t
+r5usc2
+r2us
+ru2t1i5n
+r4u1t2i
+rv4e
+rvel4i
+r3ven
+rv5er.
+r5vest
+rv4e2s
+r3vey
+r3vic
+r3v2i4v
+r3vo
+r1w
+ry4c
+5rynge
+ryn5g
+ry3t
+sa2
+2s1ab
+5sack1
+sac3ri2
+s3a2c1t
+5sai2
+sa4l2a2r4
+s4a2l4m
+sa5lo
+sa4l4t
+3sanc
+sa2n
+san4de
+s4and
+s1ap
+sa5ta
+5sa3t2io
+sa2t3u
+sau4
+sa5vor
+5saw
+4s5b
+scan4t5
+s1ca
+sca2n
+sca4p
+scav5
+s4ced
+4s3cei2
+s4ces
+s2ch2
+s4cho2
+3s4c2ie4
+s1ci
+5sc4in4d
+s2cin
+scle5
+s1c4l4
+s4cli
+scof4
+s1co
+4scopy5
+scou1r5a
+scou2
+s1cu
+4s5d
+4se.
+se4a
+seas4
+sea5w
+se2c3o
+3se2c1t
+4s4ed
+se4d4e
+s5edl
+se2g
+se1g3r
+5sei2
+se1le
+5se2l2f
+5selv
+4se1me
+se4mol
+se1mo
+sen5at
+se1na
+4senc
+sen4d
+s5e2ned
+sen5g
+s5en1in
+4sen4t1d
+sen1t
+4sen2tl
+se2p3a3
+4s1er.
+s4er1l
+s2er4o
+4ser3vo
+s1e4s
+s4e5s2h
+ses5t
+5se5um
+s4eu
+5sev
+sev3en
+sew4i2
+5sex
+4s3f
+2s3g
+s2h
+2sh.
+sh1er
+5shev
+sh1in
+sh3io
+3sh2i4p
+sh2i2v5
+sho4
+sh5o2l2d
+sho2n3
+shor4
+short5
+4sh1w
+si1b
+s5ic3c
+3si2de.
+s2id
+5side4s2
+5si2di
+si5diz
+4sig1n4a
+s2ig
+sil4e
+4si1ly
+2s1in
+s2i1na
+5si2ne.
+s2ine
+s3ing
+1s2io
+5sio2n
+sio1n5a
+s4i2r
+si1r5a
+1sis
+3s2i1t2io
+si1ti
+5si1u
+1s2iv
+5siz
+sk2
+4ske
+s3ket
+sk5ine
+sk1i
+sk5in4g
+s1l2
+s3lat
+s2le
+sl2ith5
+sl1it
+2s1m
+s3ma
+smal1l3
+sma2n3
+smel4
+s5men
+5s4m2ith
+smo2l5d4
+s1mo
+s1n4
+1so
+so4ce
+so2ft3
+so4lab
+so1la
+so2l3d2
+so3lic
+sol2i
+5sol2v
+3som
+3s4on.
+so2n
+so1n1a4
+son4g
+s4op
+5soph1ic
+s2oph
+s5o3phiz
+s5o1phy
+sor5c
+sor5d
+4sov
+so5vi
+2s1pa
+5sp4ai2
+spa4n
+spen4d
+2s5peo
+2sper
+s2phe
+3sph4er
+spho5
+spil4
+sp5ing
+spi2n
+4s3p2i1o
+s4p1ly
+s1p2l2
+s4po2n
+s1p4or4
+4sp4ot
+squal4l
+squ2
+s1r
+2ss
+s1sa2
+ssas3
+s2s5c
+s3sel
+s5sen5g
+s4ses.
+ss1e4s
+s5set
+s1si
+s4s2ie4
+ssi4er
+s4s5i1ly
+s4s1l2
+ss4li
+s4s1n4
+sspen4d4
+ss2t
+ssu1r5a
+s1su
+ssu2r
+ss5w2
+2st.
+s2tag
+s1ta
+s2ta2l
+stam4i
+5st4and
+sta2n
+s4ta4p
+5stat.
+s4t1ed
+stern5i
+s5t2ero
+ste2w
+ste1w5a
+s3th2e
+st2i
+s4ti.
+s5t2i1a
+s1tic
+5s4tick1
+s4t2ie4
+s3tif2
+st3ing
+s2t1in
+5st4ir
+s1tle
+s2tl
+5stock1
+s1to
+sto2m3a
+5stone
+sto2n
+s4top
+3store
+st4r
+s4tra2d
+s1tra
+5stra2tu
+s4tray
+s4tr2id
+4stry
+4st3w4
+s2ty
+1su
+su1al
+su4b3
+su2g3
+su5is
+s2ui2
+suit3
+s4ul
+su2m
+su1m3i
+su2n
+su2r
+4sv
+sw2
+4s1wo2
+s4y
+4sy1c
+3syl
+syn5o
+sy5rin
+1ta
+3ta.
+2tab
+ta5bles2
+tab2l2
+5tab5o5l1iz
+tabol2i
+4t4a2ci
+ta5do
+ta2d
+4ta2f4
+tai5lo
+tai2
+ta2l
+ta5la
+tal5en
+t2ale
+tal3i
+4talk
+tal4lis
+tal1l
+tall2i
+ta5log
+ta5mo
+tan4de
+ta2n
+t4and
+1tan1ta3
+tan1t
+ta5per
+ta5p2l2
+tar4a
+t2a2r
+4tar1c
+4tare
+ta3r2iz
+tar1i
+tas4e
+ta5s4y
+4tat1ic
+ta4tur
+ta2tu
+taun4
+tav4
+2taw
+tax4is
+tax3i
+2t1b
+4tc
+t4ch
+tch5e4t
+tche2
+4t1d
+4te.
+te2ad4i
+tea2d1
+4tea2t
+te1ce4
+5te2c1t
+2t1ed
+t4e5di
+1tee
+teg4
+te5ger4
+te5gi
+3tel.
+tel2i4
+5te2l1s2
+te2ma2
+tem3at
+3ten2a2n
+te1na
+3tenc
+3tend
+4te1nes
+1ten1t
+ten4tag
+ten1ta
+1teo
+te4p
+te5pe
+ter3c
+5ter3d
+1ter1i
+ter5ies
+ter2ie4
+ter3is
+teri5za1
+5t4er3n2it
+ter5v
+4tes.
+4t2e2ss
+t3ess.
+teth5e
+3t4eu
+3tex
+4tey
+2t1f
+4t1g
+2th.
+tha2n4
+th2e
+4thea
+th3eas
+the5a2t
+the3is
+thei2
+3the4t
+th5ic.
+th5i1ca
+4th4il2
+5th4i4nk2
+4t4h1l4
+th5ode
+5thod3ic
+4thoo2
+thor5it
+tho5riz
+2t4h1s2
+1t2i1a
+ti4ab
+ti4a1to
+2ti2b
+4tick1
+t4i1co
+t4ic1u
+5ti2di
+t2id
+3tien
+t2ie4
+tif2
+ti5fy
+2t2ig
+5tigu
+til2l5in4
+til1l
+till2i
+1tim
+4ti4m1p
+tim5ul
+ti2mu
+2t1in
+t2i1na
+3ti2ne.
+t2ine
+3t2ini
+1t2io
+ti5oc
+tion5ee
+tio2n
+5tiq
+ti3sa2
+3t4ise
+ti2s4m
+ti5so
+tis4p
+5tisti1ca
+tis1t2i
+tis1tic
+ti3tl
+ti4u
+1t2iv
+ti1v4a
+1tiz
+ti3za1
+ti3ze4n
+ti2ze
+2tl
+t5la
+tla2n4
+3tle.
+3tled
+3tles.
+tles2
+t5let.
+t5lo
+4t1m
+tme4
+2t1n2
+1to
+to3b
+to5crat
+4to2do4
+2tof
+to2gr
+to5ic
+toi2
+to2ma
+to4m4b
+to3my
+ton4a4l1i
+to2n
+to1n1a
+to3n2at
+4tono
+4tony
+to2ra
+to3r2ie4
+tor5iz
+tos2
+5tour
+tou2
+4tout
+to3w2a2r
+4t1p
+1tra
+t2ra3b
+tra5ch
+tr4a2ci4
+tra2c4it
+trac4te
+tra2c1t
+tr2as4
+tra5ven
+trav5e2s5
+tre5f
+tre4m
+trem5i
+5tr2i3a
+tri5ces
+tr4ice
+5tri3c2i1a
+t4r2i1ci
+4tri4c3s2
+2trim
+tr2i4v
+tro5m4i
+tron5i
+tro2n
+4trony
+tro5phe
+tr2oph
+tro3sp
+tro3v
+tr2u5i2
+tr2us4
+4t1s2
+t4sc
+ts2h4
+t4sw2
+4t3t2
+t4tes
+t5to
+t1tu4
+1tu
+tu1a
+tu3a2r
+tu4b4i
+tud2
+4tue
+4tuf4
+5t2u3i2
+3tum
+tu4nis
+tu1ni
+2t3up.
+3ture
+5turi
+tur3is
+tur5o
+tu5ry
+3t2us
+4tv
+tw4
+4t1wa
+twis4
+twi2
+4t1wo2
+1ty
+4tya
+2tyl
+type3
+ty5ph
+4tz
+t2z4e
+4uab
+uac4
+ua5na
+ua2n
+uan4i
+uar5an1t
+u2a2r
+uara2n
+uar2d
+uar3i
+uar3t
+u1at
+uav4
+ub4e
+u4bel
+u3ber
+u4b2ero
+u1b4i
+u4b5ing
+u3b4le.
+ub2l2
+u3ca
+uci4b
+u1ci
+u2c4it
+ucle3
+u1c4l4
+u3cr
+u3cu
+u4cy
+ud5d4
+ud3er
+ud5est
+udes2
+ude1v4
+u1dic
+ud3ied
+ud2ie4
+ud3ies
+ud5is1
+u5dit
+u4do2n
+u1do
+ud4si
+u2d1s2
+u4du
+u4ene
+ue2n1s4
+uen4te
+uen1t
+uer4il
+uer1i
+3u1fa
+u3f4l2
+ugh3e2n
+ug5in
+2ui2
+uil5iz
+uil1i
+ui4n
+u1ing
+uir4m
+u4ir
+ui1ta4
+u2iv3
+ui4v4er.
+u5j
+4uk
+u1la
+ula5b
+u5lati
+ul2ch4
+u4l1c2
+5ulche2
+ul3der
+u2ld
+ul2de
+ul4e
+u1len
+ul4gi
+u4l1g4
+ul2i
+u5l2i1a
+ul3ing
+ul5is2h
+ul4l2a2r
+ul1l
+ul4li4b
+ull2i
+ul4lis
+4u2l3m
+u1l4o
+4u2l1s2
+uls5e4s
+ul2se
+ul1ti
+u4lt
+ul1tra3
+ul1tr
+4ul1tu2
+u3lu
+ul5ul
+ul5v
+u2m5ab
+u1ma
+um4bi
+u4m1b
+um4b1ly
+umb2l2
+u1mi
+u4m3ing
+umor5o
+u1mo
+umo2r
+u4m2p
+un2at4
+u1na
+u2ne
+un4er
+u1ni
+un4im
+u2n1in
+un5is2h
+un2i3v
+u2n3s4
+un4sw2
+un2t3a4b
+un1t
+un1ta
+un4ter.
+un4tes
+unu4
+un5y
+u4n5z
+u4o4rs2
+u5os
+u1ou2
+u1pe
+upe4r5s2
+u5p2i3a
+up3ing
+upi2n
+u3p2l2
+u4p3p
+upport5
+up1p4or
+up2t5i2b
+u2p1t
+up1tu4
+u1ra
+4ura.
+u4rag
+u4r2as
+ur4be
+ur1b
+ur1c4
+ur1d
+ure5a2t
+ur4fer1
+ur1f
+ur4fr
+u3rif
+uri4fic
+uri1fi
+ur1in
+u3r2i1o
+u1rit
+ur3iz
+ur2l
+url5ing.
+ur4no4
+uros4
+ur4pe
+ur1p
+ur4pi
+urs5er
+u4rs2
+ur2se
+ur5tes
+ur3th2e
+ur1ti4
+ur4t2ie4
+u3ru
+2us
+u5sa2d
+usa2
+u5sa2n
+us4ap
+usc2
+us3ci
+use5a
+u5s2i1a
+u3sic
+us4lin
+us1l2
+us1p
+us5s1l2
+u2ss
+us5tere
+us1t4r
+u2su
+usu2r4
+u2ta4b
+u1ta
+u3tat
+4u4te.
+4utel
+4uten
+uten4i
+4u1t2i
+uti5l2iz
+util1i
+u3t2ine
+u2t1in
+ut3ing
+utio1n5a
+u1t2io
+utio2n
+u4tis
+5u5tiz
+u4t1l
+u2t5of
+u1to
+uto5g
+uto5mat1ic
+uto2ma
+u5to2n
+u4tou2
+u4t1s4
+u3u
+uu4m
+u1v2
+ux1u3
+u2z4e
+1va
+5va.
+2v1a4b
+vac5il
+v4a2ci
+vac3u
+vag4
+va4ge
+va5l2i4e4
+val1i
+val5o
+val1u
+va5mo
+va5niz
+va2n
+va5pi
+var5ied
+v2a2r
+var1i
+var2ie4
+3vat
+4ve.
+4ved
+veg3
+v3el.
+vel3l2i
+vel1l
+ve4lo
+v4e1ly
+ven3om
+v4eno
+v5enue
+v4erd
+5v2e2re.
+v4erel
+v3eren
+ver5enc
+v4eres
+ver3ie4
+ver1i
+vermi4n
+ver3m4
+3ver2se
+ve4r1s2
+ver3th
+v4e2s
+4ves.
+ves4te
+ve4te
+vet3er
+ve4ty
+vi5al1i
+v2i1a
+vi2al
+5vi2a2n
+5vi2de.
+v2id
+5vi2d1ed
+4v3i1den
+5vide4s2
+5vi2di
+v3if
+vi5gn
+v2ig
+v4ik4
+2vil
+5v2il1it
+vil1i
+v3i3l2iz
+v1in
+4vi4na
+v2inc
+v4in5d
+4ving
+vi1o3l
+v2io
+v3io4r
+vi1ou2
+v2i4p
+vi5ro
+v4ir
+vis3it
+vi3so
+vi3su
+4vi1ti
+vit3r
+4vi1ty
+3v2iv
+5vo.
+voi4
+3v2ok
+vo4la
+v5ole
+5vo4l2t
+3vol2v
+vom5i
+vo2r5ab
+vo1ra
+vori4
+vo4ry
+vo4ta
+4vo1tee
+4vv4
+v4y
+w5ab2l2
+2wac
+wa5ger
+wa2g5o
+wait5
+wai2
+w5al.
+wam4
+war4t
+w2a2r
+was4t
+wa1te
+wa5ver
+w1b
+wea5r2ie4
+we2a2r
+wear1i
+we4ath3
+wea2t
+we4d4n4
+weet3
+wee5v
+wel4l
+w1er
+west3
+w3ev
+whi4
+wi2
+wil2
+wil2l5in4
+wil1l
+will2i
+win4de
+w4ind
+win4g
+w4ir4
+3w4ise
+w2ith3
+wiz5
+w4k
+wl4es2
+wl3in
+w4no
+1wo2
+wom1
+wo5v4en
+w5p
+wra4
+wri4
+wri1ta4
+w3s2h
+ws4l2
+ws4pe
+w5s4t
+4wt
+wy4
+x1a
+xac5e
+x4a2go
+xam3
+x4ap
+xas5
+x3c2
+x1e
+xe4cu1to
+xe1cu
+xe3c4ut
+x2ed
+xer4i
+x2e5ro
+x1h
+xhi2
+xh4il5
+xhu4
+x3i
+x2i5a
+xi5c
+xi5di
+x2id
+x4ime
+xi5m2iz
+xim1i
+x3o
+x4ob
+x3p
+xp4an4d
+x1pa
+xpa2n
+xpec1to5
+xpe2c
+xpe2c1t
+x2p2e3d
+x1t2
+x3ti
+x1u
+xu3a
+xx4
+y5ac
+3y2a2r4
+y5at
+y1b
+y1c
+y2ce
+yc5er
+y3ch
+ych4e2
+ycom4
+y1co
+ycot4
+y1d
+y5ee
+y1er
+y4er1f
+yes4
+ye4t
+y5gi
+4y3h
+y1i
+y3la
+ylla5b2l2
+yl1l
+y3lo
+y5lu
+ymbol5
+y4m1b
+yme4
+ym1pa3
+y4m1p
+yn3c4hr4
+yn2ch
+yn5d
+yn5g
+yn5ic
+5ynx
+y1o4
+yo5d
+y4o5g
+yom4
+yo5net
+yo2n
+y4o2n3s2
+y4os
+y4p2ed
+yper5
+yp3i
+y3po
+y4po4c
+yp2ta
+y2p1t
+y5pu
+yra5m
+yr5i3a
+y3ro
+yr4r4
+ys4c
+y3s2e
+ys3i1ca
+y1s3io
+3y1sis
+y4so
+y2ss4
+ys1t
+ys3ta
+ysu2r4
+y1su
+y3thin
+yt3ic
+y1w
+za1
+z5a2b
+z2a2r2
+4zb
+2ze
+ze4n
+ze4p
+z1er
+z2e3ro
+zet4
+2z1i
+z4il
+z4is
+5zl
+4zm
+1zo
+zo4m
+zo5ol
+zoo2
+zte4
+4z1z2
+z4zy
+.as9s8o9c8i8a8te.
+.as1so
+.asso1ci
+.asso3c2i1a
+.as9s8o9c8i8a8t8es.
+.de8c9l8i9n8a9t8i8on.
+.de1c4l4
+.decl4i1na
+.declin2at
+.declina1t2io
+.declinatio2n
+.ob8l8i8g9a9t8o8ry.
+.ob2l2
+.obl2ig
+.obli1ga
+.obliga1to
+.obligato1ry
+.ph8i8l9a8n9t8h8r8o8p8ic.
+.ph4il2
+.phi1la
+.phila2n
+.philan1t
+.philant4hr4
+.philanthrop3ic
+.pr8e8s8e8nt.
+.p3re1s2e
+.presen1t
+.pr8e8s8e8n8ts.
+.presen4t4s2
+.pr8o8j8e8ct.
+.pro5j
+.pro1je
+.proje2c1t
+.pr8o8j8e8c8ts.
+.projec4t1s2
+.re8c9i9p8r8o8c9i9t8y.
+.re1c2i
+.rec2ip
+.recipr2
+.recipr2oc
+.re1cipro1ci
+.recipro2c1it
+.reciproci1ty
+.re9c8o8g9n8i9z8a8n8ce.
+.re1co
+.re2cog
+.rec3ogniz
+.recog1ni
+.recogniza1
+.recogniza2n
+.re8f9o8r9m8a9t8i8on.
+.re1f
+.re1fo
+.refo2r
+.refor1m
+.refor1ma
+.reforma1t2io
+.reformatio2n
+.re8t9r8i9b8u9t8i8on.
+.re3tri
+.retr4ib
+.retri3bu1t2io
+.retrib4u1t2i
+.retributio2n
+.ta9b8le.
+.2tab
+.tab2l2
+.ac8a8d9e9m8y.
+.a1ca
+.aca2d
+.acad4em
+.acade3my
+.ac8a8d9e9m8i8e8s.
+.academ2i4e4
+.ac9c8u9s8a9t8i8v8e.
+.ac3c
+.ac1c2us
+.accusa2
+.accusa1t2iv
+.ac8r8o9n8y8m.
+.acro2n
+.acronym4
+.ac8r8y8l9a8m8i8d8e.
+.acry3la
+.acrylam2id
+.ac8r8y8l9a8m8i8d8e8s.
+.acrylamide4s2
+.ac8r8y8l9a8l8d8e9h8y8d8e.
+.acryla2ld
+.acrylal2de
+.acrylalde1h4
+.acrylaldehy1d
+.ad8d9a9b8l8e.
+.ad1d2a
+.ad2d3a4b
+.addab2l2
+.ad8d9i9b8l8e.
+.addi1b2l2
+.ad8r8e8n9a9l8i8n8e.
+.a1dr
+.adre4
+.a5dren
+.adre1na
+.adrena4l1i
+.adrena1l4ine
+.ae8r8o9s8p8a8c8e.
+.ae4r
+.a2ero
+.aero2s4pa
+.aerospa4ce
+.af9t8e8r9t8h8o8u8g8h8t.
+.afterthou2
+.af9t8e8r9t8h8o8u8g8h8t8s.
+.afterthough4t1s2
+.ag8r8o8n9o9m8i8s8t.
+.a1gr
+.ag4ro
+.agro2n
+.agronom2is
+.ag8r8o8n9o9m8i8s8t8s.
+.agronomis4t1s2
+.al9g8e9b8r8a9i9c8a8l9l8y.
+.a4l1g4
+.alg2e1b
+.alge3br
+.algebr2ai2
+.algebrai1ca
+.algebraical1l
+.algebraical1ly
+.am9p8h8e8t9a9m8i8n8e.
+.a4m1p
+.amphe4t
+.amphe1ta
+.amphetam1in
+.amphetam2ine
+.am9p8h8e8t9a9m8i8n8e8s.
+.amphetami1nes
+.an9a9l8y8s8e.
+.3ana1ly
+.a1na
+.an4a2lys4
+.anal5y3s2e
+.an9a9l8y8s8e8d.
+.analy4s4ed
+.an8a8l8y9s8e8s.
+.analys1e4s
+.an9i8s8o9t8r8o8p9i8c.
+.ani2so
+.anisotrop3ic
+.an9i8s8o9t8r8o8p9i9c8a8l9l8y.
+.anisotropi1ca
+.anisotropical1l
+.anisotropical1ly
+.an9i8s8o8t9r8o9p8i8s8m.
+.anisotropi2s1m
+.an9i8s8o8t9r8o8p8y.
+.anisotropy5
+.an8o8m9a8l8y.
+.ano4
+.anoma5l
+.ano1ma
+.anoma1ly
+.an8o8m9a8l8i8e8s.
+.anomal1i
+.anomal2i4e4
+.an8t8i9d8e8r8i8v9a9t8i8v8e.
+.ant2id
+.antider1i
+.antider2i4v
+.antide4ri1va
+.antideri3vat
+.antider2iva1t2iv
+.an8t8i9d8e8r8i8v9a9t8i8v8e8s.
+.antiderivativ4e2s
+.an8t8i9h8o8l8o9m8o8r9p8h8i8c.
+.anti3h
+.antiholo1mo
+.antiholomo2r
+.antiholomor1p
+.antiholomorp4h4
+.antiholomorph1ic
+.an9t8i8n9o9m8y.
+.an2t1in
+.ant2i1no
+.antino3my
+.an9t8i8n9o9m8i8e8s.
+.antinom2ie4
+.an9t8i9n8u9c8l8e8a8r.
+.antin1u
+.antinucle3
+.antinu1c4l4
+.antinucle2a
+.antinucle2a2r
+.an9t8i9n8u9c8l8e9o8n.
+.antinucleo2n
+.an9t8i9r8e8v9o9l8u9t8i8o8n9a8r8y.
+.ant4ir
+.antirev2
+.antirev5olu
+.antirevo1lut
+.antirevol4u1t2i
+.antirevolutio1n5a
+.antirevolu1t2io
+.antirevolutio2n
+.antirevolution2a2r
+.ap8o8t8h9e9o9s8e8s.
+.ap4ot
+.ap4oth
+.apoth2e
+.apotheos4
+.apotheos1e4s
+.ap8o8t8h9e9o9s8i8s.
+.apotheo1sis
+.ap9p8e8n9d8i8x.
+.a4p1p
+.ap2pe
+.ap3pen
+.ar9c8h8i9m8e9d8e8a8n.
+.ar1c
+.ar2ch
+.archi2med
+.archimedea2n
+.ar9c8h8i9p8e8l9a8g8o.
+.arch2i4p
+.archipe4
+.archipe4la
+.archipela2go
+.ar9c8h8i9p8e8l9a9g8o8s.
+.ar9c8h8i8v8e.
+.arch2i2v
+.ar9c8h8i8v8e8s.
+.archiv4e2s
+.ar9c8h8i8v9i8n8g.
+.archiv1in
+.archi4ving
+.ar9c8h8i8v9i8s8t.
+.ar9c8h8i8v9i8s8t8s.
+.archivis4t1s2
+.ar9c8h8e9t8y8p9a8l.
+.arche2
+.arche4t
+.arche1ty
+.archety1pa
+.archetyp4al
+.ar9c8h8e9t8y8p9i9c8a8l.
+.archetyp3i
+.archetypi1ca
+.ar8c9t8a8n9g8e8n8t.
+.ar2c1t
+.arct5ang
+.arc1ta
+.arcta2n
+.arctan1gen
+.arctangen1t
+.ar8c9t8a8n9g8e8n8t8s.
+.arctangen4t4s2
+.as9s8i8g8n9a9b8l8e.
+.as1si
+.as4sig1n4a
+.ass2ig
+.assig2n1a2b
+.assignab2l2
+.as9s8i8g8n9o8r.
+.assig1no
+.as9s8i8g8n9o8r8s.
+.assigno4rs2
+.as9s8i8s8t9a8n8t9s8h8i8p.
+.as1sis
+.assis1ta
+.assista2n
+.assistan1t
+.assistan4t4s2
+.assistants2h4
+.assistant3sh2i4p
+.as9s8i8s8t9a8n8t9s8h8i8p8s.
+.assistantshi2p1s2
+.as8y8m8p9t8o9m8a8t8i8c.
+.as4y
+.asy4m1p
+.asym2p1t
+.asymp1to
+.asympto2ma
+.asymptomat1ic
+.as9y8m8p9t8o8t9i8c.
+.as8y8n9c8h8r8o9n8o8u8s.
+.asyn3c4hr4
+.asyn2ch
+.asynchro2n
+.asynchro1nou2
+.asynchrono2us
+.at8h9e8r9o9s8c8l8e9r8o9s8i8s.
+.4ath
+.ath2e
+.ath2ero
+.atheros2c
+.atheroscle5
+.atheros1c4l4
+.ath2eroscl4ero
+.atherosclero1sis
+.at9m8o8s9p8h8e8r8e.
+.a4t1m
+.at1mo
+.atmos2
+.atmo3sp
+.atmos2phe
+.atmo3sph4er
+.at9m8o8s9p8h8e8r8e8s.
+.at9t8r8i8b9u8t8e8d.
+.a4t3t2
+.attr4ib
+.attribu2t1ed
+.at9t8r8i8b9u8t9a8b8l8e.
+.attri4bu1ta
+.attribu2ta4b
+.attributab2l2
+.au9t8o9m8a9t8i8o8n.
+.au1to
+.auto2ma
+.automa1t2io
+.automatio2n
+.au9t8o8m9a9t8o8n.
+.automa1to
+.automato2n
+.au9t8o8m9a9t8a.
+.automa2ta
+.au9t8o9n8u8m9b8e8r9i8n8g.
+.au5to2n
+.auton5um
+.autonu4m1b
+.autonumber1i
+.autonumberin4g
+.au9t8o8n9o9m8o8u8s.
+.au4tono
+.autono4mo
+.autono3mo2us
+.autonomou2
+.au8t8o9r8o8u8n8d9i8n8g.
+.autorou2
+.autoroun2d
+.autoround1in
+.av9o8i8r9d8u9p8o8i8s.
+.avoi4
+.avo4ir
+.avoir1du
+.avoir4dup
+.avoirdupoi2
+.ba8n8d9l8e8a8d8e8r.
+.b4and
+.ban1dl
+.bandle2a
+.bandlea2d1
+.ba8n8d9l8e8a8d8e8r8s.
+.bandleade4r5s2
+.ba8n8k9r8u8p8t.
+.ba4nk2
+.bankru2p1t
+.ba8n8k9r8u8p8t9c8y.
+.bankrup4tc
+.bankrupt1cy
+.ba8n8k9r8u8p8t9c8i8e8s.
+.bankrupt1ci
+.bankruptc2ie4
+.ba8r9o8n8i8e8s.
+.b2a2r
+.ba5roni
+.baro2n
+.baron2ie4
+.ba8s8e9l8i8n8e9s8k8i8p.
+.basel2i
+.base1l4ine
+.baseli1nes
+.baselinesk2
+.baselinesk1i
+.baselinesk2i4p
+.ba9t8h8y8m9e9t8r8y.
+.1bat
+.b4ath
+.bathyme4
+.bathym4etr
+.bathyme3try
+.ba8t8h8y9s8c8a8p8h8e.
+.bathy2s
+.bathys4c
+.bathysca4p
+.bathys1ca
+.be8a8n9i8e8s.
+.bea2n
+.bea3nies
+.bean2ie4
+.be9h8a8v9i8o8u8r.
+.be1h4
+.behav1i
+.behavi1ou2
+.behav2io
+.behavi4our
+.be9h8a8v9i8o8u8r8s.
+.behaviou4rs2
+.be8v8i8e8s.
+.be1vi
+.bev2ie4
+.bi8b9l8i9o8g9r8a9p8h8y9s8t8y8l8e.
+.bi2b
+.bi1b2l2
+.bib3li
+.bibli5og
+.bibl2io
+.biblio2gr
+.biblio4g3ra1phy
+.bibliography2s
+.bibliographys1t
+.bibliographys2ty
+.bibliographys2tyl
+.bi9d8i8f9f8e8r9e8n9t8i8a8l.
+.b2i4d
+.bi2di
+.bid1if
+.bidi4f1f
+.bidiffer1
+.bidiffer3en1t
+.bidifferent2i
+.bidifferen1t2i1a
+.bidifferenti2al
+.bi8g9g8e8s8t.
+.b2ig
+.bi4g1g2
+.big2ge
+.bi8l8l9a8b8l8e.
+.1bil
+.bill5ab
+.bil1l
+.billab2l2
+.bi8o9m8a8t8h9e9m8a8t9i8c8s.
+.b2io
+.bio4m
+.bio1ma
+.biom4ath3
+.biomath5em
+.biomath2e
+.biomathe1ma
+.biomathemat1ic
+.biomathemati4c3s2
+.bi8o9m8e8d9i9c8a8l.
+.bio2me
+.bio2med
+.biom4edi
+.biomed3i1ca
+.bi8o9m8e8d9i9c8i8n8e.
+.biomed2i1ci
+.biomedi2cin
+.biomedic2ine
+.bi8o9r8h8y8t8h8m8s.
+.biorh4
+.biorhyt4h1m
+.biorhyth4m1s2
+.bi8t9m8a8p.
+.bi2t
+.bi4t1m
+.bit1ma
+.bit4map
+.bi8t9m8a8p8s.
+.bitma2p1s2
+.bl8a8n8d9e8r.
+.b2l2
+.b3l4and
+.bla2n
+.blan1de
+.bl8a8n8d9e8s8t.
+.blande4s2
+.bl8i8n8d9e8r.
+.bl4ind
+.blin1de
+.bl8o8n8d8e8s.
+.b4lo
+.blo2n
+.bl2ond
+.blon1de
+.blondes2
+.bl8u8e9p8r8i8n8t.
+.bluepr2
+.blueprin4t3
+.bl8u8e9p8r8i8n8t8s.
+.blueprin4t4s2
+.bo9l8o8m9e9t8e8r.
+.bolo2me
+.bolo4met
+.bolome1te
+.bo8o8k9s8e8l8l9e8r.
+.3boo2
+.bo2o4k
+.boo4k1s2
+.booksel1l
+.booksel2le
+.bo8o8k9s8e8l8l9e8r8s.
+.bookselle4r1s2
+.bo8o8l9e8a8n.
+.boole2a
+.boolea2n
+.bo8o8l9e8a8n8s.
+.boolea2n1s2
+.bo8r9n8o9l8o8g9i9c8a8l.
+.borno4
+.borno3log1ic
+.bornologi1ca
+.bo8t9u9l8i8s8m.
+.bo1tu
+.botul2i
+.botuli2s1m
+.br8u8s8q8u8e8r.
+.br2us
+.brusqu2
+.brus3quer
+.bu8f9f8e8r.
+.buf4fer1
+.bu4f1f
+.bu8f9f8e8r8s.
+.buffe4r1s2
+.bu8s8i8e8r.
+.bus5ie4
+.b2us
+.bu8s8i8e8s8t.
+.busi1est
+.bu8s8s8i8n8g.
+.bu2ss
+.bus1si
+.bus2s1in
+.buss3ing
+.bu8t8t8e8d.
+.but2t1ed
+.bu8z8z9w8o8r8d.
+.bu4z1z2
+.buzz1wo2
+.bu8z8z9w8o8r8d8s.
+.buzzwor2d1s2
+.ca9c8o8p8h9o9n8y.
+.ca1co
+.cac2oph
+.cacopho5ny
+.cacopho2n
+.ca9c8o8p8h9o9n8i8e8s.
+.caco5phoni
+.cacophon2ie4
+.ca8l8l9e8r.
+.cal1l
+.cal2le
+.ca8l8l9e8r8s.
+.calle4r1s2
+.ca8m9e8r8a9m8e8n.
+.cam5er1a
+.camera1men
+.ca8r8t9w8h8e8e8l.
+.cartw4
+.ca8r8t9w8h8e8e8l8s.
+.cartwhee2l1s2
+.ca9t8a8r8r8h8s.
+.ca2ta
+.cat2a2r
+.catar1r4
+.catarrh4
+.catarr4h1s2
+.ca8t9a9s8t8r8o8p8h9i8c.
+.catas1t4r
+.catastr2oph
+.catastroph1ic
+.ca8t9a9s8t8r8o8p8h9i9c8a8l8l8y.
+.catastrophi1ca
+.catastrophical1l
+.catastrophical1ly
+.ca8t9e9n8o8i8d.
+.cat4eno
+.catenoi2
+.cateno2id
+.ca8t9e9n8o8i8d8s.
+.catenoi2d1s2
+.ca8u9l8i9f8l8o8w9e8r.
+.cau4l2
+.caul2i
+.cauli4f4l2
+.cauliflow1er
+.ch8a8p9a8r9r8a8l.
+.chap2a2r4
+.cha1pa
+.chapar1r4
+.ch8a8r9t8r8e8u8s8e.
+.ch2a2r
+.chartr4eu2
+.chartre2us4
+.ch8e8m8o9t8h8e8r9a8p8y.
+.che2
+.che1mo
+.chem4oth3
+.chemoth2e
+.chemoth4er1a
+.chemothera3p
+.ch8e8m8o9t8h8e8r9a9p8i8e8s.
+.chemotherap2ie4
+.ch8l8o8r8o9m8e8t8h9a8n8e.
+.c4h1l4
+.ch2lo
+.chloro2me
+.chloro4met
+.chlorometha2n4
+.ch8l8o8r8o9m8e8t8h9a8n8e8s.
+.chlorometha1nes
+.ch8o9l8e8s9t8e8r8i8c.
+.3cho2
+.c3hol4e
+.choles2
+.choles1ter1i
+.ci8g9a9r8e8t8t8e.
+.c2ig
+.ci1ga
+.cig2a2r
+.cigare4t3t2
+.ci8g9a9r8e8t8t8e8s.
+.cigaret4tes
+.ci8n8q8u8e9f8o8i8l.
+.2cin
+.cin1q
+.cinqu2
+.cinque1f
+.cinque1fo
+.cinquefoi2
+.co9a8s8s8o9c8i8a9t8i8v8e.
+.c4oa
+.coa2ss
+.coas1so
+.coasso1ci
+.coasso3c2i1a
+.coassoci4a1t2iv
+.co9g8n8a8c.
+.2cog
+.cog1n4a
+.co9g8n8a8c8s.
+.cogna4c3s2
+.co9k8e8r9n8e8l.
+.c2ok
+.cok1er
+.coker3nel
+.co9k8e8r9n8e8l8s.
+.cokerne2l1s2
+.co8l9l8i8n9e8a9t8i8o8n.
+.col1l
+.coll2i
+.col2lin4
+.col1l4ine
+.collin3ea
+.collinea2t
+.collinea1t2io
+.collineatio2n
+.co8l9u8m8n8s.
+.colu4m1n
+.colum2n1s2
+.co8m9p8a8r9a8n8d.
+.co4m1p
+.compara5
+.com1pa
+.comp2a2r
+.compara2n
+.compar4and
+.co8m9p8a8r9a8n8d8s.
+.comparan2d1s2
+.co8m9p8e8n9d8i8u8m.
+.compendi1u
+.co8m9p8o9n8e8n8t9w8i8s8e.
+.compo2n
+.compo3nen
+.componen1t
+.componentw4
+.componentwis4
+.componentwi2
+.component3w4ise
+.co8m8p9t8r8o8l9l8e8r.
+.comp4tr
+.com2p1t
+.comptrol1l
+.comptrol2le
+.co8m8p9t8r8o8l9l8e8r8s.
+.comptrolle4r1s2
+.co8n9f8o8r8m9a8b8l8e.
+.co2n
+.con3f
+.con1fo
+.confo2r
+.confor1m
+.confor1ma
+.confor2mab
+.conformab2l2
+.co8n9f8o8r8m9i8s8t.
+.confor2mi
+.conform2is
+.co8n9f8o8r8m9i8s8t8s.
+.conformis4t1s2
+.co8n9f8o8r8m9i8t8y.
+.confor3mit
+.conformi1ty
+.co8n9g8r8e8s8s.
+.con3g
+.con1gr
+.congr2e2ss
+.co8n9g8r8e8s8s8e8s.
+.congress1e4s
+.co8n9t8r8i8b9u8t8e.
+.con5t
+.contr4ib
+.co8n9t8r8i8b9u8t8e8s.
+.co8n9t8r8i8b9u8t8e8d.
+.contribu2t1ed
+.co9r8e9l8a9t8i8o8n.
+.core1la
+.corela1t2io
+.corelatio2n
+.co9r8e9l8a9t8i8o8n8s.
+.corelatio2n3s2
+.co9r8e9l8i9g8i8o8n9i8s8t.
+.core1l2i
+.corel2ig
+.corel4igi
+.coreli5g2io
+.coreligion3i
+.coreligio2n
+.coreligion1is
+.co9r8e9l8i9g8i8o8n9i8s8t8s.
+.coreligionis4t1s2
+.co9r8e9o8p9s8i8s.
+.core1o
+.coreo2p1s2
+.coreop1sis
+.co9r8e9s8p8o8n9d8e8n8t.
+.core1sp
+.cores4po2n
+.coresp2ond
+.corespon1de
+.corespon1den
+.coresponden1t
+.co9r8e9s8p8o8n9d8e8n8t8s.
+.coresponden4t4s2
+.co9s8e9c8a8n8t.
+.cos4e
+.cose1ca
+.coseca2n
+.cosecan1t
+.co9t8a8n9g8e8n8t.
+.co4ta2n
+.co1ta
+.cot2ang
+.cotan1gen
+.cotangen1t
+.co8u8r9s8e8s.
+.cou2
+.cou4rs2
+.cour2se
+.cours3e4s
+.co9w8o8r8k9e8r.
+.co4wo2
+.cowork1er
+.co9w8o8r8k9e8r8s.
+.coworke4r1s2
+.cr8a8n8k9c8a8s8e.
+.cra2n
+.cra4nk2
+.crank1ca
+.cr8a8n8k9s8h8a8f8t.
+.cran4k1s2
+.cranks2h
+.cranksha2f
+.cranksha2ft
+.cr8o8c9o9d8i8l8e.
+.cr2oc
+.cro4cod
+.cro1co
+.cr8o8c9o9d8i8l8e8s.
+.crocodiles2
+.cr8o8s8s9h8a8t8c8h.
+.cro2s4s
+.cross2h
+.crossha4tc
+.crosshat4ch
+.cr8o8s8s9h8a8t8c8h8e8d.
+.crosshatche2
+.crosshat4ch4ed
+.cr8o8s8s9o8v8e8r.
+.cros1so
+.cros4sov
+.cr8y8p9t8o9g8r8a8m.
+.cry2p1t
+.cryp1to
+.crypto2gr
+.cr8y8p9t8o9g8r8a8m8s.
+.cryptogra4m1s2
+.cu8f8f9l8i8n8k.
+.c4uf
+.cu4f1f
+.cuff4l2
+.cufflin4
+.cuffl4i4nk2
+.cu8f8f9l8i8n8k8s.
+.cufflin4k1s2
+.cu9n8e8i9f8o8r8m.
+.3cun
+.cu2ne
+.cunei2
+.cunei1fo
+.cuneifo2r
+.cuneifor1m
+.cu8s9t8o8m9i8z9a9b8l8e.
+.1c2us
+.cus1to
+.custom2iz
+.customiza1
+.customiz5a2b
+.customizab2l2
+.cu8s9t8o8m9i8z8e.
+.customi2ze
+.cu8s9t8o8m9i8z8e8s.
+.cu8s9t8o8m9i8z8e8d.
+.da8c8h8s9h8u8n8d.
+.1d2a
+.da2ch4
+.dac4h1s2
+.dach4s2h
+.da8m9s8e8l9f8l8y.
+.da2m2
+.da4m1s2
+.dam5se2l2f
+.damself4l2
+.damself2ly5
+.da8m9s8e8l9f8l8i8e8s.
+.damselfl2ie4
+.da8c8t8y8l9o9g8r8a8m.
+.da2c1t
+.dac1ty
+.dac2tyl
+.dacty3lo
+.dactylo1gr
+.da8c8t8y8l9o9g8r8a8p8h.
+.da8t8a9b8a8s8e.
+.3dat
+.da2ta
+.da2tab
+.da8t8a9b8a8s8e8s.
+.databas1e4s
+.da8t8a9p8a8t8h.
+.dat5ap
+.datap5at
+.data1pa
+.datap4ath
+.da8t8a9p8a8t8h8s.
+.datapa2t4h1s2
+.da8t8e9s8t8a8m8p.
+.dat3est
+.dates1ta
+.datesta4m1p
+.da8t8e9s8t8a8m8p8s.
+.datestam2p1s2
+.de9c8l8a8r9a8b8l8e.
+.de4cl2a2r
+.decla2rab
+.declarab2l2
+.de9f8i8n9i9t8i8v8e.
+.de1f
+.de1fi
+.de2fin
+.def2ini
+.defin2it
+.defini1ti
+.defini1t2iv
+.de9l8e8c9t8a9b8l8e.
+.d5elec
+.dele2c1t
+.delec2ta4b
+.delec1ta
+.delectab2l2
+.de8m8i9s8e8m8i9q8u8a9v8e8r.
+.de4m2is
+.dem4ise
+.demisemi3qua
+.demisemiqu2
+.demisemiqua5v4
+.de8m8i9s8e8m8i9q8u8a9v8e8r8s.
+.demisemiquave4r1s2
+.de9m8o8c9r8a9t8i8s8m.
+.de4mocr
+.democrati2s4m
+.de8m8o8s.
+.demos2
+.de9r8i8v9a9t8i8v8e.
+.der2i4v
+.de4ri1va
+.deri3vat
+.der2iva1t2iv
+.de9r8i8v9a9t8i8v8e8s.
+.derivativ4e2s
+.di8a9l8e8c9t8i8c.
+.1d4i3a
+.di2al
+.di2ale
+.diale2c1t
+.di8a9l8e8c9t8i8c8s.
+.dialecti4c3s2
+.di8a9l8e8c9t8i9c8i8a8n.
+.dialect2i1ci
+.d2i1alecti3c2i1a
+.dialectici2a2n
+.di8a9l8e8c9t8i9c8i8a8n8s.
+.dialecticia2n1s2
+.di9c8h8l8o8r8o9m8e8t8h9a8n8e.
+.d4i2ch
+.dic4h1l4
+.dich2lo
+.dichloro2me
+.dichloro4met
+.dichlorometha2n4
+.di8f9f8r8a8c8t.
+.d1if
+.dif4fr
+.di4f1f
+.diffra2c1t
+.di8f9f8r8a8c8t8s.
+.diffrac4t1s2
+.di8f9f8r8a8c9t8i8o8n.
+.diffrac1t2io
+.diffractio2n
+.di8f9f8r8a8c9t8i8o8n8s.
+.diffractio2n3s2
+.di8r8e8r.
+.d4ir2
+.di1re
+.dir1er4
+.di8r8e9n8e8s8s.
+.dire1nes
+.diren2e2ss
+.di8s9p8a8r9a8n8d.
+.dis1
+.dis1p
+.di2s1pa
+.disp2a2r
+.dispara2n
+.dispar4and
+.di8s9p8a8r9a8n8d8s.
+.disparan2d1s2
+.di8s9t8r8a8u8g8h8t9l8y.
+.d4is3t
+.dist4r
+.dis1tra
+.distraugh3
+.distraugh2tl
+.distraught1ly
+.di8s9t8r8i8b9u8t8e.
+.distr4ib
+.di8s9t8r8i8b9u8t8e8s.
+.di8s9t8r8i8b9u8t8e8d.
+.distribu2t1ed
+.do8u9b8l8e9s8p8a8c8e.
+.dou2
+.dou3b2l2
+.dou5ble1sp
+.doubles2
+.double2s1pa
+.doublespa4ce
+.do8u9b8l8e9s8p8a8c9i8n8g.
+.doublesp4a2ci
+.doublespa2c1in
+.doublespac1ing
+.do8l8l9i8s8h.
+.dol1l
+.doll2i
+.dollis2h
+.dr8i8f8t9a8g8e.
+.1dr
+.dr4i2ft
+.drif1ta
+.dr8i8v9e8r8s.
+.dr2iv
+.drive4r1s2
+.dr8o8m9e9d8a8r8y.
+.dro2me
+.dro2med
+.drom2e2d2a
+.drome4dary
+.dromed2a2r
+.dr8o8m9e9d8a8r8i8e8s.
+.dromedar1i
+.dromedar2ie4
+.du9o8p9o9l8i8s8t.
+.duopol2i
+.du9o8p9o9l8i8s8t8s.
+.duopolis4t1s2
+.du9o8p9o8l8y.
+.duopo2ly
+.dy8s9l8e8x8i8a.
+.d2y
+.dys1l2
+.dys2le
+.dyslex3i
+.dyslex2i5a
+.dy8s9l8e8c9t8i8c.
+.dysle2c1t
+.ea8s8t9e8n8d9e8r8s.
+.east3
+.eas3ten
+.eas3tend
+.easten1de
+.eastende4r5s2
+.ec8o9n8o8m9i8c8s.
+.e1co
+.eco2n
+.eco3nomic
+.economi4c3s2
+.ec8o8n9o9m8i8s8t.
+.econom2is
+.ec8o8n9o9m8i8s8t8s.
+.economis4t1s2
+.ei9g8e8n9c8l8a8s8s.
+.ei2
+.e2ig2
+.ei1gen
+.eigen1c4l4
+.eigencla2ss
+.ei9g8e8n9c8l8a8s8s8e8s.
+.eigenclass1e4s
+.ei9g8e8n9v8a8l9u8e.
+.eigen1v2
+.eigen1va
+.eigenval1u
+.ei9g8e8n9v8a8l9u8e8s.
+.el8e8c8t8r8o9m8e8c8h8a8n9i9c8a8l.
+.5elec
+.ele2c1t
+.electro2me
+.electrome2ch
+.electrome5cha4n1ic
+.electromecha2n
+.electromechani1ca
+.el8e8c8t8r8o9m8e8c8h8a8n8o9a8c8o8u8s8t8i8c.
+.electromechano4
+.electromechan4oa
+.electromechanoa1co
+.electromechanoacou2
+.electromechanoaco2us
+.electromechanoacoust2i
+.electromechanoacous1tic
+.el8i8t9i8s8t.
+.el2i
+.el1it
+.eli1ti
+.el4itis
+.el8i8t9i8s8t8s.
+.elitis4t1s2
+.en9t8r8e9p8r8e9n8e8u8r.
+.en1t
+.entrepr2
+.entrepren4eu
+.en9t8r8e9p8r8e9n8e8u8r9i8a8l.
+.entrepreneur2i3a
+.entrepreneuri2al
+.ep9i9n8e8p8h9r8i8n8e.
+.epi2n
+.ep2ine
+.epinep4hr4
+.ep2inephr2in4e
+.eq8u8i9v8a8r8i9a8n8t.
+.equ2iv3
+.equi1va
+.equiv2a2r
+.equivar1i
+.equivar3i2a2n
+.equivar2i3a
+.equivar4ian4t
+.eq8u8i9v8a8r8i9a8n8c8e.
+.equivar4ianc
+.et8h9a8n8e.
+.etha2n4
+.et8h9y8l9e8n8e.
+.ev8e8r9s8i9b8l8e.
+.ev1er
+.eve4r1s2
+.ever1si
+.ever4si4b
+.eversi1b2l2
+.ev8e8r8t.
+.ev8e8r8t8s.
+.ever4t1s2
+.ev8e8r8t9e8d.
+.ever2t1ed
+.ev8e8r8t9i8n8g.
+.ever1ti
+.ever2t1in
+.ex9q8u8i8s9i8t8e.
+.exqu2
+.exq2ui2
+.exquis2ite
+.ex9t8r8a9o8r9d8i9n8a8r8y.
+.ex1t2
+.ex1tra
+.extr4ao
+.extraord2i
+.extraord1in4
+.extraor1di1na
+.extraordin2a2r
+.fa8l8l9i8n8g.
+.1fa
+.fal1l
+.fall2i
+.fal2lin4
+.fe8r8m8i9o8n8s.
+.fer1
+.fer3m4
+.fer4m2io
+.fermio2n
+.fermio2n3s2
+.fi9n8i8t8e9l8y.
+.1fi
+.2fin
+.f2ini
+.fin2it
+.fin2ite
+.finite1ly
+.fl8a9g8e8l9l8u8m.
+.f4l2
+.flag5el1l
+.fl8a9g8e8l9l8a.
+.flag4ella
+.fl8a8m9m8a9b8l8e8s.
+.flam1m
+.flam1ma
+.flam2mab
+.flammab2l2
+.flammables2
+.fl8e8d8g9l8i8n8g.
+.fledgl2
+.fl8o8w9c8h8a8r8t.
+.flow2ch
+.flowch2a2r
+.fl8o8w9c8h8a8r8t8s.
+.flowchar4t1s2
+.fl8u8o8r8o9c8a8r9b8o8n.
+.flu3o
+.fluo3r
+.fluor2oc
+.fluoro1ca
+.fluoroc2a2r
+.fluorocar1b
+.fluorocarb4o
+.fluorocarbo2n
+.fo8r9m8i9d8a9b8l8e.
+.for2mi
+.formi1d4a
+.form2id
+.formi2d3a4b
+.formidab2l2
+.fo8r9m8i9d8a9b8l8y.
+.formidab1ly
+.fo8r9s8y8t8h9i8a.
+.fo4rs2
+.fors4y
+.forsyth2i1a
+.fo8r8t8h9r8i8g8h8t.
+.fort4hr4
+.forthr2ig
+.fr8e8e9l8o8a8d8e8r.
+.freel4oa
+.freeloa2d3
+.fr8e8e9l8o8a8d8e8r8s.
+.freeloade4r5s2
+.fr8i8e8n8d9l8i8e8r.
+.fri2
+.fr2ie4
+.friendl2ie4
+.fr8i9v8o8l9i8t8y.
+.fr2iv
+.frivol2i
+.frivol1it
+.frivoli1ty
+.fr8i9v8o8l9i9t8i8e8s.
+.frivoli1ti
+.frivolit2ie4
+.fr8i8v9o9l8o8u8s.
+.frivolou2
+.frivolo2us
+.ga9l8a8c9t8i8c.
+.gala2c1t
+.ga8l9a8x8y.
+.ga8l9a8x9i8e8s.
+.galax3i
+.galax2ie4
+.ga8s9o8m9e9t8e8r.
+.ga1so
+.ga3som
+.gaso2me
+.gaso4met
+.gasome1te
+.ge9o9d8e8s9i8c.
+.geodes2
+.geode1si
+.geode2sic
+.ge9o9d8e8t9i8c.
+.geode1t
+.geodet1ic
+.ge8o9m8e8t9r8i8c.
+.ge3om
+.geo2me
+.geo4met
+.geom4etr
+.geo5met3ric
+.ge8o9m8e8t9r8i8c8s.
+.geome4tri4c3s2
+.ge9o9s8t8r8o8p8h8i8c.
+.geos4
+.geost4r
+.geostr2oph
+.geostroph1ic
+.ge8o9t8h8e8r9m8a8l.
+.ge4ot
+.ge4oth
+.geoth2e
+.geother3m4
+.geother1ma
+.ge9o8t9r8o9p8i8s8m.
+.geotropi2s1m
+.gn8o9m8o8n.
+.g1no
+.gno4mo
+.gno4mo2n
+.gn8o9m8o8n8s.
+.gnomo2n3s2
+.gr8a8n8d9u8n8c8l8e.
+.1gr
+.gra2n2
+.gr4and
+.gran1du
+.grandu4n
+.grandun1c4l4
+.gr8a8n8d9u8n8c8l8e8s.
+.granduncles2
+.gr8i8e8v9a8n8c8e.
+.gr2ie4
+.grie1va
+.grieva2n
+.gr8i8e8v9a8n8c8e8s.
+.gr8i8e8v9o8u8s.
+.grievou2
+.grievo2us
+.gr8i8e8v9o8u8s9l8y.
+.grievous1l2
+.grievous1ly
+.ha8i8r9s8t8y8l8e.
+.hai2
+.ha4ir
+.hai4rs2
+.hairs2ty
+.hairs2tyl
+.ha8i8r9s8t8y8l8e8s.
+.hairstyles2
+.ha8i8r9s8t8y8l9i8s8t.
+.ha8i8r9s8t8y8l9i8s8t8s.
+.hairstylis4t1s2
+.ha8l8f9s8p8a8c8e.
+.ha2lf
+.hal2f3s
+.half2s1pa
+.halfspa4ce
+.ha8l8f9s8p8a8c8e8s.
+.ha8l8f9w8a8y.
+.ha8r9b8i8n9g8e8r.
+.h2a2r
+.har1b
+.harbi2
+.har2bin
+.harb4inge
+.ha8r9b8i8n9g8e8r8s.
+.harbinge4r1s2
+.ha8r9l8e9q8u8i8n.
+.har4le4
+.har1l
+.harle1q
+.harlequ2
+.harleq2ui2
+.harlequi4n
+.ha8r9l8e9q8u8i8n8s.
+.harlequ2i2n1s2
+.ha8t8c8h9e8r8i8e8s.
+.ha4tc
+.hat4ch
+.hatche2
+.hatcher1i
+.hatcher2ie4
+.he8m8i9d8e8m8i9s8e8m8i9q8u8a9v8e8r.
+.hem2id
+.hemid4em
+.hemide4m2is
+.hemidem4ise
+.hemidemisemi3qua
+.hemidemisemiqu2
+.hemidemisemiqua5v4
+.he8m8i9d8e8m8i9s8e8m8i9q8u8a9v8e8r8s.
+.hemidemisemiquave4r1s2
+.he9m8o9g8l8o9b8i8n.
+.hemo4g
+.he1mo
+.hemo4gl2
+.hemo3glo
+.hemoglo1bi
+.hemoglo2bin
+.he9m8o9p8h8i8l9i8a.
+.hem2oph
+.hemoph4il2
+.hemophil1i
+.hemophil3i1a
+.he9m8o9p8h8i8l9i8a8c.
+.he9m8o9p8h8i8l9i8a8c8s.
+.hemophilia4c3s2
+.he8m8o9r8h8e9o8l9o8g8y.
+.hemo2r
+.hemorh4
+.hemorhe3ol
+.hemorheol1o1gy
+.he9p8a8t9i8c.
+.hep5
+.he2pa
+.hepat1ic
+.he8r9m8a8p8h9r8o9d8i8t8e.
+.her3m4
+.her1ma
+.her4map
+.hermap4hr4
+.hermaphrod2ite
+.he8r9m8a8p8h9r8o9d8i8t9i8c.
+.hermaphrod2i1ti
+.hermaphrod4i2tic
+.he9r8o8e8s.
+.hero4e
+.he8x8a9d8e8c9i9m8a8l.
+.hex1a
+.hexa2d
+.hexade1c2i
+.hexade2c3im
+.hexadeci1ma
+.ho9l8o9n8o9m8y.
+.holo2n
+.holon3o3my
+.ho9m8e8o9m8o8r9p8h8i8c.
+.ho2me3
+.homeo1mo
+.homeomo2r
+.homeomor1p
+.homeomorp4h4
+.homeomorph1ic
+.ho9m8e8o9m8o8r9p8h8i8s8m.
+.homeomorphi2s1m
+.ho9m8o9t8h8e8t8i8c.
+.ho1mo
+.hom4oth3
+.homoth2e
+.homo3the4t
+.homothet1ic
+.ho8r8s8e9r8a8d9i8s8h.
+.hor4se
+.ho4rs2
+.horser1a
+.horsera2d
+.horser2adi
+.horseradis1
+.horseradis2h
+.ho8t9b8e8d.
+.ho2t1b
+.hot4be2d
+.ho8t9b8e8d8s.
+.hotbe2d1s2
+.hy9d8r8o9t8h8e8r9m8a8l.
+.hy1d
+.hy1dr
+.hydro4th2e
+.hydr4oth
+.hydrother3m4
+.hydrother1ma
+.hy9p8o9t8h8a8l9a9m8u8s.
+.hy3po
+.hyp4ot
+.hyp4oth
+.hypotha3la
+.hypothala3m
+.hypothala1mu
+.hypothalam2us
+.id8e8a8l8s.
+.ide3a4l
+.idea2l1s2
+.id8e8o9g8r8a8p8h8s.
+.ideo2g
+.ideo1gr
+.ideogra4p4h1s2
+.id8i8o9s8y8n9c8r8a8s8y.
+.i2di
+.i1d3io
+.idi4os
+.idios4y
+.idiosyn1cr
+.idiosyncr2as
+.idiosyncras4y
+.id8i8o9s8y8n9c8r8a9s8i8e8s.
+.idiosyncras2ie4
+.id8i8o9s8y8n9c8r8a8t8i8c.
+.idiosyn5crat1ic
+.id8i8o9s8y8n9c8r8a8t9i9c8a8l9l8y.
+.idiosyncrati1ca
+.idiosyncratical1l
+.idiosyncratical1ly
+.ig9n8i8t9e8r.
+.2ig
+.ig1ni
+.ign2it
+.ign2ite
+.ig9n8i8t9e8r8s.
+.ignite4r1s2
+.ig9n8i9t8o8r.
+.ign3itor
+.igni1to
+.ig8n8o8r8e9s8p8a8c8e8s.
+.ig1no
+.ignore1sp
+.ignore2s1pa
+.ignorespa4ce
+.im9p8e8d9a8n8c8e.
+.im2p2ed
+.imp2e2d2a
+.impeda2n
+.im9p8e8d9a8n8c8e8s.
+.in9d8u9b8i9t8a9b8l8e.
+.4ind
+.in1du
+.indu1b4i
+.indubi2t
+.indubi1ta
+.indubi2tab
+.indubitab2l2
+.in9f8i8n9i8t8e9l8y.
+.in3f
+.in1fi
+.in2fin
+.inf2ini
+.infin2it
+.infin2ite
+.infinite1ly
+.in9f8i8n9i9t8e8s9i9m8a8l.
+.infinit4es
+.infinite1si
+.infinite2s5im
+.infinitesi1ma
+.in9f8r8a9s8t8r8u8c9t8u8r8e.
+.infr2as
+.infras1t4r
+.infrastru2c1t
+.infrastructu4r
+.infrastruc1tu
+.infrastruc3ture
+.in9f8r8a9s8t8r8u8c9t8u8r8e8s.
+.in9s8t8a8l8l9e8r.
+.ins2ta2l
+.ins1ta
+.instal1l
+.instal2le
+.in9s8t8a8l8l9e8r8s.
+.installe4r1s2
+.in9t8e8r9d8i8s9c8i9p8l8i9n8a8r8y.
+.in1t
+.in5ter3d
+.interd2i
+.interdis1
+.interd2is1c
+.interdis1ci
+.interdisc2ip
+.interdisci1p2l2
+.interdiscipli4n
+.interdiscipl4i1na
+.interdisciplin2a2r
+.in9t8e8r9g8a9l8a8c9t8i8c.
+.interg2
+.inter1ga
+.intergala2c1t
+.in9u8t8i8l8e.
+.in1u
+.in4u1t2i
+.in9u8t8i8l9i9t8y.
+.inutil1i
+.inut2il1it
+.inutili1ty
+.ir9r8e9d8u8c9i8b8l8e.
+.ir2r2ed
+.irre1du
+.irredu2c
+.irreduci4b
+.irredu1ci
+.irreduci1b2l2
+.ir9r8e9d8u8c9i8b8l8y.
+.irreducib1ly
+.ir9r8e8v9o9c8a9b8l8e.
+.irrev2
+.irre5voc
+.irrevo1ca
+.irrevoca1b2l2
+.is8o8t9r8o8p8y.
+.i2so
+.isotropy5
+.is8o9t8r8o8p9i8c.
+.isotrop3ic
+.it8i8n9e8r9a8r8y.
+.i1ti
+.i2t1in
+.it2ine
+.itin4er4a2r
+.itin1er
+.itiner1a
+.it8i8n9e8r9a8r9i8e8s.
+.itinerar1i
+.itinerar2ie4
+.je9r8e9m8i9a8d8s.
+.1je
+.jerem2i3a
+.jeremia2d
+.jeremia2d1s2
+.ke8y9n8o8t8e.
+.ke8y9n8o8t8e8s.
+.keyno4tes
+.ke8y9s8t8r8o8k8e.
+.keys4
+.keys1t
+.keyst4r
+.keystr2ok2
+.ke8y9s8t8r8o8k8e8s.
+.keystrokes4
+.ki8l8n9i8n8g.
+.k1i
+.k4i2l1n2
+.kiln1in
+.kilnin4g
+.la8c9i9e8s8t.
+.l4a2ci4
+.la3c2ie4
+.laci1est
+.la8m9e8n9t8a9b8l8e.
+.la1men
+.la3men1t
+.lamen2ta4b
+.lamen1ta
+.lamentab2l2
+.la8n8d9s8c8a8p9e8r.
+.3l4and
+.la2n
+.lan2d1s2
+.landsca4p
+.lands1ca
+.landsca5per
+.la8n8d9s8c8a8p9e8r8s.
+.landscape4r1s2
+.la8r9c8e9n8y.
+.l2a2r
+.lar1c
+.lar2ce
+.lar1cen4
+.la8r9c8e9n9i8s8t.
+.lar4ceni
+.le8a8f9h8o8p9p8e8r.
+.le2a
+.lea2f
+.lea4fh
+.leafho4p1p
+.leafhop2pe
+.leafhop3per
+.le8a8f9h8o8p9p8e8r8s.
+.leafhoppe4r1s2
+.le8t9t8e8r9s8p8a8c9i8n8g.
+.le4t3t2
+.lette4r1s2
+.letter1sp
+.letter2s1pa
+.lettersp4a2ci
+.letterspa2c1in
+.letterspac1ing
+.li8f8e9s8p8a8n.
+.life1sp
+.life2s1pa
+.lifespa4n
+.li8f8e9s8p8a8n8s.
+.lifespa2n1s2
+.li8f8e9s8t8y8l8e.
+.lifes2ty
+.lifes2tyl
+.li8f8e9s8t8y8l8e8s.
+.lifestyles2
+.li8g8h8t9w8e8i8g8h8t.
+.3ligh
+.lightw4
+.lightwei2
+.l2ightwe2ig2
+.li8m9o8u9s8i8n8e8s.
+.li4mo
+.li3mo2us
+.limou2
+.limou2s1in
+.limous2ine
+.limousi1nes
+.li8n8e9b8a8c8k8e8r.
+.1l4ine
+.lin2e2b
+.lineback1
+.lineback1er
+.li8n8e9s8p8a8c8i8n8g.
+.li1nes
+.li4ne1sp
+.line2s1pa
+.linesp4a2ci
+.linespa2c1in
+.linespac1ing
+.li9o8n9e8s8s.
+.lio2n
+.lio1nes
+.lion2e2ss
+.li8t8h9o9g8r8a8p8h8e8d.
+.l2ith
+.litho4g
+.litho1gr
+.lithograph4ed
+.li8t8h9o9g8r8a8p8h8s.
+.lithogra4p4h1s2
+.lo9b8o8t9o8m8y.
+.lobo4to
+.loboto3my
+.lo9b8o8t9o8m9i8z8e.
+.lobotom2iz
+.lobotomi2ze
+.lo8g8e8s.
+.lo1ge
+.lo8n8g9e8s8t.
+.5long
+.lo2n
+.lo9q8u8a8c9i8t8y.
+.lo1q
+.loqu2
+.loquac4
+.loqu4a2ci
+.loqua2c1it
+.loquaci1ty
+.lo8v8e9s8t8r8u8c8k.
+.4lov
+.lov4e2s
+.lov2est4r
+.lovestruc5
+.lovestruck1
+.ma8c8r8o9e8c8o9n8o8m8i8c8s.
+.macro4e
+.macroe1co
+.macroeco2n
+.macroeco3nomic
+.macroeconomi4c3s2
+.ma8l9a9p8r8o8p9i8s8m.
+.malapr2
+.malapropi2s1m
+.ma8l9a9p8r8o8p9i8s8m8s.
+.malaprop4is4m1s2
+.ma8n9s8l8a8u8g8h9t8e8r.
+.ma2n1s2
+.man2s1l2
+.manslaugh3
+.ma8n9u9s8c8r8i8p8t.
+.man2us
+.manusc2
+.manuscri2
+.manuscr2ip
+.manuscri2p1t
+.ma8r9g8i8n9a8l.
+.marg2
+.margi4n
+.margi1na
+.ma8t8h9e9m8a9t8i9c8i8a8n.
+.m4ath3
+.math5em
+.math2e
+.1mathe1ma
+.mathemat1ic
+.mathemat2i1ci
+.mathemati3c2i1a
+.mathematici2a2n
+.ma8t8h9e9m8a9t8i9c8i8a8n8s.
+.mathematicia2n1s2
+.ma8t8t8e8s.
+.mat5te
+.ma4t3t2
+.mat4tes
+.me8d9i8c9a8i8d.
+.2med
+.m4edi
+.med3i1ca
+.medicai2
+.medica2id
+.me8d8i9o8c8r8e.
+.me1d2io
+.mediocre3
+.me8d8i9o8c9r8i9t8i8e8s.
+.medi5ocrit
+.mediocri2
+.medio5cri1ti
+.mediocrit2ie4
+.me8g8a9l8i8t8h.
+.me2g
+.m4egal
+.me1ga
+.me3gal1i
+.megal1it
+.megal2ith
+.me8g8a9l8i8t8h8s.
+.megali2t4h1s2
+.me8t8a9b8o8l9i8c.
+.me4ta
+.me2ta4b
+.metabol3ic
+.metabol2i
+.me9t8a8b9o9l8i8s8m.
+.metaboli2s1m
+.me9t8a8b9o9l8i8s8m8s.
+.metabol4is4m1s2
+.me9t8a8b9o9l8i8t8e.
+.metabo5l2ite
+.metabol1it
+.me9t8a8b9o9l8i8t8e8s.
+.metabolit4es
+.me8t8a9l8a8n9g8u8a8g8e.
+.met3a2l
+.meta5la
+.metala2n
+.metal2ang
+.metalan1gu
+.metalangu4a
+.me8t8a9l8a8n9g8u8a8g8e8s.
+.me8t8a9p8h8o8r9i8c.
+.metapho4r
+.me8t8h9a8n8e.
+.metha2n4
+.me9t8r8o8p9o9l8i8s.
+.m4etr
+.metropol2i
+.me9t8r8o8p9o9l8i8s8e8s.
+.metropol4ise
+.metropolis1e4s
+.me8t9r8o9p8o8l9i9t8a8n.
+.metropol1it
+.metropoli3ta2n
+.metropoli1ta
+.me8t9r8o9p8o8l9i9t8a8n8s.
+.metropolita2n1s2
+.mi8c8r8o9e8c8o9n8o8m8i8c8s.
+.m4i1cr
+.micro4e
+.microe1co
+.microeco2n
+.microeco3nomic
+.microeconomi4c3s2
+.mi9c8r8o9f8i8c8h8e.
+.micro2fi
+.microf4i2ch
+.microfiche2
+.mi9c8r8o9f8i8c8h8e8s.
+.microfich1es
+.mi8c8r8o9o8r8g8a8n9i8s8m.
+.microo2
+.microorg2
+.microor1ga
+.microorgan5is
+.microorga2n
+.microorgani2s1m
+.mi8c8r8o9o8r8g8a8n9i8s8m8s.
+.microorgan4is4m1s2
+.mi8l8l9a8g8e.
+.m4il1l
+.mi8l9l8i9l8i8t8e8r.
+.mill2i
+.mil4l4i4l
+.millil1i
+.mill2il1it
+.millil2ite
+.mi8m8e8o9g8r8a8p8h8e8d.
+.mimeo2g
+.mimeo1gr
+.mimeograph4ed
+.mi8m8e8o9g8r8a8p8h8s.
+.mimeogra4p4h1s2
+.mi8m9i8c9r8i8e8s.
+.mim1i
+.mim4i1cr
+.mimicri2
+.mimicr2ie4
+.mi8n9i8s.
+.m2ini
+.min1is
+.mi8n8i9s8y8m9p8o9s8i8u8m.
+.minis4y
+.minisy4m1p
+.minisym1pos
+.minisympo5si4u
+.mi8n8i9s8y8m9p8o9s8i8a.
+.minisympos2i1a
+.mi9n8u8t9e8r.
+.m4in1u
+.mi9n8u8t9e8s8t.
+.mi8s9c8h8i8e9v8o8u8s9l8y.
+.m2is1c
+.mis3ch2
+.misch2ie4
+.mischievou2
+.mischievo2us
+.mischievous1l2
+.mischievous1ly
+.mi9s8e8r8s.
+.m4ise
+.mis3er
+.mise4r1s2
+.mi9s8o8g9a9m8y.
+.mi2so
+.miso1ga
+.miso2gam
+.mo8d9e8l9l8i8n8g.
+.mo2d1
+.model1l
+.modell2i
+.model2lin4
+.mo8l9e9c8u8l8e.
+.mole1cu
+.mole4cul
+.molecul4e
+.mo8l9e9c8u8l8e8s.
+.molecules2
+.mo8n9a8r8c8h8s.
+.mo1n1a
+.monar3c
+.mon2a2r
+.monar2ch
+.monarc4h1s2
+.mo8n8e8y9l8e8n9d8e8r.
+.moneylen1de
+.mo8n8e8y9l8e8n9d8e8r8s.
+.moneylende4r5s2
+.mo8n8o9c8h8r8o8m8e.
+.mono2ch4
+.monoc4hr4
+.monochro2me
+.mo8n8o9e8n9e8r9g8e8t8i8c.
+.mo3noe
+.monoen1er
+.monoenerg2
+.monoener3get
+.monoenerget1ic
+.mo8n9o8i8d.
+.monoi2
+.mono2id
+.mo8n8o9p8o8l8e.
+.mo4nop
+.mo8n8o9p8o8l8e8s.
+.monopoles2
+.mo9n8o8p9o8l8y.
+.monopo2ly
+.mo8n8o9s8p8l8i8n8e.
+.monos1p2l2
+.monospli4n
+.monosp1l4ine
+.mo8n8o9s8p8l8i8n8e8s.
+.monospli1nes
+.mo8n8o9s8t8r8o8f8i8c.
+.monos5t
+.monost4r
+.monostro2fi
+.mo9n8o8t9o9n8i8e8s.
+.mono1to
+.mo2noto2n
+.monoton2ie4
+.mo9n8o8t9o9n8o8u8s.
+.mono4tono
+.monoto1nou2
+.monotono2us
+.mo9r8o8n9i8s8m.
+.moro5n4is
+.moro2n
+.moroni2s1m
+.mo8s9q8u8i9t8o.
+.mos2
+.mosqu2
+.mosq2ui2
+.mosqui1to
+.mo8s9q8u8i9t8o8s.
+.mosquitos2
+.mo8s9q8u8i9t8o8e8s.
+.mu8d9r8o8o8m.
+.mu1dr
+.mud1room
+.mudroo2
+.mu8d9r8o8o8m8s.
+.mudroo4m1s2
+.mu8l9t8i9f8a8c9e8t8e8d.
+.5mu4lt
+.mul1ti3
+.multif2
+.multi1fa
+.multifa4ce
+.multifacet4
+.multiface2t1ed
+.mu8l9t8i9p8l8i8c9a8b8l8e.
+.mult2ip
+.multi1p2l2
+.multipli1ca
+.multiplica1b2l2
+.mu8l8t8i9u8s8e8r.
+.multi4u
+.multi2us
+.ne8o9f8i8e8l8d8s.
+.3neo
+.ne5of
+.neo2fi
+.neof2ie4
+.neofie2ld3
+.neofiel2d1s2
+.ne8o9n8a8z8i.
+.neo2n
+.neo1n1a
+.neona2z1i
+.ne8o9n8a8z8i8s.
+.neonaz4is
+.ne8p8h9e8w8s.
+.nephe4
+.ne8p8h9r8i8t8e.
+.nep4hr4
+.nephr2ite
+.ne8p8h9r8i8t8i8c.
+.nephr4i2t3ic
+.nephri1ti
+.ne8w9e8s8t.
+.ne4w
+.newest3
+.ne8w8s9l8e8t9t8e8r.
+.news4l2
+.news2le
+.newsle4t3t2
+.ne8w8s9l8e8t9t8e8r8s.
+.newslette4r1s2
+.ni8t8r8o9m8e8t8h9a8n8e.
+.n2it
+.ni3tr
+.nitro2me
+.nitro4met
+.nitrometha2n4
+.no9n8a8m8e.
+.no4n
+.no1n1a
+.no8n9a8r9i8t8h9m8e8t9i8c.
+.nonar3i
+.non2a2r
+.nonar2ith
+.nonarit4h1m
+.nonarithmet4
+.nonarithmet1ic
+.no8n9e8m8e8r9g8e8n8c8y.
+.none1me
+.nonemerg2
+.nonemer1gen
+.nonemergen1cy
+.no8n9e8q8u8i9v8a8r8i9a8n8c8e.
+.none2q
+.nonequ2
+.noneq2ui2
+.nonequ2iv3
+.nonequi1va
+.nonequiv2a2r
+.nonequivar1i
+.nonequivar3i2a2n
+.nonequivar2i3a
+.nonequivar4ianc
+.no8n8e9t8h8e9l8e8s8s.
+.noneth2e
+.nonethe1les2
+.nonethe3l2e2ss
+.no8n9e8u8c8l8i8d9e8a8n.
+.non4eu
+.noneu1c4l4
+.noneucl2id
+.noneuclidea2n
+.no8n9i8s8o9m8o8r9p8h8i8c.
+.non5i
+.non1is
+.noni2so
+.noni3som
+.noniso1mo
+.nonisomo2r
+.nonisomor1p
+.nonisomorp4h4
+.nonisomorph1ic
+.no8n9p8s8e8u8d8o9c8o8m9p8a8c8t.
+.non1p4
+.non2p1s2
+.nonp2se
+.nonps4eu
+.nonpseu1do
+.nonpseudo1co
+.nonpseudoco4m1p
+.nonpseudocom1pa
+.nonpseudocompa2c4t
+.no8n9s8m8o8o8t8h.
+.no2n3s2
+.non2s3m
+.nons1mo
+.nonsmoo2
+.nonsmo4oth
+.no8n9u8n8i9f8o8r8m.
+.no3nu4n
+.nonu1ni
+.nonuni1fo
+.nonunifo2r
+.nonunifor1m
+.no8n9u8n8i9f8o8r8m9l8y.
+.nonunifor4m1l
+.nonuniform1ly
+.no8r9e8p9i9n8e8p8h9r8i8n8e.
+.nore5pi2n
+.norep2ine
+.norepinep4hr4
+.norep2inephr2in4e
+.no8t9w8i8t8h9s8t8a8n8d9i8n8g.
+.notw4
+.notwi2
+.notw2ith3
+.notwi2t4h1s2
+.notwith5st4and
+.notwiths1ta
+.notwithsta2n
+.notwithstand1in
+.nu9c8l8e8o9t8i8d8e.
+.nucle3
+.nu1c4l4
+.nucle4ot
+.nucleot2id
+.nu9c8l8e8o9t8i8d8e8s.
+.nucleotide4s2
+.nu8t9c8r8a8c8k9e8r.
+.nu4tc
+.nutcrack1
+.nutcrack1er
+.nu8t9c8r8a8c8k9e8r8s.
+.nutcracke4r1s2
+.oe8r9s8t8e8d8s.
+.o3er
+.oe4r1s2
+.oers4t1ed
+.oerste2d1s2
+.of8f9l8i8n8e.
+.o4f1f
+.off4l2
+.offlin4
+.off1l4ine
+.of8f9l8o8a8d.
+.offl4oa
+.offloa2d3
+.of8f9l8o8a8d8s.
+.offloa2d1s2
+.of8f9l8o8a8d8e8d.
+.offloa2d1ed
+.ol8i9g8o8p9o9l8i8s8t.
+.ol2i
+.ol2ig
+.oli2go
+.ol2igopol2i
+.ol8i9g8o8p9o9l8i8s8t8s.
+.oligopolis4t1s2
+.ol8i9g8o8p9o8l8y.
+.oligopo2ly
+.ol8i9g8o8p9o8l9i8e8s.
+.oligopol2ie4
+.op9e8r9a8n8d.
+.op1er
+.3oper1a
+.op4er4and
+.opera2n
+.op9e8r9a8n8d8s.
+.operan2d1s2
+.or8a8n8g9u8t8a8n.
+.ora2n
+.or2ang
+.oran1gu
+.oran4gu4t
+.orangu1ta
+.ora2nguta2n
+.or8a8n8g9u8t8a8n8s.
+.oranguta2n1s2
+.or9t8h8o9d8o8n9t8i8s8t.
+.ortho2do4
+.orthodo2n
+.orthodon3t4i
+.orthodon1t
+.or9t8h8o9d8o8n9t8i8s8t8s.
+.orthodontis4t1s2
+.or9t8h8o9k8e8r9a9t8o8l9o8g8y.
+.orth2ok
+.orthok1er
+.orthoker1a
+.orthokera1to
+.orthokeratol1o1gy
+.or8t8h8o9n8i8t8r8o9t8o8l8u8e8n8e.
+.ortho2n
+.orthon2it
+.orthoni3tr
+.orthonitro1to
+.orthonitrotolu3en
+.orthonitrotolu4ene
+.ov8e8r9v8i8e8w.
+.overv2ie4
+.ov8e8r9v8i8e8w8s.
+.ox9i8d9i8c.
+.ox3i
+.oxi5di
+.ox2id
+.pa8d9d8i8n8g.
+.1pa
+.p4a2d
+.pad4d1in
+.pad1d4
+.pa8i8n9l8e8s8s9l8y.
+.p4ai2
+.pa4i4n4
+.pa4i4n1l
+.painles2
+.pain3l2e2ss
+.painles4s1l2
+.painless1ly
+.pa8l9e8t8t8e.
+.p4al
+.p2ale
+.pale4t3t2
+.pa8l9e8t8t8e8s.
+.palet4tes
+.pa8r9a9b8o8l8a.
+.p2a2r
+.pa2rab
+.parabo1la
+.pa8r9a9b8o8l9i8c.
+.parabol3ic
+.parabol2i
+.pa9r8a8b9o9l8o8i8d.
+.paraboloi2
+.parabolo2id
+.pa8r9a9d8i8g8m.
+.para2d
+.par2adi
+.parad2ig
+.paradig1m
+.pa8r9a9d8i8g8m8s.
+.paradig4m1s2
+.pa8r8a9c8h8u8t8e.
+.para2ch
+.parachu4t
+.pa8r8a9c8h8u8t8e8s.
+.pa8r8a9d8i9m8e8t8h8y8l9b8e8n8z8e8n8e.
+.parad4imet
+.paradimethy2l1b
+.paradimethylb4e4n3z
+.paradimethylben2ze
+.paradimethylbenze4n
+.pa8r8a9f8l8u8o8r8o9t8o8l8u8e8n8e.
+.para2f
+.paraf4l2
+.paraflu3o
+.parafluo3r
+.parafluoro1to
+.parafluorotolu3en
+.parafluorotolu4ene
+.pa8r8a9g8r8a8p8h9e8r.
+.para1gr
+.parag5ra3ph4er
+.pa8r8a9l8e9g8a8l.
+.par3al
+.par2ale
+.paral4egal
+.parale1ga
+.pa8r9a8l9l8e8l9i8s8m.
+.paral1l
+.paral2le
+.paral3lel
+.parallel2i
+.paralle2lis
+.paralleli2s1m
+.pa8r8a9m8a8g9n8e8t9i8s8m.
+.par4a1ma
+.param3ag
+.para5mag1n
+.paramagneti2s4m
+.pa8r8a9m8e8d8i8c.
+.para2med
+.param4edi
+.pa8r8a9m8e8t8h8y8l9a8n8i8s8o8l8e.
+.param3et
+.paramethy3la
+.paramethyla2n
+.paramethylani2so
+.pa9r8a8m9e9t8r8i8z8e.
+.param4etr
+.parametri2ze
+.pa8r8a9m8i8l9i9t8a8r8y.
+.par2ami
+.paramil1i
+.param2il1it
+.paramili1ta
+.paramilit2a2r
+.pa8r8a9m8o8u8n8t.
+.para2mo
+.paramou2
+.paramoun1t
+.pa8t8h9o9g8e8n9i8c.
+.p4ath
+.pat4ho
+.patho4g
+.patho1ge4
+.patho1gen
+.pe8e8v9i8s8h.
+.p4ee
+.pee1vi
+.peevis2h
+.pe8e8v9i8s8h9n8e8s8s.
+.peevis2h1n
+.peevish1nes
+.peevishn2e2ss
+.pe8n9t8a9g8o8n.
+.pen1t
+.pen1ta
+.penta2go
+.pentago2n2
+.pe8n9t8a9g8o8n8s.
+.pentago2n3s2
+.pe9t8r8o9l8e9u8m.
+.petrol4eu
+.ph8e9n8o8m9e9n8o8n.
+.ph4e3no
+.phe2n
+.pheno2me
+.pheno1men
+.phenom4eno
+.phenomeno4n
+.ph8e8n8y8l9a8l8a9n8i8n8e.
+.pheny3la
+.phenylala2n
+.phenylala5n2ine
+.phenylalan1in
+.ph8i9l8a8t9e9l8i8s8t.
+.phi4latel2i4
+.philate2lis
+.ph8i9l8a8t9e9l8i8s8t8s.
+.philatelis4t1s2
+.ph8o9n8e8m8e.
+.3phone
+.pho2n
+.phone1me
+.ph8o9n8e8m8e8s.
+.phone2mes
+.ph8o9n8e9m8i8c.
+.phone5mi
+.ph8o8s9p8h8o8r9i8c.
+.phos1p
+.phospho5
+.phospho4r
+.ph8o9t8o9g8r8a8p8h8s.
+.pho1to
+.photo2gr
+.photogra4p4h1s2
+.ph8o9t8o9o8f8f9s8e8t.
+.photoo2
+.photoo4f1f
+.photoof2f3s
+.pi8c9a9d8o8r.
+.pi1ca
+.pica2d
+.pica1do
+.picad4or
+.pi8c9a9d8o8r8s.
+.picado4rs2
+.pi8p8e9l8i8n8e.
+.p2ip
+.pipe4
+.pipel2i
+.pipe1l4ine
+.pi8p8e9l8i8n8e8s.
+.pipeli1nes
+.pi8p8e9l8i8n9i8n8g.
+.pipel2in3i
+.pipelin1in
+.pipelinin4g
+.pi9r8a9n8h8a8s.
+.p4ir
+.pi1ra
+.pira2n
+.pira4n1h4
+.piranha4
+.pl8a8c8a9b8l8e.
+.1p2l2
+.pla1ca
+.placa1b2l2
+.pl8a8n8t9h8o8p9p8e8r.
+.3pla2n
+.plan1t
+.plantho4p1p
+.planthop2pe
+.planthop3per
+.pl8a8n8t9h8o8p9p8e8r8s.
+.planthoppe4r1s2
+.pl8e8a8s9a8n8c8e.
+.ple2a
+.pleasa2
+.plea3sanc
+.pleasa2n
+.pl8u8g9i8n.
+.plug5in
+.pl8u8g9i8n8s.
+.plu5g4i2n1s2
+.po8l9t8e8r9g8e8i8s8t.
+.po4l2t
+.pol1te
+.polterg2
+.poltergei2
+.po8l8y9e8n8e.
+.po2ly
+.po8l8y9e8t8h9y8l9e8n8e.
+.polye4t
+.po9l8y8g9a9m8i8s8t.
+.poly1ga
+.poly2gam
+.polygam2is
+.po9l8y8g9a9m8i8s8t8s.
+.polygamis4t1s2
+.po8l8y8g9o8n9i9z8a9t8i8o8n.
+.poly1go
+.polygo2n2
+.polygo3ni
+.polygoniza1
+.polygoniza1t2io
+.polygonizatio2n
+.po9l8y8p8h9o9n8o8u8s.
+.polypho2n
+.polypho1nou2
+.polyphono2us
+.po8l8y9s8t8y8r8e8n8e.
+.po2lys4
+.polys1t
+.polys2ty
+.po8m8e9g8r8a8n9a8t8e.
+.po2me
+.pome2g
+.pome1gr
+.pomegra2n2
+.pomegra1na
+.pomegran2at
+.po8r8o9e8l8a8s9t8i8c.
+.1p4or
+.poro4e
+.poro4el
+.poroe1la
+.poroelast2i
+.poroelas1tic
+.po8r9o8u8s.
+.porou2
+.poro2us
+.po8r9t8a9b8l8e.
+.por1ta
+.por2tab
+.portab2l2
+.po8s8t9a8m9b8l8e.
+.1pos
+.pos2ta
+.posta4m1b
+.postamb2l2
+.po8s8t9a8m9b8l8e8s.
+.postambles2
+.po8s8t9h8u9m8o8u8s.
+.posthu1mo
+.posthu3mo2us
+.posthumou2
+.po8s8t9s8c8r8i8p8t.
+.pos4t1s2
+.post4sc
+.postscri2
+.postscr2ip
+.postscri2p1t
+.po8s8t9s8c8r8i8p8t8s.
+.postscrip4t1s2
+.po8s9t8u8r9a8l.
+.pos1tu
+.postu1ra
+.pr8e9a8m9b8l8e.
+.prea4m1b
+.preamb2l2
+.pr8e9a8m9b8l8e8s.
+.preambles2
+.pr8e9l8o8a8d8e8d.
+.prel4oa
+.preloa2d3
+.preloa2d1ed
+.pr8e9p8a8r9i8n8g.
+.pre2pa
+.prep4a4r1i
+.prep2a2r
+.preparin4g
+.pr8e9p8r8i8n8t.
+.pr2epr2
+.preprin4t3
+.pr8e9p8r8i8n8t8s.
+.preprin4t4s2
+.pr8e9p8r8o8c8e8s9s8o8r.
+.pre3pro
+.prepr2oc
+.prepro1ce
+.preproc2e2ss
+.preproces1so
+.pr8e9p8r8o8c8e8s9s8o8r8s.
+.preprocesso4rs2
+.pr8e9s8p8l8i8t9t8i8n8g.
+.pre1sp
+.pres1p2l2
+.prespl1it
+.prespl4i4t3t2
+.presplit2t1in
+.pr8e9w8r8a8p.
+.prewra4
+.pr8e9w8r8a8p8p8e8d.
+.prewra4p1p
+.prewrap2pe
+.prewrap4p2ed
+.pr8i8e8s8t9e8s8s8e8s.
+.5pr2i4e4
+.pri1est
+.pries4t2e2ss
+.priestess1e4s
+.pr8e8t9t8y9p8r8i8n9t8e8r.
+.pre4t3t2
+.pret1ty
+.pr2ettypr2
+.prettyprin4t3
+.pr8e8t9t8y9p8r8i8n9t8i8n8g.
+.prettyprint2i
+.prettyprin4t3ing
+.prettyprin2t1in
+.pr8o9c8e9d8u8r9a8l.
+.pr2oc
+.pro1ce
+.proce1du
+.procedu1ra
+.pr8o8c8e8s8s.
+.proc2e2ss
+.pr8o9c8u8r9a8n8c8e.
+.procu1ra
+.procura2n
+.pr8o8g9e9n8i8e8s.
+.pro1ge
+.pro1gen
+.proge5n2ie4
+.pr8o8g9e9n8y.
+.pro4geny
+.pr8o9g8r8a8m9m8a8b8l8e.
+.pro1gr
+.program1m
+.program1ma
+.program2mab
+.programmab2l2
+.pr8o8m9i9n8e8n8t.
+.prom4i
+.prom1in
+.prom2ine
+.promi1nen
+.prominen1t
+.pr8o9m8i8s9c8u9o8u8s.
+.prom2is
+.prom2is1c
+.promis1cu
+.promiscu1ou2
+.promiscuo2us
+.pr8o8m9i8s9s8o8r8y.
+.prom4i2s1s
+.promis1so
+.promisso1ry
+.pr8o8m9i8s8e.
+.prom4ise
+.pr8o8m9i8s8e8s.
+.promis1e4s
+.pr8o9p8e8l9l8e8r.
+.pro3pel
+.propel1l
+.propel2le
+.pr8o9p8e8l9l8e8r8s.
+.propelle4r1s2
+.pr8o9p8e8l9l8i8n8g.
+.propell2i
+.propel2lin4
+.pr8o9h8i8b9i9t8i8v8e.
+.pro1h2
+.prohibi2t
+.prohibi1ti
+.prohibi1t2iv
+.pr8o9h8i8b9i9t8i8v8e9l8y.
+.prohibitiv4e1ly
+.pr8o9s8c8i8u8t9t8o.
+.pros2c
+.pros1ci
+.prosci1u
+.prosciu4t3t2
+.prosciut5to
+.pr8o9t8e8s8t9e8r.
+.pro1t
+.pro4tes
+.pr8o9t8e8s8t9e8r8s.
+.proteste4r1s2
+.pr8o9t8e8s9t8o8r.
+.prot4es2to
+.pr8o9t8e8s9t8o8r8s.
+.protesto4rs2
+.pr8o9t8o9l8a8n9g8u8a8g8e.
+.pro1to
+.proto1la
+.proto4la2n
+.protol2ang
+.protolan1gu
+.protolangu4a
+.pr8o9t8o9t8y8p9a8l.
+.proto1ty
+.prototy1pa
+.prototyp4al
+.pr8o8v9i8n8c8e.
+.prov1in
+.prov2inc
+.pr8o8v9i8n8c8e8s.
+.pr8o9v8i8n9c8i8a8l.
+.provin1ci
+.provin3c2i1a
+.provinci2al
+.pr8o8w9e8s8s.
+.prow2e2ss
+.ps8e8u9d8o9d8i8f9f8e8r9e8n9t8i8a8l.
+.2p1s2
+.p2se
+.ps4eu
+.pseu1do
+.pseudod1if
+.pseudodi4f1f
+.pseudodiffer1
+.pseudodiffer3en1t
+.pseudodifferent2i
+.pseudodifferen1t2i1a
+.pseudodifferenti2al
+.ps8e8u9d8o9f8i9n8i8t8e.
+.pseu2d5of
+.pseudo2fi
+.pseudo2fin
+.pseudof2ini
+.pseudofin2it
+.pseudofin2ite
+.ps8e8u9d8o9f8i9n8i8t8e9l8y.
+.pseudofinite1ly
+.ps8e8u9d8o9f8o8r8c8e8s.
+.pseudo1fo
+.pseudofo2r
+.pseudofor1c
+.pseudofor2ce
+.ps8e8u9d8o8g9r8a9p8h8e8r.
+.pseud4og
+.pseudo1gr
+.pseudog5ra3ph4er
+.ps8e8u9d8o9g8r8o8u8p.
+.pseudo4g4ro
+.pseudogrou2
+.ps8e8u9d8o9g8r8o8u8p8s.
+.pseudogrou2p1s2
+.ps8e8u9d8o9n8y8m.
+.pseu4do2n
+.pseudonym4
+.ps8e8u9d8o9n8y8m8s.
+.pseudony4m1s2
+.ps8e8u9d8o9w8o8r8d.
+.pseudo4wo2
+.ps8e8u9d8o9w8o8r8d8s.
+.pseudowor2d1s2
+.ps8y9c8h8e9d8e8l9i8c.
+.ps4y
+.p4sy1c
+.psy3ch
+.psych4e2
+.psy4ch4ed
+.psychedel2i
+.ps8y8c8h8s.
+.psyc4h1s2
+.pu9b8e8s9c8e8n8c8e.
+.pub3
+.pub4e
+.pu4bes4
+.pubes2c
+.pubes1cen
+.pubes3cenc
+.qu8a8d9d8i8n8g.
+.qu2
+.qua2d
+.quad4d1in
+.quad1d4
+.qu8a9d8r8a8t9i8c.
+.qua1dr
+.quadrat1ic
+.qu8a9d8r8a8t9i8c8s.
+.quadrati4c3s2
+.qu8a8d9r8a9t8u8r8e.
+.quadra2tu
+.quadra3ture
+.qu8a8d9r8i9p8l8e8g9i8c.
+.quadri2p2l2
+.quadr2ip
+.quadripleg4ic
+.qu8a8i8n8t9e8r.
+.quai2
+.qua4i4n
+.quain1t
+.qu8a8i8n8t9e8s8t.
+.qu8a9s8i9e8q8u8i8v9a9l8e8n8c8e.
+.quas2ie4
+.quasie1q
+.qu2asiequ2
+.quasieq2ui2
+.quasiequ2iv3
+.quasiequi1va
+.quasiequiv2ale
+.quasiequiva3lenc
+.qu8a9s8i9e8q8u8i8v9a9l8e8n8c8e8s.
+.qu8a9s8i9e8q8u8i8v9a9l8e8n8t.
+.quasiequiva1len1t
+.qu8a9s8i9h8y9p8o9n8o8r9m8a8l.
+.quasi3h
+.quasihy3po
+.quasihypo2n
+.quasihyponor1m
+.quasihyponor1ma
+.qu8a9s8i9r8a8d9i9c8a8l.
+.quas4i2r
+.quasi1r5a
+.quasira2d
+.quasir2adi
+.quasirad3i1ca
+.qu8a9s8i9r8e8s8i8d9u8a8l.
+.quasi4res
+.quasire1si
+.quasire2s2id
+.quasiresi2du
+.quasiresid1u1a
+.qu8a9s8i9s8m8o8o8t8h.
+.qua1sis
+.quasi2s1m
+.quasis1mo
+.quasismoo2
+.quasismo4oth
+.qu8a9s8i9s8t8a9t8i8o8n9a8r8y.
+.quasis1ta
+.quasistation5a2r
+.quasista1t2io
+.quasistatio2n
+.quasistatio1n1a
+.qu8a9s8i9t8o8p8o8s.
+.qu5a5si4t
+.quasi1to
+.quasito1pos
+.qu8a9s8i9t8r8i9a8n9g8u9l8a8r.
+.quasi5tr2i3a
+.quasitri2a2n
+.quasitri2ang
+.quasitrian1gu
+.quasitriangu1la
+.quasitriangul2a2r
+.qu8a9s8i9t8r8i8v9i8a8l.
+.quasitr2i4v
+.quasitriv3i
+.quasitriv2i1a
+.quasitrivi2al
+.qu8i8n9t8e8s9s8e8n8c8e.
+.q2ui2
+.qui4n
+.quin1t
+.quin4t2e2ss
+.quintes4senc
+.qu8i8n9t8e8s9s8e8n8c8e8s.
+.qu8i8n9t8e8s9s8e8n9t8i8a8l.
+.quintessen1t
+.quintessent2i
+.quintessen1t2i1a
+.quintessenti2al
+.ra8b9b8i8t9r8y.
+.2rab
+.ra2b1b
+.rabbi2t
+.rabbi3tr
+.rabbit5ry
+.ra9d8i9o8g9r8a9p8h8y.
+.ra2d
+.r2adi
+.ra3d2io
+.radio5g
+.radio2gr
+.radio4g3ra1phy
+.ra8f8f9i8s8h.
+.raf5fi
+.ra2f
+.ra4f1f4
+.raf2f5is
+.raffis2h
+.ra8f8f9i8s8h9l8y.
+.raffis4h1l4
+.raffish1ly
+.ra8m9s8h8a8c8k8l8e.
+.ra4m1s2
+.ram4s2h
+.ramshack1
+.ramshack1l
+.ra8v9e8n9o8u8s.
+.rav4e4no
+.rave1nou2
+.raveno2us
+.re9a8r8r8a8n8g8e9m8e8n8t.
+.re5ar1r4
+.re2a2r
+.rearran4ge
+.rearra2n
+.rearr2ang
+.rearrange1me
+.rearrange1men
+.rearrange3men1t
+.re9a8r8r8a8n8g8e9m8e8n8t8s.
+.rearrangemen4t4s2
+.re8c9i9p8r8o8c9i9t8i8e8s.
+.reciproci1ti
+.reciprocit2ie4
+.re8c9t8a8n9g8l8e.
+.rec4ta2n
+.re2c1t
+.rect5ang
+.rec1ta
+.rectan1gl2
+.rectan1gle
+.re8c9t8a8n9g8l8e8s.
+.rectangles2
+.re8c9t8a8n9g8u9l8a8r.
+.rectan1gu
+.rectangu1la
+.rectangul2a2r
+.re9d8i9r8e8c8t.
+.2r2ed
+.r4edi
+.red4ir2
+.redi1re
+.redire2c1t
+.re9d8i9r8e8c8t9i8o8n.
+.redirec1t2io
+.redirectio2n
+.re9d8u8c9i8b8l8e.
+.re1du
+.redu2c
+.reduci4b
+.redu1ci
+.reduci1b2l2
+.re9e8c8h8o.
+.ree2c
+.ree2ch
+.ree3cho2
+.re9p8h8r8a8s8e.
+.rep4hr4
+.rephr2as
+.re9p8h8r8a8s8e8s.
+.rephras1e4s
+.re9p8h8r8a8s8e8d.
+.rephra4s4ed
+.re9p8o9s8i9t8i8o8n.
+.re4posi
+.re1po
+.re1pos
+.repo3s2i1t2io
+.reposi1ti
+.repositio2n
+.re9p8o9s8i9t8i8o8n8s.
+.repositio2n3s2
+.re9p8r8i8n8t.
+.repr2
+.reprin4t3
+.re9p8r8i8n8t8s.
+.reprin4t4s2
+.re9s8t8o8r9a8b8l8e.
+.r4es2to
+.resto2ra
+.resto2rab
+.restorab2l2
+.re8t8r8o9f8i8t.
+.retro2fi
+.re8t8r8o9f8i8t9t8e8d.
+.retrof4i4t4t2
+.retrofit2t1ed
+.re9u8s9a8b8l8e.
+.r4eu2
+.re2us4
+.reusa2
+.reu2s1ab
+.reusab2l2
+.re9u8s8e.
+.re9w8i8r8e.
+.rewi2
+.rew4ir4
+.re9w8r8a8p.
+.rewra4
+.re9w8r8a8p8p8e8d.
+.rewra4p1p
+.rewrap2pe
+.rewrap4p2ed
+.re9w8r8i8t8e.
+.rewri4
+.rewr2ite
+.rh8i9n8o8c9e8r9o8s.
+.rh4
+.rh2i1no
+.rhi4no4c
+.rhino1ce
+.rhinoc2ero
+.ri8g8h8t9e8o8u8s.
+.righ1teo
+.righteou2
+.righteo2us
+.ri8g8h8t9e8o8u8s9n8e8s8s.
+.righteous1n4
+.righteous1nes
+.righteousn2e2ss
+.ri8n8g9l8e8a8d8e8r.
+.rin4g
+.ringl2
+.rin1gle
+.ringle2a
+.ringlea2d1
+.ri8n8g9l8e8a8d8e8r8s.
+.ringleade4r5s2
+.ro9b8o8t.
+.ro9b8o8t8s.
+.robo4t1s2
+.ro9b8o8t8i8c.
+.ro9b8o8t9i8c8s.
+.roboti4c3s2
+.ro8u8n8d9t8a8b8l8e.
+.rou2
+.roun2d
+.round1ta
+.round2tab
+.roundtab2l2
+.ro8u8n8d9t8a8b8l8e8s.
+.roundta5bles2
+.sa8l8e8s9c8l8e8r8k.
+.sa2
+.s2ale
+.sales2
+.sales2c
+.salescle5
+.sales1c4l4
+.sa8l8e8s9c8l8e8r8k8s.
+.salescler4k1s2
+.sa8l8e8s9w8o8m8a8n.
+.sales4w2
+.sale4s1wo2
+.saleswom1
+.saleswo1ma
+.saleswoma2n
+.sa8l8e8s9w8o8m8e8n.
+.saleswo2me
+.saleswo1men
+.sa8l9m8o9n8e8l9l8a.
+.s4a2l4m
+.salmo2n4
+.sal1mo
+.salmon4ella
+.salmonel1l
+.sa8l9t8a9t8i8o8n.
+.sa4l4t
+.sal1ta
+.salta1t2io
+.saltatio2n
+.sa8r9s8a9p8a8r9i8l9l8a.
+.s2a2r
+.sa2r4sa2
+.sa4rs2
+.sars1ap
+.s2a2rsap2a2r4
+.sarsa1pa
+.sarsap4a4r1i
+.sarsaparil1l
+.sa8u8e8r9k8r8a8u8t.
+.sau4
+.sauerkrau4t
+.sc8a8t9o9l8o8g9i9c8a8l.
+.s1ca
+.sca1to
+.scato3log1ic
+.scatologi1ca
+.sc8h8e8d9u8l9i8n8g.
+.s2ch2
+.sche2
+.s4ch4ed
+.sche4dul
+.sche1du
+.schedul2i
+.schedul3ing
+.sc8h8i8z9o9p8h8r8e8n8i8c.
+.schi2z
+.schi1zo
+.schiz2oph
+.schizop4hr4
+.sc8h8n8a8u9z8e8r.
+.sc2h1n
+.sch1na
+.schn2au
+.schnau2z4e
+.schnauz1er
+.sc8h8o8o8l9c8h8i8l8d.
+.s4cho2
+.schoo2
+.schoo4l1c2
+.s2chool2ch
+.schoolch4il2
+.schoolchi2ld
+.sc8h8o8o8l9c8h8i8l8d9r8e8n.
+.schoolchil3dr
+.schoolchildre4
+.schoolchil5dren
+.sc8h8o8o8l9t8e8a8c8h8e8r.
+.schoo4l2t
+.school1te
+.s2chooltea2ch
+.schoolteache2
+.sc8h8o8o8l9t8e8a8c8h9e8r8s.
+.schoolteach3e4r1s2
+.sc8r8u9t8i9n8y.
+.scru2t1i5n
+.scr4u1t2i
+.scrut4iny
+.sc8y8t8h9i8n8g.
+.s1cy
+.scy3thin
+.se8l8l9e8r.
+.sel2le
+.se8l8l9e8r8s.
+.selle4r1s2
+.se8c9r8e9t8a8r9i8a8t.
+.se1cr
+.se4c3re1ta
+.secret2a2r
+.secretar1i
+.secretar2i3a
+.se8c9r8e9t8a8r9i8a8t8s.
+.secretaria4t1s2
+.se8m9a9p8h8o8r8e.
+.se1ma
+.se4map
+.semapho4r
+.se8m9a9p8h8o8r8e8s.
+.se9m8e8s9t8e8r.
+.4se1me
+.se2mes
+.se8m8i9d8e8f9i9n8i8t8e.
+.sem2id
+.semide1f
+.semidef5i5n2ite
+.semide1fi
+.semide2fin
+.semidef2ini
+.semidefin2it
+.se8m8i9d8i9r8e8c8t.
+.semi2di
+.semid4ir2
+.semidi1re
+.semidire2c1t
+.se8m8i9h8o9m8o9t8h8e8t9i8c.
+.semi3h
+.semiho1mo
+.semihom4oth3
+.semihomoth2e
+.semihomo3the4t
+.semihomothet1ic
+.se8m8i9r8i8n8g.
+.sem4ir
+.semir1i
+.semirin4g
+.se8m8i9r8i8n8g8s.
+.semirings2
+.se8m8i9s8i8m9p8l8e.
+.se4m2is
+.semisi4m1p
+.semisim1p2l2
+.se8m8i9s8k8i8l8l8e8d.
+.sem4is4k2
+.semisk1i
+.semisk4il1l
+.semiskil2le
+.se8r8o9e8p8i9d8e9m8i9o9l8o8g9i9c8a8l.
+.s2er4o
+.sero4e
+.seroep4id
+.seroepi3de
+.seroepid4em
+.seroepidem2io
+.seroepidemi1ol
+.seroepidemio3log1ic
+.seroepidemiologi1ca
+.se8r9v8o9m8e8c8h9a8n8i8s8m.
+.4ser3vo
+.servo2me
+.servome2ch
+.servomech5a5nis
+.servomecha2n
+.servomechani2s1m
+.se8r9v8o9m8e8c8h9a8n8i8s8m8s.
+.servomechan4is4m1s2
+.se8s9q8u8i9p8e9d8a9l8i8a8n.
+.s1e4s
+.sesqu2
+.sesq2ui2
+.sesqu2ip
+.sesquipe4
+.sesqui2p2ed
+.sesquip2e2d2a
+.sesquipedal1i
+.sesquipedal2i1a
+.sesquipedali2a2n
+.se8t9u8p.
+.se1tu
+.se8t9u8p8s.
+.setu2p1s2
+.se9v8e8r8e9l8y.
+.5sev
+.sev1er
+.sev4erel
+.severe1ly
+.sh8a8p8e9a8b8l8e.
+.sha3pe4a
+.shape1a4b
+.shapeab2l2
+.sh8o8e9s8t8r8i8n8g.
+.sho4
+.sho2est4r
+.shoestrin4g
+.sh8o8e9s8t8r8i8n8g8s.
+.shoestrings2
+.si8d8e9s8t8e8p.
+.5side4s2
+.s2id
+.sideste4p
+.si8d8e9s8t8e8p8s.
+.sideste2p1s2
+.si8d8e9s8w8i8p8e.
+.sides4w2
+.sideswi2
+.sidesw2ip
+.sideswipe4
+.sk8y9s8c8r8a8p8e8r.
+.sk2
+.skys4c
+.skyscrap3er
+.sk8y9s8c8r8a8p8e8r8s.
+.skyscrape4r1s2
+.sm8o8k8e9s8t8a8c8k.
+.2s1m
+.s1mo
+.s4m2ok
+.smokes4
+.smokes1ta
+.smokestack1
+.sm8o8k8e9s8t8a8c8k8s.
+.smokestac4k1s2
+.sn8o8r9k8e8l9i8n8g.
+.s1n4
+.snorke5l2i
+.snorke4l3ing
+.so9l8e9n8o8i8d.
+.1so
+.sol4eno
+.solenoi2
+.soleno2id
+.so9l8e9n8o8i8d8s.
+.solenoi2d1s2
+.so8l8u8t8e.
+.so1lut
+.so8l8u8t8e8s.
+.so8v9e8r9e8i8g8n.
+.4sov
+.soverei2
+.sovere2ig2
+.so8v9e8r9e8i8g8n8s.
+.sovereig2n1s2
+.sp8a9c8e8s.
+.2s1pa
+.spa4ce
+.sp8e9c8i8o8u8s.
+.spe2c
+.spe1c2i
+.spec2io
+.speciou2
+.specio2us
+.sp8e8l8l9e8r.
+.spel1l
+.spel2le
+.sp8e8l8l9e8r8s.
+.spelle4r1s2
+.sp8e8l8l9i8n8g.
+.spell2i
+.spel2lin4
+.sp8e9l8u8n8k9e8r.
+.spelu4nk2
+.spelunk1er
+.sp8e8n8d9t8h8r8i8f8t.
+.spen4d
+.spend2th
+.spendt4hr4
+.spendthr4i2ft
+.sp8h8e8r9o8i8d.
+.s2phe
+.3sph4er
+.sph2ero
+.spheroi2
+.sphero2id
+.sp8h8e8r9o8i8d9a8l.
+.spheroi1d2a
+.sp8h8i8n9g8e8s.
+.sph5ing
+.sph4inge
+.sp8i8c9i9l8y.
+.sp2i1ci
+.spici1ly
+.sp8i8n9o8r8s.
+.spi2n
+.sp4i1no
+.spino4rs2
+.sp8o8k8e8s9w8o8m8a8n.
+.sp2ok
+.spokes4
+.spokes4w2
+.spoke4s1wo2
+.spokeswom1
+.spokeswo1ma
+.spokeswoma2n
+.sp8o8k8e8s9w8o8m8e8n.
+.spokeswo2me
+.spokeswo1men
+.sp8o8r8t8s9c8a8s8t.
+.s1p4or4
+.spor4t1s2
+.sport4sc
+.sports1ca
+.sp8o8r8t8s9c8a8s8t9e8r.
+.sportscast5er
+.sp8o8r9t8i8v8e9l8y.
+.spor1ti
+.spor4t2iv
+.sportiv4e1ly
+.sp8o8r8t8s9w8e8a8r.
+.sport4sw2
+.sportswe2a2r
+.sp8o8r8t8s9w8r8i8t8e8r.
+.sportswri4
+.sportswr2ite
+.sp8o8r8t8s9w8r8i8t8e8r8s.
+.sportswrit5e4r1s2
+.sp8r8i8g8h8t9l8i8e8r.
+.spr2
+.spr2ig
+.sprigh2tl
+.sprightl2ie4
+.sq8u8e8a9m8i8s8h.
+.squ2
+.squeam2is
+.squeamis2h
+.st8a8n8d9a8l8o8n8e.
+.5st4and
+.sta2n
+.stan1d2a
+.standalo2n
+.st8a8r9t8l8i8n8g.
+.st2a2r
+.star2tl
+.st8a8r9t8l8i8n8g9l8y.
+.startlingl2
+.startling1ly
+.st8a9t8i8s9t8i8c8s.
+.statis1t2i
+.statis1tic
+.statisti4c3s2
+.st8e8a8l8t8h9i8l8y.
+.stea4l
+.stea4lt
+.stealth3i
+.steal4th4il2
+.stealthi1ly
+.st8e8e8p8l8e9c8h8a8s8e.
+.s1tee
+.stee4p1
+.stee1p2l2
+.steeple2ch
+.st8e8r8e8o9g8r8a8p8h9i8c.
+.stere1o
+.stereo2g
+.stereo1gr
+.stereo5graph1ic
+.stereogr4aphi
+.st8o9c8h8a8s9t8i8c.
+.s1to
+.sto2ch4
+.stochast2i
+.stochas1tic
+.st8r8a8n8g8e9n8e8s8s.
+.st4r
+.s1tra
+.stran4ge
+.stra2n
+.str2ang
+.strange4n4e
+.stran1gen
+.strange1nes
+.strangen2e2ss
+.st8r8a8p9h8a8n8g8e8r.
+.straph2an4g
+.straphang5er
+.strapha2n
+.st8r8a8t9a9g8e8m.
+.stra2ta
+.st8r8a8t9a9g8e8m8s.
+.stratage4m1s2
+.st8r8e8t8c8h9i9e8r.
+.stre4tc
+.stret4ch
+.stretch2ie4
+.st8r8i8p9t8e8a8s8e.
+.str2ip
+.stri2p1t
+.strip2te
+.st8r8o8n8g9h8o8l8d.
+.stro2n
+.strongho2l2d
+.st8r8o8n8g9e8s8t.
+.st8u9p8i8d9e8r.
+.s1tu
+.stup4id
+.stupi3de
+.st8u9p8i8d9e8s8t.
+.stupide4s2
+.su8b9d8i8f9f8e8r9e8n9t8i8a8l.
+.1su
+.su4b3
+.su4b1d
+.subd1if
+.subdi4f1f
+.subdiffer1
+.subdiffer3en1t
+.subdifferent2i
+.subdifferen1t2i1a
+.subdifferenti2al
+.su8b9e8x9p8r8e8s9s8i8o8n.
+.sub4e
+.sub1ex3p
+.subexpr2
+.subex3pr2e2ss
+.subexpres1si
+.subexpres1s2io
+.subexpres5sio2n
+.su8b9e8x9p8r8e8s9s8i8o8n8s.
+.subexpressio2n3s2
+.su8m9m8a9b8l8e.
+.su2m
+.sum1m
+.sum1ma
+.sum2mab
+.summab2l2
+.su8p8e8r9e8g8o.
+.su1pe
+.supere1go
+.su8p8e8r9e8g8o8s.
+.supere4gos
+.su9p8r8e8m9a9c8i8s8t.
+.supr2
+.supre4mac
+.supre1ma
+.suprem4a2ci
+.su9p8r8e8m9a9c8i8s8t8s.
+.supremacis4t1s2
+.su8r9v8e8i8l9l8a8n8c8e.
+.su2r
+.surv4e
+.survei2
+.surveil1l
+.surveilla2n
+.sw8i8m9m8i8n8g9l8y.
+.sw2
+.swi2
+.swim1m
+.swimm4ingl2
+.swimm5ing1ly
+.sy8m8p9t8o9m8a8t8i8c.
+.sy4m1p
+.sym2p1t
+.symp1to
+.sympto2ma
+.symptomat1ic
+.sy8n9c8h8r8o9m8e8s8h.
+.syn3c4hr4
+.syn2ch
+.synchro2me
+.synchro2mes
+.synchrom4es2h
+.sy8n9c8h8r8o9n8o8u8s.
+.synchro2n
+.synchro1nou2
+.synchrono2us
+.sy8n9c8h8r8o9t8r8o8n.
+.synchrotro2n
+.ta8f8f9r8a8i8l.
+.4ta2f4
+.ta4f1f4
+.taffr2ai2
+.ta8l8k9a9t8i8v8e.
+.ta2l
+.4talk
+.talka3
+.talka4t
+.talka1t2iv
+.ta9p8e8s9t8r8y.
+.tap2est4r
+.tape4stry
+.ta9p8e8s9t8r8i8e8s.
+.tapestr2ie4
+.ta8r9p8a8u9l8i8n.
+.t2a2r
+.tar2p
+.tar1pa
+.tarpau4l2
+.tarpaul2i
+.ta8r9p8a8u9l8i8n8s.
+.tarpaul2i2n1s2
+.te9l8e8g9r8a9p8h8e8r.
+.tele1gr
+.teleg5ra3ph4er
+.te9l8e8g9r8a9p8h8e8r8s.
+.telegraphe4r1s2
+.te8l8e9k8i9n8e8t9i8c.
+.teleki4n
+.telek1i
+.telek2ine
+.teleki3net1ic
+.te8l8e9k8i9n8e8t9i8c8s.
+.telekineti4c3s2
+.te8l8e9r8o9b8o8t9i8c8s.
+.te4l1er
+.tel4ero
+.teler5ob
+.teleroboti4c3s2
+.te8l8l9e8r.
+.tel1l
+.tel2le
+.te8l8l9e8r8s.
+.telle4r1s2
+.te8m9p8o9r8a8r9i8l8y.
+.te4m1p
+.tem1p4or
+.tempo1ra
+.tempo4raril
+.tempor2a2r
+.temporar1i
+.temporari1ly
+.te8n9u8r8e.
+.te8s8t9b8e8d.
+.tes2t1b
+.test4be2d
+.te8x8t9w8i8d8t8h.
+.3tex
+.tex1t2
+.textw4
+.textwi2
+.textw2id
+.textwid2th
+.th8a8l9a9m8u8s.
+.tha3la
+.thala3m
+.thala1mu
+.thalam2us
+.th8e8r9m8o9e8l8a8s9t8i8c.
+.th2e
+.ther3m4
+.ther1mo
+.thermo4el
+.thermoe1la
+.thermoelast2i
+.thermoelas1tic
+.ti8m8e9s8t8a8m8p.
+.ti2mes
+.times1ta
+.timesta4m1p
+.ti8m8e9s8t8a8m8p8s.
+.timestam2p1s2
+.to8o8l9k8i8t.
+.too2
+.toolk1i
+.to8o8l9k8i8t8s.
+.toolki4t1s2
+.to8p8o9g8r8a8p8h9i9c8a8l.
+.to5po4g
+.topo1gr
+.topo5graph1ic
+.topogr4aphi
+.topographi1ca
+.to8q8u8e8s.
+.to1q
+.toqu2
+.tr8a8i9t8o8r9o8u8s.
+.1tra
+.tr2ai2
+.trai1to
+.traitorou2
+.traitoro2us
+.tr8a8n8s9c8e8i8v8e8r.
+.tra2n
+.tra2n1s2
+.trans4c
+.tran4s3cei2
+.transce2iv
+.tr8a8n8s9c8e8i8v8e8r8s.
+.transceive4r1s2
+.tr8a8n8s9g8r8e8s8s.
+.tran2s3g
+.trans1gr
+.transgr2e2ss
+.tr8a8n8s9v8e8r9s8a8l.
+.tran4sv
+.transve4r1s2
+.transver1sa2
+.tr8a8n8s9v8e8r9s8a8l8s.
+.transversa2l1s2
+.tr8a8n8s9v8e8s9t8i8t8e.
+.transv4e2s
+.transvest2i
+.transvest2ite
+.tr8a8n8s9v8e8s9t8i8t8e8s.
+.transvestit4es
+.tr8a9v8e8r8s9a9b8l8e.
+.trave4r1s2
+.traver1sa2
+.traver2s1ab
+.traversab2l2
+.tr8a9v8e8r9s8a8l.
+.tr8a9v8e8r9s8a8l8s.
+.traversa2l1s2
+.tr8i9e8t8h8y8l9a8m8i8n8e.
+.tri5et
+.tr2ie4
+.triethy3la
+.triethylam1in
+.triethylam2ine
+.tr8e8a8c8h9e8r8i8e8s.
+.trea2ch
+.treache2
+.treacher1i
+.treacher2ie4
+.tr8o8u9b8a9d8o8u8r.
+.trou2
+.trouba2d
+.trouba1do
+.troubadou2
+.tu8r9k8e8y.
+.1tu
+.tu8r9k8e8y8s.
+.turkeys4
+.tu8r8n9a8r8o8u8n8d.
+.tur4n2a2r
+.tur1na
+.turnarou2
+.turnaroun2d
+.tu8r8n9a8r8o8u8n8d8s.
+.turnaroun2d1s2
+.ty8p9a8l.
+.1ty
+.ty1pa
+.typ4al
+.un9a8t9t8a8c8h8e8d.
+.un2at4
+.una4t3t2
+.unat1ta
+.unatta2ch
+.unattache2
+.unatta4ch4ed
+.un9e8r8r9i8n8g9l8y.
+.un4er
+.uner4r4
+.unerrin4g
+.unerringl2
+.unerring1ly
+.un9f8r8i8e8n8d9l8y.
+.un3f
+.unfri2
+.unfr2ie4
+.unfrien2d1ly
+.un9f8r8i8e8n8d9l8i9e8r.
+.unfriendl2ie4
+.va8g8u8e8r.
+.1va
+.vag4
+.va5guer
+.va2gue
+.va8u8d8e9v8i8l8l8e.
+.vaude1v4
+.vaude2v3i4l
+.vaude1vi
+.vaudevil1l
+.vaudevil2le
+.vi8c9a8r8s.
+.v4ic2a2r
+.vi1ca
+.vica4rs2
+.vi8l9l8a8i8n9e8s8s.
+.2vil
+.vil1l
+.villai2
+.villa4i4n
+.villa2ine
+.villai5n2e2ss
+.villai1nes
+.vi8s9u8a8l.
+.vi3su
+.visu1al
+.vi8s9u8a8l9l8y.
+.visual1l
+.visual1ly
+.vi9v8i8p9a9r8o8u8s.
+.3v2iv
+.viv2i4p
+.vivi1pa
+.vivip2a2r
+.viviparou2
+.viviparo2us
+.vo8i8c8e9p8r8i8n8t.
+.voi4
+.voi3cep
+.voicepr2
+.voiceprin4t3
+.vs8p8a8c8e.
+.v2s1pa
+.vspa4ce
+.wa8d9d8i8n8g.
+.wa2d
+.wad4d1in
+.wad1d4
+.wa8l8l9f8l8o8w8e8r.
+.wal1l
+.wal2lf
+.wallf4l2
+.wallflow1er
+.wa8l8l9f8l8o8w9e8r8s.
+.wallflowe4r1s2
+.wa8r8m9e8s8t.
+.w2a2r
+.war1m
+.war2me
+.war2mes
+.wa8s8t8e9w8a8t8e8r.
+.was4t
+.waste2w
+.waste1w5a
+.wastewa1te
+.wa8v8e9g8u8i8d8e.
+.waveg3
+.waveg2ui2
+.wavegu2id
+.wa8v8e9g8u8i8d8e8s.
+.waveguide4s2
+.wa8v8e9l8e8t.
+.wa8v8e9l8e8t8s.
+.wavele4t1s2
+.we8b9l8i8k8e.
+.w2e1b
+.web2l2
+.web3l4ik
+.we8e8k9n8i8g8h8t.
+.weekn2ig
+.we8e8k9n8i8g8h8t8s.
+.weeknigh4t1s2
+.wh8e8e8l9c8h8a8i8r.
+.whee4l1c2
+.wheel2ch
+.wheelchai2
+.wheelcha4ir
+.wh8e8e8l9c8h8a8i8r8s.
+.wheelchai4rs2
+.wh8i8c8h9e8v8e8r.
+.whi4
+.wh4i2ch
+.whiche2
+.whichev1er
+.wh8i8t8e9s8i8d8e8d.
+.wh2ite
+.whit4es
+.white1si
+.white2s2id
+.whitesi2d1ed
+.wh8i8t8e9s8p8a8c8e.
+.white1sp
+.white2s1pa
+.whitespa4ce
+.wh8i8t8e9s8p8a8c8e8s.
+.wi8d8e9s8p8r8e8a8d.
+.w2id
+.wide4s2
+.wide1sp
+.wides4pre
+.widespr2
+.widesprea2d1
+.wi8n8g9s8p8a8n.
+.win4g
+.wings2
+.wing2s1pa
+.wingspa4n
+.wi8n8g9s8p8a8n8s.
+.wingspa2n1s2
+.wi8n8g9s8p8r8e8a8d.
+.wingspr2
+.wingsprea2d1
+.wi8t8c8h9c8r8a8f8t.
+.wi4tc
+.wit4ch
+.witchcra2f4t
+.witchcra2f
+.wo8r8d9s8p8a8c9i8n8g.
+.1wo2
+.wor2d1s2
+.words4p
+.word2s1pa
+.wordsp4a2ci
+.wordspa2c1in
+.wordspac1ing
+.wo8r8k9a8r8o8u8n8d.
+.work2a2r
+.workarou2
+.workaroun2d
+.wo8r8k9a8r8o8u8n8d8s.
+.workaroun2d1s2
+.wo8r8k9h8o8r8s8e.
+.workh4
+.workhor4se
+.workho4rs2
+.wo8r8k9h8o8r8s8e8s.
+.workhors3e4s
+.wr8a8p9a8r8o8u8n8d.
+.wra4
+.wrap2a2r4
+.wra1pa
+.wraparou2
+.wraparoun2d
+.wr8e8t8c8h9e8d.
+.wre4tc
+.wret4ch
+.wretche2
+.wret4ch4ed
+.wr8e8t8c8h9e8d9l8y.
+.wretche2d1ly
+.ye8s9t8e8r9y8e8a8r.
+.yes4
+.yesterye2a2r
+.al9g8e9b8r8a8i9s8c8h8e.
+.algebra2is1c
+.algebrais3ch2
+.algebraische2
+.al9l8e9g8h8e9n8y.
+.al1l
+.al2le
+.al3leg
+.alleghe2n
+.ar9k8a8n9s8a8s.
+.arka2n
+.arkan2sa2
+.arka2n1s2
+.at8p9a8s8e.
+.a4t1p
+.at1pa
+.at8p9a8s8e8s.
+.atpas1e4s
+.au8s9t8r8a8l9a8s8i8a8n.
+.a2us
+.aus1t4r
+.aus1tra
+.australas2i1a
+.australasi2a2n
+.au8t8o9m8a8t8i9s8i8e8r9t8e8r.
+.automa3tis
+.automatis2ie4
+.automatisiert3er
+.be9d8i8e9n8u8n8g.
+.4be2d
+.b4e3di
+.be5di3en
+.bed2ie4
+.bedie3nu4n
+.be8m8b8o.
+.4be5m
+.be4m5b
+.bi8b9l8i9o9g8r8a9p8h8i9s8c8h8e.
+.bibliogr4aphi
+.bibliograph2is1c
+.bibliographis3ch2
+.bibliographische2
+.bo8s9t8o8n.
+.5bos4
+.bos1to
+.bosto2n
+.br8o8w8n9i8a8n.
+.brown5i
+.brow3n4i1a
+.browni3a2n
+.br8u8n8s9w8i8c8k.
+.bru2n
+.bru2n3s4
+.brun4sw2
+.brunswi2
+.brunswick1
+.bu9d8a9p8e8s8t.
+.bu1d2a
+.ca8r9i8b9b8e8a8n.
+.car1i
+.car4ib
+.cari2b1b
+.carib2be
+.caribbea2n
+.ch8a8r8l8e8s9t8o8n.
+.char4le4
+.char1l
+.charles2
+.charl4es2to
+.charle3sto2n
+.ch8a8r9l8o8t8t8e8s9v8i8l8l8e.
+.char3lo4
+.charlo4t3t2
+.charlot4tes
+.charlotte4sv
+.charlottes2vil
+.charlottesvil1l
+.charlottesvil2le
+.co9l8u8m9b8i8a.
+.colum4bi
+.colu4m1b
+.columb2i1a
+.cz8e8c8h8o9s8l8o9v8a9k8i8a.
+.c2ze4
+.cze2ch
+.cze3cho2
+.czechos4l2
+.czechos4lov
+.czechoslo1va
+.czechoslovak1i
+.czechoslovak2i1a
+.de8l9a9w8a8r8e.
+.de1la
+.de4law
+.delaw2a2r
+.di8j8k9s8t8r8a.
+.di3j
+.dij4k1s2
+.dijkst4r
+.dijks1tra
+.du8a8n8e.
+.d1u1a
+.dua2n
+.dy9n8a9m8i9s8c8h8e.
+.5dyn
+.dy1na
+.dynam2is
+.dynam2is1c
+.dynamis3ch2
+.dynamische2
+.en8g9l8i8s8h.
+.engl2
+.englis2h
+.eu8l8e8r9i8a8n.
+.eul4e
+.eu3l4er1i
+.eule1r2i3a4
+.euleri2a2n
+.ev8a8n9s8t8o8n.
+.e1va
+.eva2n
+.evan4st
+.eva2n1s2
+.evans1to
+.evansto2n
+.fe8b9r8u9a8r8y.
+.f2e4b
+.fe3br
+.febru3a
+.febru2a2r
+.fe8s8t9s8c8h8r8i8f8t.
+.fes4t1s2
+.fest4sc
+.fests2ch2
+.festsc4hr4
+.festschr4i2ft
+.fl8o8r9i9d8a.
+.flor2id
+.flori1d2a
+.fl8o8r9i9d9i8a8n.
+.flori2di
+.florid5i2a2n
+.flori1d4i3a
+.fo8r9s8c8h8u8n8g8s9i8n9s8t8i9t8u8t.
+.fors4c
+.fors2ch2
+.forschungs2
+.forschung2s1in
+.forschungs2i2n1s2
+.forschungsinst2i
+.forschungsinsti1tu
+.fr8e8e9b8s8d.
+.fre2e1b
+.free2b5s2
+.freeb4s5d
+.fu8n8k9t8s8i8o8n8a8l.
+.3fu
+.fu4nk2
+.funk5t
+.funk4t1s2
+.funkt1s2io
+.funkt5sio2n
+.funktsio1n5a
+.ga8u8s8s9i8a8n.
+.ga2us
+.gau2ss
+.gaus1si
+.gauss2i1a
+.gaussi2a2n
+.gh8o8s8t9s8c8r8i8p8t.
+.ghos4t1s2
+.ghost4sc
+.ghostscri2
+.ghostscr2ip
+.ghostscri2p1t
+.gh8o8s8t9v8i8e8w.
+.ghos4tv
+.ghostv2ie4
+.gr8a8s8s9m8a8n8n9i8a8n.
+.gr2as
+.gra2ss
+.gras2s1m
+.grass3ma
+.grassma2n3
+.grassma4n1n2
+.grassman3n4i1a
+.grassma2nni3a2n
+.gr8e8i8f8s9w8a8l8d.
+.grei2
+.grei2f3s
+.greifsw2
+.greifswa2ld
+.gr8o8t8h8e8n9d8i8e8c8k.
+.g4ro
+.gro4th2e
+.gr4oth
+.grothe2n
+.grothend2ie4
+.grothendieck1
+.gr8u8n8d9l8e8h9r8e8n.
+.gru2n
+.grundle1h4
+.grundle4hr4
+.ha9d8a9m8a8r8d.
+.ha2d
+.ha1d2a
+.hada2m2
+.had4a1ma
+.hadam2a2r
+.ha8i9f8a.
+.hai1fa
+.ha8m8i8l9t8o8n9i8a8n.
+.ha4m
+.hami4lt
+.hamil1to
+.hamilto2n
+.hamilto3n4i1a
+.hamiltoni3a2n
+.he8l9s8i8n8k8i.
+.he2l1s2
+.hel2s1in
+.hels4i4nk2
+.helsink1i
+.he8r9m8i8t9i8a8n.
+.her3mit
+.hermi1ti
+.herm4i1t2i1a
+.hermiti2a2n
+.hi8b8b8s.
+.hi2b1b
+.hib2b5s2
+.ho8k9k8a8i9d8o.
+.h2ok
+.hokk4
+.hokkai2
+.hokka2id
+.hokkai1do
+.ja8c9k8o8w9s8k8i.
+.5ja
+.jack1
+.jackowsk2
+.jackowsk1i
+.ja8n9u9a8r8y.
+.ja2n
+.jan3u1a
+.janu2a2r
+.ja9p8a9n8e8s8e.
+.ja4p
+.ja1pa
+.japa2n
+.japa1nes
+.japane1s2e
+.ka8d9o8m9t8s8e8v.
+.ka2d
+.ka1do
+.kado4mt
+.kadom4t1s2
+.kadomt5sev
+.ka8n9s8a8s.
+.ka2n
+.kan2sa2
+.ka2n1s2
+.ka8r8l8s9r8u8h8e.
+.k2a2r
+.kar1l
+.kar2l1s2
+.karls1r
+.ko8r9t8e9w8e8g.
+.ko5r
+.kr8i8s8h8n8a.
+.kr2is
+.kr3is2h
+.kris2h1n
+.krish1na
+.kr8i8s8h9n8a9i8s8m.
+.krishnai2
+.krishnai2s1m
+.kr8i8s8h9n8a8n.
+.krishn2a2n
+.la8n9c8a8s9t8e8r.
+.lan1ca
+.lancast5er
+.le9g8e8n8d8r8e.
+.le1gen
+.legen1dr
+.legendre4
+.le8i8c8e8s9t8e8r.
+.lei2
+.le5ic
+.leices5t
+.li8p9s8c8h8i8t8z.
+.l2ip
+.li2p1s2
+.lips2ch2
+.lips3chit
+.lipschi4tz
+.li8p9s8c8h8i8t8z9i8a8n.
+.lipschit2z1i
+.lipschitz2i1a
+.lipschitzi2a2n
+.lo8j9b8a8n.
+.lo5j
+.lojba2n
+.lo8u9i9s8i9a8n8a.
+.lou2
+.lo2ui2
+.louis2i1a
+.louisi2a2n
+.louisia1na
+.ma8c9o8s.
+.ma1co
+.ma8n9c8h8e8s9t8e8r.
+.man2ch
+.manche2
+.manch1es
+.ma8r9k8o8v9i8a8n.
+.marko5vi2a2n
+.markov2i1a
+.ma8r8k8t9o8b8e8r9d8o8r8f.
+.mark5t
+.mark1to
+.markto3b
+.marktober1do
+.marktoberd4or
+.marktoberdor1f
+.ma8s8s9a9c8h8u9s8e8t8t8s.
+.ma2ss
+.mas1sa2
+.massa2ch
+.massach2us
+.massachuse4t3t2
+.massachuset4t1s2
+.ma8x9w8e8l8l.
+.maxwel4l
+.mi9c8r8o9s8o8f8t.
+.micro2so
+.microso2ft3
+.mi8n9n8e9a8p9o9l8i8s.
+.m2i4n1n2
+.minne4
+.minneapol2i
+.mi8n9n8e9s8o8t8a.
+.min1nes
+.minne1so
+.minneso1ta
+.mo8s9c8o8w.
+.mos2c
+.mos1co
+.na8c8h9r8i8c8h8t8e8n.
+.1na
+.na2ch
+.nac4hr4
+.na2chr4i2ch
+.nachricht1en
+.na8s8h9v8i8l8l8e.
+.n4as
+.nas2h
+.nash2vil
+.nashvil1l
+.nashvil2le
+.ne8t9b8s8d.
+.ne2t1b
+.net2b5s2
+.netb4s5d
+.ne8t9s8c8a8p8e.
+.ne4t1s2
+.net4sc
+.netsca4p
+.nets1ca
+.ni8j9m8e9g8e8n.
+.ni3j
+.nijme2g
+.nijme1gen
+.no8e9t8h8e8r9i8a8n.
+.3noe
+.noeth2e
+.noether1i
+.noethe1r2i3a4
+.noetheri2a2n
+.no8o8r8d9w8i8j8k8e8r9h8o8u8t.
+.noo2
+.no3ord
+.noord1w
+.noordwi2
+.noordwi3j
+.noordwijk1er
+.noordwijker1h4
+.noordwijkerhou2
+.no9v8e8m9b8e8r.
+.nove4m5b
+.op8e8n9b8s8d.
+.ope4n1b4
+.open2b5s2
+.openb4s5d
+.op8e8n9o8f8f8i8c8e.
+.op4eno
+.openo4f1f
+.openof1fi
+.pa8l8a9t8i8n8o.
+.pala2t1in
+.palat2i1no
+.pa9l8e8r9m8o.
+.paler3m4
+.paler1mo
+.pe9t8r8o8v9s8k8i.
+.petro3v
+.petrovsk2
+.petrovsk1i
+.pf8a8f8f9i8a8n.
+.4pf
+.p1fa
+.pfa2f
+.pfa4f1f4
+.pfaf1fi
+.pfaff2i3a
+.pfaffi2a2n
+.ph8i8l9a9d8e8l9p8h8i8a.
+.phi4l4ade
+.phila2d
+.philade2lp
+.philadel5phi
+.philadelph2i1a
+.ph8i8l9o9s8o8p8h9i9s8c8h8e.
+.philo2so
+.philos4op
+.philos2oph
+.philosoph2is1c
+.philosophis3ch2
+.philosophische2
+.po8i8n9c8a8r8e.
+.poin2
+.poi2
+.poinc2a2r5
+.poin1ca
+.po9t8e8n9t8i8a8l9g8l8e8i9c8h8u8n8g.
+.p4ot
+.po1ten1t
+.potent2i
+.poten1t2i1a
+.potenti2al
+.potentia4l1g4
+.potentialgl2
+.potential1gle
+.potentialglei2
+.potentialgle5ic
+.potentialgle4i2ch
+.ra9d8h8a9k8r8i8s8h9n8a8n.
+.rad1h2
+.radhakr2is
+.radhakr3is2h
+.radhakris2h1n
+.radhakrish1na
+.radhakrishn2a2n
+.ra8t8h8s9k8e8l9l8e8r.
+.r4ath
+.ra2t4h1s2
+.rathsk2
+.rath4ske
+.rathskel1l
+.rathskel2le
+.ri8e9m8a8n8n9i8a8n.
+.r2ie4
+.rie5ma2n
+.rie1ma
+.riema4n1n2
+.rieman3n4i1a
+.riema2nni3a2n
+.ry8d9b8e8r8g.
+.ry1d
+.ryd1b
+.rydberg2
+.sc8h8o8t9t8i8s8c8h8e.
+.scho4t3t2
+.schott2is1c
+.s2ch2ottis3ch2
+.schottische2
+.sc8h8r8o9d8i8n8g9e8r.
+.sc4hr4
+.schrod1in
+.schrod4inge
+.sc8h8w8a9b8a9c8h8e8r.
+.sch1w
+.schwaba2ch
+.schwabache2
+.sc8h8w8a8r8z9s8c8h8i8l8d.
+.schw2a2r
+.s2chwarzs2ch2
+.schwarzsch4il2
+.schwarzschi2ld
+.se8p9t8e8m9b8e8r.
+.se2p1t
+.sep2te
+.septe4m5b
+.st8o8k8e8s9s8c8h8e.
+.st2ok
+.stokes4
+.stok2e2ss
+.stokes2s5c
+.stokess2ch2
+.stokessche2
+.st8u8t8t9g8a8r8t.
+.stu4t3t2
+.stut4t1g
+.stutt1ga
+.stuttg2a2r
+.su8s9q8u8e9h8a8n9n8a.
+.s2us
+.susqu2
+.susque1h4
+.susqueha2n
+.susqueha4n1n2
+.susquehan1na
+.ta8u9b8e8r9i8a8n.
+.tau4b
+.taub4e
+.tau3ber
+.tauber1i
+.taube1r2i3a4
+.tauberi2a2n
+.te8c8h9n8i9s8c8h8e.
+.te2ch
+.tec2h1n
+.techn2is1c
+.te2chnis3ch2
+.technische2
+.te8n9n8e8s9s8e8e.
+.t4e4n1n2
+.tenne4
+.ten1nes
+.tenn2e2ss
+.to9m8a9s8z8e8w9s8k8i.
+.to2ma
+.tomas2ze
+.tomaszewsk2
+.tomaszewsk1i
+.ty9p8o9g8r8a8p8h8i8q8u8e.
+.ty3po
+.ty5po4g
+.typo1gr
+.typogr4aphi
+.typographiqu2
+.uk8r8a8i8n9i8a8n.
+.4uk
+.ukr2ai2
+.ukra4i4n
+.ukra2ini
+.ukrai4n4i1a
+.ukraini3a2n
+.ve8r9a8l8l9g8e9m8e8i8n9e8r8t8e.
+.veral1l
+.veral4l1g4
+.verallge1me
+.verallgemei2
+.verallgeme2ine
+.verallgemein1er
+.ve8r9e8i8n9i9g8u8n8g.
+.vere3in
+.verei2
+.vere2ini
+.verein2ig
+.vereini3gun
+.ve8r9t8e8i9l8u8n9g8e8n.
+.vertei2
+.verteilun1gen
+.vi8i8i8t8h.
+.v4i5i4
+.vi4i5i4
+.vii2ith
+.vi8i8t8h.
+.vi2ith
+.wa8h8r9s8c8h8e8i8n9l8i8c8h9k8e8i8t8s9t8h8e8o9r8i8e.
+.wa4hr4
+.wah4rs2
+.wahrs4c
+.wahrs2ch2
+.wahrsche2
+.wahrschei2
+.wahrsche4i4n1l
+.wahrs2cheinl4i2ch
+.wahrscheinlic4hk
+.wahrscheinlichkei2
+.wahrscheinlichkei4t1s2
+.wahrscheinlichkeits3th2e
+.wahrscheinlichkeitsthe1o5r
+.wahrscheinlichkeitstheor2ie4
+.we8r9n8e8r.
+.w1er
+.wer4n1er
+.we8r9t8h8e8r9i8a8n.
+.werth2e
+.werther1i
+.werthe1r2i3a4
+.wertheri2a2n
+.wi8n9c8h8e8s9t8e8r.
+.win2ch
+.winche2
+.winch1es
+.wi8r8t9s8c8h8a8f8t.
+.w4ir4
+.wir4t1s2
+.wirt4sc
+.wirts2ch2
+.wirtscha2f
+.wirtscha2ft
+.wi8s9s8e8n9s8c8h8a8f8t9l8i8c8h.
+.w4i2s1s
+.wissen4
+.wisse2n1s2
+.wissens4c
+.wissens2ch2
+.wissenscha2f
+.wissenscha2ft
+.wissenschaf2tl
+.wissens2chaftl4i2ch
+.xv8i8i8i8t8h.
+.xv4i5i4
+.xvi4i5i4
+.xvii2ith
+.xv8i8i8t8h.
+.xvi2ith
+.xx8i8i8i8r8d.
+.xx4
+.xx3i
+.xx4i5i4
+.xxi4i5i4
+.xxii4ir
+.xx8i8i8n8d.
+.xxi4ind
+.yi8n8g9y8o8n8g.
+.y1i
+.yin2gy
+.yingy1o4
+.yingyo2n
+.sh8u9x8u8e.
+.shux1u3
+.ji9s8u8a8n.
+.ji2su
+.jisua2n
+.ze8a9l8a8n8d.
+.2ze
+.zea4l
+.zea3l4and
+.zeala2n
+.ze8i8t9s8c8h8r8i8f8t.
+.zei2
+.zei4t1s2
+.zeit4sc
+.zeits2ch2
+.zeitsc4hr4
+.zeitschr4i2ft
diff --git a/core/res/res/drawable-hdpi/combobox_disabled.png b/core/res/res/drawable-hdpi/combobox_disabled.png
new file mode 100644
index 0000000..50eb45e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/combobox_disabled.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/combobox_nohighlight.png b/core/res/res/drawable-hdpi/combobox_nohighlight.png
new file mode 100644
index 0000000..9d60301
--- /dev/null
+++ b/core/res/res/drawable-hdpi/combobox_nohighlight.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/quickcontact_nobadge.9.png b/core/res/res/drawable-hdpi/quickcontact_nobadge.9.png
new file mode 100644
index 0000000..68d43c4
--- /dev/null
+++ b/core/res/res/drawable-hdpi/quickcontact_nobadge.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sym_action_call.png b/core/res/res/drawable-hdpi/sym_action_call.png
index 105f7d0..da8afee 100644
--- a/core/res/res/drawable-hdpi/sym_action_call.png
+++ b/core/res/res/drawable-hdpi/sym_action_call.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/combobox_disabled.png b/core/res/res/drawable-mdpi/combobox_disabled.png
new file mode 100644
index 0000000..c32db7e
--- /dev/null
+++ b/core/res/res/drawable-mdpi/combobox_disabled.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/combobox_nohighlight.png b/core/res/res/drawable-mdpi/combobox_nohighlight.png
new file mode 100644
index 0000000..1963316
--- /dev/null
+++ b/core/res/res/drawable-mdpi/combobox_nohighlight.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/quickcontact_nobadge.9.png b/core/res/res/drawable-mdpi/quickcontact_nobadge.9.png
new file mode 100644
index 0000000..ebe747b
--- /dev/null
+++ b/core/res/res/drawable-mdpi/quickcontact_nobadge.9.png
Binary files differ
diff --git a/core/res/res/drawable-nodpi/loading_tile_android.png b/core/res/res/drawable-nodpi/loading_tile_android.png
new file mode 100644
index 0000000..8fde46f
--- /dev/null
+++ b/core/res/res/drawable-nodpi/loading_tile_android.png
Binary files differ
diff --git a/core/res/res/drawable-nodpi/no_tile_256.png b/core/res/res/drawable-nodpi/no_tile_256.png
new file mode 100644
index 0000000..388234e
--- /dev/null
+++ b/core/res/res/drawable-nodpi/no_tile_256.png
Binary files differ
diff --git a/core/res/res/drawable/action_bar_background.xml b/core/res/res/drawable/action_bar_background.xml
new file mode 100644
index 0000000..3929d7f
--- /dev/null
+++ b/core/res/res/drawable/action_bar_background.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <gradient
+ android:startColor="#ffd1d2d4"
+ android:endColor="#ff85878a"
+ android:angle="270" />
+</shape>
diff --git a/core/res/res/drawable/action_bar_divider.xml b/core/res/res/drawable/action_bar_divider.xml
new file mode 100644
index 0000000..414309f
--- /dev/null
+++ b/core/res/res/drawable/action_bar_divider.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <gradient
+ android:startColor="#ffe1e2e4"
+ android:endColor="#ff95979a"
+ android:angle="270" />
+</shape>
diff --git a/core/res/res/drawable/ic_btn_back.png b/core/res/res/drawable/ic_btn_back.png
new file mode 100644
index 0000000..c9bff4c
--- /dev/null
+++ b/core/res/res/drawable/ic_btn_back.png
Binary files differ
diff --git a/core/res/res/drawable/ic_btn_next.png b/core/res/res/drawable/ic_btn_next.png
new file mode 100755
index 0000000..c6cf436
--- /dev/null
+++ b/core/res/res/drawable/ic_btn_next.png
Binary files differ
diff --git a/core/res/res/drawable/quickcontact_nobadge.xml b/core/res/res/drawable/quickcontact_nobadge.xml
deleted file mode 100644
index 922fa0e..0000000
--- a/core/res/res/drawable/quickcontact_nobadge.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* bubble_with_chats.xml
-**
-** Copyright 2009, Google Inc.
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="true" android:drawable="@drawable/quickcontact_nobadge_pressed" />
- <item android:state_selected="true" android:drawable="@drawable/quickcontact_nobadge_highlight" />
- <item android:state_focused="true" android:drawable="@drawable/quickcontact_nobadge_highlight" />
- <item android:state_enabled="false" android:drawable="@drawable/quickcontact_nobadge_normal" />
- <item android:drawable="@drawable/quickcontact_nobadge_normal" />
-</selector>
diff --git a/core/res/res/drawable/quickcontact_nobadge_highlight.9.png b/core/res/res/drawable/quickcontact_nobadge_highlight.9.png
deleted file mode 100644
index f0f50b3..0000000
--- a/core/res/res/drawable/quickcontact_nobadge_highlight.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/quickcontact_nobadge_normal.9.png b/core/res/res/drawable/quickcontact_nobadge_normal.9.png
deleted file mode 100644
index 01cc9dc..0000000
--- a/core/res/res/drawable/quickcontact_nobadge_normal.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/quickcontact_nobadge_pressed.9.png b/core/res/res/drawable/quickcontact_nobadge_pressed.9.png
deleted file mode 100644
index 6e22c87..0000000
--- a/core/res/res/drawable/quickcontact_nobadge_pressed.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/layout/action_bar_title_item.xml b/core/res/res/layout/action_bar_title_item.xml
new file mode 100644
index 0000000..d7f7c13
--- /dev/null
+++ b/core/res/res/layout/action_bar_title_item.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:textAppearance="?android:attr/textAppearanceMediumInverse" />
diff --git a/core/res/res/layout/keyguard_screen_unlock_landscape.xml b/core/res/res/layout/keyguard_screen_unlock_landscape.xml
index c1b406f..83381a1 100644
--- a/core/res/res/layout/keyguard_screen_unlock_landscape.xml
+++ b/core/res/res/layout/keyguard_screen_unlock_landscape.xml
@@ -58,18 +58,19 @@
android:ellipsize="marquee"
android:gravity="right|bottom"
/>
+
<com.android.internal.widget.DigitalClock android:id="@+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_marginTop="8dip"
+ android:layout_marginBottom="8dip"
>
<TextView android:id="@+id/timeDisplay"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:gravity="bottom"
android:singleLine="true"
android:ellipsize="none"
android:textSize="72sp"
@@ -84,8 +85,9 @@
<TextView android:id="@+id/am_pm"
android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:gravity="bottom"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/timeDisplay"
+ android:layout_alignBaseline="@id/timeDisplay"
android:singleLine="true"
android:ellipsize="none"
android:textSize="22sp"
diff --git a/core/res/res/layout/keyguard_screen_unlock_portrait.xml b/core/res/res/layout/keyguard_screen_unlock_portrait.xml
index 74a0eee..8dacfaf 100644
--- a/core/res/res/layout/keyguard_screen_unlock_portrait.xml
+++ b/core/res/res/layout/keyguard_screen_unlock_portrait.xml
@@ -55,12 +55,12 @@
android:layout_alignParentTop="true"
android:layout_marginTop="15dip"
android:layout_marginLeft="20dip"
+ android:layout_marginBottom="8dip"
>
<TextView android:id="@+id/timeDisplay"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:gravity="bottom"
android:singleLine="true"
android:ellipsize="none"
android:textSize="56sp"
@@ -74,8 +74,9 @@
<TextView android:id="@+id/am_pm"
android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:gravity="bottom"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/timeDisplay"
+ android:layout_alignBaseline="@id/timeDisplay"
android:singleLine="true"
android:ellipsize="none"
android:textSize="18sp"
diff --git a/core/res/res/layout/preference_list_content.xml b/core/res/res/layout/preference_list_content.xml
index 8f86981..844d338 100644
--- a/core/res/res/layout/preference_list_content.xml
+++ b/core/res/res/layout/preference_list_content.xml
@@ -4,22 +4,58 @@
**
** Copyright 2006, The Android Open Source Project
**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
+** 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
+** 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
+** 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.
*/
-->
-<ListView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@android:id/list"
- android:layout_width="match_parent"
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
android:layout_height="match_parent"
- android:drawSelectorOnTop="false"
- android:scrollbarAlwaysDrawVerticalTrack="true"
+ android:layout_width="match_parent">
+
+ <ListView android:id="@android:id/list"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layout_weight="1"
+ android:drawSelectorOnTop="false"
+ android:scrollbarAlwaysDrawVerticalTrack="true"
/>
+
+ <RelativeLayout android:id="@+id/button_bar"
+ android:layout_height="wrap_content"
+ android:layout_width="fill_parent"
+ android:layout_weight="0"
+ android:background="@android:drawable/bottom_bar"
+ android:visibility="gone">
+
+ <Button android:id="@+id/back_button"
+ android:layout_width="150dip"
+ android:layout_height="wrap_content"
+ android:layout_margin="5dip"
+ android:layout_alignParentLeft="true"
+ android:drawableLeft="@drawable/ic_btn_back"
+ android:drawablePadding="3dip"
+ android:text="@string/back_button_label"
+ />
+
+ <Button android:id="@+id/next_button"
+ android:layout_width="150dip"
+ android:layout_height="wrap_content"
+ android:layout_margin="5dip"
+ android:layout_alignParentRight="true"
+ android:drawableRight="@drawable/ic_btn_next"
+ android:drawablePadding="3dip"
+ android:text="@string/next_button_label"
+ />
+ </RelativeLayout>
+</LinearLayout>
diff --git a/core/res/res/layout/screen_action_bar.xml b/core/res/res/layout/screen_action_bar.xml
new file mode 100644
index 0000000..01a4b42
--- /dev/null
+++ b/core/res/res/layout/screen_action_bar.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!--
+This is an optimized layout for a screen with the Action Bar enabled.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:fitsSystemWindows="true">
+ <ActionBarView android:id="@+id/action_bar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="?android:attr/windowActionBarStyle" />
+ <FrameLayout android:id="@android:id/content"
+ android:layout_width="match_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1"
+ android:foregroundGravity="fill_horizontal|top"
+ android:foreground="?android:attr/windowContentOverlay" />
+ <LinearLayout android:id="@+id/context_action_bar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="?android:attr/windowActionBarStyle"
+ android:visibility="gone" />
+</LinearLayout>
+
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 8d4fa4e..d1fc0a3 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -244,6 +244,13 @@
{@link android.R.styleable#WindowAnimation}. -->
<attr name="windowAnimationStyle" format="reference" />
+ <!-- Flag indicating whether this window should have an Action Bar
+ in place of the usual title bar. -->
+ <attr name="windowActionBar" format="boolean" />
+
+ <!-- Reference to a style for the Action Bar -->
+ <attr name="windowActionBarStyle" format="reference" />
+
<!-- Defines the default soft input state that this window would
like when it is displayed. -->
<attr name="windowSoftInputMode">
@@ -390,6 +397,8 @@
<attr name="horizontalScrollViewStyle" format="reference" />
<!-- Default Spinner style. -->
<attr name="spinnerStyle" format="reference" />
+ <!-- Dropdown Spinner style. -->
+ <attr name="dropDownSpinnerStyle" format="reference" />
<!-- Default Star style. -->
<attr name="starStyle" format="reference" />
<!-- Default TabWidget style. -->
@@ -948,6 +957,8 @@
<attr name="textColor" />
<attr name="backgroundDimEnabled" />
<attr name="backgroundDimAmount" />
+ <attr name="windowActionBar" />
+ <attr name="windowActionBarStyle" />
</declare-styleable>
<!-- The set of attributes that describe a AlertDialog's theme. -->
@@ -1520,6 +1531,8 @@
will use only the number of items in the adapter and the number of items visible
on screen to determine the scrollbar's properties. -->
<attr name="smoothScrollbar" format="boolean" />
+ <!-- A reference to an XML description of the adapter to attach to the list. -->
+ <attr name="adapter" format="reference" />
</declare-styleable>
<declare-styleable name="AbsSpinner">
<!-- Reference to an array resource that will populate the Spinner. For static content,
@@ -2196,6 +2209,30 @@
<declare-styleable name="Spinner">
<!-- The prompt to display when the spinner's dialog is shown. -->
<attr name="prompt" format="reference" />
+ <!-- Display mode for spinner options. -->
+ <attr name="spinnerMode" format="enum">
+ <!-- Spinner options will be presented to the user as a dialog window. -->
+ <enum name="dialog" value="0" />
+ <!-- Spinner options will be presented to the user as an inline dropdown
+ anchored to the spinner widget itself. -->
+ <enum name="dropdown" value="1" />
+ </attr>
+ <!-- List selector to use for spinnerMode="dropdown" display. -->
+ <attr name="dropDownSelector" />
+ <!-- Background drawable to use for the dropdown in spinnerMode="dropdown". -->
+ <attr name="popupBackground" />
+ <!-- Vertical offset from the spinner widget for positioning the dropdown in
+ spinnerMode="dropdown". -->
+ <attr name="dropDownVerticalOffset" />
+ <!-- Horizontal offset from the spinner widget for positioning the dropdown
+ in spinnerMode="dropdown". -->
+ <attr name="dropDownHorizontalOffset" />
+ <!-- Width of the dropdown in spinnerMode="dropdown". -->
+ <attr name="dropDownWidth" />
+ <!-- Reference to a layout to use for displaying a prompt in the dropdown for
+ spinnerMode="dropdown". This layout must contain a TextView with the id
+ @android:id/text1 to be populated with the prompt text. -->
+ <attr name="popupPromptView" format="reference" />
</declare-styleable>
<declare-styleable name="DatePicker">
<!-- The first year (inclusive), for example "1940". -->
@@ -2506,6 +2543,10 @@
<attr name="drawable" />
</declare-styleable>
+ <declare-styleable name="MipmapDrawableItem">
+ <attr name="drawable" />
+ </declare-styleable>
+
<declare-styleable name="RotateDrawable">
<attr name="visible" />
<attr name="fromDegrees" format="float" />
@@ -3237,6 +3278,10 @@
<!-- Whether the item is enabled. -->
<attr name="enabled" />
+ <!-- Name of a method on the Context used to inflate the menu that will be
+ called when the item is clicked. -->
+ <attr name="onClick" />
+
</declare-styleable>
<!-- **************************************************************** -->
@@ -3339,6 +3384,16 @@
<attr name="entryValues" format="reference" />
</declare-styleable>
+ <declare-styleable name="MultiSelectListPreference">
+ <!-- The human-readable array to present as a list. Each entry must have a corresponding
+ index in entryValues. -->
+ <attr name="entries" />
+ <!-- The array to find the value to save for a preference when an entry from
+ entries is selected. If a user clicks the second item in entries, the
+ second item in this array will be saved to the preference. -->
+ <attr name="entryValues" />
+ </declare-styleable>
+
<!-- Base attributes available to RingtonePreference. -->
<declare-styleable name="RingtonePreference">
<!-- Which ringtone type(s) to show in the picker. -->
@@ -3514,6 +3569,39 @@
<!-- =============================== -->
<eat-comment />
+ <!-- ============================= -->
+ <!-- View package class attributes -->
+ <!-- ============================= -->
+ <eat-comment />
+
+ <!-- Attributes that can be used with <code><fragment></code>
+ tags inside of the layout of an Activity. This instantiates
+ the given {@link android.app.Fragment} and inserts its content
+ view into the current location in the layout. -->
+ <declare-styleable name="Fragment">
+ <!-- Supply the name of the fragment class to instantiate. -->
+ <attr name="name" />
+
+ <!-- Supply an identifier name for the top-level view, to later retrieve it
+ with {@link android.view.View#findViewById View.findViewById()} or
+ {@link android.app.Activity#findViewById Activity.findViewById()}.
+ This must be a
+ resource reference; typically you set this using the
+ <code>@+</code> syntax to create a new ID resources.
+ For example: <code>android:id="@+id/my_id"</code> which
+ allows you to later retrieve the view
+ with <code>findViewById(R.id.my_id)</code>. -->
+ <attr name="id" />
+
+ <!-- Supply a tag for the top-level view containing a String, to be retrieved
+ later with {@link android.view.View#getTag View.getTag()} or
+ searched for with {@link android.view.View#findViewWithTag
+ View.findViewWithTag()}. It is generally preferable to use
+ IDs (through the android:id attribute) instead of tags because
+ they are faster and allow for compile-time type checking. -->
+ <attr name="tag" />
+ </declare-styleable>
+
<!-- Use <code>device-admin</code> as the root tag of the XML resource that
describes a
{@link android.app.admin.DeviceAdminReceiver}, which is
@@ -3616,6 +3704,9 @@
<attr name="detailColumn" format="string" />
<!-- Flag indicating that detail should be built from SocialProvider. -->
<attr name="detailSocialSummary" format="boolean" />
+ <!-- Resource representing the term "All Contacts" (e.g. "All Friends" or
+ "All connections"). Optional (Default is "All Contacts"). -->
+ <attr name="allContactsName" format="string" />
</declare-styleable>
<!-- =============================== -->
@@ -3646,5 +3737,106 @@
<declare-styleable name="RecognitionService">
<attr name="settingsActivity" />
</declare-styleable>
+
+ <!-- =============================== -->
+ <!-- Adapters attributes -->
+ <!-- =============================== -->
+ <eat-comment />
+
+ <!-- Adapter used to bind cursors. -->
+ <declare-styleable name="CursorAdapter">
+ <!-- URI to get the cursor from. Optional. -->
+ <attr name="uri" format="string" />
+ <!-- Selection statement for the query. Optional. -->
+ <attr name="selection" format="string" />
+ <!-- Sort order statement for the query. Optional. -->
+ <attr name="sortOrder" format="string" />
+ <!-- Layout resource used to display each row from the cursor. Mandatory. -->
+ <attr name="layout" />
+ </declare-styleable>
+
+ <!-- Attributes used in bind items for XML cursor adapters. -->
+ <declare-styleable name="CursorAdapter_BindItem">
+ <!-- The name of the column to bind from. Mandatory. -->
+ <attr name="from" format="string" />
+ <!-- The resource id of the view to bind to. Mandatory. -->
+ <attr name="to" format="reference" />
+ <!-- The type of binding. If this value is not specified, the type will be
+ inferred from the type of the "to" target view. Mandatory.
+
+ The type can be one of:
+ <ul>
+ <li>string, The content of the column is interpreted as a string.</li>
+ <li>image, The content of the column is interpreted as a blob describing an image.</li>
+ <li>image-uri, The content of the column is interpreted as a URI to an image.</li>
+ <li>drawable, The content of the column is interpreted as a resource id to a drawable.</li>
+ <li>A fully qualified class name, corresponding to an implementation of
+ android.widget.Adapters.CursorBinder.</li>
+ </ul>
+ -->
+ <attr name="as" format="string" />
+ </declare-styleable>
+
+ <!-- Attributes used in select items for XML cursor adapters. -->
+ <declare-styleable name="CursorAdapter_SelectItem">
+ <!-- The name of the column to select. Mandatory. -->
+ <attr name="column" format="string" />
+ </declare-styleable>
+
+ <!-- Attributes used to map values to new values in XML cursor adapters' bind items. -->
+ <declare-styleable name="CursorAdapter_MapItem">
+ <!-- The original value from the column. Mandatory. -->
+ <attr name="fromValue" format="string" />
+ <!-- The new value from the column. Mandatory. -->
+ <attr name="toValue" format="string" />
+ </declare-styleable>
+
+ <!-- Attributes used to map values to new values in XML cursor adapters' bind items. -->
+ <declare-styleable name="CursorAdapter_TransformItem">
+ <!-- The transformation expression. Mandatory if "withClass" is not specified. -->
+ <attr name="withExpression" format="string" />
+ <!-- The transformation class, an implementation of
+ android.widget.Adapters.CursorTransformation. Mandatory if "withExpression"
+ is not specified. -->
+ <attr name="withClass" format="string" />
+ </declare-styleable>
+
+ <!-- Attributes used to style the Action Bar. -->
+ <declare-styleable name="ActionBar">
+ <!-- The type of navigation to use. -->
+ <attr name="navigationMode">
+ <!-- Normal static title text -->
+ <enum name="normal" value="0" />
+ <!-- The action bar will use a drop-down selection in place of title text. -->
+ <enum name="dropdownList" value="1" />
+ <!-- The action bar will use a series of horizontal tabs in place of title text. -->
+ <enum name="tabBar" value="2" />
+ </attr>
+ <!-- Options affecting how the action bar is displayed. -->
+ <attr name="displayOptions">
+ <flag name="useLogo" value="1" />
+ <flag name="hideHome" value="2" />
+ </attr>
+ <!-- Specifies the color used to style the action bar. -->
+ <attr name="colorFilter" format="color" />
+ <!-- Specifies title text used for navigationMode="normal" -->
+ <attr name="title" />
+ <!-- Specifies subtitle text used for navigationMode="normal" -->
+ <attr name="subtitle" format="string" />
+ <!-- Specifies a style to use for title text. -->
+ <attr name="titleTextStyle" format="reference" />
+ <!-- Specifies a style to use for subtitle text. -->
+ <attr name="subtitleTextStyle" format="reference" />
+ <!-- Specifies the drawable used for the application icon. -->
+ <attr name="icon" />
+ <!-- Specifies the drawable used for the application logo. -->
+ <attr name="logo" />
+ <!-- Specifies the drawable used for item dividers. -->
+ <attr name="divider" />
+ <!-- Specifies a background drawable for the action bar. -->
+ <attr name="background" />
+ <!-- Specifies a layout for custom navigation. Overrides navigationMode. -->
+ <attr name="customNavigationLayout" format="reference" />
+ </declare-styleable>
</resources>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 5ca7b28..16aac74 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -235,6 +235,10 @@
the safe mode. -->
<attr name="vmSafeMode" format="boolean" />
+ <!-- Flag indicating whether the application's rendering should be hardware
+ accelerated if possible. -->
+ <attr name="hardwareAccelerated" format="boolean" />
+
<!-- Flag indicating whether the given application component is available
to other applications. If false, it can only be accessed by
applications with its same user id (which usually means only by
@@ -730,6 +734,7 @@
<attr name="enabled" />
<attr name="debuggable" />
<attr name="vmSafeMode" />
+ <attr name="hardwareAccelerated" />
<!-- Name of activity to be launched for managing the application's space on the device. -->
<attr name="manageSpaceActivity" />
<attr name="allowClearUserData" />
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index 8b6af71..e607fad5 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -68,4 +68,5 @@
<item type="id" name="accountPreferences" />
<item type="id" name="smallIcon" />
<item type="id" name="custom" />
+ <item type="id" name="home" />
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 1932771..65400da 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1238,7 +1238,7 @@
<public type="id" name="custom" id="0x0102002b" />
<public type="anim" name="cycle_interpolator" id="0x010a000c" />
-
+
<!-- ===============================================================
Resources introduced in kraken.
=============================================================== -->
@@ -1259,4 +1259,34 @@
<public-padding type="color" name="kraken_resource_pad" end="0x01060020" />
<public-padding type="array" name="kraken_resource_pad" end="0x01070010" />
+<!-- ===============================================================
+ Resources proposed for Gingerbread.
+ =============================================================== -->
+ <eat-comment />
+ <public type="attr" name="adapter" />
+ <public type="attr" name="selection" />
+ <public type="attr" name="sortOrder" />
+ <public type="attr" name="uri" />
+ <public type="attr" name="from" />
+ <public type="attr" name="to" />
+ <public type="attr" name="as" />
+ <public type="attr" name="fromValue" />
+ <public type="attr" name="toValue" />
+ <public type="attr" name="column" />
+ <public type="attr" name="withExpression" />
+ <public type="attr" name="withClass" />
+ <public type="attr" name="allContactsName" />
+ <public type="attr" name="windowActionBar" />
+ <public type="attr" name="windowActionBarStyle" />
+ <public type="attr" name="navigationMode" />
+ <public type="attr" name="displayOptions" />
+ <public type="attr" name="subtitle" />
+ <public type="attr" name="customNavigationLayout" />
+ <public type="attr" name="hardwareAccelerated" />
+
+ <public type="id" name="home" />
+
+ <public type="style" name="Theme.WithActionBar" />
+ <public type="style" name="Widget.Spinner.DropDown" />
+
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index e7f892a..a30b44b 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -934,6 +934,11 @@
the flashlight.</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_accessUsb">access USB devices</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_accessUsb">Allows the application to access USB devices.</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_hardware_test">test hardware</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_hardware_test">Allows the application to control
@@ -1421,10 +1426,14 @@
Displayed in one line in a large font. -->
<string name="keyguard_password_enter_pin_code">Enter PIN code</string>
- <!-- Instructions telling the user to enter their PIN password to unlock the keyguard.
+ <!-- Instructions telling the user to enter their text password to unlock the keyguard.
Displayed in one line in a large font. -->
<string name="keyguard_password_enter_password_code">Enter password to unlock</string>
+ <!-- Instructions telling the user to enter their PIN password to unlock the keyguard.
+ Displayed in one line in a large font. -->
+ <string name="keyguard_password_enter_pin_password_code">Enter PIN to unlock</string>
+
<!-- Instructions telling the user that they entered the wrong pin while trying
to unlock the keyguard. Displayed in one line in a large font. -->
<string name="keyguard_password_wrong_pin_code">Incorrect PIN code!</string>
@@ -1461,6 +1470,8 @@
<string name="lockscreen_pattern_correct">Correct!</string>
<!-- On the unlock pattern screen, shown when the user enters the wrong lock pattern and must try again. -->
<string name="lockscreen_pattern_wrong">Sorry, try again</string>
+ <!-- On the unlock password screen, shown when the user enters the wrong lock password and must try again. -->
+ <string name="lockscreen_password_wrong">Sorry, try again</string>
<!-- When the lock screen is showing and the phone plugged in, and the battery
is not fully charged, show the current charge %. -->
@@ -1504,12 +1515,27 @@
progress dialog in the meantime. this is the emssage. -->
<string name="lockscreen_sim_unlock_progress_dialog_message">Unlocking SIM card\u2026</string>
- <!-- For the unlock screen, Information message shown in dialog when user has too many failed attempts -->
+ <!-- For the unlock screen, Information message shown in dialog when user has too many failed attempts at
+ drawing the unlock pattern -->
<string name="lockscreen_too_many_failed_attempts_dialog_message">
You have incorrectly drawn your unlock pattern <xliff:g id="number">%d</xliff:g> times.
\n\nPlease try again in <xliff:g id="number">%d</xliff:g> seconds.
</string>
+ <!-- For the unlock screen, Information message shown in dialog when user has too many failed attempts at
+ entering the password -->
+ <string name="lockscreen_too_many_failed_password_attempts_dialog_message">
+ You have incorrectly entered your password <xliff:g id="number">%d</xliff:g> times.
+ \n\nPlease try again in <xliff:g id="number">%d</xliff:g> seconds.
+ </string>
+
+ <!-- For the unlock screen, Information message shown in dialog when user has too many failed attempts at
+ entering the PIN -->
+ <string name="lockscreen_too_many_failed_pin_attempts_dialog_message">
+ You have incorrectly entered your PIN <xliff:g id="number">%d</xliff:g> times.
+ \n\nPlease try again in <xliff:g id="number">%d</xliff:g> seconds.
+ </string>
+
<!-- For the unlock screen, Information message shown in dialog when user is almost at the limit
where they will be locked out and may have to enter an alternate username/password to unlock the phone -->
<string name="lockscreen_failed_attempts_almost_glogin">
@@ -1580,7 +1606,7 @@
<!-- Do not translate. WebView User Agent string -->
<string name="web_user_agent" translatable="false"><xliff:g id="x">Mozilla/5.0 (Linux; U; Android %s)
- AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1</xliff:g></string>
+ AppleWebKit/534.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.1</xliff:g></string>
<!-- Title for a JavaScript dialog. "The page at <url of current page> says:" -->
<string name="js_dialog_title">The page at \'<xliff:g id="title">%s</xliff:g>\' says:</string>
@@ -2225,6 +2251,8 @@
<!-- Localized strings for WebView -->
<!-- Label for button in a WebView that will open a chooser to choose a file to upload -->
<string name="upload_file">Choose file</string>
+ <!-- Label for the file upload control when no file has been chosen yet -->
+ <string name="no_file_chosen">No file chosen</string>
<!-- Label for <input type="reset"> button in html -->
<string name="reset">Reset</string>
<!-- Label for <input type="submit"> button in html -->
@@ -2246,6 +2274,10 @@
<string name="tethered_notification_title">Tethering or hotspot active</string>
<string name="tethered_notification_message">Touch to configure</string>
+ <!-- Strings for possible PreferenceActivity Back/Next buttons -->
+ <string name="back_button_label">Back</string>
+ <string name="next_button_label">Next</string>
+
<!-- Strings for throttling notification -->
<!-- Shown when the user is in danger of being throttled -->
<string name="throttle_warning_notification_title">High mobile data use</string>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index af04117..4f74413 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -451,6 +451,18 @@
<style name="Widget.Spinner">
<item name="android:background">@android:drawable/btn_dropdown</item>
<item name="android:clickable">true</item>
+ <item name="android:spinnerMode">dialog</item>
+
+ <item name="android:dropDownSelector">@android:drawable/list_selector_background</item>
+ <item name="android:popupBackground">@android:drawable/spinner_dropdown_background</item>
+ <item name="android:dropDownVerticalOffset">-10dip</item>
+ <item name="android:dropDownHorizontalOffset">0dip</item>
+ <item name="android:dropDownWidth">wrap_content</item>
+ <item name="android:popupPromptView">@android:layout/simple_dropdown_hint</item>
+ </style>
+
+ <style name="Widget.Spinner.DropDown">
+ <item name="android:spinnerMode">dropdown</item>
</style>
<style name="Widget.TextView.PopupMenu">
@@ -567,6 +579,7 @@
<item name="android:background">@android:drawable/quickcontact_badge</item>
<item name="android:clickable">true</item>
<item name="android:scaleType">fitCenter</item>
+ <item name="android:src">@android:drawable/ic_contact_picture</item>
</style>
<style name="Widget.QuickContactBadgeSmall">
@@ -854,4 +867,10 @@
<item name="android:paddingBottom">1dip</item>
<item name="android:background">@android:drawable/bottom_bar</item>
</style>
+
+ <style name="ActionBar">
+ <item name="android:background">@android:drawable/action_bar_background</item>
+ <item name="android:displayOptions">useLogo</item>
+ <item name="android:divider">@android:drawable/action_bar_divider</item>
+ </style>
</resources>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index d585d9e..bc5f610 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -115,6 +115,8 @@
<item name="windowTitleBackgroundStyle">@android:style/WindowTitleBackground</item>
<item name="android:windowAnimationStyle">@android:style/Animation.Activity</item>
<item name="android:windowSoftInputMode">stateUnspecified|adjustUnspecified</item>
+ <item name="windowActionBar">false</item>
+ <item name="windowActionBarStyle">@android:style/ActionBar</item>
<!-- Dialog attributes -->
<item name="alertDialogStyle">@android:style/AlertDialog</item>
@@ -167,6 +169,7 @@
<item name="scrollViewStyle">@android:style/Widget.ScrollView</item>
<item name="horizontalScrollViewStyle">@android:style/Widget.HorizontalScrollView</item>
<item name="spinnerStyle">@android:style/Widget.Spinner</item>
+ <item name="dropDownSpinnerStyle">@android:style/Widget.Spinner.DropDown</item>
<item name="starStyle">@android:style/Widget.CompoundButton.Star</item>
<item name="tabWidgetStyle">@android:style/Widget.TabWidget</item>
<item name="textViewStyle">@android:style/Widget.TextView</item>
@@ -521,5 +524,9 @@
<item name="android:windowAnimationStyle">@android:style/Animation.RecentApplications</item>
<item name="android:textColor">@android:color/secondary_text_nofocus</item>
</style>
+
+ <style name="Theme.WithActionBar">
+ <item name="android:windowActionBar">true</item>
+ </style>
</resources>
diff --git a/core/res/res/xml/power_profile.xml b/core/res/res/xml/power_profile.xml
index ce623e8..30312b3 100644
--- a/core/res/res/xml/power_profile.xml
+++ b/core/res/res/xml/power_profile.xml
@@ -18,6 +18,7 @@
-->
<device name="Android">
+ <!-- All values are in mAh except as noted -->
<item name="none">0</item>
<item name="screen.on">0.1</item>
<item name="bluetooth.active">0.1</item>
@@ -48,4 +49,6 @@
<array name="cpu.active">
<value>0.2</value>
</array>
+ <!-- This is the battery capacity in mAh -->
+ <item name="battery.capacity">1000</item>
</device>
diff --git a/core/tests/coretests/res/raw/v21_backslash.vcf b/core/tests/coretests/res/raw/v21_backslash.vcf
deleted file mode 100644
index bd3002b..0000000
--- a/core/tests/coretests/res/raw/v21_backslash.vcf
+++ /dev/null
@@ -1,5 +0,0 @@
-BEGIN:VCARD
-VERSION:2.1
-N:;A\;B\\;C\\\;;D;\:E;\\\\;
-FN:A;B\C\;D:E\\
-END:VCARD
diff --git a/core/tests/coretests/res/raw/v21_complicated.vcf b/core/tests/coretests/res/raw/v21_complicated.vcf
deleted file mode 100644
index de34e16..0000000
--- a/core/tests/coretests/res/raw/v21_complicated.vcf
+++ /dev/null
@@ -1,106 +0,0 @@
-BEGIN:VCARD
-VERSION:2.1
-N:Gump;Forrest;Hoge;Pos;Tao
-FN:Joe Due
-ORG:Gump Shrimp Co.;Sales Dept.\;Manager;Fish keeper
-ROLE:Fish Cake Keeper!
-X-CLASS:PUBLIC
-TITLE:Shrimp Man
-TEL;WORK;VOICE:(111) 555-1212
-TEL;HOME;VOICE:(404) 555-1212
-TEL;CELL:0311111111
-TEL;VIDEO:0322222222
-TEL;VOICE:0333333333
-ADR;WORK:;;100 Waters Edge;Baytown;LA;30314;United States of America
-LABEL;WORK;ENCODING=QUOTED-PRINTABLE:100 Waters Edge=0D=0ABaytown, LA 30314=0D=0AUnited States of America
-ADR;HOME:;;42 Plantation St.;Baytown;LA;30314;United States of America
-LABEL;HOME;ENCODING=QUOTED-PRINTABLE:42 Plantation St.=0D=0A=
-Baytown, LA 30314=0D=0A=
-United States of America
-EMAIL;PREF;INTERNET:forrestgump@walladalla.com
-EMAIL;CELL:cell@example.com
-NOTE:The following note is the example from RFC 2045.
-NOTE;ENCODING=QUOTED-PRINTABLE:Now's the time =
-for all folk to come=
- to the aid of their country.
-
-PHOTO;ENCODING=BASE64;TYPE=JPEG:
- /9j/4QoPRXhpZgAATU0AKgAAAAgADQEOAAIAAAAPAAAAqgEPAAIAAAAHAAAAugEQAAIAAAAG
- AAAAwgESAAMAAAABAAEAAAEaAAUAAAABAAAAyAEbAAUAAAABAAAA0AEoAAMAAAABAAIAAAEx
- AAIAAAAOAAAA2AEyAAIAAAAUAAAA5gITAAMAAAABAAEAAIKYAAIAAAAOAAAA+odpAAQAAAAB
- AAABhMSlAAcAAAB8AAABCAAABB4yMDA4MTAyOTEzNTUzMQAARG9Db01vAABEOTA1aQAAAABI
- AAAAAQAAAEgAAAABRDkwNWkgVmVyMS4wMAAyMDA4OjEwOjI5IDEzOjU1OjQ3ACAgICAgICAg
- ICAgICAAUHJpbnRJTQAwMzAwAAAABgABABQAFAACAQAAAAADAAAANAEABQAAAAEBAQAAAAEQ
- gAAAAAAAEQkAACcQAAAPCwAAJxAAAAWXAAAnEAAACLAAACcQAAAcAQAAJxAAAAJeAAAnEAAA
- AIsAACcQAAADywAAJxAAABvlAAAnEAAogpoABQAAAAEAAANqgp0ABQAAAAEAAANyiCIAAwAA
- AAEAAgAAkAAABwAAAAQwMjIwkAMAAgAAABQAAAN6kAQAAgAAABQAAAOOkQEABwAAAAQBAgMA
- kQIABQAAAAEAAAOikgEACgAAAAEAAAOqkgIABQAAAAEAAAOykgQACgAAAAEAAAO6kgUABQAA
- AAEAAAPCkgcAAwAAAAEAAgAAkggAAwAAAAEAAAAAkgkAAwAAAAEAAAAAkgoABQAAAAEAAAPK
- knwABwAAAAEAAAAAkoYABwAAABYAAAPSoAAABwAAAAQwMTAwoAEAAwAAAAEAAQAAoAIAAwAA
- AAEAYAAAoAMAAwAAAAEASAAAoAUABAAAAAEAAAQAog4ABQAAAAEAAAPoog8ABQAAAAEAAAPw
- ohAAAwAAAAEAAgAAohcAAwAAAAEAAgAAowAABwAAAAEDAAAAowEABwAAAAEBAAAApAEAAwAA
- AAEAAAAApAIAAwAAAAEAAAAApAMAAwAAAAEAAAAApAQABQAAAAEAAAP4pAUAAwAAAAEAHQAA
- pAYAAwAAAAEAAAAApAcAAwAAAAEAAAAApAgAAwAAAAEAAAAApAkAAwAAAAEAAAAApAoAAwAA
- AAEAAAAApAwAAwAAAAEAAgAAAAAAAAAAAFMAACcQAAABXgAAAGQyMDA4OjEwOjI5IDEzOjU1
- OjMxADIwMDg6MTA6MjkgMTM6NTU6NDcAAAApiAAAGwAAAAKyAAAAZAAAAV4AAABkAAAAAAAA
- AGQAAAAlAAAACgAADpIAAAPoAAAAAAAAAAAyMDA4MTAyOTEzNTUzMQAAICoAAAAKAAAq4gAA
- AAoAAAAAAAAAAQACAAEAAgAAAARSOTgAAAIABwAAAAQwMTAwAAAAAAAGAQMAAwAAAAEABgAA
- ARoABQAAAAEAAARsARsABQAAAAEAAAR0ASgAAwAAAAEAAgAAAgEABAAAAAEAAAR8AgIABAAA
- AAEAAAWLAAAAAAAAAEgAAAABAAAASAAAAAH/2P/bAIQAIBYYHBgUIBwaHCQiICYwUDQwLCww
- YkZKOlB0Znp4cmZwboCQuJyAiK6KbnCg2qKuvsTO0M58muLy4MjwuMrOxgEiJCQwKjBeNDRe
- xoRwhMbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbG
- /8AAEQgAeACgAwEhAAIRAQMRAf/EAaIAAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKCxAA
- AgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkK
- FhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWG
- h4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl
- 5ufo6erx8vP09fb3+Pn6AQADAQEBAQEBAQEBAAAAAAAAAQIDBAUGBwgJCgsRAAIBAgQEAwQH
- BQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGxwQkjM1LwFWJy0QoWJDThJfEXGBka
- JicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJipKT
- lJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5+jp6vLz
- 9PX29/j5+v/aAAwDAQACEQMRAD8AFFSqKkZIoqRVpgSKKeBTEOApwFADsUYpgIRSEUANIppF
- ICNhUTCgCMio2FICJhULCgC0oqVaAJFFSqKBkgFOApiHCnCgB2KMUCENJQA0imEUDGMKiYUA
- RtUbUgIWqJhQBZSpFoAlWpVoGPFPFMQ7tSK2ODQA4yKO9HmKe9FxAzDHFIOlAAaYaAGNUTUD
- ImqNqQETVE1AE6VKKAJFNSqaAHg08GmANIFFQM5Y5qJMBuT60ZNQIcrkVYSQMKuLGKaaasQx
- qiagZE1RtSAjaomoAkQ1KpoAlU1IpoAkU07OBTArO+5qkV12Y71lfUBmaKkCRSuznrTFba2a
- oCwGyM0E1qIjY1GxoGRNUZNICNqiagByGplNAEimpFNMB4YDvSucpxSYEIU04KazsAu1qArU
- WELtPpTSposBNETt5pxNaoCNjUbGgCNjUZoGRtUTUgFU1KpoAkBqQHigCFnO7rUqOdlZp6gA
- c+tODn1pXAXzD60eYfWncQvmNSGQ07gOMhCVEJGz1ptgS5yKYxqwGE1GxoAiamGkMapqVTQB
- Kpp+eKAICfmqWM/Kaz6gANOBqQFzRmmAuaTNACsfkqMHmm9wJs8U0mtRDGNRsaAI2phpDI1N
- SqaAJFNSA8UCISfmqSM/Kaz6jAHmnA1ICg0uaAFzSZpgKx+SmDrTe4E2eKaTWoiMmmMaAIzT
- DSGRKakU0ASKaeDTERseakjPyms+oxAacDUgOBpc0gFzSZpgOY/KKYv3qrqIlpprQBjGoyaA
- GGmmkMgU1IppgPBqQGgQu0Gn4wvFKwEQpwNZDHZpc0ALmigRKBleaQKBWtgA001QDGqM0gGm
- mGkMrqakBoAepp4NMRIDTwaAE2A008GokgHxjd1pzKFpW0uAg5NSBBTirgOpDWgDTTTQAw0w
- 0gGGmmgZWBp4pASKaeDTEOBp4NADwajbrUyBEkXWnSUdAGr1qeiAMSkNWAhphoAaaYaQDDTT
- SGVRTwaYDxTwaBDwaeDQA4GlK5oauIeo20pGaLaAKqgU6hKwBSGmAhphoAaaYaQxhpppDKgN
- PFMB4p4oEPFOBpgPBp4NAhwpwoAWloAKSgBDTTQMYaYaQDTTTSGA/9n/2wCEAAoHBwgHBgoI
- CAgLCgoLDhgQDg0NDh0VFhEYIx8lJCIfIiEmKzcvJik0KSEiMEExNDk7Pj4+JS5ESUM8SDc9
- PjsBCgsLDg0OHBAQHDsoIig7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7
- Ozs7Ozs7Ozs7Ozs7O//AABEIAEgAYAMBIQACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAA
- AQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNC
- scEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hp
- anN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS
- 09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+gEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcI
- CQoLEQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVi
- ctEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4
- eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY
- 2dri4+Tl5ufo6ery8/T19vf4+fr/2gAMAwEAAhEDEQA/AJ7SLgcVr20I4rNFGvbQAAHFaEUX
- SrQi5HCMdKk8oY6VSJYx4hjpVaWMelAFC4iGDxWPdR8mkxmRdxjBrEvI+tZjN20xtHNbNqAc
- UIDXg6Cr0WKtCY8XKQOyzOB3FKNWsyceZ+lS6sY6NkjvPSdwImBHUmmy4q076oCjOODWPdgc
- 0MpGPdAYNYl4o5rNjNKzkyorZtXxihAa1vIDip7m9Frb7/4jwKcnyxbEzN3ieJppZsyZ4U1H
- urzZau4mWVlNrGk0UuWPVa1YroXEIkHfrXZh5W90RWncAHmsi6bJNdQ0ZNw3BrGuiMGs2Mks
- puBzWzbzdOaEBeOpR2oUtkk9hTru7iuo4m8wgemKyqTi04sBsfkEf68j8KlUQZz9o/SuZRj3
- JYriAji4/Sp7W6htbV2aXcu70ramoxle4gN7HcIXjbis+4k5NdaaauhmVcv1rHuW61DGiG1m
- 6c1s20/TmgAv5vmj57VKk3+ixnPc1xVV70h9CVJuOtSrL71hFgxzScUkkn+iY/2q1i9xDrGT
- 9y31pJ5Otd1L+GhMy7mTrWXO2SapjRn28vTmta3nxjmgGOvJd2w1Kkv+ipz/ABGuOoveYdCe
- ObjrU6y5rlsA8ycUksn+ij/eNaw6iJLNsW59zTJn6816FP4EJmbO+Saz5m602UjIgk4HNadv
- LwKaBl+MpIMOMipp490SCJeF7CoqQvF2JuRqWQ4YEGrSiQJuKnHrXByMpki73GFBNXIoh9n2
- SrnnOK6MPTbd3sSwIVF2qMCqkzHmuy1lYRnTHrVGWpZaMKB+BWlbycYoQM0IZDxzV+GU8c1a
- IYy5Y+dnHatAsfsAHfArmS1mPoh1gT8x9qtk1rQX7tCe5DIapzGtGBQm71SlqGWjnIH6Vowt
- zmhAy/E3vV6F6tEMuxlWIyAfrVxCCAO1VZEEyYA4AApxNGwyJ+lVJRUsaKMw61SlFQzRAP/Z
-
-X-ATTRIBUTE:Some String
-BDAY:19800101
-GEO:35.6563854,139.6994233
-URL:http://www.example.com/
-REV:20080424T195243Z
-END:VCARD
\ No newline at end of file
diff --git a/core/tests/coretests/res/raw/v21_invalid_comment_line.vcf b/core/tests/coretests/res/raw/v21_invalid_comment_line.vcf
deleted file mode 100644
index f910710..0000000
--- a/core/tests/coretests/res/raw/v21_invalid_comment_line.vcf
+++ /dev/null
@@ -1,10 +0,0 @@
-BEGIN:vCard
-VERSION:2.1
-UID:357
-N:;Conference Call
-FN:Conference Call
-# This line must be ignored.
-NOTE;ENCODING=QUOTED-PRINTABLE:This is an (sharp ->=
-#<- sharp) example. This message must NOT be ignored.
-# This line must be ignored too.
-END:vCard
diff --git a/core/tests/coretests/res/raw/v21_japanese_1.vcf b/core/tests/coretests/res/raw/v21_japanese_1.vcf
deleted file mode 100644
index d05e2ff..0000000
--- a/core/tests/coretests/res/raw/v21_japanese_1.vcf
+++ /dev/null
@@ -1,6 +0,0 @@
-BEGIN:VCARD
-VERSION:2.1
-N;CHARSET=SHIFT_JIS:À¡Ch;;;;
-SOUND;X-IRMC-N;CHARSET=SHIFT_JIS:±ÝÄÞ³Û²ÄÞ;;;;
-TEL;PREF;VOICE:0300000000
-END:VCARD
diff --git a/core/tests/coretests/res/raw/v21_japanese_2.vcf b/core/tests/coretests/res/raw/v21_japanese_2.vcf
deleted file mode 100644
index fa54acb..0000000
--- a/core/tests/coretests/res/raw/v21_japanese_2.vcf
+++ /dev/null
@@ -1,10 +0,0 @@
-BEGIN:VCARD
-VERSION:2.1
-FN;CHARSET=SHIFT_JIS:À¡ Ch 1
-N;CHARSET=SHIFT_JIS:À¡;Ch1;;;
-SOUND;X-IRMC-N;CHARSET=SHIFT_JIS:±ÝÄÞ³;Û²ÄÞ1;;;
-ADR;HOME;CHARSET=SHIFT_JIS;ENCODING=QUOTED-PRINTABLE:;=93=8C=8B=9E=93=73=
-=8F=61=92=4A=8B=E6=8D=F7=8B=75=92=AC26-1=83=5A=83=8B=83=8A=83=41=83=93=
-=83=5E=83=8F=81=5B6=8A=4B;;;;150-8512;
-NOTE;CHARSET=SHIFT_JIS;ENCODING=QUOTED-PRINTABLE:=83=81=83=82
-END:VCARD
diff --git a/core/tests/coretests/res/raw/v21_multiple_entry.vcf b/core/tests/coretests/res/raw/v21_multiple_entry.vcf
deleted file mode 100644
index ebbb19a..0000000
--- a/core/tests/coretests/res/raw/v21_multiple_entry.vcf
+++ /dev/null
@@ -1,33 +0,0 @@
-BEGIN:VCARD
-VERSION:2.1
-N;CHARSET=SHIFT_JIS:À¡Ch3;;;;
-SOUND;X-IRMC-N;CHARSET=SHIFT_JIS:±ÝÄÞ³Û²ÄÞ3;;;;
-TEL;X-NEC-SECRET:9
-TEL;X-NEC-HOTEL:10
-TEL;X-NEC-SCHOOL:11
-TEL;HOME;FAX:12
-END:VCARD
-
-
-BEGIN:VCARD
-VERSION:2.1
-N;CHARSET=SHIFT_JIS:À¡Ch4;;;;
-SOUND;X-IRMC-N;CHARSET=SHIFT_JIS:±ÝÄÞ³Û²ÄÞ4;;;;
-TEL;MODEM:13
-TEL;PAGER:14
-TEL;X-NEC-FAMILY:15
-TEL;X-NEC-GIRL:16
-END:VCARD
-
-
-BEGIN:VCARD
-VERSION:2.1
-N;CHARSET=SHIFT_JIS:À¡Ch5;;;;
-SOUND;X-IRMC-N;CHARSET=SHIFT_JIS:±ÝÄÞ³Û²ÄÞ5;;;;
-TEL;X-NEC-BOY:17
-TEL;X-NEC-FRIEND:18
-TEL;X-NEC-PHS:19
-TEL;X-NEC-RESTAURANT:20
-END:VCARD
-
-
diff --git a/core/tests/coretests/res/raw/v21_org_before_title.vcf b/core/tests/coretests/res/raw/v21_org_before_title.vcf
deleted file mode 100644
index 8ff1190..0000000
--- a/core/tests/coretests/res/raw/v21_org_before_title.vcf
+++ /dev/null
@@ -1,6 +0,0 @@
-BEGIN:VCARD
-VERSION:2.1
-FN:Normal Guy
-ORG:Company;Organization;Devision;Room;Sheet No.
-TITLE:Excellent Janitor
-END:VCARD
diff --git a/core/tests/coretests/res/raw/v21_pref_handling.vcf b/core/tests/coretests/res/raw/v21_pref_handling.vcf
deleted file mode 100644
index 5105310..0000000
--- a/core/tests/coretests/res/raw/v21_pref_handling.vcf
+++ /dev/null
@@ -1,15 +0,0 @@
-BEGIN:VCARD
-VERSION:2.1
-FN:Smith
-TEL;HOME:1
-TEL;WORK;PREF:2
-TEL;ISDN:3
-EMAIL;PREF;HOME:test@example.com
-EMAIL;CELL;PREF:test2@examination.com
-ORG:Company
-TITLE:Engineer
-ORG:Mystery
-TITLE:Blogger
-ORG:Poetry
-TITLE:Poet
-END:VCARD
diff --git a/core/tests/coretests/res/raw/v21_simple_1.vcf b/core/tests/coretests/res/raw/v21_simple_1.vcf
deleted file mode 100644
index 6aabb4c..0000000
--- a/core/tests/coretests/res/raw/v21_simple_1.vcf
+++ /dev/null
@@ -1,3 +0,0 @@
-BEGIN:VCARD
-N:Ando;Roid;
-END:VCARD
diff --git a/core/tests/coretests/res/raw/v21_simple_2.vcf b/core/tests/coretests/res/raw/v21_simple_2.vcf
deleted file mode 100644
index f0d5ab5..0000000
--- a/core/tests/coretests/res/raw/v21_simple_2.vcf
+++ /dev/null
@@ -1,3 +0,0 @@
-BEGIN:VCARD
-FN:Ando Roid
-END:VCARD
diff --git a/core/tests/coretests/res/raw/v21_simple_3.vcf b/core/tests/coretests/res/raw/v21_simple_3.vcf
deleted file mode 100644
index beddabb..0000000
--- a/core/tests/coretests/res/raw/v21_simple_3.vcf
+++ /dev/null
@@ -1,4 +0,0 @@
-BEGIN:VCARD
-N:Ando;Roid;
-FN:Ando Roid
-END:VCARD
diff --git a/core/tests/coretests/res/raw/v21_title_before_org.vcf b/core/tests/coretests/res/raw/v21_title_before_org.vcf
deleted file mode 100644
index 9fdc738..0000000
--- a/core/tests/coretests/res/raw/v21_title_before_org.vcf
+++ /dev/null
@@ -1,6 +0,0 @@
-BEGIN:VCARD
-VERSION:2.1
-FN:Nice Guy
-TITLE:Cool Title
-ORG:Marverous;Perfect;Great;Good;Bad;Poor
-END:VCARD
diff --git a/core/tests/coretests/res/raw/v21_winmo_65.vcf b/core/tests/coretests/res/raw/v21_winmo_65.vcf
deleted file mode 100644
index f380d0d..0000000
--- a/core/tests/coretests/res/raw/v21_winmo_65.vcf
+++ /dev/null
@@ -1,10 +0,0 @@
-BEGIN:VCARD
-VERSION:2.1
-N:Example;;;;
-FN:Example
-ANNIVERSARY;VALUE=DATE:20091010
-AGENT:Invalid line which must be handled correctly.
-X-CLASS:PUBLIC
-X-REDUCTION:
-X-NO:
-END:VCARD
diff --git a/core/tests/coretests/res/raw/v30_comma_separated.vcf b/core/tests/coretests/res/raw/v30_comma_separated.vcf
deleted file mode 100644
index 98a7f20..0000000
--- a/core/tests/coretests/res/raw/v30_comma_separated.vcf
+++ /dev/null
@@ -1,5 +0,0 @@
-BEGIN:VCARD
-VERSION:3.0
-N:F;G;M;;
-TEL;TYPE=PAGER,WORK,MSG:6101231234@pagersample.com
-END:VCARD
diff --git a/core/tests/coretests/res/raw/v30_simple.vcf b/core/tests/coretests/res/raw/v30_simple.vcf
deleted file mode 100644
index 418661f..0000000
--- a/core/tests/coretests/res/raw/v30_simple.vcf
+++ /dev/null
@@ -1,13 +0,0 @@
-BEGIN:VCARD
-VERSION:3.0
-FN:And Roid
-N:And;Roid;;;
-ORG:Open;Handset; Alliance
-SORT-STRING:android
-TEL;TYPE=PREF;TYPE=VOICE:0300000000
-CLASS:PUBLIC
-X-GNO:0
-X-GN:group0
-X-REDUCTION:0
-REV:20081031T065854Z
-END:VCARD
diff --git a/core/tests/coretests/src/android/accessibilityservice/AccessibilityTestService.java b/core/tests/coretests/src/android/accessibilityservice/AccessibilityTestService.java
deleted file mode 100644
index 2a51eea..0000000
--- a/core/tests/coretests/src/android/accessibilityservice/AccessibilityTestService.java
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.accessibilityservice;
-
-import android.accessibilityservice.AccessibilityService;
-import android.accessibilityservice.AccessibilityServiceInfo;
-import android.app.Notification;
-import android.util.Log;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
-
-import java.util.Timer;
-import java.util.TimerTask;
-
-/**
- * This class text the accessibility framework end to end.
- * <p>
- * Note: Since accessibility is provided by {@link AccessibilityService}s we create one,
- * and it generates an event and an interruption dispatching them through the
- * {@link AccessibilityManager}. We verify the received result. To trigger the test
- * go to Settings->Accessibility and select the enable accessibility check and then
- * select the check for this service (same name as the class).
- */
-public class AccessibilityTestService extends AccessibilityService {
-
- private static final String LOG_TAG = "AccessibilityTestService";
-
- private static final String CLASS_NAME = "foo.bar.baz.Test";
- private static final String PACKAGE_NAME = "foo.bar.baz";
- private static final String TEXT = "Some stuff";
- private static final String BEFORE_TEXT = "Some other stuff";
-
- private static final String CONTENT_DESCRIPTION = "Content description";
-
- private static final int ITEM_COUNT = 10;
- private static final int CURRENT_ITEM_INDEX = 1;
- private static final int INTERRUPT_INVOCATION_TYPE = 0x00000200;
-
- private static final int FROM_INDEX = 1;
- private static final int ADDED_COUNT = 2;
- private static final int REMOVED_COUNT = 1;
-
- private static final int NOTIFICATION_TIMEOUT_MILLIS = 80;
-
- private int mReceivedResult;
-
- private Timer mTimer = new Timer();
-
- @Override
- public void onServiceConnected() {
- AccessibilityServiceInfo info = new AccessibilityServiceInfo();
- info.eventTypes = AccessibilityEvent.TYPES_ALL_MASK;
- info.feedbackType = AccessibilityServiceInfo.FEEDBACK_AUDIBLE;
- info.notificationTimeout = NOTIFICATION_TIMEOUT_MILLIS;
- info.flags &= AccessibilityServiceInfo.DEFAULT;
- setServiceInfo(info);
-
- // we need to wait until the system picks our configuration
- // otherwise it will not notify us
- mTimer.schedule(new TimerTask() {
- @Override
- public void run() {
- try {
- testAccessibilityEventDispatching();
- testInterrupt();
- } catch (Exception e) {
- Log.e(LOG_TAG, "Error in testing Accessibility feature", e);
- }
- }
- }, 1000);
- }
-
- /**
- * Check here if the event we received is actually the one we sent.
- */
- @Override
- public void onAccessibilityEvent(AccessibilityEvent event) {
- assert(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED == event.getEventType());
- assert(event != null);
- assert(event.getEventTime() > 0);
- assert(CLASS_NAME.equals(event.getClassName()));
- assert(PACKAGE_NAME.equals(event.getPackageName()));
- assert(1 == event.getText().size());
- assert(TEXT.equals(event.getText().get(0)));
- assert(BEFORE_TEXT.equals(event.getBeforeText()));
- assert(event.isChecked());
- assert(CONTENT_DESCRIPTION.equals(event.getContentDescription()));
- assert(ITEM_COUNT == event.getItemCount());
- assert(CURRENT_ITEM_INDEX == event.getCurrentItemIndex());
- assert(event.isEnabled());
- assert(event.isPassword());
- assert(FROM_INDEX == event.getFromIndex());
- assert(ADDED_COUNT == event.getAddedCount());
- assert(REMOVED_COUNT == event.getRemovedCount());
- assert(event.getParcelableData() != null);
- assert(1 == ((Notification) event.getParcelableData()).icon);
-
- // set the type of the receved request
- mReceivedResult = AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED;
- }
-
- /**
- * Set a flag that we received the interrupt request.
- */
- @Override
- public void onInterrupt() {
-
- // set the type of the receved request
- mReceivedResult = INTERRUPT_INVOCATION_TYPE;
- }
-
- /**
- * If an {@link AccessibilityEvent} is sent and received correctly.
- */
- public void testAccessibilityEventDispatching() throws Exception {
- AccessibilityEvent event =
- AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
-
- assert(event != null);
- event.setClassName(CLASS_NAME);
- event.setPackageName(PACKAGE_NAME);
- event.getText().add(TEXT);
- event.setBeforeText(BEFORE_TEXT);
- event.setChecked(true);
- event.setContentDescription(CONTENT_DESCRIPTION);
- event.setItemCount(ITEM_COUNT);
- event.setCurrentItemIndex(CURRENT_ITEM_INDEX);
- event.setEnabled(true);
- event.setPassword(true);
- event.setFromIndex(FROM_INDEX);
- event.setAddedCount(ADDED_COUNT);
- event.setRemovedCount(REMOVED_COUNT);
- event.setParcelableData(new Notification(1, "Foo", 1234));
-
- AccessibilityManager.getInstance(this).sendAccessibilityEvent(event);
-
- assert(mReceivedResult == event.getEventType());
-
- Log.i(LOG_TAG, "AccessibilityTestService#testAccessibilityEventDispatching: Success");
- }
-
- /**
- * If accessibility feedback interruption is triggered and received correctly.
- */
- public void testInterrupt() throws Exception {
- AccessibilityManager.getInstance(this).interrupt();
-
- assert(INTERRUPT_INVOCATION_TYPE == mReceivedResult);
-
- Log.i(LOG_TAG, "AccessibilityTestService#testInterrupt: Success");
- }
-}
-
diff --git a/core/tests/coretests/src/android/database/DatabaseCursorTest.java b/core/tests/coretests/src/android/database/DatabaseCursorTest.java
index fb5a36f..0265c87 100644
--- a/core/tests/coretests/src/android/database/DatabaseCursorTest.java
+++ b/core/tests/coretests/src/android/database/DatabaseCursorTest.java
@@ -92,43 +92,6 @@
}
@MediumTest
- public void testCursorUpdate() {
- mDatabase.execSQL(
- "CREATE TABLE test (_id INTEGER PRIMARY KEY, d INTEGER, s INTEGER);");
- for(int i = 0; i < 20; i++) {
- mDatabase.execSQL("INSERT INTO test (d, s) VALUES (" + i +
- "," + i%2 + ");");
- }
-
- Cursor c = mDatabase.query("test", null, "s = 0", null, null, null, null);
- int dCol = c.getColumnIndexOrThrow("d");
- int sCol = c.getColumnIndexOrThrow("s");
-
- int count = 0;
- while (c.moveToNext()) {
- assertTrue(c.updateInt(dCol, 3));
- count++;
- }
- assertEquals(10, count);
-
- assertTrue(c.commitUpdates());
-
- assertTrue(c.requery());
-
- count = 0;
- while (c.moveToNext()) {
- assertEquals(3, c.getInt(dCol));
- count++;
- }
-
- assertEquals(10, count);
- assertTrue(c.moveToFirst());
- assertTrue(c.deleteRow());
- assertEquals(9, c.getCount());
- c.close();
- }
-
- @MediumTest
public void testBlob() throws Exception {
// create table
mDatabase.execSQL(
@@ -164,24 +127,7 @@
assertTrue(Arrays.equals(blob, cBlob));
assertEquals(s, c.getString(sCol));
assertEquals((double)d, c.getDouble(dCol));
- assertEquals((long)l, c.getLong(lCol));
-
- // new byte[]
- byte[] newblob = new byte[1000];
- value = 98;
- Arrays.fill(blob, value);
-
- c.updateBlob(bCol, newblob);
- cBlob = c.getBlob(bCol);
- assertTrue(Arrays.equals(newblob, cBlob));
-
- // commit
- assertTrue(c.commitUpdates());
- assertTrue(c.requery());
- c.moveToNext();
- cBlob = c.getBlob(bCol);
- assertTrue(Arrays.equals(newblob, cBlob));
- c.close();
+ assertEquals((long)l, c.getLong(lCol));
}
@MediumTest
diff --git a/core/tests/coretests/src/android/database/DatabaseGeneralTest.java b/core/tests/coretests/src/android/database/DatabaseGeneralTest.java
index 656029d..c86bdfa 100644
--- a/core/tests/coretests/src/android/database/DatabaseGeneralTest.java
+++ b/core/tests/coretests/src/android/database/DatabaseGeneralTest.java
@@ -26,13 +26,16 @@
import android.os.Parcel;
import android.test.AndroidTestCase;
import android.test.PerformanceTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
import android.test.suitebuilder.annotation.MediumTest;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
+import android.util.Pair;
import junit.framework.Assert;
import java.io.File;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Locale;
@@ -467,45 +470,6 @@
}
@MediumTest
- public void testNotificationTest1() throws Exception {
- /*
- Cursor c = mContentResolver.query(Notes.CONTENT_URI,
- new String[] {Notes._ID, Notes.NOTE},
- null, null);
- c.registerContentObserver(new MyContentObserver(true));
- int count = c.count();
-
- MyContentObserver observer = new MyContentObserver(false);
- mContentResolver.registerContentObserver(Notes.CONTENT_URI, true, observer);
-
- Uri uri;
-
- HashMap<String, String> values = new HashMap<String, String>();
- values.put(Notes.NOTE, "test note1");
- uri = mContentResolver.insert(Notes.CONTENT_URI, values);
- assertEquals(1, mCursorNotificationCount);
- assertEquals(1, mNotificationCount);
-
- c.requery();
- assertEquals(count + 1, c.count());
- c.first();
- assertEquals("test note1", c.getString(c.getColumnIndex(Notes.NOTE)));
- c.updateString(c.getColumnIndex(Notes.NOTE), "test note2");
- c.commitUpdates();
-
- assertEquals(2, mCursorNotificationCount);
- assertEquals(2, mNotificationCount);
-
- mContentResolver.delete(uri, null);
-
- assertEquals(3, mCursorNotificationCount);
- assertEquals(3, mNotificationCount);
-
- mContentResolver.unregisterContentObserver(observer);
- */
- }
-
- @MediumTest
public void testSelectionArgs() throws Exception {
mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data TEXT);");
ContentValues values = new ContentValues(1);
@@ -1023,6 +987,34 @@
}
}
+ @MediumTest
+ public void testUnionsWithBindArgs() {
+ /* make sure unions with bindargs work http://b/issue?id=1061291 */
+ mDatabase.execSQL("CREATE TABLE A (i int);");
+ mDatabase.execSQL("create table B (k int);");
+ mDatabase.execSQL("create table C (n int);");
+ mDatabase.execSQL("insert into A values(1);");
+ mDatabase.execSQL("insert into A values(2);");
+ mDatabase.execSQL("insert into A values(3);");
+ mDatabase.execSQL("insert into B values(201);");
+ mDatabase.execSQL("insert into B values(202);");
+ mDatabase.execSQL("insert into B values(203);");
+ mDatabase.execSQL("insert into C values(901);");
+ mDatabase.execSQL("insert into C values(902);");
+ String s = "select i from A where i > 2 " +
+ "UNION select k from B where k > 201 " +
+ "UNION select n from C where n !=900;";
+ Cursor c = mDatabase.rawQuery(s, null);
+ int n = c.getCount();
+ c.close();
+ String s1 = "select i from A where i > ? " +
+ "UNION select k from B where k > ? " +
+ "UNION select n from C where n != ?;";
+ Cursor c1 = mDatabase.rawQuery(s1, new String[]{"2", "201", "900"});
+ assertEquals(n, c1.getCount());
+ c1.close();
+ }
+
/**
* This test is available only when the platform has a locale with the language "ja".
* It finishes without failure when it is not available.
@@ -1108,5 +1100,304 @@
}
}
}
- }
+ }
+
+ @SmallTest
+ public void testLruCachingOfSqliteCompiledSqlObjs() {
+ mDatabase.execSQL("CREATE TABLE test (i int, j int);");
+ mDatabase.execSQL("insert into test values(1,1);");
+ // set cache size
+ int N = SQLiteDatabase.MAX_SQL_CACHE_SIZE;
+ mDatabase.setMaxSqlCacheSize(N);
+
+ // do N+1 queries - and when the 0th entry is removed from LRU cache due to the
+ // insertion of (N+1)th entry, make sure 0th entry is closed
+ ArrayList<SQLiteStatement> stmtObjs = new ArrayList<SQLiteStatement>();
+ for (int i = 0; i < N+1; i++) {
+ SQLiteStatement c = mDatabase.compileStatement("select * from test where i = " + i);
+ c.close();
+ stmtObjs.add(i, c);
+ }
+
+ assertEquals(0, stmtObjs.get(0).getUniqueId());
+ for (int i = 1; i < N+1; i++) {
+ assertTrue(stmtObjs.get(i).getUniqueId() > 0);
+ }
+ }
+
+ @SmallTest
+ public void testSetMaxCahesize() {
+ mDatabase.execSQL("CREATE TABLE test (i int, j int);");
+ mDatabase.execSQL("insert into test values(1,1);");
+ // set cache size
+ int N = SQLiteDatabase.MAX_SQL_CACHE_SIZE;
+ mDatabase.setMaxSqlCacheSize(N);
+
+ // try reduce cachesize
+ try {
+ mDatabase.setMaxSqlCacheSize(1);
+ } catch (IllegalStateException e) {
+ assertTrue(e.getMessage().contains("cannot set cacheSize to a value less than"));
+ }
+ }
+
+ @LargeTest
+ public void testDefaultDatabaseErrorHandler() {
+ DefaultDatabaseErrorHandler errorHandler = new DefaultDatabaseErrorHandler();
+
+ // close the database. and call corruption handler.
+ // it should delete the database file.
+ File dbfile = new File(mDatabase.getPath());
+ mDatabase.close();
+ assertFalse(mDatabase.isOpen());
+ assertTrue(dbfile.exists());
+ try {
+ errorHandler.onCorruption(mDatabase);
+ assertFalse(dbfile.exists());
+ } catch (Exception e) {
+ fail("unexpected");
+ }
+
+ // create an in-memory database. and corruption handler shouldn't try to delete it
+ SQLiteDatabase memoryDb = SQLiteDatabase.openOrCreateDatabase(":memory:", null);
+ assertNotNull(memoryDb);
+ memoryDb.close();
+ assertFalse(memoryDb.isOpen());
+ try {
+ errorHandler.onCorruption(memoryDb);
+ } catch (Exception e) {
+ fail("unexpected");
+ }
+
+ // create a database, keep it open, call corruption handler. database file should be deleted
+ SQLiteDatabase dbObj = SQLiteDatabase.openOrCreateDatabase(mDatabase.getPath(), null);
+ assertTrue(dbfile.exists());
+ assertNotNull(dbObj);
+ assertTrue(dbObj.isOpen());
+ try {
+ errorHandler.onCorruption(dbObj);
+ assertFalse(dbfile.exists());
+ } catch (Exception e) {
+ fail("unexpected");
+ }
+
+ // create a database, attach 2 more databases to it
+ // attached database # 1: ":memory:"
+ // attached database # 2: mDatabase.getPath() + "1";
+ // call corruption handler. database files including the one for attached database # 2
+ // should be deleted
+ String attachedDb1File = mDatabase.getPath() + "1";
+ dbObj = SQLiteDatabase.openOrCreateDatabase(mDatabase.getPath(), null);
+ dbObj.execSQL("ATTACH DATABASE ':memory:' as memoryDb");
+ dbObj.execSQL("ATTACH DATABASE '" + attachedDb1File + "' as attachedDb1");
+ assertTrue(dbfile.exists());
+ assertTrue(new File(attachedDb1File).exists());
+ assertNotNull(dbObj);
+ assertTrue(dbObj.isOpen());
+ ArrayList<Pair<String, String>> attachedDbs = dbObj.getAttachedDbs();
+ try {
+ errorHandler.onCorruption(dbObj);
+ assertFalse(dbfile.exists());
+ assertFalse(new File(attachedDb1File).exists());
+ } catch (Exception e) {
+ fail("unexpected");
+ }
+
+ // same as above, except this is a bit of stress testing. attach 5 database files
+ // and make sure they are all removed.
+ int N = 5;
+ ArrayList<String> attachedDbFiles = new ArrayList<String>(N);
+ for (int i = 0; i < N; i++) {
+ attachedDbFiles.add(mDatabase.getPath() + i);
+ }
+ dbObj = SQLiteDatabase.openOrCreateDatabase(mDatabase.getPath(), null);
+ dbObj.execSQL("ATTACH DATABASE ':memory:' as memoryDb");
+ for (int i = 0; i < N; i++) {
+ dbObj.execSQL("ATTACH DATABASE '" + attachedDbFiles.get(i) + "' as attachedDb" + i);
+ }
+ assertTrue(dbfile.exists());
+ for (int i = 0; i < N; i++) {
+ assertTrue(new File(attachedDbFiles.get(i)).exists());
+ }
+ assertNotNull(dbObj);
+ assertTrue(dbObj.isOpen());
+ attachedDbs = dbObj.getAttachedDbs();
+ try {
+ errorHandler.onCorruption(dbObj);
+ assertFalse(dbfile.exists());
+ for (int i = 0; i < N; i++) {
+ assertFalse(new File(attachedDbFiles.get(i)).exists());
+ }
+ } catch (Exception e) {
+ fail("unexpected");
+ }
+ }
+
+ /**
+ * test to make sure the statement finalizations are not done right away but
+ * piggybacked onto the next sql statement execution on the same database.
+ */
+ @SmallTest
+ public void testStatementClose() {
+ mDatabase.execSQL("CREATE TABLE test (i int);");
+ // fill up statement cache in mDatabase\
+ int N = 26;
+ mDatabase.setMaxSqlCacheSize(N);
+ SQLiteStatement stmt;
+ int stmt0Id = 0;
+ for (int i = 0; i < N; i ++) {
+ stmt = mDatabase.compileStatement("insert into test values(" + i + ");");
+ stmt.executeInsert();
+ // keep track of 0th entry
+ if (i == 0) {
+ stmt0Id = stmt.getUniqueId();
+ }
+ stmt.close();
+ }
+
+ // add one more to the cache - and the above 'stmt0Id' should fall out of cache
+ SQLiteStatement stmt1 = mDatabase.compileStatement("select * from test where i = 1;");
+ stmt1.close();
+
+ // the above close() should have queuedUp the statement for finalization
+ ArrayList<Integer> statementIds = mDatabase.getQueuedUpStmtList();
+ assertTrue(statementIds.contains(stmt0Id));
+
+ // execute something to see if this statement gets finalized
+ mDatabase.execSQL("delete from test where i = 10;");
+ statementIds = mDatabase.getQueuedUpStmtList();
+ assertEquals(0, statementIds.size());
+ }
+
+ /**
+ * same as above - except that the statement to be finalized is from Thread # 1.
+ * and it is eventually finalized in Thread # 2 when it executes a sql statement.
+ * @throws InterruptedException
+ */
+ @LargeTest
+ public void testStatementCloseDiffThread() throws InterruptedException {
+ mDatabase.execSQL("CREATE TABLE test (i int);");
+ // fill up statement cache in mDatabase in a thread
+ Thread t1 = new Thread() {
+ @Override public void run() {
+ int N = 26;
+ mDatabase.setMaxSqlCacheSize(N);
+ SQLiteStatement stmt;
+ for (int i = 0; i < N; i ++) {
+ stmt = mDatabase.compileStatement("insert into test values(" + i + ");");
+ stmt.executeInsert();
+ // keep track of 0th entry
+ if (i == 0) {
+ setStmt0Id(stmt.getUniqueId());
+ }
+ stmt.close();
+ }
+ }
+ };
+ t1.start();
+ // wait for the thread to finish
+ t1.join();
+
+ // add one more to the cache - and the above 'stmt0Id' should fall out of cache
+ // just for the heck of it, do it in a separate thread
+ Thread t2 = new Thread() {
+ @Override public void run() {
+ SQLiteStatement stmt1 = mDatabase.compileStatement(
+ "select * from test where i = 1;");
+ stmt1.close();
+ }
+ };
+ t2.start();
+ t2.join();
+
+ // close() in the above thread should have queuedUp the statement for finalization
+ ArrayList<Integer> statementIds = mDatabase.getQueuedUpStmtList();
+ assertTrue(getStmt0Id() > 0);
+ assertTrue(statementIds.contains(stmt0Id));
+ assertEquals(1, statementIds.size());
+
+ // execute something to see if this statement gets finalized
+ // again do it in a separate thread
+ Thread t3 = new Thread() {
+ @Override public void run() {
+ mDatabase.execSQL("delete from test where i = 10;");
+ }
+ };
+ t3.start();
+ t3.join();
+
+ // is the statement finalized?
+ statementIds = mDatabase.getQueuedUpStmtList();
+ assertEquals(0, statementIds.size());
+ }
+
+ private volatile int stmt0Id = 0;
+ private synchronized void setStmt0Id(int stmt0Id) {
+ this.stmt0Id = stmt0Id;
+ }
+ private synchronized int getStmt0Id() {
+ return this.stmt0Id;
+ }
+
+ /**
+ * same as above - except that the queue of statements to be finalized are finalized
+ * by database close() operation.
+ */
+ @LargeTest
+ public void testStatementCloseByDbClose() throws InterruptedException {
+ mDatabase.execSQL("CREATE TABLE test (i int);");
+ // fill up statement cache in mDatabase in a thread
+ Thread t1 = new Thread() {
+ @Override public void run() {
+ int N = 26;
+ mDatabase.setMaxSqlCacheSize(N);
+ SQLiteStatement stmt;
+ for (int i = 0; i < N; i ++) {
+ stmt = mDatabase.compileStatement("insert into test values(" + i + ");");
+ stmt.executeInsert();
+ // keep track of 0th entry
+ if (i == 0) {
+ setStmt0Id(stmt.getUniqueId());
+ }
+ stmt.close();
+ }
+ }
+ };
+ t1.start();
+ // wait for the thread to finish
+ t1.join();
+
+ // add one more to the cache - and the above 'stmt0Id' should fall out of cache
+ // just for the heck of it, do it in a separate thread
+ Thread t2 = new Thread() {
+ @Override public void run() {
+ SQLiteStatement stmt1 = mDatabase.compileStatement(
+ "select * from test where i = 1;");
+ stmt1.close();
+ }
+ };
+ t2.start();
+ t2.join();
+
+ // close() in the above thread should have queuedUp the statement for finalization
+ ArrayList<Integer> statementIds = mDatabase.getQueuedUpStmtList();
+ assertTrue(getStmt0Id() > 0);
+ assertTrue(statementIds.contains(stmt0Id));
+ assertEquals(1, statementIds.size());
+
+ // close the database. everything from mClosedStatementIds in mDatabase
+ // should be finalized and cleared from the list
+ // again do it in a separate thread
+ Thread t3 = new Thread() {
+ @Override public void run() {
+ mDatabase.close();
+ }
+ };
+ t3.start();
+ t3.join();
+
+ // check mClosedStatementIds in mDatabase. it should be empty
+ statementIds = mDatabase.getQueuedUpStmtList();
+ assertEquals(0, statementIds.size());
+ }
}
diff --git a/core/tests/coretests/src/android/pim/vcard/ContentValuesBuilder.java b/core/tests/coretests/src/android/pim/vcard/ContentValuesBuilder.java
deleted file mode 100644
index b3c0773..0000000
--- a/core/tests/coretests/src/android/pim/vcard/ContentValuesBuilder.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.pim.vcard;
-
-import android.content.ContentValues;
-
-/**
- * ContentValues-like class which enables users to chain put() methods and restricts
- * the other methods.
- */
-/* package */ class ContentValuesBuilder {
- private final ContentValues mContentValues;
-
- public ContentValuesBuilder(final ContentValues contentValues) {
- mContentValues = contentValues;
- }
-
- public ContentValuesBuilder put(String key, String value) {
- mContentValues.put(key, value);
- return this;
- }
-
- public ContentValuesBuilder put(String key, Byte value) {
- mContentValues.put(key, value);
- return this;
- }
-
- public ContentValuesBuilder put(String key, Short value) {
- mContentValues.put(key, value);
- return this;
- }
-
- public ContentValuesBuilder put(String key, Integer value) {
- mContentValues.put(key, value);
- return this;
- }
-
- public ContentValuesBuilder put(String key, Long value) {
- mContentValues.put(key, value);
- return this;
- }
-
- public ContentValuesBuilder put(String key, Float value) {
- mContentValues.put(key, value);
- return this;
- }
-
- public ContentValuesBuilder put(String key, Double value) {
- mContentValues.put(key, value);
- return this;
- }
-
- public ContentValuesBuilder put(String key, Boolean value) {
- mContentValues.put(key, value);
- return this;
- }
-
- public ContentValuesBuilder put(String key, byte[] value) {
- mContentValues.put(key, value);
- return this;
- }
-
- public ContentValuesBuilder putNull(String key) {
- mContentValues.putNull(key);
- return this;
- }
-}
diff --git a/core/tests/coretests/src/android/pim/vcard/ContentValuesVerifier.java b/core/tests/coretests/src/android/pim/vcard/ContentValuesVerifier.java
deleted file mode 100644
index b9e9875..0000000
--- a/core/tests/coretests/src/android/pim/vcard/ContentValuesVerifier.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.pim.vcard;
-
-import android.pim.vcard.VCardConfig;
-import android.pim.vcard.VCardEntry;
-import android.pim.vcard.VCardEntryConstructor;
-import android.pim.vcard.VCardEntryHandler;
-import android.pim.vcard.VCardParser;
-import android.pim.vcard.VCardParser_V21;
-import android.pim.vcard.VCardParser_V30;
-import android.pim.vcard.exception.VCardException;
-import android.test.AndroidTestCase;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.List;
-
-/* package */ class ContentValuesVerifier implements VCardEntryHandler {
- private AndroidTestCase mTestCase;
- private List<ContentValuesVerifierElem> mContentValuesVerifierElemList =
- new ArrayList<ContentValuesVerifierElem>();
- private int mIndex;
-
- public ContentValuesVerifierElem addElem(AndroidTestCase androidTestCase) {
- mTestCase = androidTestCase;
- ContentValuesVerifierElem importVerifier = new ContentValuesVerifierElem(androidTestCase);
- mContentValuesVerifierElemList.add(importVerifier);
- return importVerifier;
- }
-
- public void verify(int resId, int vCardType) throws IOException, VCardException {
- verify(mTestCase.getContext().getResources().openRawResource(resId), vCardType);
- }
-
- public void verify(int resId, int vCardType, final VCardParser vCardParser)
- throws IOException, VCardException {
- verify(mTestCase.getContext().getResources().openRawResource(resId),
- vCardType, vCardParser);
- }
-
- public void verify(InputStream is, int vCardType) throws IOException, VCardException {
- final VCardParser vCardParser;
- if (VCardConfig.isV30(vCardType)) {
- vCardParser = new VCardParser_V30(true); // use StrictParsing
- } else {
- vCardParser = new VCardParser_V21();
- }
- verify(is, vCardType, vCardParser);
- }
-
- public void verify(InputStream is, int vCardType, final VCardParser vCardParser)
- throws IOException, VCardException {
- VCardEntryConstructor builder =
- new VCardEntryConstructor(null, null, false, vCardType, null);
- builder.addEntryHandler(this);
- try {
- vCardParser.parse(is, builder);
- } finally {
- if (is != null) {
- try {
- is.close();
- } catch (IOException e) {
- }
- }
- }
- }
-
- public void onStart() {
- for (ContentValuesVerifierElem elem : mContentValuesVerifierElemList) {
- elem.onParsingStart();
- }
- }
-
- public void onEntryCreated(VCardEntry entry) {
- mTestCase.assertTrue(mIndex < mContentValuesVerifierElemList.size());
- mContentValuesVerifierElemList.get(mIndex).onEntryCreated(entry);
- mIndex++;
- }
-
- public void onEnd() {
- for (ContentValuesVerifierElem elem : mContentValuesVerifierElemList) {
- elem.onParsingEnd();
- elem.verifyResolver();
- }
- }
-}
diff --git a/core/tests/coretests/src/android/pim/vcard/ContentValuesVerifierElem.java b/core/tests/coretests/src/android/pim/vcard/ContentValuesVerifierElem.java
deleted file mode 100644
index 2edbb36..0000000
--- a/core/tests/coretests/src/android/pim/vcard/ContentValuesVerifierElem.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.pim.vcard;
-
-import android.content.ContentValues;
-import android.pim.vcard.VCardConfig;
-import android.pim.vcard.VCardEntry;
-import android.pim.vcard.VCardEntryCommitter;
-import android.pim.vcard.VCardEntryConstructor;
-import android.pim.vcard.VCardEntryHandler;
-import android.pim.vcard.VCardParser;
-import android.pim.vcard.VCardParser_V21;
-import android.pim.vcard.VCardParser_V30;
-import android.pim.vcard.exception.VCardException;
-import android.provider.ContactsContract.Data;
-import android.test.AndroidTestCase;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-/* package */ class ContentValuesVerifierElem {
- private final AndroidTestCase mTestCase;
- private final ImportTestResolver mResolver;
- private final VCardEntryHandler mHandler;
-
- public ContentValuesVerifierElem(AndroidTestCase androidTestCase) {
- mTestCase = androidTestCase;
- mResolver = new ImportTestResolver(androidTestCase);
- mHandler = new VCardEntryCommitter(mResolver);
- }
-
- public ContentValuesBuilder addExpected(String mimeType) {
- ContentValues contentValues = new ContentValues();
- contentValues.put(Data.MIMETYPE, mimeType);
- mResolver.addExpectedContentValues(contentValues);
- return new ContentValuesBuilder(contentValues);
- }
-
- public void verify(int resId, int vCardType)
- throws IOException, VCardException {
- verify(mTestCase.getContext().getResources().openRawResource(resId), vCardType);
- }
-
- public void verify(InputStream is, int vCardType) throws IOException, VCardException {
- final VCardParser vCardParser;
- if (VCardConfig.isV30(vCardType)) {
- vCardParser = new VCardParser_V30(true); // use StrictParsing
- } else {
- vCardParser = new VCardParser_V21();
- }
- VCardEntryConstructor builder =
- new VCardEntryConstructor(null, null, false, vCardType, null);
- builder.addEntryHandler(mHandler);
- try {
- vCardParser.parse(is, builder);
- } finally {
- if (is != null) {
- try {
- is.close();
- } catch (IOException e) {
- }
- }
- }
- verifyResolver();
- }
-
- public void verifyResolver() {
- mResolver.verify();
- }
-
- public void onParsingStart() {
- mHandler.onStart();
- }
-
- public void onEntryCreated(VCardEntry entry) {
- mHandler.onEntryCreated(entry);
- }
-
- public void onParsingEnd() {
- mHandler.onEnd();
- }
-}
diff --git a/core/tests/coretests/src/android/pim/vcard/ExportTestResolver.java b/core/tests/coretests/src/android/pim/vcard/ExportTestResolver.java
deleted file mode 100644
index 5968e83..0000000
--- a/core/tests/coretests/src/android/pim/vcard/ExportTestResolver.java
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package android.pim.vcard;
-
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Entity;
-import android.content.EntityIterator;
-import android.database.Cursor;
-import android.net.Uri;
-import android.provider.ContactsContract.Contacts;
-import android.provider.ContactsContract.Data;
-import android.provider.ContactsContract.RawContacts;
-import android.test.mock.MockContentResolver;
-import android.test.mock.MockCursor;
-
-import junit.framework.TestCase;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-/* package */ public class ExportTestResolver extends MockContentResolver {
- ExportTestProvider mProvider;
- public ExportTestResolver(TestCase testCase) {
- mProvider = new ExportTestProvider(testCase);
- addProvider(VCardComposer.VCARD_TEST_AUTHORITY, mProvider);
- addProvider(RawContacts.CONTENT_URI.getAuthority(), mProvider);
- }
-
- public ContactEntry addInputContactEntry() {
- return mProvider.buildInputEntry();
- }
-}
-
-/* package */ class MockEntityIterator implements EntityIterator {
- List<Entity> mEntityList;
- Iterator<Entity> mIterator;
-
- public MockEntityIterator(List<ContentValues> contentValuesList) {
- mEntityList = new ArrayList<Entity>();
- Entity entity = new Entity(new ContentValues());
- for (ContentValues contentValues : contentValuesList) {
- entity.addSubValue(Data.CONTENT_URI, contentValues);
- }
- mEntityList.add(entity);
- mIterator = mEntityList.iterator();
- }
-
- public boolean hasNext() {
- return mIterator.hasNext();
- }
-
- public Entity next() {
- return mIterator.next();
- }
-
- public void remove() {
- throw new UnsupportedOperationException("remove not supported");
- }
-
- public void reset() {
- mIterator = mEntityList.iterator();
- }
-
- public void close() {
- }
-}
-
-/**
- * Represents one contact, which should contain multiple ContentValues like
- * StructuredName, Email, etc.
- */
-/* package */ class ContactEntry {
- private final List<ContentValues> mContentValuesList = new ArrayList<ContentValues>();
-
- public ContentValuesBuilder addContentValues(String mimeType) {
- ContentValues contentValues = new ContentValues();
- contentValues.put(Data.MIMETYPE, mimeType);
- mContentValuesList.add(contentValues);
- return new ContentValuesBuilder(contentValues);
- }
-
- public List<ContentValues> getList() {
- return mContentValuesList;
- }
-}
-
-/* package */ class ExportTestProvider extends MockContentProvider {
- final private TestCase mTestCase;
- final private ArrayList<ContactEntry> mContactEntryList = new ArrayList<ContactEntry>();
-
- public ExportTestProvider(TestCase testCase) {
- mTestCase = testCase;
- }
-
- public ContactEntry buildInputEntry() {
- ContactEntry contactEntry = new ContactEntry();
- mContactEntryList.add(contactEntry);
- return contactEntry;
- }
-
- /**
- * <p>
- * An old method which had existed but was removed from ContentResolver.
- * </p>
- * <p>
- * We still keep using this method since we don't have a propeer way to know
- * which value in the ContentValue corresponds to the entry in Contacts database.
- * </p>
- * <p>
- * Detail:
- * There's an easy way to know which index "family name" corresponds to, via
- * {@link android.provider.ContactsContract}.
- * FAMILY_NAME equals DATA3, so the corresponding index
- * for "family name" should be 2 (note that index is 0-origin).
- * However, we cannot know what the index 2 corresponds to; it may be "family name",
- * "label" for now, but may be the other some column in the future. We don't have
- * convenient way to know the original data structure.
- * </p>
- */
- public EntityIterator queryEntities(Uri uri,
- String selection, String[] selectionArgs, String sortOrder) {
- mTestCase.assertTrue(uri != null);
- mTestCase.assertTrue(ContentResolver.SCHEME_CONTENT.equals(uri.getScheme()));
- final String authority = uri.getAuthority();
- mTestCase.assertTrue(RawContacts.CONTENT_URI.getAuthority().equals(authority));
- mTestCase.assertTrue((Data.CONTACT_ID + "=?").equals(selection));
- mTestCase.assertEquals(1, selectionArgs.length);
- final int id = Integer.parseInt(selectionArgs[0]);
- mTestCase.assertTrue(id >= 0 && id < mContactEntryList.size());
-
- return new MockEntityIterator(mContactEntryList.get(id).getList());
- }
-
- @Override
- public Cursor query(Uri uri,String[] projection,
- String selection, String[] selectionArgs, String sortOrder) {
- mTestCase.assertTrue(VCardComposer.CONTACTS_TEST_CONTENT_URI.equals(uri));
- // In this test, following arguments are not supported.
- mTestCase.assertNull(selection);
- mTestCase.assertNull(selectionArgs);
- mTestCase.assertNull(sortOrder);
-
- return new MockCursor() {
- int mCurrentPosition = -1;
-
- @Override
- public int getCount() {
- return mContactEntryList.size();
- }
-
- @Override
- public boolean moveToFirst() {
- mCurrentPosition = 0;
- return true;
- }
-
- @Override
- public boolean moveToNext() {
- if (mCurrentPosition < mContactEntryList.size()) {
- mCurrentPosition++;
- return true;
- } else {
- return false;
- }
- }
-
- @Override
- public boolean isBeforeFirst() {
- return mCurrentPosition < 0;
- }
-
- @Override
- public boolean isAfterLast() {
- return mCurrentPosition >= mContactEntryList.size();
- }
-
- @Override
- public int getColumnIndex(String columnName) {
- mTestCase.assertEquals(Contacts._ID, columnName);
- return 0;
- }
-
- @Override
- public int getInt(int columnIndex) {
- mTestCase.assertEquals(0, columnIndex);
- mTestCase.assertTrue(mCurrentPosition >= 0
- && mCurrentPosition < mContactEntryList.size());
- return mCurrentPosition;
- }
-
- @Override
- public String getString(int columnIndex) {
- return String.valueOf(getInt(columnIndex));
- }
-
- @Override
- public void close() {
- }
- };
- }
-}
diff --git a/core/tests/coretests/src/android/pim/vcard/ImportTestResolver.java b/core/tests/coretests/src/android/pim/vcard/ImportTestResolver.java
deleted file mode 100644
index c3f6f79..0000000
--- a/core/tests/coretests/src/android/pim/vcard/ImportTestResolver.java
+++ /dev/null
@@ -1,299 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.pim.vcard;
-
-import android.content.ContentProviderOperation;
-import android.content.ContentProviderResult;
-import android.content.ContentValues;
-import android.net.Uri;
-import android.provider.ContactsContract.Data;
-import android.provider.ContactsContract.RawContacts;
-import android.provider.ContactsContract.CommonDataKinds.Email;
-import android.provider.ContactsContract.CommonDataKinds.Event;
-import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
-import android.provider.ContactsContract.CommonDataKinds.Im;
-import android.provider.ContactsContract.CommonDataKinds.Nickname;
-import android.provider.ContactsContract.CommonDataKinds.Note;
-import android.provider.ContactsContract.CommonDataKinds.Organization;
-import android.provider.ContactsContract.CommonDataKinds.Phone;
-import android.provider.ContactsContract.CommonDataKinds.Photo;
-import android.provider.ContactsContract.CommonDataKinds.Relation;
-import android.provider.ContactsContract.CommonDataKinds.StructuredName;
-import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
-import android.provider.ContactsContract.CommonDataKinds.Website;
-import android.test.mock.MockContentResolver;
-import android.text.TextUtils;
-
-import junit.framework.TestCase;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.SortedMap;
-import java.util.TreeMap;
-import java.util.Map.Entry;
-
-/* package */ class ImportTestResolver extends MockContentResolver {
- final ImportTestProvider mProvider;
-
- public ImportTestResolver(TestCase testCase) {
- mProvider = new ImportTestProvider(testCase);
- }
-
- @Override
- public ContentProviderResult[] applyBatch(String authority,
- ArrayList<ContentProviderOperation> operations) {
- equalsString(authority, RawContacts.CONTENT_URI.toString());
- return mProvider.applyBatch(operations);
- }
-
- public void addExpectedContentValues(ContentValues expectedContentValues) {
- mProvider.addExpectedContentValues(expectedContentValues);
- }
-
- public void verify() {
- mProvider.verify();
- }
-
- private static boolean equalsString(String a, String b) {
- if (a == null || a.length() == 0) {
- return b == null || b.length() == 0;
- } else {
- return a.equals(b);
- }
- }
-}
-
-/* package */ class ImportTestProvider extends MockContentProvider {
- private static final Set<String> sKnownMimeTypeSet =
- new HashSet<String>(Arrays.asList(StructuredName.CONTENT_ITEM_TYPE,
- Nickname.CONTENT_ITEM_TYPE, Phone.CONTENT_ITEM_TYPE,
- Email.CONTENT_ITEM_TYPE, StructuredPostal.CONTENT_ITEM_TYPE,
- Im.CONTENT_ITEM_TYPE, Organization.CONTENT_ITEM_TYPE,
- Event.CONTENT_ITEM_TYPE, Photo.CONTENT_ITEM_TYPE,
- Note.CONTENT_ITEM_TYPE, Website.CONTENT_ITEM_TYPE,
- Relation.CONTENT_ITEM_TYPE, Event.CONTENT_ITEM_TYPE,
- GroupMembership.CONTENT_ITEM_TYPE));
-
- final Map<String, Collection<ContentValues>> mMimeTypeToExpectedContentValues;
-
- private final TestCase mTestCase;
-
- public ImportTestProvider(TestCase testCase) {
- mTestCase = testCase;
- mMimeTypeToExpectedContentValues =
- new HashMap<String, Collection<ContentValues>>();
- for (String acceptanbleMimeType : sKnownMimeTypeSet) {
- // Do not use HashSet since the current implementation changes the content of
- // ContentValues after the insertion, which make the result of hashCode()
- // changes...
- mMimeTypeToExpectedContentValues.put(
- acceptanbleMimeType, new ArrayList<ContentValues>());
- }
- }
-
- public void addExpectedContentValues(ContentValues expectedContentValues) {
- final String mimeType = expectedContentValues.getAsString(Data.MIMETYPE);
- if (!sKnownMimeTypeSet.contains(mimeType)) {
- mTestCase.fail(String.format(
- "Unknow MimeType %s in the test code. Test code should be broken.",
- mimeType));
- }
-
- final Collection<ContentValues> contentValuesCollection =
- mMimeTypeToExpectedContentValues.get(mimeType);
- contentValuesCollection.add(expectedContentValues);
- }
-
- @Override
- public ContentProviderResult[] applyBatch(
- ArrayList<ContentProviderOperation> operations) {
- if (operations == null) {
- mTestCase.fail("There is no operation.");
- }
-
- final int size = operations.size();
- ContentProviderResult[] fakeResultArray = new ContentProviderResult[size];
- for (int i = 0; i < size; i++) {
- Uri uri = Uri.withAppendedPath(RawContacts.CONTENT_URI, String.valueOf(i));
- fakeResultArray[i] = new ContentProviderResult(uri);
- }
-
- for (int i = 0; i < size; i++) {
- ContentProviderOperation operation = operations.get(i);
- ContentValues contentValues = operation.resolveValueBackReferences(
- fakeResultArray, i);
- }
- for (int i = 0; i < size; i++) {
- ContentProviderOperation operation = operations.get(i);
- ContentValues actualContentValues = operation.resolveValueBackReferences(
- fakeResultArray, i);
- final Uri uri = operation.getUri();
- if (uri.equals(RawContacts.CONTENT_URI)) {
- mTestCase.assertNull(actualContentValues.get(RawContacts.ACCOUNT_NAME));
- mTestCase.assertNull(actualContentValues.get(RawContacts.ACCOUNT_TYPE));
- } else if (uri.equals(Data.CONTENT_URI)) {
- final String mimeType = actualContentValues.getAsString(Data.MIMETYPE);
- if (!sKnownMimeTypeSet.contains(mimeType)) {
- mTestCase.fail(String.format(
- "Unknown MimeType %s. Probably added after developing this test",
- mimeType));
- }
- // Remove data meaningless in this unit tests.
- // Specifically, Data.DATA1 - DATA7 are set to null or empty String
- // regardless of the input, but it may change depending on how
- // resolver-related code handles it.
- // Here, we ignore these implementation-dependent specs and
- // just check whether vCard importer correctly inserts rellevent data.
- Set<String> keyToBeRemoved = new HashSet<String>();
- for (Entry<String, Object> entry : actualContentValues.valueSet()) {
- Object value = entry.getValue();
- if (value == null || TextUtils.isEmpty(value.toString())) {
- keyToBeRemoved.add(entry.getKey());
- }
- }
- for (String key: keyToBeRemoved) {
- actualContentValues.remove(key);
- }
- /* for testing
- Log.d("@@@",
- String.format("MimeType: %s, data: %s",
- mimeType, actualContentValues.toString())); */
- // Remove RAW_CONTACT_ID entry just for safety, since we do not care
- // how resolver-related code handles the entry in this unit test,
- if (actualContentValues.containsKey(Data.RAW_CONTACT_ID)) {
- actualContentValues.remove(Data.RAW_CONTACT_ID);
- }
- final Collection<ContentValues> contentValuesCollection =
- mMimeTypeToExpectedContentValues.get(mimeType);
- if (contentValuesCollection.isEmpty()) {
- mTestCase.fail("ContentValues for MimeType " + mimeType
- + " is not expected at all (" + actualContentValues + ")");
- }
- boolean checked = false;
- for (ContentValues expectedContentValues : contentValuesCollection) {
- /*for testing
- Log.d("@@@", "expected: "
- + convertToEasilyReadableString(expectedContentValues));
- Log.d("@@@", "actual : "
- + convertToEasilyReadableString(actualContentValues));*/
- if (equalsForContentValues(expectedContentValues,
- actualContentValues)) {
- mTestCase.assertTrue(contentValuesCollection.remove(expectedContentValues));
- checked = true;
- break;
- }
- }
- if (!checked) {
- final StringBuilder builder = new StringBuilder();
- builder.append("Unexpected: ");
- builder.append(convertToEasilyReadableString(actualContentValues));
- builder.append("\nExpected: ");
- for (ContentValues expectedContentValues : contentValuesCollection) {
- builder.append(convertToEasilyReadableString(expectedContentValues));
- }
- mTestCase.fail(builder.toString());
- }
- } else {
- mTestCase.fail("Unexpected Uri has come: " + uri);
- }
- } // for (int i = 0; i < size; i++) {
- return fakeResultArray;
- }
-
- public void verify() {
- StringBuilder builder = new StringBuilder();
- for (Collection<ContentValues> contentValuesCollection :
- mMimeTypeToExpectedContentValues.values()) {
- for (ContentValues expectedContentValues: contentValuesCollection) {
- builder.append(convertToEasilyReadableString(expectedContentValues));
- builder.append("\n");
- }
- }
- if (builder.length() > 0) {
- final String failMsg =
- "There is(are) remaining expected ContentValues instance(s): \n"
- + builder.toString();
- mTestCase.fail(failMsg);
- }
- }
-
- /**
- * Utility method to print ContentValues whose content is printed with sorted keys.
- */
- private String convertToEasilyReadableString(ContentValues contentValues) {
- if (contentValues == null) {
- return "null";
- }
- String mimeTypeValue = "";
- SortedMap<String, String> sortedMap = new TreeMap<String, String>();
- for (Entry<String, Object> entry : contentValues.valueSet()) {
- final String key = entry.getKey();
- final Object value = entry.getValue();
- final String valueString = (value != null ? value.toString() : null);
- if (Data.MIMETYPE.equals(key)) {
- mimeTypeValue = valueString;
- } else {
- mTestCase.assertNotNull(key);
- sortedMap.put(key, valueString);
- }
- }
- StringBuilder builder = new StringBuilder();
- builder.append(Data.MIMETYPE);
- builder.append('=');
- builder.append(mimeTypeValue);
- for (Entry<String, String> entry : sortedMap.entrySet()) {
- final String key = entry.getKey();
- final String value = entry.getValue();
- builder.append(' ');
- builder.append(key);
- builder.append("=\"");
- builder.append(value);
- builder.append('"');
- }
- return builder.toString();
- }
-
- private static boolean equalsForContentValues(
- ContentValues expected, ContentValues actual) {
- if (expected == actual) {
- return true;
- } else if (expected == null || actual == null || expected.size() != actual.size()) {
- return false;
- }
-
- for (Entry<String, Object> entry : expected.valueSet()) {
- final String key = entry.getKey();
- final Object value = entry.getValue();
- if (!actual.containsKey(key)) {
- return false;
- }
- if (value instanceof byte[]) {
- Object actualValue = actual.get(key);
- if (!Arrays.equals((byte[])value, (byte[])actualValue)) {
- return false;
- }
- } else if (!value.equals(actual.get(key))) {
- return false;
- }
- }
- return true;
- }
-}
diff --git a/core/tests/coretests/src/android/pim/vcard/LineVerifier.java b/core/tests/coretests/src/android/pim/vcard/LineVerifier.java
deleted file mode 100644
index cef15fd..0000000
--- a/core/tests/coretests/src/android/pim/vcard/LineVerifier.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.pim.vcard;
-
-import android.content.Context;
-import android.pim.vcard.VCardComposer;
-
-import junit.framework.TestCase;
-
-import java.util.ArrayList;
-
-class LineVerifier implements VCardComposer.OneEntryHandler {
- private final TestCase mTestCase;
- private final ArrayList<LineVerifierElem> mLineVerifierElemList;
- private int mVCardType;
- private int index;
-
- public LineVerifier(TestCase testCase, int vcardType) {
- mTestCase = testCase;
- mLineVerifierElemList = new ArrayList<LineVerifierElem>();
- mVCardType = vcardType;
- }
-
- public LineVerifierElem addLineVerifierElem() {
- LineVerifierElem lineVerifier = new LineVerifierElem(mTestCase, mVCardType);
- mLineVerifierElemList.add(lineVerifier);
- return lineVerifier;
- }
-
- public void verify(String vcard) {
- if (index >= mLineVerifierElemList.size()) {
- mTestCase.fail("Insufficient number of LineVerifier (" + index + ")");
- }
-
- LineVerifierElem lineVerifier = mLineVerifierElemList.get(index);
- lineVerifier.verify(vcard);
-
- index++;
- }
-
- public boolean onEntryCreated(String vcard) {
- verify(vcard);
- return true;
- }
-
- public boolean onInit(Context context) {
- return true;
- }
-
- public void onTerminate() {
- }
-}
diff --git a/core/tests/coretests/src/android/pim/vcard/LineVerifierElem.java b/core/tests/coretests/src/android/pim/vcard/LineVerifierElem.java
deleted file mode 100644
index b23b29b..0000000
--- a/core/tests/coretests/src/android/pim/vcard/LineVerifierElem.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package android.pim.vcard;
-
-import android.pim.vcard.VCardConfig;
-import android.text.TextUtils;
-
-import junit.framework.TestCase;
-
-import java.util.ArrayList;
-import java.util.List;
-
-class LineVerifierElem {
- private final TestCase mTestCase;
- private final List<String> mExpectedLineList = new ArrayList<String>();
- private final boolean mIsV30;
-
- public LineVerifierElem(TestCase testCase, int vcardType) {
- mTestCase = testCase;
- mIsV30 = VCardConfig.isV30(vcardType);
- }
-
- public LineVerifierElem addExpected(final String line) {
- if (!TextUtils.isEmpty(line)) {
- mExpectedLineList.add(line);
- }
- return this;
- }
-
- public void verify(final String vcard) {
- final String[] lineArray = vcard.split("\\r?\\n");
- final int length = lineArray.length;
- boolean beginExists = false;
- boolean endExists = false;
- boolean versionExists = false;
-
- for (int i = 0; i < length; i++) {
- final String line = lineArray[i];
- if (TextUtils.isEmpty(line)) {
- continue;
- }
-
- if ("BEGIN:VCARD".equalsIgnoreCase(line)) {
- if (beginExists) {
- mTestCase.fail("Multiple \"BEGIN:VCARD\" line found");
- } else {
- beginExists = true;
- continue;
- }
- } else if ("END:VCARD".equalsIgnoreCase(line)) {
- if (endExists) {
- mTestCase.fail("Multiple \"END:VCARD\" line found");
- } else {
- endExists = true;
- continue;
- }
- } else if ((mIsV30 ? "VERSION:3.0" : "VERSION:2.1").equalsIgnoreCase(line)) {
- if (versionExists) {
- mTestCase.fail("Multiple VERSION line + found");
- } else {
- versionExists = true;
- continue;
- }
- }
-
- if (!beginExists) {
- mTestCase.fail("Property other than BEGIN came before BEGIN property: "
- + line);
- } else if (endExists) {
- mTestCase.fail("Property other than END came after END property: "
- + line);
- }
-
- final int index = mExpectedLineList.indexOf(line);
- if (index >= 0) {
- mExpectedLineList.remove(index);
- } else {
- mTestCase.fail("Unexpected line: " + line);
- }
- }
-
- if (!mExpectedLineList.isEmpty()) {
- StringBuffer buffer = new StringBuffer();
- for (String expectedLine : mExpectedLineList) {
- buffer.append(expectedLine);
- buffer.append("\n");
- }
-
- mTestCase.fail("Expected line(s) not found:" + buffer.toString());
- }
- }
-}
diff --git a/core/tests/coretests/src/android/pim/vcard/PropertyNode.java b/core/tests/coretests/src/android/pim/vcard/PropertyNode.java
deleted file mode 100644
index 2c1f6d2..0000000
--- a/core/tests/coretests/src/android/pim/vcard/PropertyNode.java
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.pim.vcard;
-
-import android.content.ContentValues;
-import android.pim.vcard.VCardEntry;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * Previously used in main vCard handling code but now exists only for testing.
- *
- * Especially useful for testing parser code (VCardParser), since all properties can be
- * checked via this class unlike {@link VCardEntry}, which only emits the result of
- * interpretation of the content of each vCard. We cannot know whether vCard parser or
- * ContactStruct is wrong withouth this class.
- */
-public class PropertyNode {
- public String propName;
- public String propValue;
- public List<String> propValue_vector;
-
- /** Store value as byte[],after decode.
- * Used when propValue is encoded by something like BASE64, QUOTED-PRINTABLE, etc.
- */
- public byte[] propValue_bytes;
-
- /** param store: key=paramType, value=paramValue
- * Note that currently PropertyNode class does not support multiple param-values
- * defined in vCard 3.0 (See also RFC 2426). multiple-values are stored as
- * one String value like "A,B", not ["A", "B"]...
- * TODO: fix this.
- */
- public ContentValues paramMap;
-
- /** Only for TYPE=??? param store. */
- public Set<String> paramMap_TYPE;
-
- /** Store group values. Used only in VCard. */
- public Set<String> propGroupSet;
-
- public PropertyNode() {
- propName = "";
- propValue = "";
- propValue_vector = new ArrayList<String>();
- paramMap = new ContentValues();
- paramMap_TYPE = new HashSet<String>();
- propGroupSet = new HashSet<String>();
- }
-
- public PropertyNode(
- String propName, String propValue, List<String> propValue_vector,
- byte[] propValue_bytes, ContentValues paramMap, Set<String> paramMap_TYPE,
- Set<String> propGroupSet) {
- if (propName != null) {
- this.propName = propName;
- } else {
- this.propName = "";
- }
- if (propValue != null) {
- this.propValue = propValue;
- } else {
- this.propValue = "";
- }
- if (propValue_vector != null) {
- this.propValue_vector = propValue_vector;
- } else {
- this.propValue_vector = new ArrayList<String>();
- }
- this.propValue_bytes = propValue_bytes;
- if (paramMap != null) {
- this.paramMap = paramMap;
- } else {
- this.paramMap = new ContentValues();
- }
- if (paramMap_TYPE != null) {
- this.paramMap_TYPE = paramMap_TYPE;
- } else {
- this.paramMap_TYPE = new HashSet<String>();
- }
- if (propGroupSet != null) {
- this.propGroupSet = propGroupSet;
- } else {
- this.propGroupSet = new HashSet<String>();
- }
- }
-
- @Override
- public int hashCode() {
- // vCard may contain more than one same line in one entry, while HashSet or any other
- // library which utilize hashCode() does not honor that, so intentionally throw an
- // Exception.
- throw new UnsupportedOperationException(
- "PropertyNode does not provide hashCode() implementation intentionally.");
- }
-
- @Override
- public boolean equals(Object obj) {
- if (!(obj instanceof PropertyNode)) {
- return false;
- }
-
- PropertyNode node = (PropertyNode)obj;
-
- if (propName == null || !propName.equals(node.propName)) {
- return false;
- } else if (!paramMap_TYPE.equals(node.paramMap_TYPE)) {
- return false;
- } else if (!paramMap_TYPE.equals(node.paramMap_TYPE)) {
- return false;
- } else if (!propGroupSet.equals(node.propGroupSet)) {
- return false;
- }
-
- if (propValue_bytes != null && Arrays.equals(propValue_bytes, node.propValue_bytes)) {
- return true;
- } else {
- if (!propValue.equals(node.propValue)) {
- return false;
- }
-
- // The value in propValue_vector is not decoded even if it should be
- // decoded by BASE64 or QUOTED-PRINTABLE. When the size of propValue_vector
- // is 1, the encoded value is stored in propValue, so we do not have to
- // check it.
- return (propValue_vector.equals(node.propValue_vector) ||
- propValue_vector.size() == 1 ||
- node.propValue_vector.size() == 1);
- }
- }
-
- @Override
- public String toString() {
- StringBuilder builder = new StringBuilder();
- builder.append("propName: ");
- builder.append(propName);
- builder.append(", paramMap: ");
- builder.append(paramMap.toString());
- builder.append(", paramMap_TYPE: [");
- boolean first = true;
- for (String elem : paramMap_TYPE) {
- if (first) {
- first = false;
- } else {
- builder.append(", ");
- }
- builder.append('"');
- builder.append(elem);
- builder.append('"');
- }
- builder.append("]");
- if (!propGroupSet.isEmpty()) {
- builder.append(", propGroupSet: [");
- first = true;
- for (String elem : propGroupSet) {
- if (first) {
- first = false;
- } else {
- builder.append(", ");
- }
- builder.append('"');
- builder.append(elem);
- builder.append('"');
- }
- builder.append("]");
- }
- if (propValue_vector != null && propValue_vector.size() > 1) {
- builder.append(", propValue_vector size: ");
- builder.append(propValue_vector.size());
- }
- if (propValue_bytes != null) {
- builder.append(", propValue_bytes size: ");
- builder.append(propValue_bytes.length);
- }
- builder.append(", propValue: \"");
- builder.append(propValue);
- builder.append("\"");
- return builder.toString();
- }
-}
diff --git a/core/tests/coretests/src/android/pim/vcard/PropertyNodesVerifier.java b/core/tests/coretests/src/android/pim/vcard/PropertyNodesVerifier.java
deleted file mode 100644
index cfdd074..0000000
--- a/core/tests/coretests/src/android/pim/vcard/PropertyNodesVerifier.java
+++ /dev/null
@@ -1,386 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.pim.vcard;
-
-import android.content.ContentValues;
-import android.pim.vcard.VCardConfig;
-import android.pim.vcard.VCardParser;
-import android.pim.vcard.VCardParser_V21;
-import android.pim.vcard.VCardParser_V30;
-import android.pim.vcard.exception.VCardException;
-import android.test.AndroidTestCase;
-
-import junit.framework.TestCase;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-
-/* package */ class PropertyNodesVerifier extends VNodeBuilder {
- private final List<PropertyNodesVerifierElem> mPropertyNodesVerifierElemList;
- private final AndroidTestCase mAndroidTestCase;
- private int mIndex;
-
- public PropertyNodesVerifier(AndroidTestCase testCase) {
- mPropertyNodesVerifierElemList = new ArrayList<PropertyNodesVerifierElem>();
- mAndroidTestCase = testCase;
- }
-
- public PropertyNodesVerifierElem addPropertyNodesVerifierElem() {
- PropertyNodesVerifierElem elem = new PropertyNodesVerifierElem(mAndroidTestCase);
- mPropertyNodesVerifierElemList.add(elem);
- return elem;
- }
-
- public void verify(int resId, int vCardType)
- throws IOException, VCardException {
- verify(mAndroidTestCase.getContext().getResources().openRawResource(resId), vCardType);
- }
-
- public void verify(int resId, int vCardType, final VCardParser vCardParser)
- throws IOException, VCardException {
- verify(mAndroidTestCase.getContext().getResources().openRawResource(resId),
- vCardType, vCardParser);
- }
-
- public void verify(InputStream is, int vCardType) throws IOException, VCardException {
- final VCardParser vCardParser;
- if (VCardConfig.isV30(vCardType)) {
- vCardParser = new VCardParser_V30(true); // Use StrictParsing.
- } else {
- vCardParser = new VCardParser_V21();
- }
- verify(is, vCardType, vCardParser);
- }
-
- public void verify(InputStream is, int vCardType, final VCardParser vCardParser)
- throws IOException, VCardException {
- try {
- vCardParser.parse(is, this);
- } finally {
- if (is != null) {
- try {
- is.close();
- } catch (IOException e) {
- }
- }
- }
- }
-
- @Override
- public void endEntry() {
- super.endEntry();
- mAndroidTestCase.assertTrue(mIndex < mPropertyNodesVerifierElemList.size());
- mAndroidTestCase.assertTrue(mIndex < vNodeList.size());
- mPropertyNodesVerifierElemList.get(mIndex).verify(vNodeList.get(mIndex));
- mIndex++;
- }
-}
-
-/**
- * Utility class which verifies input VNode.
- *
- * This class first checks whether each propertyNode in the VNode is in the
- * "ordered expected property list".
- * If the node does not exist in the "ordered list", the class refers to
- * "unorderd expected property set" and checks the node is expected somewhere.
- */
-/* package */ class PropertyNodesVerifierElem {
- public static class TypeSet extends HashSet<String> {
- public TypeSet(String ... array) {
- super(Arrays.asList(array));
- }
- }
-
- public static class GroupSet extends HashSet<String> {
- public GroupSet(String ... array) {
- super(Arrays.asList(array));
- }
- }
-
- private final HashMap<String, List<PropertyNode>> mOrderedNodeMap;
- // Intentionally use ArrayList instead of Set, assuming there may be more than one
- // exactly same objects.
- private final ArrayList<PropertyNode> mUnorderedNodeList;
- private final TestCase mTestCase;
-
- public PropertyNodesVerifierElem(TestCase testCase) {
- mOrderedNodeMap = new HashMap<String, List<PropertyNode>>();
- mUnorderedNodeList = new ArrayList<PropertyNode>();
- mTestCase = testCase;
- }
-
- // WithOrder
-
- public PropertyNodesVerifierElem addExpectedNodeWithOrder(String propName, String propValue) {
- return addExpectedNodeWithOrder(propName, propValue, null, null, null, null, null);
- }
-
- public PropertyNodesVerifierElem addExpectedNodeWithOrder(
- String propName, String propValue, ContentValues contentValues) {
- return addExpectedNodeWithOrder(propName, propValue, null,
- null, contentValues, null, null);
- }
-
- public PropertyNodesVerifierElem addExpectedNodeWithOrder(
- String propName, List<String> propValueList, ContentValues contentValues) {
- return addExpectedNodeWithOrder(propName, null, propValueList,
- null, contentValues, null, null);
- }
-
- public PropertyNodesVerifierElem addExpectedNodeWithOrder(
- String propName, String propValue, List<String> propValueList) {
- return addExpectedNodeWithOrder(propName, propValue, propValueList, null,
- null, null, null);
- }
-
- public PropertyNodesVerifierElem addExpectedNodeWithOrder(
- String propName, List<String> propValueList) {
- final String propValue = concatinateListWithSemiColon(propValueList);
- return addExpectedNodeWithOrder(propName, propValue.toString(), propValueList,
- null, null, null, null);
- }
-
- public PropertyNodesVerifierElem addExpectedNodeWithOrder(String propName, String propValue,
- TypeSet paramMap_TYPE) {
- return addExpectedNodeWithOrder(propName, propValue, null,
- null, null, paramMap_TYPE, null);
- }
-
- public PropertyNodesVerifierElem addExpectedNodeWithOrder(String propName,
- List<String> propValueList, TypeSet paramMap_TYPE) {
- return addExpectedNodeWithOrder(propName, null, propValueList, null, null,
- paramMap_TYPE, null);
- }
-
- public PropertyNodesVerifierElem addExpectedNodeWithOrder(String propName, String propValue,
- ContentValues paramMap, TypeSet paramMap_TYPE) {
- return addExpectedNodeWithOrder(propName, propValue, null, null,
- paramMap, paramMap_TYPE, null);
- }
-
- public PropertyNodesVerifierElem addExpectedNodeWithOrder(String propName, String propValue,
- List<String> propValueList, TypeSet paramMap_TYPE) {
- return addExpectedNodeWithOrder(propName, propValue, propValueList, null, null,
- paramMap_TYPE, null);
- }
-
- public PropertyNodesVerifierElem addExpectedNodeWithOrder(String propName, String propValue,
- List<String> propValueList, byte[] propValue_bytes,
- ContentValues paramMap, TypeSet paramMap_TYPE, GroupSet propGroupSet) {
- if (propValue == null && propValueList != null) {
- propValue = concatinateListWithSemiColon(propValueList);
- }
- PropertyNode propertyNode = new PropertyNode(propName,
- propValue, propValueList, propValue_bytes,
- paramMap, paramMap_TYPE, propGroupSet);
- List<PropertyNode> expectedNodeList = mOrderedNodeMap.get(propName);
- if (expectedNodeList == null) {
- expectedNodeList = new ArrayList<PropertyNode>();
- mOrderedNodeMap.put(propName, expectedNodeList);
- }
- expectedNodeList.add(propertyNode);
- return this;
- }
-
- // WithoutOrder
-
- public PropertyNodesVerifierElem addExpectedNode(String propName, String propValue) {
- return addExpectedNode(propName, propValue, null, null, null, null, null);
- }
-
- public PropertyNodesVerifierElem addExpectedNode(String propName, String propValue,
- ContentValues contentValues) {
- return addExpectedNode(propName, propValue, null, null, contentValues, null, null);
- }
-
- public PropertyNodesVerifierElem addExpectedNode(String propName,
- List<String> propValueList, ContentValues contentValues) {
- return addExpectedNode(propName, null,
- propValueList, null, contentValues, null, null);
- }
-
- public PropertyNodesVerifierElem addExpectedNode(String propName, String propValue,
- List<String> propValueList) {
- return addExpectedNode(propName, propValue, propValueList, null, null, null, null);
- }
-
- public PropertyNodesVerifierElem addExpectedNode(String propName,
- List<String> propValueList) {
- return addExpectedNode(propName, null, propValueList,
- null, null, null, null);
- }
-
- public PropertyNodesVerifierElem addExpectedNode(String propName, String propValue,
- TypeSet paramMap_TYPE) {
- return addExpectedNode(propName, propValue, null, null, null, paramMap_TYPE, null);
- }
-
- public PropertyNodesVerifierElem addExpectedNode(String propName,
- List<String> propValueList, TypeSet paramMap_TYPE) {
- final String propValue = concatinateListWithSemiColon(propValueList);
- return addExpectedNode(propName, propValue, propValueList, null, null,
- paramMap_TYPE, null);
- }
-
- public PropertyNodesVerifierElem addExpectedNode(String propName, String propValue,
- List<String> propValueList, TypeSet paramMap_TYPE) {
- return addExpectedNode(propName, propValue, propValueList, null, null,
- paramMap_TYPE, null);
- }
-
- public PropertyNodesVerifierElem addExpectedNode(String propName, String propValue,
- ContentValues paramMap, TypeSet paramMap_TYPE) {
- return addExpectedNode(propName, propValue, null, null,
- paramMap, paramMap_TYPE, null);
- }
-
- public PropertyNodesVerifierElem addExpectedNode(String propName, String propValue,
- List<String> propValueList, byte[] propValue_bytes,
- ContentValues paramMap, TypeSet paramMap_TYPE, GroupSet propGroupSet) {
- if (propValue == null && propValueList != null) {
- propValue = concatinateListWithSemiColon(propValueList);
- }
- mUnorderedNodeList.add(new PropertyNode(propName, propValue,
- propValueList, propValue_bytes, paramMap, paramMap_TYPE, propGroupSet));
- return this;
- }
-
- public void verify(VNode vnode) {
- for (PropertyNode actualNode : vnode.propList) {
- verifyNode(actualNode.propName, actualNode);
- }
- if (!mOrderedNodeMap.isEmpty() || !mUnorderedNodeList.isEmpty()) {
- List<String> expectedProps = new ArrayList<String>();
- for (List<PropertyNode> nodes : mOrderedNodeMap.values()) {
- for (PropertyNode node : nodes) {
- if (!expectedProps.contains(node.propName)) {
- expectedProps.add(node.propName);
- }
- }
- }
- for (PropertyNode node : mUnorderedNodeList) {
- if (!expectedProps.contains(node.propName)) {
- expectedProps.add(node.propName);
- }
- }
- mTestCase.fail("Expected property " + Arrays.toString(expectedProps.toArray())
- + " was not found.");
- }
- }
-
- private void verifyNode(final String propName, final PropertyNode actualNode) {
- List<PropertyNode> expectedNodeList = mOrderedNodeMap.get(propName);
- final int size = (expectedNodeList != null ? expectedNodeList.size() : 0);
- if (size > 0) {
- for (int i = 0; i < size; i++) {
- PropertyNode expectedNode = expectedNodeList.get(i);
- List<PropertyNode> expectedButDifferentValueList = new ArrayList<PropertyNode>();
- if (expectedNode.propName.equals(propName)) {
- if (expectedNode.equals(actualNode)) {
- expectedNodeList.remove(i);
- if (expectedNodeList.size() == 0) {
- mOrderedNodeMap.remove(propName);
- }
- return;
- } else {
- expectedButDifferentValueList.add(expectedNode);
- }
- }
-
- // "actualNode" is not in ordered expected list.
- // Try looking over unordered expected list.
- if (tryFoundExpectedNodeFromUnorderedList(actualNode,
- expectedButDifferentValueList)) {
- return;
- }
-
- if (!expectedButDifferentValueList.isEmpty()) {
- // Same propName exists but with different value(s).
- failWithExpectedNodeList(propName, actualNode,
- expectedButDifferentValueList);
- } else {
- // There's no expected node with same propName.
- mTestCase.fail("Unexpected property \"" + propName + "\" exists.");
- }
- }
- } else {
- List<PropertyNode> expectedButDifferentValueList =
- new ArrayList<PropertyNode>();
- if (tryFoundExpectedNodeFromUnorderedList(actualNode, expectedButDifferentValueList)) {
- return;
- } else {
- if (!expectedButDifferentValueList.isEmpty()) {
- // Same propName exists but with different value(s).
- failWithExpectedNodeList(propName, actualNode,
- expectedButDifferentValueList);
- } else {
- // There's no expected node with same propName.
- mTestCase.fail("Unexpected property \"" + propName + "\" exists.");
- }
- }
- }
- }
-
- private String concatinateListWithSemiColon(List<String> array) {
- StringBuffer buffer = new StringBuffer();
- boolean first = true;
- for (String propValueElem : array) {
- if (first) {
- first = false;
- } else {
- buffer.append(';');
- }
- buffer.append(propValueElem);
- }
-
- return buffer.toString();
- }
-
- private boolean tryFoundExpectedNodeFromUnorderedList(PropertyNode actualNode,
- List<PropertyNode> expectedButDifferentValueList) {
- final String propName = actualNode.propName;
- int unorderedListSize = mUnorderedNodeList.size();
- for (int i = 0; i < unorderedListSize; i++) {
- PropertyNode unorderedExpectedNode = mUnorderedNodeList.get(i);
- if (unorderedExpectedNode.propName.equals(propName)) {
- if (unorderedExpectedNode.equals(actualNode)) {
- mUnorderedNodeList.remove(i);
- return true;
- }
- expectedButDifferentValueList.add(unorderedExpectedNode);
- }
- }
- return false;
- }
-
- private void failWithExpectedNodeList(String propName, PropertyNode actualNode,
- List<PropertyNode> expectedNodeList) {
- StringBuilder builder = new StringBuilder();
- for (PropertyNode expectedNode : expectedNodeList) {
- builder.append("expected: ");
- builder.append(expectedNode.toString());
- builder.append("\n");
- }
- mTestCase.fail("Property \"" + propName + "\" has wrong value.\n"
- + builder.toString()
- + " actual: " + actualNode.toString());
- }
-}
diff --git a/core/tests/coretests/src/android/pim/vcard/VCardExporterTests.java b/core/tests/coretests/src/android/pim/vcard/VCardExporterTests.java
deleted file mode 100644
index 2de0464..0000000
--- a/core/tests/coretests/src/android/pim/vcard/VCardExporterTests.java
+++ /dev/null
@@ -1,969 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.pim.vcard;
-
-import android.content.ContentValues;
-import android.pim.vcard.VCardConfig;
-import android.provider.ContactsContract.CommonDataKinds.Email;
-import android.provider.ContactsContract.CommonDataKinds.Event;
-import android.provider.ContactsContract.CommonDataKinds.Im;
-import android.provider.ContactsContract.CommonDataKinds.Nickname;
-import android.provider.ContactsContract.CommonDataKinds.Note;
-import android.provider.ContactsContract.CommonDataKinds.Organization;
-import android.provider.ContactsContract.CommonDataKinds.Phone;
-import android.provider.ContactsContract.CommonDataKinds.Photo;
-import android.provider.ContactsContract.CommonDataKinds.Relation;
-import android.provider.ContactsContract.CommonDataKinds.StructuredName;
-import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
-import android.provider.ContactsContract.CommonDataKinds.Website;
-
-import android.pim.vcard.PropertyNodesVerifierElem.TypeSet;
-
-import java.util.Arrays;
-
-/**
- * Tests for the code related to vCard exporter, inculding vCard composer.
- * This test class depends on vCard importer code, so if tests for vCard importer fail,
- * the result of this class will not be reliable.
- */
-public class VCardExporterTests extends VCardTestsBase {
- private static final byte[] sPhotoByteArray =
- VCardImporterTests.sPhotoByteArrayForComplicatedCase;
-
- public void testSimpleV21() {
- mVerifier.initForExportTest(V21);
- mVerifier.addInputEntry().addContentValues(StructuredName.CONTENT_ITEM_TYPE)
- .put(StructuredName.FAMILY_NAME, "Ando")
- .put(StructuredName.GIVEN_NAME, "Roid");
- mVerifier.addPropertyNodesVerifierElem()
- .addExpectedNode("FN", "Roid Ando")
- .addExpectedNode("N", "Ando;Roid;;;",
- Arrays.asList("Ando", "Roid", "", "", ""));
- }
-
- private void testStructuredNameBasic(int vcardType) {
- final boolean isV30 = VCardConfig.isV30(vcardType);
- mVerifier.initForExportTest(vcardType);
- mVerifier.addInputEntry().addContentValues(StructuredName.CONTENT_ITEM_TYPE)
- .put(StructuredName.FAMILY_NAME, "AppropriateFamilyName")
- .put(StructuredName.GIVEN_NAME, "AppropriateGivenName")
- .put(StructuredName.MIDDLE_NAME, "AppropriateMiddleName")
- .put(StructuredName.PREFIX, "AppropriatePrefix")
- .put(StructuredName.SUFFIX, "AppropriateSuffix")
- .put(StructuredName.PHONETIC_FAMILY_NAME, "AppropriatePhoneticFamily")
- .put(StructuredName.PHONETIC_GIVEN_NAME, "AppropriatePhoneticGiven")
- .put(StructuredName.PHONETIC_MIDDLE_NAME, "AppropriatePhoneticMiddle");
-
- PropertyNodesVerifierElem elem = mVerifier.addPropertyNodesVerifierElem()
- .addExpectedNodeWithOrder("N",
- "AppropriateFamilyName;AppropriateGivenName;AppropriateMiddleName;"
- + "AppropriatePrefix;AppropriateSuffix",
- Arrays.asList("AppropriateFamilyName", "AppropriateGivenName",
- "AppropriateMiddleName", "AppropriatePrefix", "AppropriateSuffix"))
- .addExpectedNodeWithOrder("FN",
- "AppropriatePrefix AppropriateGivenName "
- + "AppropriateMiddleName AppropriateFamilyName AppropriateSuffix")
- .addExpectedNode("X-PHONETIC-FIRST-NAME", "AppropriatePhoneticGiven")
- .addExpectedNode("X-PHONETIC-MIDDLE-NAME", "AppropriatePhoneticMiddle")
- .addExpectedNode("X-PHONETIC-LAST-NAME", "AppropriatePhoneticFamily");
-
- if (isV30) {
- elem.addExpectedNode("SORT-STRING",
- "AppropriatePhoneticGiven AppropriatePhoneticMiddle "
- + "AppropriatePhoneticFamily");
- }
- }
-
- public void testStructuredNameBasicV21() {
- testStructuredNameBasic(V21);
- }
-
- public void testStructuredNameBasicV30() {
- testStructuredNameBasic(V30);
- }
-
- /**
- * Test that only "primary" StructuredName is emitted, so that our vCard file
- * will not confuse the external importer, assuming there may be some importer
- * which presume that there's only one property toward each of "N", "FN", etc.
- * Note that more than one "N", "FN", etc. properties are acceptable in vCard spec.
- */
- private void testStructuredNameUsePrimaryCommon(int vcardType) {
- final boolean isV30 = (vcardType == V30);
- mVerifier.initForExportTest(vcardType);
- ContactEntry entry = mVerifier.addInputEntry();
- entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
- .put(StructuredName.FAMILY_NAME, "DoNotEmitFamilyName1")
- .put(StructuredName.GIVEN_NAME, "DoNotEmitGivenName1")
- .put(StructuredName.MIDDLE_NAME, "DoNotEmitMiddleName1")
- .put(StructuredName.PREFIX, "DoNotEmitPrefix1")
- .put(StructuredName.SUFFIX, "DoNotEmitSuffix1")
- .put(StructuredName.PHONETIC_FAMILY_NAME, "DoNotEmitPhoneticFamily1")
- .put(StructuredName.PHONETIC_GIVEN_NAME, "DoNotEmitPhoneticGiven1")
- .put(StructuredName.PHONETIC_MIDDLE_NAME, "DoNotEmitPhoneticMiddle1");
-
- // With "IS_PRIMARY=1". This is what we should use.
- entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
- .put(StructuredName.FAMILY_NAME, "AppropriateFamilyName")
- .put(StructuredName.GIVEN_NAME, "AppropriateGivenName")
- .put(StructuredName.MIDDLE_NAME, "AppropriateMiddleName")
- .put(StructuredName.PREFIX, "AppropriatePrefix")
- .put(StructuredName.SUFFIX, "AppropriateSuffix")
- .put(StructuredName.PHONETIC_FAMILY_NAME, "AppropriatePhoneticFamily")
- .put(StructuredName.PHONETIC_GIVEN_NAME, "AppropriatePhoneticGiven")
- .put(StructuredName.PHONETIC_MIDDLE_NAME, "AppropriatePhoneticMiddle")
- .put(StructuredName.IS_PRIMARY, 1);
-
- // With "IS_PRIMARY=1", but we should ignore this time, since this is second, not first.
- entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
- .put(StructuredName.FAMILY_NAME, "DoNotEmitFamilyName2")
- .put(StructuredName.GIVEN_NAME, "DoNotEmitGivenName2")
- .put(StructuredName.MIDDLE_NAME, "DoNotEmitMiddleName2")
- .put(StructuredName.PREFIX, "DoNotEmitPrefix2")
- .put(StructuredName.SUFFIX, "DoNotEmitSuffix2")
- .put(StructuredName.PHONETIC_FAMILY_NAME, "DoNotEmitPhoneticFamily2")
- .put(StructuredName.PHONETIC_GIVEN_NAME, "DoNotEmitPhoneticGiven2")
- .put(StructuredName.PHONETIC_MIDDLE_NAME, "DoNotEmitPhoneticMiddle2")
- .put(StructuredName.IS_PRIMARY, 1);
-
- PropertyNodesVerifierElem elem = mVerifier.addPropertyNodesVerifierElem()
- .addExpectedNodeWithOrder("N",
- "AppropriateFamilyName;AppropriateGivenName;AppropriateMiddleName;"
- + "AppropriatePrefix;AppropriateSuffix",
- Arrays.asList("AppropriateFamilyName", "AppropriateGivenName",
- "AppropriateMiddleName", "AppropriatePrefix", "AppropriateSuffix"))
- .addExpectedNodeWithOrder("FN",
- "AppropriatePrefix AppropriateGivenName "
- + "AppropriateMiddleName AppropriateFamilyName AppropriateSuffix")
- .addExpectedNode("X-PHONETIC-FIRST-NAME", "AppropriatePhoneticGiven")
- .addExpectedNode("X-PHONETIC-MIDDLE-NAME", "AppropriatePhoneticMiddle")
- .addExpectedNode("X-PHONETIC-LAST-NAME", "AppropriatePhoneticFamily");
-
- if (isV30) {
- elem.addExpectedNode("SORT-STRING",
- "AppropriatePhoneticGiven AppropriatePhoneticMiddle "
- + "AppropriatePhoneticFamily");
- }
- }
-
- public void testStructuredNameUsePrimaryV21() {
- testStructuredNameUsePrimaryCommon(V21);
- }
-
- public void testStructuredNameUsePrimaryV30() {
- testStructuredNameUsePrimaryCommon(V30);
- }
-
- /**
- * Tests that only "super primary" StructuredName is emitted.
- * See also the comment in {@link #testStructuredNameUsePrimaryCommon(int)}.
- */
- private void testStructuredNameUseSuperPrimaryCommon(int vcardType) {
- final boolean isV30 = (vcardType == V30);
- mVerifier.initForExportTest(vcardType);
- ContactEntry entry = mVerifier.addInputEntry();
- entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
- .put(StructuredName.FAMILY_NAME, "DoNotEmitFamilyName1")
- .put(StructuredName.GIVEN_NAME, "DoNotEmitGivenName1")
- .put(StructuredName.MIDDLE_NAME, "DoNotEmitMiddleName1")
- .put(StructuredName.PREFIX, "DoNotEmitPrefix1")
- .put(StructuredName.SUFFIX, "DoNotEmitSuffix1")
- .put(StructuredName.PHONETIC_FAMILY_NAME, "DoNotEmitPhoneticFamily1")
- .put(StructuredName.PHONETIC_GIVEN_NAME, "DoNotEmitPhoneticGiven1")
- .put(StructuredName.PHONETIC_MIDDLE_NAME, "DoNotEmitPhoneticMiddle1");
-
- // With "IS_PRIMARY=1", but we should ignore this time.
- entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
- .put(StructuredName.FAMILY_NAME, "DoNotEmitFamilyName2")
- .put(StructuredName.GIVEN_NAME, "DoNotEmitGivenName2")
- .put(StructuredName.MIDDLE_NAME, "DoNotEmitMiddleName2")
- .put(StructuredName.PREFIX, "DoNotEmitPrefix2")
- .put(StructuredName.SUFFIX, "DoNotEmitSuffix2")
- .put(StructuredName.PHONETIC_FAMILY_NAME, "DoNotEmitPhoneticFamily2")
- .put(StructuredName.PHONETIC_GIVEN_NAME, "DoNotEmitPhoneticGiven2")
- .put(StructuredName.PHONETIC_MIDDLE_NAME, "DoNotEmitPhoneticMiddle2")
- .put(StructuredName.IS_PRIMARY, 1);
-
- // With "IS_SUPER_PRIMARY=1". This is what we should use.
- entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
- .put(StructuredName.FAMILY_NAME, "AppropriateFamilyName")
- .put(StructuredName.GIVEN_NAME, "AppropriateGivenName")
- .put(StructuredName.MIDDLE_NAME, "AppropriateMiddleName")
- .put(StructuredName.PREFIX, "AppropriatePrefix")
- .put(StructuredName.SUFFIX, "AppropriateSuffix")
- .put(StructuredName.PHONETIC_FAMILY_NAME, "AppropriatePhoneticFamily")
- .put(StructuredName.PHONETIC_GIVEN_NAME, "AppropriatePhoneticGiven")
- .put(StructuredName.PHONETIC_MIDDLE_NAME, "AppropriatePhoneticMiddle")
- .put(StructuredName.IS_SUPER_PRIMARY, 1);
-
- entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
- .put(StructuredName.FAMILY_NAME, "DoNotEmitFamilyName3")
- .put(StructuredName.GIVEN_NAME, "DoNotEmitGivenName3")
- .put(StructuredName.MIDDLE_NAME, "DoNotEmitMiddleName3")
- .put(StructuredName.PREFIX, "DoNotEmitPrefix3")
- .put(StructuredName.SUFFIX, "DoNotEmitSuffix3")
- .put(StructuredName.PHONETIC_FAMILY_NAME, "DoNotEmitPhoneticFamily3")
- .put(StructuredName.PHONETIC_GIVEN_NAME, "DoNotEmitPhoneticGiven3")
- .put(StructuredName.PHONETIC_MIDDLE_NAME, "DoNotEmitPhoneticMiddle3")
- .put(StructuredName.IS_PRIMARY, 1);
-
- PropertyNodesVerifierElem elem = mVerifier.addPropertyNodesVerifierElem()
- .addExpectedNodeWithOrder("N",
- "AppropriateFamilyName;AppropriateGivenName;AppropriateMiddleName;"
- + "AppropriatePrefix;AppropriateSuffix",
- Arrays.asList("AppropriateFamilyName", "AppropriateGivenName",
- "AppropriateMiddleName", "AppropriatePrefix", "AppropriateSuffix"))
- .addExpectedNodeWithOrder("FN",
- "AppropriatePrefix AppropriateGivenName "
- + "AppropriateMiddleName AppropriateFamilyName AppropriateSuffix")
- .addExpectedNode("X-PHONETIC-FIRST-NAME", "AppropriatePhoneticGiven")
- .addExpectedNode("X-PHONETIC-MIDDLE-NAME", "AppropriatePhoneticMiddle")
- .addExpectedNode("X-PHONETIC-LAST-NAME", "AppropriatePhoneticFamily");
-
- if (isV30) {
- elem.addExpectedNode("SORT-STRING",
- "AppropriatePhoneticGiven AppropriatePhoneticMiddle"
- + " AppropriatePhoneticFamily");
- }
- }
-
- public void testStructuredNameUseSuperPrimaryV21() {
- testStructuredNameUseSuperPrimaryCommon(V21);
- }
-
- public void testStructuredNameUseSuperPrimaryV30() {
- testStructuredNameUseSuperPrimaryCommon(V30);
- }
-
- public void testNickNameV30() {
- mVerifier.initForExportTest(V30);
- mVerifier.addInputEntry().addContentValues(Nickname.CONTENT_ITEM_TYPE)
- .put(Nickname.NAME, "Nicky");
-
- mVerifier.addPropertyNodesVerifierElemWithEmptyName()
- .addExpectedNodeWithOrder("NICKNAME", "Nicky");
- }
-
- private void testPhoneBasicCommon(int vcardType) {
- mVerifier.initForExportTest(vcardType);
- mVerifier.addInputEntry().addContentValues(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.NUMBER, "1")
- .put(Phone.TYPE, Phone.TYPE_HOME);
- mVerifier.addPropertyNodesVerifierElemWithEmptyName()
- .addExpectedNode("TEL", "1", new TypeSet("HOME"));
- }
-
- public void testPhoneBasicV21() {
- testPhoneBasicCommon(V21);
- }
-
- public void testPhoneBasicV30() {
- testPhoneBasicCommon(V30);
- }
-
- public void testPhoneRefrainFormatting() {
- mVerifier.initForExportTest(V21 | VCardConfig.FLAG_REFRAIN_PHONE_NUMBER_FORMATTING);
- mVerifier.addInputEntry().addContentValues(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.NUMBER, "1234567890(abcdefghijklmnopqrstuvwxyz)")
- .put(Phone.TYPE, Phone.TYPE_HOME);
- mVerifier.addPropertyNodesVerifierElemWithEmptyName()
- .addExpectedNode("TEL", "1234567890(abcdefghijklmnopqrstuvwxyz)",
- new TypeSet("HOME"));
- }
-
- /**
- * Tests that vCard composer emits corresponding type param which we expect.
- */
- private void testPhoneVariousTypeSupport(int vcardType) {
- mVerifier.initForExportTest(vcardType);
- ContactEntry entry = mVerifier.addInputEntry();
- entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.NUMBER, "10")
- .put(Phone.TYPE, Phone.TYPE_HOME);
- entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.NUMBER, "20")
- .put(Phone.TYPE, Phone.TYPE_WORK);
- entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.NUMBER, "30")
- .put(Phone.TYPE, Phone.TYPE_FAX_HOME);
- entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.NUMBER, "40")
- .put(Phone.TYPE, Phone.TYPE_FAX_WORK);
- entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.NUMBER, "50")
- .put(Phone.TYPE, Phone.TYPE_MOBILE);
- entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.NUMBER, "60")
- .put(Phone.TYPE, Phone.TYPE_PAGER);
- entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.NUMBER, "70")
- .put(Phone.TYPE, Phone.TYPE_OTHER);
- entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.NUMBER, "80")
- .put(Phone.TYPE, Phone.TYPE_CAR);
- entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.NUMBER, "90")
- .put(Phone.TYPE, Phone.TYPE_COMPANY_MAIN);
- entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.NUMBER, "100")
- .put(Phone.TYPE, Phone.TYPE_ISDN);
- entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.NUMBER, "110")
- .put(Phone.TYPE, Phone.TYPE_MAIN);
- entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.NUMBER, "120")
- .put(Phone.TYPE, Phone.TYPE_OTHER_FAX);
- entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.NUMBER, "130")
- .put(Phone.TYPE, Phone.TYPE_TELEX);
- entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.NUMBER, "140")
- .put(Phone.TYPE, Phone.TYPE_WORK_MOBILE);
- entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.NUMBER, "150")
- .put(Phone.TYPE, Phone.TYPE_WORK_PAGER);
- entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.NUMBER, "160")
- .put(Phone.TYPE, Phone.TYPE_MMS);
-
- mVerifier.addPropertyNodesVerifierElemWithEmptyName()
- .addExpectedNode("TEL", "10", new TypeSet("HOME"))
- .addExpectedNode("TEL", "20", new TypeSet("WORK"))
- .addExpectedNode("TEL", "30", new TypeSet("HOME", "FAX"))
- .addExpectedNode("TEL", "40", new TypeSet("WORK", "FAX"))
- .addExpectedNode("TEL", "50", new TypeSet("CELL"))
- .addExpectedNode("TEL", "60", new TypeSet("PAGER"))
- .addExpectedNode("TEL", "70", new TypeSet("VOICE"))
- .addExpectedNode("TEL", "80", new TypeSet("CAR"))
- .addExpectedNode("TEL", "90", new TypeSet("WORK", "PREF"))
- .addExpectedNode("TEL", "100", new TypeSet("ISDN"))
- .addExpectedNode("TEL", "110", new TypeSet("PREF"))
- .addExpectedNode("TEL", "120", new TypeSet("FAX"))
- .addExpectedNode("TEL", "130", new TypeSet("TLX"))
- .addExpectedNode("TEL", "140", new TypeSet("WORK", "CELL"))
- .addExpectedNode("TEL", "150", new TypeSet("WORK", "PAGER"))
- .addExpectedNode("TEL", "160", new TypeSet("MSG"));
- }
-
- public void testPhoneVariousTypeSupportV21() {
- testPhoneVariousTypeSupport(V21);
- }
-
- public void testPhoneVariousTypeSupportV30() {
- testPhoneVariousTypeSupport(V30);
- }
-
- /**
- * Tests that "PREF"s are emitted appropriately.
- */
- private void testPhonePrefHandlingCommon(int vcardType) {
- mVerifier.initForExportTest(vcardType);
- ContactEntry entry = mVerifier.addInputEntry();
- entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.NUMBER, "1")
- .put(Phone.TYPE, Phone.TYPE_HOME);
- entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.NUMBER, "2")
- .put(Phone.TYPE, Phone.TYPE_WORK)
- .put(Phone.IS_PRIMARY, 1);
- entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.NUMBER, "3")
- .put(Phone.TYPE, Phone.TYPE_FAX_HOME)
- .put(Phone.IS_PRIMARY, 1);
- entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.NUMBER, "4")
- .put(Phone.TYPE, Phone.TYPE_FAX_WORK);
-
- mVerifier.addPropertyNodesVerifierElemWithEmptyName()
- .addExpectedNode("TEL", "4", new TypeSet("WORK", "FAX"))
- .addExpectedNode("TEL", "3", new TypeSet("HOME", "FAX", "PREF"))
- .addExpectedNode("TEL", "2", new TypeSet("WORK", "PREF"))
- .addExpectedNode("TEL", "1", new TypeSet("HOME"));
- }
-
- public void testPhonePrefHandlingV21() {
- testPhonePrefHandlingCommon(V21);
- }
-
- public void testPhonePrefHandlingV30() {
- testPhonePrefHandlingCommon(V30);
- }
-
- private void testMiscPhoneTypeHandling(int vcardType) {
- mVerifier.initForExportTest(vcardType);
- ContactEntry entry = mVerifier.addInputEntry();
- entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.NUMBER, "1")
- .put(Phone.TYPE, Phone.TYPE_CUSTOM)
- .put(Phone.LABEL, "Modem");
- entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.NUMBER, "2")
- .put(Phone.TYPE, Phone.TYPE_CUSTOM)
- .put(Phone.LABEL, "MSG");
- entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.NUMBER, "3")
- .put(Phone.TYPE, Phone.TYPE_CUSTOM)
- .put(Phone.LABEL, "BBS");
- entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.NUMBER, "4")
- .put(Phone.TYPE, Phone.TYPE_CUSTOM)
- .put(Phone.LABEL, "VIDEO");
- entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.NUMBER, "5")
- .put(Phone.TYPE, Phone.TYPE_CUSTOM);
- entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.NUMBER, "6")
- .put(Phone.TYPE, Phone.TYPE_CUSTOM)
- .put(Phone.LABEL, "_AUTO_CELL"); // The old indicator for the type mobile.
- entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.NUMBER, "7")
- .put(Phone.TYPE, Phone.TYPE_CUSTOM)
- .put(Phone.LABEL, "\u643A\u5E2F"); // Mobile phone in Japanese Kanji
- entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.NUMBER, "8")
- .put(Phone.TYPE, Phone.TYPE_CUSTOM)
- .put(Phone.LABEL, "invalid");
- PropertyNodesVerifierElem elem = mVerifier.addPropertyNodesVerifierElemWithEmptyName();
- elem.addExpectedNode("TEL", "1", new TypeSet("MODEM"))
- .addExpectedNode("TEL", "2", new TypeSet("MSG"))
- .addExpectedNode("TEL", "3", new TypeSet("BBS"))
- .addExpectedNode("TEL", "4", new TypeSet("VIDEO"))
- .addExpectedNode("TEL", "5", new TypeSet("VOICE"))
- .addExpectedNode("TEL", "6", new TypeSet("CELL"))
- .addExpectedNode("TEL", "7", new TypeSet("CELL"))
- .addExpectedNode("TEL", "8", new TypeSet("X-invalid"));
- }
-
- public void testPhoneTypeHandlingV21() {
- testMiscPhoneTypeHandling(V21);
- }
-
- public void testPhoneTypeHandlingV30() {
- testMiscPhoneTypeHandling(V30);
- }
-
- private void testEmailBasicCommon(int vcardType) {
- mVerifier.initForExportTest(vcardType);
- mVerifier.addInputEntry().addContentValues(Email.CONTENT_ITEM_TYPE)
- .put(Email.DATA, "sample@example.com");
- mVerifier.addPropertyNodesVerifierElemWithEmptyName()
- .addExpectedNode("EMAIL", "sample@example.com");
- }
-
- public void testEmailBasicV21() {
- testEmailBasicCommon(V21);
- }
-
- public void testEmailBasicV30() {
- testEmailBasicCommon(V30);
- }
-
- private void testEmailVariousTypeSupportCommon(int vcardType) {
- mVerifier.initForExportTest(vcardType);
- ContactEntry entry = mVerifier.addInputEntry();
- entry.addContentValues(Email.CONTENT_ITEM_TYPE)
- .put(Email.DATA, "type_home@example.com")
- .put(Email.TYPE, Email.TYPE_HOME);
- entry.addContentValues(Email.CONTENT_ITEM_TYPE)
- .put(Email.DATA, "type_work@example.com")
- .put(Email.TYPE, Email.TYPE_WORK);
- entry.addContentValues(Email.CONTENT_ITEM_TYPE)
- .put(Email.DATA, "type_mobile@example.com")
- .put(Email.TYPE, Email.TYPE_MOBILE);
- entry.addContentValues(Email.CONTENT_ITEM_TYPE)
- .put(Email.DATA, "type_other@example.com")
- .put(Email.TYPE, Email.TYPE_OTHER);
- mVerifier.addPropertyNodesVerifierElemWithEmptyName()
- .addExpectedNode("EMAIL", "type_home@example.com", new TypeSet("HOME"))
- .addExpectedNode("EMAIL", "type_work@example.com", new TypeSet("WORK"))
- .addExpectedNode("EMAIL", "type_mobile@example.com", new TypeSet("CELL"))
- .addExpectedNode("EMAIL", "type_other@example.com");
- }
-
- public void testEmailVariousTypeSupportV21() {
- testEmailVariousTypeSupportCommon(V21);
- }
-
- public void testEmailVariousTypeSupportV30() {
- testEmailVariousTypeSupportCommon(V30);
- }
-
- private void testEmailPrefHandlingCommon(int vcardType) {
- mVerifier.initForExportTest(vcardType);
- ContactEntry entry = mVerifier.addInputEntry();
- entry.addContentValues(Email.CONTENT_ITEM_TYPE)
- .put(Email.DATA, "type_home@example.com")
- .put(Email.TYPE, Email.TYPE_HOME)
- .put(Email.IS_PRIMARY, 1);
- entry.addContentValues(Email.CONTENT_ITEM_TYPE)
- .put(Email.DATA, "type_notype@example.com")
- .put(Email.IS_PRIMARY, 1);
-
- mVerifier.addPropertyNodesVerifierElemWithEmptyName()
- .addExpectedNode("EMAIL", "type_notype@example.com", new TypeSet("PREF"))
- .addExpectedNode("EMAIL", "type_home@example.com", new TypeSet("HOME", "PREF"));
- }
-
- public void testEmailPrefHandlingV21() {
- testEmailPrefHandlingCommon(V21);
- }
-
- public void testEmailPrefHandlingV30() {
- testEmailPrefHandlingCommon(V30);
- }
-
- private void testPostalAddressCommon(int vcardType) {
- mVerifier.initForExportTest(vcardType);
- mVerifier.addInputEntry().addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
- .put(StructuredPostal.POBOX, "Pobox")
- .put(StructuredPostal.NEIGHBORHOOD, "Neighborhood")
- .put(StructuredPostal.STREET, "Street")
- .put(StructuredPostal.CITY, "City")
- .put(StructuredPostal.REGION, "Region")
- .put(StructuredPostal.POSTCODE, "100")
- .put(StructuredPostal.COUNTRY, "Country")
- .put(StructuredPostal.FORMATTED_ADDRESS, "Formatted Address")
- .put(StructuredPostal.TYPE, StructuredPostal.TYPE_WORK);
- // adr-value = 0*6(text-value ";") text-value
- // ; PO Box, Extended Address, Street, Locality, Region, Postal Code,
- // ; Country Name
- //
- // The NEIGHBORHOOD field is appended after the CITY field.
- mVerifier.addPropertyNodesVerifierElemWithEmptyName()
- .addExpectedNode("ADR",
- Arrays.asList("Pobox", "", "Street", "City Neighborhood",
- "Region", "100", "Country"), new TypeSet("WORK"));
- }
-
- public void testPostalAddressV21() {
- testPostalAddressCommon(V21);
- }
-
- public void testPostalAddressV30() {
- testPostalAddressCommon(V30);
- }
-
- private void testPostalAddressNonNeighborhood(int vcardType) {
- mVerifier.initForExportTest(vcardType);
- mVerifier.addInputEntry().addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
- .put(StructuredPostal.CITY, "City");
- mVerifier.addPropertyNodesVerifierElemWithEmptyName()
- .addExpectedNode("ADR",
- Arrays.asList("", "", "", "City", "", "", ""), new TypeSet("HOME"));
- }
-
- public void testPostalAddressNonNeighborhoodV21() {
- testPostalAddressNonNeighborhood(V21);
- }
-
- public void testPostalAddressNonNeighborhoodV30() {
- testPostalAddressNonNeighborhood(V30);
- }
-
- private void testPostalAddressNonCity(int vcardType) {
- mVerifier.initForExportTest(vcardType);
- mVerifier.addInputEntry().addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
- .put(StructuredPostal.NEIGHBORHOOD, "Neighborhood");
- mVerifier.addPropertyNodesVerifierElemWithEmptyName()
- .addExpectedNode("ADR",
- Arrays.asList("", "", "", "Neighborhood", "", "", ""), new TypeSet("HOME"));
- }
-
- public void testPostalAddressNonCityV21() {
- testPostalAddressNonCity(V21);
- }
-
- public void testPostalAddressNonCityV30() {
- testPostalAddressNonCity(V30);
- }
-
- private void testPostalOnlyWithFormattedAddressCommon(int vcardType) {
- mVerifier.initForExportTest(vcardType);
- mVerifier.addInputEntry().addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
- .put(StructuredPostal.REGION, "") // Must be ignored.
- .put(StructuredPostal.FORMATTED_ADDRESS,
- "Formatted address CA 123-334 United Statue");
- mVerifier.addPropertyNodesVerifierElemWithEmptyName()
- .addExpectedNodeWithOrder("ADR", ";Formatted address CA 123-334 United Statue;;;;;",
- Arrays.asList("", "Formatted address CA 123-334 United Statue",
- "", "", "", "", ""), new TypeSet("HOME"));
- }
-
- public void testPostalOnlyWithFormattedAddressV21() {
- testPostalOnlyWithFormattedAddressCommon(V21);
- }
-
- public void testPostalOnlyWithFormattedAddressV30() {
- testPostalOnlyWithFormattedAddressCommon(V30);
- }
-
- /**
- * Tests that the vCard composer honors formatted data when it is available
- * even when it is partial.
- */
- private void testPostalWithBothStructuredAndFormattedCommon(int vcardType) {
- mVerifier.initForExportTest(vcardType);
- mVerifier.addInputEntry().addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
- .put(StructuredPostal.POBOX, "Pobox")
- .put(StructuredPostal.COUNTRY, "Country")
- .put(StructuredPostal.FORMATTED_ADDRESS,
- "Formatted address CA 123-334 United Statue"); // Should be ignored
- mVerifier.addPropertyNodesVerifierElemWithEmptyName()
- .addExpectedNode("ADR", "Pobox;;;;;;Country",
- Arrays.asList("Pobox", "", "", "", "", "", "Country"),
- new TypeSet("HOME"));
- }
-
- public void testPostalWithBothStructuredAndFormattedV21() {
- testPostalWithBothStructuredAndFormattedCommon(V21);
- }
-
- public void testPostalWithBothStructuredAndFormattedV30() {
- testPostalWithBothStructuredAndFormattedCommon(V30);
- }
-
- private void testOrganizationCommon(int vcardType) {
- mVerifier.initForExportTest(vcardType);
- ContactEntry entry = mVerifier.addInputEntry();
- entry.addContentValues(Organization.CONTENT_ITEM_TYPE)
- .put(Organization.COMPANY, "CompanyX")
- .put(Organization.DEPARTMENT, "DepartmentY")
- .put(Organization.TITLE, "TitleZ")
- .put(Organization.JOB_DESCRIPTION, "Description Rambda") // Ignored.
- .put(Organization.OFFICE_LOCATION, "Mountain View") // Ignored.
- .put(Organization.PHONETIC_NAME, "PhoneticName!") // Ignored
- .put(Organization.SYMBOL, "(^o^)/~~"); // Ignore him (her).
- entry.addContentValues(Organization.CONTENT_ITEM_TYPE)
- .putNull(Organization.COMPANY)
- .put(Organization.DEPARTMENT, "DepartmentXX")
- .putNull(Organization.TITLE);
- entry.addContentValues(Organization.CONTENT_ITEM_TYPE)
- .put(Organization.COMPANY, "CompanyXYZ")
- .putNull(Organization.DEPARTMENT)
- .put(Organization.TITLE, "TitleXYZYX");
- // Currently we do not use group but depend on the order.
- mVerifier.addPropertyNodesVerifierElemWithEmptyName()
- .addExpectedNodeWithOrder("ORG", "CompanyX;DepartmentY",
- Arrays.asList("CompanyX", "DepartmentY"))
- .addExpectedNodeWithOrder("TITLE", "TitleZ")
- .addExpectedNodeWithOrder("ORG", "DepartmentXX")
- .addExpectedNodeWithOrder("ORG", "CompanyXYZ")
- .addExpectedNodeWithOrder("TITLE", "TitleXYZYX");
- }
-
- public void testOrganizationV21() {
- testOrganizationCommon(V21);
- }
-
- public void testOrganizationV30() {
- testOrganizationCommon(V30);
- }
-
- private void testImVariousTypeSupportCommon(int vcardType) {
- mVerifier.initForExportTest(vcardType);
- ContactEntry entry = mVerifier.addInputEntry();
- entry.addContentValues(Im.CONTENT_ITEM_TYPE)
- .put(Im.PROTOCOL, Im.PROTOCOL_AIM)
- .put(Im.DATA, "aim");
- entry.addContentValues(Im.CONTENT_ITEM_TYPE)
- .put(Im.PROTOCOL, Im.PROTOCOL_MSN)
- .put(Im.DATA, "msn");
- entry.addContentValues(Im.CONTENT_ITEM_TYPE)
- .put(Im.PROTOCOL, Im.PROTOCOL_YAHOO)
- .put(Im.DATA, "yahoo");
- entry.addContentValues(Im.CONTENT_ITEM_TYPE)
- .put(Im.PROTOCOL, Im.PROTOCOL_SKYPE)
- .put(Im.DATA, "skype");
- entry.addContentValues(Im.CONTENT_ITEM_TYPE)
- .put(Im.PROTOCOL, Im.PROTOCOL_QQ)
- .put(Im.DATA, "qq");
- entry.addContentValues(Im.CONTENT_ITEM_TYPE)
- .put(Im.PROTOCOL, Im.PROTOCOL_GOOGLE_TALK)
- .put(Im.DATA, "google talk");
- entry.addContentValues(Im.CONTENT_ITEM_TYPE)
- .put(Im.PROTOCOL, Im.PROTOCOL_ICQ)
- .put(Im.DATA, "icq");
- entry.addContentValues(Im.CONTENT_ITEM_TYPE)
- .put(Im.PROTOCOL, Im.PROTOCOL_JABBER)
- .put(Im.DATA, "jabber");
- entry.addContentValues(Im.CONTENT_ITEM_TYPE)
- .put(Im.PROTOCOL, Im.PROTOCOL_NETMEETING)
- .put(Im.DATA, "netmeeting");
-
- // No determined way to express unknown type...
- mVerifier.addPropertyNodesVerifierElemWithEmptyName()
- .addExpectedNode("X-JABBER", "jabber")
- .addExpectedNode("X-ICQ", "icq")
- .addExpectedNode("X-GOOGLE-TALK", "google talk")
- .addExpectedNode("X-QQ", "qq")
- .addExpectedNode("X-SKYPE-USERNAME", "skype")
- .addExpectedNode("X-YAHOO", "yahoo")
- .addExpectedNode("X-MSN", "msn")
- .addExpectedNode("X-NETMEETING", "netmeeting")
- .addExpectedNode("X-AIM", "aim");
- }
-
- public void testImBasiV21() {
- testImVariousTypeSupportCommon(V21);
- }
-
- public void testImBasicV30() {
- testImVariousTypeSupportCommon(V30);
- }
-
- private void testImPrefHandlingCommon(int vcardType) {
- mVerifier.initForExportTest(vcardType);
- ContactEntry entry = mVerifier.addInputEntry();
- entry.addContentValues(Im.CONTENT_ITEM_TYPE)
- .put(Im.PROTOCOL, Im.PROTOCOL_AIM)
- .put(Im.DATA, "aim1");
- entry.addContentValues(Im.CONTENT_ITEM_TYPE)
- .put(Im.PROTOCOL, Im.PROTOCOL_AIM)
- .put(Im.DATA, "aim2")
- .put(Im.TYPE, Im.TYPE_HOME)
- .put(Im.IS_PRIMARY, 1);
-
- mVerifier.addPropertyNodesVerifierElemWithEmptyName()
- .addExpectedNode("X-AIM", "aim1")
- .addExpectedNode("X-AIM", "aim2", new TypeSet("HOME", "PREF"));
- }
-
- public void testImPrefHandlingV21() {
- testImPrefHandlingCommon(V21);
- }
-
- public void testImPrefHandlingV30() {
- testImPrefHandlingCommon(V30);
- }
-
- private void testWebsiteCommon(int vcardType) {
- mVerifier.initForExportTest(vcardType);
- ContactEntry entry = mVerifier.addInputEntry();
- entry.addContentValues(Website.CONTENT_ITEM_TYPE)
- .put(Website.URL, "http://website.example.android.com/index.html")
- .put(Website.TYPE, Website.TYPE_BLOG);
- entry.addContentValues(Website.CONTENT_ITEM_TYPE)
- .put(Website.URL, "ftp://ftp.example.android.com/index.html")
- .put(Website.TYPE, Website.TYPE_FTP);
-
- // We drop TYPE information since vCard (especially 3.0) does not allow us to emit it.
- mVerifier.addPropertyNodesVerifierElemWithEmptyName()
- .addExpectedNode("URL", "ftp://ftp.example.android.com/index.html")
- .addExpectedNode("URL", "http://website.example.android.com/index.html");
- }
-
- public void testWebsiteV21() {
- testWebsiteCommon(V21);
- }
-
- public void testWebsiteV30() {
- testWebsiteCommon(V30);
- }
-
- private String getAndroidPropValue(final String mimeType, String value, Integer type) {
- return getAndroidPropValue(mimeType, value, type, null);
- }
-
- private String getAndroidPropValue(final String mimeType, String value,
- Integer type, String label) {
- return (mimeType + ";" + value + ";"
- + (type != null ? type : "") + ";"
- + (label != null ? label : "") + ";;;;;;;;;;;;");
- }
-
- private void testEventCommon(int vcardType) {
- mVerifier.initForExportTest(vcardType);
- ContactEntry entry = mVerifier.addInputEntry();
- entry.addContentValues(Event.CONTENT_ITEM_TYPE)
- .put(Event.TYPE, Event.TYPE_ANNIVERSARY)
- .put(Event.START_DATE, "1982-06-16");
- entry.addContentValues(Event.CONTENT_ITEM_TYPE)
- .put(Event.TYPE, Event.TYPE_BIRTHDAY)
- .put(Event.START_DATE, "2008-10-22");
- entry.addContentValues(Event.CONTENT_ITEM_TYPE)
- .put(Event.TYPE, Event.TYPE_OTHER)
- .put(Event.START_DATE, "2018-03-12");
- entry.addContentValues(Event.CONTENT_ITEM_TYPE)
- .put(Event.TYPE, Event.TYPE_CUSTOM)
- .put(Event.LABEL, "The last day")
- .put(Event.START_DATE, "When the Tower of Hanoi with 64 rings is completed.");
- entry.addContentValues(Event.CONTENT_ITEM_TYPE)
- .put(Event.TYPE, Event.TYPE_BIRTHDAY)
- .put(Event.START_DATE, "2009-05-19"); // Should be ignored.
- mVerifier.addPropertyNodesVerifierElemWithEmptyName()
- .addExpectedNode("BDAY", "2008-10-22")
- .addExpectedNode("X-ANDROID-CUSTOM",
- getAndroidPropValue(
- Event.CONTENT_ITEM_TYPE, "1982-06-16", Event.TYPE_ANNIVERSARY))
- .addExpectedNode("X-ANDROID-CUSTOM",
- getAndroidPropValue(
- Event.CONTENT_ITEM_TYPE, "2018-03-12", Event.TYPE_OTHER))
- .addExpectedNode("X-ANDROID-CUSTOM",
- getAndroidPropValue(
- Event.CONTENT_ITEM_TYPE,
- "When the Tower of Hanoi with 64 rings is completed.",
- Event.TYPE_CUSTOM, "The last day"));
- }
-
- public void testEventV21() {
- testEventCommon(V21);
- }
-
- public void testEventV30() {
- testEventCommon(V30);
- }
-
- private void testNoteCommon(int vcardType) {
- mVerifier.initForExportTest(vcardType);
- ContactEntry entry = mVerifier.addInputEntry();
- entry.addContentValues(Note.CONTENT_ITEM_TYPE)
- .put(Note.NOTE, "note1");
- entry.addContentValues(Note.CONTENT_ITEM_TYPE)
- .put(Note.NOTE, "note2")
- .put(Note.IS_PRIMARY, 1); // Just ignored.
- mVerifier.addPropertyNodesVerifierElemWithEmptyName()
- .addExpectedNodeWithOrder("NOTE", "note1")
- .addExpectedNodeWithOrder("NOTE", "note2");
- }
-
- public void testNoteV21() {
- testNoteCommon(V21);
- }
-
- public void testNoteV30() {
- testNoteCommon(V30);
- }
-
- private void testPhotoCommon(int vcardType) {
- final boolean isV30 = vcardType == V30;
- mVerifier.initForExportTest(vcardType);
- ContactEntry entry = mVerifier.addInputEntry();
- entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
- .put(StructuredName.FAMILY_NAME, "PhotoTest");
- entry.addContentValues(Photo.CONTENT_ITEM_TYPE)
- .put(Photo.PHOTO, sPhotoByteArray);
-
- ContentValues contentValuesForPhoto = new ContentValues();
- contentValuesForPhoto.put("ENCODING", (isV30 ? "b" : "BASE64"));
- mVerifier.addPropertyNodesVerifierElem()
- .addExpectedNode("FN", "PhotoTest")
- .addExpectedNode("N", "PhotoTest;;;;",
- Arrays.asList("PhotoTest", "", "", "", ""))
- .addExpectedNodeWithOrder("PHOTO", null, null, sPhotoByteArray,
- contentValuesForPhoto, new TypeSet("JPEG"), null);
- }
-
- public void testPhotoV21() {
- testPhotoCommon(V21);
- }
-
- public void testPhotoV30() {
- testPhotoCommon(V30);
- }
-
- private void testRelationCommon(int vcardType) {
- mVerifier.initForExportTest(vcardType);
- mVerifier.addInputEntry().addContentValues(Relation.CONTENT_ITEM_TYPE)
- .put(Relation.TYPE, Relation.TYPE_MOTHER)
- .put(Relation.NAME, "Ms. Mother");
- mVerifier.addContentValuesVerifierElem().addExpected(Relation.CONTENT_ITEM_TYPE)
- .put(Relation.TYPE, Relation.TYPE_MOTHER)
- .put(Relation.NAME, "Ms. Mother");
- }
-
- public void testRelationV21() {
- testRelationCommon(V21);
- }
-
- public void testRelationV30() {
- testRelationCommon(V30);
- }
-
- public void testV30HandleEscape() {
- mVerifier.initForExportTest(V30);
- mVerifier.addInputEntry().addContentValues(StructuredName.CONTENT_ITEM_TYPE)
- .put(StructuredName.FAMILY_NAME, "\\")
- .put(StructuredName.GIVEN_NAME, ";")
- .put(StructuredName.MIDDLE_NAME, ",")
- .put(StructuredName.PREFIX, "\n")
- .put(StructuredName.DISPLAY_NAME, "[<{Unescaped:Asciis}>]");
- // Verifies the vCard String correctly escapes each character which must be escaped.
- mVerifier.addLineVerifierElem()
- .addExpected("N:\\\\;\\;;\\,;\\n;")
- .addExpected("FN:[<{Unescaped:Asciis}>]");
- mVerifier.addPropertyNodesVerifierElem()
- .addExpectedNode("FN", "[<{Unescaped:Asciis}>]")
- .addExpectedNode("N", Arrays.asList("\\", ";", ",", "\n", ""));
- }
-
- /**
- * There's no "NICKNAME" property in vCard 2.1, while there is in vCard 3.0.
- * We use Android-specific "X-ANDROID-CUSTOM" property.
- * This test verifies the functionality.
- */
- public void testNickNameV21() {
- mVerifier.initForExportTest(V21);
- mVerifier.addInputEntry().addContentValues(Nickname.CONTENT_ITEM_TYPE)
- .put(Nickname.NAME, "Nicky");
- mVerifier.addPropertyNodesVerifierElemWithEmptyName()
- .addExpectedNode("X-ANDROID-CUSTOM",
- Nickname.CONTENT_ITEM_TYPE + ";Nicky;;;;;;;;;;;;;;");
- mVerifier.addContentValuesVerifierElem().addExpected(Nickname.CONTENT_ITEM_TYPE)
- .put(Nickname.NAME, "Nicky");
- }
-
- public void testTolerateBrokenPhoneNumberEntryV21() {
- mVerifier.initForExportTest(V21);
- ContactEntry entry = mVerifier.addInputEntry();
- entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.TYPE, Phone.TYPE_HOME)
- .put(Phone.NUMBER, "111-222-3333 (Miami)\n444-5555-666 (Tokyo);"
- + "777-888-9999 (Chicago);111-222-3333 (Miami)");
- mVerifier.addPropertyNodesVerifierElemWithEmptyName()
- .addExpectedNode("TEL", "111-222-3333", new TypeSet("HOME"))
- .addExpectedNode("TEL", "444-555-5666", new TypeSet("HOME"))
- .addExpectedNode("TEL", "777-888-9999", new TypeSet("HOME"));
- }
-
- private void testPickUpNonEmptyContentValuesCommon(int vcardType) {
- mVerifier.initForExportTest(vcardType);
- ContactEntry entry = mVerifier.addInputEntry();
- entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
- .put(StructuredName.IS_PRIMARY, 1); // Empty name. Should be ignored.
- entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
- .put(StructuredName.FAMILY_NAME, "family1"); // Not primary. Should be ignored.
- entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
- .put(StructuredName.IS_PRIMARY, 1)
- .put(StructuredName.FAMILY_NAME, "family2"); // This entry is what we want.
- entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
- .put(StructuredName.IS_PRIMARY, 1)
- .put(StructuredName.FAMILY_NAME, "family3");
- entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
- .put(StructuredName.FAMILY_NAME, "family4");
- mVerifier.addPropertyNodesVerifierElem()
- .addExpectedNode("N", Arrays.asList("family2", "", "", "", ""))
- .addExpectedNode("FN", "family2");
- }
-
- public void testPickUpNonEmptyContentValuesV21() {
- testPickUpNonEmptyContentValuesCommon(V21);
- }
-
- public void testPickUpNonEmptyContentValuesV30() {
- testPickUpNonEmptyContentValuesCommon(V30);
- }
-}
diff --git a/core/tests/coretests/src/android/pim/vcard/VCardImporterTests.java b/core/tests/coretests/src/android/pim/vcard/VCardImporterTests.java
deleted file mode 100644
index 21f2254..0000000
--- a/core/tests/coretests/src/android/pim/vcard/VCardImporterTests.java
+++ /dev/null
@@ -1,1011 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.pim.vcard;
-
-import android.content.ContentValues;
-import android.pim.vcard.VCardConfig;
-import android.provider.ContactsContract.Data;
-import android.provider.ContactsContract.CommonDataKinds.Email;
-import android.provider.ContactsContract.CommonDataKinds.Event;
-import android.provider.ContactsContract.CommonDataKinds.Note;
-import android.provider.ContactsContract.CommonDataKinds.Organization;
-import android.provider.ContactsContract.CommonDataKinds.Phone;
-import android.provider.ContactsContract.CommonDataKinds.Photo;
-import android.provider.ContactsContract.CommonDataKinds.StructuredName;
-import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
-import android.provider.ContactsContract.CommonDataKinds.Website;
-
-import com.android.frameworks.coretests.R;
-import android.pim.vcard.PropertyNodesVerifierElem.TypeSet;
-
-import java.util.Arrays;
-
-public class VCardImporterTests extends VCardTestsBase {
- // Push data into int array at first since values like 0x80 are
- // interpreted as int by the compiler and casting all of them is
- // cumbersome...
- private static final int[] sPhotoIntArrayForComplicatedCase = {
- 0xff, 0xd8, 0xff, 0xe1, 0x0a, 0x0f, 0x45, 0x78, 0x69, 0x66, 0x00,
- 0x00, 0x4d, 0x4d, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0d,
- 0x01, 0x0e, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
- 0xaa, 0x01, 0x0f, 0x00, 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
- 0x00, 0xba, 0x01, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00,
- 0x00, 0x00, 0xc2, 0x01, 0x12, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01,
- 0x00, 0x01, 0x00, 0x00, 0x01, 0x1a, 0x00, 0x05, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0xc8, 0x01, 0x1b, 0x00, 0x05, 0x00, 0x00,
- 0x00, 0x01, 0x00, 0x00, 0x00, 0xd0, 0x01, 0x28, 0x00, 0x03, 0x00,
- 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x01, 0x31, 0x00, 0x02,
- 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0xd8, 0x01, 0x32, 0x00,
- 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xe6, 0x02, 0x13,
- 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x82,
- 0x98, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0xfa,
- 0x87, 0x69, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
- 0x84, 0xc4, 0xa5, 0x00, 0x07, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00,
- 0x01, 0x08, 0x00, 0x00, 0x04, 0x1e, 0x32, 0x30, 0x30, 0x38, 0x31,
- 0x30, 0x32, 0x39, 0x31, 0x33, 0x35, 0x35, 0x33, 0x31, 0x00, 0x00,
- 0x44, 0x6f, 0x43, 0x6f, 0x4d, 0x6f, 0x00, 0x00, 0x44, 0x39, 0x30,
- 0x35, 0x69, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x44, 0x39, 0x30,
- 0x35, 0x69, 0x20, 0x56, 0x65, 0x72, 0x31, 0x2e, 0x30, 0x30, 0x00,
- 0x32, 0x30, 0x30, 0x38, 0x3a, 0x31, 0x30, 0x3a, 0x32, 0x39, 0x20,
- 0x31, 0x33, 0x3a, 0x35, 0x35, 0x3a, 0x34, 0x37, 0x00, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x00, 0x50, 0x72, 0x69, 0x6e, 0x74, 0x49, 0x4d, 0x00, 0x30, 0x33,
- 0x30, 0x30, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x14, 0x00,
- 0x14, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
- 0x00, 0x34, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01,
- 0x00, 0x00, 0x00, 0x01, 0x10, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x11, 0x09, 0x00, 0x00, 0x27, 0x10, 0x00, 0x00, 0x0f, 0x0b, 0x00,
- 0x00, 0x27, 0x10, 0x00, 0x00, 0x05, 0x97, 0x00, 0x00, 0x27, 0x10,
- 0x00, 0x00, 0x08, 0xb0, 0x00, 0x00, 0x27, 0x10, 0x00, 0x00, 0x1c,
- 0x01, 0x00, 0x00, 0x27, 0x10, 0x00, 0x00, 0x02, 0x5e, 0x00, 0x00,
- 0x27, 0x10, 0x00, 0x00, 0x00, 0x8b, 0x00, 0x00, 0x27, 0x10, 0x00,
- 0x00, 0x03, 0xcb, 0x00, 0x00, 0x27, 0x10, 0x00, 0x00, 0x1b, 0xe5,
- 0x00, 0x00, 0x27, 0x10, 0x00, 0x28, 0x82, 0x9a, 0x00, 0x05, 0x00,
- 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x6a, 0x82, 0x9d, 0x00, 0x05,
- 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x72, 0x88, 0x22, 0x00,
- 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x90, 0x00,
- 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x30, 0x32, 0x32, 0x30, 0x90,
- 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x03, 0x7a,
- 0x90, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x03,
- 0x8e, 0x91, 0x01, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x01, 0x02,
- 0x03, 0x00, 0x91, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x00, 0x03, 0xa2, 0x92, 0x01, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x03, 0xaa, 0x92, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x03, 0xb2, 0x92, 0x04, 0x00, 0x0a, 0x00, 0x00,
- 0x00, 0x01, 0x00, 0x00, 0x03, 0xba, 0x92, 0x05, 0x00, 0x05, 0x00,
- 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0xc2, 0x92, 0x07, 0x00, 0x03,
- 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x92, 0x08, 0x00,
- 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x92, 0x09,
- 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x92,
- 0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0xca,
- 0x92, 0x7c, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x00, 0x92, 0x86, 0x00, 0x07, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00,
- 0x03, 0xd2, 0xa0, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x30,
- 0x31, 0x30, 0x30, 0xa0, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01,
- 0x00, 0x01, 0x00, 0x00, 0xa0, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x60, 0x00, 0x00, 0xa0, 0x03, 0x00, 0x03, 0x00, 0x00,
- 0x00, 0x01, 0x00, 0x48, 0x00, 0x00, 0xa0, 0x05, 0x00, 0x04, 0x00,
- 0x00, 0x00, 0x01, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x0e, 0x00, 0x05,
- 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0xe8, 0xa2, 0x0f, 0x00,
- 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0xf0, 0xa2, 0x10,
- 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0xa2,
- 0x17, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00,
- 0xa3, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00,
- 0x00, 0xa3, 0x01, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00,
- 0x00, 0x00, 0xa4, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x00, 0x00, 0x00, 0xa4, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x00, 0x00, 0xa4, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x04, 0x00, 0x05, 0x00, 0x00,
- 0x00, 0x01, 0x00, 0x00, 0x03, 0xf8, 0xa4, 0x05, 0x00, 0x03, 0x00,
- 0x00, 0x00, 0x01, 0x00, 0x1d, 0x00, 0x00, 0xa4, 0x06, 0x00, 0x03,
- 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x07, 0x00,
- 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x08,
- 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4,
- 0x09, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
- 0xa4, 0x0a, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x00, 0xa4, 0x0c, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x00,
- 0x00, 0x27, 0x10, 0x00, 0x00, 0x01, 0x5e, 0x00, 0x00, 0x00, 0x64,
- 0x32, 0x30, 0x30, 0x38, 0x3a, 0x31, 0x30, 0x3a, 0x32, 0x39, 0x20,
- 0x31, 0x33, 0x3a, 0x35, 0x35, 0x3a, 0x33, 0x31, 0x00, 0x32, 0x30,
- 0x30, 0x38, 0x3a, 0x31, 0x30, 0x3a, 0x32, 0x39, 0x20, 0x31, 0x33,
- 0x3a, 0x35, 0x35, 0x3a, 0x34, 0x37, 0x00, 0x00, 0x00, 0x29, 0x88,
- 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x02, 0xb2, 0x00, 0x00, 0x00,
- 0x64, 0x00, 0x00, 0x01, 0x5e, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x25, 0x00,
- 0x00, 0x00, 0x0a, 0x00, 0x00, 0x0e, 0x92, 0x00, 0x00, 0x03, 0xe8,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x30, 0x30,
- 0x38, 0x31, 0x30, 0x32, 0x39, 0x31, 0x33, 0x35, 0x35, 0x33, 0x31,
- 0x00, 0x00, 0x20, 0x2a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x2a,
- 0xe2, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00,
- 0x04, 0x52, 0x39, 0x38, 0x00, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00,
- 0x00, 0x04, 0x30, 0x31, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x06, 0x01, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x06,
- 0x00, 0x00, 0x01, 0x1a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x00, 0x04, 0x6c, 0x01, 0x1b, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x04, 0x74, 0x01, 0x28, 0x00, 0x03, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x02, 0x00, 0x00, 0x02, 0x01, 0x00, 0x04, 0x00, 0x00,
- 0x00, 0x01, 0x00, 0x00, 0x04, 0x7c, 0x02, 0x02, 0x00, 0x04, 0x00,
- 0x00, 0x00, 0x01, 0x00, 0x00, 0x05, 0x8b, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x48, 0x00, 0x00, 0x00, 0x01, 0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84,
- 0x00, 0x20, 0x16, 0x18, 0x1c, 0x18, 0x14, 0x20, 0x1c, 0x1a, 0x1c,
- 0x24, 0x22, 0x20, 0x26, 0x30, 0x50, 0x34, 0x30, 0x2c, 0x2c, 0x30,
- 0x62, 0x46, 0x4a, 0x3a, 0x50, 0x74, 0x66, 0x7a, 0x78, 0x72, 0x66,
- 0x70, 0x6e, 0x80, 0x90, 0xb8, 0x9c, 0x80, 0x88, 0xae, 0x8a, 0x6e,
- 0x70, 0xa0, 0xda, 0xa2, 0xae, 0xbe, 0xc4, 0xce, 0xd0, 0xce, 0x7c,
- 0x9a, 0xe2, 0xf2, 0xe0, 0xc8, 0xf0, 0xb8, 0xca, 0xce, 0xc6, 0x01,
- 0x22, 0x24, 0x24, 0x30, 0x2a, 0x30, 0x5e, 0x34, 0x34, 0x5e, 0xc6,
- 0x84, 0x70, 0x84, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
- 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
- 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
- 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
- 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xff, 0xc0,
- 0x00, 0x11, 0x08, 0x00, 0x78, 0x00, 0xa0, 0x03, 0x01, 0x21, 0x00,
- 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xc4, 0x01, 0xa2, 0x00,
- 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
- 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03,
- 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01,
- 0x7d, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31,
- 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81,
- 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
- 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19,
- 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37,
- 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
- 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65,
- 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
- 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92,
- 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4,
- 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
- 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8,
- 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
- 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1,
- 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0x01, 0x00,
- 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
- 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04,
- 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77,
- 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12,
- 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14,
- 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15,
- 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17,
- 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37,
- 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
- 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65,
- 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
- 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a,
- 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3,
- 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5,
- 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
- 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9,
- 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2,
- 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xff, 0xda, 0x00,
- 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00,
- 0x14, 0x54, 0xaa, 0x2a, 0x46, 0x48, 0xa2, 0xa4, 0x55, 0xa6, 0x04,
- 0x8a, 0x29, 0xe0, 0x53, 0x10, 0xe0, 0x29, 0xc0, 0x50, 0x03, 0xb1,
- 0x46, 0x29, 0x80, 0x84, 0x52, 0x11, 0x40, 0x0d, 0x22, 0x9a, 0x45,
- 0x20, 0x23, 0x61, 0x51, 0x30, 0xa0, 0x08, 0xc8, 0xa8, 0xd8, 0x52,
- 0x02, 0x26, 0x15, 0x0b, 0x0a, 0x00, 0xb4, 0xa2, 0xa5, 0x5a, 0x00,
- 0x91, 0x45, 0x4a, 0xa2, 0x81, 0x92, 0x01, 0x4e, 0x02, 0x98, 0x87,
- 0x0a, 0x70, 0xa0, 0x07, 0x62, 0x8c, 0x50, 0x21, 0x0d, 0x25, 0x00,
- 0x34, 0x8a, 0x61, 0x14, 0x0c, 0x63, 0x0a, 0x89, 0x85, 0x00, 0x46,
- 0xd5, 0x1b, 0x52, 0x02, 0x16, 0xa8, 0x98, 0x50, 0x05, 0x94, 0xa9,
- 0x16, 0x80, 0x25, 0x5a, 0x95, 0x68, 0x18, 0xf1, 0x4f, 0x14, 0xc4,
- 0x3b, 0xb5, 0x22, 0xb6, 0x38, 0x34, 0x00, 0xe3, 0x22, 0x8e, 0xf4,
- 0x79, 0x8a, 0x7b, 0xd1, 0x71, 0x03, 0x30, 0xc7, 0x14, 0x83, 0xa5,
- 0x00, 0x06, 0x98, 0x68, 0x01, 0x8d, 0x51, 0x35, 0x03, 0x22, 0x6a,
- 0x8d, 0xa9, 0x01, 0x13, 0x54, 0x4d, 0x40, 0x13, 0xa5, 0x4a, 0x28,
- 0x02, 0x45, 0x35, 0x2a, 0x9a, 0x00, 0x78, 0x34, 0xf0, 0x69, 0x80,
- 0x34, 0x81, 0x45, 0x40, 0xce, 0x58, 0xe6, 0xa2, 0x4c, 0x06, 0xe4,
- 0xfa, 0xd1, 0x93, 0x50, 0x21, 0xca, 0xe4, 0x55, 0x84, 0x90, 0x30,
- 0xab, 0x8b, 0x18, 0xa6, 0x9a, 0x6a, 0xc4, 0x31, 0xaa, 0x26, 0xa0,
- 0x64, 0x4d, 0x51, 0xb5, 0x20, 0x23, 0x6a, 0x89, 0xa8, 0x02, 0x44,
- 0x35, 0x2a, 0x9a, 0x00, 0x95, 0x4d, 0x48, 0xa6, 0x80, 0x24, 0x53,
- 0x4e, 0xce, 0x05, 0x30, 0x2b, 0x3b, 0xee, 0x6a, 0x91, 0x5d, 0x76,
- 0x63, 0xbd, 0x65, 0x7d, 0x40, 0x66, 0x68, 0xa9, 0x02, 0x45, 0x2b,
- 0xb3, 0x9e, 0xb4, 0xc5, 0x6d, 0xad, 0x9a, 0xa0, 0x2c, 0x06, 0xc8,
- 0xcd, 0x04, 0xd6, 0xa2, 0x23, 0x63, 0x51, 0xb1, 0xa0, 0x64, 0x4d,
- 0x51, 0x93, 0x48, 0x08, 0xda, 0xa2, 0x6a, 0x00, 0x72, 0x1a, 0x99,
- 0x4d, 0x00, 0x48, 0xa6, 0xa4, 0x53, 0x4c, 0x07, 0x86, 0x03, 0xbd,
- 0x2b, 0x9c, 0xa7, 0x14, 0x98, 0x10, 0x85, 0x34, 0xe0, 0xa6, 0xb3,
- 0xb0, 0x0b, 0xb5, 0xa8, 0x0a, 0xd4, 0x58, 0x42, 0xed, 0x3e, 0x94,
- 0xd2, 0xa6, 0x8b, 0x01, 0x34, 0x44, 0xed, 0xe6, 0x9c, 0x4d, 0x6a,
- 0x80, 0x8d, 0x8d, 0x46, 0xc6, 0x80, 0x23, 0x63, 0x51, 0x9a, 0x06,
- 0x46, 0xd5, 0x13, 0x52, 0x01, 0x54, 0xd4, 0xaa, 0x68, 0x02, 0x40,
- 0x6a, 0x40, 0x78, 0xa0, 0x08, 0x59, 0xce, 0xee, 0xb5, 0x2a, 0x39,
- 0xd9, 0x59, 0xa7, 0xa8, 0x00, 0x73, 0xeb, 0x4e, 0x0e, 0x7d, 0x69,
- 0x5c, 0x05, 0xf3, 0x0f, 0xad, 0x1e, 0x61, 0xf5, 0xa7, 0x71, 0x0b,
- 0xe6, 0x35, 0x21, 0x90, 0xd3, 0xb8, 0x0e, 0x32, 0x10, 0x95, 0x10,
- 0x91, 0xb3, 0xd6, 0x9b, 0x60, 0x4b, 0x9c, 0x8a, 0x63, 0x1a, 0xb0,
- 0x18, 0x4d, 0x46, 0xc6, 0x80, 0x22, 0x6a, 0x61, 0xa4, 0x31, 0xaa,
- 0x6a, 0x55, 0x34, 0x01, 0x2a, 0x9a, 0x7e, 0x78, 0xa0, 0x08, 0x09,
- 0xf9, 0xaa, 0x58, 0xcf, 0xca, 0x6b, 0x3e, 0xa0, 0x00, 0xd3, 0x81,
- 0xa9, 0x01, 0x73, 0x46, 0x69, 0x80, 0xb9, 0xa4, 0xcd, 0x00, 0x2b,
- 0x1f, 0x92, 0xa3, 0x07, 0x9a, 0x6f, 0x70, 0x26, 0xcf, 0x14, 0xd2,
- 0x6b, 0x51, 0x0c, 0x63, 0x51, 0xb1, 0xa0, 0x08, 0xda, 0x98, 0x69,
- 0x0c, 0x8d, 0x4d, 0x4a, 0xa6, 0x80, 0x24, 0x53, 0x52, 0x03, 0xc5,
- 0x02, 0x21, 0x27, 0xe6, 0xa9, 0x23, 0x3f, 0x29, 0xac, 0xfa, 0x8c,
- 0x01, 0xe6, 0x9c, 0x0d, 0x48, 0x0a, 0x0d, 0x2e, 0x68, 0x01, 0x73,
- 0x49, 0x9a, 0x60, 0x2b, 0x1f, 0x92, 0x98, 0x3a, 0xd3, 0x7b, 0x81,
- 0x36, 0x78, 0xa6, 0x93, 0x5a, 0x88, 0x8c, 0x9a, 0x63, 0x1a, 0x00,
- 0x8c, 0xd3, 0x0d, 0x21, 0x91, 0x29, 0xa9, 0x14, 0xd0, 0x04, 0x8a,
- 0x69, 0xe0, 0xd3, 0x11, 0x1b, 0x1e, 0x6a, 0x48, 0xcf, 0xca, 0x6b,
- 0x3e, 0xa3, 0x10, 0x1a, 0x70, 0x35, 0x20, 0x38, 0x1a, 0x5c, 0xd2,
- 0x01, 0x73, 0x49, 0x9a, 0x60, 0x39, 0x8f, 0xca, 0x29, 0x8b, 0xf7,
- 0xaa, 0xba, 0x88, 0x96, 0x9a, 0x6b, 0x40, 0x18, 0xc6, 0xa3, 0x26,
- 0x80, 0x18, 0x69, 0xa6, 0x90, 0xc8, 0x14, 0xd4, 0x8a, 0x69, 0x80,
- 0xf0, 0x6a, 0x40, 0x68, 0x10, 0xbb, 0x41, 0xa7, 0xe3, 0x0b, 0xc5,
- 0x2b, 0x01, 0x10, 0xa7, 0x03, 0x59, 0x0c, 0x76, 0x69, 0x73, 0x40,
- 0x0b, 0x9a, 0x28, 0x11, 0x28, 0x19, 0x5e, 0x69, 0x02, 0x81, 0x5a,
- 0xd8, 0x00, 0xd3, 0x4d, 0x50, 0x0c, 0x6a, 0x8c, 0xd2, 0x01, 0xa6,
- 0x98, 0x69, 0x0c, 0xae, 0xa6, 0xa4, 0x06, 0x80, 0x1e, 0xa6, 0x9e,
- 0x0d, 0x31, 0x12, 0x03, 0x4f, 0x06, 0x80, 0x13, 0x60, 0x34, 0xd3,
- 0xc1, 0xa8, 0x92, 0x01, 0xf1, 0x8d, 0xdd, 0x69, 0xcc, 0xa1, 0x69,
- 0x5b, 0x4b, 0x80, 0x83, 0x93, 0x52, 0x04, 0x14, 0xe2, 0xae, 0x03,
- 0xa9, 0x0d, 0x68, 0x03, 0x4d, 0x34, 0xd0, 0x03, 0x0d, 0x30, 0xd2,
- 0x01, 0x86, 0x9a, 0x68, 0x19, 0x58, 0x1a, 0x78, 0xa4, 0x04, 0x8a,
- 0x69, 0xe0, 0xd3, 0x10, 0xe0, 0x69, 0xe0, 0xd0, 0x03, 0xc1, 0xa8,
- 0xdb, 0xad, 0x4c, 0x81, 0x12, 0x45, 0xd6, 0x9d, 0x25, 0x1d, 0x00,
- 0x6a, 0xf5, 0xa9, 0xe8, 0x80, 0x31, 0x29, 0x0d, 0x58, 0x08, 0x69,
- 0x86, 0x80, 0x1a, 0x69, 0x86, 0x90, 0x0c, 0x34, 0xd3, 0x48, 0x65,
- 0x51, 0x4f, 0x06, 0x98, 0x0f, 0x14, 0xf0, 0x68, 0x10, 0xf0, 0x69,
- 0xe0, 0xd0, 0x03, 0x81, 0xa5, 0x2b, 0x9a, 0x1a, 0xb8, 0x87, 0xa8,
- 0xdb, 0x4a, 0x46, 0x68, 0xb6, 0x80, 0x2a, 0xa8, 0x14, 0xea, 0x12,
- 0xb0, 0x05, 0x21, 0xa6, 0x02, 0x1a, 0x61, 0xa0, 0x06, 0x9a, 0x61,
- 0xa4, 0x31, 0x86, 0x9a, 0x69, 0x0c, 0xa8, 0x0d, 0x3c, 0x53, 0x01,
- 0xe2, 0x9e, 0x28, 0x10, 0xf1, 0x4e, 0x06, 0x98, 0x0f, 0x06, 0x9e,
- 0x0d, 0x02, 0x1c, 0x29, 0xc2, 0x80, 0x16, 0x96, 0x80, 0x0a, 0x4a,
- 0x00, 0x43, 0x4d, 0x34, 0x0c, 0x61, 0xa6, 0x1a, 0x40, 0x34, 0xd3,
- 0x4d, 0x21, 0x80, 0xff, 0xd9, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x0a,
- 0x07, 0x07, 0x08, 0x07, 0x06, 0x0a, 0x08, 0x08, 0x08, 0x0b, 0x0a,
- 0x0a, 0x0b, 0x0e, 0x18, 0x10, 0x0e, 0x0d, 0x0d, 0x0e, 0x1d, 0x15,
- 0x16, 0x11, 0x18, 0x23, 0x1f, 0x25, 0x24, 0x22, 0x1f, 0x22, 0x21,
- 0x26, 0x2b, 0x37, 0x2f, 0x26, 0x29, 0x34, 0x29, 0x21, 0x22, 0x30,
- 0x41, 0x31, 0x34, 0x39, 0x3b, 0x3e, 0x3e, 0x3e, 0x25, 0x2e, 0x44,
- 0x49, 0x43, 0x3c, 0x48, 0x37, 0x3d, 0x3e, 0x3b, 0x01, 0x0a, 0x0b,
- 0x0b, 0x0e, 0x0d, 0x0e, 0x1c, 0x10, 0x10, 0x1c, 0x3b, 0x28, 0x22,
- 0x28, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
- 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
- 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
- 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
- 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0xff, 0xc0, 0x00, 0x11,
- 0x08, 0x00, 0x48, 0x00, 0x60, 0x03, 0x01, 0x21, 0x00, 0x02, 0x11,
- 0x01, 0x03, 0x11, 0x01, 0xff, 0xc4, 0x01, 0xa2, 0x00, 0x00, 0x01,
- 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02,
- 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, 0x01,
- 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06,
- 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1,
- 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33,
- 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25,
- 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
- 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54,
- 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67,
- 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,
- 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94,
- 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6,
- 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8,
- 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca,
- 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
- 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3,
- 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0x01, 0x00, 0x03, 0x01,
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
- 0x09, 0x0a, 0x0b, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03,
- 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01,
- 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51,
- 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
- 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72,
- 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19,
- 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39,
- 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54,
- 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67,
- 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,
- 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93,
- 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
- 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
- 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9,
- 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2,
- 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4,
- 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xff, 0xda, 0x00, 0x0c, 0x03,
- 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00, 0x9e, 0xd2,
- 0x2e, 0x07, 0x15, 0xaf, 0x6d, 0x08, 0xe2, 0xb3, 0x45, 0x1a, 0xf6,
- 0xd0, 0x00, 0x01, 0xc5, 0x68, 0x45, 0x17, 0x4a, 0xb4, 0x22, 0xe4,
- 0x70, 0x8c, 0x74, 0xa9, 0x3c, 0xa1, 0x8e, 0x95, 0x48, 0x96, 0x31,
- 0xe2, 0x18, 0xe9, 0x55, 0xa5, 0x8c, 0x7a, 0x50, 0x05, 0x0b, 0x88,
- 0x86, 0x0f, 0x15, 0x8f, 0x75, 0x1f, 0x26, 0x93, 0x19, 0x91, 0x77,
- 0x18, 0xc1, 0xac, 0x4b, 0xc8, 0xfa, 0xd6, 0x63, 0x37, 0x6d, 0x31,
- 0xb4, 0x73, 0x5b, 0x36, 0xa0, 0x1c, 0x50, 0x80, 0xd7, 0x83, 0xa0,
- 0xab, 0xd1, 0x62, 0xad, 0x09, 0x8f, 0x17, 0x29, 0x03, 0xb2, 0xcc,
- 0xe0, 0x77, 0x14, 0xa3, 0x56, 0xb3, 0x27, 0x1e, 0x67, 0xe9, 0x52,
- 0xea, 0xc6, 0x3a, 0x36, 0x48, 0xef, 0x3d, 0x27, 0x70, 0x22, 0x60,
- 0x47, 0x52, 0x69, 0xb2, 0xe2, 0xad, 0x3b, 0xea, 0x80, 0xa3, 0x38,
- 0xe0, 0xd6, 0x3d, 0xd8, 0x1c, 0xd0, 0xca, 0x46, 0x3d, 0xd0, 0x18,
- 0x35, 0x89, 0x78, 0xa3, 0x9a, 0xcd, 0x8c, 0xd2, 0xb3, 0x93, 0x2a,
- 0x2b, 0x66, 0xd5, 0xf1, 0x8a, 0x10, 0x1a, 0xd6, 0xf2, 0x03, 0x8a,
- 0x9e, 0xe6, 0xf4, 0x5a, 0xdb, 0xef, 0xfe, 0x23, 0xc0, 0xa7, 0x27,
- 0xcb, 0x16, 0xc4, 0xcc, 0xdd, 0xe2, 0x78, 0x9a, 0x69, 0x66, 0xcc,
- 0x99, 0xe1, 0x4d, 0x47, 0xba, 0xbc, 0xd9, 0x6a, 0xee, 0x26, 0x59,
- 0x59, 0x4d, 0xac, 0x69, 0x34, 0x52, 0xe5, 0x8f, 0x55, 0xad, 0x58,
- 0xae, 0x85, 0xc4, 0x22, 0x41, 0xdf, 0xad, 0x76, 0x61, 0xe5, 0x6f,
- 0x74, 0x45, 0x69, 0xdc, 0x00, 0x79, 0xac, 0x8b, 0xa6, 0xc9, 0x35,
- 0xd4, 0x34, 0x64, 0xdc, 0x37, 0x06, 0xb1, 0xae, 0x88, 0xc1, 0xac,
- 0xd8, 0xc9, 0x2c, 0xa6, 0xe0, 0x73, 0x5b, 0x36, 0xf3, 0x74, 0xe6,
- 0x84, 0x05, 0xe3, 0xa9, 0x47, 0x6a, 0x14, 0xb6, 0x49, 0x3d, 0x85,
- 0x3a, 0xee, 0xee, 0x2b, 0xa8, 0xe2, 0x6f, 0x30, 0x81, 0xe9, 0x8a,
- 0xca, 0xa4, 0xe2, 0xd3, 0x8b, 0x01, 0xb1, 0xf9, 0x04, 0x7f, 0xaf,
- 0x23, 0xf0, 0xa9, 0x54, 0x41, 0x9c, 0xfd, 0xa3, 0xf4, 0xae, 0x65,
- 0x18, 0xf7, 0x25, 0x8a, 0xe2, 0x02, 0x38, 0xb8, 0xfd, 0x2a, 0x7b,
- 0x5b, 0xa8, 0x6d, 0x6d, 0x5d, 0x9a, 0x5d, 0xcb, 0xbb, 0xd2, 0xb6,
- 0xa6, 0xa3, 0x19, 0x5e, 0xe2, 0x03, 0x7b, 0x1d, 0xc2, 0x17, 0x8d,
- 0xb8, 0xac, 0xfb, 0x89, 0x39, 0x35, 0xd6, 0x9a, 0x6a, 0xe8, 0x66,
- 0x55, 0xcb, 0xf5, 0xac, 0x7b, 0x96, 0xeb, 0x50, 0xc6, 0x88, 0x6d,
- 0x66, 0xe9, 0xcd, 0x6c, 0xdb, 0x4f, 0xd3, 0x9a, 0x00, 0x2f, 0xe6,
- 0xf9, 0xa3, 0xe7, 0xb5, 0x4a, 0x93, 0x7f, 0xa2, 0xc6, 0x73, 0xdc,
- 0xd7, 0x15, 0x55, 0xef, 0x48, 0x7d, 0x09, 0x52, 0x6e, 0x3a, 0xd4,
- 0xab, 0x2f, 0xbd, 0x61, 0x16, 0x0c, 0x73, 0x49, 0xc5, 0x24, 0x92,
- 0x7f, 0xa2, 0x63, 0xfd, 0xaa, 0xd6, 0x2f, 0x71, 0x0e, 0xb1, 0x93,
- 0xf7, 0x2d, 0xf5, 0xa4, 0x9e, 0x4e, 0xb5, 0xdd, 0x4b, 0xf8, 0x68,
- 0x4c, 0xcb, 0xb9, 0x93, 0xad, 0x65, 0xce, 0xd9, 0x26, 0xa9, 0x8d,
- 0x19, 0xf6, 0xf2, 0xf4, 0xe6, 0xb5, 0xad, 0xe7, 0xc6, 0x39, 0xa0,
- 0x18, 0xeb, 0xc9, 0x77, 0x6c, 0x35, 0x2a, 0x4b, 0xfe, 0x8a, 0x9c,
- 0xff, 0x00, 0x11, 0xae, 0x3a, 0x8b, 0xde, 0x61, 0xd0, 0x9e, 0x39,
- 0xb8, 0xeb, 0x53, 0xac, 0xb9, 0xae, 0x5b, 0x00, 0xf3, 0x27, 0x14,
- 0x92, 0xc9, 0xfe, 0x8a, 0x3f, 0xde, 0x35, 0xac, 0x3a, 0x88, 0x92,
- 0xcd, 0xb1, 0x6e, 0x7d, 0xcd, 0x32, 0x67, 0xeb, 0xcd, 0x7a, 0x14,
- 0xfe, 0x04, 0x26, 0x66, 0xce, 0xf9, 0x26, 0xb3, 0xe6, 0x6e, 0xb4,
- 0xd9, 0x48, 0xc8, 0x82, 0x4e, 0x07, 0x35, 0xa7, 0x6f, 0x2f, 0x02,
- 0x9a, 0x06, 0x5f, 0x8c, 0xa4, 0x83, 0x0e, 0x32, 0x2a, 0x69, 0xe3,
- 0xdd, 0x12, 0x08, 0x97, 0x85, 0xec, 0x2a, 0x2a, 0x42, 0xf1, 0x76,
- 0x26, 0xe4, 0x6a, 0x59, 0x0e, 0x18, 0x10, 0x6a, 0xd2, 0x89, 0x02,
- 0x6e, 0x2a, 0x71, 0xeb, 0x5c, 0x1c, 0x8c, 0xa6, 0x48, 0xbb, 0xdc,
- 0x61, 0x41, 0x35, 0x72, 0x28, 0x87, 0xd9, 0xf6, 0x4a, 0xb9, 0xe7,
- 0x38, 0xae, 0x8c, 0x3d, 0x36, 0xdd, 0xde, 0xc4, 0xb0, 0x21, 0x51,
- 0x76, 0xa8, 0xc0, 0xaa, 0x93, 0x31, 0xe6, 0xbb, 0x2d, 0x65, 0x61,
- 0x19, 0xd3, 0x1e, 0xb5, 0x46, 0x5a, 0x96, 0x5a, 0x30, 0xa0, 0x7e,
- 0x05, 0x69, 0x5b, 0xc9, 0xc6, 0x28, 0x40, 0xcd, 0x08, 0x64, 0x3c,
- 0x73, 0x57, 0xe1, 0x94, 0xf1, 0xcd, 0x5a, 0x21, 0x8c, 0xb9, 0x63,
- 0xe7, 0x67, 0x1d, 0xab, 0x40, 0xb1, 0xfb, 0x00, 0x1d, 0xf0, 0x2b,
- 0x99, 0x2d, 0x66, 0x3e, 0x88, 0x75, 0x81, 0x3f, 0x31, 0xf6, 0xab,
- 0x64, 0xd6, 0xb4, 0x17, 0xee, 0xd0, 0x9e, 0xe4, 0x32, 0x1a, 0xa7,
- 0x31, 0xad, 0x18, 0x14, 0x26, 0xef, 0x54, 0xa5, 0xa8, 0x65, 0xa3,
- 0x9c, 0x81, 0xfa, 0x56, 0x8c, 0x2d, 0xce, 0x68, 0x40, 0xcb, 0xf1,
- 0x37, 0xbd, 0x5e, 0x85, 0xea, 0xd1, 0x0c, 0xbb, 0x19, 0x56, 0x23,
- 0x20, 0x1f, 0xad, 0x5c, 0x42, 0x08, 0x03, 0xb5, 0x55, 0x91, 0x04,
- 0xc9, 0x80, 0x38, 0x00, 0x0a, 0x71, 0x34, 0x6c, 0x32, 0x27, 0xe9,
- 0x55, 0x25, 0x15, 0x2c, 0x68, 0xa3, 0x30, 0xeb, 0x54, 0xa5, 0x15,
- 0x0c, 0xd1, 0x00, 0xff, 0xd9};
-
- /* package */ static final byte[] sPhotoByteArrayForComplicatedCase;
-
- static {
- final int length = sPhotoIntArrayForComplicatedCase.length;
- sPhotoByteArrayForComplicatedCase = new byte[length];
- for (int i = 0; i < length; i++) {
- sPhotoByteArrayForComplicatedCase[i] = (byte)sPhotoIntArrayForComplicatedCase[i];
- }
- }
-
- public void testV21SimpleCase1_Parsing() {
- mVerifier.initForImportTest(V21, R.raw.v21_simple_1);
- mVerifier.addPropertyNodesVerifierElem()
- .addExpectedNodeWithOrder("N", "Ando;Roid;", Arrays.asList("Ando", "Roid", ""));
- }
-
- public void testV21SimpleCase1_Type_Generic() {
- mVerifier.initForImportTest(VCardConfig.VCARD_TYPE_V21_GENERIC_UTF8, R.raw.v21_simple_1);
- mVerifier.addContentValuesVerifierElem()
- .addExpected(StructuredName.CONTENT_ITEM_TYPE)
- .put(StructuredName.FAMILY_NAME, "Ando")
- .put(StructuredName.GIVEN_NAME, "Roid")
- .put(StructuredName.DISPLAY_NAME, "Roid Ando");
- }
-
- public void testV21SimpleCase1_Type_Japanese() {
- mVerifier.initForImportTest(VCardConfig.VCARD_TYPE_V21_JAPANESE_SJIS, R.raw.v21_simple_1);
- mVerifier.addContentValuesVerifierElem()
- .addExpected(StructuredName.CONTENT_ITEM_TYPE)
- .put(StructuredName.FAMILY_NAME, "Ando")
- .put(StructuredName.GIVEN_NAME, "Roid")
- // If name-related strings only contains printable Ascii,
- // the order is remained to be US's:
- // "Prefix Given Middle Family Suffix"
- .put(StructuredName.DISPLAY_NAME, "Roid Ando");
- }
-
- public void testV21SimpleCase2() {
- mVerifier.initForImportTest(VCardConfig.VCARD_TYPE_V21_JAPANESE_SJIS, R.raw.v21_simple_2);
- mVerifier.addContentValuesVerifierElem()
- .addExpected(StructuredName.CONTENT_ITEM_TYPE)
- .put(StructuredName.DISPLAY_NAME, "Ando Roid");
- }
-
- public void testV21SimpleCase3() {
- mVerifier.initForImportTest(V21, R.raw.v21_simple_3);
- mVerifier.addContentValuesVerifierElem()
- .addExpected(StructuredName.CONTENT_ITEM_TYPE)
- .put(StructuredName.FAMILY_NAME, "Ando")
- .put(StructuredName.GIVEN_NAME, "Roid")
- // "FN" field should be prefered since it should contain the original
- // order intended by the author of the file.
- .put(StructuredName.DISPLAY_NAME, "Ando Roid");
- }
-
- /**
- * Tests ';' is properly handled by VCardParser implementation.
- */
- public void testV21BackslashCase_Parsing() {
- mVerifier.initForImportTest(V21, R.raw.v21_backslash);
- mVerifier.addPropertyNodesVerifierElem()
- .addExpectedNodeWithOrder("VERSION", "2.1")
- .addExpectedNodeWithOrder("N", ";A;B\\;C\\;;D;:E;\\\\;",
- Arrays.asList("", "A;B\\", "C\\;", "D", ":E", "\\\\", ""))
- .addExpectedNodeWithOrder("FN", "A;B\\C\\;D:E\\\\");
-
- }
-
- /**
- * Tests ContactStruct correctly ignores redundant fields in "N" property values and
- * inserts name related data.
- */
- public void testV21BackslashCase() {
- mVerifier.initForImportTest(V21, R.raw.v21_backslash);
- mVerifier.addContentValuesVerifierElem()
- .addExpected(StructuredName.CONTENT_ITEM_TYPE)
- // FAMILY_NAME is empty and removed in this test...
- .put(StructuredName.GIVEN_NAME, "A;B\\")
- .put(StructuredName.MIDDLE_NAME, "C\\;")
- .put(StructuredName.PREFIX, "D")
- .put(StructuredName.SUFFIX, ":E")
- .put(StructuredName.DISPLAY_NAME, "A;B\\C\\;D:E\\\\");
- }
-
- public void testOrgBeforTitle() {
- mVerifier.initForImportTest(V21, R.raw.v21_org_before_title);
- ContentValuesVerifierElem elem = mVerifier.addContentValuesVerifierElem();
- elem.addExpected(StructuredName.CONTENT_ITEM_TYPE)
- .put(StructuredName.DISPLAY_NAME, "Normal Guy");
- elem.addExpected(Organization.CONTENT_ITEM_TYPE)
- .put(Organization.COMPANY, "Company")
- .put(Organization.DEPARTMENT, "Organization Devision Room Sheet No.")
- .put(Organization.TITLE, "Excellent Janitor")
- .put(Organization.TYPE, Organization.TYPE_WORK);
- }
-
- public void testTitleBeforOrg() {
- mVerifier.initForImportTest(V21, R.raw.v21_title_before_org);
- ContentValuesVerifierElem elem = mVerifier.addContentValuesVerifierElem();
- elem.addExpected(StructuredName.CONTENT_ITEM_TYPE)
- .put(StructuredName.DISPLAY_NAME, "Nice Guy");
- elem.addExpected(Organization.CONTENT_ITEM_TYPE)
- .put(Organization.COMPANY, "Marverous")
- .put(Organization.DEPARTMENT, "Perfect Great Good Bad Poor")
- .put(Organization.TITLE, "Cool Title")
- .put(Organization.TYPE, Organization.TYPE_WORK);
- }
-
- /**
- * Verifies that vCard importer correctly interpret "PREF" attribute to IS_PRIMARY.
- * The data contain three cases: one "PREF", no "PREF" and multiple "PREF", in each type.
- */
- public void testV21PrefToIsPrimary() {
- mVerifier.initForImportTest(V21, R.raw.v21_pref_handling);
- ContentValuesVerifierElem elem = mVerifier.addContentValuesVerifierElem();
- elem.addExpected(StructuredName.CONTENT_ITEM_TYPE)
- .put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE)
- .put(StructuredName.DISPLAY_NAME, "Smith");
- elem.addExpected(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.NUMBER, "1")
- .put(Phone.TYPE, Phone.TYPE_HOME);
- elem.addExpected(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.NUMBER, "2")
- .put(Phone.TYPE, Phone.TYPE_WORK)
- .put(Phone.IS_PRIMARY, 1);
- elem.addExpected(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.NUMBER, "3")
- .put(Phone.TYPE, Phone.TYPE_ISDN);
- elem.addExpected(Email.CONTENT_ITEM_TYPE)
- .put(Email.DATA, "test@example.com")
- .put(Email.TYPE, Email.TYPE_HOME)
- .put(Email.IS_PRIMARY, 1);
- elem.addExpected(Email.CONTENT_ITEM_TYPE)
- .put(Email.DATA, "test2@examination.com")
- .put(Email.TYPE, Email.TYPE_MOBILE)
- .put(Email.IS_PRIMARY, 1);
- elem.addExpected(Organization.CONTENT_ITEM_TYPE)
- .put(Organization.COMPANY, "Company")
- .put(Organization.TITLE, "Engineer")
- .put(Organization.TYPE, Organization.TYPE_WORK);
- elem.addExpected(Organization.CONTENT_ITEM_TYPE)
- .put(Organization.COMPANY, "Mystery")
- .put(Organization.TITLE, "Blogger")
- .put(Organization.TYPE, Organization.TYPE_WORK);
- elem.addExpected(Organization.CONTENT_ITEM_TYPE)
- .put(Organization.COMPANY, "Poetry")
- .put(Organization.TITLE, "Poet")
- .put(Organization.TYPE, Organization.TYPE_WORK);
- }
-
- /**
- * Tests all the properties in a complicated vCard are correctly parsed by the VCardParser.
- */
- public void testV21ComplicatedCase_Parsing() {
- mVerifier.initForImportTest(V21, R.raw.v21_complicated);
- mVerifier.addPropertyNodesVerifierElem()
- .addExpectedNodeWithOrder("VERSION", "2.1")
- .addExpectedNodeWithOrder("N", "Gump;Forrest;Hoge;Pos;Tao",
- Arrays.asList("Gump", "Forrest", "Hoge", "Pos", "Tao"))
- .addExpectedNodeWithOrder("FN", "Joe Due")
- .addExpectedNodeWithOrder("ORG", "Gump Shrimp Co.;Sales Dept.;Manager;Fish keeper",
- Arrays.asList("Gump Shrimp Co.", "Sales Dept.;Manager", "Fish keeper"))
- .addExpectedNodeWithOrder("ROLE", "Fish Cake Keeper!")
- .addExpectedNodeWithOrder("TITLE", "Shrimp Man")
- .addExpectedNodeWithOrder("X-CLASS", "PUBLIC")
- .addExpectedNodeWithOrder("TEL", "(111) 555-1212", new TypeSet("WORK", "VOICE"))
- .addExpectedNodeWithOrder("TEL", "(404) 555-1212", new TypeSet("HOME", "VOICE"))
- .addExpectedNodeWithOrder("TEL", "0311111111", new TypeSet("CELL"))
- .addExpectedNodeWithOrder("TEL", "0322222222", new TypeSet("VIDEO"))
- .addExpectedNodeWithOrder("TEL", "0333333333", new TypeSet("VOICE"))
- .addExpectedNodeWithOrder("ADR",
- ";;100 Waters Edge;Baytown;LA;30314;United States of America",
- Arrays.asList("", "", "100 Waters Edge", "Baytown",
- "LA", "30314", "United States of America"),
- null, null, new TypeSet("WORK"), null)
- .addExpectedNodeWithOrder("LABEL",
- "100 Waters Edge\r\nBaytown, LA 30314\r\nUnited States of America",
- null, null, mContentValuesForQP, new TypeSet("WORK"), null)
- .addExpectedNodeWithOrder("ADR",
- ";;42 Plantation St.;Baytown;LA;30314;United States of America",
- Arrays.asList("", "", "42 Plantation St.", "Baytown",
- "LA", "30314", "United States of America"), null, null,
- new TypeSet("HOME"), null)
- .addExpectedNodeWithOrder("LABEL",
- "42 Plantation St.\r\nBaytown, LA 30314\r\nUnited States of America",
- null, null, mContentValuesForQP,
- new TypeSet("HOME"), null)
- .addExpectedNodeWithOrder("EMAIL", "forrestgump@walladalla.com",
- new TypeSet("PREF", "INTERNET"))
- .addExpectedNodeWithOrder("EMAIL", "cell@example.com", new TypeSet("CELL"))
- .addExpectedNodeWithOrder("NOTE", "The following note is the example from RFC 2045.")
- .addExpectedNodeWithOrder("NOTE",
- "Now's the time for all folk to come to the aid of their country.",
- null, null, mContentValuesForQP, null, null)
- .addExpectedNodeWithOrder("PHOTO", null,
- null, sPhotoByteArrayForComplicatedCase, mContentValuesForBase64V21,
- new TypeSet("JPEG"), null)
- .addExpectedNodeWithOrder("X-ATTRIBUTE", "Some String")
- .addExpectedNodeWithOrder("BDAY", "19800101")
- .addExpectedNodeWithOrder("GEO", "35.6563854,139.6994233")
- .addExpectedNodeWithOrder("URL", "http://www.example.com/")
- .addExpectedNodeWithOrder("REV", "20080424T195243Z");
- }
-
- /**
- * Checks ContactStruct correctly inserts values in a complicated vCard
- * into ContentResolver.
- */
- public void testV21ComplicatedCase() {
- mVerifier.initForImportTest(V21, R.raw.v21_complicated);
- ContentValuesVerifierElem elem = mVerifier.addContentValuesVerifierElem();
- elem.addExpected(StructuredName.CONTENT_ITEM_TYPE)
- .put(StructuredName.FAMILY_NAME, "Gump")
- .put(StructuredName.GIVEN_NAME, "Forrest")
- .put(StructuredName.MIDDLE_NAME, "Hoge")
- .put(StructuredName.PREFIX, "Pos")
- .put(StructuredName.SUFFIX, "Tao")
- .put(StructuredName.DISPLAY_NAME, "Joe Due");
- elem.addExpected(Organization.CONTENT_ITEM_TYPE)
- .put(Organization.TYPE, Organization.TYPE_WORK)
- .put(Organization.COMPANY, "Gump Shrimp Co.")
- .put(Organization.DEPARTMENT, "Sales Dept.;Manager Fish keeper")
- .put(Organization.TITLE, "Shrimp Man");
- elem.addExpected(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.TYPE, Phone.TYPE_WORK)
- // Phone number is expected to be formated with NAMP format in default.
- .put(Phone.NUMBER, "111-555-1212");
- elem.addExpected(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.TYPE, Phone.TYPE_HOME)
- .put(Phone.NUMBER, "404-555-1212");
- elem.addExpected(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.TYPE, Phone.TYPE_MOBILE)
- .put(Phone.NUMBER, "031-111-1111");
- elem.addExpected(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.TYPE, Phone.TYPE_CUSTOM)
- .put(Phone.LABEL, "VIDEO")
- .put(Phone.NUMBER, "032-222-2222");
- elem.addExpected(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.TYPE, Phone.TYPE_CUSTOM)
- .put(Phone.LABEL, "VOICE")
- .put(Phone.NUMBER, "033-333-3333");
- elem.addExpected(StructuredPostal.CONTENT_ITEM_TYPE)
- .put(StructuredPostal.TYPE, StructuredPostal.TYPE_WORK)
- .put(StructuredPostal.COUNTRY, "United States of America")
- .put(StructuredPostal.POSTCODE, "30314")
- .put(StructuredPostal.REGION, "LA")
- .put(StructuredPostal.CITY, "Baytown")
- .put(StructuredPostal.STREET, "100 Waters Edge")
- .put(StructuredPostal.FORMATTED_ADDRESS,
- "100 Waters Edge Baytown LA 30314 United States of America");
- elem.addExpected(StructuredPostal.CONTENT_ITEM_TYPE)
- .put(StructuredPostal.TYPE, StructuredPostal.TYPE_HOME)
- .put(StructuredPostal.COUNTRY, "United States of America")
- .put(StructuredPostal.POSTCODE, "30314")
- .put(StructuredPostal.REGION, "LA")
- .put(StructuredPostal.CITY, "Baytown")
- .put(StructuredPostal.STREET, "42 Plantation St.")
- .put(StructuredPostal.FORMATTED_ADDRESS,
- "42 Plantation St. Baytown LA 30314 United States of America");
- elem.addExpected(Email.CONTENT_ITEM_TYPE)
- // "TYPE=INTERNET" -> TYPE_CUSTOM + the label "INTERNET"
- .put(Email.TYPE, Email.TYPE_CUSTOM)
- .put(Email.LABEL, "INTERNET")
- .put(Email.DATA, "forrestgump@walladalla.com")
- .put(Email.IS_PRIMARY, 1);
- elem.addExpected(Email.CONTENT_ITEM_TYPE)
- .put(Email.TYPE, Email.TYPE_MOBILE)
- .put(Email.DATA, "cell@example.com");
- elem.addExpected(Note.CONTENT_ITEM_TYPE)
- .put(Note.NOTE, "The following note is the example from RFC 2045.");
- elem.addExpected(Note.CONTENT_ITEM_TYPE)
- .put(Note.NOTE,
- "Now's the time for all folk to come to the aid of their country.");
- elem.addExpected(Photo.CONTENT_ITEM_TYPE)
- // No information about its image format can be inserted.
- .put(Photo.PHOTO, sPhotoByteArrayForComplicatedCase);
- elem.addExpected(Event.CONTENT_ITEM_TYPE)
- .put(Event.START_DATE, "19800101")
- .put(Event.TYPE, Event.TYPE_BIRTHDAY);
- elem.addExpected(Website.CONTENT_ITEM_TYPE)
- .put(Website.URL, "http://www.example.com/")
- .put(Website.TYPE, Website.TYPE_HOMEPAGE);
- }
-
- public void testV30Simple_Parsing() {
- mVerifier.initForImportTest(V30, R.raw.v30_simple);
- mVerifier.addPropertyNodesVerifierElem()
- .addExpectedNodeWithOrder("VERSION", "3.0")
- .addExpectedNodeWithOrder("FN", "And Roid")
- .addExpectedNodeWithOrder("N", "And;Roid;;;", Arrays.asList("And", "Roid", "", "", ""))
- .addExpectedNodeWithOrder("ORG", "Open;Handset; Alliance",
- Arrays.asList("Open", "Handset", " Alliance"))
- .addExpectedNodeWithOrder("SORT-STRING", "android")
- .addExpectedNodeWithOrder("TEL", "0300000000", new TypeSet("PREF", "VOICE"))
- .addExpectedNodeWithOrder("CLASS", "PUBLIC")
- .addExpectedNodeWithOrder("X-GNO", "0")
- .addExpectedNodeWithOrder("X-GN", "group0")
- .addExpectedNodeWithOrder("X-REDUCTION", "0")
- .addExpectedNodeWithOrder("REV", "20081031T065854Z");
- }
-
- public void testV30Simple() {
- mVerifier.initForImportTest(V30, R.raw.v30_simple);
- ContentValuesVerifierElem elem = mVerifier.addContentValuesVerifierElem();
- elem.addExpected(StructuredName.CONTENT_ITEM_TYPE)
- .put(StructuredName.FAMILY_NAME, "And")
- .put(StructuredName.GIVEN_NAME, "Roid")
- .put(StructuredName.DISPLAY_NAME, "And Roid")
- .put(StructuredName.PHONETIC_GIVEN_NAME, "android");
- elem.addExpected(Organization.CONTENT_ITEM_TYPE)
- .put(Organization.COMPANY, "Open")
- .put(Organization.DEPARTMENT, "Handset Alliance")
- .put(Organization.TYPE, Organization.TYPE_WORK);
- elem.addExpected(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.TYPE, Phone.TYPE_CUSTOM)
- .put(Phone.LABEL, "VOICE")
- .put(Phone.NUMBER, "030-000-0000")
- .put(Phone.IS_PRIMARY, 1);
- }
-
- public void testV21Japanese1_Parsing() {
- // Though Japanese careers append ";;;;" at the end of the value of "SOUND",
- // vCard 2.1/3.0 specification does not allow multiple values.
- // Do not need to handle it as multiple values.
- mVerifier.initForImportTest(VCardConfig.VCARD_TYPE_V21_JAPANESE_SJIS,
- R.raw.v21_japanese_1);
- mVerifier.addPropertyNodesVerifierElem()
- .addExpectedNodeWithOrder("VERSION", "2.1", null, null, null, null, null)
- .addExpectedNodeWithOrder("N", "\u5B89\u85E4\u30ED\u30A4\u30C9;;;;",
- Arrays.asList("\u5B89\u85E4\u30ED\u30A4\u30C9", "", "", "", ""),
- null, mContentValuesForSJis, null, null)
- .addExpectedNodeWithOrder("SOUND",
- "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E;;;;",
- null, null, mContentValuesForSJis,
- new TypeSet("X-IRMC-N"), null)
- .addExpectedNodeWithOrder("TEL", "0300000000", null, null, null,
- new TypeSet("VOICE", "PREF"), null);
- }
-
- private void testV21Japanese1Common(int resId, int vcardType, boolean japanese) {
- mVerifier.initForImportTest(vcardType, resId);
- ContentValuesVerifierElem elem = mVerifier.addContentValuesVerifierElem();
- elem.addExpected(StructuredName.CONTENT_ITEM_TYPE)
- .put(StructuredName.FAMILY_NAME, "\u5B89\u85E4\u30ED\u30A4\u30C9")
- .put(StructuredName.DISPLAY_NAME, "\u5B89\u85E4\u30ED\u30A4\u30C9")
- // While vCard parser does not split "SOUND" property values,
- // ContactStruct care it.
- .put(StructuredName.PHONETIC_GIVEN_NAME,
- "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E");
- elem.addExpected(Phone.CONTENT_ITEM_TYPE)
- // Phone number formatting is different.
- .put(Phone.NUMBER, (japanese ? "03-0000-0000" : "030-000-0000"))
- .put(Phone.TYPE, Phone.TYPE_CUSTOM)
- .put(Phone.LABEL, "VOICE")
- .put(Phone.IS_PRIMARY, 1);
- }
-
- /**
- * Verifies vCard with Japanese can be parsed correctly with
- * {@link android.pim.vcard.VCardConfig#VCARD_TYPE_V21_GENERIC_UTF8}.
- */
- public void testV21Japanese1_Type_Generic_Utf8() {
- testV21Japanese1Common(
- R.raw.v21_japanese_1, VCardConfig.VCARD_TYPE_V21_GENERIC_UTF8, false);
- }
-
- /**
- * Verifies vCard with Japanese can be parsed correctly with
- * {@link android.pim.vcard.VCardConfig#VCARD_TYPE_V21_JAPANESE_SJIS}.
- */
- public void testV21Japanese1_Type_Japanese_Sjis() {
- testV21Japanese1Common(
- R.raw.v21_japanese_1, VCardConfig.VCARD_TYPE_V21_JAPANESE_SJIS, true);
- }
-
- /**
- * Verifies vCard with Japanese can be parsed correctly with
- * {@link android.pim.vcard.VCardConfig#VCARD_TYPE_V21_JAPANESE_UTF8}.
- * since vCard 2.1 specifies the charset of each line if it contains non-Ascii.
- */
- public void testV21Japanese1_Type_Japanese_Utf8() {
- testV21Japanese1Common(
- R.raw.v21_japanese_1, VCardConfig.VCARD_TYPE_V21_JAPANESE_UTF8, true);
- }
-
- public void testV21Japanese2_Parsing() {
- mVerifier.initForImportTest(VCardConfig.VCARD_TYPE_V21_JAPANESE_SJIS,
- R.raw.v21_japanese_2);
- mVerifier.addPropertyNodesVerifierElem()
- .addExpectedNodeWithOrder("VERSION", "2.1")
- .addExpectedNodeWithOrder("N", "\u5B89\u85E4;\u30ED\u30A4\u30C9\u0031;;;",
- Arrays.asList("\u5B89\u85E4", "\u30ED\u30A4\u30C9\u0031",
- "", "", ""),
- null, mContentValuesForSJis, null, null)
- .addExpectedNodeWithOrder("FN", "\u5B89\u85E4\u0020\u30ED\u30A4\u30C9\u0020\u0031",
- null, null, mContentValuesForSJis, null, null)
- .addExpectedNodeWithOrder("SOUND",
- "\uFF71\uFF9D\uFF84\uFF9E\uFF73;\uFF9B\uFF72\uFF84\uFF9E\u0031;;;",
- null, null, mContentValuesForSJis,
- new TypeSet("X-IRMC-N"), null)
- .addExpectedNodeWithOrder("ADR",
- ";\u6771\u4EAC\u90FD\u6E0B\u8C37\u533A\u685C" +
- "\u4E18\u753A\u0032\u0036\u002D\u0031\u30BB" +
- "\u30EB\u30EA\u30A2\u30F3\u30BF\u30EF\u30FC\u0036" +
- "\u968E;;;;150-8512;",
- Arrays.asList("",
- "\u6771\u4EAC\u90FD\u6E0B\u8C37\u533A\u685C" +
- "\u4E18\u753A\u0032\u0036\u002D\u0031\u30BB" +
- "\u30EB\u30EA\u30A2\u30F3\u30BF\u30EF\u30FC" +
- "\u0036\u968E", "", "", "", "150-8512", ""),
- null, mContentValuesForQPAndSJis, new TypeSet("HOME"), null)
- .addExpectedNodeWithOrder("NOTE", "\u30E1\u30E2", null, null,
- mContentValuesForQPAndSJis, null, null);
- }
-
- public void testV21Japanese2_Type_Generic_Utf8() {
- mVerifier.initForImportTest(V21, R.raw.v21_japanese_2);
- ContentValuesVerifierElem elem = mVerifier.addContentValuesVerifierElem();
- elem.addExpected(StructuredName.CONTENT_ITEM_TYPE)
- .put(StructuredName.FAMILY_NAME, "\u5B89\u85E4")
- .put(StructuredName.GIVEN_NAME, "\u30ED\u30A4\u30C9\u0031")
- .put(StructuredName.DISPLAY_NAME,
- "\u5B89\u85E4\u0020\u30ED\u30A4\u30C9\u0020\u0031")
- // ContactStruct should correctly split "SOUND" property into several elements,
- // even though VCardParser side does not care it.
- .put(StructuredName.PHONETIC_FAMILY_NAME, "\uFF71\uFF9D\uFF84\uFF9E\uFF73")
- .put(StructuredName.PHONETIC_GIVEN_NAME, "\uFF9B\uFF72\uFF84\uFF9E\u0031");
- elem.addExpected(StructuredPostal.CONTENT_ITEM_TYPE)
- .put(StructuredPostal.POSTCODE, "150-8512")
- .put(StructuredPostal.STREET,
- "\u6771\u4EAC\u90FD\u6E0B\u8C37\u533A\u685C" +
- "\u4E18\u753A\u0032\u0036\u002D\u0031\u30BB" +
- "\u30EB\u30EA\u30A2\u30F3\u30BF\u30EF\u30FC" +
- "\u0036\u968E")
- .put(StructuredPostal.FORMATTED_ADDRESS,
- "\u6771\u4EAC\u90FD\u6E0B\u8C37\u533A\u685C" +
- "\u4E18\u753A\u0032\u0036\u002D\u0031\u30BB" +
- "\u30EB\u30EA\u30A2\u30F3\u30BF\u30EF\u30FC" +
- "\u0036\u968E 150-8512")
- .put(StructuredPostal.TYPE, StructuredPostal.TYPE_HOME);
- elem.addExpected(Note.CONTENT_ITEM_TYPE)
- .put(Note.NOTE, "\u30E1\u30E2");
- }
-
- public void testV21MultipleEntryCase_Parse() {
- mVerifier.initForImportTest(VCardConfig.VCARD_TYPE_V21_JAPANESE_SJIS,
- R.raw.v21_multiple_entry);
- mVerifier.addPropertyNodesVerifierElem()
- .addExpectedNodeWithOrder("VERSION", "2.1")
- .addExpectedNodeWithOrder("N", "\u5B89\u85E4\u30ED\u30A4\u30C9\u0033;;;;",
- Arrays.asList("\u5B89\u85E4\u30ED\u30A4\u30C9\u0033", "", "", "", ""),
- null, mContentValuesForSJis, null, null)
- .addExpectedNodeWithOrder("SOUND",
- "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E\u0033;;;;",
- null, null, mContentValuesForSJis,
- new TypeSet("X-IRMC-N"), null)
- .addExpectedNodeWithOrder("TEL", "9", new TypeSet("X-NEC-SECRET"))
- .addExpectedNodeWithOrder("TEL", "10", new TypeSet("X-NEC-HOTEL"))
- .addExpectedNodeWithOrder("TEL", "11", new TypeSet("X-NEC-SCHOOL"))
- .addExpectedNodeWithOrder("TEL", "12", new TypeSet("FAX", "HOME"));
- mVerifier.addPropertyNodesVerifierElem()
- .addExpectedNodeWithOrder("VERSION", "2.1")
- .addExpectedNodeWithOrder("N", "\u5B89\u85E4\u30ED\u30A4\u30C9\u0034;;;;",
- Arrays.asList("\u5B89\u85E4\u30ED\u30A4\u30C9\u0034", "", "", "", ""),
- null, mContentValuesForSJis, null, null)
- .addExpectedNodeWithOrder("SOUND",
- "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E\u0034;;;;",
- null, null, mContentValuesForSJis,
- new TypeSet("X-IRMC-N"), null)
- .addExpectedNodeWithOrder("TEL", "13", new TypeSet("MODEM"))
- .addExpectedNodeWithOrder("TEL", "14", new TypeSet("PAGER"))
- .addExpectedNodeWithOrder("TEL", "15", new TypeSet("X-NEC-FAMILY"))
- .addExpectedNodeWithOrder("TEL", "16", new TypeSet("X-NEC-GIRL"));
- mVerifier.addPropertyNodesVerifierElem()
- .addExpectedNodeWithOrder("VERSION", "2.1")
- .addExpectedNodeWithOrder("N", "\u5B89\u85E4\u30ED\u30A4\u30C9\u0035;;;;",
- Arrays.asList("\u5B89\u85E4\u30ED\u30A4\u30C9\u0035", "", "", "", ""),
- null, mContentValuesForSJis, null, null)
- .addExpectedNodeWithOrder("SOUND",
- "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E\u0035;;;;",
- null, null, mContentValuesForSJis,
- new TypeSet("X-IRMC-N"), null)
- .addExpectedNodeWithOrder("TEL", "17", new TypeSet("X-NEC-BOY"))
- .addExpectedNodeWithOrder("TEL", "18", new TypeSet("X-NEC-FRIEND"))
- .addExpectedNodeWithOrder("TEL", "19", new TypeSet("X-NEC-PHS"))
- .addExpectedNodeWithOrder("TEL", "20", new TypeSet("X-NEC-RESTAURANT"));
- }
-
- public void testV21MultipleEntryCase() {
- mVerifier.initForImportTest(VCardConfig.VCARD_TYPE_V21_JAPANESE_SJIS,
- R.raw.v21_multiple_entry);
- ContentValuesVerifierElem elem = mVerifier.addContentValuesVerifierElem();
- elem.addExpected(StructuredName.CONTENT_ITEM_TYPE)
- .put(StructuredName.FAMILY_NAME, "\u5B89\u85E4\u30ED\u30A4\u30C9\u0033")
- .put(StructuredName.DISPLAY_NAME, "\u5B89\u85E4\u30ED\u30A4\u30C9\u0033")
- .put(StructuredName.PHONETIC_GIVEN_NAME,
- "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E\u0033");
- elem.addExpected(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.TYPE, Phone.TYPE_CUSTOM)
- .put(Phone.LABEL, "NEC-SECRET")
- .put(Phone.NUMBER, "9");
- elem.addExpected(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.TYPE, Phone.TYPE_CUSTOM)
- .put(Phone.LABEL, "NEC-HOTEL")
- .put(Phone.NUMBER, "10");
- elem.addExpected(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.TYPE, Phone.TYPE_CUSTOM)
- .put(Phone.LABEL, "NEC-SCHOOL")
- .put(Phone.NUMBER, "11");
- elem.addExpected(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.TYPE, Phone.TYPE_FAX_HOME)
- .put(Phone.NUMBER, "12");
-
- elem = mVerifier.addContentValuesVerifierElem();
- elem.addExpected(StructuredName.CONTENT_ITEM_TYPE)
- .put(StructuredName.FAMILY_NAME, "\u5B89\u85E4\u30ED\u30A4\u30C9\u0034")
- .put(StructuredName.DISPLAY_NAME, "\u5B89\u85E4\u30ED\u30A4\u30C9\u0034")
- .put(StructuredName.PHONETIC_GIVEN_NAME,
- "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E\u0034");
- elem.addExpected(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.TYPE, Phone.TYPE_CUSTOM)
- .put(Phone.LABEL, "MODEM")
- .put(Phone.NUMBER, "13");
- elem.addExpected(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.TYPE, Phone.TYPE_PAGER)
- .put(Phone.NUMBER, "14");
- elem.addExpected(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.TYPE, Phone.TYPE_CUSTOM)
- .put(Phone.LABEL, "NEC-FAMILY")
- .put(Phone.NUMBER, "15");
- elem.addExpected(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.TYPE, Phone.TYPE_CUSTOM)
- .put(Phone.LABEL, "NEC-GIRL")
- .put(Phone.NUMBER, "16");
-
- elem = mVerifier.addContentValuesVerifierElem();
- elem.addExpected(StructuredName.CONTENT_ITEM_TYPE)
- .put(StructuredName.FAMILY_NAME, "\u5B89\u85E4\u30ED\u30A4\u30C9\u0035")
- .put(StructuredName.DISPLAY_NAME, "\u5B89\u85E4\u30ED\u30A4\u30C9\u0035")
- .put(StructuredName.PHONETIC_GIVEN_NAME,
- "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E\u0035");
- elem.addExpected(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.TYPE, Phone.TYPE_CUSTOM)
- .put(Phone.LABEL, "NEC-BOY")
- .put(Phone.NUMBER, "17");
- elem.addExpected(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.TYPE, Phone.TYPE_CUSTOM)
- .put(Phone.LABEL, "NEC-FRIEND")
- .put(Phone.NUMBER, "18");
- elem.addExpected(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.TYPE, Phone.TYPE_CUSTOM)
- .put(Phone.LABEL, "NEC-PHS")
- .put(Phone.NUMBER, "19");
- elem.addExpected(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.TYPE, Phone.TYPE_CUSTOM)
- .put(Phone.LABEL, "NEC-RESTAURANT")
- .put(Phone.NUMBER, "20");
- }
-
- public void testIgnoreAgentV21_Parse() {
- mVerifier.initForImportTest(V21, R.raw.v21_winmo_65);
- ContentValues contentValuesForValue = new ContentValues();
- contentValuesForValue.put("VALUE", "DATE");
- mVerifier.addPropertyNodesVerifierElem()
- .addExpectedNodeWithOrder("VERSION", "2.1")
- .addExpectedNodeWithOrder("N", Arrays.asList("Example", "", "", "", ""))
- .addExpectedNodeWithOrder("FN", "Example")
- .addExpectedNodeWithOrder("ANNIVERSARY", "20091010", contentValuesForValue)
- .addExpectedNodeWithOrder("AGENT", "")
- .addExpectedNodeWithOrder("X-CLASS", "PUBLIC")
- .addExpectedNodeWithOrder("X-REDUCTION", "")
- .addExpectedNodeWithOrder("X-NO", "");
- }
-
- public void testIgnoreAgentV21() {
- mVerifier.initForImportTest(V21, R.raw.v21_winmo_65);
- ContentValuesVerifier verifier = new ContentValuesVerifier();
- ContentValuesVerifierElem elem = mVerifier.addContentValuesVerifierElem();
- elem.addExpected(StructuredName.CONTENT_ITEM_TYPE)
- .put(StructuredName.FAMILY_NAME, "Example")
- .put(StructuredName.DISPLAY_NAME, "Example");
- }
-
- public void testTolerateInvalidCommentLikeLineV21() {
- mVerifier.initForImportTest(V21, R.raw.v21_invalid_comment_line);
- ContentValuesVerifierElem elem = mVerifier.addContentValuesVerifierElem();
- elem.addExpected(StructuredName.CONTENT_ITEM_TYPE)
- .put(StructuredName.GIVEN_NAME, "Conference Call")
- .put(StructuredName.DISPLAY_NAME, "Conference Call");
- elem.addExpected(Note.CONTENT_ITEM_TYPE)
- .put(Note.NOTE, "This is an (sharp ->#<- sharp) example. "
- + "This message must NOT be ignored.");
- }
-
- public void testPagerV30_Parse() {
- mVerifier.initForImportTest(V30, R.raw.v30_comma_separated);
- mVerifier.addPropertyNodesVerifierElem()
- .addExpectedNodeWithOrder("VERSION", "3.0")
- .addExpectedNodeWithOrder("N", Arrays.asList("F", "G", "M", "", ""))
- .addExpectedNodeWithOrder("TEL", "6101231234@pagersample.com",
- new TypeSet("WORK", "MSG", "PAGER"));
- }
-
- public void testPagerV30() {
- mVerifier.initForImportTest(V30, R.raw.v30_comma_separated);
- ContentValuesVerifierElem elem = mVerifier.addContentValuesVerifierElem();
- elem.addExpected(StructuredName.CONTENT_ITEM_TYPE)
- .put(StructuredName.FAMILY_NAME, "F")
- .put(StructuredName.MIDDLE_NAME, "M")
- .put(StructuredName.GIVEN_NAME, "G")
- .put(StructuredName.DISPLAY_NAME, "G M F");
- elem.addExpected(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.TYPE, Phone.TYPE_PAGER)
- .put(Phone.NUMBER, "6101231234@pagersample.com");
- }
-}
diff --git a/core/tests/coretests/src/android/pim/vcard/VCardJapanizationTests.java b/core/tests/coretests/src/android/pim/vcard/VCardJapanizationTests.java
deleted file mode 100644
index 5b60342..0000000
--- a/core/tests/coretests/src/android/pim/vcard/VCardJapanizationTests.java
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.pim.vcard;
-
-import android.content.ContentValues;
-import android.pim.vcard.VCardConfig;
-import android.provider.ContactsContract.CommonDataKinds.Nickname;
-import android.provider.ContactsContract.CommonDataKinds.Note;
-import android.provider.ContactsContract.CommonDataKinds.Phone;
-import android.provider.ContactsContract.CommonDataKinds.StructuredName;
-import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
-
-import android.pim.vcard.PropertyNodesVerifierElem.TypeSet;
-
-import java.util.Arrays;
-
-public class VCardJapanizationTests extends VCardTestsBase {
- private void testNameUtf8Common(int vcardType) {
- mVerifier.initForExportTest(vcardType);
- ContactEntry entry = mVerifier.addInputEntry();
- entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
- .put(StructuredName.FAMILY_NAME, "\u3075\u308B\u3069")
- .put(StructuredName.GIVEN_NAME, "\u3091\u308A\u304B")
- .put(StructuredName.MIDDLE_NAME, "B")
- .put(StructuredName.PREFIX, "Dr.")
- .put(StructuredName.SUFFIX, "Ph.D");
- ContentValues contentValues =
- (VCardConfig.isV30(vcardType) ? null : mContentValuesForQPAndUtf8);
- mVerifier.addPropertyNodesVerifierElem()
- .addExpectedNode("FN", "Dr. \u3075\u308B\u3069 B \u3091\u308A\u304B Ph.D",
- contentValues)
- .addExpectedNode("N", "\u3075\u308B\u3069;\u3091\u308A\u304B;B;Dr.;Ph.D",
- Arrays.asList(
- "\u3075\u308B\u3069", "\u3091\u308A\u304B", "B", "Dr.", "Ph.D"),
- null, contentValues, null, null);
- }
-
- public void testNameUtf8V21() {
- testNameUtf8Common(VCardConfig.VCARD_TYPE_V21_JAPANESE_UTF8);
- }
-
- public void testNameUtf8V30() {
- testNameUtf8Common(VCardConfig.VCARD_TYPE_V30_JAPANESE_UTF8);
- }
-
- public void testNameShiftJis() {
- mVerifier.initForExportTest(VCardConfig.VCARD_TYPE_V30_JAPANESE_SJIS);
- ContactEntry entry = mVerifier.addInputEntry();
- entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
- .put(StructuredName.FAMILY_NAME, "\u3075\u308B\u3069")
- .put(StructuredName.GIVEN_NAME, "\u3091\u308A\u304B")
- .put(StructuredName.MIDDLE_NAME, "B")
- .put(StructuredName.PREFIX, "Dr.")
- .put(StructuredName.SUFFIX, "Ph.D");
-
- mVerifier.addPropertyNodesVerifierElem()
- .addExpectedNode("FN", "Dr. \u3075\u308B\u3069 B \u3091\u308A\u304B Ph.D",
- mContentValuesForSJis)
- .addExpectedNode("N", "\u3075\u308B\u3069;\u3091\u308A\u304B;B;Dr.;Ph.D",
- Arrays.asList(
- "\u3075\u308B\u3069", "\u3091\u308A\u304B", "B", "Dr.", "Ph.D"),
- null, mContentValuesForSJis, null, null);
- }
-
- /**
- * DoCoMo phones require all name elements should be in "family name" field.
- */
- public void testNameDoCoMo() {
- mVerifier.initForExportTest(VCardConfig.VCARD_TYPE_DOCOMO);
- ContactEntry entry = mVerifier.addInputEntry();
- entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
- .put(StructuredName.FAMILY_NAME, "\u3075\u308B\u3069")
- .put(StructuredName.GIVEN_NAME, "\u3091\u308A\u304B")
- .put(StructuredName.MIDDLE_NAME, "B")
- .put(StructuredName.PREFIX, "Dr.")
- .put(StructuredName.SUFFIX, "Ph.D");
-
- final String fullName = "Dr. \u3075\u308B\u3069 B \u3091\u308A\u304B Ph.D";
- mVerifier.addPropertyNodesVerifierElem()
- .addExpectedNode("N", fullName + ";;;;",
- Arrays.asList(fullName, "", "", "", ""),
- null, mContentValuesForSJis, null, null)
- .addExpectedNode("FN", fullName, mContentValuesForSJis)
- .addExpectedNode("SOUND", ";;;;", new TypeSet("X-IRMC-N"))
- .addExpectedNode("TEL", "", new TypeSet("HOME"))
- .addExpectedNode("EMAIL", "", new TypeSet("HOME"))
- .addExpectedNode("ADR", "", new TypeSet("HOME"))
- .addExpectedNode("X-CLASS", "PUBLIC")
- .addExpectedNode("X-REDUCTION", "")
- .addExpectedNode("X-NO", "")
- .addExpectedNode("X-DCM-HMN-MODE", "");
- }
-
- private void testPhoneticNameCommon(int vcardType) {
- mVerifier.initForExportTest(vcardType);
- ContactEntry entry = mVerifier.addInputEntry();
- entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
- .put(StructuredName.PHONETIC_FAMILY_NAME, "\u3084\u307E\u3060")
- .put(StructuredName.PHONETIC_MIDDLE_NAME, "\u30DF\u30C9\u30EB\u30CD\u30FC\u30E0")
- .put(StructuredName.PHONETIC_GIVEN_NAME, "\u305F\u308D\u3046");
-
- final ContentValues contentValues =
- (VCardConfig.usesShiftJis(vcardType) ?
- (VCardConfig.isV30(vcardType) ? mContentValuesForSJis :
- mContentValuesForQPAndSJis) :
- (VCardConfig.isV30(vcardType) ? null : mContentValuesForQPAndUtf8));
- PropertyNodesVerifierElem elem = mVerifier.addPropertyNodesVerifierElemWithEmptyName();
- elem.addExpectedNode("X-PHONETIC-LAST-NAME", "\u3084\u307E\u3060",
- contentValues)
- .addExpectedNode("X-PHONETIC-MIDDLE-NAME",
- "\u30DF\u30C9\u30EB\u30CD\u30FC\u30E0",
- contentValues)
- .addExpectedNode("X-PHONETIC-FIRST-NAME", "\u305F\u308D\u3046",
- contentValues);
- if (VCardConfig.isV30(vcardType)) {
- elem.addExpectedNode("SORT-STRING",
- "\u3084\u307E\u3060 \u30DF\u30C9\u30EB\u30CD\u30FC\u30E0 \u305F\u308D\u3046",
- contentValues);
- }
- ContentValuesBuilder builder = mVerifier.addContentValuesVerifierElem()
- .addExpected(StructuredName.CONTENT_ITEM_TYPE);
- builder.put(StructuredName.PHONETIC_FAMILY_NAME, "\u3084\u307E\u3060")
- .put(StructuredName.PHONETIC_MIDDLE_NAME, "\u30DF\u30C9\u30EB\u30CD\u30FC\u30E0")
- .put(StructuredName.PHONETIC_GIVEN_NAME, "\u305F\u308D\u3046")
- .put(StructuredName.DISPLAY_NAME,
- "\u3084\u307E\u3060 \u30DF\u30C9\u30EB\u30CD\u30FC\u30E0 " +
- "\u305F\u308D\u3046");
- }
-
- public void testPhoneticNameForJapaneseV21Utf8() {
- testPhoneticNameCommon(VCardConfig.VCARD_TYPE_V21_JAPANESE_UTF8);
- }
-
- public void testPhoneticNameForJapaneseV21Sjis() {
- testPhoneticNameCommon(VCardConfig.VCARD_TYPE_V21_JAPANESE_SJIS);
- }
-
- public void testPhoneticNameForJapaneseV30Utf8() {
- testPhoneticNameCommon(VCardConfig.VCARD_TYPE_V30_JAPANESE_UTF8);
- }
-
- public void testPhoneticNameForJapaneseV30SJis() {
- testPhoneticNameCommon(VCardConfig.VCARD_TYPE_V30_JAPANESE_SJIS);
- }
-
- public void testPhoneticNameForMobileV21_1() {
- mVerifier.initForExportTest(VCardConfig.VCARD_TYPE_V21_JAPANESE_MOBILE);
- ContactEntry entry = mVerifier.addInputEntry();
- entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
- .put(StructuredName.PHONETIC_FAMILY_NAME, "\u3084\u307E\u3060")
- .put(StructuredName.PHONETIC_MIDDLE_NAME, "\u30DF\u30C9\u30EB\u30CD\u30FC\u30E0")
- .put(StructuredName.PHONETIC_GIVEN_NAME, "\u305F\u308D\u3046");
-
- mVerifier.addPropertyNodesVerifierElem()
- .addExpectedNode("SOUND",
- "\uFF94\uFF8F\uFF80\uFF9E \uFF90\uFF84\uFF9E\uFF99\uFF88\uFF70\uFF91 " +
- "\uFF80\uFF9B\uFF73;;;;",
- mContentValuesForSJis, new TypeSet("X-IRMC-N"));
- ContentValuesBuilder builder = mVerifier.addContentValuesVerifierElem()
- .addExpected(StructuredName.CONTENT_ITEM_TYPE);
- builder.put(StructuredName.PHONETIC_FAMILY_NAME, "\uFF94\uFF8F\uFF80\uFF9E")
- .put(StructuredName.PHONETIC_MIDDLE_NAME,
- "\uFF90\uFF84\uFF9E\uFF99\uFF88\uFF70\uFF91")
- .put(StructuredName.PHONETIC_GIVEN_NAME, "\uFF80\uFF9B\uFF73")
- .put(StructuredName.DISPLAY_NAME,
- "\uFF94\uFF8F\uFF80\uFF9E \uFF90\uFF84\uFF9E\uFF99\uFF88\uFF70\uFF91 " +
- "\uFF80\uFF9B\uFF73");
- }
-
- public void testPhoneticNameForMobileV21_2() {
- mVerifier.initForExportTest(VCardConfig.VCARD_TYPE_V21_JAPANESE_MOBILE);
- ContactEntry entry = mVerifier.addInputEntry();
- entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
- .put(StructuredName.PHONETIC_FAMILY_NAME, "\u3084\u307E\u3060")
- .put(StructuredName.PHONETIC_GIVEN_NAME, "\u305F\u308D\u3046");
-
- mVerifier.addPropertyNodesVerifierElem()
- .addExpectedNode("SOUND", "\uFF94\uFF8F\uFF80\uFF9E \uFF80\uFF9B\uFF73;;;;",
- mContentValuesForSJis, new TypeSet("X-IRMC-N"));
- ContentValuesBuilder builder = mVerifier.addContentValuesVerifierElem()
- .addExpected(StructuredName.CONTENT_ITEM_TYPE);
- builder.put(StructuredName.PHONETIC_FAMILY_NAME, "\uFF94\uFF8F\uFF80\uFF9E")
- .put(StructuredName.PHONETIC_GIVEN_NAME, "\uFF80\uFF9B\uFF73")
- .put(StructuredName.DISPLAY_NAME, "\uFF94\uFF8F\uFF80\uFF9E \uFF80\uFF9B\uFF73");
- }
-
- private void testPostalAddressWithJapaneseCommon(int vcardType) {
- mVerifier.initForExportTest(vcardType);
- ContactEntry entry = mVerifier.addInputEntry();
- entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
- .put(StructuredPostal.POBOX, "\u79C1\u66F8\u7BB107")
- .put(StructuredPostal.STREET, "\u96DB\u898B\u6CA2\u6751")
- .put(StructuredPostal.CITY, "\u9E7F\u9AA8\u5E02")
- .put(StructuredPostal.REGION, "\u00D7\u00D7\u770C")
- .put(StructuredPostal.POSTCODE, "494-1313")
- .put(StructuredPostal.COUNTRY, "\u65E5\u672C")
- .put(StructuredPostal.FORMATTED_ADDRESS,
- "\u3053\u3093\u306A\u3068\u3053\u308D\u3092\u898B"
- + "\u308B\u306A\u3093\u3066\u6687\u4EBA\u3067\u3059\u304B\uFF1F")
- .put(StructuredPostal.TYPE, StructuredPostal.TYPE_CUSTOM)
- .put(StructuredPostal.LABEL, "\u304A\u3082\u3061\u304B\u3048\u308A");
-
- ContentValues contentValues = (VCardConfig.usesShiftJis(vcardType) ?
- (VCardConfig.isV30(vcardType) ? mContentValuesForSJis :
- mContentValuesForQPAndSJis) :
- (VCardConfig.isV30(vcardType) ? mContentValuesForUtf8 :
- mContentValuesForQPAndUtf8));
-
- PropertyNodesVerifierElem elem = mVerifier.addPropertyNodesVerifierElemWithEmptyName();
- // LABEL must be ignored in vCard 2.1. As for vCard 3.0, the current behavior is
- // same as that in vCard 3.0, which can be changed in the future.
- elem.addExpectedNode("ADR", Arrays.asList("\u79C1\u66F8\u7BB107",
- "", "\u96DB\u898B\u6CA2\u6751", "\u9E7F\u9AA8\u5E02", "\u00D7\u00D7\u770C",
- "494-1313", "\u65E5\u672C"),
- contentValues);
- mVerifier.addContentValuesVerifierElem().addExpected(StructuredPostal.CONTENT_ITEM_TYPE)
- .put(StructuredPostal.POBOX, "\u79C1\u66F8\u7BB107")
- .put(StructuredPostal.STREET, "\u96DB\u898B\u6CA2\u6751")
- .put(StructuredPostal.CITY, "\u9E7F\u9AA8\u5E02")
- .put(StructuredPostal.REGION, "\u00D7\u00D7\u770C")
- .put(StructuredPostal.POSTCODE, "494-1313")
- .put(StructuredPostal.COUNTRY, "\u65E5\u672C")
- .put(StructuredPostal.FORMATTED_ADDRESS,
- "\u65E5\u672C 494-1313 \u00D7\u00D7\u770C \u9E7F\u9AA8\u5E02 " +
- "\u96DB\u898B\u6CA2\u6751 " + "\u79C1\u66F8\u7BB107")
- .put(StructuredPostal.TYPE, StructuredPostal.TYPE_HOME);
- }
- public void testPostalAddresswithJapaneseV21() {
- testPostalAddressWithJapaneseCommon(VCardConfig.VCARD_TYPE_V21_JAPANESE_SJIS);
- }
-
- /**
- * Verifies that only one address field is emitted toward DoCoMo phones.
- * Prefered type must (should?) be: HOME > WORK > OTHER > CUSTOM
- */
- public void testPostalAdrressForDoCoMo_1() {
- mVerifier.initForExportTest(VCardConfig.VCARD_TYPE_DOCOMO);
- ContactEntry entry = mVerifier.addInputEntry();
- entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
- .put(StructuredPostal.TYPE, StructuredPostal.TYPE_WORK)
- .put(StructuredPostal.POBOX, "1");
- entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
- .put(StructuredPostal.TYPE, StructuredPostal.TYPE_OTHER)
- .put(StructuredPostal.POBOX, "2");
- entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
- .put(StructuredPostal.TYPE, StructuredPostal.TYPE_HOME)
- .put(StructuredPostal.POBOX, "3");
- entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
- .put(StructuredPostal.TYPE, StructuredPostal.TYPE_CUSTOM)
- .put(StructuredPostal.LABEL, "custom")
- .put(StructuredPostal.POBOX, "4");
-
- mVerifier.addPropertyNodesVerifierElemWithEmptyName()
- .addExpectedNode("TEL", "", new TypeSet("HOME"))
- .addExpectedNode("EMAIL", "", new TypeSet("HOME"))
- .addExpectedNode("X-CLASS", "PUBLIC")
- .addExpectedNode("X-REDUCTION", "")
- .addExpectedNode("X-NO", "")
- .addExpectedNode("X-DCM-HMN-MODE", "")
- .addExpectedNode("ADR",
- Arrays.asList("3", "", "", "", "", "", ""), new TypeSet("HOME"));
- }
-
- public void testPostalAdrressForDoCoMo_2() {
- mVerifier.initForExportTest(VCardConfig.VCARD_TYPE_DOCOMO);
- ContactEntry entry = mVerifier.addInputEntry();
- entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
- .put(StructuredPostal.TYPE, StructuredPostal.TYPE_OTHER)
- .put(StructuredPostal.POBOX, "1");
- entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
- .put(StructuredPostal.TYPE, StructuredPostal.TYPE_WORK)
- .put(StructuredPostal.POBOX, "2");
- entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
- .put(StructuredPostal.TYPE, StructuredPostal.TYPE_CUSTOM)
- .put(StructuredPostal.LABEL, "custom")
- .put(StructuredPostal.POBOX, "3");
-
- mVerifier.addPropertyNodesVerifierElemWithEmptyName()
- .addExpectedNode("TEL", "", new TypeSet("HOME"))
- .addExpectedNode("EMAIL", "", new TypeSet("HOME"))
- .addExpectedNode("X-CLASS", "PUBLIC")
- .addExpectedNode("X-REDUCTION", "")
- .addExpectedNode("X-NO", "")
- .addExpectedNode("X-DCM-HMN-MODE", "")
- .addExpectedNode("ADR",
- Arrays.asList("2", "", "", "", "", "", ""), new TypeSet("WORK"));
- }
-
- public void testPostalAdrressForDoCoMo_3() {
- mVerifier.initForExportTest(VCardConfig.VCARD_TYPE_DOCOMO);
- ContactEntry entry = mVerifier.addInputEntry();
- entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
- .put(StructuredPostal.TYPE, StructuredPostal.TYPE_CUSTOM)
- .put(StructuredPostal.LABEL, "custom1")
- .put(StructuredPostal.POBOX, "1");
- entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
- .put(StructuredPostal.TYPE, StructuredPostal.TYPE_OTHER)
- .put(StructuredPostal.POBOX, "2");
- entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
- .put(StructuredPostal.TYPE, StructuredPostal.TYPE_CUSTOM)
- .put(StructuredPostal.LABEL, "custom2")
- .put(StructuredPostal.POBOX, "3");
-
- mVerifier.addPropertyNodesVerifierElemWithEmptyName()
- .addExpectedNode("TEL", "", new TypeSet("HOME"))
- .addExpectedNode("EMAIL", "", new TypeSet("HOME"))
- .addExpectedNode("X-CLASS", "PUBLIC")
- .addExpectedNode("X-REDUCTION", "")
- .addExpectedNode("X-NO", "")
- .addExpectedNode("X-DCM-HMN-MODE", "")
- .addExpectedNode("ADR", Arrays.asList("2", "", "", "", "", "", ""));
- }
-
- /**
- * Verifies the vCard exporter tolerates null TYPE.
- */
- public void testPostalAdrressForDoCoMo_4() {
- mVerifier.initForExportTest(VCardConfig.VCARD_TYPE_DOCOMO);
- ContactEntry entry = mVerifier.addInputEntry();
- entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
- .put(StructuredPostal.POBOX, "1");
- entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
- .put(StructuredPostal.TYPE, StructuredPostal.TYPE_OTHER)
- .put(StructuredPostal.POBOX, "2");
- entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
- .put(StructuredPostal.TYPE, StructuredPostal.TYPE_HOME)
- .put(StructuredPostal.POBOX, "3");
- entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
- .put(StructuredPostal.TYPE, StructuredPostal.TYPE_WORK)
- .put(StructuredPostal.POBOX, "4");
- entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
- .put(StructuredPostal.POBOX, "5");
-
- mVerifier.addPropertyNodesVerifierElemWithEmptyName()
- .addExpectedNode("TEL", "", new TypeSet("HOME"))
- .addExpectedNode("EMAIL", "", new TypeSet("HOME"))
- .addExpectedNode("X-CLASS", "PUBLIC")
- .addExpectedNode("X-REDUCTION", "")
- .addExpectedNode("X-NO", "")
- .addExpectedNode("X-DCM-HMN-MODE", "")
- .addExpectedNode("ADR",
- Arrays.asList("3", "", "", "", "", "", ""), new TypeSet("HOME"));
- }
-
- private void testJapanesePhoneNumberCommon(int vcardType) {
- mVerifier.initForExportTest(vcardType);
- ContactEntry entry = mVerifier.addInputEntry();
- entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.NUMBER, "0312341234")
- .put(Phone.TYPE, Phone.TYPE_HOME);
- entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.NUMBER, "09012341234")
- .put(Phone.TYPE, Phone.TYPE_MOBILE);
- mVerifier.addPropertyNodesVerifierElemWithEmptyName()
- .addExpectedNode("TEL", "03-1234-1234", new TypeSet("HOME"))
- .addExpectedNode("TEL", "090-1234-1234", new TypeSet("CELL"));
- }
-
- public void testJapanesePhoneNumberV21_1() {
- testJapanesePhoneNumberCommon(VCardConfig.VCARD_TYPE_V21_JAPANESE_UTF8);
- }
-
- public void testJapanesePhoneNumberV30() {
- testJapanesePhoneNumberCommon(VCardConfig.VCARD_TYPE_V30_JAPANESE_UTF8);
- }
-
- public void testJapanesePhoneNumberDoCoMo() {
- mVerifier.initForExportTest(VCardConfig.VCARD_TYPE_DOCOMO);
- ContactEntry entry = mVerifier.addInputEntry();
- entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.NUMBER, "0312341234")
- .put(Phone.TYPE, Phone.TYPE_HOME);
- entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
- .put(Phone.NUMBER, "09012341234")
- .put(Phone.TYPE, Phone.TYPE_MOBILE);
- mVerifier.addPropertyNodesVerifierElemWithEmptyName()
- .addExpectedNode("EMAIL", "", new TypeSet("HOME"))
- .addExpectedNode("X-CLASS", "PUBLIC")
- .addExpectedNode("X-REDUCTION", "")
- .addExpectedNode("X-NO", "")
- .addExpectedNode("X-DCM-HMN-MODE", "")
- .addExpectedNode("ADR", "", new TypeSet("HOME"))
- .addExpectedNode("TEL", "03-1234-1234", new TypeSet("HOME"))
- .addExpectedNode("TEL", "090-1234-1234", new TypeSet("CELL"));
- }
-
- public void testNoteDoCoMo() {
- mVerifier.initForExportTest(VCardConfig.VCARD_TYPE_DOCOMO);
- ContactEntry entry = mVerifier.addInputEntry();
- entry.addContentValues(Note.CONTENT_ITEM_TYPE)
- .put(Note.NOTE, "note1");
- entry.addContentValues(Note.CONTENT_ITEM_TYPE)
- .put(Note.NOTE, "note2");
- entry.addContentValues(Note.CONTENT_ITEM_TYPE)
- .put(Note.NOTE, "note3");
-
- // More than one note fields must be aggregated into one note.
- mVerifier.addPropertyNodesVerifierElemWithEmptyName()
- .addExpectedNode("TEL", "", new TypeSet("HOME"))
- .addExpectedNode("EMAIL", "", new TypeSet("HOME"))
- .addExpectedNode("X-CLASS", "PUBLIC")
- .addExpectedNode("X-REDUCTION", "")
- .addExpectedNode("X-NO", "")
- .addExpectedNode("X-DCM-HMN-MODE", "")
- .addExpectedNode("ADR", "", new TypeSet("HOME"))
- .addExpectedNode("NOTE", "note1\nnote2\nnote3", mContentValuesForQP);
- }
-
- public void testAndroidCustomV21() {
- mVerifier.initForExportTest(VCardConfig.VCARD_TYPE_V21_GENERIC_UTF8);
- mVerifier.addInputEntry().addContentValues(Nickname.CONTENT_ITEM_TYPE)
- .put(Nickname.NAME, "\u304D\u3083\u30FC\u30A8\u30C3\u30C1\u30FC");
- mVerifier.addPropertyNodesVerifierElemWithEmptyName()
- .addExpectedNode("X-ANDROID-CUSTOM",
- Arrays.asList(Nickname.CONTENT_ITEM_TYPE,
- "\u304D\u3083\u30FC\u30A8\u30C3\u30C1\u30FC",
- "", "", "", "", "", "", "", "", "", "", "", "", "", ""),
- mContentValuesForQPAndUtf8);
- }
-}
diff --git a/core/tests/coretests/src/android/pim/vcard/VCardTestsBase.java b/core/tests/coretests/src/android/pim/vcard/VCardTestsBase.java
deleted file mode 100644
index 0857e0c..0000000
--- a/core/tests/coretests/src/android/pim/vcard/VCardTestsBase.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.pim.vcard;
-
-import android.content.ContentProvider;
-import android.content.ContentProviderOperation;
-import android.content.ContentProviderResult;
-import android.content.ContentValues;
-import android.content.EntityIterator;
-import android.content.res.AssetFileDescriptor;
-import android.database.Cursor;
-import android.database.CursorWindow;
-import android.database.IBulkCursor;
-import android.database.IContentObserver;
-import android.net.Uri;
-import android.os.IBinder;
-import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
-import android.pim.vcard.VCardConfig;
-import android.test.AndroidTestCase;
-import android.util.Log;
-
-import java.util.ArrayList;
-
-/**
- * Almost a dead copy of android.test.mock.MockContentProvider, but different in that this
- * class extends ContentProvider, not implementing IContentProvider,
- * so that MockContentResolver is able to accept this class :(
- */
-class MockContentProvider extends ContentProvider {
- @Override
- public boolean onCreate() {
- return true;
- }
-
- @Override
- public int bulkInsert(Uri url, ContentValues[] initialValues) {
- throw new UnsupportedOperationException("unimplemented mock method");
- }
-
- @SuppressWarnings("unused")
- public IBulkCursor bulkQuery(Uri url, String[] projection, String selection,
- String[] selectionArgs, String sortOrder, IContentObserver observer,
- CursorWindow window) throws RemoteException {
- throw new UnsupportedOperationException("unimplemented mock method");
- }
-
- @Override
- @SuppressWarnings("unused")
- public int delete(Uri url, String selection, String[] selectionArgs) {
- throw new UnsupportedOperationException("unimplemented mock method");
- }
-
- @Override
- public String getType(Uri url) {
- throw new UnsupportedOperationException("unimplemented mock method");
- }
-
- @Override
- public Uri insert(Uri url, ContentValues initialValues) {
- throw new UnsupportedOperationException("unimplemented mock method");
- }
-
- @Override
- public ParcelFileDescriptor openFile(Uri url, String mode) {
- throw new UnsupportedOperationException("unimplemented mock method");
- }
-
- @Override
- public AssetFileDescriptor openAssetFile(Uri uri, String mode) {
- throw new UnsupportedOperationException("unimplemented mock method");
- }
-
- @Override
- public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) {
- throw new UnsupportedOperationException("unimplemented mock method");
- }
-
- @Override
- public Cursor query(Uri url, String[] projection, String selection, String[] selectionArgs,
- String sortOrder) {
- throw new UnsupportedOperationException("unimplemented mock method");
- }
-
- @Override
- public int update(Uri url, ContentValues values, String selection, String[] selectionArgs) {
- throw new UnsupportedOperationException("unimplemented mock method");
- }
-
- public IBinder asBinder() {
- throw new UnsupportedOperationException("unimplemented mock method");
- }
-}
-
-/**
- * BaseClass for vCard unit tests with utility classes.
- * Please do not add each unit test here.
- */
-/* package */ class VCardTestsBase extends AndroidTestCase {
- public static final int V21 = VCardConfig.VCARD_TYPE_V21_GENERIC_UTF8;
- public static final int V30 = VCardConfig.VCARD_TYPE_V30_GENERIC_UTF8;
-
- // Do not modify these during tests.
- protected final ContentValues mContentValuesForQP;
- protected final ContentValues mContentValuesForSJis;
- protected final ContentValues mContentValuesForUtf8;
- protected final ContentValues mContentValuesForQPAndSJis;
- protected final ContentValues mContentValuesForQPAndUtf8;
- protected final ContentValues mContentValuesForBase64V21;
- protected final ContentValues mContentValuesForBase64V30;
-
- protected VCardVerifier mVerifier;
- private boolean mSkipVerification;
-
- public VCardTestsBase() {
- super();
- mContentValuesForQP = new ContentValues();
- mContentValuesForQP.put("ENCODING", "QUOTED-PRINTABLE");
- mContentValuesForSJis = new ContentValues();
- mContentValuesForSJis.put("CHARSET", "SHIFT_JIS");
- mContentValuesForUtf8 = new ContentValues();
- mContentValuesForUtf8.put("CHARSET", "UTF-8");
- mContentValuesForQPAndSJis = new ContentValues();
- mContentValuesForQPAndSJis.put("ENCODING", "QUOTED-PRINTABLE");
- mContentValuesForQPAndSJis.put("CHARSET", "SHIFT_JIS");
- mContentValuesForQPAndUtf8 = new ContentValues();
- mContentValuesForQPAndUtf8.put("ENCODING", "QUOTED-PRINTABLE");
- mContentValuesForQPAndUtf8.put("CHARSET", "UTF-8");
- mContentValuesForBase64V21 = new ContentValues();
- mContentValuesForBase64V21.put("ENCODING", "BASE64");
- mContentValuesForBase64V30 = new ContentValues();
- mContentValuesForBase64V30.put("ENCODING", "b");
- }
-
- @Override
- public void testAndroidTestCaseSetupProperly() {
- super.testAndroidTestCaseSetupProperly();
- mSkipVerification = true;
- }
-
- @Override
- public void setUp() throws Exception{
- super.setUp();
- mVerifier = new VCardVerifier(this);
- mSkipVerification = false;
- }
-
- @Override
- public void tearDown() throws Exception {
- super.tearDown();
- if (!mSkipVerification) {
- mVerifier.verify();
- }
- }
-}
diff --git a/core/tests/coretests/src/android/pim/vcard/VCardUtilsTests.java b/core/tests/coretests/src/android/pim/vcard/VCardUtilsTests.java
deleted file mode 100644
index 59299f9..0000000
--- a/core/tests/coretests/src/android/pim/vcard/VCardUtilsTests.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.pim.vcard;
-
-import android.pim.vcard.VCardUtils;
-
-import junit.framework.TestCase;
-
-import java.util.List;
-
-public class VCardUtilsTests extends TestCase {
- public void testContainsOnlyPrintableAscii() {
- assertTrue(VCardUtils.containsOnlyPrintableAscii((String)null));
- assertTrue(VCardUtils.containsOnlyPrintableAscii((String[])null));
- assertTrue(VCardUtils.containsOnlyPrintableAscii((List<String>)null));
- assertTrue(VCardUtils.containsOnlyPrintableAscii(""));
- assertTrue(VCardUtils.containsOnlyPrintableAscii("abcdefghijklmnopqrstuvwxyz"));
- assertTrue(VCardUtils.containsOnlyPrintableAscii("ABCDEFGHIJKLMNOPQRSTUVWXYZ"));
- StringBuilder builder = new StringBuilder();
- for (int i = 0x20; i < 0x7F; i++) {
- builder.append((char)i);
- }
- assertTrue(VCardUtils.containsOnlyPrintableAscii(builder.toString()));
- assertTrue(VCardUtils.containsOnlyPrintableAscii("\r\n"));
- assertFalse(VCardUtils.containsOnlyPrintableAscii("\u0019"));
- assertFalse(VCardUtils.containsOnlyPrintableAscii("\u007F"));
- }
-
- public void testContainsOnlyNonCrLfPrintableAscii() {
- assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii((String)null));
- assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii((String[])null));
- assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii((List<String>)null));
- assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii(""));
- assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii("abcdefghijklmnopqrstuvwxyz"));
- assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii("ABCDEFGHIJKLMNOPQRSTUVWXYZ"));
- StringBuilder builder = new StringBuilder();
- for (int i = 0x20; i < 0x7F; i++) {
- builder.append((char)i);
- }
- assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii(builder.toString()));
- assertFalse(VCardUtils.containsOnlyNonCrLfPrintableAscii("\u0019"));
- assertFalse(VCardUtils.containsOnlyNonCrLfPrintableAscii("\u007F"));
- assertFalse(VCardUtils.containsOnlyNonCrLfPrintableAscii("\r"));
- assertFalse(VCardUtils.containsOnlyNonCrLfPrintableAscii("\n"));
- }
-
- public void testContainsOnlyAlphaDigitHyphen() {
- assertTrue(VCardUtils.containsOnlyAlphaDigitHyphen((String)null));
- assertTrue(VCardUtils.containsOnlyAlphaDigitHyphen((String[])null));
- assertTrue(VCardUtils.containsOnlyAlphaDigitHyphen((List<String>)null));
- assertTrue(VCardUtils.containsOnlyAlphaDigitHyphen(""));
- assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii("abcdefghijklmnopqrstuvwxyz"));
- assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii("ABCDEFGHIJKLMNOPQRSTUVWXYZ"));
- assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii("0123456789-"));
- for (int i = 0; i < 0x30; i++) {
- if (i == 0x2D) { // -
- continue;
- }
- assertFalse(VCardUtils.containsOnlyAlphaDigitHyphen(String.valueOf((char)i)));
- }
- for (int i = 0x3A; i < 0x41; i++) {
- assertFalse(VCardUtils.containsOnlyAlphaDigitHyphen(String.valueOf((char)i)));
- }
- for (int i = 0x5B; i < 0x61; i++) {
- assertFalse(VCardUtils.containsOnlyAlphaDigitHyphen(String.valueOf((char)i)));
- }
- for (int i = 0x7B; i < 0x100; i++) {
- assertFalse(VCardUtils.containsOnlyAlphaDigitHyphen(String.valueOf((char)i)));
- }
- }
-}
diff --git a/core/tests/coretests/src/android/pim/vcard/VCardVerifier.java b/core/tests/coretests/src/android/pim/vcard/VCardVerifier.java
deleted file mode 100644
index bfc3158..0000000
--- a/core/tests/coretests/src/android/pim/vcard/VCardVerifier.java
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package android.pim.vcard;
-
-import android.content.ContentProvider;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.EntityIterator;
-import android.net.Uri;
-import android.pim.vcard.VCardComposer;
-import android.pim.vcard.VCardConfig;
-import android.pim.vcard.VCardEntryConstructor;
-import android.pim.vcard.VCardInterpreter;
-import android.pim.vcard.VCardInterpreterCollection;
-import android.pim.vcard.VCardParser;
-import android.pim.vcard.VCardParser_V21;
-import android.pim.vcard.VCardParser_V30;
-import android.pim.vcard.exception.VCardException;
-import android.test.AndroidTestCase;
-import android.test.mock.MockContext;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.reflect.Method;
-import java.util.Arrays;
-
-/* package */ class CustomMockContext extends MockContext {
- final ContentResolver mResolver;
- public CustomMockContext(ContentResolver resolver) {
- mResolver = resolver;
- }
-
- @Override
- public ContentResolver getContentResolver() {
- return mResolver;
- }
-}
-
-/* package */ class VCardVerifier {
- private class VCardVerifierInternal implements VCardComposer.OneEntryHandler {
- public boolean onInit(Context context) {
- return true;
- }
- public boolean onEntryCreated(String vcard) {
- verifyOneVCard(vcard);
- return true;
- }
- public void onTerminate() {
- }
- }
-
- private final AndroidTestCase mTestCase;
- private final VCardVerifierInternal mVCardVerifierInternal;
- private int mVCardType;
- private boolean mIsV30;
- private boolean mIsDoCoMo;
-
- // Only one of them must be non-empty.
- private ExportTestResolver mExportTestResolver;
- private InputStream mInputStream;
-
- // To allow duplication, use list instead of set.
- // When null, we don't need to do the verification.
- private PropertyNodesVerifier mPropertyNodesVerifier;
- private LineVerifier mLineVerifier;
- private ContentValuesVerifier mContentValuesVerifier;
- private boolean mInitialized;
- private boolean mVerified = false;
-
- public VCardVerifier(AndroidTestCase androidTestCase) {
- mTestCase = androidTestCase;
- mVCardVerifierInternal = new VCardVerifierInternal();
- mExportTestResolver = null;
- mInputStream = null;
- mInitialized = false;
- mVerified = false;
- }
-
- public void initForExportTest(int vcardType) {
- if (mInitialized) {
- mTestCase.fail("Already initialized");
- }
- mExportTestResolver = new ExportTestResolver(mTestCase);
- mVCardType = vcardType;
- mIsV30 = VCardConfig.isV30(vcardType);
- mIsDoCoMo = VCardConfig.isDoCoMo(vcardType);
- mInitialized = true;
- }
-
- public void initForImportTest(int vcardType, int resId) {
- if (mInitialized) {
- mTestCase.fail("Already initialized");
- }
- mVCardType = vcardType;
- mIsV30 = VCardConfig.isV30(vcardType);
- mIsDoCoMo = VCardConfig.isDoCoMo(vcardType);
- setInputResourceId(resId);
- mInitialized = true;
- }
-
- private void setInputResourceId(int resId) {
- InputStream inputStream = mTestCase.getContext().getResources().openRawResource(resId);
- if (inputStream == null) {
- mTestCase.fail("Wrong resId: " + resId);
- }
- setInputStream(inputStream);
- }
-
- private void setInputStream(InputStream inputStream) {
- if (mExportTestResolver != null) {
- mTestCase.fail("addInputEntry() is called.");
- } else if (mInputStream != null) {
- mTestCase.fail("InputStream is already set");
- }
- mInputStream = inputStream;
- }
-
- public ContactEntry addInputEntry() {
- if (!mInitialized) {
- mTestCase.fail("Not initialized");
- }
- if (mInputStream != null) {
- mTestCase.fail("setInputStream is called");
- }
- return mExportTestResolver.addInputContactEntry();
- }
-
- public PropertyNodesVerifierElem addPropertyNodesVerifierElem() {
- if (!mInitialized) {
- mTestCase.fail("Not initialized");
- }
- if (mPropertyNodesVerifier == null) {
- mPropertyNodesVerifier = new PropertyNodesVerifier(mTestCase);
- }
- PropertyNodesVerifierElem elem =
- mPropertyNodesVerifier.addPropertyNodesVerifierElem();
- elem.addExpectedNodeWithOrder("VERSION", (mIsV30 ? "3.0" : "2.1"));
-
- return elem;
- }
-
- public PropertyNodesVerifierElem addPropertyNodesVerifierElemWithEmptyName() {
- if (!mInitialized) {
- mTestCase.fail("Not initialized");
- }
- PropertyNodesVerifierElem elem = addPropertyNodesVerifierElem();
- if (mIsV30) {
- elem.addExpectedNodeWithOrder("N", "").addExpectedNodeWithOrder("FN", "");
- } else if (mIsDoCoMo) {
- elem.addExpectedNodeWithOrder("N", "");
- }
- return elem;
- }
-
- public LineVerifierElem addLineVerifierElem() {
- if (!mInitialized) {
- mTestCase.fail("Not initialized");
- }
- if (mLineVerifier == null) {
- mLineVerifier = new LineVerifier(mTestCase, mVCardType);
- }
- return mLineVerifier.addLineVerifierElem();
- }
-
- public ContentValuesVerifierElem addContentValuesVerifierElem() {
- if (!mInitialized) {
- mTestCase.fail("Not initialized");
- }
- if (mContentValuesVerifier == null) {
- mContentValuesVerifier = new ContentValuesVerifier();
- }
-
- return mContentValuesVerifier.addElem(mTestCase);
- }
-
- private void verifyOneVCard(final String vcard) {
- // Log.d("@@@", vcard);
- final VCardInterpreter builder;
- if (mContentValuesVerifier != null) {
- final VNodeBuilder vnodeBuilder = mPropertyNodesVerifier;
- final VCardEntryConstructor vcardDataBuilder =
- new VCardEntryConstructor(mVCardType);
- vcardDataBuilder.addEntryHandler(mContentValuesVerifier);
- if (mPropertyNodesVerifier != null) {
- builder = new VCardInterpreterCollection(Arrays.asList(
- mPropertyNodesVerifier, vcardDataBuilder));
- } else {
- builder = vnodeBuilder;
- }
- } else {
- if (mPropertyNodesVerifier != null) {
- builder = mPropertyNodesVerifier;
- } else {
- return;
- }
- }
-
- final VCardParser parser =
- (mIsV30 ? new VCardParser_V30(true) : new VCardParser_V21());
- InputStream is = null;
- try {
- String charset =
- (VCardConfig.usesShiftJis(mVCardType) ? "SHIFT_JIS" : "UTF-8");
- is = new ByteArrayInputStream(vcard.getBytes(charset));
- mTestCase.assertEquals(true, parser.parse(is, null, builder));
- } catch (IOException e) {
- mTestCase.fail("Unexpected IOException: " + e.getMessage());
- } catch (VCardException e) {
- mTestCase.fail("Unexpected VCardException: " + e.getMessage());
- } finally {
- if (is != null) {
- try {
- is.close();
- } catch (IOException e) {
- }
- }
- }
- }
-
- public void verify() {
- if (!mInitialized) {
- mTestCase.fail("Not initialized.");
- }
- if (mVerified) {
- mTestCase.fail("verify() was called twice.");
- }
- if (mInputStream != null) {
- try {
- verifyForImportTest();
- } catch (IOException e) {
- mTestCase.fail("IOException was thrown: " + e.getMessage());
- } catch (VCardException e) {
- mTestCase.fail("VCardException was thrown: " + e.getMessage());
- }
- } else if (mExportTestResolver != null){
- verifyForExportTest();
- } else {
- mTestCase.fail("No input is determined");
- }
- mVerified = true;
- }
-
- private void verifyForImportTest() throws IOException, VCardException {
- if (mLineVerifier != null) {
- mTestCase.fail("Not supported now.");
- }
- if (mContentValuesVerifier != null) {
- mContentValuesVerifier.verify(mInputStream, mVCardType);
- }
- }
-
- public static EntityIterator mockGetEntityIteratorMethod(
- final ContentResolver resolver,
- final Uri uri, final String selection,
- final String[] selectionArgs, final String sortOrder) {
- final ContentProvider provider =
- resolver.acquireContentProviderClient(uri).getLocalContentProvider();
- return ((ExportTestProvider)provider).queryEntities(
- uri, selection, selectionArgs, sortOrder);
- }
-
- private Method getMockGetEntityIteratorMethod()
- throws SecurityException, NoSuchMethodException {
- return this.getClass().getMethod("mockGetEntityIteratorMethod",
- ContentResolver.class, Uri.class, String.class, String[].class, String.class);
- }
-
- private void verifyForExportTest() {
- final VCardComposer composer =
- new VCardComposer(new CustomMockContext(mExportTestResolver), mVCardType);
- composer.addHandler(mLineVerifier);
- composer.addHandler(mVCardVerifierInternal);
- if (!composer.init(VCardComposer.CONTACTS_TEST_CONTENT_URI, null, null, null)) {
- mTestCase.fail("init() failed. Reason: " + composer.getErrorReason());
- }
- mTestCase.assertFalse(composer.isAfterLast());
- try {
- while (!composer.isAfterLast()) {
- try {
- final Method mockGetEntityIteratorMethod = getMockGetEntityIteratorMethod();
- mTestCase.assertTrue(
- composer.createOneEntry(getMockGetEntityIteratorMethod()));
- } catch (Exception e) {
- e.printStackTrace();
- mTestCase.fail();
- }
- }
- } finally {
- composer.terminate();
- }
- }
-}
diff --git a/core/tests/coretests/src/android/pim/vcard/VNode.java b/core/tests/coretests/src/android/pim/vcard/VNode.java
deleted file mode 100644
index 79f10dc..0000000
--- a/core/tests/coretests/src/android/pim/vcard/VNode.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.pim.vcard;
-
-import java.util.ArrayList;
-
-/**
- * Previously used in main vCard handling code but now exists only for testing.
- */
-public class VNode {
- public String VName;
-
- public ArrayList<PropertyNode> propList = new ArrayList<PropertyNode>();
-
- /** 0:parse over. 1:parsing. */
- public int parseStatus = 1;
-}
diff --git a/core/tests/coretests/src/android/pim/vcard/VNodeBuilder.java b/core/tests/coretests/src/android/pim/vcard/VNodeBuilder.java
deleted file mode 100644
index 0e6c325..0000000
--- a/core/tests/coretests/src/android/pim/vcard/VNodeBuilder.java
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.pim.vcard;
-
-import android.content.ContentValues;
-import android.pim.vcard.VCardInterpreter;
-import android.pim.vcard.VCardConfig;
-import android.util.CharsetUtils;
-import android.util.Log;
-
-import org.apache.commons.codec.DecoderException;
-import org.apache.commons.codec.binary.Base64;
-import org.apache.commons.codec.net.QuotedPrintableCodec;
-
-import java.io.UnsupportedEncodingException;
-import java.nio.ByteBuffer;
-import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Store the parse result to custom datastruct: VNode, PropertyNode
- * Maybe several vcard instance, so use vNodeList to store.
- * VNode: standy by a vcard instance.
- * PropertyNode: standy by a property line of a card.
- *
- * Previously used in main vCard handling code but now exists only for testing.
- */
-public class VNodeBuilder implements VCardInterpreter {
- static private String LOG_TAG = "VNodeBuilder";
-
- /**
- * If there's no other information available, this class uses this charset for encoding
- * byte arrays.
- */
- static public String TARGET_CHARSET = "UTF-8";
-
- /** type=VNode */
- public List<VNode> vNodeList = new ArrayList<VNode>();
- private int mNodeListPos = 0;
- private VNode mCurrentVNode;
- private PropertyNode mCurrentPropNode;
- private String mCurrentParamType;
-
- /**
- * The charset using which VParser parses the text.
- */
- private String mSourceCharset;
-
- /**
- * The charset with which byte array is encoded to String.
- */
- private String mTargetCharset;
-
- private boolean mStrictLineBreakParsing;
-
- public VNodeBuilder() {
- this(VCardConfig.DEFAULT_CHARSET, TARGET_CHARSET, false);
- }
-
- public VNodeBuilder(String charset, boolean strictLineBreakParsing) {
- this(null, charset, strictLineBreakParsing);
- }
-
- /**
- * @hide sourceCharset is temporal.
- */
- public VNodeBuilder(String sourceCharset, String targetCharset,
- boolean strictLineBreakParsing) {
- if (sourceCharset != null) {
- mSourceCharset = sourceCharset;
- } else {
- mSourceCharset = VCardConfig.DEFAULT_CHARSET;
- }
- if (targetCharset != null) {
- mTargetCharset = targetCharset;
- } else {
- mTargetCharset = TARGET_CHARSET;
- }
- mStrictLineBreakParsing = strictLineBreakParsing;
- }
-
- public void start() {
- }
-
- public void end() {
- }
-
- // Note: I guess that this code assumes the Record may nest like this:
- // START:VPOS
- // ...
- // START:VPOS2
- // ...
- // END:VPOS2
- // ...
- // END:VPOS
- //
- // However the following code has a bug.
- // When error occurs after calling startRecord(), the entry which is probably
- // the cause of the error remains to be in vNodeList, while endRecord() is not called.
- //
- // I leave this code as is since I'm not familiar with vcalendar specification.
- // But I believe we should refactor this code in the future.
- // Until this, the last entry has to be removed when some error occurs.
- public void startEntry() {
- VNode vnode = new VNode();
- vnode.parseStatus = 1;
- vnode.VName = "VCARD";
- // I feel this should be done in endRecord(), but it cannot be done because of
- // the reason above.
- vNodeList.add(vnode);
- mNodeListPos = vNodeList.size() - 1;
- mCurrentVNode = vNodeList.get(mNodeListPos);
- }
-
- public void endEntry() {
- VNode endNode = vNodeList.get(mNodeListPos);
- endNode.parseStatus = 0;
- while(mNodeListPos > 0){
- mNodeListPos--;
- if((vNodeList.get(mNodeListPos)).parseStatus == 1)
- break;
- }
- mCurrentVNode = vNodeList.get(mNodeListPos);
- }
-
- public void startProperty() {
- mCurrentPropNode = new PropertyNode();
- }
-
- public void endProperty() {
- mCurrentVNode.propList.add(mCurrentPropNode);
- }
-
- public void propertyName(String name) {
- mCurrentPropNode.propName = name;
- }
-
- // Used only in VCard.
- public void propertyGroup(String group) {
- mCurrentPropNode.propGroupSet.add(group);
- }
-
- public void propertyParamType(String type) {
- mCurrentParamType = type;
- }
-
- public void propertyParamValue(String value) {
- if (mCurrentParamType == null ||
- mCurrentParamType.equalsIgnoreCase("TYPE")) {
- mCurrentPropNode.paramMap_TYPE.add(value);
- } else {
- mCurrentPropNode.paramMap.put(mCurrentParamType, value);
- }
-
- mCurrentParamType = null;
- }
-
- private String encodeString(String originalString, String targetCharset) {
- if (mSourceCharset.equalsIgnoreCase(targetCharset)) {
- return originalString;
- }
- Charset charset = Charset.forName(mSourceCharset);
- ByteBuffer byteBuffer = charset.encode(originalString);
- // byteBuffer.array() "may" return byte array which is larger than
- // byteBuffer.remaining(). Here, we keep on the safe side.
- byte[] bytes = new byte[byteBuffer.remaining()];
- byteBuffer.get(bytes);
- try {
- return new String(bytes, targetCharset);
- } catch (UnsupportedEncodingException e) {
- Log.e(LOG_TAG, "Failed to encode: charset=" + targetCharset);
- return null;
- }
- }
-
- private String handleOneValue(String value, String targetCharset, String encoding) {
- if (encoding != null) {
- encoding = encoding.toUpperCase();
- if (encoding.equals("BASE64") || encoding.equals("B")) {
- // Assume BASE64 is used only when the number of values is 1.
- mCurrentPropNode.propValue_bytes =
- Base64.decodeBase64(value.getBytes());
- return value;
- } else if (encoding.equals("QUOTED-PRINTABLE")) {
- String quotedPrintable = value
- .replaceAll("= ", " ").replaceAll("=\t", "\t");
- String[] lines;
- if (mStrictLineBreakParsing) {
- lines = quotedPrintable.split("\r\n");
- } else {
- StringBuilder builder = new StringBuilder();
- int length = quotedPrintable.length();
- ArrayList<String> list = new ArrayList<String>();
- for (int i = 0; i < length; i++) {
- char ch = quotedPrintable.charAt(i);
- if (ch == '\n') {
- list.add(builder.toString());
- builder = new StringBuilder();
- } else if (ch == '\r') {
- list.add(builder.toString());
- builder = new StringBuilder();
- if (i < length - 1) {
- char nextCh = quotedPrintable.charAt(i + 1);
- if (nextCh == '\n') {
- i++;
- }
- }
- } else {
- builder.append(ch);
- }
- }
- String finalLine = builder.toString();
- if (finalLine.length() > 0) {
- list.add(finalLine);
- }
- lines = list.toArray(new String[0]);
- }
- StringBuilder builder = new StringBuilder();
- for (String line : lines) {
- if (line.endsWith("=")) {
- line = line.substring(0, line.length() - 1);
- }
- builder.append(line);
- }
- byte[] bytes;
- try {
- bytes = builder.toString().getBytes(mSourceCharset);
- } catch (UnsupportedEncodingException e1) {
- Log.e(LOG_TAG, "Failed to encode: charset=" + mSourceCharset);
- bytes = builder.toString().getBytes();
- }
-
- try {
- bytes = QuotedPrintableCodec.decodeQuotedPrintable(bytes);
- } catch (DecoderException e) {
- Log.e(LOG_TAG, "Failed to decode quoted-printable: " + e);
- return "";
- }
-
- try {
- return new String(bytes, targetCharset);
- } catch (UnsupportedEncodingException e) {
- Log.e(LOG_TAG, "Failed to encode: charset=" + targetCharset);
- return new String(bytes);
- }
- }
- // Unknown encoding. Fall back to default.
- }
- return encodeString(value, targetCharset);
- }
-
- public void propertyValues(List<String> values) {
- if (values == null || values.size() == 0) {
- mCurrentPropNode.propValue_bytes = null;
- mCurrentPropNode.propValue_vector.clear();
- mCurrentPropNode.propValue_vector.add("");
- mCurrentPropNode.propValue = "";
- return;
- }
-
- ContentValues paramMap = mCurrentPropNode.paramMap;
-
- String targetCharset = CharsetUtils.nameForDefaultVendor(paramMap.getAsString("CHARSET"));
- String encoding = paramMap.getAsString("ENCODING");
-
- if (targetCharset == null || targetCharset.length() == 0) {
- targetCharset = mTargetCharset;
- }
-
- for (String value : values) {
- mCurrentPropNode.propValue_vector.add(
- handleOneValue(value, targetCharset, encoding));
- }
-
- mCurrentPropNode.propValue = listToString(mCurrentPropNode.propValue_vector);
- }
-
- private String listToString(List<String> list){
- int size = list.size();
- if (size > 1) {
- StringBuilder typeListB = new StringBuilder();
- for (String type : list) {
- typeListB.append(type).append(";");
- }
- int len = typeListB.length();
- if (len > 0 && typeListB.charAt(len - 1) == ';') {
- return typeListB.substring(0, len - 1);
- }
- return typeListB.toString();
- } else if (size == 1) {
- return list.get(0);
- } else {
- return "";
- }
- }
-
- public String getResult(){
- return null;
- }
-}
diff --git a/core/tests/coretests/src/android/provider/SettingsProviderTest.java b/core/tests/coretests/src/android/provider/SettingsProviderTest.java
index 370ae78..b82e698 100644
--- a/core/tests/coretests/src/android/provider/SettingsProviderTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsProviderTest.java
@@ -144,4 +144,51 @@
assertEquals(null, Settings.Bookmarks.getIntentForShortcut(r, '*'));
}
+
+ @MediumTest
+ public void testParseProviderList() {
+ ContentResolver r = getContext().getContentResolver();
+
+ // Make sure we get out what we put in.
+ Settings.Secure.putString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+ "test1,test2,test3");
+ assertEquals(Settings.Secure.getString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED),
+ "test1,test2,test3");
+
+ // Test adding a value
+ Settings.Secure.putString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+ "");
+ Settings.Secure.putString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "+test1");
+ assertEquals("test1",
+ Settings.Secure.getString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED));
+
+ // Test adding a second value
+ Settings.Secure.putString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "+test2");
+ assertEquals("test1,test2",
+ Settings.Secure.getString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED));
+
+ // Test adding a third value
+ Settings.Secure.putString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "+test3");
+ assertEquals("test1,test2,test3",
+ Settings.Secure.getString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED));
+
+ // Test deleting the first value in a 3 item list
+ Settings.Secure.putString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "-test1");
+ assertEquals("test2,test3",
+ Settings.Secure.getString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED));
+
+ // Test deleting the middle value in a 3 item list
+ Settings.Secure.putString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+ "test1,test2,test3");
+ Settings.Secure.putString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "-test2");
+ assertEquals("test1,test3",
+ Settings.Secure.getString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED));
+
+ // Test deleting the last value in a 3 item list
+ Settings.Secure.putString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+ "test1,test2,test3");
+ Settings.Secure.putString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "-test3");
+ assertEquals("test1,test2",
+ Settings.Secure.getString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED));
+ }
}
diff --git a/core/tests/coretests/src/android/text/StaticLayoutBidiTest.java b/core/tests/coretests/src/android/text/StaticLayoutBidiTest.java
index 8e7e63e..fb0f0c1 100644
--- a/core/tests/coretests/src/android/text/StaticLayoutBidiTest.java
+++ b/core/tests/coretests/src/android/text/StaticLayoutBidiTest.java
@@ -22,7 +22,7 @@
import junit.framework.TestCase;
/**
- * Tests StaticLayout bidi implementation.
+ * Quick check of native bidi implementation.
*/
public class StaticLayoutBidiTest extends TestCase {
@@ -41,73 +41,47 @@
//@SmallTest
public void testAllLtr() {
- expectBidi(REQ_DL, "a test", "000000", L);
+ expectNativeBidi(REQ_DL, "a test", "000000", L);
}
//@SmallTest
public void testLtrRtl() {
- expectBidi(REQ_DL, "abc " + ALEF + BET + GIMEL, "0000111", L);
+ expectNativeBidi(REQ_DL, "abc " + ALEF + BET + GIMEL, "0000111", L);
}
//@SmallTest
public void testAllRtl() {
- expectBidi(REQ_DL, ALEF + SP + ALEF + BET + GIMEL + DALET, "111111", R);
+ expectNativeBidi(REQ_DL, ALEF + SP + ALEF + BET + GIMEL + DALET, "111111", R);
}
//@SmallTest
public void testRtlLtr() {
- expectBidi(REQ_DL, ALEF + BET + GIMEL + " abc", "1111000", R);
+ expectNativeBidi(REQ_DL, ALEF + BET + GIMEL + " abc", "1111222", R);
}
//@SmallTest
public void testRAllLtr() {
- expectBidi(REQ_R, "a test", "000000", R);
+ expectNativeBidi(REQ_R, "a test", "222222", R);
}
//@SmallTest
public void testRLtrRtl() {
- expectBidi(REQ_R, "abc " + ALEF + BET + GIMEL, "0001111", R);
+ expectNativeBidi(REQ_R, "abc " + ALEF + BET + GIMEL, "2221111", R);
}
//@SmallTest
public void testLAllRtl() {
- expectBidi(REQ_L, ALEF + SP + ALEF + BET + GIMEL + DALET, "111111", L);
+ expectNativeBidi(REQ_L, ALEF + SP + ALEF + BET + GIMEL + DALET, "111111", L);
}
//@SmallTest
public void testLRtlLtr() {
- expectBidi(REQ_L, ALEF + BET + GIMEL + " abc", "1110000", L);
- }
-
- private void expectBidi(int dir, String text,
- String expectedLevels, int expectedDir) {
- char[] chs = text.toCharArray();
- int n = chs.length;
- byte[] chInfo = new byte[n];
-
- int resultDir = StaticLayout.bidi(dir, chs, chInfo, n, false);
-
- {
- StringBuilder sb = new StringBuilder("info:");
- for (int i = 0; i < n; ++i) {
- sb.append(" ").append(String.valueOf(chInfo[i]));
- }
- Log.i("BIDI", sb.toString());
- }
-
- char[] resultLevelChars = new char[n];
- for (int i = 0; i < n; ++i) {
- resultLevelChars[i] = (char)('0' + chInfo[i]);
- }
- String resultLevels = new String(resultLevelChars);
- assertEquals("direction", expectedDir, resultDir);
- assertEquals("levels", expectedLevels, resultLevels);
+ expectNativeBidi(REQ_DL, ALEF + BET + GIMEL + " abc", "1111222", R);
}
//@SmallTest
public void testNativeBidi() {
- // native bidi returns levels, not simply directions
- expectNativeBidi(REQ_DL, ALEF + BET + GIMEL + " abc", "1111222", R);
+ expectNativeBidi(REQ_L, ALEF + BET + GIMEL + " abc", "1110000", L);
}
private void expectNativeBidi(int dir, String text,
diff --git a/core/tests/coretests/src/android/text/StaticLayoutDirectionsTest.java b/core/tests/coretests/src/android/text/StaticLayoutDirectionsTest.java
new file mode 100644
index 0000000..4fde849
--- /dev/null
+++ b/core/tests/coretests/src/android/text/StaticLayoutDirectionsTest.java
@@ -0,0 +1,243 @@
+/*
+ * 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.text;
+
+import android.text.Layout.Directions;
+import android.text.StaticLayoutTest.LayoutBuilder;
+
+import java.util.Arrays;
+import java.util.Formatter;
+
+import junit.framework.TestCase;
+
+public class StaticLayoutDirectionsTest extends TestCase {
+ private static final char ALEF = '\u05d0';
+
+ private static Directions dirs(int ... dirs) {
+ return new Directions(dirs);
+ }
+
+ // constants from Layout that are package-protected
+ private static final int RUN_LENGTH_MASK = 0x03ffffff;
+ private static final int RUN_LEVEL_SHIFT = 26;
+ private static final int RUN_LEVEL_MASK = 0x3f;
+ private static final int RUN_RTL_FLAG = 1 << RUN_LEVEL_SHIFT;
+
+ private static final Directions DIRS_ALL_LEFT_TO_RIGHT =
+ new Directions(new int[] { 0, RUN_LENGTH_MASK });
+ private static final Directions DIRS_ALL_RIGHT_TO_LEFT =
+ new Directions(new int[] { 0, RUN_LENGTH_MASK | RUN_RTL_FLAG });
+
+ private static final int LVL1_1 = 1 | (1 << RUN_LEVEL_SHIFT);
+ private static final int LVL2_1 = 1 | (2 << RUN_LEVEL_SHIFT);
+ private static final int LVL2_2 = 2 | (2 << RUN_LEVEL_SHIFT);
+
+ private static String[] texts = {
+ "",
+ " ",
+ "a",
+ "a1",
+ "aA",
+ "a1b",
+ "a1A",
+ "aA1",
+ "aAb",
+ "aA1B",
+ "aA1B2",
+
+ // rtl
+ "A",
+ "A1",
+ "Aa",
+ "A1B",
+ "A1a",
+ "Aa1",
+ "AaB"
+ };
+
+ // Expected directions are an array of start/length+level pairs,
+ // in visual order from the leading margin.
+ private static Directions[] expected = {
+ DIRS_ALL_LEFT_TO_RIGHT,
+ DIRS_ALL_LEFT_TO_RIGHT,
+ DIRS_ALL_LEFT_TO_RIGHT,
+ DIRS_ALL_LEFT_TO_RIGHT,
+ dirs(0, 1, 1, LVL1_1),
+ DIRS_ALL_LEFT_TO_RIGHT,
+ dirs(0, 2, 2, LVL1_1),
+ dirs(0, 1, 2, LVL2_1, 1, LVL1_1),
+ dirs(0, 1, 1, LVL1_1, 2, 1),
+ dirs(0, 1, 3, LVL1_1, 2, LVL2_1, 1, LVL1_1),
+ dirs(0, 1, 4, LVL2_1, 3, LVL1_1, 2, LVL2_1, 1, LVL1_1),
+
+ // rtl
+ DIRS_ALL_RIGHT_TO_LEFT,
+ dirs(0, LVL1_1, 1, LVL2_1),
+ dirs(0, LVL1_1, 1, LVL2_1),
+ dirs(0, LVL1_1, 1, LVL2_1, 2, LVL1_1),
+ dirs(0, LVL1_1, 1, LVL2_2),
+ dirs(0, LVL1_1, 1, LVL2_2),
+ dirs(0, LVL1_1, 1, LVL2_1, 2, LVL1_1),
+ };
+
+ private static String pseudoBidiToReal(String src) {
+ char[] chars = src.toCharArray();
+ for (int j = 0; j < chars.length; ++j) {
+ char c = chars[j];
+ if (c >= 'A' && c <= 'D') {
+ chars[j] = (char)(ALEF + c - 'A');
+ }
+ }
+
+ return new String(chars, 0, chars.length);
+ }
+
+ // @SmallTest
+ public void testDirections() {
+ StringBuilder buf = new StringBuilder("\n");
+ Formatter f = new Formatter(buf);
+
+ LayoutBuilder b = StaticLayoutTest.builder();
+ for (int i = 0; i < texts.length; ++i) {
+ b.setText(pseudoBidiToReal(texts[i]));
+ checkDirections(b.build(), i, b.text, expected, f);
+ }
+ if (buf.length() > 1) {
+ fail(buf.toString());
+ }
+ }
+
+ // @SmallTest
+ public void testTrailingWhitespace() {
+ LayoutBuilder b = StaticLayoutTest.builder();
+ b.setText(pseudoBidiToReal("Ab c"));
+ float width = b.paint.measureText(b.text, 0, 5); // exclude 'c'
+ b.setWidth(Math.round(width));
+ Layout l = b.build();
+ if (l.getLineCount() != 2) {
+ throw new RuntimeException("expected 2 lines, got: " + l.getLineCount());
+ }
+ Directions result = l.getLineDirections(0);
+ Directions expected = dirs(0, LVL1_1, 1, LVL2_1, 2, 3 | (1 << Layout.RUN_LEVEL_SHIFT));
+ expectDirections("split line", expected, result);
+ }
+
+ public void testNextToRightOf() {
+ LayoutBuilder b = StaticLayoutTest.builder();
+ b.setText(pseudoBidiToReal("aA1B2"));
+ // visual a2B1A positions 04321
+ // 0: |a2B1A, strong is sol, after -> 0
+ // 1: a|2B1A, strong is a, after ->, 1
+ // 2: a2|B1A, strong is B, after -> 4
+ // 3: a2B|1A, strong is B, before -> 3
+ // 4: a2B1|A, strong is A, after -> 2
+ // 5: a2B1A|, strong is eol, before -> 5
+ int[] expected = { 0, 1, 4, 3, 2, 5 };
+ Layout l = b.build();
+ int n = 0;
+ for (int i = 1; i < expected.length; ++i) {
+ int t = l.getOffsetToRightOf(n);
+ if (t != expected[i]) {
+ fail("offset[" + i + "] to right of: " + n + " expected: " +
+ expected[i] + " got: " + t);
+ }
+ n = t;
+ }
+ }
+
+ public void testNextToLeftOf() {
+ LayoutBuilder b = StaticLayoutTest.builder();
+ b.setText(pseudoBidiToReal("aA1B2"));
+ int[] expected = { 0, 1, 4, 3, 2, 5 };
+ Layout l = b.build();
+ int n = 5;
+ for (int i = expected.length - 1; --i >= 0;) {
+ int t = l.getOffsetToLeftOf(n);
+ if (t != expected[i]) {
+ fail("offset[" + i + "] to left of: " + n + " expected: " +
+ expected[i] + " got: " + t);
+ }
+ n = t;
+ }
+ }
+
+ // utility, not really a test
+ /*
+ public void testMeasureText1() {
+ LayoutBuilder b = StaticLayoutTest.builder();
+ String text = "ABC"; // "abAB"
+ b.setText(pseudoBidiToReal(text));
+ Layout l = b.build();
+ Directions directions = l.getLineDirections(0);
+
+ TextPaint workPaint = new TextPaint();
+
+ int dir = -1; // LEFT_TO_RIGHT
+ boolean trailing = true;
+ boolean alt = true;
+ do {
+ dir = -dir;
+ do {
+ trailing = !trailing;
+ for (int offset = 0, end = b.text.length(); offset <= end; ++offset) {
+ float width = Layout.measureText(b.paint,
+ workPaint,
+ b.text,
+ 0, offset, end,
+ dir, directions,
+ trailing, false,
+ null);
+ Log.i("BIDI", "dir: " + dir + " trail: " + trailing +
+ " offset: " + offset + " width: " + width);
+ }
+ } while (!trailing);
+ } while (dir > 0);
+ }
+ */
+
+ // utility for displaying arrays in hex
+ private static String hexArray(int[] array) {
+ StringBuilder sb = new StringBuilder();
+ sb.append('{');
+ for (int i : array) {
+ if (sb.length() > 1) {
+ sb.append(", ");
+ }
+ sb.append(Integer.toHexString(i));
+ }
+ sb.append('}');
+ return sb.toString();
+ }
+
+ private void checkDirections(Layout l, int i, String text,
+ Directions[] expectedDirs, Formatter f) {
+ Directions expected = expectedDirs[i];
+ Directions result = l.getLineDirections(0);
+ if (!Arrays.equals(expected.mDirections, result.mDirections)) {
+ f.format("%n[%2d] '%s', %s != %s", i, text,
+ hexArray(expected.mDirections),
+ hexArray(result.mDirections));
+ }
+ }
+
+ private void expectDirections(String msg, Directions expected, Directions result) {
+ if (!Arrays.equals(expected.mDirections, result.mDirections)) {
+ fail("expected: " + hexArray(expected.mDirections) +
+ " got: " + hexArray(result.mDirections));
+ }
+ }
+}
diff --git a/core/tests/coretests/src/android/text/StaticLayoutTest.java b/core/tests/coretests/src/android/text/StaticLayoutTest.java
index 1f58a2c..d554a50 100644
--- a/core/tests/coretests/src/android/text/StaticLayoutTest.java
+++ b/core/tests/coretests/src/android/text/StaticLayoutTest.java
@@ -228,11 +228,11 @@
}
}
- private static LayoutBuilder builder() {
+ /* package */ static LayoutBuilder builder() {
return new LayoutBuilder();
}
- private static class LayoutBuilder {
+ /* package */ static class LayoutBuilder {
String text = "This is a test";
TextPaint paint = new TextPaint(); // default
int width = 100;
diff --git a/core/tests/coretests/src/android/util/ExpandableListScenario.java b/core/tests/coretests/src/android/util/ExpandableListScenario.java
deleted file mode 100644
index 4a12b0d..0000000
--- a/core/tests/coretests/src/android/util/ExpandableListScenario.java
+++ /dev/null
@@ -1,386 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.util;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import android.view.Gravity;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AbsListView;
-import android.widget.BaseExpandableListAdapter;
-import android.widget.ExpandableListAdapter;
-import android.widget.ExpandableListView;
-import android.widget.ListView;
-import android.widget.TextView;
-
-/**
- * Utility base class for creating various Expandable List scenarios.
- * <p>
- * WARNING: A lot of the features are mixed between ListView's expected position
- * (flat list position) and an ExpandableListView's expected position. You must add/change
- * features as you need them.
- *
- * @see ListScenario
- */
-public abstract class ExpandableListScenario extends ListScenario {
- protected ExpandableListAdapter mAdapter;
- protected List<MyGroup> mGroups;
-
- @Override
- protected ListView createListView() {
- return new ExpandableListView(this);
- }
-
- @Override
- protected Params createParams() {
- return new ExpandableParams();
- }
-
- @Override
- protected void setAdapter(ListView listView) {
- ((ExpandableListView) listView).setAdapter(mAdapter = createAdapter());
- }
-
- protected ExpandableListAdapter createAdapter() {
- return new MyAdapter();
- }
-
- @Override
- protected void readAndValidateParams(Params params) {
- ExpandableParams expandableParams = (ExpandableParams) params;
-
- int[] numChildren = expandableParams.mNumChildren;
-
- mGroups = new ArrayList<MyGroup>(numChildren.length);
- for (int i = 0; i < numChildren.length; i++) {
- mGroups.add(new MyGroup(numChildren[i]));
- }
-
- expandableParams.superSetNumItems();
-
- super.readAndValidateParams(params);
- }
-
- /**
- * Get the ExpandableListView widget.
- * @return The main widget.
- */
- public ExpandableListView getExpandableListView() {
- return (ExpandableListView) super.getListView();
- }
-
- public static class ExpandableParams extends Params {
- private int[] mNumChildren;
-
- /**
- * Sets the number of children per group.
- *
- * @param numChildrenPerGroup The number of children per group.
- */
- public ExpandableParams setNumChildren(int[] numChildren) {
- mNumChildren = numChildren;
- return this;
- }
-
- /**
- * Sets the number of items on the superclass based on the number of
- * groups and children per group.
- */
- private ExpandableParams superSetNumItems() {
- int numItems = 0;
-
- if (mNumChildren != null) {
- for (int i = mNumChildren.length - 1; i >= 0; i--) {
- numItems += mNumChildren[i];
- }
- }
-
- super.setNumItems(numItems);
-
- return this;
- }
-
- @Override
- public Params setNumItems(int numItems) {
- throw new IllegalStateException("Use setNumGroups and setNumChildren instead.");
- }
-
- @Override
- public ExpandableParams setFadingEdgeScreenSizeFactor(double fadingEdgeScreenSizeFactor) {
- return (ExpandableParams) super.setFadingEdgeScreenSizeFactor(fadingEdgeScreenSizeFactor);
- }
-
- @Override
- public ExpandableParams setItemScreenSizeFactor(double itemScreenSizeFactor) {
- return (ExpandableParams) super.setItemScreenSizeFactor(itemScreenSizeFactor);
- }
-
- @Override
- public ExpandableParams setItemsFocusable(boolean itemsFocusable) {
- return (ExpandableParams) super.setItemsFocusable(itemsFocusable);
- }
-
- @Override
- public ExpandableParams setMustFillScreen(boolean fillScreen) {
- return (ExpandableParams) super.setMustFillScreen(fillScreen);
- }
-
- @Override
- public ExpandableParams setPositionScreenSizeFactorOverride(int position, double itemScreenSizeFactor) {
- return (ExpandableParams) super.setPositionScreenSizeFactorOverride(position, itemScreenSizeFactor);
- }
-
- @Override
- public ExpandableParams setPositionUnselectable(int position) {
- return (ExpandableParams) super.setPositionUnselectable(position);
- }
-
- @Override
- public ExpandableParams setStackFromBottom(boolean stackFromBottom) {
- return (ExpandableParams) super.setStackFromBottom(stackFromBottom);
- }
-
- @Override
- public ExpandableParams setStartingSelectionPosition(int startingSelectionPosition) {
- return (ExpandableParams) super.setStartingSelectionPosition(startingSelectionPosition);
- }
-
- @Override
- public ExpandableParams setConnectAdapter(boolean connectAdapter) {
- return (ExpandableParams) super.setConnectAdapter(connectAdapter);
- }
- }
-
- /**
- * Gets a string for the value of some item.
- * @param packedPosition The position of the item.
- * @return The string.
- */
- public final String getValueAtPosition(long packedPosition) {
- final int type = ExpandableListView.getPackedPositionType(packedPosition);
-
- if (type == ExpandableListView.PACKED_POSITION_TYPE_CHILD) {
- return mGroups.get(ExpandableListView.getPackedPositionGroup(packedPosition))
- .children.get(ExpandableListView.getPackedPositionChild(packedPosition))
- .name;
- } else if (type == ExpandableListView.PACKED_POSITION_TYPE_GROUP) {
- return mGroups.get(ExpandableListView.getPackedPositionGroup(packedPosition))
- .name;
- } else {
- throw new IllegalStateException("packedPosition is not a valid position.");
- }
- }
-
- /**
- * Whether a particular position is out of bounds.
- *
- * @param packedPosition The packed position.
- * @return Whether it's out of bounds.
- */
- private boolean isOutOfBounds(long packedPosition) {
- final int type = ExpandableListView.getPackedPositionType(packedPosition);
-
- if (type == ExpandableListView.PACKED_POSITION_TYPE_NULL) {
- throw new IllegalStateException("packedPosition is not a valid position.");
- }
-
- final int group = ExpandableListView.getPackedPositionGroup(packedPosition);
- if (group >= mGroups.size() || group < 0) {
- return true;
- }
-
- if (type == ExpandableListView.PACKED_POSITION_TYPE_CHILD) {
- final int child = ExpandableListView.getPackedPositionChild(packedPosition);
- if (child >= mGroups.get(group).children.size() || child < 0) {
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * Gets a view for the packed position, possibly reusing the convertView.
- *
- * @param packedPosition The position to get a view for.
- * @param convertView Optional view to convert.
- * @param parent The future parent.
- * @return A view.
- */
- private View getView(long packedPosition, View convertView, ViewGroup parent) {
- if (isOutOfBounds(packedPosition)) {
- throw new IllegalStateException("position out of range for adapter!");
- }
-
- final ExpandableListView elv = getExpandableListView();
- final int flPos = elv.getFlatListPosition(packedPosition);
-
- if (convertView != null) {
- ((TextView) convertView).setText(getValueAtPosition(packedPosition));
- convertView.setId(flPos);
- return convertView;
- }
-
- int desiredHeight = getHeightForPosition(flPos);
- return createView(packedPosition, flPos, parent, desiredHeight);
- }
-
- /**
- * Create a view for a group or child position.
- *
- * @param packedPosition The packed position (has type, group pos, and optionally child pos).
- * @param flPos The flat list position (the position that the ListView goes by).
- * @param parent The parent view.
- * @param desiredHeight The desired height.
- * @return A view.
- */
- protected View createView(long packedPosition, int flPos, ViewGroup parent, int desiredHeight) {
- TextView result = new TextView(parent.getContext());
- result.setHeight(desiredHeight);
- result.setText(getValueAtPosition(packedPosition));
- final ViewGroup.LayoutParams lp = new AbsListView.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT);
- result.setLayoutParams(lp);
- result.setGravity(Gravity.CENTER_VERTICAL);
- result.setPadding(36, 0, 0, 0);
- result.setId(flPos);
- return result;
- }
-
- /**
- * Returns a group index containing either the number of children or at
- * least one child.
- *
- * @param numChildren The group must have this amount, or -1 if using
- * atLeastOneChild.
- * @param atLeastOneChild The group must have at least one child, or false
- * if using numChildren.
- * @return A group index with the requirements.
- */
- public int findGroupWithNumChildren(int numChildren, boolean atLeastOneChild) {
- final ExpandableListAdapter adapter = mAdapter;
-
- for (int i = adapter.getGroupCount() - 1; i >= 0; i--) {
- final int curNumChildren = adapter.getChildrenCount(i);
-
- if (numChildren == curNumChildren || atLeastOneChild && curNumChildren > 0) {
- return i;
- }
- }
-
- return -1;
- }
-
- public List<MyGroup> getGroups() {
- return mGroups;
- }
-
- public ExpandableListAdapter getAdapter() {
- return mAdapter;
- }
-
- /**
- * Simple expandable list adapter.
- */
- protected class MyAdapter extends BaseExpandableListAdapter {
- public Object getChild(int groupPosition, int childPosition) {
- return getValueAtPosition(ExpandableListView.getPackedPositionForChild(groupPosition,
- childPosition));
- }
-
- public long getChildId(int groupPosition, int childPosition) {
- return mGroups.get(groupPosition).children.get(childPosition).id;
- }
-
- public int getChildrenCount(int groupPosition) {
- return mGroups.get(groupPosition).children.size();
- }
-
- public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
- View convertView, ViewGroup parent) {
- return getView(ExpandableListView.getPackedPositionForChild(groupPosition,
- childPosition), convertView, parent);
- }
-
- public Object getGroup(int groupPosition) {
- return getValueAtPosition(ExpandableListView.getPackedPositionForGroup(groupPosition));
- }
-
- public int getGroupCount() {
- return mGroups.size();
- }
-
- public long getGroupId(int groupPosition) {
- return mGroups.get(groupPosition).id;
- }
-
- public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
- ViewGroup parent) {
- return getView(ExpandableListView.getPackedPositionForGroup(groupPosition),
- convertView, parent);
- }
-
- public boolean isChildSelectable(int groupPosition, int childPosition) {
- return true;
- }
-
- public boolean hasStableIds() {
- return true;
- }
-
- }
-
- public static class MyGroup {
- private static long mNextId = 1000;
-
- String name;
- long id = mNextId++;
- List<MyChild> children;
-
- public MyGroup(int numChildren) {
- name = "Group " + id;
- children = new ArrayList<MyChild>(numChildren);
- for (int i = 0; i < numChildren; i++) {
- children.add(new MyChild());
- }
- }
- }
-
- public static class MyChild {
- private static long mNextId = 2000;
-
- String name;
- long id = mNextId++;
-
- public MyChild() {
- name = "Child " + id;
- }
- }
-
- @Override
- protected final void init(Params params) {
- init((ExpandableParams) params);
- }
-
- /**
- * @see ListScenario#init
- */
- protected abstract void init(ExpandableParams params);
-}
diff --git a/core/tests/coretests/src/android/util/PatternsTest.java b/core/tests/coretests/src/android/util/PatternsTest.java
index b90c97b..aad3fe1 100644
--- a/core/tests/coretests/src/android/util/PatternsTest.java
+++ b/core/tests/coretests/src/android/util/PatternsTest.java
@@ -68,6 +68,13 @@
t = Patterns.WEB_URL.matcher("xn--fsqu00a.xn--0zwm56d").matches();
assertTrue("Valid URL", t);
+ // Url for testing top level Arabic country code domain in Punycode:
+ // http://xn--4gbrim.xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c/ar/default.aspx
+ t = Patterns.WEB_URL.matcher("http://xn--4gbrim.xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c/ar/default.aspx").matches();
+ assertTrue("Valid URL", t);
+ t = Patterns.WEB_URL.matcher("xn--4gbrim.xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c/ar/default.aspx").matches();
+ assertTrue("Valid URL", t);
+
// Internationalized URL.
t = Patterns.WEB_URL.matcher("http://\uD604\uAE08\uC601\uC218\uC99D.kr").matches();
assertTrue("Valid URL", t);
@@ -109,7 +116,7 @@
t = Patterns.DOMAIN_NAME.matcher("mail.example.com").matches();
assertTrue("Valid domain", t);
- t = Patterns.WEB_URL.matcher("google.me").matches();
+ t = Patterns.DOMAIN_NAME.matcher("google.me").matches();
assertTrue("Valid domain", t);
// Internationalized domains.
@@ -118,6 +125,14 @@
t = Patterns.DOMAIN_NAME.matcher("__+&42.xer").matches();
assertFalse("Invalid domain", t);
+
+ // Obsolete domain .yu
+ t = Patterns.DOMAIN_NAME.matcher("test.yu").matches();
+ assertFalse("Obsolete country code top level domain", t);
+
+ // Testing top level Arabic country code domain in Punycode:
+ t = Patterns.DOMAIN_NAME.matcher("xn--4gbrim.xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c").matches();
+ assertTrue("Valid domain", t);
}
@SmallTest
diff --git a/core/tests/coretests/src/android/widget/expandablelistview/ExpandableListBasicTest.java b/core/tests/coretests/src/android/widget/expandablelistview/ExpandableListBasicTest.java
deleted file mode 100644
index e23b516..0000000
--- a/core/tests/coretests/src/android/widget/expandablelistview/ExpandableListBasicTest.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.widget.expandablelistview;
-
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.util.ExpandableListScenario;
-import android.util.ListUtil;
-import android.util.ExpandableListScenario.MyGroup;
-import android.view.KeyEvent;
-import android.widget.BaseExpandableListAdapter;
-import android.widget.ExpandableListAdapter;
-import android.widget.ExpandableListView;
-
-import java.util.List;
-
-public class ExpandableListBasicTest extends ActivityInstrumentationTestCase2<ExpandableListSimple> {
- private ExpandableListScenario mActivity;
- private ExpandableListView mExpandableListView;
- private ExpandableListAdapter mAdapter;
- private ListUtil mListUtil;
-
- public ExpandableListBasicTest() {
- super(ExpandableListSimple.class);
- }
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
- mActivity = getActivity();
- mExpandableListView = mActivity.getExpandableListView();
- mAdapter = mExpandableListView.getExpandableListAdapter();
- mListUtil = new ListUtil(mExpandableListView, getInstrumentation());
- }
-
- @MediumTest
- public void testPreconditions() {
- assertNotNull(mActivity);
- assertNotNull(mExpandableListView);
- }
-
- private int expandGroup(int numChildren, boolean atLeastOneChild) {
- final int groupPos = mActivity.findGroupWithNumChildren(numChildren, atLeastOneChild);
- assertTrue("Could not find group to expand", groupPos >= 0);
-
- assertFalse("Group is already expanded", mExpandableListView.isGroupExpanded(groupPos));
- mListUtil.arrowScrollToSelectedPosition(groupPos);
- getInstrumentation().waitForIdleSync();
- sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
- getInstrumentation().waitForIdleSync();
- assertTrue("Group did not expand", mExpandableListView.isGroupExpanded(groupPos));
-
- return groupPos;
- }
-
- @MediumTest
- public void testExpandGroup() {
- expandGroup(-1, true);
- }
-
- @MediumTest
- public void testCollapseGroup() {
- final int groupPos = expandGroup(-1, true);
-
- sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
- getInstrumentation().waitForIdleSync();
- assertFalse("Group did not collapse", mExpandableListView.isGroupExpanded(groupPos));
- }
-
- @MediumTest
- public void testExpandedGroupMovement() {
- // Expand the first group
- mListUtil.arrowScrollToSelectedPosition(0);
- sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
- getInstrumentation().waitForIdleSync();
-
- // Ensure it expanded
- assertTrue("Group did not expand", mExpandableListView.isGroupExpanded(0));
-
- // Wait until that's all good
- getInstrumentation().waitForIdleSync();
-
- // Make sure it expanded
- assertTrue("Group did not expand", mExpandableListView.isGroupExpanded(0));
-
- // Insert a collapsed group in front of the one just expanded
- List<MyGroup> groups = mActivity.getGroups();
- MyGroup insertedGroup = new MyGroup(1);
- groups.add(0, insertedGroup);
-
- // Notify data change
- assertTrue("Adapter is not an instance of the base adapter",
- mAdapter instanceof BaseExpandableListAdapter);
- final BaseExpandableListAdapter adapter = (BaseExpandableListAdapter) mAdapter;
-
- mActivity.runOnUiThread(new Runnable() {
- public void run() {
- adapter.notifyDataSetChanged();
- }
- });
- getInstrumentation().waitForIdleSync();
-
- // Make sure the right group is expanded
- assertTrue("The expanded state didn't stay with the proper group",
- mExpandableListView.isGroupExpanded(1));
- assertFalse("The expanded state was given to the inserted group",
- mExpandableListView.isGroupExpanded(0));
- }
-
- @MediumTest
- public void testContextMenus() {
- ExpandableListTester tester = new ExpandableListTester(mExpandableListView, this);
- tester.testContextMenus();
- }
-
- @MediumTest
- public void testConvertionBetweenFlatAndPacked() {
- ExpandableListTester tester = new ExpandableListTester(mExpandableListView, this);
- tester.testConvertionBetweenFlatAndPackedOnGroups();
- tester.testConvertionBetweenFlatAndPackedOnChildren();
- }
-
- @MediumTest
- public void testSelectedPosition() {
- ExpandableListTester tester = new ExpandableListTester(mExpandableListView, this);
- tester.testSelectedPositionOnGroups();
- tester.testSelectedPositionOnChildren();
- }
-}
diff --git a/core/tests/coretests/src/android/widget/expandablelistview/ExpandableListSimple.java b/core/tests/coretests/src/android/widget/expandablelistview/ExpandableListSimple.java
deleted file mode 100644
index 78db28c..0000000
--- a/core/tests/coretests/src/android/widget/expandablelistview/ExpandableListSimple.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.widget.expandablelistview;
-
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.MenuItem.OnMenuItemClickListener;
-import android.widget.BaseExpandableListAdapter;
-
-import android.util.ExpandableListScenario;
-
-public class ExpandableListSimple extends ExpandableListScenario {
- private static final int[] NUM_CHILDREN = {4, 3, 2, 1, 0};
-
- @Override
- protected void init(ExpandableParams params) {
- params.setNumChildren(NUM_CHILDREN)
- .setItemScreenSizeFactor(0.14);
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
-
- menu.add("Add item").setOnMenuItemClickListener(new OnMenuItemClickListener() {
- public boolean onMenuItemClick(MenuItem item) {
- mGroups.add(0, new MyGroup(2));
- ((BaseExpandableListAdapter) mAdapter).notifyDataSetChanged();
- return true;
- }
- });
-
- return true;
- }
-
-}
diff --git a/core/tests/coretests/src/android/widget/expandablelistview/ExpandableListTester.java b/core/tests/coretests/src/android/widget/expandablelistview/ExpandableListTester.java
deleted file mode 100644
index dfb10fb..0000000
--- a/core/tests/coretests/src/android/widget/expandablelistview/ExpandableListTester.java
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.widget.expandablelistview;
-
-import android.app.Instrumentation;
-import android.test.ActivityInstrumentationTestCase2;
-import android.util.ExpandableListScenario;
-import android.util.ListUtil;
-import android.view.KeyEvent;
-import android.view.View;
-import android.widget.ExpandableListAdapter;
-import android.widget.ExpandableListView;
-
-import junit.framework.Assert;
-
-public class ExpandableListTester {
- private final ExpandableListView mExpandableListView;
- private final ExpandableListAdapter mAdapter;
- private final ListUtil mListUtil;
-
- private final ActivityInstrumentationTestCase2<? extends ExpandableListScenario>
- mActivityInstrumentation;
-
- Instrumentation mInstrumentation;
-
- public ExpandableListTester(
- ExpandableListView expandableListView,
- ActivityInstrumentationTestCase2<? extends ExpandableListScenario>
- activityInstrumentation) {
- mExpandableListView = expandableListView;
- Instrumentation instrumentation = activityInstrumentation.getInstrumentation();
- mListUtil = new ListUtil(mExpandableListView, instrumentation);
- mAdapter = mExpandableListView.getExpandableListAdapter();
- mActivityInstrumentation = activityInstrumentation;
- mInstrumentation = mActivityInstrumentation.getInstrumentation();
- }
-
- private void expandGroup(final int groupIndex, int flatPosition) {
- Assert.assertFalse("Group is already expanded", mExpandableListView
- .isGroupExpanded(groupIndex));
- mListUtil.arrowScrollToSelectedPosition(flatPosition);
- mInstrumentation.waitForIdleSync();
- mActivityInstrumentation.sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
- mActivityInstrumentation.getInstrumentation().waitForIdleSync();
- Assert.assertTrue("Group did not expand " + groupIndex,
- mExpandableListView.isGroupExpanded(groupIndex));
- }
-
- void testContextMenus() {
- // Add a position tester ContextMenu listener to the ExpandableListView
- PositionTesterContextMenuListener menuListener = new PositionTesterContextMenuListener();
- mExpandableListView.setOnCreateContextMenuListener(menuListener);
-
- int index = 0;
-
- // Scrolling on header elements should trigger an AdapterContextMenu
- for (int i=0; i<mExpandableListView.getHeaderViewsCount(); i++) {
- // Check group index in context menu
- menuListener.expectAdapterContextMenu(i);
- // Make sure the group is visible so that getChild finds it
- mListUtil.arrowScrollToSelectedPosition(index);
- View headerChild = mExpandableListView.getChildAt(index
- - mExpandableListView.getFirstVisiblePosition());
- mExpandableListView.showContextMenuForChild(headerChild);
- mInstrumentation.waitForIdleSync();
- Assert.assertNull(menuListener.getErrorMessage(), menuListener.getErrorMessage());
- index++;
- }
-
- int groupCount = mAdapter.getGroupCount();
- for (int groupIndex = 0; groupIndex < groupCount; groupIndex++) {
-
- // Expand group
- expandGroup(groupIndex, index);
-
- // Check group index in context menu
- menuListener.expectGroupContextMenu(groupIndex);
- // Make sure the group is visible so that getChild finds it
- mListUtil.arrowScrollToSelectedPosition(index);
- View groupChild = mExpandableListView.getChildAt(index
- - mExpandableListView.getFirstVisiblePosition());
- mExpandableListView.showContextMenuForChild(groupChild);
- mInstrumentation.waitForIdleSync();
- Assert.assertNull(menuListener.getErrorMessage(), menuListener.getErrorMessage());
- index++;
-
- final int childrenCount = mAdapter.getChildrenCount(groupIndex);
- for (int childIndex = 0; childIndex < childrenCount; childIndex++) {
- // Check child index in context menu
- mListUtil.arrowScrollToSelectedPosition(index);
- menuListener.expectChildContextMenu(groupIndex, childIndex);
- View child = mExpandableListView.getChildAt(index
- - mExpandableListView.getFirstVisiblePosition());
- mExpandableListView.showContextMenuForChild(child);
- mInstrumentation.waitForIdleSync();
- Assert.assertNull(menuListener.getErrorMessage(), menuListener.getErrorMessage());
- index++;
- }
- }
-
- // Scrolling on footer elements should trigger an AdapterContextMenu
- for (int i=0; i<mExpandableListView.getFooterViewsCount(); i++) {
- // Check group index in context menu
- menuListener.expectAdapterContextMenu(index);
- // Make sure the group is visible so that getChild finds it
- mListUtil.arrowScrollToSelectedPosition(index);
- View footerChild = mExpandableListView.getChildAt(index
- - mExpandableListView.getFirstVisiblePosition());
- mExpandableListView.showContextMenuForChild(footerChild);
- mInstrumentation.waitForIdleSync();
- Assert.assertNull(menuListener.getErrorMessage(), menuListener.getErrorMessage());
- index++;
- }
-
- // Cleanup: remove the listener we added.
- mExpandableListView.setOnCreateContextMenuListener(null);
- }
-
- private int expandAGroup() {
- final int groupIndex = 2;
- final int headerCount = mExpandableListView.getHeaderViewsCount();
- Assert.assertTrue("Not enough groups", groupIndex < mAdapter.getGroupCount());
- expandGroup(groupIndex, groupIndex + headerCount);
- return groupIndex;
- }
-
- // This method assumes that NO group is expanded when called
- void testConvertionBetweenFlatAndPackedOnGroups() {
- final int headerCount = mExpandableListView.getHeaderViewsCount();
-
- for (int i=0; i<headerCount; i++) {
- Assert.assertEquals("Non NULL position for header item",
- ExpandableListView.PACKED_POSITION_VALUE_NULL,
- mExpandableListView.getExpandableListPosition(i));
- }
-
- // Test all (non expanded) groups
- final int groupCount = mAdapter.getGroupCount();
- for (int groupIndex = 0; groupIndex < groupCount; groupIndex++) {
- int expectedFlatPosition = headerCount + groupIndex;
- long packedPositionForGroup = ExpandableListView.getPackedPositionForGroup(groupIndex);
- Assert.assertEquals("Group not found at flat position " + expectedFlatPosition,
- packedPositionForGroup,
- mExpandableListView.getExpandableListPosition(expectedFlatPosition));
-
- Assert.assertEquals("Wrong flat position for group " + groupIndex,
- expectedFlatPosition,
- mExpandableListView.getFlatListPosition(packedPositionForGroup));
- }
-
- for (int i=0; i<mExpandableListView.getFooterViewsCount(); i++) {
- Assert.assertEquals("Non NULL position for header item",
- ExpandableListView.PACKED_POSITION_VALUE_NULL,
- mExpandableListView.getExpandableListPosition(headerCount + groupCount + i));
- }
- }
-
- // This method assumes that NO group is expanded when called
- void testConvertionBetweenFlatAndPackedOnChildren() {
- // Test with an expanded group
- final int headerCount = mExpandableListView.getHeaderViewsCount();
- final int groupIndex = expandAGroup();
-
- final int childrenCount = mAdapter.getChildrenCount(groupIndex);
- for (int childIndex = 0; childIndex < childrenCount; childIndex++) {
- int expectedFlatPosition = headerCount + groupIndex + 1 + childIndex;
- long childPos = ExpandableListView.getPackedPositionForChild(groupIndex, childIndex);
-
- Assert.assertEquals("Wrong flat position for child ",
- childPos,
- mExpandableListView.getExpandableListPosition(expectedFlatPosition));
-
- Assert.assertEquals("Wrong flat position for child ",
- expectedFlatPosition,
- mExpandableListView.getFlatListPosition(childPos));
- }
- }
-
- // This method assumes that NO group is expanded when called
- void testSelectedPositionOnGroups() {
- int index = 0;
-
- // Scrolling on header elements should not give a valid selected position.
- for (int i=0; i<mExpandableListView.getHeaderViewsCount(); i++) {
- mListUtil.arrowScrollToSelectedPosition(index);
- Assert.assertEquals("Header item is selected",
- ExpandableListView.PACKED_POSITION_VALUE_NULL,
- mExpandableListView.getSelectedPosition());
- index++;
- }
-
- // Check selection on group items
- final int groupCount = mAdapter.getGroupCount();
- for (int groupIndex = 0; groupIndex < groupCount; groupIndex++) {
- mListUtil.arrowScrollToSelectedPosition(index);
- Assert.assertEquals("Group item is not selected",
- ExpandableListView.getPackedPositionForGroup(groupIndex),
- mExpandableListView.getSelectedPosition());
- index++;
- }
-
- // Scrolling on footer elements should not give a valid selected position.
- for (int i=0; i<mExpandableListView.getFooterViewsCount(); i++) {
- mListUtil.arrowScrollToSelectedPosition(index);
- Assert.assertEquals("Footer item is selected",
- ExpandableListView.PACKED_POSITION_VALUE_NULL,
- mExpandableListView.getSelectedPosition());
- index++;
- }
- }
-
- // This method assumes that NO group is expanded when called
- void testSelectedPositionOnChildren() {
- // Test with an expanded group
- final int headerCount = mExpandableListView.getHeaderViewsCount();
- final int groupIndex = expandAGroup();
-
- final int childrenCount = mAdapter.getChildrenCount(groupIndex);
- for (int childIndex = 0; childIndex < childrenCount; childIndex++) {
- int childFlatPosition = headerCount + groupIndex + 1 + childIndex;
- mListUtil.arrowScrollToSelectedPosition(childFlatPosition);
- Assert.assertEquals("Group item is not selected",
- ExpandableListView.getPackedPositionForChild(groupIndex, childIndex),
- mExpandableListView.getSelectedPosition());
- }
- }
-}
diff --git a/core/tests/coretests/src/android/widget/expandablelistview/ExpandableListWithHeaders.java b/core/tests/coretests/src/android/widget/expandablelistview/ExpandableListWithHeaders.java
deleted file mode 100644
index 2251c1d..0000000
--- a/core/tests/coretests/src/android/widget/expandablelistview/ExpandableListWithHeaders.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.widget.expandablelistview;
-
-import android.os.Bundle;
-import android.util.ExpandableListScenario;
-import android.widget.Button;
-import android.widget.ExpandableListView;
-
-public class ExpandableListWithHeaders extends ExpandableListScenario {
- private static final int[] sNumChildren = {1, 4, 3, 2, 6};
- private static final int sNumOfHeadersAndFooters = 12;
-
- @Override
- protected void init(ExpandableParams params) {
- params.setStackFromBottom(false)
- .setStartingSelectionPosition(-1)
- .setNumChildren(sNumChildren)
- .setItemScreenSizeFactor(0.14)
- .setConnectAdapter(false);
- }
-
- @Override
- protected void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- final ExpandableListView expandableListView = getExpandableListView();
- expandableListView.setItemsCanFocus(true);
-
- for (int i = 0; i < sNumOfHeadersAndFooters; i++) {
- Button header = new Button(this);
- header.setText("Header View " + i);
- expandableListView.addHeaderView(header);
- }
-
- for (int i = 0; i < sNumOfHeadersAndFooters; i++) {
- Button footer = new Button(this);
- footer.setText("Footer View " + i);
- expandableListView.addFooterView(footer);
- }
-
- // Set adapter here AFTER we set header and footer views
- setAdapter(expandableListView);
- }
-
- /**
- * @return The number of headers (and the same number of footers)
- */
- public int getNumOfHeadersAndFooters() {
- return sNumOfHeadersAndFooters;
- }
-
-}
diff --git a/core/tests/coretests/src/android/widget/expandablelistview/ExpandableListWithHeadersTest.java b/core/tests/coretests/src/android/widget/expandablelistview/ExpandableListWithHeadersTest.java
deleted file mode 100644
index 64a0fff..0000000
--- a/core/tests/coretests/src/android/widget/expandablelistview/ExpandableListWithHeadersTest.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.widget.expandablelistview;
-
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.util.ListUtil;
-import android.view.KeyEvent;
-import android.widget.ExpandableListView;
-
-public class ExpandableListWithHeadersTest extends
- ActivityInstrumentationTestCase2<ExpandableListWithHeaders> {
- private ExpandableListView mExpandableListView;
- private ListUtil mListUtil;
-
- public ExpandableListWithHeadersTest() {
- super(ExpandableListWithHeaders.class);
- }
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
- mExpandableListView = getActivity().getExpandableListView();
- mListUtil = new ListUtil(mExpandableListView, getInstrumentation());
- }
-
- @MediumTest
- public void testPreconditions() {
- assertNotNull(mExpandableListView);
- }
-
- @MediumTest
- public void testExpandOnFirstPosition() {
- // Should be a header, and hence the first group should NOT have expanded
- mListUtil.arrowScrollToSelectedPosition(0);
- sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
- getInstrumentation().waitForIdleSync();
- assertFalse(mExpandableListView.isGroupExpanded(0));
- }
-
- @LargeTest
- public void testExpandOnFirstGroup() {
- mListUtil.arrowScrollToSelectedPosition(getActivity().getNumOfHeadersAndFooters());
- sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
- getInstrumentation().waitForIdleSync();
- assertTrue(mExpandableListView.isGroupExpanded(0));
- }
-
- @MediumTest
- public void testContextMenus() {
- ExpandableListTester tester = new ExpandableListTester(mExpandableListView, this);
- tester.testContextMenus();
- }
-
- @MediumTest
- public void testConvertionBetweenFlatAndPacked() {
- ExpandableListTester tester = new ExpandableListTester(mExpandableListView, this);
- tester.testConvertionBetweenFlatAndPackedOnGroups();
- tester.testConvertionBetweenFlatAndPackedOnChildren();
- }
-
- @MediumTest
- public void testSelectedPosition() {
- ExpandableListTester tester = new ExpandableListTester(mExpandableListView, this);
- tester.testSelectedPositionOnGroups();
- tester.testSelectedPositionOnChildren();
- }
-}
diff --git a/core/tests/coretests/src/android/widget/expandablelistview/InflatedExpandableListView.java b/core/tests/coretests/src/android/widget/expandablelistview/InflatedExpandableListView.java
deleted file mode 100644
index f4c9d56..0000000
--- a/core/tests/coretests/src/android/widget/expandablelistview/InflatedExpandableListView.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.widget.expandablelistview;
-
-import com.android.frameworks.coretests.R;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.Gravity;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AbsListView;
-import android.widget.BaseExpandableListAdapter;
-import android.widget.ExpandableListView;
-import android.widget.TextView;
-
-public class InflatedExpandableListView extends Activity {
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- setContentView(R.layout.inflated_expandablelistview);
-
- ExpandableListView elv = (ExpandableListView) findViewById(R.id.elv);
- elv.setAdapter(new MyExpandableListAdapter());
- }
-
- public class MyExpandableListAdapter extends BaseExpandableListAdapter {
- // Sample data set. children[i] contains the children (String[]) for groups[i].
- private String[] groups = { "People Names", "Dog Names", "Cat Names", "Fish Names" };
- private String[][] children = {
- { "Arnold", "Barry", "Chuck", "David" },
- { "Ace", "Bandit", "Cha-Cha", "Deuce" },
- { "Fluffy", "Snuggles" },
- { "Goldy", "Bubbles" }
- };
-
- public Object getChild(int groupPosition, int childPosition) {
- return children[groupPosition][childPosition];
- }
-
- public long getChildId(int groupPosition, int childPosition) {
- return childPosition;
- }
-
- public int getChildrenCount(int groupPosition) {
- return children[groupPosition].length;
- }
-
- public TextView getGenericView() {
- // Layout parameters for the ExpandableListView
- AbsListView.LayoutParams lp = new AbsListView.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT, 64);
-
- TextView textView = new TextView(InflatedExpandableListView.this);
- textView.setLayoutParams(lp);
- // Center the text vertically
- textView.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
- // Set the text starting position
- textView.setPadding(36, 0, 0, 0);
- return textView;
- }
-
- public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
- View convertView, ViewGroup parent) {
- TextView textView = getGenericView();
- textView.setText(getChild(groupPosition, childPosition).toString());
- return textView;
- }
-
- public Object getGroup(int groupPosition) {
- return groups[groupPosition];
- }
-
- public int getGroupCount() {
- return groups.length;
- }
-
- public long getGroupId(int groupPosition) {
- return groupPosition;
- }
-
- public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
- ViewGroup parent) {
- TextView textView = getGenericView();
- textView.setText(getGroup(groupPosition).toString());
- return textView;
- }
-
- public boolean isChildSelectable(int groupPosition, int childPosition) {
- return true;
- }
-
- public boolean hasStableIds() {
- return true;
- }
-
- }
-
-}
diff --git a/core/tests/coretests/src/android/widget/expandablelistview/PositionTesterContextMenuListener.java b/core/tests/coretests/src/android/widget/expandablelistview/PositionTesterContextMenuListener.java
deleted file mode 100644
index 2dbdff8..0000000
--- a/core/tests/coretests/src/android/widget/expandablelistview/PositionTesterContextMenuListener.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.widget.expandablelistview;
-
-import android.view.ContextMenu;
-import android.view.View;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.view.View.OnCreateContextMenuListener;
-import android.widget.ExpandableListView;
-import android.widget.AdapterView.AdapterContextMenuInfo;
-
-public class PositionTesterContextMenuListener implements OnCreateContextMenuListener {
-
- private int groupPosition, childPosition;
-
- // Fake constant to store in testType a test type specific to headers and footers
- private static final int ADAPTER_TYPE = -1;
- private int testType; // as returned by getPackedPositionType
-
- // Will be set to null by each call to onCreateContextMenu, unless an error occurred.
- private String errorMessage;
-
- public void expectGroupContextMenu(int groupPosition) {
- this.groupPosition = groupPosition;
- testType = ExpandableListView.PACKED_POSITION_TYPE_GROUP;
- }
-
- public void expectChildContextMenu(int groupPosition, int childPosition) {
- this.groupPosition = groupPosition;
- this.childPosition = childPosition;
- testType = ExpandableListView.PACKED_POSITION_TYPE_CHILD;
- }
-
- public void expectAdapterContextMenu(int flatPosition) {
- this.groupPosition = flatPosition;
- testType = ADAPTER_TYPE;
- }
-
- public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
- errorMessage = null;
- if (testType == ADAPTER_TYPE) {
- if (!isTrue("MenuInfo is not an AdapterContextMenuInfo",
- menuInfo instanceof AdapterContextMenuInfo)) {
- return;
- }
- AdapterContextMenuInfo adapterContextMenuInfo = (AdapterContextMenuInfo) menuInfo;
- if (!areEqual("Wrong flat position", groupPosition, adapterContextMenuInfo.position)) {
- return;
- }
- } else {
- if (!isTrue("MenuInfo is not an ExpandableListContextMenuInfo",
- menuInfo instanceof ExpandableListView.ExpandableListContextMenuInfo)) {
- return;
- }
- ExpandableListView.ExpandableListContextMenuInfo elvMenuInfo =
- (ExpandableListView.ExpandableListContextMenuInfo) menuInfo;
- long packedPosition = elvMenuInfo.packedPosition;
-
- int packedPositionType = ExpandableListView.getPackedPositionType(packedPosition);
- if (!areEqual("Wrong packed position type", testType, packedPositionType)) {
- return;
- }
-
- int packedPositionGroup = ExpandableListView.getPackedPositionGroup(packedPosition);
- if (!areEqual("Wrong group position", groupPosition, packedPositionGroup)) {
- return;
- }
-
- if (testType == ExpandableListView.PACKED_POSITION_TYPE_CHILD) {
- int packedPositionChild = ExpandableListView.getPackedPositionChild(packedPosition);
- if (!areEqual("Wrong child position", childPosition, packedPositionChild)) {
- return;
- }
- }
- }
- }
-
- private boolean areEqual(String message, int expected, int actual) {
- if (expected != actual) {
- errorMessage = String.format(message + " (%d vs %d", expected, actual);
- return false;
- }
- return true;
- }
-
- private boolean isTrue(String message, boolean value) {
- if (!value) {
- errorMessage = message;
- return false;
- }
- return true;
- }
-
- public String getErrorMessage() {
- return errorMessage;
- }
-}
diff --git a/core/tests/hosttests/src/android/content/pm/PackageManagerHostTestUtils.java b/core/tests/hosttests/src/android/content/pm/PackageManagerHostTestUtils.java
index 91cbe2f..19c9d26 100644
--- a/core/tests/hosttests/src/android/content/pm/PackageManagerHostTestUtils.java
+++ b/core/tests/hosttests/src/android/content/pm/PackageManagerHostTestUtils.java
@@ -124,7 +124,11 @@
RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(
pkgName, mDevice);
CollectingTestRunListener listener = new CollectingTestRunListener();
- testRunner.run(listener);
+ try {
+ testRunner.run(listener);
+ } catch (IOException ioe) {
+ Log.w(LOG_TAG, "encountered IOException " + ioe);
+ }
return listener;
}
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 7322e6c..0e5df8c 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -58,6 +58,10 @@
<group gid="sdcard_rw" />
</permission>
+ <permission name="android.permission.ACCESS_USB" >
+ <group gid="usb" />
+ </permission>
+
<!-- The group that /cache belongs to, linked to the permission
set on the applications that can access /cache -->
<permission name="android.permission.ACCESS_CACHE_FILESYSTEM" >
diff --git a/docs/html/guide/topics/testing/testing_android.jd b/docs/html/guide/topics/testing/testing_android.jd
index 46ba769..9ace1cb 100755
--- a/docs/html/guide/topics/testing/testing_android.jd
+++ b/docs/html/guide/topics/testing/testing_android.jd
@@ -23,9 +23,9 @@
<li>
<a href="#MockObjects">Mock object classes</a>
</li>
- <li>
- <a href="#InstrumentationTestRunner">Instrumentation Test Runner</a>
- </li>
+ <li>
+ <a href="#InstrumentationTestRunner">Instrumentation Test Runner</a>
+ </li>
</ol>
</li>
<li>
@@ -64,7 +64,8 @@
<h2>Related Tutorials</h2>
<ol>
<li>
- <a href="{@docRoot}resources/tutorials/testing/helloandroid_test.html">Hello, Testing</a>
+ <a href="{@docRoot}resources/tutorials/testing/helloandroid_test.html">
+ Hello, Testing</a>
</li>
<li>
<a href="{@docRoot}resources/tutorials/testing/activity_test.html">Activity Testing</a>
@@ -73,10 +74,12 @@
<h2>See Also</h2>
<ol>
<li>
- <a href="{@docRoot}guide/developing/testing/testing_eclipse.html">Testing in Eclipse, with ADT</a>
+ <a href="{@docRoot}guide/developing/testing/testing_eclipse.html">
+ Testing in Eclipse, with ADT</a>
</li>
<li>
- <a href="{@docRoot}guide/developing/testing/testing_otheride.html">Testing in Other IDEs</a>
+ <a href="{@docRoot}guide/developing/testing/testing_otheride.html">
+ Testing in Other IDEs</a>
</li>
</ol>
</div>
@@ -118,45 +121,55 @@
in the same process. </p>
<p>Your test application is linked to the application under test by means of an
-<a
-href="{@docRoot}guide/topics/manifest/instrumentation-element.html"><code><instrumentation></code></a>
-element in the test application's manifest file. The attributes of the element
-specify the package name of the application under test and also tell Android how
-to run the test application. Instrumentation is described in more detail in the
-section <a href="#InstrumentationTestRunner">Instrumentation Test
-Runner</a>.</p>
+ <a
+ href="{@docRoot}guide/topics/manifest/instrumentation-element.html">
+ <code><instrumentation></code></a> element in the test application's manifest file.
+ The attributes of the element specify the package name of the application under test and also
+ tell Android how to run the test application. Instrumentation is described in more detail
+ in the section <a href="#InstrumentationTestRunner">Instrumentation Test Runner</a>.
+</p>
<p>The following diagram summarizes the Android testing environment:</p>
<img src="{@docRoot}images/testing/android_test_framework.png"/>
-<p>In Android, test applications are themselves Android applications, so you
-write them in much the same way as the application you are testing. The SDK
-tools help you create a main application project and its test project at the same
-time. You can run Android tests within Eclipse with ADT or from the command
-line. Eclipse with ADT provides an extensive set of tools for creating tests,
-running them, and viewing their results. You can also use the <code>adb</code>
-tool to run tests, or use a built-in Ant target.</p>
+<p>
+ In Android, test applications are themselves Android applications, so you
+ write them in much the same way as the application you are testing. The SDK
+ tools help you create a main application project and its test project at the same
+ time. You can run Android tests within Eclipse with ADT or from the command
+ line. Eclipse with ADT provides an extensive set of tools for creating tests,
+ running them, and viewing their results. You can also use the <code>adb</code>
+ tool to run tests, or use a built-in Ant target.
+</p>
-<p>To learn how to set up and run tests in Eclipse, please refer to <a
-href="{@docRoot}guide/developing/testing/testing_eclipse.html">Testing in
-Eclipse, with ADT</a>. If you're not working in Eclipse, refer to <a
-href="{@docRoot}guide/developing/testing/testing_otheride.html">Testing in Other
-IDEs</a>.</p>
+<p>
+ To learn how to set up and run tests in Eclipse, please refer to <a
+ href="{@docRoot}guide/developing/testing/testing_eclipse.html">Testing in
+ Eclipse, with ADT</a>. If you're not working in Eclipse, refer to <a
+ href="{@docRoot}guide/developing/testing/testing_otheride.html">Testing in Other
+ IDEs</a>.
+</p>
-<p>If you want a step-by-step introduction to Android testing, try one of the
-testing tutorials:</p>
+<p>
+ If you want a step-by-step introduction to Android testing, try one of the
+ testing tutorials:
+</p>
<ul>
- <li>The <a
-href="{@docRoot}resources/tutorials/testing/helloandroid_test.html">Hello,
-Testing</a> tutorial introduces basic testing concepts and procedures in the
-context of the Hello, World application.</li>
- <li>The <a
-href="{@docRoot}resources/tutorials/testing/activity_test.html">Activity
-Testing</a> tutorial is an excellent follow-up to the Hello, Testing tutorial.
-It guides you through a more complex testing scenario that you develop against a
-more realistic application.</li>
+ <li>
+ The <a
+ href="{@docRoot}resources/tutorials/testing/helloandroid_test.html">Hello,
+ Testing</a> tutorial introduces basic testing concepts and procedures in the
+ context of the Hello, World application.
+ </li>
+ <li>
+ The <a
+ href="{@docRoot}resources/tutorials/testing/activity_test.html">Activity
+ Testing</a> tutorial is an excellent follow-up to the Hello, Testing tutorial.
+ It guides you through a more complex testing scenario that you develop against a
+ more realistic application.
+ </li>
</ul>
<h2 id="TestAPI">The Testing API</h2>
@@ -166,120 +179,156 @@
a powerful instrumentation framework that lets your tests access the state and runtime objects
of the application under tests.
</p>
-<p>The sections below describe the major components of the testing API available in Android.</p>
+<p>
+ The sections below describe the major components of the testing API available in Android.
+</p>
<h3 id="Extensions">JUnit test case classes</h3>
<p>
- Some of the classes in the testing API extend the JUnit {@link junit.framework.TestCase TestCase} but do not use the instrumentation framework. These classes
- contain methods for accessing system objects such as the Context of the application under test. With this Context, you can look at its resources, files, databases,
- and so forth. The base class is {@link android.test.AndroidTestCase}, but you usually use a subclass associated with a particular component.
+ Some of the classes in the testing API extend the JUnit {@link junit.framework.TestCase TestCase}
+ but do not use the instrumentation framework. These classes contain methods for accessing system
+ objects such as the Context of the application under test. With this Context, you can look at its
+ resources, files, databases, and so forth. The base class is {@link android.test.AndroidTestCase},
+ but you usually use a subclass associated with a particular component.
<p>
The subclasses are:
</p>
<ul>
<li>
- {@link android.test.ApplicationTestCase} - A class for testing an entire application. It allows you to inject a mock Context into the application,
- set up initial test parameters before the application starts, and examine the application after it finishes but before it is destroyed.
+ {@link android.test.ApplicationTestCase} - A class for testing an entire application.
+ It allows you to inject a mock Context into the application, set up initial test parameters
+ before the application starts, and examine the application after it finishes but before it
+ is destroyed.
</li>
<li>
- {@link android.test.ProviderTestCase2} - A class for isolated testing of a single {@link android.content.ContentProvider}. Since it is restricted to using a
- {@link android.test.mock.MockContentResolver} for the provider, and it injects an {@link android.test.IsolatedContext}, your provider testing is isolated
+ {@link android.test.ProviderTestCase2} - A class for isolated testing of a single
+ {@link android.content.ContentProvider}. Since it is restricted to using a
+ {@link android.test.mock.MockContentResolver} for the provider, and it injects an
+ {@link android.test.IsolatedContext}, your provider testing is isolated
from the rest of the OS.
</li>
<li>
- {@link android.test.ServiceTestCase} - a class for isolated testing of a single {@link android.app.Service}. You can inject a mock Context or
- mock Application (or both), or let Android provide you a full Context and a {@link android.test.mock.MockApplication}.
+ {@link android.test.ServiceTestCase} - a class for isolated testing of a single
+ {@link android.app.Service}. You can inject a mock Context or mock Application (or both), or
+ let Android provide you a full Context and a {@link android.test.mock.MockApplication}.
</li>
</ul>
<h3 id="Instrumentation">Instrumentation test case classes</h3>
<p>
- The API for testing activities extends the JUnit {@link junit.framework.TestCase TestCase} class and also uses the instrumentation framework. With instrumentation,
- Android can automate UI testing by sending events to the application under test, precisely control the start of an activity, and monitor the state of the
- activity during its life cycle.
+ The API for testing activities extends the JUnit {@link junit.framework.TestCase TestCase} class
+ and also uses the instrumentation framework. With instrumentation, Android can automate UI
+ testing by sending events to the application under test, precisely control the start of an
+ activity, and monitor the state of the activity during its life cycle.
</p>
<p>
- The base class is {@link android.test.InstrumentationTestCase}. All of its subclasses have the ability to send a keystroke or touch event to the UI of the application
- under test. The subclasses can also inject a mock Intent.
- The subclasses are:
+ The base class is {@link android.test.InstrumentationTestCase}. All of its subclasses have
+ the ability to send a keystroke or touch event to the UI of the application
+ under test. The subclasses can also inject a mock Intent. The subclasses are:
</p>
<ul>
<li>
{@link android.test.ActivityTestCase} - A base class for activity test classes.
</li>
<li>
- {@link android.test.SingleLaunchActivityTestCase} - A convenience class for testing a single activity.
- It invokes {@link junit.framework.TestCase#setUp() setUp()} and {@link junit.framework.TestCase#tearDown() tearDown()} only
- once, instead of once per method call. Use it when all of your test methods run against the same activity.
+ {@link android.test.SingleLaunchActivityTestCase} - A convenience class for
+ testing a single activity. It invokes {@link junit.framework.TestCase#setUp() setUp()} and
+ {@link junit.framework.TestCase#tearDown() tearDown()} only once, instead of once per
+ method call. Use it when all of your test methods run against the same activity.
</li>
<li>
- {@link android.test.SyncBaseInstrumentation} - A class that tests synchronization of a content provider. It uses instrumentation to cancel and disable
- existing synchronizations before starting the test synchronization.
+ {@link android.test.SyncBaseInstrumentation} - A class that tests synchronization of a
+ content provider. It uses instrumentation to cancel and disable existing synchronizations
+ before starting the test synchronization.
</li>
<li>
- {@link android.test.ActivityUnitTestCase} - This class does an isolated test of a single activity. With it, you can inject a mock context or application, or both.
- It is intended for doing unit tests of an activity, and is the activity equivalent of the test classes described in <a href="#Extensions">JUnit test case classes</a>.
- <p> Unlike the other instrumentation classes, this test class cannot inject a mock Intent.</p>
+ {@link android.test.ActivityUnitTestCase} - This class does an isolated test of a single
+ activity. With it, you can inject a mock context or application, or both.
+ It is intended for doing unit tests of an activity, and is the activity equivalent of the
+ test classes described in <a href="#Extensions">JUnit test case classes</a>.
+ <p>
+ Unlike the other instrumentation classes, this test class cannot inject a mock Intent.
+ </p>
</li>
<li>
- {@link android.test.ActivityInstrumentationTestCase2} - This class tests a single activity within the normal system environment.
- You cannot inject a mock Context, but you can inject mock Intents. Also, you can run a test method on the UI thread (the main thread of the application under test),
- which allows you to send key and touch events to the application UI.
+ {@link android.test.ActivityInstrumentationTestCase2} - This class tests a single activity
+ within the normal system environment. You cannot inject a mock Context, but you can inject
+ mock Intents. Also, you can run a test method on the UI thread (the main thread of the
+ application under test), which allows you to send key and touch events to the
+ application UI.
</li>
</ul>
<h3 id="Assert">Assert classes</h3>
<p>
- Android also extends the JUnit {@link junit.framework.Assert} class that is the basis of <code>assert()</code> calls in tests.
- There are two extensions to this class, {@link android.test.MoreAsserts} and {@link android.test.ViewAsserts}:
+ Android also extends the JUnit {@link junit.framework.Assert} class that is the basis of
+ <code>assert()</code> calls in tests. There are two extensions to this class,
+ {@link android.test.MoreAsserts} and {@link android.test.ViewAsserts}:
</p>
<ul>
<li>
- The <code>MoreAsserts</code> class contains more powerful assertions such as {@link android.test.MoreAsserts#assertContainsRegex} that does regular expression matching.
+ The <code>MoreAsserts</code> class contains more powerful assertions such as
+ {@link android.test.MoreAsserts#assertContainsRegex} that does regular expression matching.
</li>
<li>
- The {@link android.test.ViewAsserts} class contains useful assertions about Android Views, such as {@link android.test.ViewAsserts#assertHasScreenCoordinates} that tests if a View has a particular X and Y
- position on the visible screen. These asserts simplify testing of geometry and alignment in the UI.
+ The {@link android.test.ViewAsserts} class contains useful assertions about Android Views,
+ such as {@link android.test.ViewAsserts#assertHasScreenCoordinates} that tests if a View has a
+ particular X and Y position on the visible screen. These asserts simplify testing of geometry
+ and alignment in the UI.
</li>
</ul>
<h3 id="MockObjects">Mock object classes</h3>
<p>
- Android has convenience classes for creating mock system objects such as applications, contexts, content resolvers, and resources. Android also provides
- methods in some test classes for creating mock Intents. Use these mocks to facilitate dependency injection, since they are easier to use than creating their
- real counterparts. These convenience classes are found in {@link android.test} and {@link android.test.mock}. They are:
+ Android has convenience classes for creating mock system objects such as applications, contexts,
+ content resolvers, and resources. Android also provides methods in some test classes for
+ creating mock Intents. Use these mocks to facilitate dependency injection, since they are
+ easier to use than creating their real counterparts. These convenience classes are found in
+ {@link android.test} and {@link android.test.mock}. They are:
</p>
<ul>
<li>
- {@link android.test.IsolatedContext} - Mocks a Context so that the application using it runs in isolation.
- At the same time, it has enough stub code to satisfy OS code that tries to communicate with contexts. This class is useful in unit testing.
+ {@link android.test.IsolatedContext} - Mocks a Context so that the application using it
+ runs in isolation. At the same time, it has enough stub code to satisfy OS code that tries
+ to communicate with contexts. This class is useful in unit testing.
</li>
<li>
- {@link android.test.RenamingDelegatingContext} - Delegates most context functions to an existing, normal context while changing the default file and database
- names in the context. Use this to test file and database operations with a normal system context, using test names.
+ {@link android.test.RenamingDelegatingContext} - Delegates most context functions to an
+ existing, normal context while changing the default file and database
+ names in the context. Use this to test file and database operations with a normal system
+ context, using test names.
</li>
<li>
- {@link android.test.mock.MockApplication}, {@link android.test.mock.MockContentResolver}, {@link android.test.mock.MockContext},
- {@link android.test.mock.MockDialogInterface}, {@link android.test.mock.MockPackageManager},
- {@link android.test.mock.MockResources} - Classes that create mock Android system objects for use in testing. They expose only those methods that are
- useful in managing the object. The default implementations of these methods simply throw an Exception. You are expected to extend the classes and
- override any methods that are called by the application under test.
+ {@link android.test.mock.MockApplication}, {@link android.test.mock.MockContentResolver},
+ {@link android.test.mock.MockContext}, {@link android.test.mock.MockDialogInterface},
+ {@link android.test.mock.MockPackageManager}, {@link android.test.mock.MockResources} -
+ Classes that create mock Android system objects for use in testing. They expose only those
+ methods that are useful in managing the object. The default implementations of these methods
+ simply throw an Exception. You are expected to extend the classes and override any methods '
+ that are called by the application under test.
</li>
</ul>
<h3 id="InstrumentationTestRunner">Instrumentation Test Runner</h3>
<p>
Android provides a custom class for running tests with instrumentation called called
{@link android.test.InstrumentationTestRunner}. This class
- controls of the application under test, runs the test application and the main application in the same process, and routes
- test output to the appropriate place. Using instrumentation is key to the ability of <code>InstrumentationTestRunner</code> to control the entire test
- environment at runtime. Notice that you use this test runner even if your test class does not itself use instrumentation.
+ controls of the application under test, runs the test application and the main application in the
+ same process, and routes test output to the appropriate place. Using instrumentation is key to the
+ ability of <code>InstrumentationTestRunner</code> to control the entire test
+ environment at runtime. Notice that you use this test runner even if your test class does not
+ itself use instrumentation.
</p>
<p>
- When you run a test application, you first run a system utility called Activity Manager. Activity Manager uses the instrumentation framework to start and control the test runner, which in turn uses instrumentation to shut down any running instances
- of the main application, starts the test application, and then starts the main application in the same process. This allows various aspects of the test application to work directly with the main application.
+ When you run a test application, you first run a system utility called Activity Manager. Activity
+ Manager uses the instrumentation framework to start and control the test runner, which in turn
+ uses instrumentation to shut down any running instances of the main application, starts the test
+ application, and then starts the main application in the same process. This allows various
+ aspects of the test application to work directly with the main application.
</p>
<p>
- If you are developing in Eclipse, the ADT plugin assists you in the setup of <code>InstrumentationTestRunner</code> or other test runners.
- The plugin UI prompts you to specify the test runner class to use, as well as the package name of the application under test.
- The plugin then adds an <code><instrumentation></code> element with appropriate attributes to the manifest file of the test application.
- Eclipse with ADT automatically starts a test application under the control of Activity Manager using instrumentation,
- and redirects the test output to the Eclipse window's JUnit view.
+ If you are developing in Eclipse, the ADT plugin assists you in the setup of
+ <code>InstrumentationTestRunner</code> or other test runners. The plugin UI prompts you to specify
+ the test runner class to use, as well as the package name of the application under test.
+ The plugin then adds an <code><instrumentation></code> element with appropriate attributes
+ to the manifest file of the test application. Eclipse with ADT automatically starts a test
+ application under the control of Activity Manager using instrumentation, and redirects the test
+ output to the Eclipse window's JUnit view.
</p>
<p>
If you prefer working from the command line, you can use Ant and the <code>android</code>
@@ -289,68 +338,105 @@
</p>
<h2 id="TestEnviroment">Working in the Test Environment</h2>
<p>
- The tests for an Android application are contained in a test application, which itself is an Android application. A test application resides in a separate Android project that has the
- same files and directories as a regular Android application. The test project is linked to the project of the application it tests
- (known as the application under test) by its manifest file.
+ The tests for an Android application are contained in a test application, which itself is an
+ Android application. A test application resides in a separate Android project that has the
+ same files and directories as a regular Android application. The test project is linked to the
+ project of the application it tests (known as the application under test) by its manifest file.
</p>
<p>
Each test application contains one or more test case classes based on an Android class for a
- particular type of component. The test case class contains methods that define tests on some part of the application under test. When you run the test application, Android
- starts it, loads the application under test into the same process, and then invokes each method in the test case class.
+ particular type of component. The test case class contains methods that define tests on some
+ part of the application under test. When you run the test application, Android
+ starts it, loads the application under test into the same process, and then invokes each method
+ in the test case class.
</p>
<p>
- The tools and procedures you use with testing depend on the development environment you are using. If you use Eclipse, then the ADT plug in for Eclipse provides tools that
- allow you to develop and run tests entirely within Eclipse. This is documented in the topic <a href="{@docRoot}guide/developing/testing/testing_eclipse.html">Testing in Eclipse, with ADT</a>.
- If you use another development environment, then you use Android's command-line tools, as documented in the topic <a href="{@docRoot}guide/developing/testing/testing_otheride.html">Testing in Other IDEs</a>.
+ The tools and procedures you use with testing depend on the development environment you are
+ using. If you use Eclipse, then the ADT plug in for Eclipse provides tools that allow you to
+ develop and run tests entirely within Eclipse. This is documented in the topic
+ <a href="{@docRoot}guide/developing/testing/testing_eclipse.html">
+ Testing in Eclipse, with ADT</a>. If you use another development environment, then you use
+ Android's command-line tools, as documented in the topic
+ <a href="{@docRoot}guide/developing/testing/testing_otheride.html">Testing in Other IDEs</a>.
</p>
<h3 id="TestProjects">Working with test projects</h3>
<p>
- To start testing an Android application, you create a test project for it using Android tools. The tools create the project directory and the files and subdirectories needed.
- The tools also create a manifest file that links the application in the test project to the application under test. The procedure for creating a test project in Eclipse with
- ADT is documented in <a href="{@docRoot}guide/developing/testing/testing_eclipse.html">Testing in Eclipse, with ADT</a>. The procedure for creating a test project for use with development
- tools other than Eclipse is documented in <a href="{@docRoot}guide/developing/testing/testing_otheride.html">Testing in Other IDEs</a>.
+ To start testing an Android application, you create a test project for it using Android tools.
+ The tools create the project directory and the files and subdirectories needed.
+ The tools also create a manifest file that links the application in the test project to the
+ application under test. The procedure for creating a test project in Eclipse with ADT is
+ documented in <a href="{@docRoot}guide/developing/testing/testing_eclipse.html">
+ Testing in Eclipse, with ADT</a>. The procedure for creating a test project for use with
+ development tools other than Eclipse is documented in
+ <a href="{@docRoot}guide/developing/testing/testing_otheride.html">Testing in Other IDEs</a>.
</p>
<h3 id="TestClasses">Working with test case classes</h3>
<p>
- A test application contains one or more test case classes that extend an Android test case class. You choose a test case class based on the type of Android component you are testing and the
- tests you are doing. A test application can test different components, but each test case class is designed to test a single type of component.
- The Android test case classes are described in the section <a href="#TestAPI">The Testing API</a>.
+ A test application contains one or more test case classes that extend an Android test case
+ class. You choose a test case class based on the type of Android component you are testing and
+ the tests you are doing. A test application can test different components, but each test case
+ class is designed to test a single type of component. The Android test case classes are
+ described in the section <a href="#TestAPI">The Testing API</a>.
</p>
<p>
- Some Android components have more than one associated test case class. In this case, you choose among the available classes based on the type of tests you want to do. For activities,
- for example, you have the choice of either {@link android.test.ActivityInstrumentationTestCase2} or {@link android.test.ActivityUnitTestCase}.
+ Some Android components have more than one associated test case class. In this case, you choose
+ among the available classes based on the type of tests you want to do. For activities, for
+ example, you have the choice of either {@link android.test.ActivityInstrumentationTestCase2} or
+ {@link android.test.ActivityUnitTestCase}.
<p>
- <code>ActivityInstrumentationTestCase2</code> is designed to do functional testing, so it tests activities in a normal system infrastructure. You can inject mocked Intents, but not
+ <code>ActivityInstrumentationTestCase2</code> is designed to do functional testing, so it tests
+ activities in a normal system infrastructure. You can inject mocked Intents, but not
mocked Contexts. In general, you can't mock dependencies for the activity under test.
</p>
<p>
- In comparison, <code>ActivityUnitTestCase</code> is designed for unit testing, so it tests activities in an isolated system infrastructure. You can inject mocked or wrappered dependencies for
- the activity under test, particularly mocked Contexts. On the other hand, when you use this test case class the activity under test runs in isolation and can't interact with other activities.
+ In comparison, <code>ActivityUnitTestCase</code> is designed for unit testing, so it tests
+ activities in an isolated system infrastructure. You can inject mocked or wrappered
+ dependencies for the activity under test, particularly mocked Contexts. On the other hand,
+ when you use this test case class the activity under test runs in isolation and can't interact
+ with other activities.
</p>
<p>
- As a rule of thumb, if you wanted to test an activity's interaction with the rest of Android, you would use <code>ActivityInstrumentationTestCase2</code>. If you wanted to do regression testing
- on an activity, you would use <code>ActivityUnitTestCase</code>.
+ As a rule of thumb, if you wanted to test an activity's interaction with the rest of Android,
+ you would use <code>ActivityInstrumentationTestCase2</code>. If you wanted to do regression
+ testing on an activity, you would use <code>ActivityUnitTestCase</code>.
</p>
<h3 id="Tests">Working with test methods</h3>
<p>
- Each test case class provides methods that you use to set up the test environment and control the application under test. For example, all test case classes provide the JUnit {@link junit.framework.TestCase#setUp() setUp()}
- method that you can override to set up fixtures. In addition, you add methods to the class to define individual tests. Each method you add is run once each time you run the test application. If you override the <code>setUp()</code>
- method, it runs before each of your methods. Similarly, the JUnit {@link junit.framework.TestCase#tearDown() tearDown()} method is run once after each of your methods.
+ Each test case class provides methods that you use to set up the test environment and control
+ the application under test. For example, all test case classes provide the JUnit
+ {@link junit.framework.TestCase#setUp() setUp()} method that you can override to set up
+ fixtures. In addition, you add methods to the class to define individual tests. Each method you
+ add is run once each time you run the test application. If you override the <code>setUp()</code>
+ method, it runs before each of your methods. Similarly, the JUnit
+ {@link junit.framework.TestCase#tearDown() tearDown()} method is run once after each of
+ your methods.
</p>
<p>
- The test case classes give you substantial control over starting and stopping components. For this reason, you have to specifically tell Android to start a component before you run tests against it. For example, you use the
- {@link android.test.ActivityInstrumentationTestCase2#getActivity()} method to start the activity under test. You can call this method once during the entire test case, or once for each test method. You can even destroy the
- activity under test by calling its {@link android.app.Activity#finish()} method and then restart it with <code>getActivity()</code> within a single test method.
+ The test case classes give you substantial control over starting and stopping components. For
+ this reason, you have to specifically tell Android to start a component before you run tests
+ against it. For example, you use the
+ {@link android.test.ActivityInstrumentationTestCase2#getActivity()} method to start the activity
+ under test. You can call this method once during the entire test case, or once for each test
+ method. You can even destroy the activity under test by calling its
+ {@link android.app.Activity#finish()} method and then restart it with
+ <code>getActivity()</code> within a single test method.
</p>
<h3 id="RunTests">Running tests and seeing the results</h3>
<p>
- To run your tests, you build your test project and then run the test application using the system utility Activity Manager with instrumentation. You provide to Activity Manager the name of the test runner (usually
- {@link android.test.InstrumentationTestRunner}) you specified for your application; the name includes both your test application's package name and the test runner class name. Activity Manager loads and starts your
- test application, kills any instances of the application under test, loads an instance of the application under test into the same process as the test application, and then passes control to the first test case
- class in your test application. The test runner then takes control of the tests, running each of your test methods against the application under test until all the methods in all the classes have been run.
+ To run your tests, you build your test project and then run the test application using the
+ system utility Activity Manager with instrumentation. You provide to Activity Manager the name
+ of the test runner (usually {@link android.test.InstrumentationTestRunner}) you specified for
+ your application; the name includes both your test application's package name and the test
+ runner class name. Activity Manager loads and starts your test application, kills any instances
+ of the application under test, loads an instance of the application under test into the same
+ process as the test application, and then passes control to the first test case class in your
+ test application. The test runner then takes control of the tests, running each of your test
+ methods against the application under test until all the methods in all the classes have been
+ run.
</p>
<p>
- If you run a test within Eclipse with ADT, the output appears in a new JUnit view pane. If you run a test from the command line, the output goes to STDOUT.
+ If you run a test within Eclipse with ADT, the output appears in a new JUnit view pane. If you
+ run a test from the command line, the output goes to STDOUT.
</p>
<h2 id="TestAreas">What to Test</h2>
<p>
@@ -359,58 +445,64 @@
</p>
<ul>
<li>
- Activity lifecycle events: You should test that your activities handle lifecycle events correctly. For example
- an activity should respond to pause or destroy events by saving its state. Remember that even a change in screen orientation
- causes the current activity to be destroyed, so you should test that accidental device movements don't accidentally lose the
+ Activity lifecycle events: You should test that your activities handle lifecycle events
+ correctly. For example, an activity should respond to pause or destroy events by saving its
+ state. Remember that even a change in screen orientation causes the current activity to be
+ destroyed, so you should test that accidental device movements don't accidentally lose the
application state.
</li>
<li>
- Database operations: You should ensure that database operations correctly handle changes to the application's state.
- To do this, use mock objects from the package {@link android.test.mock android.test.mock}.
+ Database operations: You should ensure that database operations correctly handle changes to
+ the application's state. To do this, use mock objects from the package
+ {@link android.test.mock android.test.mock}.
</li>
<li>
- Screen sizes and resolutions: Before you publish your application, make sure to test it on all of the
- screen sizes and densities on which you want it to run. You can test the application on multiple sizes and densities using
- AVDs, or you can test your application directly on the devices that you are targeting. For more information, see
- the topic <a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple Screens</a>.
+ Screen sizes and resolutions: Before you publish your application, make sure to test it on
+ all of the screen sizes and densities on which you want it to run. You can test the
+ application on multiple sizes and densities using AVDs, or you can test your application
+ directly on the devices that you are targeting. For more information, see the topic
+ <a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple Screens</a>.
</li>
</ul>
<p>
- When possible, you should run these tests on an actual device. If this is not possible, you can
- use the <a href="{@docRoot}guide/developing/tools/emulator.html">Android Emulator</a> with
- <a href="{@docRoot}guide/developing/tools/avd.html">Android Virtual Devices</a> configured for
- the hardware, screens, and versions you want to test.
+ When possible, you should run these tests on an actual device. If this is not possible, you can
+ use the <a href="{@docRoot}guide/developing/tools/emulator.html">Android Emulator</a> with
+ <a href="{@docRoot}guide/developing/tools/avd.html">Android Virtual Devices</a> configured for
+ the hardware, screens, and versions you want to test.
</p>
<h2 id="UITesting">Appendix: UI Testing Notes</h2>
<p>
- The following sections have tips for testing the UI of your Android application, specifically
- to help you handle actions that run in the UI thread, touch screen and keyboard events, and home
- screen unlock during testing.
+ The following sections have tips for testing the UI of your Android application, specifically
+ to help you handle actions that run in the UI thread, touch screen and keyboard events, and home
+ screen unlock during testing.
</p>
<h3 id="RunOnUIThread">Testing on the UI thread</h3>
<p>
- An application's activities run on the application's <strong>UI thread</strong>. Once the
- UI is instantiated, for example in the activity's <code>onCreate()</code> method, then all
- interactions with the UI must run in the UI thread. When you run the application normally, it
- has access to the thread and does not have to do anything special.
+ An application's activities run on the application's <strong>UI thread</strong>. Once the
+ UI is instantiated, for example in the activity's <code>onCreate()</code> method, then all
+ interactions with the UI must run in the UI thread. When you run the application normally, it
+ has access to the thread and does not have to do anything special.
</p>
<p>
- This changes when you run tests against the application. With instrumentation-based classes,
- you can invoke methods against the UI of the application under test. The other test classes don't allow this.
- To run an entire test method on the UI thread, you can annotate the thread with <code>@UIThreadTest</code>.
- Notice that this will run <em>all</em> of the method statements on the UI thread. Methods that do not interact with the UI
- are not allowed; for example, you can't invoke <code>Instrumentation.waitForIdleSync()</code>.
+ This changes when you run tests against the application. With instrumentation-based classes,
+ you can invoke methods against the UI of the application under test. The other test classes
+ don't allow this. To run an entire test method on the UI thread, you can annotate the thread
+ with <code>@UIThreadTest</code>. Notice that this will run <em>all</em> of the method statements
+ on the UI thread. Methods that do not interact with the UI are not allowed; for example, you
+ can't invoke <code>Instrumentation.waitForIdleSync()</code>.
</p>
<p>
- To run a subset of a test method on the UI thread, create an anonymous class of type
- <code>Runnable</code>, put the statements you want in the <code>run()</code> method, and instantiate a new
- instance of the class as a parameter to the method <code><em>appActivity</em>.runOnUiThread()</code>, where
- <code><em>appActivity</em></code> is the instance of the app you are testing.
+ To run a subset of a test method on the UI thread, create an anonymous class of type
+ <code>Runnable</code>, put the statements you want in the <code>run()</code> method, and
+ instantiate a new instance of the class as a parameter to the method
+ <code><em>appActivity</em>.runOnUiThread()</code>, where <code><em>appActivity</em></code> is
+ the instance of the app you are testing.
</p>
<p>
- For example, this code instantiates an activity to test, requests focus (a UI action) for the Spinner displayed
- by the activity, and then sends a key to it. Notice that the calls to <code>waitForIdleSync</code> and <code>sendKeys</code>
- aren't allowed to run on the UI thread:</p>
+ For example, this code instantiates an activity to test, requests focus (a UI action) for the
+ Spinner displayed by the activity, and then sends a key to it. Notice that the calls to
+ <code>waitForIdleSync</code> and <code>sendKeys</code> aren't allowed to run on the UI thread:
+</p>
<pre>
private MyActivity mActivity; // MyActivity is the class name of the app under test
private Spinner mSpinner;
@@ -449,31 +541,36 @@
<h3 id="NotouchMode">Turning off touch mode</h3>
<p>
- To control the emulator or a device with key events you send from your tests, you must turn off
- touch mode. If you do not do this, the key events are ignored.
+ To control the emulator or a device with key events you send from your tests, you must turn off
+ touch mode. If you do not do this, the key events are ignored.
</p>
<p>
- To turn off touch mode, you invoke <code>ActivityInstrumentationTestCase2.setActivityTouchMode(false)</code>
- <em>before</em> you call <code>getActivity()</code> to start the activity. You must invoke the method in a test method
- that is <em>not</em> running on the UI thread. For this reason, you can't invoke the touch mode method
- from a test method that is annotated with <code>@UIThread</code>. Instead, invoke the touch mode method from <code>setUp()</code>.
+ To turn off touch mode, you invoke
+ <code>ActivityInstrumentationTestCase2.setActivityTouchMode(false)</code>
+ <em>before</em> you call <code>getActivity()</code> to start the activity. You must invoke the
+ method in a test method that is <em>not</em> running on the UI thread. For this reason, you
+ can't invoke the touch mode method from a test method that is annotated with
+ <code>@UIThread</code>. Instead, invoke the touch mode method from <code>setUp()</code>.
</p>
<h3 id="UnlockDevice">Unlocking the emulator or device</h3>
<p>
- You may find that UI tests don't work if the emulator's or device's home screen is disabled with the keyguard pattern.
- This is because the application under test can't receive key events sent by <code>sendKeys()</code>. The best
- way to avoid this is to start your emulator or device first and then disable the keyguard for the home screen.
+ You may find that UI tests don't work if the emulator's or device's home screen is disabled with
+ the keyguard pattern. This is because the application under test can't receive key events sent '
+ by <code>sendKeys()</code>. The best way to avoid this is to start your emulator or device
+ first and then disable the keyguard for the home screen.
</p>
<p>
- You can also explicitly disable the keyguard. To do this,
- you need to add a permission in the manifest file (<code>AndroidManifest.xml</code>) and
- then disable the keyguard in your application under test. Note, though, that you either have to remove this before
- you publish your application, or you have to disable it programmatically in the published app.
+ You can also explicitly disable the keyguard. To do this,
+ you need to add a permission in the manifest file (<code>AndroidManifest.xml</code>) and
+ then disable the keyguard in your application under test. Note, though, that you either have to
+ remove this before you publish your application, or you have to disable it programmatically in
+ the published app.
</p>
<p>
- To add the the permission, add the element <code><uses-permission android:name="android.permission.DISABLE_KEYGUARD"/></code>
- as a child of the <code><manifest></code> element. To disable the KeyGuard, add the following code
- to the <code>onCreate()</code> method of activities you intend to test:
+ To add the the permission, add the element
+ <code><uses-permission android:name="android.permission.DISABLE_KEYGUARD"/></code>
+ as a child of the <code><manifest></code> element. To disable the KeyGuard, add the
+ following code to the <code>onCreate()</code> method of activities you intend to test:
</p>
<pre>
mKeyGuardManager = (KeyguardManager) getSystemService(KEYGUARD_SERVICE);
@@ -483,7 +580,8 @@
<p>where <code><em>activity_classname</em></code> is the class name of the activity.</p>
<h3 id="UITestTroubleshooting">Troubleshooting UI tests</h3>
<p>
- This section lists some of the common test failures you may encounter in UI testing, and their causes:
+ This section lists some of the common test failures you may encounter in UI testing, and their
+ causes:
</p>
<dl>
<dt><code>WrongThreadException</code></dt>
@@ -491,27 +589,33 @@
<p><strong>Problem:</strong></p>
For a failed test, the Failure Trace contains the following error message:
<code>
- android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
+ android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created
+ a view hierarchy can touch its views.
</code>
<p><strong>Probable Cause:</strong></p>
- This error is common if you tried to send UI events to the UI thread from outside the UI thread. This commonly happens if you send UI events
- from the test application, but you don't use the <code>@UIThread</code> annotation or the <code>runOnUiThread()</code> method. The test method tried to interact with the UI outside the UI thread.
+ This error is common if you tried to send UI events to the UI thread from outside the UI
+ thread. This commonly happens if you send UI events from the test application, but you don't
+ use the <code>@UIThread</code> annotation or the <code>runOnUiThread()</code> method. The
+ test method tried to interact with the UI outside the UI thread.
<p><strong>Suggested Resolution:</strong></p>
- Run the interaction on the UI thread. Use a test class that provides instrumentation. See the previous section <a href="#RunOnUIThread">Testing on the UI Thread</a>
+ Run the interaction on the UI thread. Use a test class that provides instrumentation. See
+ the previous section <a href="#RunOnUIThread">Testing on the UI Thread</a>
for more details.
</dd>
<dt><code>java.lang.RuntimeException</code></dt>
<dd>
<p><strong>Problem:</strong></p>
- For a failed test, the Failure Trace contains the following error message:
+ For a failed test, the Failure Trace contains the following error message:
<code>
java.lang.RuntimeException: This method can not be called from the main application thread
</code>
<p><strong>Probable Cause:</strong></p>
- This error is common if your test method is annotated with <code>@UiThreadTest</code> but then tries to
- do something outside the UI thread or tries to invoke <code>runOnUiThread()</code>.
+ This error is common if your test method is annotated with <code>@UiThreadTest</code> but
+ then tries to do something outside the UI thread or tries to invoke
+ <code>runOnUiThread()</code>.
<p><strong>Suggested Resolution:</strong></p>
- Remove the <code>@UiThreadTest</code> annotation, remove the <code>runOnUiThread()</code> call, or re-factor your tests.
+ Remove the <code>@UiThreadTest</code> annotation, remove the <code>runOnUiThread()</code>
+ call, or re-factor your tests.
</dd>
</dl>
diff --git a/docs/html/resources/browser.jd b/docs/html/resources/browser.jd
new file mode 100644
index 0000000..8a08769
--- /dev/null
+++ b/docs/html/resources/browser.jd
@@ -0,0 +1,49 @@
+page.title=Technical Resources
+@jd:body
+
+<style type="text/css">
+ {@literal @import} "{@docRoot}assets/android-developer-resource-browser.css";
+</style>
+
+<script type="text/javascript" src="{@docRoot}assets/android-developer-resource-browser.js"></script>
+<script type="text/javascript" src="{@docRoot}assets/microtemplate.js"></script>
+
+<div>
+ <p style="display: none; float: right">Filter: <input id="resource-browser-keyword-filter"/></p>
+ <p id="resource-browser-search-params">Showing all technical resources:</p>
+</div>
+
+<noscript>
+ <p class="note"><strong>Error:</strong>
+ You must have JavaScript enabled to view this page. Resources are also
+ available offline in the SDK.
+ </p>
+</noscript>
+
+<div id="resource-browser-results">
+ <div class="no-results">No results.</div>
+</div>
+
+<script type="text/html" id="tmpl_resource_browser_result">
+<div class="result">
+ <h3>
+ <% if ('external' in tagsHash) { %><strong>External: </strong> <% } %>
+ <a href="<%= path %>"><%= title.en %></a>
+ <% if ('new' in tagsHash) { %><span class="new">new!</span> <% } %>
+ </h3>
+ <p class="resource-meta"><%
+ var __g = ['', ''];
+ if ('article' in tagsHash) {
+ __g = ['Article', 'about'];
+ } else if ('tutorial' in tagsHash) {
+ __g = ['Tutorial', 'on'];
+ } else if ('sample' in tagsHash) {
+ __g = ['Sample', 'for'];
+ } else if ('video' in tagsHash) {
+ __g = ['Video', 'about'];
+ }
+ %>
+ <%= __g[0] %><% if (topicsHtml) { %> <%= __g[1] %><% } %> <%= topicsHtml %></p>
+ <p><%= description.en %></p>
+</div>
+</script>
diff --git a/docs/html/resources/index.jd b/docs/html/resources/index.jd
index 1668721..9055868 100644
--- a/docs/html/resources/index.jd
+++ b/docs/html/resources/index.jd
@@ -1,38 +1,90 @@
page.title=Developer Resources
@jd:body
+<style type="text/css">
+ #resource-list-table td {
+ border: 0;
+ padding: 0 24px;
+ width: 33%;
+ max-width: 250px;
+ border-right: 1px solid #ddd;
+ }
+
+ #resource-list-table td.last {
+ border-right: 0;
+ padding-right: 0;
+ }
+</style>
+
<p>
-This section provides technical articles, tutorials, sample code, and other
+This section provides articles, tutorials, sample code, and other
information to help you quickly implement the features you want in your
-application.
+application. To return to this page later, just click the "Resources"
+tab while any Resources page is loaded.
</p>
+<h2>Technical Resources</h2>
+
+<table id="resource-list-table">
+<tr>
+ <td>
+ <a href="{@docRoot}resources/browser.html?tag=sample">
+ <img src="{@docRoot}assets/images/resource-big-sample.png"/>
+ </a>
+ <h3><a href="{@docRoot}resources/browser.html?tag=sample">
+ Sample Code
+ </a></h3>
+ <p>Fully-functioning sample applications that you can build and run
+ to learn about how Android works. Feel free to reuse any of the code or
+ techniques in the samples.</p>
+ </td>
+ <td>
+ <a href="{@docRoot}resources/browser.html?tag=article">
+ <img src="{@docRoot}assets/images/resource-big-article.png"/>
+ </a>
+ <h3><a href="{@docRoot}resources/browser.html?tag=article">
+ Articles
+ </a></h3>
+ <p>Focused discussions about Android development subjects, including
+ optimizations, tips, interesting implementations, "how-tos",
+ and so on.</p>
+ </td>
+ <td>
+ <a href="{@docRoot}resources/browser.html?tag=tutorial">
+ <img src="{@docRoot}assets/images/resource-big-tutorial.png"/>
+ </a>
+ <h3><a href="{@docRoot}resources/browser.html?tag=tutorial">
+ Tutorials
+ </a></h3>
+ <p>Step-by-step instructions demonstrating how to build an Android application
+ that has the specific features you want.</p>
+ </td>
+ <!-- <td class="last">
+ <a href="{@docRoot}resources/browser.html?tag=video">
+ <img src="{@docRoot}assets/images/resource-big-video.png"/>
+ </a>
+ <h3><a href="{@docRoot}resources/browser.html?tag=video">
+ Videos & Screencasts
+ </a></h3>
+ <p>Videos and presentation slides from developer events, along with
+ screencasts to walk you through common Android development
+ workflows.</p>
+ </td> -->
+</tr>
+</table>
+
+<h2>Other Resources</h2>
+
<dl>
-<dt><b>Technical Articles</b></dt>
-<dd>Focused discussions about Android development subjects, including
-optimizations, tips, interesting implementations,
-and so on. Most of the articles provide "how-to" instructions for adding
-features or functionality to your app. The articles are drawn from posts to the
-Android Developers Blog.
-</dd>
-
-<dt><b>Tutorials</b></dt>
-<dd>Step-by-step instructions demonstrating how to build an Android application
-that has the specific features you want. </dd>
-
-<dt><b>Sample Code</b></dt>
-<dd>Fully-functioning sample applications that you can look at or build and run,
-to learn about how Android works. Feel free to reuse any of the code or
-techniques that you find in the samples!</dd>
-
<dt><b>Community</b></dt>
<dd>Links to the Android discussion groups and information about other ways to
collaborate with other developers. </dd>
+<dt><b>Device Dashboard</b></dt>
+<dd>Device distribution data, grouped by various dimensions such as screen size
+and Android platform version. </dd>
+
<dt><b>More</b></dt>
<dd>Quick development tips, troubleshooting information, and frequently asked
questions (FAQs). </dd>
</dl>
-
-<p>To return to this page later, just click the "Resources" tab while any
-Resources page is loaded. </p>
\ No newline at end of file
diff --git a/docs/html/resources/resources-data.js b/docs/html/resources/resources-data.js
new file mode 100644
index 0000000..9bbe060
--- /dev/null
+++ b/docs/html/resources/resources-data.js
@@ -0,0 +1,622 @@
+var ANDROID_TAGS = {
+ type: {
+ 'article': 'Article',
+ 'tutorial': 'Tutorial',
+ 'sample': 'Sample',
+ 'video': 'Video',
+ 'library': 'Code Library'
+ },
+ topic: {
+ 'accessibility': 'Accessibility',
+ 'accountsync': 'Accounts & Sync',
+ 'bestpractice': 'Best Practices',
+ 'communication': 'Communication',
+ 'compatibility': 'Compatibility',
+ 'data': 'Data Access',
+ 'drawing': 'Canvas Drawing',
+ 'gamedev': 'Game Development',
+ 'gl': 'OpenGL ES',
+ 'input': 'Input Methods',
+ 'intent': 'Intents',
+ 'layout': 'Layouts/Views',
+ 'media': 'Multimedia',
+ 'newfeature': 'New Features',
+ 'performance': 'Performance',
+ 'search': 'Search',
+ 'testing': 'Testing',
+ 'ui': 'User Interface',
+ 'web': 'Web Content'
+ },
+ misc: {
+ 'external': 'External',
+ 'new': 'New'
+ }
+};
+
+var ANDROID_RESOURCES = [
+
+//////////////////////////
+/// TECHNICAL ARTICLES ///
+//////////////////////////
+
+ {
+ tags: ['article', 'performance', 'bestpractice'],
+ path: 'articles/avoiding-memory-leaks.html',
+ title: {
+ en: 'Avoiding Memory Leaks'
+ },
+ description: {
+ en: 'Mobile devices often have limited memory, and memory leaks can cause your application to waste this valuable resource without your knowledge. This article provides tips to help you avoid common causes of memory leaks on the Android platform.'
+ }
+ },
+ {
+ tags: ['article', 'compatibility'],
+ path: 'articles/backward-compatibility.html',
+ title: {
+ en: 'Backward Compatibility'
+ },
+ description: {
+ en: 'The Android platform strives to ensure backwards compatibility. However, sometimes you want to use new features which aren\'t supported on older platforms. This article discusses strategies for selectively using these features based on availability, allowing you to keep your applications portable across a wide range of devices.'
+ }
+ },
+ {
+ tags: ['article', 'intent'],
+ path: 'articles/can-i-use-this-intent.html',
+ title: {
+ en: 'Can I Use this Intent?'
+ },
+ description: {
+ en: 'Android offers a very powerful and yet easy-to-use message type called an intent. You can use intents to turn applications into high-level libraries and make code modular and reusable. While it is nice to be able to make use of a loosely coupled API, there is no guarantee that the intent you send will be received by another application. This article describes a technique you can use to find out whether the system contains any application capable of responding to the intent you want to use.'
+ }
+ },
+ {
+ tags: ['article', 'input'],
+ path: 'articles/creating-input-method.html',
+ title: {
+ en: 'Creating an Input Method'
+ },
+ description: {
+ en: 'Input Method Editors (IMEs) provide the mechanism for entering text into text fields and other Views. Android devices come bundled with at least one IME, but users can install additional IMEs. This article covers the basics of developing an IME for the Android platform.'
+ }
+ },
+ {
+ tags: ['article', 'drawing', 'ui'],
+ path: 'articles/drawable-mutations.html',
+ title: {
+ en: 'Drawable Mutations'
+ },
+ description: {
+ en: 'Drawables are pluggable drawing containers that allow applications to display graphics. This article explains some common pitfalls when trying to modify the properties of multiple Drawables.'
+ }
+ },
+ {
+ tags: ['article', 'bestpractice', 'ui'],
+ path: 'articles/faster-screen-orientation-change.html',
+ title: {
+ en: 'Faster Screen Orientation Change'
+ },
+ description: {
+ en: 'When an Android device changes its orientation, the default behavior is to automatically restart the current activity with a new configuration. However, this can become a bottleneck in applications that access a large amount of external data. This article discusses how to gracefully handle this situation without resorting to manually processing configuration changes.'
+ }
+ },
+ {
+ tags: ['article', 'compatibility'],
+ path: 'articles/future-proofing.html',
+ title: {
+ en: 'Future-Proofing Your Apps'
+ },
+ description: {
+ en: 'A collection of common sense advice to help you ensure that your applications don\'t break when new versions of the Android platform are released.'
+ }
+ },
+ {
+ tags: ['article', 'input'],
+ path: 'articles/gestures.html',
+ title: {
+ en: 'Gestures'
+ },
+ description: {
+ en: 'Touch screens allow users to perform gestures, such as tapping, dragging, flinging, or sliding, to perform various actions. The gestures API enables your application to recognize even complicated gestures with ease. This article explains how to integrate this API into an application.'
+ }
+ },
+ {
+ tags: ['article', 'gamedev', 'gl'],
+ path: 'articles/glsurfaceview.html',
+ title: {
+ en: 'Introducing GLSurfaceView'
+ },
+ description: {
+ en: 'This article provides an overview of GLSurfaceView, a class that makes it easy to implement 2D or 3D OpenGL rendering inside of an Android application.'
+ }
+ },
+ {
+ tags: ['article', 'ui', 'layout'],
+ path: 'articles/layout-tricks-reuse.html',
+ title: {
+ en: 'Layout Tricks: Creating Reusable UI Components'
+ },
+ description: {
+ en: 'Learn how to combine multiple standard UI widgets into a single high-level component, which can be reused throughout your application.'
+ }
+ },
+ {
+ tags: ['article', 'layout', 'ui', 'performance', 'bestpractice'],
+ path: 'articles/layout-tricks-efficiency.html',
+ title: {
+ en: 'Layout Tricks: Creating Efficient Layouts'
+ },
+ description: {
+ en: 'Learn how to optimize application layouts as this article walks you through converting a LinearLayout into a RelativeLayout, and analyzes the resulting implications on performance.'
+ }
+ },
+ {
+ tags: ['article', 'layout', 'ui', 'performance', 'bestpractice'],
+ path: 'articles/layout-tricks-stubs.html',
+ title: {
+ en: 'Layout Tricks: Using ViewStubs'
+ },
+ description: {
+ en: 'Learn about using ViewStubs inside an application\'s layout in order to inflate rarely used UI elements, without the performance implications which would otherwise be caused by using the <code><include></code> tag.'
+ }
+ },
+ {
+ tags: ['article', 'layout', 'ui', 'performance', 'bestpractice'],
+ path: 'articles/layout-tricks-merge.html',
+ title: {
+ en: 'Layout Tricks: Merging Layouts'
+ },
+ description: {
+ en: 'Learn how to use the <code><merge></code> tag in your XML layouts in order to avoid unnecessary levels of hierarchy within an application\'s view tree.'
+ }
+ },
+ {
+ tags: ['article', 'ui', 'performance'],
+ path: 'articles/listview-backgrounds.html',
+ title: {
+ en: 'ListView Backgrounds: An Optimization'
+ },
+ description: {
+ en: 'ListViews are very popular widgets within the Android framework. This article describes some of the optimizations used by the ListView widget, and how to avoid some common issues that this causes when trying to use a custom background.'
+ }
+ },
+ {
+ tags: ['article', 'ui', 'newfeature'],
+ path: 'articles/live-folders.html',
+ title: {
+ en: 'Live Folders'
+ },
+ description: {
+ en: 'Live Folders allow users to display any source of data on their home screen without launching an application. This article discusses how to export an application\'s data in a format suitable for display inside of a live folder.'
+ }
+ },
+ {
+ tags: ['article', 'ui', 'newfeature'],
+ path: 'articles/live-wallpapers.html',
+ title: {
+ en: 'Live Wallpapers'
+ },
+ description: {
+ en: 'Live wallpapers are richer, animated, interactive backgrounds that users can display in their home screens. Learn how to create a live wallpaper and bundle it in an application that users can install on their devices.'
+ }
+ },
+ {
+ tags: ['article', 'input'],
+ path: 'articles/on-screen-inputs.html',
+ title: {
+ en: 'Onscreen Input Methods'
+ },
+ description: {
+ en: 'The Input Method Framework (IMF) allows users to take advantage of on-screen input methods, such as software keyboards. This article provides an overview of Input Method Editors (IMEs) and how applications interact with them.'
+ }
+ },
+ {
+ tags: ['article', 'performance', 'bestpractice'],
+ path: 'articles/painless-threading.html',
+ title: {
+ en: 'Painless Threading'
+ },
+ description: {
+ en: 'This article discusses the threading model used by Android applications and how applications can ensure best UI performance by spawning worker threads to handle long-running operations, rather than handling them in the main thread. The article also explains the API that your application can use to interact with Android UI toolkit components running on the main thread and spawn managed worker threads.'
+ }
+ },
+ {
+ tags: ['article', 'ui', 'search'],
+ path: 'articles/qsb.html',
+ title: {
+ en: 'Quick Search Box'
+ },
+ description: {
+ en: 'Quick Search Box (QSB) is a powerful, system-wide search framework. QSB makes it possible for users to quickly and easily find what they\'re looking for, both on their devices and on the web. This article discusses how to work with the QSB framework to add new search results for an installed application.'
+ }
+ },
+ {
+ tags: ['article', 'ui'],
+ path: 'articles/touch-mode.html',
+ title: {
+ en: 'Touch Mode'
+ },
+ description: {
+ en: 'This article explains the touch mode, one of the most important principles of Android\'s UI toolkit. Whenever a user interacts with a device\'s touch screen, the system enters touch mode. While simple in concept, there are important implications touch mode that are often overlooked.'
+ }
+ },
+ {
+ tags: ['article', 'performance', 'bestpractice'],
+ path: 'articles/track-mem.html',
+ title: {
+ en: 'Tracking Memory Allocations'
+ },
+ description: {
+ en: 'This article discusses how to use the Allocation Tracker tool to observe memory allocations and avoid performance problems that would otherwise be caused by ignoring the effect of Dalvik\'s garbage collector.'
+ }
+ },
+ {
+ tags: ['article', 'newfeature'],
+ path: 'articles/ui-1.5.html',
+ title: {
+ en: 'UI Framework Changes in Android 1.5'
+ },
+ description: {
+ en: 'Explore the UI changes that were introduced in Android 1.5, compared with the UI provided in Android 1.0 and 1.1.'
+ }
+ },
+ {
+ tags: ['article', 'newfeature'],
+ path: 'articles/ui-1.6.html',
+ title: {
+ en: 'UI Framework Changes in Android 1.6'
+ },
+ description: {
+ en: 'Explore the UI changes that were introduced in Android 1.6, compared with the UI provided in Android 1.5. In particular, this article discusses changes to RelativeLayouts and click listeners.'
+ }
+ },
+ {
+ tags: ['article', 'ui', 'bestpractice'],
+ path: 'articles/timed-ui-updates.html',
+ title: {
+ en: 'Updating the UI from a Timer'
+ },
+ description: {
+ en: 'Learn about how to use Handlers as a more efficient replacement for java.util.Timer on the Android platform.'
+ }
+ },
+ {
+ tags: ['article', 'ui', 'accessibility'],
+ path: 'articles/tts.html',
+ title: {
+ en: 'Using Text-to-Speech'
+ },
+ description: {
+ en: 'The text-to-speech API lets your application "speak" to users, in any of several languages. This article provides an overview of the TTS API and how you use to add speech capabilities to your application.'
+ }
+ },
+ {
+ tags: ['article', 'ui', 'web'],
+ path: 'articles/using-webviews.html',
+ title: {
+ en: 'Using WebViews'
+ },
+ description: {
+ en: 'WebViews allow an application to dynamically display HTML and execute JavaScript, without relinquishing control to a separate browser application. This article introduces the WebView classes and provides a sample application that demonstrates its use.'
+ }
+ },
+ {
+ tags: ['article', 'ui'],
+ path: 'articles/wikinotes-linkify.html',
+ title: {
+ en: 'WikiNotes: Linkify your Text!'
+ },
+ description: {
+ en: 'This article introduces WikiNotes for Android, part of the Apps for Android project. It covers the use of Linkify to turn ordinary text views into richer, link-oriented content that causes Android intents to fire when a link is selected.'
+ }
+ },
+ {
+ tags: ['article', 'intent'],
+ path: 'articles/wikinotes-intents.html',
+ title: {
+ en: 'WikiNotes: Routing Intents'
+ },
+ description: {
+ en: 'This article illustrates how an application, in this case the WikiNotes sample app, can use intents to route various types of linked text to the application that handles that type of data. For example, an app can use intents to route a linked telephone number to a dialer app and a web URL to a browser.'
+ }
+ },
+ {
+ tags: ['article', 'ui', 'performance'],
+ path: 'articles/window-bg-speed.html',
+ title: {
+ en: 'Window Backgrounds & UI Speed'
+ },
+ description: {
+ en: 'Some Android applications need to squeeze every bit of performance out of the UI toolkit and there are many ways to do so. In this article, you will discover how to speed up the drawing and the perceived startup time of your activities. Both of these techniques rely on a single feature, the window\'s background drawable.'
+ }
+ },
+ {
+ tags: ['article', 'performance', 'bestpractice'],
+ path: 'articles/zipalign.html',
+ title: {
+ en: 'Zipalign: an Easy Optimization'
+ },
+ description: {
+ en: 'The Android SDK includes a tool called zipalign that optimizes the way an application is packaged. Running zipalign against your application enables Android to interact with it more efficiently at run time and thus has the potential to make it and the overall system run faster. This article provides a high-level overview of the zipalign tool and its use.'
+ }
+ },
+
+///////////////////
+/// SAMPLE CODE ///
+///////////////////
+
+ {
+ tags: ['sample', 'layout', 'ui'],
+ path: 'samples/ApiDemos/index.html',
+ title: {
+ en: 'API Demos'
+ },
+ description: {
+ en: 'A variety of small applications that demonstrate an extensive collection of framework topics.'
+ }
+ },
+ {
+ tags: ['sample', 'data', 'newfeature', 'accountsync', 'new'],
+ path: 'samples/BackupRestore/index.html',
+ title: {
+ en: 'Backup and Restore'
+ },
+ description: {
+ en: 'Illustrates a few different approaches that an application developer can take when integrating with the Android Backup Manager using the BackupAgent API introduced in Android 2.2.'
+ }
+ },
+ {
+ tags: ['sample', 'communication'],
+ path: 'samples/BluetoothChat/index.html',
+ title: {
+ en: 'Bluetooth Chat'
+ },
+ description: {
+ en: 'An application for two-way text messaging over Bluetooth.'
+ }
+ },
+ {
+ tags: ['sample', 'accountsync'],
+ path: 'samples/BusinessCard/index.html',
+ title: {
+ en: 'BusinessCard'
+ },
+ description: {
+ en: 'An application that demonstrates how to launch the built-in contact picker from within an activity. This sample also uses reflection to ensure that the correct version of the contacts API is used, depending on which API level the application is running under.'
+ }
+ },
+ {
+ tags: ['sample', 'accountsync'],
+ path: 'samples/ContactManager/index.html',
+ title: {
+ en: 'Contact Manager'
+ },
+ description: {
+ en: 'An application that demonstrates how to query the system contacts provider using the <code>ContactsContract</code> API, as well as insert contacts into a specific account.'
+ }
+ },
+ {
+ tags: ['sample'],
+ path: 'samples/Home/index.html',
+ title: {
+ en: 'Home'
+ },
+ description: {
+ en: 'A home screen replacement application.'
+ }
+ },
+ {
+ tags: ['sample', 'gamedev', 'media'],
+ path: 'samples/JetBoy/index.html',
+ title: {
+ en: 'JetBoy'
+ },
+ description: {
+ en: 'A game that demonstrates the SONiVOX JET interactive music technology, with <code><a href="/reference/android/media/JetPlayer.html">JetPlayer</a></code>.'
+ }
+ },
+ {
+ tags: ['sample', 'ui', 'newfeature'],
+ path: 'samples/CubeLiveWallpaper/index.html',
+ title: {
+ en: 'Live Wallpaper'
+ },
+ description: {
+ en: 'An application that demonstrates how to create a live wallpaper and bundle it in an application that users can install on their devices.'
+ }
+ },
+ {
+ tags: ['sample', 'gamedev', 'media'],
+ path: 'samples/LunarLander/index.html',
+ title: {
+ en: 'Lunar Lander'
+ },
+ description: {
+ en: 'A classic Lunar Lander game.'
+ }
+ },
+ {
+ tags: ['sample', 'ui', 'bestpractice', 'layout'],
+ path: 'samples/MultiResolution/index.html',
+ title: {
+ en: 'Multiple Resolutions'
+ },
+ description: {
+ en: 'A sample application that shows how to use resource directory qualifiers to provide different resources for different screen configurations.'
+ }
+ },
+ {
+ tags: ['sample', 'data'],
+ path: 'samples/NotePad/index.html',
+ title: {
+ en: 'Note Pad'
+ },
+ description: {
+ en: 'An application for saving notes. Similar (but not identical) to the <a href="/resources/tutorials/notepad/index.html">Notepad tutorial</a>.'
+ }
+ },
+ {
+ tags: ['sample', 'accountsync'],
+ path: 'samples/SampleSyncAdapter/index.html',
+ title: {
+ en: 'SampleSyncAdapter'
+ },
+ description: {
+ en: 'Demonstrates how an application can communicate with a cloud-based service and synchronize its data with data stored locally in a content provider. The sample uses two related parts of the Android framework — the account manager and the synchronization manager (through a sync adapter).'
+ }
+ },
+ {
+ tags: ['sample', 'ui', 'search', 'new'],
+ path: 'samples/SearchableDictionary/index.html',
+ title: {
+ en: 'Searchable Dictionary v2'
+ },
+ description: {
+ en: 'A sample application that demonstrates Android\'s search framework, including how to provide search suggestions for Quick Search Box.'
+ }
+ },
+ {
+ tags: ['sample', 'layout', 'ui'],
+ path: 'samples/Snake/index.html',
+ title: {
+ en: 'Snake'
+ },
+ description: {
+ en: 'An implementation of the classic game "Snake."'
+ }
+ },
+ {
+ tags: ['sample', 'testing', 'new'],
+ path: 'samples/Spinner/index.html',
+ title: {
+ en: 'Spinner'
+ },
+ description: {
+ en: 'A simple application that serves as an application under test for the SpinnerTest example.'
+ }
+ },
+ {
+ tags: ['sample', 'testing', 'new'],
+ path: 'samples/SpinnerTest/index.html',
+ title: {
+ en: 'SpinnerTest'
+ },
+ description: {
+ en: 'The test application for the Activity Testing tutorial. It tests the Spinner example application.'
+ }
+ },
+ {
+ tags: ['sample', 'newfeature', 'new'],
+ path: 'samples/TicTacToeLib/index.html',
+ title: {
+ en: 'TicTacToeLib'
+ },
+ description: {
+ en: 'An example of an Android library project, a type of project that lets you store and manage shared code and resources in one place, then make them available to your other Android applications.'
+ }
+ },
+ {
+ tags: ['sample', 'newfeature', 'new'],
+ path: 'samples/TicTacToeMain/index.html',
+ title: {
+ en: 'TicTacToeMain'
+ },
+ description: {
+ en: 'Demonstrates how an application can make use of shared code and resources stored in an Android library project.'
+ }
+ },
+ {
+ tags: ['sample', 'input'],
+ path: 'samples/SoftKeyboard/index.html',
+ title: {
+ en: 'Soft Keyboard'
+ },
+ description: {
+ en: 'An example of writing an input method for a software keyboard.'
+ }
+ },
+ {
+ tags: ['sample', 'ui'],
+ path: 'samples/Wiktionary/index.html',
+ title: {
+ en: 'Wiktionary'
+ },
+ description: {
+ en: 'An example of creating interactive widgets for display on the Android home screen.'
+ }
+ },
+ {
+ tags: ['sample', 'ui'],
+ path: 'samples/WiktionarySimple/index.html',
+ title: {
+ en: 'Wiktionary (Simplified)'
+ },
+ description: {
+ en: 'A simple Android home screen widgets example.'
+ }
+ },
+
+/////////////////
+/// TUTORIALS ///
+/////////////////
+
+ {
+ tags: ['tutorial'],
+ path: 'tutorials/hello-world.html',
+ title: {
+ en: 'Hello World'
+ },
+ description: {
+ en: 'Beginning basic application development with the Android SDK.'
+ }
+ },
+ {
+ tags: ['tutorial', 'ui', 'layout'],
+ path: 'tutorials/views/index.html',
+ title: {
+ en: 'Hello Views'
+ },
+ description: {
+ en: 'A walk-through of the various types of layouts and views available in the Android SDK.'
+ }
+ },
+ {
+ tags: ['tutorial', 'ui', 'bestpractice'],
+ path: 'tutorials/localization/index.html',
+ title: {
+ en: 'Hello Localization'
+ },
+ description: {
+ en: 'The basics of localizing your applications for multiple languages and locales.'
+ }
+ },
+ {
+ tags: ['tutorial', 'data'],
+ path: 'tutorials/notepad/index.html',
+ title: {
+ en: 'Notepad Tutorial'
+ },
+ description: {
+ en: 'A multi-part tutorial discussing intermediate-level concepts such as data access.'
+ }
+ },
+ {
+ tags: ['tutorial', 'testing', 'new'],
+ path: 'tutorials/testing/helloandroid_test.html',
+ title: {
+ en: 'Hello Testing'
+ },
+ description: {
+ en: 'A basic introduction to the Android testing framework.'
+ }
+ },
+ {
+ tags: ['tutorial', 'testing', 'new'],
+ path: 'tutorials/testing/activity_test.html',
+ title: {
+ en: 'Activity Testing'
+ },
+ description: {
+ en: 'A more advanced demonstration of the Android testing framework and tools.'
+ }
+ }
+];
diff --git a/docs/html/resources/resources_toc.cs b/docs/html/resources/resources_toc.cs
index 52689b6..a1711b5 100644
--- a/docs/html/resources/resources_toc.cs
+++ b/docs/html/resources/resources_toc.cs
@@ -1,5 +1,56 @@
<ul>
<li>
+ <h2><span class="en">Technical Resources</span>
+ </h2>
+ <ul>
+ <li class="toggle-list">
+ <div><a href="<?cs var:toroot ?>resources/browser.html?tag=sample">
+ <span class="en">Sample Code</span>
+ <span class="de" style="display:none">Beispielcode</span>
+ <span class="es" style="display:none">Código de ejemplo</span>
+ <span class="fr" style="display:none">Exemple de code</span>
+ <span class="it" style="display:none">Codice di esempio</span>
+ <span class="ja" style="display:none">サンプル コード</span>
+ <span class="zh-CN" style="display:none"></span>
+ <span class="zh-TW" style="display:none"></span>
+ </a></div>
+ <ul id="devdoc-nav-sample-list">
+ <li><a href="<?cs var:toroot ?>resources/samples/get.html">
+ <span class="en">Getting the Samples</span>
+ </a></li>
+ </ul>
+ </li>
+ <li class="toggle-list">
+ <div><a href="<?cs var:toroot ?>resources/browser.html?tag=article">
+ <span class="en">Articles</span>
+ </a></div>
+ <ul id="devdoc-nav-article-list">
+ </ul>
+ </li>
+ <li class="toggle-list">
+ <div><a href="<?cs var:toroot ?>resources/browser.html?tag=tutorial">
+ <span class="en">Tutorials</span>
+ <span class="de" style="display:none">Lernprogramme</span>
+ <span class="es" style="display:none">Tutoriales</span>
+ <span class="fr" style="display:none">Didacticiels</span>
+ <span class="it" style="display:none">Esercitazioni</span>
+ <span class="ja" style="display:none">チュートリアル</span>
+ <span class="zh-CN" style="display:none"></span>
+ <span class="zh-TW" style="display:none"></span>
+ </a></div>
+ <ul id="devdoc-nav-tutorial-list">
+ </ul>
+ </li>
+ <li class="toggle-list">
+ <div><a href="<?cs var:toroot ?>resources/topics.html">
+ <span class="en">Topics</span>
+ </a></div>
+ <ul id="devdoc-nav-topic-list">
+ </ul>
+ </li>
+ </ul>
+ </li>
+ <li>
<h2><span class="en">Community</span>
<span style="display:none" class="de"></span>
<span style="display:none" class="es">Comunidad</span>
@@ -34,241 +85,6 @@
</li><?cs
/if
?>
-
- <li>
- <h2><span class="en">Technical Articles</span>
- </h2>
- <ul>
- <li class="toggle-list">
- <div><a href="<?cs var:toroot ?>resources/articles/index.html">
- <span class="en">List of Articles</span>
- </a></div>
- <ul>
- <li><a href="<?cs var:toroot ?>resources/articles/avoiding-memory-leaks.html">
- <span class="en">Avoiding Memory Leaks</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/articles/backward-compatibility.html">
- <span class="en">Backward Compatibility</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/articles/can-i-use-this-intent.html">
- <span class="en">Can I Use this Intent?</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/articles/creating-input-method.html">
- <span class="en">Creating an Input Method</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/articles/drawable-mutations.html">
- <span class="en">Drawable Mutations</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/articles/faster-screen-orientation-change.html">
- <span class="en">Faster Screen Orientation Change</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/articles/future-proofing.html">
- <span class="en">Future-Proofing Your Apps</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/articles/gestures.html">
- <span class="en">Gestures</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/articles/glsurfaceview.html">
- <span class="en">Introducing GLSurfaceView</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/articles/layout-tricks-reuse.html">
- <span class="en">Layout Tricks: Reusing </span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/articles/layout-tricks-efficiency.html">
- <span class="en">Layout Tricks: Efficiency</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/articles/layout-tricks-stubs.html">
- <span class="en">Layout Tricks: ViewStubs </span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/articles/layout-tricks-merge.html">
- <span class="en">Layout Tricks: Merging </span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/articles/listview-backgrounds.html">
- <span class="en">ListView Backgrounds</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/articles/live-folders.html">
- <span class="en">Live Folders</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/articles/live-wallpapers.html">
- <span class="en">Live Wallpapers</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/articles/on-screen-inputs.html">
- <span class="en">Onscreen Input Methods</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/articles/painless-threading.html">
- <span class="en">Painless Threading</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/articles/qsb.html">
- <span class="en">Quick Search Box</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/articles/speech-input.html">
- <span class="en">Speech Input</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/articles/touch-mode.html">
- <span class="en">Touch Mode</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/articles/track-mem.html">
- <span class="en">Tracking Memory Allocations</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/articles/ui-1.5.html">
- <span class="en">UI Framework Changes in Android 1.5</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/articles/ui-1.6.html">
- <span class="en">UI Framework Changes in Android 1.6</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/articles/timed-ui-updates.html">
- <span class="en">Updating the UI from a Timer</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/articles/tts.html">
- <span class="en">Using Text-to-Speech</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/articles/contacts.html">
- <span class="en">Using the Contacts API</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/articles/using-webviews.html">
- <span class="en">Using WebViews</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/articles/wikinotes-linkify.html">
- <span class="en">WikiNotes: Linkify your Text!</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/articles/wikinotes-intents.html">
- <span class="en">WikiNotes: Routing Intents</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/articles/window-bg-speed.html">
- <span class="en">Window Backgrounds & UI Speed</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/articles/zipalign.html">
- <span class="en">Zipalign: An Easy Optimization</span>
- </a></li>
- </ul>
- </li>
- </ul>
- </li>
-
- <li>
- <h2><span class="en">Tutorials</span>
- <span class="de" style="display:none">Lernprogramme</span>
- <span class="es" style="display:none">Tutoriales</span>
- <span class="fr" style="display:none">Didacticiels</span>
- <span class="it" style="display:none">Esercitazioni</span>
- <span class="ja" style="display:none">チュートリアル</span>
- <span class="zh-CN" style="display:none"></span>
- <span class="zh-TW" style="display:none"></span>
- </h2>
- <ul>
- <li><a href="<?cs var:toroot ?>resources/tutorials/hello-world.html">
- <span class="en">Hello World</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/tutorials/views/index.html">
- <span class="en">Hello Views</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/tutorials/localization/index.html">
- <span class="en">Hello Localization</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/tutorials/testing/helloandroid_test.html">
- <span class="en">Hello Testing</span></a>
- <span class="new">new!</span>
- </li>
- <li><a href="<?cs var:toroot ?>resources/tutorials/notepad/index.html">
- <span class="en">Notepad Tutorial</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/tutorials/testing/activity_test.html">
- <span class="en">Activity Testing</span></a>
- <span class="new">new!</span>
- </li>
- </ul>
- </li>
-
-
- <li>
- <h2><span class="en">Sample Code</span>
- <span class="de" style="display:none">Beispielcode</span>
- <span class="es" style="display:none">Código de ejemplo</span>
- <span class="fr" style="display:none">Exemple de code</span>
- <span class="it" style="display:none">Codice di esempio</span>
- <span class="ja" style="display:none">サンプル コード</span>
- <span class="zh-CN" style="display:none"></span>
- <span class="zh-TW" style="display:none"></span>
- </h2>
- <ul>
- <li><a href="<?cs var:toroot ?>resources/samples/get.html">
- <span class="en">Getting the Samples</span>
- </a></li>
- <li class="toggle-list">
- <div><a href="<?cs var:toroot ?>resources/samples/index.html">
- <span class="en">List of Samples</span>
- </a></div>
- <ul>
- <li><a href="<?cs var:toroot ?>resources/samples/ApiDemos/index.html">
- <span class="en">API Demos</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/samples/BackupRestore/index.html">
- <span class="en">Backup and Restore</span>
- </a> <span class="new">new!</span></li>
- <li><a href="<?cs var:toroot ?>resources/samples/BluetoothChat/index.html">
- <span class="en">Bluetooth Chat</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/samples/BusinessCard/index.html">
- <span class="en">Business Card</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/samples/ContactManager/index.html">
- <span class="en">Contact Manager</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/samples/Home/index.html">
- <span class="en">Home</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/samples/JetBoy/index.html">
- <span class="en">JetBoy</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/samples/CubeLiveWallpaper/index.html">
- <span class="en">Live Wallpaper</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/samples/LunarLander/index.html">
- <span class="en">Lunar Lander</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/samples/MultiResolution/index.html">
- <span class="en">Multiple Resolutions</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/samples/NotePad/index.html">
- <span class="en">Note Pad</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/samples/SampleSyncAdapter/index.html">
- <span class="en">Sample Sync Adapter</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/samples/SearchableDictionary/index.html">
- <span class="en">Searchable Dictionary v2</span>
- </a> <span class="new">new!</span></li>
- <li><a href="<?cs var:toroot ?>resources/samples/Snake/index.html">
- <span class="en">Snake</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/samples/SoftKeyboard/index.html">
- <span class="en">Soft Keyboard</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/samples/Spinner/index.html">
- <span class="en">Spinner</span>
- </a> <span class="new">new!</span></li>
- <li><a href="<?cs var:toroot ?>resources/samples/SpinnerTest/index.html">
- <span class="en">SpinnerTest</span>
- </a> <span class="new">new!</span></li>
- <li><a href="<?cs var:toroot ?>resources/samples/TicTacToeLib/index.html">
- <span class="en">TicTacToeLib</span>
- </a> <span class="new">new!</span></li>
- <li><a href="<?cs var:toroot ?>resources/samples/TicTacToeMain/index.html">
- <span class="en">TicTacToeMain</span>
- </a> <span class="new">new!</span></li>
- <li><a href="<?cs var:toroot ?>resources/samples/Wiktionary/index.html">
- <span class="en">Wiktionary</span>
- </a></li>
- <li><a href="<?cs var:toroot ?>resources/samples/WiktionarySimple/index.html">
- <span class="en">Wiktionary (Simplified)</span>
- </a></li>
- </ul>
- </li>
- </ul>
- </li>
-
-
-
<li>
<h2><span class="en">More</span>
</h2>
@@ -297,8 +113,6 @@
</li>
</ul>
</li>
-
-
</ul>
<script type="text/javascript">
diff --git a/docs/html/resources/topics.jd b/docs/html/resources/topics.jd
new file mode 100644
index 0000000..b5960ff
--- /dev/null
+++ b/docs/html/resources/topics.jd
@@ -0,0 +1,72 @@
+page.title=Technical Resource Topics
+@jd:body
+
+<style type="text/css">
+ #resource-topic-table td {
+ border: 0;
+ padding: 0;
+ margin: 0;
+ padding-left: 1em;
+ width: 18em;
+ }
+
+ #resource-topic-table ul {
+ padding: 0;
+ margin: 0;
+ }
+
+ #resource-topic-table li {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ }
+</style>
+
+<p>
+You can browse the list of technical resources by topic by clicking on the
+links below. Over time, as more topics are added, they will be added to the
+list below.
+</p>
+
+<noscript>
+ <p class="note"><strong>Error:</strong>
+ You must have JavaScript enabled to view this page. Resources are also
+ available offline in the SDK.
+ </p>
+</noscript>
+
+<table id="resource-topic-table">
+ <tr></tr>
+</table>
+
+<script type="text/javascript">
+<!--
+(function() {
+ var topics = [];
+ for (var topic in ANDROID_TAGS['topic']) {
+ topics.push({name:topic,title:ANDROID_TAGS['topic'][topic]});
+ }
+ topics.sort(function(x,y){ return (x.title < y.title) ? -1 : 1; });
+ var topicParent = null;
+ for (var i = 0; i < topics.length; i++) {
+ if (topicParent == null || i % 10 == 0) {
+ // create a new column
+ topicParent = $('ul', $('<td><ul>').appendTo('#resource-topic-table tr'));
+ }
+
+ topicParent.append(
+ $('<li>').append(
+ $('<h3>').append(
+ $('<a>')
+ .attr('href', toRoot + "resources/browser.html?tag=" + topics[i].name)
+ .append($('<span>')
+ .addClass('en')
+ .html(topics[i].title)
+ )
+ )
+ )
+ );
+ }
+})();
+//-->
+</script>
\ No newline at end of file
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 76cde73..aec977a 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -16,11 +16,10 @@
package android.graphics;
-import android.text.TextUtils;
-import android.text.SpannedString;
-import android.text.SpannableString;
import android.text.GraphicsOperations;
-import android.util.DisplayMetrics;
+import android.text.SpannableString;
+import android.text.SpannedString;
+import android.text.TextUtils;
import javax.microedition.khronos.opengles.GL;
@@ -59,6 +58,18 @@
private int mSurfaceFormat;
/**
+ * Flag for drawTextRun indicating left-to-right run direction.
+ * @hide
+ */
+ public static final int DIRECTION_LTR = 0;
+
+ /**
+ * Flag for drawTextRun indicating right-to-left run direction.
+ * @hide
+ */
+ public static final int DIRECTION_RTL = 1;
+
+ /**
* Construct an empty raster canvas. Use setBitmap() to specify a bitmap to
* draw into. The initial target density is {@link Bitmap#DENSITY_NONE};
* this will typically be replaced when a target bitmap is set for the
@@ -1246,8 +1257,8 @@
(text.length - index - count)) < 0) {
throw new IndexOutOfBoundsException();
}
- native_drawText(mNativeCanvas, text, index, count, x, y,
- paint.mNativePaint);
+ native_drawText(mNativeCanvas, text, index, count, x, y, paint.mBidiFlags,
+ paint.mNativePaint);
}
/**
@@ -1259,7 +1270,10 @@
* @param y The y-coordinate of the origin of the text being drawn
* @param paint The paint used for the text (e.g. color, size, style)
*/
- public native void drawText(String text, float x, float y, Paint paint);
+ public void drawText(String text, float x, float y, Paint paint) {
+ native_drawText(mNativeCanvas, text, 0, text.length(), x, y, paint.mBidiFlags,
+ paint.mNativePaint);
+ }
/**
* Draw the text, with origin at (x,y), using the specified paint.
@@ -1277,8 +1291,8 @@
if ((start | end | (end - start) | (text.length() - end)) < 0) {
throw new IndexOutOfBoundsException();
}
- native_drawText(mNativeCanvas, text, start, end, x, y,
- paint.mNativePaint);
+ native_drawText(mNativeCanvas, text, start, end, x, y, paint.mBidiFlags,
+ paint.mNativePaint);
}
/**
@@ -1299,16 +1313,100 @@
if (text instanceof String || text instanceof SpannedString ||
text instanceof SpannableString) {
native_drawText(mNativeCanvas, text.toString(), start, end, x, y,
- paint.mNativePaint);
- }
- else if (text instanceof GraphicsOperations) {
+ paint.mBidiFlags, paint.mNativePaint);
+ } else if (text instanceof GraphicsOperations) {
((GraphicsOperations) text).drawText(this, start, end, x, y,
paint);
- }
- else {
+ } else {
char[] buf = TemporaryBuffer.obtain(end - start);
TextUtils.getChars(text, start, end, buf, 0);
- drawText(buf, 0, end - start, x, y, paint);
+ native_drawText(mNativeCanvas, buf, 0, end - start, x, y,
+ paint.mBidiFlags, paint.mNativePaint);
+ TemporaryBuffer.recycle(buf);
+ }
+ }
+
+ /**
+ * Render a run of all LTR or all RTL text, with shaping. This does not run
+ * bidi on the provided text, but renders it as a uniform right-to-left or
+ * left-to-right run, as indicated by dir. Alignment of the text is as
+ * determined by the Paint's TextAlign value.
+ *
+ * @param text the text to render
+ * @param index the start of the text to render. Data before this position
+ * can be used for shaping context.
+ * @param length the length of the text to render. Data at or after this
+ * position (start + length) can be used for shaping context.
+ * @param x the x position at which to draw the text
+ * @param y the y position at which to draw the text
+ * @param dir the run direction, either {@link DIRECTION_LTR} or
+ * {@link DIRECTION_RTL}.
+ * @param paint the paint
+ * @hide
+ */
+ public void drawTextRun(char[] text, int index, int length, float x, float y, int dir,
+ Paint paint) {
+
+ if (text == null) {
+ throw new NullPointerException("text is null");
+ }
+ if (paint == null) {
+ throw new NullPointerException("paint is null");
+ }
+ if ((index | length | text.length - index - length) < 0) {
+ throw new IndexOutOfBoundsException();
+ }
+ if (dir != DIRECTION_LTR && dir != DIRECTION_RTL) {
+ throw new IllegalArgumentException("unknown dir: " + dir);
+ }
+
+ native_drawTextRun(mNativeCanvas, text, index, length, x, y, dir, paint.mNativePaint);
+ }
+
+ /**
+ * Render a run of all LTR or all RTL text, with shaping. This does not run
+ * bidi on the provided text, but renders it as a uniform right-to-left or
+ * left-to-right run, as indicated by dir. Alignment of the text is as
+ * determined by the Paint's TextAlign value.
+ *
+ * @param text the text to render
+ * @param start the start of the text to render. Data before this position
+ * can be used for shaping context.
+ * @param end the end of the text to render. Data at or after this
+ * position can be used for shaping context.
+ * @param x the x position at which to draw the text
+ * @param y the y position at which to draw the text
+ * @param dir the run direction, either 0 for LTR or 1 for RTL.
+ * @param paint the paint
+ * @hide
+ */
+ public void drawTextRun(CharSequence text, int start, int end, float x,
+ float y, int dir, Paint paint) {
+
+ if (text == null) {
+ throw new NullPointerException("text is null");
+ }
+ if (paint == null) {
+ throw new NullPointerException("paint is null");
+ }
+ if ((start | end | end - start | text.length() - end) < 0) {
+ throw new IndexOutOfBoundsException();
+ }
+
+ int flags = dir == 0 ? 0 : 1;
+
+ if (text instanceof String || text instanceof SpannedString ||
+ text instanceof SpannableString) {
+ native_drawTextRun(mNativeCanvas, text.toString(), start, end, x, y,
+ flags, paint.mNativePaint);
+ } else if (text instanceof GraphicsOperations) {
+ ((GraphicsOperations) text).drawTextRun(this, start, end, x, y, flags,
+ paint);
+ } else {
+ char[] buf = TemporaryBuffer.obtain(end - start);
+ TextUtils.getChars(text, start, end, buf, 0);
+ native_drawTextRun(mNativeCanvas, buf, 0, end - start, x, y,
+ flags, paint.mNativePaint);
TemporaryBuffer.recycle(buf);
}
}
@@ -1555,10 +1653,17 @@
private static native void native_drawText(int nativeCanvas, char[] text,
int index, int count, float x,
- float y, int paint);
+ float y, int flags, int paint);
private static native void native_drawText(int nativeCanvas, String text,
int start, int end, float x,
- float y, int paint);
+ float y, int flags, int paint);
+
+ private static native void native_drawTextRun(int nativeCanvas, String
+ text, int start, int end, float x, float y, int flags, int paint);
+
+ private static native void native_drawTextRun(int nativeCanvas, char[]
+ text, int start, int len, float x, float y, int flags, int paint);
+
private static native void native_drawPosText(int nativeCanvas,
char[] text, int index,
int count, float[] pos,
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 3e3f87b..b564929 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -16,10 +16,10 @@
package android.graphics;
-import android.text.TextUtils;
+import android.text.GraphicsOperations;
import android.text.SpannableString;
import android.text.SpannedString;
-import android.text.GraphicsOperations;
+import android.text.TextUtils;
/**
* The Paint class holds the style and color information about how to draw
@@ -39,6 +39,7 @@
private boolean mHasCompatScaling;
private float mCompatScaling;
private float mInvCompatScaling;
+ /* package */ int mBidiFlags = BIDI_DEFAULT_LTR;
private static final Style[] sStyleArray = {
Style.FILL, Style.STROKE, Style.FILL_AND_STROKE
@@ -76,8 +77,64 @@
private static final int DEFAULT_PAINT_FLAGS = DEV_KERN_TEXT_FLAG;
/**
- * The Style specifies if the primitive being drawn is filled,
- * stroked, or both (in the same color). The default is FILL.
+ * Bidi flag to set LTR paragraph direction.
+ *
+ * @hide
+ */
+ public static final int BIDI_LTR = 0x0;
+
+ /**
+ * Bidi flag to set RTL paragraph direction.
+ *
+ * @hide
+ */
+ public static final int BIDI_RTL = 0x1;
+
+ /**
+ * Bidi flag to detect paragraph direction via heuristics, defaulting to
+ * LTR.
+ *
+ * @hide
+ */
+ public static final int BIDI_DEFAULT_LTR = 0x2;
+
+ /**
+ * Bidi flag to detect paragraph direction via heuristics, defaulting to
+ * RTL.
+ *
+ * @hide
+ */
+ public static final int BIDI_DEFAULT_RTL = 0x3;
+
+ /**
+ * Bidi flag to override direction to all LTR (ignore bidi).
+ *
+ * @hide
+ */
+ public static final int BIDI_FORCE_LTR = 0x4;
+
+ /**
+ * Bidi flag to override direction to all RTL (ignore bidi).
+ *
+ * @hide
+ */
+ public static final int BIDI_FORCE_RTL = 0x5;
+
+ /**
+ * Maximum Bidi flag value.
+ * @hide
+ */
+ private static final int BIDI_MAX_FLAG_VALUE = BIDI_FORCE_RTL;
+
+ /**
+ * Mask for bidi flags.
+ * @hide
+ */
+ private static final int BIDI_FLAG_MASK = 0x7;
+
+ /**
+ * The Style specifies if the primitive being drawn is filled, stroked, or
+ * both (in the same color). The default is FILL.
*/
public enum Style {
/**
@@ -93,7 +150,9 @@
/**
* Geometry and text drawn with this style will be both filled and
* stroked at the same time, respecting the stroke-related fields on
- * the paint.
+ * the paint. This mode can give unexpected results if the geometry
+ * is oriented counter-clockwise. This restriction does not apply to
+ * either FILL or STROKE.
*/
FILL_AND_STROKE (2);
@@ -208,6 +267,7 @@
mHasCompatScaling = paint.mHasCompatScaling;
mCompatScaling = paint.mCompatScaling;
mInvCompatScaling = paint.mInvCompatScaling;
+ mBidiFlags = paint.mBidiFlags;
}
/** Restores the paint to its default settings. */
@@ -216,6 +276,7 @@
setFlags(DEFAULT_PAINT_FLAGS);
mHasCompatScaling = false;
mCompatScaling = mInvCompatScaling = 1;
+ mBidiFlags = BIDI_DEFAULT_LTR;
}
/**
@@ -238,6 +299,7 @@
mHasCompatScaling = src.mHasCompatScaling;
mCompatScaling = src.mCompatScaling;
mInvCompatScaling = src.mInvCompatScaling;
+ mBidiFlags = src.mBidiFlags;
}
}
@@ -252,10 +314,33 @@
mInvCompatScaling = 1.0f/factor;
}
}
-
+
+ /**
+ * Return the bidi flags on the paint.
+ *
+ * @return the bidi flags on the paint
+ * @hide
+ */
+ public int getBidiFlags() {
+ return mBidiFlags;
+ }
+
+ /**
+ * Set the bidi flags on the paint.
+ * @hide
+ */
+ public void setBidiFlags(int flags) {
+ // only flag value is the 3-bit BIDI control setting
+ flags &= BIDI_FLAG_MASK;
+ if (flags > BIDI_MAX_FLAG_VALUE) {
+ throw new IllegalArgumentException("unknown bidi flag: " + flags);
+ }
+ mBidiFlags = flags;
+ }
+
/**
* Return the paint's flags. Use the Flag enum to test flag values.
- *
+ *
* @return the paint's flags (see enums ending in _Flag for bit masks)
*/
public native int getFlags();
diff --git a/graphics/java/android/graphics/PorterDuff.java b/graphics/java/android/graphics/PorterDuff.java
index 3904234..0e405c2 100644
--- a/graphics/java/android/graphics/PorterDuff.java
+++ b/graphics/java/android/graphics/PorterDuff.java
@@ -53,7 +53,10 @@
/** [Sa * Da, Sc * Dc] */
MULTIPLY (14),
/** [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] */
- SCREEN (15);
+ SCREEN (15),
+ /** Saturate(S + D) */
+ ADD (16),
+ OVERLAY (17);
Mode(int nativeInt) {
this.nativeInt = nativeInt;
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 6a7b2d1..4c1d243 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -16,21 +16,30 @@
package android.graphics.drawable;
-import java.io.InputStream;
-import java.io.IOException;
-import java.util.Arrays;
-
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import android.content.res.Resources;
import android.content.res.TypedArray;
-import android.graphics.*;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.NinePatch;
+import android.graphics.PixelFormat;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.graphics.Rect;
+import android.graphics.Region;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.StateSet;
-import android.util.Xml;
import android.util.TypedValue;
+import android.util.Xml;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
/**
* A Drawable is a general abstraction for "something that can be drawn." Most
@@ -645,6 +654,8 @@
* Calling this method on a mutable Drawable will have no effect.
*
* @return This drawable.
+ * @see ConstantState
+ * @see #getConstantState()
*/
public Drawable mutate() {
return this;
@@ -750,6 +761,8 @@
drawable = new StateListDrawable();
} else if (name.equals("level-list")) {
drawable = new LevelListDrawable();
+ } else if (name.equals("mipmap")) {
+ drawable = new MipmapDrawable();
} else if (name.equals("layer-list")) {
drawable = new LayerDrawable();
} else if (name.equals("transition")) {
@@ -771,7 +784,7 @@
} else if (name.equals("inset")) {
drawable = new InsetDrawable();
} else if (name.equals("bitmap")) {
- drawable = new BitmapDrawable();
+ drawable = new BitmapDrawable(r);
if (r != null) {
((BitmapDrawable) drawable).setTargetDensity(r.getDisplayMetrics());
}
@@ -806,6 +819,9 @@
return null;
}
+ /**
+ * Inflate this Drawable from an XML resource.
+ */
public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs)
throws XmlPullParserException, IOException {
@@ -814,6 +830,12 @@
a.recycle();
}
+ /**
+ * Inflate a Drawable from an XML resource.
+ *
+ * @throws XmlPullParserException
+ * @throws IOException
+ */
void inflateWithAttributes(Resources r, XmlPullParser parser,
TypedArray attrs, int visibleAttr)
throws XmlPullParserException, IOException {
@@ -821,12 +843,27 @@
mVisible = attrs.getBoolean(visibleAttr, mVisible);
}
+ /**
+ * This abstract class is used by {@link Drawable}s to store shared constant state and data
+ * between Drawables. {@link BitmapDrawable}s created from the same resource will for instance
+ * share a unique bitmap stored in their ConstantState.
+ *
+ * <p>
+ * {@link #newDrawable(Resources)} can be used as a factory to create new Drawable instances
+ * from this ConstantState.
+ * </p>
+ *
+ * Use {@link Drawable#getConstantState()} to retrieve the ConstantState of a Drawable. Calling
+ * {@link Drawable#mutate()} on a Drawable should typically create a new ConstantState for that
+ * Drawable.
+ */
public static abstract class ConstantState {
/**
* Create a new drawable without supplying resources the caller
* is running in. Note that using this means the density-dependent
* drawables (like bitmaps) will not be able to update their target
- * density correctly.
+ * density correctly. One should use {@link #newDrawable(Resources)}
+ * instead to provide a resource.
*/
public abstract Drawable newDrawable();
/**
@@ -845,6 +882,13 @@
public abstract int getChangingConfigurations();
}
+ /**
+ * Return a {@link ConstantState} instance that holds the shared state of this Drawable.
+ *q
+ * @return The ConstantState associated to that Drawable.
+ * @see ConstantState
+ * @see Drawable#mutate()
+ */
public ConstantState getConstantState() {
return null;
}
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index c6f57d4..124d907 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -17,8 +17,16 @@
package android.graphics.drawable;
import android.content.res.Resources;
-import android.graphics.*;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+/**
+ * A helper class that contains several {@link Drawable}s and selects which one to use.
+ *
+ * You can subclass it to create your own DrawableContainers or directly use one its child classes.
+ */
public class DrawableContainer extends Drawable implements Drawable.Callback {
/**
@@ -196,8 +204,7 @@
mDrawableContainerState.getOpacity();
}
- public boolean selectDrawable(int idx)
- {
+ public boolean selectDrawable(int idx) {
if (idx == mCurIndex) {
return false;
}
@@ -255,6 +262,12 @@
return this;
}
+ /**
+ * A ConstantState that can contain several {@link Drawable}s.
+ *
+ * This class was made public to enable testing, and its visibility may change in a future
+ * release.
+ */
public abstract static class DrawableContainerState extends ConstantState {
final DrawableContainer mOwner;
@@ -443,12 +456,12 @@
return mConstantMinimumHeight;
}
- private void computeConstantSize() {
+ protected void computeConstantSize() {
mComputedConstantSize = true;
final int N = getChildCount();
final Drawable[] drawables = mDrawables;
- mConstantWidth = mConstantHeight = 0;
+ mConstantWidth = mConstantHeight = -1;
mConstantMinimumWidth = mConstantMinimumHeight = 0;
for (int i = 0; i < N; i++) {
Drawable dr = drawables[i];
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index 389fd40..b727d47 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -265,6 +265,7 @@
*/
public boolean setDrawableByLayerId(int id, Drawable drawable) {
final ChildDrawable[] layers = mLayerState.mChildren;
+ drawable.setCallback(this);
for (int i = mLayerState.mNum - 1; i >= 0; i--) {
if (layers[i].mId == id) {
diff --git a/graphics/java/android/graphics/drawable/MipmapDrawable.java b/graphics/java/android/graphics/drawable/MipmapDrawable.java
new file mode 100644
index 0000000..75fdeed
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/MipmapDrawable.java
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics.drawable;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+
+import java.io.IOException;
+
+/**
+ * A resource that manages a number of alternate Drawables, and which actually draws the one which
+ * size matches the most closely the drawing bounds. Providing several pre-scaled version of the
+ * drawable helps minimizing the aliasing artifacts that can be introduced by the scaling.
+ *
+ * <p>
+ * Use {@link #addDrawable(Drawable)} to define the different Drawables that will represent the
+ * mipmap levels of this MipmapDrawable. The mipmap Drawable that will actually be used when this
+ * MipmapDrawable is drawn is the one which has the smallest intrinsic height greater or equal than
+ * the bounds' height. This selection ensures that the best available mipmap level is scaled down to
+ * draw this MipmapDrawable.
+ * </p>
+ *
+ * If the bounds' height is larger than the largest mipmap, the largest mipmap will be scaled up.
+ * Note that Drawables without intrinsic height (i.e. with a negative value, such as Color) will
+ * only be used if no other mipmap Drawable are provided. The Drawables' intrinsic heights should
+ * not be changed after the Drawable has been added to this MipmapDrawable.
+ *
+ * <p>
+ * The different mipmaps' parameters (opacity, padding, color filter, gravity...) should typically
+ * be similar to ensure a continuous visual appearance when the MipmapDrawable is scaled. The aspect
+ * ratio of the different mipmaps should especially be equal.
+ * </p>
+ *
+ * A typical example use of a MipmapDrawable would be for an image which is intended to be scaled at
+ * various sizes, and for which one wants to provide pre-scaled versions to precisely control its
+ * appearance.
+ *
+ * <p>
+ * The intrinsic size of a MipmapDrawable are inferred from those of the largest mipmap (in terms of
+ * {@link Drawable#getIntrinsicHeight()}). On the opposite, its minimum
+ * size is defined by the smallest provided mipmap.
+ * </p>
+
+ * It can be defined in an XML file with the <code><mipmap></code> element.
+ * Each mipmap Drawable is defined in a nested <code><item></code>. For example:
+ * <pre>
+ * <mipmap xmlns:android="http://schemas.android.com/apk/res/android">
+ * <item android:drawable="@drawable/my_image_8" />
+ * <item android:drawable="@drawable/my_image_32" />
+ * <item android:drawable="@drawable/my_image_128" />
+ * </mipmap>
+ *</pre>
+ * <p>
+ * With this XML saved into the res/drawable/ folder of the project, it can be referenced as
+ * the drawable for an {@link android.widget.ImageView}. Assuming that the heights of the provided
+ * drawables are respectively 8, 32 and 128 pixels, the first one will be scaled down when the
+ * bounds' height is lower or equal than 8 pixels. The second drawable will then be used up to a
+ * height of 32 pixels and the largest drawable will be used for greater heights.
+ * </p>
+ * @attr ref android.R.styleable#MipmapDrawableItem_drawable
+ */
+public class MipmapDrawable extends DrawableContainer {
+ private final MipmapContainerState mMipmapContainerState;
+ private boolean mMutated;
+
+ public MipmapDrawable() {
+ this(null, null);
+ }
+
+ /**
+ * Adds a Drawable to the list of available mipmap Drawables. The Drawable actually used when
+ * this MipmapDrawable is drawn is determined from its bounds.
+ *
+ * This method has no effect if drawable is null.
+ *
+ * @param drawable The Drawable that will be added to list of available mipmap Drawables.
+ */
+
+ public void addDrawable(Drawable drawable) {
+ if (drawable != null) {
+ mMipmapContainerState.addDrawable(drawable);
+ onDrawableAdded();
+ }
+ }
+
+ private void onDrawableAdded() {
+ // selectDrawable assumes that the container content does not change.
+ // When a Drawable is added, the same index can correspond to a new Drawable, and since
+ // selectDrawable has a fast exit case when oldIndex==newIndex, the new drawable could end
+ // up not being used in place of the previous one if they happen to share the same index.
+ // This make sure the new computed index can actually replace the previous one.
+ selectDrawable(-1);
+ onBoundsChange(getBounds());
+ }
+
+ // overrides from Drawable
+
+ @Override
+ protected void onBoundsChange(Rect bounds) {
+ final int index = mMipmapContainerState.indexForBounds(bounds);
+
+ // Will call invalidateSelf() if needed
+ selectDrawable(index);
+
+ super.onBoundsChange(bounds);
+ }
+
+ @Override
+ public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs)
+ throws XmlPullParserException, IOException {
+
+ super.inflate(r, parser, attrs);
+
+ int type;
+
+ final int innerDepth = parser.getDepth() + 1;
+ int depth;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && ((depth = parser.getDepth()) >= innerDepth
+ || type != XmlPullParser.END_TAG)) {
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+
+ if (depth > innerDepth || !parser.getName().equals("item")) {
+ continue;
+ }
+
+ TypedArray a = r.obtainAttributes(attrs,
+ com.android.internal.R.styleable.MipmapDrawableItem);
+
+ int drawableRes = a.getResourceId(
+ com.android.internal.R.styleable.MipmapDrawableItem_drawable, 0);
+
+ a.recycle();
+
+ Drawable dr;
+ if (drawableRes != 0) {
+ dr = r.getDrawable(drawableRes);
+ } else {
+ while ((type = parser.next()) == XmlPullParser.TEXT) {
+ }
+ if (type != XmlPullParser.START_TAG) {
+ throw new XmlPullParserException(
+ parser.getPositionDescription()
+ + ": <item> tag requires a 'drawable' attribute or "
+ + "child tag defining a drawable");
+ }
+ dr = Drawable.createFromXmlInner(r, parser, attrs);
+ }
+
+ mMipmapContainerState.addDrawable(dr);
+ }
+
+ onDrawableAdded();
+ }
+
+ @Override
+ public Drawable mutate() {
+ if (!mMutated && super.mutate() == this) {
+ mMipmapContainerState.mMipmapHeights = mMipmapContainerState.mMipmapHeights.clone();
+ mMutated = true;
+ }
+ return this;
+ }
+
+ private final static class MipmapContainerState extends DrawableContainerState {
+ private int[] mMipmapHeights;
+
+ MipmapContainerState(MipmapContainerState orig, MipmapDrawable owner, Resources res) {
+ super(orig, owner, res);
+
+ if (orig != null) {
+ mMipmapHeights = orig.mMipmapHeights;
+ } else {
+ mMipmapHeights = new int[getChildren().length];
+ }
+
+ // Change the default value
+ setConstantSize(true);
+ }
+
+ /**
+ * Returns the index of the child mipmap drawable that will best fit the provided bounds.
+ * This index is determined by comparing bounds' height and children intrinsic heights.
+ * The returned mipmap index is the smallest mipmap which height is greater or equal than
+ * the bounds' height. If the bounds' height is larger than the largest mipmap, the largest
+ * mipmap index is returned.
+ *
+ * @param bounds The bounds of the MipMapDrawable.
+ * @return The index of the child Drawable that will best fit these bounds, or -1 if there
+ * are no children mipmaps.
+ */
+ public int indexForBounds(Rect bounds) {
+ final int boundsHeight = bounds.height();
+ final int N = getChildCount();
+ for (int i = 0; i < N; i++) {
+ if (boundsHeight <= mMipmapHeights[i]) {
+ return i;
+ }
+ }
+
+ // No mipmap larger than bounds found. Use largest one which will be scaled up.
+ if (N > 0) {
+ return N - 1;
+ }
+ // No Drawable mipmap at all
+ return -1;
+ }
+
+ /**
+ * Adds a Drawable to the list of available mipmap Drawables. This list can be retrieved
+ * using {@link DrawableContainer.DrawableContainerState#getChildren()} and this method
+ * ensures that it is always sorted by increasing {@link Drawable#getIntrinsicHeight()}.
+ *
+ * @param drawable The Drawable that will be added to children list
+ */
+ public void addDrawable(Drawable drawable) {
+ // Insert drawable in last position, correctly resetting cached values and
+ // especially mComputedConstantSize
+ int pos = addChild(drawable);
+
+ // Bubble sort the last drawable to restore the sort by intrinsic height
+ final int drawableHeight = drawable.getIntrinsicHeight();
+
+ while (pos > 0) {
+ final Drawable previousDrawable = mDrawables[pos-1];
+ final int previousIntrinsicHeight = previousDrawable.getIntrinsicHeight();
+
+ if (drawableHeight < previousIntrinsicHeight) {
+ mDrawables[pos] = previousDrawable;
+ mMipmapHeights[pos] = previousIntrinsicHeight;
+
+ mDrawables[pos-1] = drawable;
+ mMipmapHeights[pos-1] = drawableHeight;
+ pos--;
+ } else {
+ break;
+ }
+ }
+ }
+
+ /**
+ * Intrinsic sizes are those of the largest available mipmap.
+ * Minimum sizes are those of the smallest available mipmap.
+ */
+ @Override
+ protected void computeConstantSize() {
+ final int N = getChildCount();
+ if (N > 0) {
+ final Drawable smallestDrawable = mDrawables[0];
+ mConstantMinimumWidth = smallestDrawable.getMinimumWidth();
+ mConstantMinimumHeight = smallestDrawable.getMinimumHeight();
+
+ final Drawable largestDrawable = mDrawables[N-1];
+ mConstantWidth = largestDrawable.getIntrinsicWidth();
+ mConstantHeight = largestDrawable.getIntrinsicHeight();
+ } else {
+ mConstantWidth = mConstantHeight = -1;
+ mConstantMinimumWidth = mConstantMinimumHeight = 0;
+ }
+ mComputedConstantSize = true;
+ }
+
+ @Override
+ public Drawable newDrawable() {
+ return new MipmapDrawable(this, null);
+ }
+
+ @Override
+ public Drawable newDrawable(Resources res) {
+ return new MipmapDrawable(this, res);
+ }
+
+ @Override
+ public void growArray(int oldSize, int newSize) {
+ super.growArray(oldSize, newSize);
+ int[] newInts = new int[newSize];
+ System.arraycopy(mMipmapHeights, 0, newInts, 0, oldSize);
+ mMipmapHeights = newInts;
+ }
+ }
+
+ private MipmapDrawable(MipmapContainerState state, Resources res) {
+ MipmapContainerState as = new MipmapContainerState(state, this, res);
+ mMipmapContainerState = as;
+ setConstantState(as);
+ onDrawableAdded();
+ }
+}
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index 17c0778..d32a0b5 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -76,10 +76,30 @@
subData1D(0, mType.getElementCount(), d);
}
+ public void subData(int off, FieldPacker fp) {
+ int eSize = mType.mElement.getSizeBytes();
+ final byte[] data = fp.getData();
+
+ int count = data.length / eSize;
+ if ((eSize * count) != data.length) {
+ throw new IllegalArgumentException("Field packer length " + data.length +
+ " not divisible by element size " + eSize + ".");
+ }
+ data1DChecks(off, count, data.length, data.length);
+ mRS.nAllocationSubData1D(mID, off, count, data, data.length);
+ }
+
private void data1DChecks(int off, int count, int len, int dataSize) {
mRS.validate();
- if((off < 0) || (count < 1) || ((off + count) > mType.getElementCount())) {
- throw new IllegalArgumentException("Offset or Count out of bounds.");
+ if(off < 0) {
+ throw new IllegalArgumentException("Offset must be >= 0.");
+ }
+ if(count < 1) {
+ throw new IllegalArgumentException("Count must be >= 1.");
+ }
+ if((off + count) > mType.getElementCount()) {
+ throw new IllegalArgumentException("Overflow, Available count " + mType.getElementCount() +
+ ", got " + count + " at offset " + off + ".");
}
if((len) < dataSize) {
throw new IllegalArgumentException("Array too small for allocation type.");
diff --git a/graphics/java/android/renderscript/Vector2f.java b/graphics/java/android/renderscript/Byte2.java
similarity index 89%
copy from graphics/java/android/renderscript/Vector2f.java
copy to graphics/java/android/renderscript/Byte2.java
index 567d57fa..95cf88c 100644
--- a/graphics/java/android/renderscript/Vector2f.java
+++ b/graphics/java/android/renderscript/Byte2.java
@@ -24,12 +24,12 @@
* @hide
*
**/
-public class Vector2f {
- public Vector2f() {
+public class Byte2 {
+ public Byte2() {
}
- public float x;
- public float y;
+ public byte x;
+ public byte y;
}
diff --git a/graphics/java/android/renderscript/Vector2f.java b/graphics/java/android/renderscript/Byte3.java
similarity index 87%
copy from graphics/java/android/renderscript/Vector2f.java
copy to graphics/java/android/renderscript/Byte3.java
index 567d57fa..a6c0ca9 100644
--- a/graphics/java/android/renderscript/Vector2f.java
+++ b/graphics/java/android/renderscript/Byte3.java
@@ -24,12 +24,13 @@
* @hide
*
**/
-public class Vector2f {
- public Vector2f() {
+public class Byte3 {
+ public Byte3() {
}
- public float x;
- public float y;
+ public byte x;
+ public byte y;
+ public byte z;
}
diff --git a/graphics/java/android/renderscript/Vector2f.java b/graphics/java/android/renderscript/Byte4.java
similarity index 85%
copy from graphics/java/android/renderscript/Vector2f.java
copy to graphics/java/android/renderscript/Byte4.java
index 567d57fa..a5bfc61 100644
--- a/graphics/java/android/renderscript/Vector2f.java
+++ b/graphics/java/android/renderscript/Byte4.java
@@ -24,14 +24,15 @@
* @hide
*
**/
-public class Vector2f {
- public Vector2f() {
+public class Byte4 {
+ public Byte4() {
}
- public float x;
- public float y;
+ public byte x;
+ public byte y;
+ public byte z;
+ public byte w;
}
-
diff --git a/graphics/java/android/renderscript/Element.java b/graphics/java/android/renderscript/Element.java
index 10ef05a..22291e6 100644
--- a/graphics/java/android/renderscript/Element.java
+++ b/graphics/java/android/renderscript/Element.java
@@ -72,12 +72,6 @@
public enum DataKind {
USER (0),
- COLOR (1),
- POSITION (2),
- TEXTURE (3),
- NORMAL (4),
- INDEX (5),
- POINT_SIZE(6),
PIXEL_L (7),
PIXEL_A (8),
@@ -91,41 +85,126 @@
}
}
- public static Element USER_U8(RenderScript rs) {
- if(rs.mElement_USER_U8 == null) {
- rs.mElement_USER_U8 = createUser(rs, DataType.UNSIGNED_8);
+ public static Element U8(RenderScript rs) {
+ if(rs.mElement_U8 == null) {
+ rs.mElement_U8 = createUser(rs, DataType.UNSIGNED_8);
}
- return rs.mElement_USER_U8;
+ return rs.mElement_U8;
}
- public static Element USER_I8(RenderScript rs) {
- if(rs.mElement_USER_I8 == null) {
- rs.mElement_USER_I8 = createUser(rs, DataType.SIGNED_8);
+ public static Element I8(RenderScript rs) {
+ if(rs.mElement_I8 == null) {
+ rs.mElement_I8 = createUser(rs, DataType.SIGNED_8);
}
- return rs.mElement_USER_I8;
+ return rs.mElement_I8;
}
- public static Element USER_U32(RenderScript rs) {
- if(rs.mElement_USER_U32 == null) {
- rs.mElement_USER_U32 = createUser(rs, DataType.UNSIGNED_32);
+ public static Element U16(RenderScript rs) {
+ if(rs.mElement_U16 == null) {
+ rs.mElement_U16 = createUser(rs, DataType.UNSIGNED_16);
}
- return rs.mElement_USER_U32;
+ return rs.mElement_U16;
}
- public static Element USER_I32(RenderScript rs) {
- if(rs.mElement_USER_I32 == null) {
- rs.mElement_USER_I32 = createUser(rs, DataType.SIGNED_32);
+ public static Element I16(RenderScript rs) {
+ if(rs.mElement_I16 == null) {
+ rs.mElement_I16 = createUser(rs, DataType.SIGNED_16);
}
- return rs.mElement_USER_I32;
+ return rs.mElement_I16;
}
- public static Element USER_F32(RenderScript rs) {
- if(rs.mElement_USER_F32 == null) {
- rs.mElement_USER_F32 = createUser(rs, DataType.FLOAT_32);
+ public static Element U32(RenderScript rs) {
+ if(rs.mElement_U32 == null) {
+ rs.mElement_U32 = createUser(rs, DataType.UNSIGNED_32);
}
- return rs.mElement_USER_F32;
+ return rs.mElement_U32;
}
+ public static Element I32(RenderScript rs) {
+ if(rs.mElement_I32 == null) {
+ rs.mElement_I32 = createUser(rs, DataType.SIGNED_32);
+ }
+ return rs.mElement_I32;
+ }
+
+ public static Element F32(RenderScript rs) {
+ if(rs.mElement_F32 == null) {
+ rs.mElement_F32 = createUser(rs, DataType.FLOAT_32);
+ }
+ return rs.mElement_F32;
+ }
+
+ public static Element ELEMENT(RenderScript rs) {
+ if(rs.mElement_ELEMENT == null) {
+ rs.mElement_ELEMENT = createUser(rs, DataType.RS_ELEMENT);
+ }
+ return rs.mElement_ELEMENT;
+ }
+
+ public static Element TYPE(RenderScript rs) {
+ if(rs.mElement_TYPE == null) {
+ rs.mElement_TYPE = createUser(rs, DataType.RS_TYPE);
+ }
+ return rs.mElement_TYPE;
+ }
+
+ public static Element ALLOCATION(RenderScript rs) {
+ if(rs.mElement_ALLOCATION == null) {
+ rs.mElement_ALLOCATION = createUser(rs, DataType.RS_ALLOCATION);
+ }
+ return rs.mElement_ALLOCATION;
+ }
+
+ public static Element SAMPLER(RenderScript rs) {
+ if(rs.mElement_SAMPLER == null) {
+ rs.mElement_SAMPLER = createUser(rs, DataType.RS_SAMPLER);
+ }
+ return rs.mElement_SAMPLER;
+ }
+
+ public static Element SCRIPT(RenderScript rs) {
+ if(rs.mElement_SCRIPT == null) {
+ rs.mElement_SCRIPT = createUser(rs, DataType.RS_SCRIPT);
+ }
+ return rs.mElement_SCRIPT;
+ }
+
+ public static Element MESH(RenderScript rs) {
+ if(rs.mElement_MESH == null) {
+ rs.mElement_MESH = createUser(rs, DataType.RS_MESH);
+ }
+ return rs.mElement_MESH;
+ }
+
+ public static Element PROGRAM_FRAGMENT(RenderScript rs) {
+ if(rs.mElement_PROGRAM_FRAGMENT == null) {
+ rs.mElement_PROGRAM_FRAGMENT = createUser(rs, DataType.RS_PROGRAM_FRAGMENT);
+ }
+ return rs.mElement_PROGRAM_FRAGMENT;
+ }
+
+ public static Element PROGRAM_VERTEX(RenderScript rs) {
+ if(rs.mElement_PROGRAM_VERTEX == null) {
+ rs.mElement_PROGRAM_VERTEX = createUser(rs, DataType.RS_PROGRAM_VERTEX);
+ }
+ return rs.mElement_PROGRAM_VERTEX;
+ }
+
+ public static Element PROGRAM_RASTER(RenderScript rs) {
+ if(rs.mElement_PROGRAM_RASTER == null) {
+ rs.mElement_PROGRAM_RASTER = createUser(rs, DataType.RS_PROGRAM_RASTER);
+ }
+ return rs.mElement_PROGRAM_RASTER;
+ }
+
+ public static Element PROGRAM_STORE(RenderScript rs) {
+ if(rs.mElement_PROGRAM_STORE == null) {
+ rs.mElement_PROGRAM_STORE = createUser(rs, DataType.RS_PROGRAM_STORE);
+ }
+ return rs.mElement_PROGRAM_STORE;
+ }
+
+
public static Element A_8(RenderScript rs) {
if(rs.mElement_A_8 == null) {
rs.mElement_A_8 = createPixel(rs, DataType.UNSIGNED_8, DataKind.PIXEL_A);
@@ -168,54 +247,34 @@
return rs.mElement_RGBA_8888;
}
- public static Element INDEX_16(RenderScript rs) {
- if(rs.mElement_INDEX_16 == null) {
- rs.mElement_INDEX_16 = createIndex(rs);
+ public static Element F32_2(RenderScript rs) {
+ if(rs.mElement_FLOAT_2 == null) {
+ rs.mElement_FLOAT_2 = createVector(rs, DataType.FLOAT_32, 2);
}
- return rs.mElement_INDEX_16;
+ return rs.mElement_FLOAT_2;
}
- public static Element ATTRIB_POSITION_2(RenderScript rs) {
- if(rs.mElement_POSITION_2 == null) {
- rs.mElement_POSITION_2 = createAttrib(rs, DataType.FLOAT_32, DataKind.POSITION, 2);
+ public static Element F32_3(RenderScript rs) {
+ if(rs.mElement_FLOAT_3 == null) {
+ rs.mElement_FLOAT_3 = createVector(rs, DataType.FLOAT_32, 3);
}
- return rs.mElement_POSITION_2;
+ return rs.mElement_FLOAT_3;
}
- public static Element ATTRIB_POSITION_3(RenderScript rs) {
- if(rs.mElement_POSITION_3 == null) {
- rs.mElement_POSITION_3 = createAttrib(rs, DataType.FLOAT_32, DataKind.POSITION, 3);
+ public static Element F32_4(RenderScript rs) {
+ if(rs.mElement_FLOAT_4 == null) {
+ rs.mElement_FLOAT_4 = createVector(rs, DataType.FLOAT_32, 4);
}
- return rs.mElement_POSITION_3;
+ return rs.mElement_FLOAT_4;
}
- public static Element ATTRIB_TEXTURE_2(RenderScript rs) {
- if(rs.mElement_TEXTURE_2 == null) {
- rs.mElement_TEXTURE_2 = createAttrib(rs, DataType.FLOAT_32, DataKind.TEXTURE, 2);
+ public static Element U8_4(RenderScript rs) {
+ if(rs.mElement_UCHAR_4 == null) {
+ rs.mElement_UCHAR_4 = createVector(rs, DataType.UNSIGNED_8, 4);
}
- return rs.mElement_TEXTURE_2;
+ return rs.mElement_UCHAR_4;
}
- public static Element ATTRIB_NORMAL_3(RenderScript rs) {
- if(rs.mElement_NORMAL_3 == null) {
- rs.mElement_NORMAL_3 = createAttrib(rs, DataType.FLOAT_32, DataKind.NORMAL, 3);
- }
- return rs.mElement_NORMAL_3;
- }
-
- public static Element ATTRIB_COLOR_U8_4(RenderScript rs) {
- if(rs.mElement_COLOR_U8_4 == null) {
- rs.mElement_COLOR_U8_4 = createAttrib(rs, DataType.UNSIGNED_8, DataKind.COLOR, 4);
- }
- return rs.mElement_COLOR_U8_4;
- }
-
- public static Element ATTRIB_COLOR_F32_4(RenderScript rs) {
- if(rs.mElement_COLOR_F32_4 == null) {
- rs.mElement_COLOR_F32_4 = createAttrib(rs, DataType.FLOAT_32, DataKind.COLOR, 4);
- }
- return rs.mElement_COLOR_F32_4;
- }
Element(RenderScript rs, Element[] e, String[] n) {
super(rs);
@@ -244,29 +303,6 @@
super.destroy();
}
- public static Element createFromClass(RenderScript rs, Class c) {
- rs.validate();
- Field[] fields = c.getFields();
- Builder b = new Builder(rs);
-
- for(Field f: fields) {
- Class fc = f.getType();
- if(fc == int.class) {
- b.add(createUser(rs, DataType.SIGNED_32), f.getName());
- } else if(fc == short.class) {
- b.add(createUser(rs, DataType.SIGNED_16), f.getName());
- } else if(fc == byte.class) {
- b.add(createUser(rs, DataType.SIGNED_8), f.getName());
- } else if(fc == float.class) {
- b.add(createUser(rs, DataType.FLOAT_32), f.getName());
- } else {
- throw new IllegalArgumentException("Unkown field type");
- }
- }
- return b.create();
- }
-
-
/////////////////////////////////////////
public static Element createUser(RenderScript rs, DataType dt) {
return new Element(rs, dt, DataKind.USER, false, 1);
@@ -279,59 +315,6 @@
return new Element(rs, dt, DataKind.USER, false, size);
}
- public static Element createIndex(RenderScript rs) {
- return new Element(rs, DataType.UNSIGNED_16, DataKind.INDEX, false, 1);
- }
-
- public static Element createAttrib(RenderScript rs, DataType dt, DataKind dk, int size) {
- if (!(dt == DataType.FLOAT_32 ||
- dt == DataType.UNSIGNED_8 ||
- dt == DataType.UNSIGNED_16 ||
- dt == DataType.UNSIGNED_32 ||
- dt == DataType.SIGNED_8 ||
- dt == DataType.SIGNED_16 ||
- dt == DataType.SIGNED_32)) {
- throw new IllegalArgumentException("Unsupported DataType");
- }
-
- if (!(dk == DataKind.COLOR ||
- dk == DataKind.POSITION ||
- dk == DataKind.TEXTURE ||
- dk == DataKind.NORMAL ||
- dk == DataKind.POINT_SIZE ||
- dk == DataKind.USER)) {
- throw new IllegalArgumentException("Unsupported DataKind");
- }
-
- if (dk == DataKind.COLOR &&
- ((dt != DataType.FLOAT_32 && dt != DataType.UNSIGNED_8) ||
- size < 3 || size > 4)) {
- throw new IllegalArgumentException("Bad combo");
- }
- if (dk == DataKind.POSITION && (size < 1 || size > 4)) {
- throw new IllegalArgumentException("Bad combo");
- }
- if (dk == DataKind.TEXTURE &&
- (dt != DataType.FLOAT_32 || size < 1 || size > 4)) {
- throw new IllegalArgumentException("Bad combo");
- }
- if (dk == DataKind.NORMAL &&
- (dt != DataType.FLOAT_32 || size != 3)) {
- throw new IllegalArgumentException("Bad combo");
- }
- if (dk == DataKind.POINT_SIZE &&
- (dt != DataType.FLOAT_32 || size != 1)) {
- throw new IllegalArgumentException("Bad combo");
- }
-
- boolean norm = false;
- if (dk == DataKind.COLOR && dt == DataType.UNSIGNED_8) {
- norm = true;
- }
-
- return new Element(rs, dt, dk, norm, size);
- }
-
public static Element createPixel(RenderScript rs, DataType dt, DataKind dk) {
if (!(dk == DataKind.PIXEL_L ||
dk == DataKind.PIXEL_A ||
diff --git a/graphics/java/android/renderscript/FieldPacker.java b/graphics/java/android/renderscript/FieldPacker.java
index b26e47d..6d55c7e 100644
--- a/graphics/java/android/renderscript/FieldPacker.java
+++ b/graphics/java/android/renderscript/FieldPacker.java
@@ -33,21 +33,24 @@
}
}
- void reset() {
+ public void reset() {
mPos = 0;
}
+ public void reset(int i) {
+ mPos = i;
+ }
- void addI8(byte v) {
+ public void addI8(byte v) {
mData[mPos++] = v;
}
- void addI16(short v) {
+ public void addI16(short v) {
align(2);
mData[mPos++] = (byte)(v & 0xff);
mData[mPos++] = (byte)(v >> 8);
}
- void addI32(int v) {
+ public void addI32(int v) {
align(4);
mData[mPos++] = (byte)(v & 0xff);
mData[mPos++] = (byte)((v >> 8) & 0xff);
@@ -55,7 +58,7 @@
mData[mPos++] = (byte)((v >> 24) & 0xff);
}
- void addI64(long v) {
+ public void addI64(long v) {
align(8);
mData[mPos++] = (byte)(v & 0xff);
mData[mPos++] = (byte)((v >> 8) & 0xff);
@@ -67,14 +70,14 @@
mData[mPos++] = (byte)((v >> 56) & 0xff);
}
- void addU8(short v) {
+ public void addU8(short v) {
if ((v < 0) || (v > 0xff)) {
throw new IllegalArgumentException("Saving value out of range for type");
}
mData[mPos++] = (byte)v;
}
- void addU16(int v) {
+ public void addU16(int v) {
if ((v < 0) || (v > 0xffff)) {
throw new IllegalArgumentException("Saving value out of range for type");
}
@@ -83,7 +86,7 @@
mData[mPos++] = (byte)(v >> 8);
}
- void addU32(long v) {
+ public void addU32(long v) {
if ((v < 0) || (v > 0xffffffff)) {
throw new IllegalArgumentException("Saving value out of range for type");
}
@@ -94,7 +97,7 @@
mData[mPos++] = (byte)((v >> 24) & 0xff);
}
- void addU64(long v) {
+ public void addU64(long v) {
if (v < 0) {
throw new IllegalArgumentException("Saving value out of range for type");
}
@@ -109,15 +112,135 @@
mData[mPos++] = (byte)((v >> 56) & 0xff);
}
- void addF32(float v) {
+ public void addF32(float v) {
addI32(Float.floatToRawIntBits(v));
}
- void addF64(float v) {
+ public void addF64(float v) {
addI64(Double.doubleToRawLongBits(v));
}
- final byte[] getData() {
+ public void addObj(BaseObj obj) {
+ if (obj != null) {
+ addI32(obj.getID());
+ } else {
+ addI32(0);
+ }
+ }
+
+ public void addF32(Float2 v) {
+ addF32(v.x);
+ addF32(v.y);
+ }
+ public void addF32(Float3 v) {
+ addF32(v.x);
+ addF32(v.y);
+ addF32(v.z);
+ }
+ public void addF32(Float4 v) {
+ addF32(v.x);
+ addF32(v.y);
+ addF32(v.z);
+ addF32(v.w);
+ }
+
+ public void addI8(Byte2 v) {
+ addI8(v.x);
+ addI8(v.y);
+ }
+ public void addI8(Byte3 v) {
+ addI8(v.x);
+ addI8(v.y);
+ addI8(v.z);
+ }
+ public void addI8(Byte4 v) {
+ addI8(v.x);
+ addI8(v.y);
+ addI8(v.z);
+ addI8(v.w);
+ }
+
+ public void addU8(Short2 v) {
+ addU8(v.x);
+ addU8(v.y);
+ }
+ public void addU8(Short3 v) {
+ addU8(v.x);
+ addU8(v.y);
+ addU8(v.z);
+ }
+ public void addU8(Short4 v) {
+ addU8(v.x);
+ addU8(v.y);
+ addU8(v.z);
+ addU8(v.w);
+ }
+
+ public void addI16(Short2 v) {
+ addI16(v.x);
+ addI16(v.y);
+ }
+ public void addI16(Short3 v) {
+ addI16(v.x);
+ addI16(v.y);
+ addI16(v.z);
+ }
+ public void addI16(Short4 v) {
+ addI16(v.x);
+ addI16(v.y);
+ addI16(v.z);
+ addI16(v.w);
+ }
+
+ public void addU16(Int2 v) {
+ addU16(v.x);
+ addU16(v.y);
+ }
+ public void addU16(Int3 v) {
+ addU16(v.x);
+ addU16(v.y);
+ addU16(v.z);
+ }
+ public void addU16(Int4 v) {
+ addU16(v.x);
+ addU16(v.y);
+ addU16(v.z);
+ addU16(v.w);
+ }
+
+ public void addI32(Int2 v) {
+ addI32(v.x);
+ addI32(v.y);
+ }
+ public void addI32(Int3 v) {
+ addI32(v.x);
+ addI32(v.y);
+ addI32(v.z);
+ }
+ public void addI32(Int4 v) {
+ addI32(v.x);
+ addI32(v.y);
+ addI32(v.z);
+ addI32(v.w);
+ }
+
+ public void addU32(Int2 v) {
+ addU32(v.x);
+ addU32(v.y);
+ }
+ public void addU32(Int3 v) {
+ addU32(v.x);
+ addU32(v.y);
+ addU32(v.z);
+ }
+ public void addU32(Int4 v) {
+ addU32(v.x);
+ addU32(v.y);
+ addU32(v.z);
+ addU32(v.w);
+ }
+
+ public final byte[] getData() {
return mData;
}
diff --git a/graphics/java/android/renderscript/FileA3D.java b/graphics/java/android/renderscript/FileA3D.java
new file mode 100644
index 0000000..fb36f1f
--- /dev/null
+++ b/graphics/java/android/renderscript/FileA3D.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.renderscript;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import android.content.res.Resources;
+import android.content.res.AssetManager;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.util.Log;
+import android.util.TypedValue;
+
+/**
+ * @hide
+ *
+ **/
+public class FileA3D extends BaseObj {
+
+ public enum ClassID {
+
+ UNKNOWN,
+ MESH,
+ SIMPLE_MESH,
+ TYPE,
+ ELEMENT,
+ ALLOCATION,
+ PROGRAM_VERTEX,
+ PROGRAM_RASTER,
+ PROGRAM_FRAGMENT,
+ PROGRAM_STORE,
+ SAMPLER,
+ ANIMATION,
+ LIGHT,
+ ADAPTER_1D,
+ ADAPTER_2D,
+ SCRIPT_C;
+
+ public static ClassID toClassID(int intID) {
+ return ClassID.values()[intID];
+ }
+ }
+
+ // Read only class with index entries
+ public class IndexEntry {
+ RenderScript mRS;
+ int mIndex;
+ int mID;
+ String mName;
+ ClassID mClassID;
+ BaseObj mLoadedObj;
+
+ public String getName() {
+ return mName;
+ }
+
+ public ClassID getClassID() {
+ return mClassID;
+ }
+
+ public BaseObj getObject() {
+ if(mLoadedObj != null) {
+ return mLoadedObj;
+ }
+
+ if(mClassID == ClassID.UNKNOWN) {
+ return null;
+ }
+
+ int objectID = mRS.nFileA3DGetEntryByIndex(mID, mIndex);
+ if(objectID == 0) {
+ return null;
+ }
+
+ switch (mClassID) {
+ case MESH:
+ mLoadedObj = null;
+ break;
+ case SIMPLE_MESH:
+ mLoadedObj = new SimpleMesh(objectID, mRS);
+ break;
+ case TYPE:
+ mLoadedObj = new Type(objectID, mRS);
+ break;
+ case ELEMENT:
+ mLoadedObj = null;
+ break;
+ case ALLOCATION:
+ mLoadedObj = null;
+ break;
+ case PROGRAM_VERTEX:
+ mLoadedObj = new ProgramVertex(objectID, mRS);
+ break;
+ case PROGRAM_RASTER:
+ break;
+ case PROGRAM_FRAGMENT:
+ break;
+ case PROGRAM_STORE:
+ break;
+ case SAMPLER:
+ break;
+ case ANIMATION:
+ break;
+ case LIGHT:
+ break;
+ case ADAPTER_1D:
+ break;
+ case ADAPTER_2D:
+ break;
+ case SCRIPT_C:
+ break;
+ }
+
+ return mLoadedObj;
+ }
+
+ IndexEntry(RenderScript rs, int index, int id, String name, ClassID classID) {
+ mRS = rs;
+ mIndex = index;
+ mID = id;
+ mName = name;
+ mClassID = classID;
+ mLoadedObj = null;
+ }
+ }
+
+ IndexEntry[] mFileEntries;
+
+ FileA3D(int id, RenderScript rs) {
+ super(rs);
+ mID = id;
+ }
+
+ private void initEntries() {
+ int numFileEntries = mRS.nFileA3DGetNumIndexEntries(mID);
+ if(numFileEntries <= 0) {
+ return;
+ }
+
+ mFileEntries = new IndexEntry[numFileEntries];
+ int[] ids = new int[numFileEntries];
+ String[] names = new String[numFileEntries];
+
+ mRS.nFileA3DGetIndexEntries(mID, numFileEntries, ids, names);
+
+ for(int i = 0; i < numFileEntries; i ++) {
+ mFileEntries[i] = new IndexEntry(mRS, i, mID, names[i], ClassID.toClassID(ids[i]));
+ }
+ }
+
+ public int getNumIndexEntries() {
+ if(mFileEntries == null) {
+ return 0;
+ }
+ return mFileEntries.length;
+ }
+
+ public IndexEntry getIndexEntry(int index) {
+ if(getNumIndexEntries() == 0 || index < 0 || index >= mFileEntries.length) {
+ return null;
+ }
+ return mFileEntries[index];
+ }
+
+ static public FileA3D createFromResource(RenderScript rs, Resources res, int id)
+ throws IllegalArgumentException {
+
+ rs.validate();
+ InputStream is = null;
+ try {
+ final TypedValue value = new TypedValue();
+ is = res.openRawResource(id, value);
+
+ int asset = ((AssetManager.AssetInputStream) is).getAssetInt();
+
+ int fileId = rs.nFileA3DCreateFromAssetStream(asset);
+
+ if(fileId == 0) {
+ throw new IllegalStateException("Load failed.");
+ }
+ FileA3D fa3d = new FileA3D(fileId, rs);
+ fa3d.initEntries();
+ return fa3d;
+
+ } catch (Exception e) {
+ // Ignore
+ } finally {
+ if (is != null) {
+ try {
+ is.close();
+ } catch (IOException e) {
+ // Ignore
+ }
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/graphics/java/android/renderscript/Vector2f.java b/graphics/java/android/renderscript/Float2.java
similarity index 93%
rename from graphics/java/android/renderscript/Vector2f.java
rename to graphics/java/android/renderscript/Float2.java
index 567d57fa..8fea91f 100644
--- a/graphics/java/android/renderscript/Vector2f.java
+++ b/graphics/java/android/renderscript/Float2.java
@@ -24,8 +24,8 @@
* @hide
*
**/
-public class Vector2f {
- public Vector2f() {
+public class Float2 {
+ public Float2() {
}
public float x;
diff --git a/graphics/java/android/renderscript/Vector3f.java b/graphics/java/android/renderscript/Float3.java
similarity index 94%
rename from graphics/java/android/renderscript/Vector3f.java
rename to graphics/java/android/renderscript/Float3.java
index f2842f3..9d9e406 100644
--- a/graphics/java/android/renderscript/Vector3f.java
+++ b/graphics/java/android/renderscript/Float3.java
@@ -24,8 +24,8 @@
* @hide
*
**/
-public class Vector3f {
- public Vector3f() {
+public class Float3 {
+ public Float3() {
}
public float x;
diff --git a/graphics/java/android/renderscript/Vector4f.java b/graphics/java/android/renderscript/Float4.java
similarity index 94%
rename from graphics/java/android/renderscript/Vector4f.java
rename to graphics/java/android/renderscript/Float4.java
index fabd959..a703e80 100644
--- a/graphics/java/android/renderscript/Vector4f.java
+++ b/graphics/java/android/renderscript/Float4.java
@@ -24,8 +24,8 @@
* @hide
*
**/
-public class Vector4f {
- public Vector4f() {
+public class Float4 {
+ public Float4() {
}
public float x;
diff --git a/graphics/java/android/renderscript/Vector2f.java b/graphics/java/android/renderscript/Int2.java
similarity index 89%
copy from graphics/java/android/renderscript/Vector2f.java
copy to graphics/java/android/renderscript/Int2.java
index 567d57fa..56e2fe9 100644
--- a/graphics/java/android/renderscript/Vector2f.java
+++ b/graphics/java/android/renderscript/Int2.java
@@ -24,12 +24,12 @@
* @hide
*
**/
-public class Vector2f {
- public Vector2f() {
+public class Int2 {
+ public Int2() {
}
- public float x;
- public float y;
+ public int x;
+ public int y;
}
diff --git a/graphics/java/android/renderscript/Vector2f.java b/graphics/java/android/renderscript/Int3.java
similarity index 88%
copy from graphics/java/android/renderscript/Vector2f.java
copy to graphics/java/android/renderscript/Int3.java
index 567d57fa..1b27509 100644
--- a/graphics/java/android/renderscript/Vector2f.java
+++ b/graphics/java/android/renderscript/Int3.java
@@ -24,12 +24,13 @@
* @hide
*
**/
-public class Vector2f {
- public Vector2f() {
+public class Int3 {
+ public Int3() {
}
- public float x;
- public float y;
+ public int x;
+ public int y;
+ public int z;
}
diff --git a/graphics/java/android/renderscript/Vector2f.java b/graphics/java/android/renderscript/Int4.java
similarity index 86%
copy from graphics/java/android/renderscript/Vector2f.java
copy to graphics/java/android/renderscript/Int4.java
index 567d57fa..3d6f3f5 100644
--- a/graphics/java/android/renderscript/Vector2f.java
+++ b/graphics/java/android/renderscript/Int4.java
@@ -24,14 +24,15 @@
* @hide
*
**/
-public class Vector2f {
- public Vector2f() {
+public class Int4 {
+ public Int4() {
}
- public float x;
- public float y;
+ public int x;
+ public int y;
+ public int z;
+ public int w;
}
-
diff --git a/graphics/java/android/renderscript/Vector2f.java b/graphics/java/android/renderscript/Long2.java
similarity index 89%
copy from graphics/java/android/renderscript/Vector2f.java
copy to graphics/java/android/renderscript/Long2.java
index 567d57fa..11ead2f 100644
--- a/graphics/java/android/renderscript/Vector2f.java
+++ b/graphics/java/android/renderscript/Long2.java
@@ -24,12 +24,12 @@
* @hide
*
**/
-public class Vector2f {
- public Vector2f() {
+public class Long2 {
+ public Long2() {
}
- public float x;
- public float y;
+ public long x;
+ public long y;
}
diff --git a/graphics/java/android/renderscript/Vector2f.java b/graphics/java/android/renderscript/Long3.java
similarity index 87%
copy from graphics/java/android/renderscript/Vector2f.java
copy to graphics/java/android/renderscript/Long3.java
index 567d57fa..1604532 100644
--- a/graphics/java/android/renderscript/Vector2f.java
+++ b/graphics/java/android/renderscript/Long3.java
@@ -24,12 +24,13 @@
* @hide
*
**/
-public class Vector2f {
- public Vector2f() {
+public class Long3 {
+ public Long3() {
}
- public float x;
- public float y;
+ public long x;
+ public long y;
+ public long z;
}
diff --git a/graphics/java/android/renderscript/Vector2f.java b/graphics/java/android/renderscript/Long4.java
similarity index 85%
copy from graphics/java/android/renderscript/Vector2f.java
copy to graphics/java/android/renderscript/Long4.java
index 567d57fa..2fd2747 100644
--- a/graphics/java/android/renderscript/Vector2f.java
+++ b/graphics/java/android/renderscript/Long4.java
@@ -24,14 +24,15 @@
* @hide
*
**/
-public class Vector2f {
- public Vector2f() {
+public class Long4 {
+ public Long4() {
}
- public float x;
- public float y;
+ public long x;
+ public long y;
+ public long z;
+ public long w;
}
-
diff --git a/graphics/java/android/renderscript/ProgramStore.java b/graphics/java/android/renderscript/ProgramStore.java
index 69be245..f558117 100644
--- a/graphics/java/android/renderscript/ProgramStore.java
+++ b/graphics/java/android/renderscript/ProgramStore.java
@@ -147,17 +147,17 @@
if (b.mOut != null) {
outID = b.mOut.mID;
}
- rs.nProgramFragmentStoreBegin(inID, outID);
- rs.nProgramFragmentStoreDepthFunc(b.mDepthFunc.mID);
- rs.nProgramFragmentStoreDepthMask(b.mDepthMask);
- rs.nProgramFragmentStoreColorMask(b.mColorMaskR,
+ rs.nProgramStoreBegin(inID, outID);
+ rs.nProgramStoreDepthFunc(b.mDepthFunc.mID);
+ rs.nProgramStoreDepthMask(b.mDepthMask);
+ rs.nProgramStoreColorMask(b.mColorMaskR,
b.mColorMaskG,
b.mColorMaskB,
b.mColorMaskA);
- rs.nProgramFragmentStoreBlendFunc(b.mBlendSrc.mID, b.mBlendDst.mID);
- rs.nProgramFragmentStoreDither(b.mDither);
+ rs.nProgramStoreBlendFunc(b.mBlendSrc.mID, b.mBlendDst.mID);
+ rs.nProgramStoreDither(b.mDither);
- int id = rs.nProgramFragmentStoreCreate();
+ int id = rs.nProgramStoreCreate();
return new ProgramStore(id, rs);
}
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index a935243..9dd8d1e 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -71,7 +71,7 @@
native void nContextBindRootScript(int script);
native void nContextBindSampler(int sampler, int slot);
- native void nContextBindProgramFragmentStore(int pfs);
+ native void nContextBindProgramStore(int pfs);
native void nContextBindProgramFragment(int pf);
native void nContextBindProgramVertex(int pf);
native void nContextBindProgramRaster(int pr);
@@ -117,6 +117,11 @@
native void nAllocationSubDataFromObject(int id, Type t, int offset, Object o);
native void nAllocationSubReadFromObject(int id, Type t, int offset, Object o);
+ native int nFileA3DCreateFromAssetStream(int assetStream);
+ native int nFileA3DGetNumIndexEntries(int fileA3D);
+ native void nFileA3DGetIndexEntries(int fileA3D, int numEntries, int[] IDs, String[] names);
+ native int nFileA3DGetEntryByIndex(int fileA3D, int index);
+
native void nAdapter1DBindAllocation(int ad, int alloc);
native void nAdapter1DSetConstraint(int ad, int dim, int value);
native void nAdapter1DData(int ad, int[] d);
@@ -134,32 +139,29 @@
native int nAdapter2DCreate();
native void nScriptBindAllocation(int script, int alloc, int slot);
- native void nScriptSetClearColor(int script, float r, float g, float b, float a);
- native void nScriptSetClearDepth(int script, float depth);
- native void nScriptSetClearStencil(int script, int stencil);
native void nScriptSetTimeZone(int script, byte[] timeZone);
- native void nScriptSetType(int type, boolean writable, String name, int slot);
- native void nScriptSetRoot(boolean isRoot);
- native void nScriptSetInvokable(String name, int slot);
native void nScriptInvoke(int id, int slot);
+ native void nScriptInvokeData(int id, int slot);
+ native void nScriptInvokeV(int id, int slot, byte[] params);
+ native void nScriptSetVarI(int id, int slot, int val);
+ native void nScriptSetVarF(int id, int slot, float val);
+ native void nScriptSetVarV(int id, int slot, byte[] val);
native void nScriptCBegin();
native void nScriptCSetScript(byte[] script, int offset, int length);
native int nScriptCCreate();
- native void nScriptCAddDefineI32(String name, int value);
- native void nScriptCAddDefineF(String name, float value);
native void nSamplerBegin();
native void nSamplerSet(int param, int value);
native int nSamplerCreate();
- native void nProgramFragmentStoreBegin(int in, int out);
- native void nProgramFragmentStoreDepthFunc(int func);
- native void nProgramFragmentStoreDepthMask(boolean enable);
- native void nProgramFragmentStoreColorMask(boolean r, boolean g, boolean b, boolean a);
- native void nProgramFragmentStoreBlendFunc(int src, int dst);
- native void nProgramFragmentStoreDither(boolean enable);
- native int nProgramFragmentStoreCreate();
+ native void nProgramStoreBegin(int in, int out);
+ native void nProgramStoreDepthFunc(int func);
+ native void nProgramStoreDepthMask(boolean enable);
+ native void nProgramStoreColorMask(boolean r, boolean g, boolean b, boolean a);
+ native void nProgramStoreBlendFunc(int src, int dst);
+ native void nProgramStoreDither(boolean enable);
+ native int nProgramStoreCreate();
native int nProgramRasterCreate(int in, int out, boolean pointSmooth, boolean lineSmooth, boolean pointSprite);
native void nProgramRasterSetLineWidth(int pr, float v);
@@ -195,13 +197,24 @@
@SuppressWarnings({"FieldCanBeLocal"})
protected MessageThread mMessageThread;
- Element mElement_USER_U8;
- Element mElement_USER_I8;
- Element mElement_USER_U16;
- Element mElement_USER_I16;
- Element mElement_USER_U32;
- Element mElement_USER_I32;
- Element mElement_USER_F32;
+ Element mElement_U8;
+ Element mElement_I8;
+ Element mElement_U16;
+ Element mElement_I16;
+ Element mElement_U32;
+ Element mElement_I32;
+ Element mElement_F32;
+
+ Element mElement_ELEMENT;
+ Element mElement_TYPE;
+ Element mElement_ALLOCATION;
+ Element mElement_SAMPLER;
+ Element mElement_SCRIPT;
+ Element mElement_MESH;
+ Element mElement_PROGRAM_FRAGMENT;
+ Element mElement_PROGRAM_VERTEX;
+ Element mElement_PROGRAM_RASTER;
+ Element mElement_PROGRAM_STORE;
Element mElement_A_8;
Element mElement_RGB_565;
@@ -210,13 +223,17 @@
Element mElement_RGBA_4444;
Element mElement_RGBA_8888;
- Element mElement_INDEX_16;
- Element mElement_POSITION_2;
- Element mElement_POSITION_3;
- Element mElement_TEXTURE_2;
- Element mElement_NORMAL_3;
- Element mElement_COLOR_U8_4;
- Element mElement_COLOR_F32_4;
+ Element mElement_FLOAT_2;
+ Element mElement_FLOAT_3;
+ Element mElement_FLOAT_4;
+ Element mElement_UCHAR_4;
+
+ Sampler mSampler_CLAMP_NEAREST;
+ Sampler mSampler_CLAMP_LINEAR;
+ Sampler mSampler_CLAMP_LINEAR_MIP_LINEAR;
+ Sampler mSampler_WRAP_NEAREST;
+ Sampler mSampler_WRAP_LINEAR;
+ Sampler mSampler_WRAP_LINEAR_MIP_LINEAR;
///////////////////////////////////////////////////////////////////////////////////
//
@@ -282,7 +299,6 @@
mRS.mMessageCallback.mID = msg;
mRS.mMessageCallback.run();
}
- //Log.d(LOG_TAG, "MessageThread msg " + msg + " v1 " + rbuf[0] + " v2 " + rbuf[1] + " v3 " +rbuf[2]);
}
Log.d(LOG_TAG, "MessageThread exiting.");
}
diff --git a/graphics/java/android/renderscript/RenderScriptGL.java b/graphics/java/android/renderscript/RenderScriptGL.java
index d1df23d..e90b4fc 100644
--- a/graphics/java/android/renderscript/RenderScriptGL.java
+++ b/graphics/java/android/renderscript/RenderScriptGL.java
@@ -74,9 +74,9 @@
nContextBindRootScript(safeID(s));
}
- public void contextBindProgramFragmentStore(ProgramStore p) {
+ public void contextBindProgramStore(ProgramStore p) {
validate();
- nContextBindProgramFragmentStore(safeID(p));
+ nContextBindProgramStore(safeID(p));
}
public void contextBindProgramFragment(ProgramFragment p) {
diff --git a/graphics/java/android/renderscript/Sampler.java b/graphics/java/android/renderscript/Sampler.java
index 40ba722..da83d04 100644
--- a/graphics/java/android/renderscript/Sampler.java
+++ b/graphics/java/android/renderscript/Sampler.java
@@ -51,6 +51,86 @@
mID = id;
}
+ Sampler mSampler_CLAMP_NEAREST;
+ Sampler mSampler_CLAMP_LINEAR;
+ Sampler mSampler_CLAMP_LINEAR_MIP;
+ Sampler mSampler_WRAP_NEAREST;
+ Sampler mSampler_WRAP_LINEAR;
+ Sampler mSampler_WRAP_LINEAR_MIP;
+
+ public static Sampler CLAMP_NEAREST(RenderScript rs) {
+ if(rs.mSampler_CLAMP_NEAREST == null) {
+ Builder b = new Builder(rs);
+ b.setMin(Value.NEAREST);
+ b.setMag(Value.NEAREST);
+ b.setWrapS(Value.CLAMP);
+ b.setWrapT(Value.CLAMP);
+ rs.mSampler_CLAMP_NEAREST = b.create();
+ }
+ return rs.mSampler_CLAMP_NEAREST;
+ }
+
+ public static Sampler CLAMP_LINEAR(RenderScript rs) {
+ if(rs.mSampler_CLAMP_LINEAR == null) {
+ Builder b = new Builder(rs);
+ b.setMin(Value.LINEAR);
+ b.setMag(Value.LINEAR);
+ b.setWrapS(Value.CLAMP);
+ b.setWrapT(Value.CLAMP);
+ rs.mSampler_CLAMP_LINEAR = b.create();
+ }
+ return rs.mSampler_CLAMP_LINEAR;
+ }
+
+ public static Sampler CLAMP_LINEAR_MIP_LINEAR(RenderScript rs) {
+ if(rs.mSampler_CLAMP_LINEAR_MIP_LINEAR == null) {
+ Builder b = new Builder(rs);
+ b.setMin(Value.LINEAR_MIP_LINEAR);
+ b.setMag(Value.LINEAR_MIP_LINEAR);
+ b.setWrapS(Value.CLAMP);
+ b.setWrapT(Value.CLAMP);
+ rs.mSampler_CLAMP_LINEAR_MIP_LINEAR = b.create();
+ }
+ return rs.mSampler_CLAMP_LINEAR_MIP_LINEAR;
+ }
+
+ public static Sampler WRAP_NEAREST(RenderScript rs) {
+ if(rs.mSampler_WRAP_NEAREST == null) {
+ Builder b = new Builder(rs);
+ b.setMin(Value.NEAREST);
+ b.setMag(Value.NEAREST);
+ b.setWrapS(Value.WRAP);
+ b.setWrapT(Value.WRAP);
+ rs.mSampler_WRAP_NEAREST = b.create();
+ }
+ return rs.mSampler_WRAP_NEAREST;
+ }
+
+ public static Sampler WRAP_LINEAR(RenderScript rs) {
+ if(rs.mSampler_WRAP_LINEAR == null) {
+ Builder b = new Builder(rs);
+ b.setMin(Value.LINEAR);
+ b.setMag(Value.LINEAR);
+ b.setWrapS(Value.WRAP);
+ b.setWrapT(Value.WRAP);
+ rs.mSampler_WRAP_LINEAR = b.create();
+ }
+ return rs.mSampler_WRAP_LINEAR;
+ }
+
+ public static Sampler WRAP_LINEAR_MIP_LINEAR(RenderScript rs) {
+ if(rs.mSampler_WRAP_LINEAR_MIP_LINEAR == null) {
+ Builder b = new Builder(rs);
+ b.setMin(Value.LINEAR_MIP_LINEAR);
+ b.setMag(Value.LINEAR_MIP_LINEAR);
+ b.setWrapS(Value.WRAP);
+ b.setWrapT(Value.WRAP);
+ rs.mSampler_WRAP_LINEAR_MIP_LINEAR = b.create();
+ }
+ return rs.mSampler_WRAP_LINEAR_MIP_LINEAR;
+ }
+
+
public static class Builder {
RenderScript mRS;
Value mMin;
diff --git a/graphics/java/android/renderscript/Script.java b/graphics/java/android/renderscript/Script.java
index 57ccfa3..4c4071a 100644
--- a/graphics/java/android/renderscript/Script.java
+++ b/graphics/java/android/renderscript/Script.java
@@ -42,6 +42,19 @@
}
}
+ protected void invoke(int slot) {
+ mRS.nScriptInvoke(mID, slot);
+ }
+
+ protected void invokeData(int slot) {
+ mRS.nScriptInvokeData(mID, slot);
+ }
+
+ protected void invokeV(int slot, FieldPacker v) {
+ mRS.nScriptInvokeV(mID, slot, v.getData());
+ }
+
+
Script(int id, RenderScript rs) {
super(rs);
mID = id;
@@ -49,22 +62,23 @@
public void bindAllocation(Allocation va, int slot) {
mRS.validate();
- mRS.nScriptBindAllocation(mID, va.mID, slot);
+ if (va != null) {
+ mRS.nScriptBindAllocation(mID, va.mID, slot);
+ } else {
+ mRS.nScriptBindAllocation(mID, 0, slot);
+ }
}
- public void setClearColor(float r, float g, float b, float a) {
- mRS.validate();
- mRS.nScriptSetClearColor(mID, r, g, b, a);
+ public void setVar(int index, float v) {
+ mRS.nScriptSetVarF(mID, index, v);
}
- public void setClearDepth(float d) {
- mRS.validate();
- mRS.nScriptSetClearDepth(mID, d);
+ public void setVar(int index, int v) {
+ mRS.nScriptSetVarI(mID, index, v);
}
- public void setClearStencil(int stencil) {
- mRS.validate();
- mRS.nScriptSetClearStencil(mID, stencil);
+ public void setVar(int index, FieldPacker v) {
+ mRS.nScriptSetVarV(mID, index, v.getData());
}
public void setTimeZone(String timeZone) {
@@ -78,72 +92,54 @@
public static class Builder {
RenderScript mRS;
- boolean mIsRoot = false;
- Type[] mTypes;
- String[] mNames;
- boolean[] mWritable;
- int mInvokableCount = 0;
- Invokable[] mInvokables;
Builder(RenderScript rs) {
mRS = rs;
- mTypes = new Type[MAX_SLOT];
- mNames = new String[MAX_SLOT];
- mWritable = new boolean[MAX_SLOT];
- mInvokables = new Invokable[MAX_SLOT];
}
-
- public void setType(Type t, int slot) {
- mTypes[slot] = t;
- mNames[slot] = null;
- }
-
- public void setType(Type t, String name, int slot) {
- mTypes[slot] = t;
- mNames[slot] = name;
- }
-
- public Invokable addInvokable(String func) {
- Invokable i = new Invokable();
- i.mName = func;
- i.mRS = mRS;
- i.mSlot = mInvokableCount;
- mInvokables[mInvokableCount++] = i;
- return i;
- }
-
- public void setType(boolean writable, int slot) {
- mWritable[slot] = writable;
- }
-
- void transferCreate() {
- mRS.nScriptSetRoot(mIsRoot);
- for(int ct=0; ct < mTypes.length; ct++) {
- if(mTypes[ct] != null) {
- mRS.nScriptSetType(mTypes[ct].mID, mWritable[ct], mNames[ct], ct);
- }
- }
- for(int ct=0; ct < mInvokableCount; ct++) {
- mRS.nScriptSetInvokable(mInvokables[ct].mName, ct);
- }
- }
-
- void transferObject(Script s) {
- s.mIsRoot = mIsRoot;
- s.mTypes = mTypes;
- s.mInvokables = new Invokable[mInvokableCount];
- for(int ct=0; ct < mInvokableCount; ct++) {
- s.mInvokables[ct] = mInvokables[ct];
- s.mInvokables[ct].mScript = s;
- }
- s.mInvokables = null;
- }
-
- public void setRoot(boolean r) {
- mIsRoot = r;
- }
-
}
+
+ public static class FieldBase {
+ protected Element mElement;
+ protected Type mType;
+ protected Allocation mAllocation;
+
+ protected void init(RenderScript rs, int dimx) {
+ mAllocation = Allocation.createSized(rs, mElement, dimx);
+ mType = mAllocation.getType();
+ }
+
+ protected FieldBase() {
+ }
+
+ public Element getElement() {
+ return mElement;
+ }
+
+ public Type getType() {
+ return mType;
+ }
+
+ public Allocation getAllocation() {
+ return mAllocation;
+ }
+
+ //@Override
+ public void updateAllocation() {
+ }
+
+
+ //
+ /*
+ public class ScriptField_UserField
+ extends android.renderscript.Script.FieldBase {
+
+ protected
+
+ }
+
+ */
+
+ }
}
diff --git a/graphics/java/android/renderscript/ScriptC.java b/graphics/java/android/renderscript/ScriptC.java
index bb99e23..5959be4 100644
--- a/graphics/java/android/renderscript/ScriptC.java
+++ b/graphics/java/android/renderscript/ScriptC.java
@@ -37,11 +37,49 @@
super(id, rs);
}
+ protected ScriptC(RenderScript rs, Resources resources, int resourceID, boolean isRoot) {
+ super(0, rs);
+ mID = internalCreate(rs, resources, resourceID);
+ }
+
+
+ private static synchronized int internalCreate(RenderScript rs, Resources resources, int resourceID) {
+ byte[] pgm;
+ int pgmLength;
+ InputStream is = resources.openRawResource(resourceID);
+ try {
+ try {
+ pgm = new byte[1024];
+ pgmLength = 0;
+ while(true) {
+ int bytesLeft = pgm.length - pgmLength;
+ if (bytesLeft == 0) {
+ byte[] buf2 = new byte[pgm.length * 2];
+ System.arraycopy(pgm, 0, buf2, 0, pgm.length);
+ pgm = buf2;
+ bytesLeft = pgm.length - pgmLength;
+ }
+ int bytesRead = is.read(pgm, pgmLength, bytesLeft);
+ if (bytesRead <= 0) {
+ break;
+ }
+ pgmLength += bytesRead;
+ }
+ } finally {
+ is.close();
+ }
+ } catch(IOException e) {
+ throw new Resources.NotFoundException();
+ }
+
+ rs.nScriptCBegin();
+ rs.nScriptCSetScript(pgm, 0, pgmLength);
+ return rs.nScriptCCreate();
+ }
+
public static class Builder extends Script.Builder {
byte[] mProgram;
int mProgramLength;
- HashMap<String,Integer> mIntDefines = new HashMap();
- HashMap<String,Float> mFloatDefines = new HashMap();
public Builder(RenderScript rs) {
super(rs);
@@ -92,66 +130,20 @@
static synchronized ScriptC internalCreate(Builder b) {
b.mRS.nScriptCBegin();
- b.transferCreate();
- for (Entry<String,Integer> e: b.mIntDefines.entrySet()) {
- b.mRS.nScriptCAddDefineI32(e.getKey(), e.getValue().intValue());
- }
- for (Entry<String,Float> e: b.mFloatDefines.entrySet()) {
- b.mRS.nScriptCAddDefineF(e.getKey(), e.getValue().floatValue());
- }
-
+ android.util.Log.e("rs", "len = " + b.mProgramLength);
b.mRS.nScriptCSetScript(b.mProgram, 0, b.mProgramLength);
int id = b.mRS.nScriptCCreate();
ScriptC obj = new ScriptC(id, b.mRS);
- b.transferObject(obj);
-
return obj;
}
- public void addDefine(String name, int value) {
- mIntDefines.put(name, value);
- }
-
- public void addDefine(String name, float value) {
- mFloatDefines.put(name, value);
- }
-
- /**
- * Takes the all public static final fields for a class, and adds defines
- * for them, using the name of the field as the name of the define.
- */
- public void addDefines(Class cl) {
- addDefines(cl.getFields(), (Modifier.STATIC | Modifier.FINAL | Modifier.PUBLIC), null);
- }
-
- /**
- * Takes the all public fields for an object, and adds defines
- * for them, using the name of the field as the name of the define.
- */
- public void addDefines(Object o) {
- addDefines(o.getClass().getFields(), Modifier.PUBLIC, o);
- }
-
- void addDefines(Field[] fields, int mask, Object o) {
- for (Field f: fields) {
- try {
- if ((f.getModifiers() & mask) == mask) {
- Class t = f.getType();
- if (t == int.class) {
- mIntDefines.put(f.getName(), f.getInt(o));
- }
- else if (t == float.class) {
- mFloatDefines.put(f.getName(), f.getFloat(o));
- }
- }
- } catch (IllegalAccessException ex) {
- // TODO: Do we want this log?
- Log.d(TAG, "addDefines skipping field " + f.getName());
- }
- }
- }
+ public void addDefine(String name, int value) {}
+ public void addDefine(String name, float value) {}
+ public void addDefines(Class cl) {}
+ public void addDefines(Object o) {}
+ void addDefines(Field[] fields, int mask, Object o) {}
public ScriptC create() {
return internalCreate(this);
diff --git a/graphics/java/android/renderscript/Vector2f.java b/graphics/java/android/renderscript/Short2.java
similarity index 89%
copy from graphics/java/android/renderscript/Vector2f.java
copy to graphics/java/android/renderscript/Short2.java
index 567d57fa..426801f 100644
--- a/graphics/java/android/renderscript/Vector2f.java
+++ b/graphics/java/android/renderscript/Short2.java
@@ -24,12 +24,12 @@
* @hide
*
**/
-public class Vector2f {
- public Vector2f() {
+public class Short2 {
+ public Short2() {
}
- public float x;
- public float y;
+ public short x;
+ public short y;
}
diff --git a/graphics/java/android/renderscript/Vector2f.java b/graphics/java/android/renderscript/Short3.java
similarity index 87%
copy from graphics/java/android/renderscript/Vector2f.java
copy to graphics/java/android/renderscript/Short3.java
index 567d57fa..7b9c305 100644
--- a/graphics/java/android/renderscript/Vector2f.java
+++ b/graphics/java/android/renderscript/Short3.java
@@ -24,12 +24,13 @@
* @hide
*
**/
-public class Vector2f {
- public Vector2f() {
+public class Short3 {
+ public Short3() {
}
- public float x;
- public float y;
+ public short x;
+ public short y;
+ public short z;
}
diff --git a/graphics/java/android/renderscript/Vector2f.java b/graphics/java/android/renderscript/Short4.java
similarity index 85%
copy from graphics/java/android/renderscript/Vector2f.java
copy to graphics/java/android/renderscript/Short4.java
index 567d57fa..9a474e2 100644
--- a/graphics/java/android/renderscript/Vector2f.java
+++ b/graphics/java/android/renderscript/Short4.java
@@ -24,14 +24,15 @@
* @hide
*
**/
-public class Vector2f {
- public Vector2f() {
+public class Short4 {
+ public Short4() {
}
- public float x;
- public float y;
+ public short x;
+ public short y;
+ public short z;
+ public short w;
}
-
diff --git a/graphics/java/android/renderscript/SimpleMesh.java b/graphics/java/android/renderscript/SimpleMesh.java
index 4a217a9..38d0736 100644
--- a/graphics/java/android/renderscript/SimpleMesh.java
+++ b/graphics/java/android/renderscript/SimpleMesh.java
@@ -313,36 +313,26 @@
public SimpleMesh create() {
Element.Builder b = new Element.Builder(mRS);
int floatCount = mVtxSize;
- b.add(Element.createAttrib(mRS,
+ b.add(Element.createVector(mRS,
Element.DataType.FLOAT_32,
- Element.DataKind.POSITION,
mVtxSize), "position");
if ((mFlags & COLOR) != 0) {
floatCount += 4;
- b.add(Element.createAttrib(mRS,
- Element.DataType.FLOAT_32,
- Element.DataKind.COLOR,
- 4), "color");
+ b.add(Element.F32_4(mRS), "color");
}
if ((mFlags & TEXTURE_0) != 0) {
floatCount += 2;
- b.add(Element.createAttrib(mRS,
- Element.DataType.FLOAT_32,
- Element.DataKind.TEXTURE,
- 2), "texture");
+ b.add(Element.F32_2(mRS), "texture0");
}
if ((mFlags & NORMAL) != 0) {
floatCount += 3;
- b.add(Element.createAttrib(mRS,
- Element.DataType.FLOAT_32,
- Element.DataKind.NORMAL,
- 3), "normal");
+ b.add(Element.F32_3(mRS), "normal");
}
mElement = b.create();
Builder smb = new Builder(mRS);
smb.addVertexType(mElement, mVtxCount / floatCount);
- smb.setIndexType(Element.createIndex(mRS), mIndexCount);
+ smb.setIndexType(Element.U16(mRS), mIndexCount);
smb.setPrimitive(Primitive.TRIANGLE);
SimpleMesh sm = smb.create();
diff --git a/graphics/java/android/renderscript/Type.java b/graphics/java/android/renderscript/Type.java
index 62d3867..14422b2 100644
--- a/graphics/java/android/renderscript/Type.java
+++ b/graphics/java/android/renderscript/Type.java
@@ -108,48 +108,9 @@
super.finalize();
}
- public static Type createFromClass(RenderScript rs, Class c, int size) {
- Element e = Element.createFromClass(rs, c);
- Builder b = new Builder(rs, e);
- b.add(Dimension.X, size);
- Type t = b.create();
- e.destroy();
-
- // native fields
- {
- Field[] fields = c.getFields();
- int[] arTypes = new int[fields.length];
- int[] arBits = new int[fields.length];
-
- for(int ct=0; ct < fields.length; ct++) {
- Field f = fields[ct];
- Class fc = f.getType();
- if(fc == int.class) {
- arTypes[ct] = Element.DataType.SIGNED_32.mID;
- arBits[ct] = 32;
- } else if(fc == short.class) {
- arTypes[ct] = Element.DataType.SIGNED_16.mID;
- arBits[ct] = 16;
- } else if(fc == byte.class) {
- arTypes[ct] = Element.DataType.SIGNED_8.mID;
- arBits[ct] = 8;
- } else if(fc == float.class) {
- arTypes[ct] = Element.DataType.FLOAT_32.mID;
- arBits[ct] = 32;
- } else {
- throw new IllegalArgumentException("Unkown field type");
- }
- }
- rs.nTypeSetupFields(t, arTypes, arBits, fields);
- }
- t.mJavaClass = c;
- return t;
- }
-
public static Type createFromClass(RenderScript rs, Class c, int size, String scriptName) {
- Type t = createFromClass(rs, c, size);
- t.setName(scriptName);
- return t;
+ android.util.Log.e("RenderScript", "Calling depricated createFromClass");
+ return null;
}
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index 45cc72e..86d7ba4 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -700,6 +700,59 @@
free(bufAlloc);
}
+// -----------------------------------
+
+static int
+nFileA3DCreateFromAssetStream(JNIEnv *_env, jobject _this, jint native_asset)
+{
+ LOGV("______nFileA3D %u", (uint32_t) native_asset);
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+
+ Asset* asset = reinterpret_cast<Asset*>(native_asset);
+
+ jint id = (jint)rsFileA3DCreateFromAssetStream(con, asset->getBuffer(false), asset->getLength());
+ return id;
+}
+
+static int
+nFileA3DGetNumIndexEntries(JNIEnv *_env, jobject _this, jint fileA3D)
+{
+ LOGV("______nFileA3D %u", (uint32_t) fileA3D);
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+
+ int32_t numEntries = 0;
+ rsFileA3DGetNumIndexEntries(con, &numEntries, (RsFile)fileA3D);
+ LOGV("______nFileA3D NumEntries %u", (uint32_t) numEntries);
+ return numEntries;
+}
+
+static void
+nFileA3DGetIndexEntries(JNIEnv *_env, jobject _this, jint fileA3D, jint numEntries, jintArray _ids, jobjectArray _entries)
+{
+ LOGV("______nFileA3D %u", (uint32_t) fileA3D);
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+
+ RsFileIndexEntry *fileEntries = (RsFileIndexEntry*)malloc((uint32_t)numEntries * sizeof(RsFileIndexEntry));
+
+ rsFileA3DGetIndexEntries(con, fileEntries, (uint32_t)numEntries, (RsFile)fileA3D);
+
+ for(jint i = 0; i < numEntries; i ++) {
+ _env->SetObjectArrayElement(_entries, i, _env->NewStringUTF(fileEntries[i].objectName));
+ _env->SetIntArrayRegion(_ids, i, 1, (const jint*)&fileEntries[i].classID);
+ }
+
+ free(fileEntries);
+}
+
+static int
+nFileA3DGetEntryByIndex(JNIEnv *_env, jobject _this, jint fileA3D, jint index)
+{
+ LOGV("______nFileA3D %u", (uint32_t) fileA3D);
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+
+ jint id = (jint)rsFileA3DGetEntryByIndex(con, (uint32_t)index, (RsFile)fileA3D);
+ return id;
+}
// -----------------------------------
@@ -854,29 +907,33 @@
}
static void
-nScriptSetClearColor(JNIEnv *_env, jobject _this, jint script, jfloat r, jfloat g, jfloat b, jfloat a)
+nScriptSetVarI(JNIEnv *_env, jobject _this, jint script, jint slot, jint val)
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
- LOG_API("nScriptSetClearColor, con(%p), s(%p), r(%f), g(%f), b(%f), a(%f)", con, (void *)script, r, g, b, a);
- rsScriptSetClearColor(con, (RsScript)script, r, g, b, a);
+ LOG_API("nScriptSetVarI, con(%p), s(%p), slot(%i), val(%i), b(%f), a(%f)", con, (void *)script, slot, val);
+ rsScriptSetVarI(con, (RsScript)script, slot, val);
}
static void
-nScriptSetClearDepth(JNIEnv *_env, jobject _this, jint script, jfloat d)
+nScriptSetVarF(JNIEnv *_env, jobject _this, jint script, jint slot, float val)
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
- LOG_API("nScriptCSetClearDepth, con(%p), s(%p), depth(%f)", con, (void *)script, d);
- rsScriptSetClearDepth(con, (RsScript)script, d);
+ LOG_API("nScriptSetVarI, con(%p), s(%p), slot(%i), val(%i), b(%f), a(%f)", con, (void *)script, slot, val);
+ rsScriptSetVarF(con, (RsScript)script, slot, val);
}
static void
-nScriptSetClearStencil(JNIEnv *_env, jobject _this, jint script, jint stencil)
+nScriptSetVarV(JNIEnv *_env, jobject _this, jint script, jint slot, jbyteArray data)
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
- LOG_API("nScriptCSetClearStencil, con(%p), s(%p), stencil(%i)", con, (void *)script, stencil);
- rsScriptSetClearStencil(con, (RsScript)script, stencil);
+ LOG_API("nScriptSetVarV, con(%p), s(%p), slot(%i)", con, (void *)script, slot);
+ jint len = _env->GetArrayLength(data);
+ jbyte *ptr = _env->GetByteArrayElements(data, NULL);
+ rsScriptSetVarV(con, (RsScript)script, slot, ptr, len);
+ _env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
}
+
static void
nScriptSetTimeZone(JNIEnv *_env, jobject _this, jint script, jbyteArray timeZone)
{
@@ -895,36 +952,6 @@
}
static void
-nScriptSetType(JNIEnv *_env, jobject _this, jint type, jboolean writable, jstring _str, jint slot)
-{
- RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
- LOG_API("nScriptCAddType, con(%p), type(%p), writable(%i), slot(%i)", con, (RsType)type, writable, slot);
- const char* n = NULL;
- if (_str) {
- n = _env->GetStringUTFChars(_str, NULL);
- }
- rsScriptSetType(con, (RsType)type, slot, writable, n);
- if (n) {
- _env->ReleaseStringUTFChars(_str, n);
- }
-}
-
-static void
-nScriptSetInvoke(JNIEnv *_env, jobject _this, jstring _str, jint slot)
-{
- RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
- LOG_API("nScriptSetInvoke, con(%p)", con);
- const char* n = NULL;
- if (_str) {
- n = _env->GetStringUTFChars(_str, NULL);
- }
- rsScriptSetInvoke(con, n, slot);
- if (n) {
- _env->ReleaseStringUTFChars(_str, n);
- }
-}
-
-static void
nScriptInvoke(JNIEnv *_env, jobject _this, jint obj, jint slot)
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
@@ -933,13 +960,26 @@
}
static void
-nScriptSetRoot(JNIEnv *_env, jobject _this, jboolean isRoot)
+nScriptInvokeData(JNIEnv *_env, jobject _this, jint obj, jint slot)
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
- LOG_API("nScriptCSetRoot, con(%p), isRoot(%i)", con, isRoot);
- rsScriptSetRoot(con, isRoot);
+ LOG_API("nScriptInvokeData, con(%p), script(%p)", con, (void *)obj);
+ rsScriptInvokeData(con, (RsScript)obj, slot, 0);
}
+
+static void
+nScriptInvokeV(JNIEnv *_env, jobject _this, jint script, jint slot, jbyteArray data)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nScriptInvokeV, con(%p), s(%p), slot(%i)", con, (void *)script, slot);
+ jint len = _env->GetArrayLength(data);
+ jbyte *ptr = _env->GetByteArrayElements(data, NULL);
+ rsScriptInvokeV(con, (RsScript)script, slot, ptr, len);
+ _env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
+}
+
+
// -----------------------------------
static void
@@ -1002,83 +1042,63 @@
return (jint)rsScriptCCreate(con);
}
-static void
-nScriptCAddDefineI32(JNIEnv *_env, jobject _this, jstring name, jint value)
-{
- RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
- const char* n = _env->GetStringUTFChars(name, NULL);
- LOG_API("nScriptCAddDefineI32, con(%p) name(%s) value(%d)", con, n, value);
- rsScriptCSetDefineI32(con, n, value);
- _env->ReleaseStringUTFChars(name, n);
-}
-
-static void
-nScriptCAddDefineF(JNIEnv *_env, jobject _this, jstring name, jfloat value)
-{
- RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
- const char* n = _env->GetStringUTFChars(name, NULL);
- LOG_API("nScriptCAddDefineF, con(%p) name(%s) value(%f)", con, n, value);
- rsScriptCSetDefineF(con, n, value);
- _env->ReleaseStringUTFChars(name, n);
-}
-
// ---------------------------------------------------------------------------
static void
-nProgramFragmentStoreBegin(JNIEnv *_env, jobject _this, jint in, jint out)
+nProgramStoreBegin(JNIEnv *_env, jobject _this, jint in, jint out)
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
- LOG_API("nProgramFragmentStoreBegin, con(%p), in(%p), out(%p)", con, (RsElement)in, (RsElement)out);
- rsProgramFragmentStoreBegin(con, (RsElement)in, (RsElement)out);
+ LOG_API("nProgramStoreBegin, con(%p), in(%p), out(%p)", con, (RsElement)in, (RsElement)out);
+ rsProgramStoreBegin(con, (RsElement)in, (RsElement)out);
}
static void
-nProgramFragmentStoreDepthFunc(JNIEnv *_env, jobject _this, jint func)
+nProgramStoreDepthFunc(JNIEnv *_env, jobject _this, jint func)
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
- LOG_API("nProgramFragmentStoreDepthFunc, con(%p), func(%i)", con, func);
- rsProgramFragmentStoreDepthFunc(con, (RsDepthFunc)func);
+ LOG_API("nProgramStoreDepthFunc, con(%p), func(%i)", con, func);
+ rsProgramStoreDepthFunc(con, (RsDepthFunc)func);
}
static void
-nProgramFragmentStoreDepthMask(JNIEnv *_env, jobject _this, jboolean enable)
+nProgramStoreDepthMask(JNIEnv *_env, jobject _this, jboolean enable)
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
- LOG_API("nProgramFragmentStoreDepthMask, con(%p), enable(%i)", con, enable);
- rsProgramFragmentStoreDepthMask(con, enable);
+ LOG_API("nProgramStoreDepthMask, con(%p), enable(%i)", con, enable);
+ rsProgramStoreDepthMask(con, enable);
}
static void
-nProgramFragmentStoreColorMask(JNIEnv *_env, jobject _this, jboolean r, jboolean g, jboolean b, jboolean a)
+nProgramStoreColorMask(JNIEnv *_env, jobject _this, jboolean r, jboolean g, jboolean b, jboolean a)
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
- LOG_API("nProgramFragmentStoreColorMask, con(%p), r(%i), g(%i), b(%i), a(%i)", con, r, g, b, a);
- rsProgramFragmentStoreColorMask(con, r, g, b, a);
+ LOG_API("nProgramStoreColorMask, con(%p), r(%i), g(%i), b(%i), a(%i)", con, r, g, b, a);
+ rsProgramStoreColorMask(con, r, g, b, a);
}
static void
-nProgramFragmentStoreBlendFunc(JNIEnv *_env, jobject _this, int src, int dst)
+nProgramStoreBlendFunc(JNIEnv *_env, jobject _this, int src, int dst)
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
- LOG_API("nProgramFragmentStoreBlendFunc, con(%p), src(%i), dst(%i)", con, src, dst);
- rsProgramFragmentStoreBlendFunc(con, (RsBlendSrcFunc)src, (RsBlendDstFunc)dst);
+ LOG_API("nProgramStoreBlendFunc, con(%p), src(%i), dst(%i)", con, src, dst);
+ rsProgramStoreBlendFunc(con, (RsBlendSrcFunc)src, (RsBlendDstFunc)dst);
}
static void
-nProgramFragmentStoreDither(JNIEnv *_env, jobject _this, jboolean enable)
+nProgramStoreDither(JNIEnv *_env, jobject _this, jboolean enable)
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
- LOG_API("nProgramFragmentStoreDither, con(%p), enable(%i)", con, enable);
- rsProgramFragmentStoreDither(con, enable);
+ LOG_API("nProgramStoreDither, con(%p), enable(%i)", con, enable);
+ rsProgramStoreDither(con, enable);
}
static jint
-nProgramFragmentStoreCreate(JNIEnv *_env, jobject _this)
+nProgramStoreCreate(JNIEnv *_env, jobject _this)
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
- LOG_API("nProgramFragmentStoreCreate, con(%p)", con);
+ LOG_API("nProgramStoreCreate, con(%p)", con);
- return (jint)rsProgramFragmentStoreCreate(con);
+ return (jint)rsProgramStoreCreate(con);
}
// ---------------------------------------------------------------------------
@@ -1208,11 +1228,11 @@
}
static void
-nContextBindProgramFragmentStore(JNIEnv *_env, jobject _this, jint pfs)
+nContextBindProgramStore(JNIEnv *_env, jobject _this, jint pfs)
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
- LOG_API("nContextBindProgramFragmentStore, con(%p), pfs(%p)", con, (RsProgramFragmentStore)pfs);
- rsContextBindProgramFragmentStore(con, (RsProgramFragmentStore)pfs);
+ LOG_API("nContextBindProgramStore, con(%p), pfs(%p)", con, (RsProgramStore)pfs);
+ rsContextBindProgramStore(con, (RsProgramStore)pfs);
}
static void
@@ -1420,28 +1440,25 @@
{"nAdapter2DCreate", "()I", (void*)nAdapter2DCreate },
{"nScriptBindAllocation", "(III)V", (void*)nScriptBindAllocation },
-{"nScriptSetClearColor", "(IFFFF)V", (void*)nScriptSetClearColor },
-{"nScriptSetClearDepth", "(IF)V", (void*)nScriptSetClearDepth },
-{"nScriptSetClearStencil", "(II)V", (void*)nScriptSetClearStencil },
{"nScriptSetTimeZone", "(I[B)V", (void*)nScriptSetTimeZone },
-{"nScriptSetType", "(IZLjava/lang/String;I)V", (void*)nScriptSetType },
-{"nScriptSetRoot", "(Z)V", (void*)nScriptSetRoot },
-{"nScriptSetInvokable", "(Ljava/lang/String;I)V", (void*)nScriptSetInvoke },
{"nScriptInvoke", "(II)V", (void*)nScriptInvoke },
+{"nScriptInvokeData", "(II)V", (void*)nScriptInvokeData },
+{"nScriptInvokeV", "(II[B)V", (void*)nScriptInvokeV },
+{"nScriptSetVarI", "(III)V", (void*)nScriptSetVarI },
+{"nScriptSetVarF", "(IIF)V", (void*)nScriptSetVarF },
+{"nScriptSetVarV", "(II[B)V", (void*)nScriptSetVarV },
{"nScriptCBegin", "()V", (void*)nScriptCBegin },
{"nScriptCSetScript", "([BII)V", (void*)nScriptCSetScript },
{"nScriptCCreate", "()I", (void*)nScriptCCreate },
-{"nScriptCAddDefineI32", "(Ljava/lang/String;I)V", (void*)nScriptCAddDefineI32 },
-{"nScriptCAddDefineF", "(Ljava/lang/String;F)V", (void*)nScriptCAddDefineF },
-{"nProgramFragmentStoreBegin", "(II)V", (void*)nProgramFragmentStoreBegin },
-{"nProgramFragmentStoreDepthFunc", "(I)V", (void*)nProgramFragmentStoreDepthFunc },
-{"nProgramFragmentStoreDepthMask", "(Z)V", (void*)nProgramFragmentStoreDepthMask },
-{"nProgramFragmentStoreColorMask", "(ZZZZ)V", (void*)nProgramFragmentStoreColorMask },
-{"nProgramFragmentStoreBlendFunc", "(II)V", (void*)nProgramFragmentStoreBlendFunc },
-{"nProgramFragmentStoreDither", "(Z)V", (void*)nProgramFragmentStoreDither },
-{"nProgramFragmentStoreCreate", "()I", (void*)nProgramFragmentStoreCreate },
+{"nProgramStoreBegin", "(II)V", (void*)nProgramStoreBegin },
+{"nProgramStoreDepthFunc", "(I)V", (void*)nProgramStoreDepthFunc },
+{"nProgramStoreDepthMask", "(Z)V", (void*)nProgramStoreDepthMask },
+{"nProgramStoreColorMask", "(ZZZZ)V", (void*)nProgramStoreColorMask },
+{"nProgramStoreBlendFunc", "(II)V", (void*)nProgramStoreBlendFunc },
+{"nProgramStoreDither", "(Z)V", (void*)nProgramStoreDither },
+{"nProgramStoreCreate", "()I", (void*)nProgramStoreCreate },
{"nProgramBindConstants", "(III)V", (void*)nProgramBindConstants },
{"nProgramBindTexture", "(III)V", (void*)nProgramBindTexture },
@@ -1465,7 +1482,7 @@
{"nLightSetPosition", "(IFFF)V", (void*)nLightSetPosition },
{"nContextBindRootScript", "(I)V", (void*)nContextBindRootScript },
-{"nContextBindProgramFragmentStore","(I)V", (void*)nContextBindProgramFragmentStore },
+{"nContextBindProgramStore", "(I)V", (void*)nContextBindProgramStore },
{"nContextBindProgramFragment", "(I)V", (void*)nContextBindProgramFragment },
{"nContextBindProgramVertex", "(I)V", (void*)nContextBindProgramVertex },
{"nContextBindProgramRaster", "(I)V", (void*)nContextBindProgramRaster },
@@ -1478,6 +1495,11 @@
{"nSimpleMeshBindVertex", "(III)V", (void*)nSimpleMeshBindVertex },
{"nSimpleMeshBindIndex", "(II)V", (void*)nSimpleMeshBindIndex },
+{"nFileA3DCreateFromAssetStream", "(I)I", (void*)nFileA3DCreateFromAssetStream },
+{"nFileA3DGetNumIndexEntries", "(I)I", (void*)nFileA3DGetNumIndexEntries },
+{"nFileA3DGetIndexEntries", "(II[I[Ljava/lang/String;)V", (void*)nFileA3DGetIndexEntries },
+{"nFileA3DGetEntryByIndex", "(II)I", (void*)nFileA3DGetEntryByIndex },
+
};
static int registerFuncs(JNIEnv *_env)
diff --git a/icu4j/java/android/icu/text/ArabicShaping.java b/icu4j/java/android/icu/text/ArabicShaping.java
new file mode 100644
index 0000000..13e2175
--- /dev/null
+++ b/icu4j/java/android/icu/text/ArabicShaping.java
@@ -0,0 +1,1947 @@
+/*
+*******************************************************************************
+* Copyright (C) 2001-2009, International Business Machines
+* Corporation and others. All Rights Reserved.
+*******************************************************************************
+*/
+
+/*
+ * Ported with minor modifications from ICU4J 4.2's
+ * com.ibm.icu.text.ArabicShaping class.
+ */
+
+package android.icu.text;
+
+
+/**
+ * Shape Arabic text on a character basis.
+ *
+ * <p>ArabicShaping performs basic operations for "shaping" Arabic text. It is most
+ * useful for use with legacy data formats and legacy display technology
+ * (simple terminals). All operations are performed on Unicode characters.</p>
+ *
+ * <p>Text-based shaping means that some character code points in the text are
+ * replaced by others depending on the context. It transforms one kind of text
+ * into another. In comparison, modern displays for Arabic text select
+ * appropriate, context-dependent font glyphs for each text element, which means
+ * that they transform text into a glyph vector.</p>
+ *
+ * <p>Text transformations are necessary when modern display technology is not
+ * available or when text needs to be transformed to or from legacy formats that
+ * use "shaped" characters. Since the Arabic script is cursive, connecting
+ * adjacent letters to each other, computers select images for each letter based
+ * on the surrounding letters. This usually results in four images per Arabic
+ * letter: initial, middle, final, and isolated forms. In Unicode, on the other
+ * hand, letters are normally stored abstract, and a display system is expected
+ * to select the necessary glyphs. (This makes searching and other text
+ * processing easier because the same letter has only one code.) It is possible
+ * to mimic this with text transformations because there are characters in
+ * Unicode that are rendered as letters with a specific shape
+ * (or cursive connectivity). They were included for interoperability with
+ * legacy systems and codepages, and for unsophisticated display systems.</p>
+ *
+ * <p>A second kind of text transformations is supported for Arabic digits:
+ * For compatibility with legacy codepages that only include European digits,
+ * it is possible to replace one set of digits by another, changing the
+ * character code points. These operations can be performed for either
+ * Arabic-Indic Digits (U+0660...U+0669) or Eastern (Extended) Arabic-Indic
+ * digits (U+06f0...U+06f9).</p>
+ *
+ * <p>Some replacements may result in more or fewer characters (code points).
+ * By default, this means that the destination buffer may receive text with a
+ * length different from the source length. Some legacy systems rely on the
+ * length of the text to be constant. They expect extra spaces to be added
+ * or consumed either next to the affected character or at the end of the
+ * text.</p>
+ * @stable ICU 2.0
+ *
+ * @hide
+ */
+public class ArabicShaping {
+ private final int options;
+ private boolean isLogical; // convenience
+ private boolean spacesRelativeToTextBeginEnd;
+ private char tailChar;
+
+ public static final ArabicShaping SHAPER = new ArabicShaping(
+ ArabicShaping.TEXT_DIRECTION_LOGICAL |
+ ArabicShaping.LENGTH_FIXED_SPACES_NEAR |
+ ArabicShaping.LETTERS_SHAPE |
+ ArabicShaping.DIGITS_NOOP);
+
+ /**
+ * Convert a range of text in the source array, putting the result
+ * into a range of text in the destination array, and return the number
+ * of characters written.
+ *
+ * @param source An array containing the input text
+ * @param sourceStart The start of the range of text to convert
+ * @param sourceLength The length of the range of text to convert
+ * @param dest The destination array that will receive the result.
+ * It may be <code>NULL</code> only if <code>destSize</code> is 0.
+ * @param destStart The start of the range of the destination buffer to use.
+ * @param destSize The size (capacity) of the destination buffer.
+ * If <code>destSize</code> is 0, then no output is produced,
+ * but the necessary buffer size is returned ("preflighting"). This
+ * does not validate the text against the options, for example,
+ * if letters are being unshaped, and spaces are being consumed
+ * following lamalef, this will not detect a lamalef without a
+ * corresponding space. An error will be thrown when the actual
+ * conversion is attempted.
+ * @return The number of chars written to the destination buffer.
+ * If an error occurs, then no output was written, or it may be
+ * incomplete.
+ * @throws ArabicShapingException if the text cannot be converted according to the options.
+ * @stable ICU 2.0
+ */
+ public int shape(char[] source, int sourceStart, int sourceLength,
+ char[] dest, int destStart, int destSize) throws ArabicShapingException {
+ if (source == null) {
+ throw new IllegalArgumentException("source can not be null");
+ }
+ if (sourceStart < 0 || sourceLength < 0 || sourceStart + sourceLength > source.length) {
+ throw new IllegalArgumentException("bad source start (" + sourceStart +
+ ") or length (" + sourceLength +
+ ") for buffer of length " + source.length);
+ }
+ if (dest == null && destSize != 0) {
+ throw new IllegalArgumentException("null dest requires destSize == 0");
+ }
+ if ((destSize != 0) &&
+ (destStart < 0 || destSize < 0 || destStart + destSize > dest.length)) {
+ throw new IllegalArgumentException("bad dest start (" + destStart +
+ ") or size (" + destSize +
+ ") for buffer of length " + dest.length);
+ }
+ /* Validate input options */
+ if ( ((options&TASHKEEL_MASK) > 0) &&
+ !(((options & TASHKEEL_MASK)==TASHKEEL_BEGIN) ||
+ ((options & TASHKEEL_MASK)==TASHKEEL_END ) ||
+ ((options & TASHKEEL_MASK)==TASHKEEL_RESIZE )||
+ ((options & TASHKEEL_MASK)==TASHKEEL_REPLACE_BY_TATWEEL)) ){
+ throw new IllegalArgumentException("Wrong Tashkeel argument");
+ }
+
+ ///CLOVER:OFF
+ //According to Steven Loomis, the code is unreachable when you OR all the constants within the if statements
+ if(((options&LAMALEF_MASK) > 0)&&
+ !(((options & LAMALEF_MASK)==LAMALEF_BEGIN) ||
+ ((options & LAMALEF_MASK)==LAMALEF_END ) ||
+ ((options & LAMALEF_MASK)==LAMALEF_RESIZE )||
+ ((options & LAMALEF_MASK)==LAMALEF_AUTO) ||
+ ((options & LAMALEF_MASK)==LAMALEF_NEAR))){
+ throw new IllegalArgumentException("Wrong Lam Alef argument");
+ }
+ ///CLOVER:ON
+
+ /* Validate Tashkeel (Tashkeel replacement options should be enabled in shaping mode only)*/
+ if(((options&TASHKEEL_MASK) > 0) && (options&LETTERS_MASK) == LETTERS_UNSHAPE) {
+ throw new IllegalArgumentException("Tashkeel replacement should not be enabled in deshaping mode ");
+ }
+ return internalShape(source, sourceStart, sourceLength, dest, destStart, destSize);
+ }
+
+ /**
+ * Convert a range of text in place. This may only be used if the Length option
+ * does not grow or shrink the text.
+ *
+ * @param source An array containing the input text
+ * @param start The start of the range of text to convert
+ * @param length The length of the range of text to convert
+ * @throws ArabicShapingException if the text cannot be converted according to the options.
+ * @stable ICU 2.0
+ */
+ public void shape(char[] source, int start, int length) throws ArabicShapingException {
+ if ((options & LAMALEF_MASK) == LAMALEF_RESIZE) {
+ throw new ArabicShapingException("Cannot shape in place with length option resize.");
+ }
+ shape(source, start, length, source, start, length);
+ }
+
+ /**
+ * Convert a string, returning the new string.
+ *
+ * @param text the string to convert
+ * @return the converted string
+ * @throws ArabicShapingException if the string cannot be converted according to the options.
+ * @stable ICU 2.0
+ */
+ public String shape(String text) throws ArabicShapingException {
+ char[] src = text.toCharArray();
+ char[] dest = src;
+ if (((options & LAMALEF_MASK) == LAMALEF_RESIZE) &&
+ ((options & LETTERS_MASK) == LETTERS_UNSHAPE)) {
+
+ dest = new char[src.length * 2]; // max
+ }
+ int len = shape(src, 0, src.length, dest, 0, dest.length);
+
+ return new String(dest, 0, len);
+ }
+
+ /**
+ * Construct ArabicShaping using the options flags.
+ * The flags are as follows:<br>
+ * 'LENGTH' flags control whether the text can change size, and if not,
+ * how to maintain the size of the text when LamAlef ligatures are
+ * formed or broken.<br>
+ * 'TEXT_DIRECTION' flags control whether the text is read and written
+ * in visual order or in logical order.<br>
+ * 'LETTERS_SHAPE' flags control whether conversion is to or from
+ * presentation forms.<br>
+ * 'DIGITS' flags control whether digits are shaped, and whether from
+ * European to Arabic-Indic or vice-versa.<br>
+ * 'DIGIT_TYPE' flags control whether standard or extended Arabic-Indic
+ * digits are used when performing digit conversion.
+ * @stable ICU 2.0
+ */
+ public ArabicShaping(int options) {
+ this.options = options;
+ if ((options & DIGITS_MASK) > 0x80) {
+ throw new IllegalArgumentException("bad DIGITS options");
+ }
+
+ isLogical = ( (options & TEXT_DIRECTION_MASK) == TEXT_DIRECTION_LOGICAL );
+ /* Validate options */
+ spacesRelativeToTextBeginEnd = ( (options & SPACES_RELATIVE_TO_TEXT_MASK) == SPACES_RELATIVE_TO_TEXT_BEGIN_END );
+ if ( (options&SHAPE_TAIL_TYPE_MASK) == SHAPE_TAIL_NEW_UNICODE){
+ tailChar = NEW_TAIL_CHAR;
+ } else {
+ tailChar = OLD_TAIL_CHAR;
+ }
+ }
+
+ /* Seen Tail options */
+ /**
+ * Memory option: the result must have the same length as the source.
+ * Shaping mode: The SEEN family character will expand into two characters using space near
+ * the SEEN family character(i.e. the space after the character).
+ * if there are no spaces found, ArabicShapingException will be thrown
+ *
+ * De-shaping mode: Any Seen character followed by Tail character will be
+ * replaced by one cell Seen and a space will replace the Tail.
+ * Affects: Seen options
+ */
+ public static final int SEEN_TWOCELL_NEAR = 0x200000;
+
+ /** Bit mask for Seen memory options. */
+ public static final int SEEN_MASK = 0x700000;
+
+ /* YehHamza options */
+ /**
+ * Memory option: the result must have the same length as the source.
+ * Shaping mode: The YEHHAMZA character will expand into two characters using space near it
+ * (i.e. the space after the character)
+ * if there are no spaces found, ArabicShapingException will be thrown
+ *
+ * De-shaping mode: Any Yeh (final or isolated) character followed by Hamza character will be
+ * replaced by one cell YehHamza and space will replace the Hamza.
+ * Affects: YehHamza options
+ */
+ public static final int YEHHAMZA_TWOCELL_NEAR = 0x1000000;
+
+
+ /** Bit mask for YehHamza memory options. */
+ public static final int YEHHAMZA_MASK = 0x3800000;
+
+ /* New Tashkeel options */
+ /**
+ * Memory option: the result must have the same length as the source.
+ * Shaping mode: Tashkeel characters will be replaced by spaces.
+ * Spaces will be placed at beginning of the buffer
+ *
+ * De-shaping mode: N/A
+ * Affects: Tashkeel options
+ */
+ public static final int TASHKEEL_BEGIN = 0x40000;
+
+ /**
+ * Memory option: the result must have the same length as the source.
+ * Shaping mode: Tashkeel characters will be replaced by spaces.
+ * Spaces will be placed at end of the buffer
+ *
+ * De-shaping mode: N/A
+ * Affects: Tashkeel options
+ */
+ public static final int TASHKEEL_END = 0x60000;
+
+ /**
+ * Memory option: allow the result to have a different length than the source.
+ * Shaping mode: Tashkeel characters will be removed, buffer length will shrink.
+ * De-shaping mode: N/A
+ *
+ * Affects: Tashkeel options
+ */
+ public static final int TASHKEEL_RESIZE = 0x80000;
+
+ /**
+ * Memory option: the result must have the same length as the source.
+ * Shaping mode: Tashkeel characters will be replaced by Tatweel if it is connected to adjacent
+ * characters (i.e. shaped on Tatweel) or replaced by space if it is not connected.
+ *
+ * De-shaping mode: N/A
+ * Affects: YehHamza options
+ */
+ public static final int TASHKEEL_REPLACE_BY_TATWEEL = 0xC0000;
+
+ /** Bit mask for Tashkeel replacement with Space or Tatweel memory options. */
+ public static final int TASHKEEL_MASK = 0xE0000;
+
+ /* Space location Control options */
+ /**
+ * This option effects the meaning of BEGIN and END options. if this option is not used the default
+ * for BEGIN and END will be as following:
+ * The Default (for both Visual LTR, Visual RTL and Logical Text)
+ * 1. BEGIN always refers to the start address of physical memory.
+ * 2. END always refers to the end address of physical memory.
+ *
+ * If this option is used it will swap the meaning of BEGIN and END only for Visual LTR text.
+ *
+ * The affect on BEGIN and END Memory Options will be as following:
+ * A. BEGIN For Visual LTR text: This will be the beginning (right side) of the visual text
+ * (corresponding to the physical memory address end, same as END in default behavior)
+ * B. BEGIN For Logical text: Same as BEGIN in default behavior.
+ * C. END For Visual LTR text: This will be the end (left side) of the visual text. (corresponding to
+ * the physical memory address beginning, same as BEGIN in default behavior)
+ * D. END For Logical text: Same as END in default behavior.
+ * Affects: All LamAlef BEGIN, END and AUTO options.
+ */
+ public static final int SPACES_RELATIVE_TO_TEXT_BEGIN_END = 0x4000000;
+
+ /** Bit mask for swapping BEGIN and END for Visual LTR text */
+ public static final int SPACES_RELATIVE_TO_TEXT_MASK = 0x4000000;
+
+ /**
+ * If this option is used, shaping will use the new Unicode code point for TAIL (i.e. 0xFE73).
+ * If this option is not specified (Default), old unofficial Unicode TAIL code point is used (i.e. 0x200B)
+ * De-shaping will not use this option as it will always search for both the new Unicode code point for the
+ * TAIL (i.e. 0xFE73) or the old unofficial Unicode TAIL code point (i.e. 0x200B) and de-shape the
+ * Seen-Family letter accordingly.
+ *
+ * Shaping Mode: Only shaping.
+ * De-shaping Mode: N/A.
+ * Affects: All Seen options
+ */
+ public static final int SHAPE_TAIL_NEW_UNICODE = 0x8000000;
+
+ /** Bit mask for new Unicode Tail option */
+ public static final int SHAPE_TAIL_TYPE_MASK = 0x8000000;
+
+ /**
+ * Memory option: allow the result to have a different length than the source.
+ * @stable ICU 2.0
+ */
+ public static final int LENGTH_GROW_SHRINK = 0;
+
+ /**
+ * Memory option: allow the result to have a different length than the source.
+ * Affects: LamAlef options
+ * This option is an alias to LENGTH_GROW_SHRINK
+ */
+ public static final int LAMALEF_RESIZE = 0;
+
+ /**
+ * Memory option: the result must have the same length as the source.
+ * If more room is necessary, then try to consume spaces next to modified characters.
+ * @stable ICU 2.0
+ */
+ public static final int LENGTH_FIXED_SPACES_NEAR = 1;
+
+ /**
+ * Memory option: the result must have the same length as the source.
+ * If more room is necessary, then try to consume spaces next to modified characters.
+ * Affects: LamAlef options
+ * This option is an alias to LENGTH_FIXED_SPACES_NEAR
+ */
+ public static final int LAMALEF_NEAR = 1 ;
+
+ /**
+ * Memory option: the result must have the same length as the source.
+ * If more room is necessary, then try to consume spaces at the end of the text.
+ * @stable ICU 2.0
+ */
+ public static final int LENGTH_FIXED_SPACES_AT_END = 2;
+
+
+ /**
+ * Memory option: the result must have the same length as the source.
+ * If more room is necessary, then try to consume spaces at the end of the text.
+ * Affects: LamAlef options
+ * This option is an alias to LENGTH_FIXED_SPACES_AT_END
+ */
+ public static final int LAMALEF_END = 2;
+
+ /**
+ * Memory option: the result must have the same length as the source.
+ * If more room is necessary, then try to consume spaces at the beginning of the text.
+ * @stable ICU 2.0
+ */
+ public static final int LENGTH_FIXED_SPACES_AT_BEGINNING = 3;
+
+ /**
+ * Memory option: the result must have the same length as the source.
+ * If more room is necessary, then try to consume spaces at the beginning of the text.
+ * Affects: LamAlef options
+ * This option is an alias to LENGTH_FIXED_SPACES_AT_BEGINNING
+ */
+ public static final int LAMALEF_BEGIN = 3;
+
+ /**
+ * Memory option: the result must have the same length as the source.
+ * Shaping Mode: For each LAMALEF character found, expand LAMALEF using space at end.
+ * If there is no space at end, use spaces at beginning of the buffer. If there
+ * is no space at beginning of the buffer, use spaces at the near (i.e. the space
+ * after the LAMALEF character).
+ *
+ * Deshaping Mode: Perform the same function as the flag equals LAMALEF_END.
+ * Affects: LamAlef options
+ */
+ public static final int LAMALEF_AUTO = 0x10000;
+
+ /**
+ * Bit mask for memory options.
+ * @stable ICU 2.0
+ */
+ public static final int LENGTH_MASK = 0x10003;
+
+ /** Bit mask for LamAlef memory options. */
+
+ public static final int LAMALEF_MASK = 0x10003;
+
+ /**
+ * Direction indicator: the source is in logical (keyboard) order.
+ * @stable ICU 2.0
+ */
+ public static final int TEXT_DIRECTION_LOGICAL = 0;
+
+ /**
+ * Direction indicator:the source is in visual RTL order,
+ * the rightmost displayed character stored first.
+ * This option is an alias to U_SHAPE_TEXT_DIRECTION_LOGICAL
+ */
+ public static final int TEXT_DIRECTION_VISUAL_RTL = 0;
+
+ /**
+ * Direction indicator: the source is in visual (display) order, that is,
+ * the leftmost displayed character is stored first.
+ * @stable ICU 2.0
+ */
+ public static final int TEXT_DIRECTION_VISUAL_LTR = 4;
+
+ /**
+ * Bit mask for direction indicators.
+ * @stable ICU 2.0
+ */
+ public static final int TEXT_DIRECTION_MASK = 4;
+
+
+ /**
+ * Letter shaping option: do not perform letter shaping.
+ * @stable ICU 2.0
+ */
+ public static final int LETTERS_NOOP = 0;
+
+ /**
+ * Letter shaping option: replace normative letter characters in the U+0600 (Arabic) block,
+ * by shaped ones in the U+FE70 (Presentation Forms B) block. Performs Lam-Alef ligature
+ * substitution.
+ * @stable ICU 2.0
+ */
+ public static final int LETTERS_SHAPE = 8;
+
+ /**
+ * Letter shaping option: replace shaped letter characters in the U+FE70 (Presentation Forms B) block
+ * by normative ones in the U+0600 (Arabic) block. Converts Lam-Alef ligatures to pairs of Lam and
+ * Alef characters, consuming spaces if required.
+ * @stable ICU 2.0
+ */
+ public static final int LETTERS_UNSHAPE = 0x10;
+
+ /**
+ * Letter shaping option: replace normative letter characters in the U+0600 (Arabic) block,
+ * except for the TASHKEEL characters at U+064B...U+0652, by shaped ones in the U+Fe70
+ * (Presentation Forms B) block. The TASHKEEL characters will always be converted to
+ * the isolated forms rather than to their correct shape.
+ * @stable ICU 2.0
+ */
+ public static final int LETTERS_SHAPE_TASHKEEL_ISOLATED = 0x18;
+
+ /**
+ * Bit mask for letter shaping options.
+ * @stable ICU 2.0
+ */
+ public static final int LETTERS_MASK = 0x18;
+
+
+ /**
+ * Digit shaping option: do not perform digit shaping.
+ * @stable ICU 2.0
+ */
+ public static final int DIGITS_NOOP = 0;
+
+ /**
+ * Digit shaping option: Replace European digits (U+0030...U+0039) by Arabic-Indic digits.
+ * @stable ICU 2.0
+ */
+ public static final int DIGITS_EN2AN = 0x20;
+
+ /**
+ * Digit shaping option: Replace Arabic-Indic digits by European digits (U+0030...U+0039).
+ * @stable ICU 2.0
+ */
+ public static final int DIGITS_AN2EN = 0x40;
+
+ /**
+ * Digit shaping option:
+ * Replace European digits (U+0030...U+0039) by Arabic-Indic digits
+ * if the most recent strongly directional character
+ * is an Arabic letter (its Bidi direction value is RIGHT_TO_LEFT_ARABIC).
+ * The initial state at the start of the text is assumed to be not an Arabic,
+ * letter, so European digits at the start of the text will not change.
+ * Compare to DIGITS_ALEN2AN_INIT_AL.
+ * @stable ICU 2.0
+ */
+ public static final int DIGITS_EN2AN_INIT_LR = 0x60;
+
+ /**
+ * Digit shaping option:
+ * Replace European digits (U+0030...U+0039) by Arabic-Indic digits
+ * if the most recent strongly directional character
+ * is an Arabic letter (its Bidi direction value is RIGHT_TO_LEFT_ARABIC).
+ * The initial state at the start of the text is assumed to be an Arabic,
+ * letter, so European digits at the start of the text will change.
+ * Compare to DIGITS_ALEN2AN_INT_LR.
+ * @stable ICU 2.0
+ */
+ public static final int DIGITS_EN2AN_INIT_AL = 0x80;
+
+ /** Not a valid option value. */
+ //private static final int DIGITS_RESERVED = 0xa0;
+
+ /**
+ * Bit mask for digit shaping options.
+ * @stable ICU 2.0
+ */
+ public static final int DIGITS_MASK = 0xe0;
+
+ /**
+ * Digit type option: Use Arabic-Indic digits (U+0660...U+0669).
+ * @stable ICU 2.0
+ */
+ public static final int DIGIT_TYPE_AN = 0;
+
+ /**
+ * Digit type option: Use Eastern (Extended) Arabic-Indic digits (U+06f0...U+06f9).
+ * @stable ICU 2.0
+ */
+ public static final int DIGIT_TYPE_AN_EXTENDED = 0x100;
+
+ /**
+ * Bit mask for digit type options.
+ * @stable ICU 2.0
+ */
+ public static final int DIGIT_TYPE_MASK = 0x0100; // 0x3f00?
+
+ /**
+ * some constants
+ */
+ private static final char HAMZAFE_CHAR = '\ufe80';
+ private static final char HAMZA06_CHAR = '\u0621';
+ private static final char YEH_HAMZA_CHAR = '\u0626';
+ private static final char YEH_HAMZAFE_CHAR = '\uFE89';
+ private static final char LAMALEF_SPACE_SUB = '\uffff';
+ private static final char TASHKEEL_SPACE_SUB = '\ufffe';
+ private static final char LAM_CHAR = '\u0644';
+ private static final char SPACE_CHAR = '\u0020';
+ private static final char SPACE_CHAR_FOR_LAMALEF = '\ufeff'; // XXX: tweak for TextLine use
+ private static final char SHADDA_CHAR = '\uFE7C';
+ private static final char TATWEEL_CHAR = '\u0640';
+ private static final char SHADDA_TATWEEL_CHAR = '\uFE7D';
+ private static final char NEW_TAIL_CHAR = '\uFE73';
+ private static final char OLD_TAIL_CHAR = '\u200B';
+ private static final int SHAPE_MODE = 0;
+ private static final int DESHAPE_MODE = 1;
+
+ /**
+ * @stable ICU 2.0
+ */
+ public boolean equals(Object rhs) {
+ return rhs != null &&
+ rhs.getClass() == ArabicShaping.class &&
+ options == ((ArabicShaping)rhs).options;
+ }
+
+ /**
+ * @stable ICU 2.0
+ */
+ ///CLOVER:OFF
+ public int hashCode() {
+ return options;
+ }
+
+ /**
+ * @stable ICU 2.0
+ */
+ public String toString() {
+ StringBuffer buf = new StringBuffer(super.toString());
+ buf.append('[');
+
+ switch (options & LAMALEF_MASK) {
+ case LAMALEF_RESIZE: buf.append("LamAlef resize"); break;
+ case LAMALEF_NEAR: buf.append("LamAlef spaces at near"); break;
+ case LAMALEF_BEGIN: buf.append("LamAlef spaces at begin"); break;
+ case LAMALEF_END: buf.append("LamAlef spaces at end"); break;
+ case LAMALEF_AUTO: buf.append("lamAlef auto"); break;
+ }
+ switch (options & TEXT_DIRECTION_MASK) {
+ case TEXT_DIRECTION_LOGICAL: buf.append(", logical"); break;
+ case TEXT_DIRECTION_VISUAL_LTR: buf.append(", visual"); break;
+ }
+ switch (options & LETTERS_MASK) {
+ case LETTERS_NOOP: buf.append(", no letter shaping"); break;
+ case LETTERS_SHAPE: buf.append(", shape letters"); break;
+ case LETTERS_SHAPE_TASHKEEL_ISOLATED: buf.append(", shape letters tashkeel isolated"); break;
+ case LETTERS_UNSHAPE: buf.append(", unshape letters"); break;
+ }
+ switch (options & SEEN_MASK) {
+ case SEEN_TWOCELL_NEAR: buf.append(", Seen at near"); break;
+ }
+ switch (options & YEHHAMZA_MASK) {
+ case YEHHAMZA_TWOCELL_NEAR: buf.append(", Yeh Hamza at near"); break;
+ }
+ switch (options & TASHKEEL_MASK) {
+ case TASHKEEL_BEGIN: buf.append(", Tashkeel at begin"); break;
+ case TASHKEEL_END: buf.append(", Tashkeel at end"); break;
+ case TASHKEEL_REPLACE_BY_TATWEEL: buf.append(", Tashkeel replace with tatweel"); break;
+ case TASHKEEL_RESIZE: buf.append(", Tashkeel resize"); break;
+ }
+
+ switch (options & DIGITS_MASK) {
+ case DIGITS_NOOP: buf.append(", no digit shaping"); break;
+ case DIGITS_EN2AN: buf.append(", shape digits to AN"); break;
+ case DIGITS_AN2EN: buf.append(", shape digits to EN"); break;
+ case DIGITS_EN2AN_INIT_LR: buf.append(", shape digits to AN contextually: default EN"); break;
+ case DIGITS_EN2AN_INIT_AL: buf.append(", shape digits to AN contextually: default AL"); break;
+ }
+ switch (options & DIGIT_TYPE_MASK) {
+ case DIGIT_TYPE_AN: buf.append(", standard Arabic-Indic digits"); break;
+ case DIGIT_TYPE_AN_EXTENDED: buf.append(", extended Arabic-Indic digits"); break;
+ }
+ buf.append("]");
+
+ return buf.toString();
+ }
+ ///CLOVER:ON
+
+ //
+ // ported api
+ //
+
+ private static final int IRRELEVANT = 4;
+ private static final int LAMTYPE = 16;
+ private static final int ALEFTYPE = 32;
+
+ private static final int LINKR = 1;
+ private static final int LINKL = 2;
+ private static final int LINK_MASK = 3;
+
+ private static final int irrelevantPos[] = {
+ 0x0, 0x2, 0x4, 0x6, 0x8, 0xA, 0xC, 0xE
+ };
+
+/*
+ private static final char convertLamAlef[] = {
+ '\u0622', // FEF5
+ '\u0622', // FEF6
+ '\u0623', // FEF7
+ '\u0623', // FEF8
+ '\u0625', // FEF9
+ '\u0625', // FEFA
+ '\u0627', // FEFB
+ '\u0627' // FEFC
+ };
+*/
+
+ private static final int tailFamilyIsolatedFinal[] = {
+ /* FEB1 */ 1,
+ /* FEB2 */ 1,
+ /* FEB3 */ 0,
+ /* FEB4 */ 0,
+ /* FEB5 */ 1,
+ /* FEB6 */ 1,
+ /* FEB7 */ 0,
+ /* FEB8 */ 0,
+ /* FEB9 */ 1,
+ /* FEBA */ 1,
+ /* FEBB */ 0,
+ /* FEBC */ 0,
+ /* FEBD */ 1,
+ /* FEBE */ 1
+ };
+
+ private static final int tashkeelMedial[] = {
+ /* FE70 */ 0,
+ /* FE71 */ 1,
+ /* FE72 */ 0,
+ /* FE73 */ 0,
+ /* FE74 */ 0,
+ /* FE75 */ 0,
+ /* FE76 */ 0,
+ /* FE77 */ 1,
+ /* FE78 */ 0,
+ /* FE79 */ 1,
+ /* FE7A */ 0,
+ /* FE7B */ 1,
+ /* FE7C */ 0,
+ /* FE7D */ 1,
+ /* FE7E */ 0,
+ /* FE7F */ 1
+ };
+
+ private static final char yehHamzaToYeh[] =
+ {
+ /* isolated*/ 0xFEEF,
+ /* final */ 0xFEF0
+ };
+
+ private static final char convertNormalizedLamAlef[] = {
+ '\u0622', // 065C
+ '\u0623', // 065D
+ '\u0625', // 065E
+ '\u0627', // 065F
+ };
+
+ private static final int[] araLink = {
+ 1 + 32 + 256 * 0x11, /*0x0622*/
+ 1 + 32 + 256 * 0x13, /*0x0623*/
+ 1 + 256 * 0x15, /*0x0624*/
+ 1 + 32 + 256 * 0x17, /*0x0625*/
+ 1 + 2 + 256 * 0x19, /*0x0626*/
+ 1 + 32 + 256 * 0x1D, /*0x0627*/
+ 1 + 2 + 256 * 0x1F, /*0x0628*/
+ 1 + 256 * 0x23, /*0x0629*/
+ 1 + 2 + 256 * 0x25, /*0x062A*/
+ 1 + 2 + 256 * 0x29, /*0x062B*/
+ 1 + 2 + 256 * 0x2D, /*0x062C*/
+ 1 + 2 + 256 * 0x31, /*0x062D*/
+ 1 + 2 + 256 * 0x35, /*0x062E*/
+ 1 + 256 * 0x39, /*0x062F*/
+ 1 + 256 * 0x3B, /*0x0630*/
+ 1 + 256 * 0x3D, /*0x0631*/
+ 1 + 256 * 0x3F, /*0x0632*/
+ 1 + 2 + 256 * 0x41, /*0x0633*/
+ 1 + 2 + 256 * 0x45, /*0x0634*/
+ 1 + 2 + 256 * 0x49, /*0x0635*/
+ 1 + 2 + 256 * 0x4D, /*0x0636*/
+ 1 + 2 + 256 * 0x51, /*0x0637*/
+ 1 + 2 + 256 * 0x55, /*0x0638*/
+ 1 + 2 + 256 * 0x59, /*0x0639*/
+ 1 + 2 + 256 * 0x5D, /*0x063A*/
+ 0, 0, 0, 0, 0, /*0x063B-0x063F*/
+ 1 + 2, /*0x0640*/
+ 1 + 2 + 256 * 0x61, /*0x0641*/
+ 1 + 2 + 256 * 0x65, /*0x0642*/
+ 1 + 2 + 256 * 0x69, /*0x0643*/
+ 1 + 2 + 16 + 256 * 0x6D, /*0x0644*/
+ 1 + 2 + 256 * 0x71, /*0x0645*/
+ 1 + 2 + 256 * 0x75, /*0x0646*/
+ 1 + 2 + 256 * 0x79, /*0x0647*/
+ 1 + 256 * 0x7D, /*0x0648*/
+ 1 + 256 * 0x7F, /*0x0649*/
+ 1 + 2 + 256 * 0x81, /*0x064A*/
+ 4, 4, 4, 4, /*0x064B-0x064E*/
+ 4, 4, 4, 4, /*0x064F-0x0652*/
+ 4, 4, 4, 0, 0, /*0x0653-0x0657*/
+ 0, 0, 0, 0, /*0x0658-0x065B*/
+ 1 + 256 * 0x85, /*0x065C*/
+ 1 + 256 * 0x87, /*0x065D*/
+ 1 + 256 * 0x89, /*0x065E*/
+ 1 + 256 * 0x8B, /*0x065F*/
+ 0, 0, 0, 0, 0, /*0x0660-0x0664*/
+ 0, 0, 0, 0, 0, /*0x0665-0x0669*/
+ 0, 0, 0, 0, 0, 0, /*0x066A-0x066F*/
+ 4, /*0x0670*/
+ 0, /*0x0671*/
+ 1 + 32, /*0x0672*/
+ 1 + 32, /*0x0673*/
+ 0, /*0x0674*/
+ 1 + 32, /*0x0675*/
+ 1, 1, /*0x0676-0x0677*/
+ 1+2, 1+2, 1+2, 1+2, 1+2, 1+2, /*0x0678-0x067D*/
+ 1+2, 1+2, 1+2, 1+2, 1+2, 1+2, /*0x067E-0x0683*/
+ 1+2, 1+2, 1+2, 1+2, /*0x0684-0x0687*/
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*0x0688-0x0691*/
+ 1, 1, 1, 1, 1, 1, 1, 1, /*0x0692-0x0699*/
+ 1+2, 1+2, 1+2, 1+2, 1+2, 1+2, /*0x069A-0x06A3*/
+ 1+2, 1+2, 1+2, 1+2, /*0x069A-0x06A3*/
+ 1+2, 1+2, 1+2, 1+2, 1+2, 1+2, /*0x06A4-0x06AD*/
+ 1+2, 1+2, 1+2, 1+2, /*0x06A4-0x06AD*/
+ 1+2, 1+2, 1+2, 1+2, 1+2, 1+2, /*0x06AE-0x06B7*/
+ 1+2, 1+2, 1+2, 1+2, /*0x06AE-0x06B7*/
+ 1+2, 1+2, 1+2, 1+2, 1+2, 1+2, /*0x06B8-0x06BF*/
+ 1+2, 1+2, /*0x06B8-0x06BF*/
+ 1, /*0x06C0*/
+ 1+2, /*0x06C1*/
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*0x06C2-0x06CB*/
+ 1+2, /*0x06CC*/
+ 1, /*0x06CD*/
+ 1+2, 1+2, 1+2, 1+2, /*0x06CE-0x06D1*/
+ 1, 1 /*0x06D2-0x06D3*/
+ };
+
+ private static final int[] presLink = {
+ 1 + 2, /*0xFE70*/
+ 1 + 2, /*0xFE71*/
+ 1 + 2, 0, 1+ 2, 0, 1+ 2, /*0xFE72-0xFE76*/
+ 1 + 2, /*0xFE77*/
+ 1+ 2, 1 + 2, 1+2, 1 + 2, /*0xFE78-0xFE81*/
+ 1+ 2, 1 + 2, 1+2, 1 + 2, /*0xFE82-0xFE85*/
+ 0, 0 + 32, 1 + 32, 0 + 32, /*0xFE86-0xFE89*/
+ 1 + 32, 0, 1, 0 + 32, /*0xFE8A-0xFE8D*/
+ 1 + 32, 0, 2, 1 + 2, /*0xFE8E-0xFE91*/
+ 1, 0 + 32, 1 + 32, 0, /*0xFE92-0xFE95*/
+ 2, 1 + 2, 1, 0, /*0xFE96-0xFE99*/
+ 1, 0, 2, 1 + 2, /*0xFE9A-0xFE9D*/
+ 1, 0, 2, 1 + 2, /*0xFE9E-0xFEA1*/
+ 1, 0, 2, 1 + 2, /*0xFEA2-0xFEA5*/
+ 1, 0, 2, 1 + 2, /*0xFEA6-0xFEA9*/
+ 1, 0, 2, 1 + 2, /*0xFEAA-0xFEAD*/
+ 1, 0, 1, 0, /*0xFEAE-0xFEB1*/
+ 1, 0, 1, 0, /*0xFEB2-0xFEB5*/
+ 1, 0, 2, 1+2, /*0xFEB6-0xFEB9*/
+ 1, 0, 2, 1+2, /*0xFEBA-0xFEBD*/
+ 1, 0, 2, 1+2, /*0xFEBE-0xFEC1*/
+ 1, 0, 2, 1+2, /*0xFEC2-0xFEC5*/
+ 1, 0, 2, 1+2, /*0xFEC6-0xFEC9*/
+ 1, 0, 2, 1+2, /*0xFECA-0xFECD*/
+ 1, 0, 2, 1+2, /*0xFECE-0xFED1*/
+ 1, 0, 2, 1+2, /*0xFED2-0xFED5*/
+ 1, 0, 2, 1+2, /*0xFED6-0xFED9*/
+ 1, 0, 2, 1+2, /*0xFEDA-0xFEDD*/
+ 1, 0, 2, 1+2, /*0xFEDE-0xFEE1*/
+ 1, 0 + 16, 2 + 16, 1 + 2 +16, /*0xFEE2-0xFEE5*/
+ 1 + 16, 0, 2, 1+2, /*0xFEE6-0xFEE9*/
+ 1, 0, 2, 1+2, /*0xFEEA-0xFEED*/
+ 1, 0, 2, 1+2, /*0xFEEE-0xFEF1*/
+ 1, 0, 1, 0, /*0xFEF2-0xFEF5*/
+ 1, 0, 2, 1+2, /*0xFEF6-0xFEF9*/
+ 1, 0, 1, 0, /*0xFEFA-0xFEFD*/
+ 1, 0, 1, 0,
+ 1
+ };
+
+ private static int[] convertFEto06 = {
+ /***********0******1******2******3******4******5******6******7******8******9******A******B******C******D******E******F***/
+ /*FE7*/ 0x64B, 0x64B, 0x64C, 0x64C, 0x64D, 0x64D, 0x64E, 0x64E, 0x64F, 0x64F, 0x650, 0x650, 0x651, 0x651, 0x652, 0x652,
+ /*FE8*/ 0x621, 0x622, 0x622, 0x623, 0x623, 0x624, 0x624, 0x625, 0x625, 0x626, 0x626, 0x626, 0x626, 0x627, 0x627, 0x628,
+ /*FE9*/ 0x628, 0x628, 0x628, 0x629, 0x629, 0x62A, 0x62A, 0x62A, 0x62A, 0x62B, 0x62B, 0x62B, 0x62B, 0x62C, 0x62C, 0x62C,
+ /*FEA*/ 0x62C, 0x62D, 0x62D, 0x62D, 0x62D, 0x62E, 0x62E, 0x62E, 0x62E, 0x62F, 0x62F, 0x630, 0x630, 0x631, 0x631, 0x632,
+ /*FEB*/ 0x632, 0x633, 0x633, 0x633, 0x633, 0x634, 0x634, 0x634, 0x634, 0x635, 0x635, 0x635, 0x635, 0x636, 0x636, 0x636,
+ /*FEC*/ 0x636, 0x637, 0x637, 0x637, 0x637, 0x638, 0x638, 0x638, 0x638, 0x639, 0x639, 0x639, 0x639, 0x63A, 0x63A, 0x63A,
+ /*FED*/ 0x63A, 0x641, 0x641, 0x641, 0x641, 0x642, 0x642, 0x642, 0x642, 0x643, 0x643, 0x643, 0x643, 0x644, 0x644, 0x644,
+ /*FEE*/ 0x644, 0x645, 0x645, 0x645, 0x645, 0x646, 0x646, 0x646, 0x646, 0x647, 0x647, 0x647, 0x647, 0x648, 0x648, 0x649,
+ /*FEF*/ 0x649, 0x64A, 0x64A, 0x64A, 0x64A, 0x65C, 0x65C, 0x65D, 0x65D, 0x65E, 0x65E, 0x65F, 0x65F
+ };
+
+ private static final int shapeTable[][][] = {
+ { {0,0,0,0}, {0,0,0,0}, {0,1,0,3}, {0,1,0,1} },
+ { {0,0,2,2}, {0,0,1,2}, {0,1,1,2}, {0,1,1,3} },
+ { {0,0,0,0}, {0,0,0,0}, {0,1,0,3}, {0,1,0,3} },
+ { {0,0,1,2}, {0,0,1,2}, {0,1,1,2}, {0,1,1,3} }
+ };
+
+ /*
+ * This function shapes European digits to Arabic-Indic digits
+ * in-place, writing over the input characters. Data is in visual
+ * order.
+ */
+ private void shapeToArabicDigitsWithContext(char[] dest,
+ int start,
+ int length,
+ char digitBase,
+ boolean lastStrongWasAL) {
+ digitBase -= '0'; // move common adjustment out of loop
+
+ for(int i = start + length; --i >= start;) {
+ char ch = dest[i];
+ switch (Character.getDirectionality(ch)) {
+ case Character.DIRECTIONALITY_LEFT_TO_RIGHT:
+ case Character.DIRECTIONALITY_RIGHT_TO_LEFT:
+ lastStrongWasAL = false;
+ break;
+ case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC:
+ lastStrongWasAL = true;
+ break;
+ case Character.DIRECTIONALITY_EUROPEAN_NUMBER:
+ if (lastStrongWasAL && ch <= '\u0039') {
+ dest[i] = (char)(ch + digitBase);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ /*
+ * Name : invertBuffer
+ * Function: This function inverts the buffer, it's used
+ * in case the user specifies the buffer to be
+ * TEXT_DIRECTION_LOGICAL
+ */
+ private static void invertBuffer(char[] buffer,
+ int start,
+ int length) {
+
+ for(int i = start, j = start + length - 1; i < j; i++, --j) {
+ char temp = buffer[i];
+ buffer[i] = buffer[j];
+ buffer[j] = temp;
+ }
+ }
+
+ /*
+ * Name : changeLamAlef
+ * Function: Converts the Alef characters into an equivalent
+ * LamAlef location in the 0x06xx Range, this is an
+ * intermediate stage in the operation of the program
+ * later it'll be converted into the 0xFExx LamAlefs
+ * in the shaping function.
+ */
+ private static char changeLamAlef(char ch) {
+ switch(ch) {
+ case '\u0622': return '\u065C';
+ case '\u0623': return '\u065D';
+ case '\u0625': return '\u065E';
+ case '\u0627': return '\u065F';
+ default: return '\u0000'; // not a lamalef
+ }
+ }
+
+ /*
+ * Name : specialChar
+ * Function: Special Arabic characters need special handling in the shapeUnicode
+ * function, this function returns 1 or 2 for these special characters
+ */
+ private static int specialChar(char ch) {
+ if ((ch > '\u0621' && ch < '\u0626') ||
+ (ch == '\u0627') ||
+ (ch > '\u062E' && ch < '\u0633') ||
+ (ch > '\u0647' && ch < '\u064A') ||
+ (ch == '\u0629')) {
+ return 1;
+ } else if (ch >= '\u064B' && ch<= '\u0652') {
+ return 2;
+ } else if (ch >= 0x0653 && ch <= 0x0655 ||
+ ch == 0x0670 ||
+ ch >= 0xFE70 && ch <= 0xFE7F) {
+ return 3;
+ } else {
+ return 0;
+ }
+ }
+
+ /*
+ * Name : getLink
+ * Function: Resolves the link between the characters as
+ * Arabic characters have four forms :
+ * Isolated, Initial, Middle and Final Form
+ */
+ private static int getLink(char ch) {
+ if (ch >= '\u0622' && ch <= '\u06D3') {
+ return araLink[ch - '\u0622'];
+ } else if (ch == '\u200D') {
+ return 3;
+ } else if (ch >= '\u206D' && ch <= '\u206F') {
+ return 4;
+ } else if (ch >= '\uFE70' && ch <= '\uFEFC') {
+ return presLink[ch - '\uFE70'];
+ } else {
+ return 0;
+ }
+ }
+
+ /*
+ * Name : countSpaces
+ * Function: Counts the number of spaces
+ * at each end of the logical buffer
+ */
+ private static int countSpacesLeft(char[] dest,
+ int start,
+ int count) {
+ for (int i = start, e = start + count; i < e; ++i) {
+ if (dest[i] != SPACE_CHAR) {
+ return i - start;
+ }
+ }
+ return count;
+ }
+
+ private static int countSpacesRight(char[] dest,
+ int start,
+ int count) {
+
+ for (int i = start + count; --i >= start;) {
+ if (dest[i] != SPACE_CHAR) {
+ return start + count - 1 - i;
+ }
+ }
+ return count;
+ }
+
+ /*
+ * Name : isTashkeelChar
+ * Function: Returns true for Tashkeel characters else return false
+ */
+ private static boolean isTashkeelChar(char ch) {
+ return ( ch >='\u064B' && ch <= '\u0652' );
+ }
+
+ /*
+ *Name : isSeenTailFamilyChar
+ *Function : returns 1 if the character is a seen family isolated character
+ * in the FE range otherwise returns 0
+ */
+
+ private static int isSeenTailFamilyChar(char ch) {
+ if (ch >= 0xfeb1 && ch < 0xfebf){
+ return tailFamilyIsolatedFinal [ch - 0xFEB1];
+ } else {
+ return 0;
+ }
+ }
+
+ /* Name : isSeenFamilyChar
+ * Function : returns 1 if the character is a seen family character in the Unicode
+ * 06 range otherwise returns 0
+ */
+
+ private static int isSeenFamilyChar(char ch){
+ if (ch >= 0x633 && ch <= 0x636){
+ return 1;
+ }else {
+ return 0;
+ }
+ }
+
+ /*
+ *Name : isTailChar
+ *Function : returns true if the character matches one of the tail characters
+ * (0xfe73 or 0x200b) otherwise returns false
+ */
+
+ private static boolean isTailChar(char ch) {
+ if(ch == OLD_TAIL_CHAR || ch == NEW_TAIL_CHAR){
+ return true;
+ }else{
+ return false;
+ }
+ }
+
+ /*
+ *Name : isAlefMaksouraChar
+ *Function : returns true if the character is a Alef Maksoura Final or isolated
+ * otherwise returns false
+ */
+ private static boolean isAlefMaksouraChar(char ch) {
+ return ( (ch == 0xFEEF) || ( ch == 0xFEF0) || (ch == 0x0649));
+ }
+
+ /*
+ * Name : isYehHamzaChar
+ * Function : returns true if the character is a yehHamza isolated or yehhamza
+ * final is found otherwise returns false
+ */
+ private static boolean isYehHamzaChar(char ch) {
+ if((ch==0xFE89)||(ch==0xFE8A)){
+ return true;
+ }else{
+ return false;
+ }
+ }
+
+ /*
+ *Name : isTashkeelCharFE
+ *Function : Returns true for Tashkeel characters in FE range else return false
+ */
+
+ private static boolean isTashkeelCharFE(char ch) {
+ return ( ch!=0xFE75 &&(ch>=0xFE70 && ch<= 0xFE7F) );
+ }
+
+ /*
+ * Name: isTashkeelOnTatweelChar
+ * Function: Checks if the Tashkeel Character is on Tatweel or not,if the
+ * Tashkeel on tatweel (FE range), it returns 1 else if the
+ * Tashkeel with shadda on tatweel (FC range)return 2 otherwise
+ * returns 0
+ */
+ private static int isTashkeelOnTatweelChar(char ch){
+ if (ch >= 0xfe70 && ch <= 0xfe7f && ch != NEW_TAIL_CHAR && ch != 0xFE75 && ch != SHADDA_TATWEEL_CHAR)
+ {
+ return tashkeelMedial [ch - 0xFE70];
+ } else if( (ch >= 0xfcf2 && ch <= 0xfcf4) || (ch == SHADDA_TATWEEL_CHAR)) {
+ return 2;
+ } else {
+ return 0;
+ }
+ }
+
+ /*
+ * Name: isIsolatedTashkeelChar
+ * Function: Checks if the Tashkeel Character is in the isolated form
+ * (i.e. Unicode FE range) returns 1 else if the Tashkeel
+ * with shadda is in the isolated form (i.e. Unicode FC range)
+ * returns 1 otherwise returns 0
+ */
+ private static int isIsolatedTashkeelChar(char ch){
+ if (ch >= 0xfe70 && ch <= 0xfe7f && ch != NEW_TAIL_CHAR && ch != 0xFE75){
+ return (1 - tashkeelMedial [ch - 0xFE70]);
+ } else if(ch >= 0xfc5e && ch <= 0xfc63){
+ return 1;
+ } else{
+ return 0;
+ }
+ }
+
+ /*
+ * Name : isAlefChar
+ * Function: Returns 1 for Alef characters else return 0
+ */
+ private static boolean isAlefChar(char ch) {
+ return ch == '\u0622' || ch == '\u0623' || ch == '\u0625' || ch == '\u0627';
+ }
+
+ /*
+ * Name : isLamAlefChar
+ * Function: Returns true for LamAlef characters else return false
+ */
+ private static boolean isLamAlefChar(char ch) {
+ return ch >= '\uFEF5' && ch <= '\uFEFC';
+ }
+
+ private static boolean isNormalizedLamAlefChar(char ch) {
+ return ch >= '\u065C' && ch <= '\u065F';
+ }
+
+ /*
+ * Name : calculateSize
+ * Function: This function calculates the destSize to be used in preflighting
+ * when the destSize is equal to 0
+ */
+ private int calculateSize(char[] source,
+ int sourceStart,
+ int sourceLength) {
+
+ int destSize = sourceLength;
+
+ switch (options & LETTERS_MASK) {
+ case LETTERS_SHAPE:
+ case LETTERS_SHAPE_TASHKEEL_ISOLATED:
+ if (isLogical) {
+ for (int i = sourceStart, e = sourceStart + sourceLength - 1; i < e; ++i) {
+ if ((source[i] == LAM_CHAR && isAlefChar(source[i+1])) || isTashkeelCharFE(source[i])){
+ --destSize;
+ }
+ }
+ } else { // visual
+ for(int i = sourceStart + 1, e = sourceStart + sourceLength; i < e; ++i) {
+ if ((source[i] == LAM_CHAR && isAlefChar(source[i-1])) || isTashkeelCharFE(source[i])) {
+ --destSize;
+ }
+ }
+ }
+ break;
+
+ case LETTERS_UNSHAPE:
+ for(int i = sourceStart, e = sourceStart + sourceLength; i < e; ++i) {
+ if (isLamAlefChar(source[i])) {
+ destSize++;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return destSize;
+ }
+
+
+ /*
+ * Name : countSpaceSub
+ * Function: Counts number of times the subChar appears in the array
+ */
+ public static int countSpaceSub(char [] dest,int length, char subChar){
+ int i = 0;
+ int count = 0;
+ while (i < length) {
+ if (dest[i] == subChar) {
+ count++;
+ }
+ i++;
+ }
+ return count;
+ }
+
+ /*
+ * Name : shiftArray
+ * Function: Shifts characters to replace space sub characters
+ */
+ public static void shiftArray(char [] dest,int start, int e, char subChar){
+ int w = e;
+ int r = e;
+ while (--r >= start) {
+ char ch = dest[r];
+ if (ch != subChar) {
+ --w;
+ if (w != r) {
+ dest[w] = ch;
+ }
+ }
+ }
+ }
+
+ /*
+ * Name : flipArray
+ * Function: inverts array, so that start becomes end and vice versa
+ */
+ public static int flipArray(char [] dest, int start, int e, int w){
+ int r;
+ if (w > start) {
+ // shift, assume small buffer size so don't use arraycopy
+ r = w;
+ w = start;
+ while (r < e) {
+ dest[w++] = dest[r++];
+ }
+ } else {
+ w = e;
+ }
+ return w;
+ }
+
+ /*
+ * Name : handleTashkeelWithTatweel
+ * Function : Replaces Tashkeel as following:
+ * Case 1 :if the Tashkeel on tatweel, replace it with Tatweel.
+ * Case 2 :if the Tashkeel aggregated with Shadda on Tatweel, replace
+ * it with Shadda on Tatweel.
+ * Case 3: if the Tashkeel is isolated replace it with Space.
+ *
+ */
+ private static int handleTashkeelWithTatweel(char[] dest, int sourceLength) {
+ int i;
+ for(i = 0; i < sourceLength; i++){
+ if((isTashkeelOnTatweelChar(dest[i]) == 1)){
+ dest[i] = TATWEEL_CHAR;
+ }else if((isTashkeelOnTatweelChar(dest[i]) == 2)){
+ dest[i] = SHADDA_TATWEEL_CHAR;
+ }else if((isIsolatedTashkeelChar(dest[i])==1) && dest[i] != SHADDA_CHAR){
+ dest[i] = SPACE_CHAR;
+ }
+ }
+ return sourceLength;
+ }
+
+ /*
+ *Name : handleGeneratedSpaces
+ *Function : The shapeUnicode function converts Lam + Alef into LamAlef + space,
+ * and Tashkeel to space.
+ * handleGeneratedSpaces function puts these generated spaces
+ * according to the options the user specifies. LamAlef and Tashkeel
+ * spaces can be replaced at begin, at end, at near or decrease the
+ * buffer size.
+ *
+ * There is also Auto option for LamAlef and tashkeel, which will put
+ * the spaces at end of the buffer (or end of text if the user used
+ * the option SPACES_RELATIVE_TO_TEXT_BEGIN_END).
+ *
+ * If the text type was visual_LTR and the option
+ * SPACES_RELATIVE_TO_TEXT_BEGIN_END was selected the END
+ * option will place the space at the beginning of the buffer and
+ * BEGIN will place the space at the end of the buffer.
+ */
+ private int handleGeneratedSpaces(char[] dest,
+ int start,
+ int length) {
+
+ int lenOptionsLamAlef = options & LAMALEF_MASK;
+ int lenOptionsTashkeel = options & TASHKEEL_MASK;
+ boolean lamAlefOn = false;
+ boolean tashkeelOn = false;
+
+ if (!isLogical & !spacesRelativeToTextBeginEnd) {
+ switch (lenOptionsLamAlef) {
+ case LAMALEF_BEGIN: lenOptionsLamAlef = LAMALEF_END; break;
+ case LAMALEF_END: lenOptionsLamAlef = LAMALEF_BEGIN; break;
+ default: break;
+ }
+ switch (lenOptionsTashkeel){
+ case TASHKEEL_BEGIN: lenOptionsTashkeel = TASHKEEL_END; break;
+ case TASHKEEL_END: lenOptionsTashkeel = TASHKEEL_BEGIN; break;
+ default: break;
+ }
+ }
+
+
+ if (lenOptionsLamAlef == LAMALEF_NEAR) {
+ for (int i = start, e = i + length; i < e; ++i) {
+ if (dest[i] == LAMALEF_SPACE_SUB) {
+ dest[i] = SPACE_CHAR_FOR_LAMALEF;
+ }
+ }
+
+ } else {
+
+ final int e = start + length;
+ int wL = countSpaceSub(dest, length, LAMALEF_SPACE_SUB);
+ int wT = countSpaceSub(dest, length, TASHKEEL_SPACE_SUB);
+
+ if (lenOptionsLamAlef == LAMALEF_END){
+ lamAlefOn = true;
+ }
+ if (lenOptionsTashkeel == TASHKEEL_END){
+ tashkeelOn = true;
+ }
+
+
+ if (lamAlefOn && (lenOptionsLamAlef == LAMALEF_END)) {
+ shiftArray(dest, start, e, LAMALEF_SPACE_SUB);
+ while (wL > start) {
+ dest[--wL] = SPACE_CHAR;
+ }
+ }
+
+ if (tashkeelOn && (lenOptionsTashkeel == TASHKEEL_END)){
+ shiftArray(dest, start, e, TASHKEEL_SPACE_SUB);
+ while (wT > start) {
+ dest[--wT] = SPACE_CHAR;
+ }
+ }
+
+ lamAlefOn = false;
+ tashkeelOn = false;
+
+ if (lenOptionsLamAlef == LAMALEF_RESIZE){
+ lamAlefOn = true;
+ }
+ if (lenOptionsTashkeel == TASHKEEL_RESIZE){
+ tashkeelOn = true;
+ }
+
+ if (lamAlefOn && (lenOptionsLamAlef == LAMALEF_RESIZE)){
+ shiftArray(dest, start, e, LAMALEF_SPACE_SUB);
+ wL = flipArray(dest,start,e, wL);
+ length = wL - start;
+ }
+ if (tashkeelOn && (lenOptionsTashkeel == TASHKEEL_RESIZE)) {
+ shiftArray(dest, start, e, TASHKEEL_SPACE_SUB);
+ wT = flipArray(dest,start,e, wT);
+ length = wT - start;
+ }
+
+ lamAlefOn = false;
+ tashkeelOn = false;
+
+ if ((lenOptionsLamAlef == LAMALEF_BEGIN) ||
+ (lenOptionsLamAlef == LAMALEF_AUTO)){
+ lamAlefOn = true;
+ }
+ if (lenOptionsTashkeel == TASHKEEL_BEGIN){
+ tashkeelOn = true;
+ }
+
+ if (lamAlefOn && ((lenOptionsLamAlef == LAMALEF_BEGIN)||
+ (lenOptionsLamAlef == LAMALEF_AUTO))) { // spaces at beginning
+ shiftArray(dest, start, e, LAMALEF_SPACE_SUB);
+ wL = flipArray(dest,start,e, wL);
+ while (wL < e) {
+ dest[wL++] = SPACE_CHAR;
+ }
+ }
+ if(tashkeelOn && (lenOptionsTashkeel == TASHKEEL_BEGIN)){
+ shiftArray(dest, start, e, TASHKEEL_SPACE_SUB);
+ wT = flipArray(dest,start,e, wT);
+ while (wT < e) {
+ dest[wT++] = SPACE_CHAR;
+ }
+ }
+ }
+
+ return length;
+ }
+
+
+ /*
+ *Name :expandCompositCharAtBegin
+ *Function :Expands the LamAlef character to Lam and Alef consuming the required
+ * space from beginning of the buffer. If the text type was visual_LTR
+ * and the option SPACES_RELATIVE_TO_TEXT_BEGIN_END was selected
+ * the spaces will be located at end of buffer.
+ * If there are no spaces to expand the LamAlef, an exception is thrown.
+*/
+ private boolean expandCompositCharAtBegin(char[] dest,int start, int length,
+ int lacount) {
+ boolean spaceNotFound = false;
+
+ if (lacount > countSpacesRight(dest, start, length)) {
+ spaceNotFound = true;
+ return spaceNotFound;
+ }
+ for (int r = start + length - lacount, w = start + length; --r >= start;) {
+ char ch = dest[r];
+ if (isNormalizedLamAlefChar(ch)) {
+ dest[--w] = LAM_CHAR;
+ dest[--w] = convertNormalizedLamAlef[ch - '\u065C'];
+ } else {
+ dest[--w] = ch;
+ }
+ }
+ return spaceNotFound;
+
+ }
+
+ /*
+ *Name : expandCompositCharAtEnd
+ *Function : Expands the LamAlef character to Lam and Alef consuming the
+ * required space from end of the buffer. If the text type was
+ * Visual LTR and the option SPACES_RELATIVE_TO_TEXT_BEGIN_END
+ * was used, the spaces will be consumed from begin of buffer. If
+ * there are no spaces to expand the LamAlef, an exception is thrown.
+ */
+
+ private boolean expandCompositCharAtEnd(char[] dest,int start, int length,
+ int lacount){
+ boolean spaceNotFound = false;
+
+ if (lacount > countSpacesLeft(dest, start, length)) {
+ spaceNotFound = true;
+ return spaceNotFound;
+ }
+ for (int r = start + lacount, w = start, e = start + length; r < e; ++r) {
+ char ch = dest[r];
+ if (isNormalizedLamAlefChar(ch)) {
+ dest[w++] = convertNormalizedLamAlef[ch - '\u065C'];
+ dest[w++] = LAM_CHAR;
+ } else {
+ dest[w++] = ch;
+ }
+ }
+ return spaceNotFound;
+ }
+
+ /*
+ *Name : expandCompositCharAtNear
+ *Function : Expands the LamAlef character into Lam + Alef, YehHamza character
+ * into Yeh + Hamza, SeenFamily character into SeenFamily character
+ * + Tail, while consuming the space next to the character.
+ */
+
+ private boolean expandCompositCharAtNear(char[] dest,int start, int length,
+ int yehHamzaOption, int seenTailOption, int lamAlefOption){
+
+ boolean spaceNotFound = false;
+
+
+
+ if (isNormalizedLamAlefChar(dest[start])) {
+ spaceNotFound = true;
+ return spaceNotFound;
+ }
+ for (int i = start + length; --i >=start;) {
+ char ch = dest[i];
+ if (lamAlefOption == 1 && isNormalizedLamAlefChar(ch)) {
+ if (i>start &&dest[i-1] == SPACE_CHAR) {
+ dest[i] = LAM_CHAR;
+ dest[--i] = convertNormalizedLamAlef[ch - '\u065C'];
+ } else {
+ spaceNotFound = true;
+ return spaceNotFound;
+ }
+ }else if(seenTailOption == 1 && isSeenTailFamilyChar(ch) == 1){
+ if(i>start &&dest[i-1] == SPACE_CHAR){
+ dest[i-1] = tailChar;
+ } else{
+ spaceNotFound = true;
+ return spaceNotFound;
+ }
+ }else if(yehHamzaOption == 1 && isYehHamzaChar(ch)){
+
+ if(i>start &&dest[i-1] == SPACE_CHAR){
+ dest[i] = yehHamzaToYeh[ch - YEH_HAMZAFE_CHAR];
+ dest[i-1] = HAMZAFE_CHAR;
+ }else{
+ spaceNotFound = true;
+ return spaceNotFound;
+ }
+
+
+ }
+ }
+ return false;
+
+ }
+
+ /*
+ * Name : expandCompositChar
+ * Function: LamAlef needs special handling as the LamAlef is
+ * one character while expanding it will give two
+ * characters Lam + Alef, so we need to expand the LamAlef
+ * in near or far spaces according to the options the user
+ * specifies or increase the buffer size.
+ * Dest has enough room for the expansion if we are growing.
+ * lamalef are normalized to the 'special characters'
+ */
+ private int expandCompositChar(char[] dest,
+ int start,
+ int length,
+ int lacount,
+ int shapingMode) throws ArabicShapingException {
+
+ int lenOptionsLamAlef = options & LAMALEF_MASK;
+ int lenOptionsSeen = options & SEEN_MASK;
+ int lenOptionsYehHamza = options & YEHHAMZA_MASK;
+ boolean spaceNotFound = false;
+
+ if (!isLogical && !spacesRelativeToTextBeginEnd) {
+ switch (lenOptionsLamAlef) {
+ case LAMALEF_BEGIN: lenOptionsLamAlef = LAMALEF_END; break;
+ case LAMALEF_END: lenOptionsLamAlef = LAMALEF_BEGIN; break;
+ default: break;
+ }
+ }
+
+ if(shapingMode == 1){
+ if(lenOptionsLamAlef == LAMALEF_AUTO){
+ if(isLogical){
+ spaceNotFound = expandCompositCharAtEnd(dest, start, length, lacount);
+ if(spaceNotFound){
+ spaceNotFound = expandCompositCharAtBegin(dest, start, length, lacount);
+ }
+ if(spaceNotFound){
+ spaceNotFound = expandCompositCharAtNear(dest, start, length,0,0,1);
+ }
+ if(spaceNotFound){
+ throw new ArabicShapingException("No spacefor lamalef");
+ }
+ }else{
+ spaceNotFound = expandCompositCharAtBegin(dest, start, length, lacount);
+ if(spaceNotFound){
+ spaceNotFound = expandCompositCharAtEnd(dest, start, length, lacount);
+ }
+ if(spaceNotFound){
+ spaceNotFound = expandCompositCharAtNear(dest, start, length,0,0,1);
+ }
+ if(spaceNotFound){
+ throw new ArabicShapingException("No spacefor lamalef");
+ }
+ }
+ }else if(lenOptionsLamAlef == LAMALEF_END){
+ spaceNotFound = expandCompositCharAtEnd(dest, start, length, lacount);
+ if(spaceNotFound){
+ throw new ArabicShapingException("No spacefor lamalef");
+ }
+ }else if(lenOptionsLamAlef == LAMALEF_BEGIN){
+ spaceNotFound = expandCompositCharAtBegin(dest, start, length, lacount);
+ if(spaceNotFound){
+ throw new ArabicShapingException("No spacefor lamalef");
+ }
+ }else if(lenOptionsLamAlef == LAMALEF_NEAR){
+ spaceNotFound = expandCompositCharAtNear(dest, start, length,0,0,1);
+ if(spaceNotFound){
+ throw new ArabicShapingException("No spacefor lamalef");
+ }
+ }else if(lenOptionsLamAlef == LAMALEF_RESIZE){
+ for (int r = start + length, w = r + lacount; --r >= start;) {
+ char ch = dest[r];
+ if (isNormalizedLamAlefChar(ch)) {
+ dest[--w] = '\u0644';
+ dest[--w] = convertNormalizedLamAlef[ch - '\u065C'];
+ } else {
+ dest[--w] = ch;
+ }
+ }
+ length += lacount;
+ }
+ }else{
+ if(lenOptionsSeen == SEEN_TWOCELL_NEAR){
+ spaceNotFound = expandCompositCharAtNear(dest, start, length,0,1,0);
+ if(spaceNotFound){
+ throw new ArabicShapingException("No space for Seen tail expansion");
+ }
+ }
+ if(lenOptionsYehHamza == YEHHAMZA_TWOCELL_NEAR){
+ spaceNotFound = expandCompositCharAtNear(dest, start, length,1,0,0);
+ if(spaceNotFound){
+ throw new ArabicShapingException("No space for YehHamza expansion");
+ }
+ }
+ }
+ return length;
+ }
+
+
+ /* Convert the input buffer from FExx Range into 06xx Range
+ * to put all characters into the 06xx range
+ * even the lamalef is converted to the special region in
+ * the 06xx range. Return the number of lamalef chars found.
+ */
+ private int normalize(char[] dest, int start, int length) {
+ int lacount = 0;
+ for (int i = start, e = i + length; i < e; ++i) {
+ char ch = dest[i];
+ if (ch >= '\uFE70' && ch <= '\uFEFC') {
+ if (isLamAlefChar(ch)) {
+ ++lacount;
+ }
+ dest[i] = (char)convertFEto06[ch - '\uFE70'];
+ }
+ }
+ return lacount;
+ }
+
+ /*
+ * Name : deshapeNormalize
+ * Function: Convert the input buffer from FExx Range into 06xx Range
+ * even the lamalef is converted to the special region in the 06xx range.
+ * According to the options the user enters, all seen family characters
+ * followed by a tail character are merged to seen tail family character and
+ * any yeh followed by a hamza character are merged to yehhamza character.
+ * Method returns the number of lamalef chars found.
+ */
+ private int deshapeNormalize(char[] dest, int start, int length) {
+ int lacount = 0;
+ int yehHamzaComposeEnabled = 0;
+ int seenComposeEnabled = 0;
+
+ yehHamzaComposeEnabled = ((options&YEHHAMZA_MASK) == YEHHAMZA_TWOCELL_NEAR) ? 1 : 0;
+ seenComposeEnabled = ((options&SEEN_MASK) == SEEN_TWOCELL_NEAR)? 1 : 0;
+
+ for (int i = start, e = i + length; i < e; ++i) {
+ char ch = dest[i];
+
+ if( (yehHamzaComposeEnabled == 1) && ((ch == HAMZA06_CHAR) || (ch == HAMZAFE_CHAR))
+ && (i < (length - 1)) && isAlefMaksouraChar(dest[i+1] )) {
+ dest[i] = SPACE_CHAR;
+ dest[i+1] = YEH_HAMZA_CHAR;
+ } else if ( (seenComposeEnabled == 1) && (isTailChar(ch)) && (i< (length - 1))
+ && (isSeenTailFamilyChar(dest[i+1])==1) ) {
+ dest[i] = SPACE_CHAR;
+ }
+ else if (ch >= '\uFE70' && ch <= '\uFEFC') {
+ if (isLamAlefChar(ch)) {
+ ++lacount;
+ }
+ dest[i] = (char)convertFEto06[ch - '\uFE70'];
+ }
+ }
+ return lacount;
+ }
+
+ /*
+ * Name : shapeUnicode
+ * Function: Converts an Arabic Unicode buffer in 06xx Range into a shaped
+ * arabic Unicode buffer in FExx Range
+ */
+ private int shapeUnicode(char[] dest,
+ int start,
+ int length,
+ int destSize,
+ int tashkeelFlag)throws ArabicShapingException {
+
+ int lamalef_count = normalize(dest, start, length);
+
+ // resolve the link between the characters.
+ // Arabic characters have four forms: Isolated, Initial, Medial and Final.
+ // Tashkeel characters have two, isolated or medial, and sometimes only isolated.
+ // tashkeelFlag == 0: shape normally, 1: shape isolated, 2: don't shape
+
+ boolean lamalef_found = false, seenfam_found = false;
+ boolean yehhamza_found = false, tashkeel_found = false;
+ int i = start + length - 1;
+ int currLink = getLink(dest[i]);
+ int nextLink = 0;
+ int prevLink = 0;
+ int lastLink = 0;
+ //int prevPos = i;
+ int lastPos = i;
+ int nx = -2;
+ int nw = 0;
+
+ while (i >= 0) {
+ // If high byte of currLink > 0 then there might be more than one shape
+ if ((currLink & '\uFF00') > 0 || isTashkeelChar(dest[i])) {
+ nw = i - 1;
+ nx = -2;
+ while (nx < 0) { // we need to know about next char
+ if (nw == -1) {
+ nextLink = 0;
+ nx = Integer.MAX_VALUE;
+ } else {
+ nextLink = getLink(dest[nw]);
+ if ((nextLink & IRRELEVANT) == 0) {
+ nx = nw;
+ } else {
+ --nw;
+ }
+ }
+ }
+
+ if (((currLink & ALEFTYPE) > 0) && ((lastLink & LAMTYPE) > 0)) {
+ lamalef_found = true;
+ char wLamalef = changeLamAlef(dest[i]); // get from 0x065C-0x065f
+ if (wLamalef != '\u0000') {
+ // replace alef by marker, it will be removed later
+ dest[i] = '\uffff';
+ dest[lastPos] = wLamalef;
+ i = lastPos;
+ }
+
+ lastLink = prevLink;
+ currLink = getLink(wLamalef); // requires '\u0000', unfortunately
+ }
+ if ((i > 0) && (dest[i-1] == SPACE_CHAR))
+ {
+ if ( isSeenFamilyChar(dest[i]) == 1){
+ seenfam_found = true;
+ } else if (dest[i] == YEH_HAMZA_CHAR) {
+ yehhamza_found = true;
+ }
+ }
+ else if(i==0){
+ if ( isSeenFamilyChar(dest[i]) == 1){
+ seenfam_found = true;
+ } else if (dest[i] == YEH_HAMZA_CHAR) {
+ yehhamza_found = true;
+ }
+ }
+
+
+ // get the proper shape according to link ability of neighbors
+ // and of character; depends on the order of the shapes
+ // (isolated, initial, middle, final) in the compatibility area
+
+ int flag = specialChar(dest[i]);
+
+ int shape = shapeTable[nextLink & LINK_MASK]
+ [lastLink & LINK_MASK]
+ [currLink & LINK_MASK];
+
+ if (flag == 1) {
+ shape &= 0x1;
+ } else if (flag == 2) {
+ if (tashkeelFlag == 0 &&
+ ((lastLink & LINKL) != 0) &&
+ ((nextLink & LINKR) != 0) &&
+ dest[i] != '\u064C' &&
+ dest[i] != '\u064D' &&
+ !((nextLink & ALEFTYPE) == ALEFTYPE &&
+ (lastLink & LAMTYPE) == LAMTYPE)) {
+
+ shape = 1;
+ } else {
+ shape = 0;
+ }
+ }
+ if (flag == 2) {
+ if (tashkeelFlag == 2) {
+ dest[i] = TASHKEEL_SPACE_SUB;
+ tashkeel_found = true;
+ }
+ else{
+ dest[i] = (char)('\uFE70' + irrelevantPos[dest[i] - '\u064B'] + shape);
+ }
+ // else leave tashkeel alone
+ } else {
+ dest[i] = (char)('\uFE70' + (currLink >> 8) + shape);
+ }
+ }
+
+ // move one notch forward
+ if ((currLink & IRRELEVANT) == 0) {
+ prevLink = lastLink;
+ lastLink = currLink;
+ //prevPos = lastPos;
+ lastPos = i;
+ }
+
+ --i;
+ if (i == nx) {
+ currLink = nextLink;
+ nx = -2;
+ } else if (i != -1) {
+ currLink = getLink(dest[i]);
+ }
+ }
+
+ // If we found a lam/alef pair in the buffer
+ // call handleGeneratedSpaces to remove the spaces that were added
+
+ destSize = length;
+ if (lamalef_found || tashkeel_found) {
+ destSize = handleGeneratedSpaces(dest, start, length);
+ }
+ if (seenfam_found || yehhamza_found){
+ destSize = expandCompositChar(dest, start, destSize, lamalef_count, SHAPE_MODE);
+ }
+ return destSize;
+ }
+
+ /*
+ * Name : deShapeUnicode
+ * Function: Converts an Arabic Unicode buffer in FExx Range into unshaped
+ * arabic Unicode buffer in 06xx Range
+ */
+ private int deShapeUnicode(char[] dest,
+ int start,
+ int length,
+ int destSize) throws ArabicShapingException {
+
+ int lamalef_count = deshapeNormalize(dest, start, length);
+
+ // If there was a lamalef in the buffer call expandLamAlef
+ if (lamalef_count != 0) {
+ // need to adjust dest to fit expanded buffer... !!!
+ destSize = expandCompositChar(dest, start, length, lamalef_count,DESHAPE_MODE);
+ } else {
+ destSize = length;
+ }
+
+ return destSize;
+ }
+
+ private int internalShape(char[] source,
+ int sourceStart,
+ int sourceLength,
+ char[] dest,
+ int destStart,
+ int destSize) throws ArabicShapingException {
+
+ if (sourceLength == 0) {
+ return 0;
+ }
+
+ if (destSize == 0) {
+ if (((options & LETTERS_MASK) != LETTERS_NOOP) &&
+ ((options & LAMALEF_MASK) == LAMALEF_RESIZE)) {
+
+ return calculateSize(source, sourceStart, sourceLength);
+ } else {
+ return sourceLength; // by definition
+ }
+ }
+
+ // always use temp buffer
+ char[] temp = new char[sourceLength * 2]; // all lamalefs requiring expansion
+ System.arraycopy(source, sourceStart, temp, 0, sourceLength);
+
+ if (isLogical) {
+ invertBuffer(temp, 0, sourceLength);
+ }
+
+ int outputSize = sourceLength;
+
+ switch (options & LETTERS_MASK) {
+ case LETTERS_SHAPE_TASHKEEL_ISOLATED:
+ outputSize = shapeUnicode(temp, 0, sourceLength, destSize, 1);
+ break;
+
+ case LETTERS_SHAPE:
+ if( ((options&TASHKEEL_MASK)> 0) &&
+ ((options&TASHKEEL_MASK) !=TASHKEEL_REPLACE_BY_TATWEEL)) {
+ /* Call the shaping function with tashkeel flag == 2 for removal of tashkeel */
+ outputSize = shapeUnicode(temp, 0, sourceLength, destSize, 2);
+ }else {
+ //default Call the shaping function with tashkeel flag == 1 */
+ outputSize = shapeUnicode(temp, 0, sourceLength, destSize, 0);
+
+ /*After shaping text check if user wants to remove tashkeel and replace it with tatweel*/
+ if( (options&TASHKEEL_MASK) == TASHKEEL_REPLACE_BY_TATWEEL){
+ outputSize = handleTashkeelWithTatweel(temp,sourceLength);
+ }
+ }
+ break;
+
+ case LETTERS_UNSHAPE:
+ outputSize = deShapeUnicode(temp, 0, sourceLength, destSize);
+ break;
+
+ default:
+ break;
+ }
+
+ if (outputSize > destSize) {
+ throw new ArabicShapingException("not enough room for result data");
+ }
+
+ if ((options & DIGITS_MASK) != DIGITS_NOOP) {
+ char digitBase = '\u0030'; // European digits
+ switch (options & DIGIT_TYPE_MASK) {
+ case DIGIT_TYPE_AN:
+ digitBase = '\u0660'; // Arabic-Indic digits
+ break;
+
+ case DIGIT_TYPE_AN_EXTENDED:
+ digitBase = '\u06f0'; // Eastern Arabic-Indic digits (Persian and Urdu)
+ break;
+
+ default:
+ break;
+ }
+
+ switch (options & DIGITS_MASK) {
+ case DIGITS_EN2AN:
+ {
+ int digitDelta = digitBase - '\u0030';
+ for (int i = 0; i < outputSize; ++i) {
+ char ch = temp[i];
+ if (ch <= '\u0039' && ch >= '\u0030') {
+ temp[i] += digitDelta;
+ }
+ }
+ }
+ break;
+
+ case DIGITS_AN2EN:
+ {
+ char digitTop = (char)(digitBase + 9);
+ int digitDelta = '\u0030' - digitBase;
+ for (int i = 0; i < outputSize; ++i) {
+ char ch = temp[i];
+ if (ch <= digitTop && ch >= digitBase) {
+ temp[i] += digitDelta;
+ }
+ }
+ }
+ break;
+
+ case DIGITS_EN2AN_INIT_LR:
+ shapeToArabicDigitsWithContext(temp, 0, outputSize, digitBase, false);
+ break;
+
+ case DIGITS_EN2AN_INIT_AL:
+ shapeToArabicDigitsWithContext(temp, 0, outputSize, digitBase, true);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (isLogical) {
+ invertBuffer(temp, 0, outputSize);
+ }
+
+ System.arraycopy(temp, 0, dest, destStart, outputSize);
+
+ return outputSize;
+ }
+
+ private static class ArabicShapingException extends RuntimeException {
+ ArabicShapingException(String msg) {
+ super(msg);
+ }
+ }
+}
diff --git a/icu4j/license.html b/icu4j/license.html
new file mode 100644
index 0000000..b905ddf
--- /dev/null
+++ b/icu4j/license.html
@@ -0,0 +1,51 @@
+<html>
+
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=us-ascii"></meta>
+<title>ICU License - ICU 1.8.1 and later</title>
+</head>
+
+<body BGCOLOR="#ffffff">
+<h2>ICU License - ICU 1.8.1 and later</h2>
+
+<p>COPYRIGHT AND PERMISSION NOTICE</p>
+
+<p>
+Copyright (c) 1995-2006 International Business Machines Corporation and others
+</p>
+<p>
+All rights reserved.
+</p>
+<p>
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, and/or sell
+copies of the Software, and to permit persons
+to whom the Software is furnished to do so, provided that the above
+copyright notice(s) and this permission notice appear in all copies
+of the Software and that both the above copyright notice(s) and this
+permission notice appear in supporting documentation.
+</p>
+<p>
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL
+THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM,
+OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER
+RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
+USE OR PERFORMANCE OF THIS SOFTWARE.
+</p>
+<p>
+Except as contained in this notice, the name of a copyright holder shall not be
+used in advertising or otherwise to promote the sale, use or other dealings in
+this Software without prior written authorization of the copyright holder.
+</p>
+
+<hr>
+<p><small>
+All trademarks and registered trademarks mentioned herein are the property of their respective owners.
+</small></p>
+</body>
+</html>
diff --git a/core/jni/CursorWindow.h b/include/binder/CursorWindow.h
similarity index 96%
rename from core/jni/CursorWindow.h
rename to include/binder/CursorWindow.h
index 3fcb560..4fbff2a 100644
--- a/core/jni/CursorWindow.h
+++ b/include/binder/CursorWindow.h
@@ -1,16 +1,16 @@
/*
* Copyright (C) 2006 The Android Open Source Project
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * 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
+ * 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
+ * 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.
*/
@@ -24,8 +24,6 @@
#include <binder/IMemory.h>
#include <utils/RefBase.h>
-#include <jni.h>
-
#define DEFAULT_WINDOW_SIZE 4096
#define MAX_WINDOW_SIZE (1024 * 1024)
#define WINDOW_ALLOCATION_SIZE 4096
@@ -82,11 +80,11 @@
} data;
} __attribute__((packed)) field_slot_t;
+#define FIELD_TYPE_NULL 0
#define FIELD_TYPE_INTEGER 1
#define FIELD_TYPE_FLOAT 2
#define FIELD_TYPE_STRING 3
#define FIELD_TYPE_BLOB 4
-#define FIELD_TYPE_NULL 5
/**
* This class stores a set of rows from a database in a buffer. The begining of the
@@ -172,7 +170,7 @@
row_slot_t * allocRowSlot();
row_slot_t * getRowSlot(int row);
-
+
/**
* return NULL if Failed to find rowSlot or
* Invalid rowSlot
diff --git a/libs/audioflinger/AudioPolicyManagerBase.cpp b/libs/audioflinger/AudioPolicyManagerBase.cpp
index 381a958..549d661 100644
--- a/libs/audioflinger/AudioPolicyManagerBase.cpp
+++ b/libs/audioflinger/AudioPolicyManagerBase.cpp
@@ -902,7 +902,8 @@
#ifdef AUDIO_POLICY_TEST
Thread(false),
#endif //AUDIO_POLICY_TEST
- mPhoneState(AudioSystem::MODE_NORMAL), mRingerMode(0), mMusicStopTime(0), mLimitRingtoneVolume(false)
+ mPhoneState(AudioSystem::MODE_NORMAL), mRingerMode(0), mMusicStopTime(0), mLimitRingtoneVolume(false),
+ mLastVoiceVolume(-1.0f)
{
mpClientInterface = clientInterface;
@@ -1713,29 +1714,38 @@
}
float volume = computeVolume(stream, index, output, device);
- // do not set volume if the float value did not change
- if (volume != mOutputs.valueFor(output)->mCurVolume[stream] || force) {
+ // We actually change the volume if:
+ // - the float value returned by computeVolume() changed
+ // - the force flag is set
+ if (volume != mOutputs.valueFor(output)->mCurVolume[stream] ||
+ force) {
mOutputs.valueFor(output)->mCurVolume[stream] = volume;
LOGV("setStreamVolume() for output %d stream %d, volume %f, delay %d", output, stream, volume, delayMs);
if (stream == AudioSystem::VOICE_CALL ||
stream == AudioSystem::DTMF ||
stream == AudioSystem::BLUETOOTH_SCO) {
- float voiceVolume = -1.0;
// offset value to reflect actual hardware volume that never reaches 0
// 1% corresponds roughly to first step in VOICE_CALL stream volume setting (see AudioService.java)
volume = 0.01 + 0.99 * volume;
- if (stream == AudioSystem::VOICE_CALL) {
- voiceVolume = (float)index/(float)mStreams[stream].mIndexMax;
- } else if (stream == AudioSystem::BLUETOOTH_SCO) {
- voiceVolume = 1.0;
- }
- if (voiceVolume >= 0 && output == mHardwareOutput) {
- mpClientInterface->setVoiceVolume(voiceVolume, delayMs);
- }
}
mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, volume, output, delayMs);
}
+ if (stream == AudioSystem::VOICE_CALL ||
+ stream == AudioSystem::BLUETOOTH_SCO) {
+ float voiceVolume;
+ // Force voice volume to max for bluetooth SCO as volume is managed by the headset
+ if (stream == AudioSystem::VOICE_CALL) {
+ voiceVolume = (float)index/(float)mStreams[stream].mIndexMax;
+ } else {
+ voiceVolume = 1.0;
+ }
+ if (voiceVolume != mLastVoiceVolume && output == mHardwareOutput) {
+ mpClientInterface->setVoiceVolume(voiceVolume, delayMs);
+ mLastVoiceVolume = voiceVolume;
+ }
+ }
+
return NO_ERROR;
}
diff --git a/libs/binder/Android.mk b/libs/binder/Android.mk
index 13dc500..f9d9f25 100644
--- a/libs/binder/Android.mk
+++ b/libs/binder/Android.mk
@@ -16,6 +16,7 @@
sources := \
Binder.cpp \
BpBinder.cpp \
+ CursorWindow.cpp \
IInterface.cpp \
IMemory.cpp \
IPCThreadState.cpp \
diff --git a/core/jni/CursorWindow.cpp b/libs/binder/CursorWindow.cpp
similarity index 99%
rename from core/jni/CursorWindow.cpp
rename to libs/binder/CursorWindow.cpp
index 7877921..20b27c9 100644
--- a/core/jni/CursorWindow.cpp
+++ b/libs/binder/CursorWindow.cpp
@@ -18,6 +18,7 @@
#define LOG_TAG "CursorWindow"
#include <utils/Log.h>
+#include <binder/CursorWindow.h>
#include <binder/MemoryHeapBase.h>
#include <binder/MemoryBase.h>
@@ -25,12 +26,6 @@
#include <string.h>
#include <stdlib.h>
-#include <jni.h>
-#include <JNIHelp.h>
-
-#include "CursorWindow.h"
-
-
namespace android {
CursorWindow::CursorWindow(size_t maxSize) :
diff --git a/libs/rs/Android.mk b/libs/rs/Android.mk
index 98464a0..3f01415 100644
--- a/libs/rs/Android.mk
+++ b/libs/rs/Android.mk
@@ -76,34 +76,39 @@
LOCAL_SRC_FILES:= \
rsAdapter.cpp \
rsAllocation.cpp \
+ rsAnimation.cpp \
rsComponent.cpp \
rsContext.cpp \
rsDevice.cpp \
rsElement.cpp \
- rsFileA3D.cpp \
+ rsFileA3D.cpp \
rsLight.cpp \
rsLocklessFifo.cpp \
rsObjectBase.cpp \
rsMatrix.cpp \
- rsMesh.cpp \
- rsNoise.cpp \
+ rsMesh.cpp \
+ rsMutex.cpp \
rsProgram.cpp \
rsProgramFragment.cpp \
- rsProgramFragmentStore.cpp \
+ rsProgramStore.cpp \
rsProgramRaster.cpp \
rsProgramVertex.cpp \
rsSampler.cpp \
rsScript.cpp \
rsScriptC.cpp \
rsScriptC_Lib.cpp \
- rsShaderCache.cpp \
+ rsScriptC_LibCL.cpp \
+ rsScriptC_LibGL.cpp \
+ rsShaderCache.cpp \
+ rsSignal.cpp \
rsSimpleMesh.cpp \
+ rsStream.cpp \
rsThreadIO.cpp \
rsType.cpp \
rsVertexArray.cpp
-LOCAL_SHARED_LIBRARIES += libcutils libutils libEGL libGLESv1_CM libGLESv2 libui libacc
+LOCAL_SHARED_LIBRARIES += libcutils libutils libEGL libGLESv1_CM libGLESv2 libui libbcc
LOCAL_LDLIBS := -lpthread -ldl
LOCAL_MODULE:= libRS
LOCAL_MODULE_TAGS := optional
diff --git a/libs/rs/RenderScript.h b/libs/rs/RenderScript.h
index d280f50..f01eadd 100644
--- a/libs/rs/RenderScript.h
+++ b/libs/rs/RenderScript.h
@@ -30,6 +30,7 @@
typedef void * RsAdapter1D;
typedef void * RsAdapter2D;
typedef void * RsAllocation;
+typedef void * RsAnimation;
typedef void * RsContext;
typedef void * RsDevice;
typedef void * RsElement;
@@ -39,11 +40,12 @@
typedef void * RsSimpleMesh;
typedef void * RsType;
typedef void * RsLight;
+typedef void * RsObjectBase;
typedef void * RsProgram;
typedef void * RsProgramVertex;
typedef void * RsProgramFragment;
-typedef void * RsProgramFragmentStore;
+typedef void * RsProgramStore;
typedef void * RsProgramRaster;
typedef void (* RsBitmapCallback_t)(void *);
@@ -101,19 +103,12 @@
enum RsDataKind {
RS_KIND_USER,
- RS_KIND_COLOR,
- RS_KIND_POSITION,
- RS_KIND_TEXTURE,
- RS_KIND_NORMAL,
- RS_KIND_INDEX,
- RS_KIND_POINT_SIZE,
- RS_KIND_PIXEL_L,
+ RS_KIND_PIXEL_L = 7,
RS_KIND_PIXEL_A,
RS_KIND_PIXEL_LA,
RS_KIND_PIXEL_RGB,
RS_KIND_PIXEL_RGBA,
-
};
enum RsSamplerParam {
@@ -205,9 +200,53 @@
enum RsError {
RS_ERROR_NONE,
RS_ERROR_BAD_SHADER,
- RS_ERROR_BAD_SCRIPT
+ RS_ERROR_BAD_SCRIPT,
+ RS_ERROR_BAD_VALUE,
+ RS_ERROR_OUT_OF_MEMORY
};
+enum RsAnimationInterpolation {
+ RS_ANIMATION_INTERPOLATION_STEP,
+ RS_ANIMATION_INTERPOLATION_LINEAR,
+ RS_ANIMATION_INTERPOLATION_BEZIER,
+ RS_ANIMATION_INTERPOLATION_CARDINAL,
+ RS_ANIMATION_INTERPOLATION_HERMITE,
+ RS_ANIMATION_INTERPOLATION_BSPLINE
+};
+
+enum RsAnimationEdge {
+ RS_ANIMATION_EDGE_UNDEFINED,
+ RS_ANIMATION_EDGE_CONSTANT,
+ RS_ANIMATION_EDGE_GRADIENT,
+ RS_ANIMATION_EDGE_CYCLE,
+ RS_ANIMATION_EDGE_OSCILLATE,
+ RS_ANIMATION_EDGE_CYLE_RELATIVE
+};
+
+enum RsA3DClassID {
+ RS_A3D_CLASS_ID_UNKNOWN,
+ RS_A3D_CLASS_ID_MESH,
+ RS_A3D_CLASS_ID_SIMPLE_MESH,
+ RS_A3D_CLASS_ID_TYPE,
+ RS_A3D_CLASS_ID_ELEMENT,
+ RS_A3D_CLASS_ID_ALLOCATION,
+ RS_A3D_CLASS_ID_PROGRAM_VERTEX,
+ RS_A3D_CLASS_ID_PROGRAM_RASTER,
+ RS_A3D_CLASS_ID_PROGRAM_FRAGMENT,
+ RS_A3D_CLASS_ID_PROGRAM_STORE,
+ RS_A3D_CLASS_ID_SAMPLER,
+ RS_A3D_CLASS_ID_ANIMATION,
+ RS_A3D_CLASS_ID_LIGHT,
+ RS_A3D_CLASS_ID_ADAPTER_1D,
+ RS_A3D_CLASS_ID_ADAPTER_2D,
+ RS_A3D_CLASS_ID_SCRIPT_C
+};
+
+typedef struct {
+ RsA3DClassID classID;
+ const char* objectName;
+} RsFileIndexEntry;
+
#ifndef NO_RS_FUNCS
#include "rsgApiFuncDecl.h"
#endif
diff --git a/libs/rs/RenderScriptEnv.h b/libs/rs/RenderScriptEnv.h
index 99b8c04..144e539 100644
--- a/libs/rs/RenderScriptEnv.h
+++ b/libs/rs/RenderScriptEnv.h
@@ -12,7 +12,7 @@
typedef void * RsSimpleMesh;
typedef void * RsType;
typedef void * RsProgramFragment;
-typedef void * RsProgramFragmentStore;
+typedef void * RsProgramStore;
typedef void * RsLight;
diff --git a/libs/rs/java/Film/src/com/android/film/FilmRS.java b/libs/rs/java/Film/src/com/android/film/FilmRS.java
index 7d04502..93438a0 100644
--- a/libs/rs/java/Film/src/com/android/film/FilmRS.java
+++ b/libs/rs/java/Film/src/com/android/film/FilmRS.java
@@ -213,14 +213,9 @@
Log.e("rs", "Done loading named");
- mStripPositionType = Type.createFromClass(mRS, StripPosition.class, 1);
-
ScriptC.Builder sb = new ScriptC.Builder(mRS);
sb.setScript(mRes, R.raw.filmstrip);
- sb.setRoot(true);
- sb.setType(mStripPositionType, "Pos", 1);
mScriptStrip = sb.create();
- mScriptStrip.setClearColor(0.0f, 0.0f, 0.0f, 1.0f);
mAllocPos = Allocation.createTyped(mRS, mStripPositionType);
diff --git a/libs/rs/java/Fountain/res/raw/fountain.c b/libs/rs/java/Fountain/res/raw/fountain.c
deleted file mode 100644
index 73b819b..0000000
--- a/libs/rs/java/Fountain/res/raw/fountain.c
+++ /dev/null
@@ -1,52 +0,0 @@
-// Fountain test script
-#pragma version(1)
-
-int newPart = 0;
-
-int main(int launchID) {
- int ct;
- int count = Control->count;
- int rate = Control->rate;
- float height = getHeight();
- struct point_s * p = (struct point_s *)point;
-
- if (rate) {
- float rMax = ((float)rate) * 0.005f;
- int x = Control->x;
- int y = Control->y;
- int color = ((int)(Control->r * 255.f)) |
- ((int)(Control->g * 255.f)) << 8 |
- ((int)(Control->b * 255.f)) << 16 |
- (0xf0 << 24);
- struct point_s * np = &p[newPart];
-
- while (rate--) {
- vec2Rand((float *)&np->delta.x, rMax);
- np->position.x = x;
- np->position.y = y;
- np->color = color;
- newPart++;
- np++;
- if (newPart >= count) {
- newPart = 0;
- np = &p[newPart];
- }
- }
- }
-
- for (ct=0; ct < count; ct++) {
- float dy = p->delta.y + 0.15f;
- float posy = p->position.y + dy;
- if ((posy > height) && (dy > 0)) {
- dy *= -0.3f;
- }
- p->delta.y = dy;
- p->position.x += p->delta.x;
- p->position.y = posy;
- p++;
- }
-
- uploadToBufferObject(NAMED_PartBuffer);
- drawSimpleMesh(NAMED_PartMesh);
- return 1;
-}
diff --git a/libs/rs/java/Fountain/res/raw/fountain.rs b/libs/rs/java/Fountain/res/raw/fountain.rs
new file mode 100644
index 0000000..7573398
--- /dev/null
+++ b/libs/rs/java/Fountain/res/raw/fountain.rs
@@ -0,0 +1,77 @@
+// Fountain test script
+#pragma version(1)
+
+#include "../../../../scriptc/rs_types.rsh"
+#include "../../../../scriptc/rs_math.rsh"
+#include "../../../../scriptc/rs_graphics.rsh"
+
+static int newPart = 0;
+
+float4 partColor;
+rs_mesh partMesh;
+
+typedef struct __attribute__((packed, aligned(4))) Point_s {
+ float2 delta;
+ float2 position;
+ uchar4 color;
+} Point_t;
+Point_t *point;
+
+#pragma rs export_var(point, partColor, partMesh)
+
+int root() {
+ rsgClearColor(0.f, 0.f, 0.f, 1.f);
+ float height = rsgGetHeight();
+ rs_allocation alloc = rsGetAllocation(point);
+ int size = rsAllocationGetDimX(alloc);
+
+ Point_t * p = point;
+ for (int ct=0; ct < size; ct++) {
+ p->delta.y += 0.15f;
+ p->position += p->delta;
+ if ((p->position.y > height) && (p->delta.y > 0)) {
+ p->delta.y *= -0.3f;
+ }
+ p++;
+ }
+
+ rsgUploadToBufferObject(alloc);
+ rsgDrawSimpleMesh(partMesh);
+ return 1;
+}
+
+#pragma rs export_func(addParticles)
+
+void addParticles(int rate, int x, int y)
+{
+ //rsDebug("partColor", partColor);
+ //rsDebug("partColor x", partColor.x);
+ //rsDebug("partColor y", partColor.y);
+ //rsDebug("partColor z", partColor.z);
+ //rsDebug("partColor w", partColor.w);
+
+ float rMax = ((float)rate) * 0.005f;
+ int size = rsAllocationGetDimX(rsGetAllocation(point));
+
+ uchar4 c = rsPackColorTo8888(partColor.x, partColor.y, partColor.z);
+
+ //rsDebug("color ", ((int *)&c)[0]);
+ Point_t * np = &point[newPart];
+
+ float2 p = {x, y};
+ while (rate--) {
+ float angle = rsRand(3.14f * 2.f);
+ float len = rsRand(rMax);
+ np->delta.x = len * sin(angle);
+ np->delta.y = len * cos(angle);
+ np->position = p;
+ np->color = c;
+ newPart++;
+ np++;
+ if (newPart >= size) {
+ newPart = 0;
+ np = &point[newPart];
+ }
+ }
+}
+
diff --git a/libs/rs/java/Fountain/res/raw/fountain2.rs b/libs/rs/java/Fountain/res/raw/fountain2.rs
deleted file mode 100644
index 3301140..0000000
--- a/libs/rs/java/Fountain/res/raw/fountain2.rs
+++ /dev/null
@@ -1,73 +0,0 @@
-// Fountain test script
-#pragma version(1)
-
-#include "rs_types.rsh"
-#include "rs_math.rsh"
-#include "rs_graphics.rsh"
-
-static int newPart = 0;
-
-typedef struct Control_s {
- int x, y;
- int rate;
- int count;
- float r, g, b;
- rs_allocation partBuffer;
- rs_mesh partMesh;
-} Control_t;
-Control_t *Control;
-
-typedef struct Point_s{
- float2 delta;
- float2 position;
- unsigned int color;
-} Point_t;
-Point_t *point;
-
-int main(int launchID) {
- int ct;
- int count = Control->count;
- int rate = Control->rate;
- float height = getHeight();
- Point_t * p = point;
-
- if (rate) {
- float rMax = ((float)rate) * 0.005f;
- int x = Control->x;
- int y = Control->y;
- int color = ((int)(Control->r * 255.f)) |
- ((int)(Control->g * 255.f)) << 8 |
- ((int)(Control->b * 255.f)) << 16 |
- (0xf0 << 24);
- Point_t * np = &p[newPart];
-
- while (rate--) {
- np->delta = vec2Rand(rMax);
- np->position.x = x;
- np->position.y = y;
- np->color = color;
- newPart++;
- np++;
- if (newPart >= count) {
- newPart = 0;
- np = &p[newPart];
- }
- }
- }
-
- for (ct=0; ct < count; ct++) {
- float dy = p->delta.y + 0.15f;
- float posy = p->position.y + dy;
- if ((posy > height) && (dy > 0)) {
- dy *= -0.3f;
- }
- p->delta.y = dy;
- p->position.x += p->delta.x;
- p->position.y = posy;
- p++;
- }
-
- uploadToBufferObject(Control->partBuffer);
- drawSimpleMesh(Control->partMesh);
- return 1;
-}
diff --git a/libs/rs/java/Fountain/res/raw/fountain_bc.bc b/libs/rs/java/Fountain/res/raw/fountain_bc.bc
new file mode 100644
index 0000000..b01098b
--- /dev/null
+++ b/libs/rs/java/Fountain/res/raw/fountain_bc.bc
Binary files differ
diff --git a/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java b/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java
index 9356579..5433597 100644
--- a/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java
+++ b/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java
@@ -24,92 +24,48 @@
public class FountainRS {
public static final int PART_COUNT = 20000;
- static class SomeData {
- public int x;
- public int y;
- public int rate;
- public int count;
- public float r;
- public float g;
- public float b;
- }
-
public FountainRS() {
}
+ private Resources mRes;
+ private RenderScriptGL mRS;
+ private ScriptC_Fountain mScript;
public void init(RenderScriptGL rs, Resources res, int width, int height) {
mRS = rs;
mRes = res;
- initRS();
- }
- public void newTouchPosition(int x, int y, int rate) {
- if (mSD.rate == 0) {
- mSD.r = ((x & 0x1) != 0) ? 0.f : 1.f;
- mSD.g = ((x & 0x2) != 0) ? 0.f : 1.f;
- mSD.b = ((x & 0x4) != 0) ? 0.f : 1.f;
- if ((mSD.r + mSD.g + mSD.b) < 0.9f) {
- mSD.r = 0.8f;
- mSD.g = 0.5f;
- mSD.b = 1.f;
- }
- }
- mSD.rate = rate;
- mSD.x = x;
- mSD.y = y;
- mIntAlloc.data(mSD);
- }
-
-
- /////////////////////////////////////////
-
- private Resources mRes;
-
- private RenderScriptGL mRS;
- private Allocation mIntAlloc;
- private SimpleMesh mSM;
- private SomeData mSD;
- private Type mSDType;
-
- private void initRS() {
- mSD = new SomeData();
- mSDType = Type.createFromClass(mRS, SomeData.class, 1, "SomeData");
- mIntAlloc = Allocation.createTyped(mRS, mSDType);
- mSD.count = PART_COUNT;
- mIntAlloc.data(mSD);
-
- Element.Builder eb = new Element.Builder(mRS);
- eb.add(Element.createVector(mRS, Element.DataType.FLOAT_32, 2), "delta");
- eb.add(Element.createAttrib(mRS, Element.DataType.FLOAT_32, Element.DataKind.POSITION, 2), "position");
- eb.add(Element.createAttrib(mRS, Element.DataType.UNSIGNED_8, Element.DataKind.COLOR, 4), "color");
- Element primElement = eb.create();
-
+ ScriptField_Point_s points = new ScriptField_Point_s(mRS, PART_COUNT);
SimpleMesh.Builder smb = new SimpleMesh.Builder(mRS);
- int vtxSlot = smb.addVertexType(primElement, PART_COUNT);
+ int vtxSlot = smb.addVertexType(points.getType());
smb.setPrimitive(Primitive.POINT);
- mSM = smb.create();
- mSM.setName("PartMesh");
+ SimpleMesh sm = smb.create();
+ sm.bindVertexAllocation(points.getAllocation(), vtxSlot);
- Allocation partAlloc = mSM.createVertexAllocation(vtxSlot);
- partAlloc.setName("PartBuffer");
- mSM.bindVertexAllocation(partAlloc, 0);
-
- // All setup of named objects should be done by this point
- // because we are about to compile the script.
- ScriptC.Builder sb = new ScriptC.Builder(mRS);
- sb.setScript(mRes, R.raw.fountain);
- sb.setRoot(true);
- sb.setType(mSDType, "Control", 0);
- sb.setType(mSM.getVertexType(0), "point", 1);
- Script script = sb.create();
- script.setClearColor(0.0f, 0.0f, 0.0f, 1.0f);
-
- script.bindAllocation(mIntAlloc, 0);
- script.bindAllocation(partAlloc, 1);
- mRS.contextBindRootScript(script);
+ mScript = new ScriptC_Fountain(mRS, mRes, true);
+ mScript.set_partMesh(sm);
+ mScript.bind_point(points);
+ mRS.contextBindRootScript(mScript);
}
+ Float4 tmpColor = new Float4();
+ boolean holdingColor = false;
+ java.util.Random mRand = new java.util.Random();
+ public void newTouchPosition(int x, int y, int rate) {
+ if (rate > 0) {
+ if (!holdingColor) {
+ tmpColor.x = mRand.nextFloat() * 0.5f + 0.5f;
+ tmpColor.y = mRand.nextFloat();
+ tmpColor.z = mRand.nextFloat();
+ mScript.set_partColor(tmpColor);
+ }
+ mScript.invoke_addParticles(rate, x, y);
+ holdingColor = true;
+ } else {
+ holdingColor = false;
+ }
+
+ }
}
diff --git a/libs/rs/java/Fountain/src/com/android/fountain/ScriptC_Fountain.java b/libs/rs/java/Fountain/src/com/android/fountain/ScriptC_Fountain.java
new file mode 100644
index 0000000..f6bef27
--- /dev/null
+++ b/libs/rs/java/Fountain/src/com/android/fountain/ScriptC_Fountain.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.fountain;
+
+import android.renderscript.*;
+import android.content.res.Resources;
+import android.util.Log;
+
+public class ScriptC_Fountain extends ScriptC {
+ // Constructor
+ public ScriptC_Fountain(RenderScript rs, Resources resources, boolean isRoot) {
+ super(rs, resources, R.raw.fountain_bc, isRoot);
+ }
+
+ private final static int mExportVarIdx_partColor = 0;
+ private Float4 mExportVar_partColor;
+ public void set_partColor(Float4 v) {
+ mExportVar_partColor = v;
+ FieldPacker fp = new FieldPacker(16);
+ fp.addF32(v);
+ setVar(mExportVarIdx_partColor, fp);
+ }
+
+ public Float4 get_partColor() {
+ return mExportVar_partColor;
+ }
+
+ private final static int mExportVarIdx_partMesh = 1;
+ private SimpleMesh mExportVar_partMesh;
+ public void set_partMesh(SimpleMesh v) {
+ mExportVar_partMesh = v;
+ int id = 0;
+ if (v != null) id = v.getID();
+ setVar(mExportVarIdx_partMesh, id);
+ }
+
+ public SimpleMesh get_partMesh() {
+ return mExportVar_partMesh;
+ }
+
+ private final static int mExportVarIdx_point = 2;
+ private ScriptField_Point_s mExportVar_point;
+ public void bind_point(ScriptField_Point_s v) {
+ mExportVar_point = v;
+ if(v == null) bindAllocation(null, mExportVarIdx_point);
+ else bindAllocation(v.getAllocation(), mExportVarIdx_point);
+ }
+
+ public ScriptField_Point_s get_point() {
+ return mExportVar_point;
+ }
+
+ private final static int mExportFuncIdx_addParticles = 0;
+ public void invoke_addParticles(int rate, int x, int y) {
+ FieldPacker addParticles_fp = new FieldPacker(12);
+ addParticles_fp.addI32(rate);
+ addParticles_fp.addI32(x);
+ addParticles_fp.addI32(y);
+ invokeV(mExportFuncIdx_addParticles, addParticles_fp);
+ }
+
+}
+
diff --git a/libs/rs/java/Fountain/src/com/android/fountain/ScriptField_Point_s.java b/libs/rs/java/Fountain/src/com/android/fountain/ScriptField_Point_s.java
new file mode 100644
index 0000000..9697a4d
--- /dev/null
+++ b/libs/rs/java/Fountain/src/com/android/fountain/ScriptField_Point_s.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.fountain;
+
+import android.renderscript.*;
+import android.content.res.Resources;
+import android.util.Log;
+
+public class ScriptField_Point_s extends android.renderscript.Script.FieldBase {
+ static public class Item {
+ public static final int sizeof = 20;
+
+ Float2 delta;
+ Float2 position;
+ Short4 color;
+
+ Item() {
+ delta = new Float2();
+ position = new Float2();
+ color = new Short4();
+ }
+
+ }
+
+ private Item mItemArray[];
+ private FieldPacker mIOBuffer;
+ public ScriptField_Point_s(RenderScript rs, int count) {
+ mItemArray = null;
+ mIOBuffer = null;
+ {
+ Element.Builder eb = new Element.Builder(rs);
+ eb.add(Element.createVector(rs, Element.DataType.FLOAT_32, 2), "delta");
+ eb.add(Element.createVector(rs, Element.DataType.FLOAT_32, 2), "position");
+ eb.add(Element.createVector(rs, Element.DataType.UNSIGNED_8, 4), "color");
+ mElement = eb.create();
+ }
+
+ init(rs, count);
+ }
+
+ private void copyToArray(Item i, int index) {
+ if (mIOBuffer == null) mIOBuffer = new FieldPacker(Item.sizeof * mType.getX() /* count */);
+ mIOBuffer.reset(index * Item.sizeof);
+ mIOBuffer.addF32(i.delta);
+ mIOBuffer.addF32(i.position);
+ mIOBuffer.addU8(i.color);
+ }
+
+ public void set(Item i, int index, boolean copyNow) {
+ if (mItemArray == null) mItemArray = new Item[mType.getX() /* count */];
+ mItemArray[index] = i;
+ if (copyNow) {
+ copyToArray(i, index);
+ mAllocation.subData1D(index * Item.sizeof, Item.sizeof, mIOBuffer.getData());
+ }
+
+ }
+
+ public void copyAll() {
+ for (int ct=0; ct < mItemArray.length; ct++) copyToArray(mItemArray[ct], ct);
+ mAllocation.data(mIOBuffer.getData());
+ }
+
+}
+
diff --git a/libs/rs/java/ImageProcessing/AndroidManifest.xml b/libs/rs/java/ImageProcessing/AndroidManifest.xml
index b48d208..d6a2db4 100644
--- a/libs/rs/java/ImageProcessing/AndroidManifest.xml
+++ b/libs/rs/java/ImageProcessing/AndroidManifest.xml
@@ -6,7 +6,8 @@
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application android:label="Image Processing">
- <activity android:name="ImageProcessingActivity">
+ <activity android:name="ImageProcessingActivity"
+ android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
diff --git a/libs/rs/java/ImageProcessing/res/layout/main.xml b/libs/rs/java/ImageProcessing/res/layout/main.xml
index 6770c18..c6ec729 100644
--- a/libs/rs/java/ImageProcessing/res/layout/main.xml
+++ b/libs/rs/java/ImageProcessing/res/layout/main.xml
@@ -25,9 +25,147 @@
android:id="@+id/display"
android:layout_width="320dip"
android:layout_height="266dip" />
-
+
+ <Button
+ android:layout_marginBottom="170dip"
+ android:layout_width="wrap_content"
+ android:layout_height="40dip"
+ android:text="@string/benchmark"
+ android:onClick="benchmark"
+ android:layout_gravity="bottom"/>
+
+ <TextView
+ android:id="@+id/benchmarkText"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textSize="18sp"
+ android:layout_marginLeft="100dip"
+ android:layout_marginBottom="175dip"
+ android:layout_gravity="bottom"
+ android:text="@string/saturation"/>
+
+ <SeekBar
+ android:id="@+id/inSaturation"
+ android:layout_marginBottom="140dip"
+ android:layout_marginLeft="10dip"
+ android:layout_marginRight="10dip"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom" />
+
+ <TextView
+ android:id="@+id/inSaturationText"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textSize="18sp"
+ android:layout_marginLeft="50dip"
+ android:layout_marginBottom="142dip"
+ android:textColor="#000"
+ android:layout_gravity="bottom"
+ android:text="@string/saturation"/>
+
<SeekBar
- android:id="@+id/threshold"
+ android:id="@+id/inGamma"
+ android:layout_marginBottom="110dip"
+ android:layout_marginLeft="10dip"
+ android:layout_marginRight="10dip"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom" />
+
+ <TextView
+ android:id="@+id/inGammaText"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textSize="18sp"
+ android:layout_marginLeft="50dip"
+ android:layout_marginBottom="112dip"
+ android:textColor="#000"
+ android:layout_gravity="bottom"
+ android:text="@string/gamma"/>
+
+ <SeekBar
+ android:id="@+id/outWhite"
+ android:layout_marginBottom="80dip"
+ android:layout_marginLeft="170dip"
+ android:layout_marginRight="10dip"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom" />
+
+ <TextView
+ android:id="@+id/outWhiteText"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textSize="18sp"
+ android:layout_marginLeft="220dip"
+ android:layout_marginBottom="82dip"
+ android:textColor="#000"
+ android:layout_gravity="bottom"
+ android:text="@string/out_white"/>
+
+ <SeekBar
+ android:id="@+id/inWhite"
+ android:layout_marginBottom="80dip"
+ android:layout_marginLeft="10dip"
+ android:layout_marginRight="170dip"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom" />
+
+ <TextView
+ android:id="@+id/inWhiteText"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textSize="18sp"
+ android:layout_marginLeft="50dip"
+ android:layout_marginBottom="82dip"
+ android:textColor="#000"
+ android:layout_gravity="bottom"
+ android:text="@string/in_white"/>
+
+ <SeekBar
+ android:id="@+id/outBlack"
+ android:layout_marginBottom="50dip"
+ android:layout_marginLeft="170dip"
+ android:layout_marginRight="10dip"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom" />
+
+ <TextView
+ android:id="@+id/outBlackText"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textSize="18sp"
+ android:layout_marginLeft="220dip"
+ android:layout_marginBottom="52dip"
+ android:textColor="#000"
+ android:layout_gravity="bottom"
+ android:text="@string/out_black"/>
+
+ <SeekBar
+ android:id="@+id/inBlack"
+ android:layout_marginBottom="50dip"
+ android:layout_marginLeft="10dip"
+ android:layout_marginRight="170dip"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom" />
+
+ <TextView
+ android:id="@+id/inBlackText"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textSize="18sp"
+ android:layout_marginLeft="50dip"
+ android:layout_marginBottom="52dip"
+ android:textColor="#000"
+ android:layout_gravity="bottom"
+ android:text="@string/in_black"/>
+
+ <SeekBar
+ android:id="@+id/radius"
android:layout_marginBottom="10dip"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
@@ -35,4 +173,15 @@
android:layout_height="wrap_content"
android:layout_gravity="bottom" />
+ <TextView
+ android:id="@+id/blurText"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textSize="18sp"
+ android:layout_marginLeft="50dip"
+ android:layout_marginBottom="12dip"
+ android:textColor="#000"
+ android:layout_gravity="bottom"
+ android:text="@string/blur_description"/>
+
</merge>
\ No newline at end of file
diff --git a/libs/rs/java/ImageProcessing/res/raw/threshold.rs b/libs/rs/java/ImageProcessing/res/raw/threshold.rs
index 888f0cd..6af4012 100644
--- a/libs/rs/java/ImageProcessing/res/raw/threshold.rs
+++ b/libs/rs/java/ImageProcessing/res/raw/threshold.rs
@@ -1,62 +1,333 @@
-/*
-// block of defines matching what RS will insert at runtime.
-struct Params_s{
- int inHeight;
- int inWidth;
- int outHeight;
- int outWidth;
- float threshold;
-};
-struct Params_s * Params;
-struct InPixel_s{
- char a;
- char b;
- char g;
- char r;
-};
-struct InPixel_s * InPixel;
-struct OutPixel_s{
- char a;
- char b;
- char g;
- char r;
-};
-struct OutPixel_s * OutPixel;
-*/
+#pragma version(1)
-struct color_s {
- char b;
- char g;
- char r;
- char a;
-};
+#include "../../../../scriptc/rs_types.rsh"
+#include "../../../../scriptc/rs_math.rsh"
+#include "../../../../scriptc/rs_graphics.rsh"
-void main() {
- int t = uptimeMillis();
+#define MAX_RADIUS 25
- struct color_s *in = (struct color_s *) InPixel;
- struct color_s *out = (struct color_s *) OutPixel;
+int height;
+int width;
+int radius;
- int count = Params->inWidth * Params->inHeight;
- int i;
- float threshold = (Params->threshold * 255.f);
+typedef struct c4u_s {
+ uint8_t r, g, b, a;
+} c4u_t;
- for (i = 0; i < count; i++) {
- float luminance = 0.2125f * in->r +
- 0.7154f * in->g +
- 0.0721f * in->b;
- if (luminance > threshold) {
- *out = *in;
- } else {
- *((int *)out) = *((int *)in) & 0xff000000;
- }
+c4u_t * InPixel;
+c4u_t * OutPixel;
+c4u_t * ScratchPixel;
- in++;
- out++;
+float inBlack;
+float outBlack;
+float inWhite;
+float outWhite;
+float gamma;
+
+float saturation;
+
+float inWMinInB;
+float outWMinOutB;
+
+#pragma rs export_var(height, width, radius, InPixel, OutPixel, ScratchPixel, inBlack, outBlack, inWhite, outWhite, gamma, saturation)
+#pragma rs export_func(filter, processNoBlur, computeColorMatrix, computeGaussianWeights);
+
+// Store our coefficients here
+float gaussian[MAX_RADIUS * 2 + 1];
+float colorMat[4][4];
+
+void computeColorMatrix() {
+ // Saturation
+ // Linear weights
+ //float rWeight = 0.3086f;
+ //float gWeight = 0.6094f;
+ //float bWeight = 0.0820f;
+
+ // Gamma 2.2 weights (we haven't converted our image to linear space yet for perf reasons)
+ float rWeight = 0.299f;
+ float gWeight = 0.587f;
+ float bWeight = 0.114f;
+
+ float oneMinusS = 1.0f - saturation;
+
+ rsMatrixLoadIdentity((rs_matrix4x4 *)colorMat);
+
+ colorMat[0][0] = oneMinusS * rWeight + saturation;
+ colorMat[0][1] = oneMinusS * rWeight;
+ colorMat[0][2] = oneMinusS * rWeight;
+ colorMat[1][0] = oneMinusS * gWeight;
+ colorMat[1][1] = oneMinusS * gWeight + saturation;
+ colorMat[1][2] = oneMinusS * gWeight;
+ colorMat[2][0] = oneMinusS * bWeight;
+ colorMat[2][1] = oneMinusS * bWeight;
+ colorMat[2][2] = oneMinusS * bWeight + saturation;
+
+ inWMinInB = inWhite - inBlack;
+ outWMinOutB = outWhite - outBlack;
+}
+
+void computeGaussianWeights() {
+ // Compute gaussian weights for the blur
+ // e is the euler's number
+ float e = 2.718281828459045f;
+ float pi = 3.1415926535897932f;
+ // g(x) = ( 1 / sqrt( 2 * pi ) * sigma) * e ^ ( -x^2 / 2 * sigma^2 )
+ // x is of the form [-radius .. 0 .. radius]
+ // and sigma varies with radius.
+ // Based on some experimental radius values and sigma's
+ // we approximately fit sigma = f(radius) as
+ // sigma = radius * 0.4 + 0.6
+ // The larger the radius gets, the more our gaussian blur
+ // will resemble a box blur since with large sigma
+ // the gaussian curve begins to lose its shape
+ float sigma = 0.4f * (float)radius + 0.6f;
+
+ // Now compute the coefficints
+ // We will store some redundant values to save some math during
+ // the blur calculations
+ // precompute some values
+ float coeff1 = 1.0f / (sqrt( 2.0f * pi ) * sigma);
+ float coeff2 = - 1.0f / (2.0f * sigma * sigma);
+
+ float normalizeFactor = 0.0f;
+ float floatR = 0.0f;
+ int r;
+ for(r = -radius; r <= radius; r ++) {
+ floatR = (float)r;
+ gaussian[r + radius] = coeff1 * pow(e, floatR * floatR * coeff2);
+ normalizeFactor += gaussian[r + radius];
}
- t= uptimeMillis() - t;
- debugI32("Filter time", t);
-
- sendToClient(&count, 1, 4, 0);
+ //Now we need to normalize the weights because all our coefficients need to add up to one
+ normalizeFactor = 1.0f / normalizeFactor;
+ for(r = -radius; r <= radius; r ++) {
+ floatR = (float)r;
+ gaussian[r + radius] *= normalizeFactor;
+ }
}
+
+// This needs to be inline
+void levelsSaturation(float4 *currentPixel) {
+ // Color matrix multiply
+ float tempX = colorMat[0][0] * currentPixel->x + colorMat[1][0] * currentPixel->y + colorMat[2][0] * currentPixel->z;
+ float tempY = colorMat[0][1] * currentPixel->x + colorMat[1][1] * currentPixel->y + colorMat[2][1] * currentPixel->z;
+ float tempZ = colorMat[0][2] * currentPixel->x + colorMat[1][2] * currentPixel->y + colorMat[2][2] * currentPixel->z;
+
+ currentPixel->x = tempX;
+ currentPixel->y = tempY;
+ currentPixel->z = tempZ;
+
+ // Clamp to 0..255
+ // Inline the code here to avoid funciton calls
+ currentPixel->x = currentPixel->x > 255.0f ? 255.0f : currentPixel->x;
+ currentPixel->y = currentPixel->y > 255.0f ? 255.0f : currentPixel->y;
+ currentPixel->z = currentPixel->z > 255.0f ? 255.0f : currentPixel->z;
+
+ currentPixel->x = currentPixel->x <= 0.0f ? 0.1f : currentPixel->x;
+ currentPixel->y = currentPixel->y <= 0.0f ? 0.1f : currentPixel->y;
+ currentPixel->z = currentPixel->z <= 0.0f ? 0.1f : currentPixel->z;
+
+ currentPixel->x = pow( (currentPixel->x - inBlack) / (inWMinInB), gamma) * (outWMinOutB) + outBlack;
+ currentPixel->y = pow( (currentPixel->y - inBlack) / (inWMinInB), gamma) * (outWMinOutB) + outBlack;
+ currentPixel->z = pow( (currentPixel->z - inBlack) / (inWMinInB), gamma) * (outWMinOutB) + outBlack;
+
+ currentPixel->x = currentPixel->x > 255.0f ? 255.0f : currentPixel->x;
+ currentPixel->y = currentPixel->y > 255.0f ? 255.0f : currentPixel->y;
+ currentPixel->z = currentPixel->z > 255.0f ? 255.0f : currentPixel->z;
+
+ currentPixel->x = currentPixel->x <= 0.0f ? 0.1f : currentPixel->x;
+ currentPixel->y = currentPixel->y <= 0.0f ? 0.1f : currentPixel->y;
+ currentPixel->z = currentPixel->z <= 0.0f ? 0.1f : currentPixel->z;
+}
+
+void processNoBlur() {
+ int w, h, r;
+ int count = 0;
+
+ float inWMinInB = inWhite - inBlack;
+ float outWMinOutB = outWhite - outBlack;
+ float4 currentPixel = 0;
+
+ for(h = 0; h < height; h ++) {
+ for(w = 0; w < width; w ++) {
+ c4u_t *input = InPixel + h*width + w;
+
+ currentPixel.x = (float)(input->r);
+ currentPixel.y = (float)(input->g);
+ currentPixel.z = (float)(input->b);
+
+ levelsSaturation(¤tPixel);
+
+ c4u_t *output = OutPixel + h*width + w;
+ output->r = (uint8_t)currentPixel.x;
+ output->g = (uint8_t)currentPixel.y;
+ output->b = (uint8_t)currentPixel.z;
+ output->a = input->a;
+ }
+ }
+ rsSendToClient(&count, 1, 4, 0);
+}
+
+void horizontalBlur() {
+ float4 blurredPixel = 0;
+ float4 currentPixel = 0;
+ // Horizontal blur
+ int w, h, r;
+ for(h = 0; h < height; h ++) {
+ for(w = 0; w < width; w ++) {
+
+ blurredPixel = 0;
+
+ for(r = -radius; r <= radius; r ++) {
+ // Stepping left and right away from the pixel
+ int validW = w + r;
+ // Clamp to zero and width max() isn't exposed for ints yet
+ if(validW < 0) {
+ validW = 0;
+ }
+ if(validW > width - 1) {
+ validW = width - 1;
+ }
+
+ c4u_t *input = InPixel + h*width + validW;
+
+ float weight = gaussian[r + radius];
+ currentPixel.x = (float)(input->r);
+ currentPixel.y = (float)(input->g);
+ currentPixel.z = (float)(input->b);
+ //currentPixel.w = (float)(input->a);
+
+ blurredPixel += currentPixel*weight;
+ }
+
+ c4u_t *output = ScratchPixel + h*width + w;
+ output->r = (uint8_t)blurredPixel.x;
+ output->g = (uint8_t)blurredPixel.y;
+ output->b = (uint8_t)blurredPixel.z;
+ //output->a = (uint8_t)blurredPixel.w;
+ }
+ }
+}
+
+void horizontalBlurLevels() {
+ float4 blurredPixel = 0;
+ float4 currentPixel = 0;
+ // Horizontal blur
+ int w, h, r;
+ for(h = 0; h < height; h ++) {
+ for(w = 0; w < width; w ++) {
+
+ blurredPixel = 0;
+
+ for(r = -radius; r <= radius; r ++) {
+ // Stepping left and right away from the pixel
+ int validW = w + r;
+ // Clamp to zero and width max() isn't exposed for ints yet
+ if(validW < 0) {
+ validW = 0;
+ }
+ if(validW > width - 1) {
+ validW = width - 1;
+ }
+
+ c4u_t *input = InPixel + h*width + validW;
+
+ float weight = gaussian[r + radius];
+ currentPixel.x = (float)(input->r);
+ currentPixel.y = (float)(input->g);
+ currentPixel.z = (float)(input->b);
+ //currentPixel.w = (float)(input->a);
+
+ blurredPixel += currentPixel*weight;
+ }
+
+ levelsSaturation(&blurredPixel);
+
+ c4u_t *output = ScratchPixel + h*width + w;
+ output->r = (uint8_t)blurredPixel.x;
+ output->g = (uint8_t)blurredPixel.y;
+ output->b = (uint8_t)blurredPixel.z;
+ //output->a = (uint8_t)blurredPixel.w;
+ }
+ }
+}
+
+void verticalBlur() {
+ float4 blurredPixel = 0;
+ float4 currentPixel = 0;
+ // Vertical blur
+ int w, h, r;
+ for(h = 0; h < height; h ++) {
+ for(w = 0; w < width; w ++) {
+
+ blurredPixel = 0;
+ for(r = -radius; r <= radius; r ++) {
+ int validH = h + r;
+ // Clamp to zero and width
+ if(validH < 0) {
+ validH = 0;
+ }
+ if(validH > height - 1) {
+ validH = height - 1;
+ }
+
+ c4u_t *input = ScratchPixel + validH*width + w;
+
+ float weight = gaussian[r + radius];
+
+ currentPixel.x = (float)(input->r);
+ currentPixel.y = (float)(input->g);
+ currentPixel.z = (float)(input->b);
+ //currentPixel.w = (float)(input->a);
+
+ blurredPixel += currentPixel*weight;
+ }
+
+ c4u_t *output = OutPixel + h*width + w;
+
+ output->r = (uint8_t)blurredPixel.x;
+ output->g = (uint8_t)blurredPixel.y;
+ output->b = (uint8_t)blurredPixel.z;
+ //output->a = (uint8_t)blurredPixel.w;
+ }
+ }
+}
+
+void filter() {
+ RS_DEBUG(height);
+ RS_DEBUG(width);
+ RS_DEBUG(radius);
+ RS_DEBUG(inBlack);
+ RS_DEBUG(outBlack);
+ RS_DEBUG(inWhite);
+ RS_DEBUG(outWhite);
+ RS_DEBUG(gamma);
+ RS_DEBUG(saturation);
+
+ computeColorMatrix();
+
+ if(radius == 0) {
+ processNoBlur();
+ return;
+ }
+
+ computeGaussianWeights();
+
+ horizontalBlurLevels();
+ verticalBlur();
+
+ int count = 0;
+ rsSendToClient(&count, 1, 4, 0);
+}
+
+void filterBenchmark() {
+
+ computeGaussianWeights();
+
+ horizontalBlur();
+ verticalBlur();
+
+ int count = 0;
+ rsSendToClient(&count, 1, 4, 0);
+}
+
diff --git a/libs/rs/java/ImageProcessing/res/raw/threshold_bc.bc b/libs/rs/java/ImageProcessing/res/raw/threshold_bc.bc
new file mode 100644
index 0000000..29eba2d
--- /dev/null
+++ b/libs/rs/java/ImageProcessing/res/raw/threshold_bc.bc
Binary files differ
diff --git a/libs/rs/java/ImageProcessing/res/values/strings.xml b/libs/rs/java/ImageProcessing/res/values/strings.xml
new file mode 100644
index 0000000..cc5cc4d
--- /dev/null
+++ b/libs/rs/java/ImageProcessing/res/values/strings.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+* Copyright (C) 2008 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- General -->
+ <skip />
+ <!--slider label -->
+ <string name="blur_description">Blur Radius</string>
+ <string name="in_white">In White</string>
+ <string name="out_white">Out White</string>
+ <string name="in_black">In Black</string>
+ <string name="out_black">Out Black</string>
+ <string name="gamma">Gamma</string>
+ <string name="saturation">Saturation</string>
+ <string name="benchmark">Benchmark</string>
+
+</resources>
diff --git a/libs/rs/java/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java b/libs/rs/java/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
index 9ce53d8..5e36a78 100644
--- a/libs/rs/java/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
+++ b/libs/rs/java/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
@@ -31,53 +31,53 @@
import android.view.SurfaceHolder;
import android.widget.ImageView;
import android.widget.SeekBar;
+import android.widget.TextView;
+import android.view.View;
import java.lang.Math;
-public class ImageProcessingActivity extends Activity implements SurfaceHolder.Callback {
- private Bitmap mBitmap;
- private Params mParams;
- private Script.Invokable mInvokable;
- private int[] mInData;
- private int[] mOutData;
+public class ImageProcessingActivity extends Activity
+ implements SurfaceHolder.Callback,
+ SeekBar.OnSeekBarChangeListener {
+ private Bitmap mBitmapIn;
+ private Bitmap mBitmapOut;
+ private Bitmap mBitmapScratch;
+ private ScriptC_Threshold mScript;
+ private int mRadius = 0;
+ private SeekBar mRadiusSeekBar;
+
+ private float mInBlack = 0.0f;
+ private SeekBar mInBlackSeekBar;
+ private float mOutBlack = 0.0f;
+ private SeekBar mOutBlackSeekBar;
+ private float mInWhite = 255.0f;
+ private SeekBar mInWhiteSeekBar;
+ private float mOutWhite = 255.0f;
+ private SeekBar mOutWhiteSeekBar;
+ private float mGamma = 1.0f;
+ private SeekBar mGammaSeekBar;
+
+ private float mSaturation = 1.0f;
+ private SeekBar mSaturationSeekBar;
+
+ private TextView mBenchmarkResult;
@SuppressWarnings({"FieldCanBeLocal"})
private RenderScript mRS;
@SuppressWarnings({"FieldCanBeLocal"})
- private Type mParamsType;
- @SuppressWarnings({"FieldCanBeLocal"})
- private Allocation mParamsAllocation;
- @SuppressWarnings({"FieldCanBeLocal"})
private Type mPixelType;
@SuppressWarnings({"FieldCanBeLocal"})
private Allocation mInPixelsAllocation;
@SuppressWarnings({"FieldCanBeLocal"})
private Allocation mOutPixelsAllocation;
+ @SuppressWarnings({"FieldCanBeLocal"})
+ private Allocation mScratchPixelsAllocation;
private SurfaceView mSurfaceView;
private ImageView mDisplayView;
- static class Params {
- public int inWidth;
- public int outWidth;
- public int inHeight;
- public int outHeight;
-
- public float threshold;
- }
-
- static class Pixel {
- public byte a;
- public byte r;
- public byte g;
- public byte b;
- }
-
class FilterCallback extends RenderScript.RSMessage {
private Runnable mAction = new Runnable() {
public void run() {
- mOutPixelsAllocation.readData(mOutData);
- mBitmap.setPixels(mOutData, 0, mParams.outWidth, 0, 0,
- mParams.outWidth, mParams.outHeight);
mDisplayView.invalidate();
}
};
@@ -89,29 +89,218 @@
}
}
- private void javaFilter() {
+ int in[];
+ int interm[];
+ int out[];
+ int MAX_RADIUS = 25;
+ // Store our coefficients here
+ float gaussian[];
+
+ private long javaFilter() {
+ final int width = mBitmapIn.getWidth();
+ final int height = mBitmapIn.getHeight();
+ final int count = width * height;
+
+ if (in == null) {
+ in = new int[count];
+ interm = new int[count];
+ out = new int[count];
+ gaussian = new float[MAX_RADIUS * 2 + 1];
+ mBitmapIn.getPixels(in, 0, width, 0, 0, width, height);
+ }
+
long t = java.lang.System.currentTimeMillis();
- int count = mParams.inWidth * mParams.inHeight;
- float threshold = mParams.threshold * 255.f;
- for (int i = 0; i < count; i++) {
- final float r = (float)((mInData[i] >> 0) & 0xff);
- final float g = (float)((mInData[i] >> 8) & 0xff);
- final float b = (float)((mInData[i] >> 16) & 0xff);
+ int w, h, r;
- final float luminance = 0.2125f * r +
- 0.7154f * g +
- 0.0721f * b;
- if (luminance > threshold) {
- mOutData[i] = mInData[i];
- } else {
- mOutData[i] = mInData[i] & 0xff000000;
+ float fRadius = (float)mRadius;
+ int radius = (int)mRadius;
+
+ // Compute gaussian weights for the blur
+ // e is the euler's number
+ float e = 2.718281828459045f;
+ float pi = 3.1415926535897932f;
+ // g(x) = ( 1 / sqrt( 2 * pi ) * sigma) * e ^ ( -x^2 / 2 * sigma^2 )
+ // x is of the form [-radius .. 0 .. radius]
+ // and sigma varies with radius.
+ // Based on some experimental radius values and sigma's
+ // we approximately fit sigma = f(radius) as
+ // sigma = radius * 0.4 + 0.6
+ // The larger the radius gets, the more our gaussian blur
+ // will resemble a box blur since with large sigma
+ // the gaussian curve begins to lose its shape
+ float sigma = 0.4f * fRadius + 0.6f;
+ // Now compute the coefficints
+ // We will store some redundant values to save some math during
+ // the blur calculations
+ // precompute some values
+ float coeff1 = 1.0f / (float)(Math.sqrt( 2.0f * pi ) * sigma);
+ float coeff2 = - 1.0f / (2.0f * sigma * sigma);
+ float normalizeFactor = 0.0f;
+ float floatR = 0.0f;
+ for(r = -radius; r <= radius; r ++) {
+ floatR = (float)r;
+ gaussian[r + radius] = coeff1 * (float)Math.pow(e, floatR * floatR * coeff2);
+ normalizeFactor += gaussian[r + radius];
+ }
+
+ //Now we need to normalize the weights because all our coefficients need to add up to one
+ normalizeFactor = 1.0f / normalizeFactor;
+ for(r = -radius; r <= radius; r ++) {
+ floatR = (float)r;
+ gaussian[r + radius] *= normalizeFactor;
+ }
+
+ float blurredPixelR = 0.0f;
+ float blurredPixelG = 0.0f;
+ float blurredPixelB = 0.0f;
+ float blurredPixelA = 0.0f;
+
+ for(h = 0; h < height; h ++) {
+ for(w = 0; w < width; w ++) {
+
+ blurredPixelR = 0.0f;
+ blurredPixelG = 0.0f;
+ blurredPixelB = 0.0f;
+ blurredPixelA = 0.0f;
+
+ for(r = -radius; r <= radius; r ++) {
+ // Stepping left and right away from the pixel
+ int validW = w + r;
+ // Clamp to zero and width max() isn't exposed for ints yet
+ if(validW < 0) {
+ validW = 0;
+ }
+ if(validW > width - 1) {
+ validW = width - 1;
+ }
+
+ int input = in[h*width + validW];
+
+ int R = ((input >> 24) & 0xff);
+ int G = ((input >> 16) & 0xff);
+ int B = ((input >> 8) & 0xff);
+ int A = (input & 0xff);
+
+ float weight = gaussian[r + radius];
+
+ blurredPixelR += (float)(R)*weight;
+ blurredPixelG += (float)(G)*weight;
+ blurredPixelB += (float)(B)*weight;
+ blurredPixelA += (float)(A)*weight;
+ }
+
+ int R = (int)blurredPixelR;
+ int G = (int)blurredPixelG;
+ int B = (int)blurredPixelB;
+ int A = (int)blurredPixelA;
+
+ interm[h*width + w] = (R << 24) | (G << 16) | (B << 8) | (A);
+ }
+ }
+
+ for(h = 0; h < height; h ++) {
+ for(w = 0; w < width; w ++) {
+
+ blurredPixelR = 0.0f;
+ blurredPixelG = 0.0f;
+ blurredPixelB = 0.0f;
+ blurredPixelA = 0.0f;
+ for(r = -radius; r <= radius; r ++) {
+ int validH = h + r;
+ // Clamp to zero and width
+ if(validH < 0) {
+ validH = 0;
+ }
+ if(validH > height - 1) {
+ validH = height - 1;
+ }
+
+ int input = interm[validH*width + w];
+
+ int R = ((input >> 24) & 0xff);
+ int G = ((input >> 16) & 0xff);
+ int B = ((input >> 8) & 0xff);
+ int A = (input & 0xff);
+
+ float weight = gaussian[r + radius];
+
+ blurredPixelR += (float)(R)*weight;
+ blurredPixelG += (float)(G)*weight;
+ blurredPixelB += (float)(B)*weight;
+ blurredPixelA += (float)(A)*weight;
+ }
+
+ int R = (int)blurredPixelR;
+ int G = (int)blurredPixelG;
+ int B = (int)blurredPixelB;
+ int A = (int)blurredPixelA;
+
+ out[h*width + w] = (R << 24) | (G << 16) | (B << 8) | (A);
}
}
t = java.lang.System.currentTimeMillis() - t;
+ android.util.Log.v("Img", "Java frame time ms " + t);
+ mBitmapOut.setPixels(out, 0, width, 0, 0, width, height);
+ return t;
+ }
- android.util.Log.v("Img", "frame time ms " + t);
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ if (fromUser) {
+
+ if(seekBar == mRadiusSeekBar) {
+ float fRadius = progress / 100.0f;
+ fRadius *= (float)(MAX_RADIUS);
+ mRadius = (int)fRadius;
+
+ mScript.set_radius(mRadius);
+ }
+ else if(seekBar == mInBlackSeekBar) {
+ mInBlack = (float)progress;
+ mScript.set_inBlack(mInBlack);
+ }
+ else if(seekBar == mOutBlackSeekBar) {
+ mOutBlack = (float)progress;
+ mScript.set_outBlack(mOutBlack);
+ }
+ else if(seekBar == mInWhiteSeekBar) {
+ mInWhite = (float)progress + 127.0f;
+ mScript.set_inWhite(mInWhite);
+ }
+ else if(seekBar == mOutWhiteSeekBar) {
+ mOutWhite = (float)progress + 127.0f;
+ mScript.set_outWhite(mOutWhite);
+ }
+ else if(seekBar == mGammaSeekBar) {
+ mGamma = (float)progress/100.0f;
+ mGamma = Math.max(mGamma, 0.1f);
+ mGamma = 1.0f / mGamma;
+ mScript.set_gamma(mGamma);
+ }
+ else if(seekBar == mSaturationSeekBar) {
+ mSaturation = (float)progress / 50.0f;
+ mScript.set_saturation(mSaturation);
+ }
+
+ long t = java.lang.System.currentTimeMillis();
+ if (true) {
+ mScript.invokable_Filter();
+ } else {
+ javaFilter();
+ }
+
+ t = java.lang.System.currentTimeMillis() - t;
+ android.util.Log.v("Img", "Renderscript frame time core ms " + t);
+
+ mDisplayView.invalidate();
+ }
+ }
+
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ }
+
+ public void onStopTrackingTouch(SeekBar seekBar) {
}
@Override
@@ -119,45 +308,53 @@
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
- mBitmap = loadBitmap(R.drawable.data);
+ mBitmapIn = loadBitmap(R.drawable.data);
+ mBitmapOut = loadBitmap(R.drawable.data);
+ mBitmapScratch = loadBitmap(R.drawable.data);
mSurfaceView = (SurfaceView) findViewById(R.id.surface);
mSurfaceView.getHolder().addCallback(this);
mDisplayView = (ImageView) findViewById(R.id.display);
- mDisplayView.setImageBitmap(mBitmap);
+ mDisplayView.setImageBitmap(mBitmapOut);
- ((SeekBar) findViewById(R.id.threshold)).setOnSeekBarChangeListener(
- new SeekBar.OnSeekBarChangeListener() {
- public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
- if (fromUser) {
- mParams.threshold = progress / 100.0f;
- mParamsAllocation.data(mParams);
+ mRadiusSeekBar = (SeekBar) findViewById(R.id.radius);
+ mRadiusSeekBar.setOnSeekBarChangeListener(this);
- if (true) {
- mInvokable.execute();
- } else {
- javaFilter();
- mBitmap.setPixels(mOutData, 0, mParams.outWidth, 0, 0,
- mParams.outWidth, mParams.outHeight);
- mDisplayView.invalidate();
- }
- }
- }
+ mInBlackSeekBar = (SeekBar)findViewById(R.id.inBlack);
+ mInBlackSeekBar.setOnSeekBarChangeListener(this);
+ mInBlackSeekBar.setMax(128);
+ mInBlackSeekBar.setProgress(0);
+ mOutBlackSeekBar = (SeekBar)findViewById(R.id.outBlack);
+ mOutBlackSeekBar.setOnSeekBarChangeListener(this);
+ mOutBlackSeekBar.setMax(128);
+ mOutBlackSeekBar.setProgress(0);
- public void onStartTrackingTouch(SeekBar seekBar) {
- }
+ mInWhiteSeekBar = (SeekBar)findViewById(R.id.inWhite);
+ mInWhiteSeekBar.setOnSeekBarChangeListener(this);
+ mInWhiteSeekBar.setMax(128);
+ mInWhiteSeekBar.setProgress(128);
+ mOutWhiteSeekBar = (SeekBar)findViewById(R.id.outWhite);
+ mOutWhiteSeekBar.setOnSeekBarChangeListener(this);
+ mOutWhiteSeekBar.setMax(128);
+ mOutWhiteSeekBar.setProgress(128);
- public void onStopTrackingTouch(SeekBar seekBar) {
- }
- });
+ mGammaSeekBar = (SeekBar)findViewById(R.id.inGamma);
+ mGammaSeekBar.setOnSeekBarChangeListener(this);
+ mGammaSeekBar.setMax(150);
+ mGammaSeekBar.setProgress(100);
+
+ mSaturationSeekBar = (SeekBar)findViewById(R.id.inSaturation);
+ mSaturationSeekBar.setOnSeekBarChangeListener(this);
+ mSaturationSeekBar.setProgress(50);
+
+ mBenchmarkResult = (TextView) findViewById(R.id.benchmarkText);
+ mBenchmarkResult.setText("Benchmark no yet run");
}
public void surfaceCreated(SurfaceHolder holder) {
- mParams = createParams();
- mInvokable = createScript();
-
- mInvokable.execute();
+ createScript();
+ mScript.invokable_Filter();
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
@@ -166,54 +363,29 @@
public void surfaceDestroyed(SurfaceHolder holder) {
}
- private Script.Invokable createScript() {
+ private void createScript() {
mRS = RenderScript.create();
mRS.mMessageCallback = new FilterCallback();
- mParamsType = Type.createFromClass(mRS, Params.class, 1, "Parameters");
- mParamsAllocation = Allocation.createTyped(mRS, mParamsType);
- mParamsAllocation.data(mParams);
+ mInPixelsAllocation = Allocation.createBitmapRef(mRS, mBitmapIn);
+ mOutPixelsAllocation = Allocation.createBitmapRef(mRS, mBitmapOut);
+ mScratchPixelsAllocation = Allocation.createBitmapRef(mRS, mBitmapScratch);
- final int pixelCount = mParams.inWidth * mParams.inHeight;
+ mScript = new ScriptC_Threshold(mRS, getResources(), false);
+ mScript.set_width(mBitmapIn.getWidth());
+ mScript.set_height(mBitmapIn.getHeight());
+ mScript.set_radius(mRadius);
- mPixelType = Type.createFromClass(mRS, Pixel.class, 1, "Pixel");
- mInPixelsAllocation = Allocation.createSized(mRS,
- Element.createUser(mRS, Element.DataType.SIGNED_32),
- pixelCount);
- mOutPixelsAllocation = Allocation.createSized(mRS,
- Element.createUser(mRS, Element.DataType.SIGNED_32),
- pixelCount);
+ mScript.set_inBlack(mInBlack);
+ mScript.set_outBlack(mOutBlack);
+ mScript.set_inWhite(mInWhite);
+ mScript.set_outWhite(mOutWhite);
+ mScript.set_gamma(mGamma);
+ mScript.set_saturation(mSaturation);
- mInData = new int[pixelCount];
- mBitmap.getPixels(mInData, 0, mParams.inWidth, 0, 0, mParams.inWidth, mParams.inHeight);
- mInPixelsAllocation.data(mInData);
-
- mOutData = new int[pixelCount];
- mOutPixelsAllocation.data(mOutData);
-
- ScriptC.Builder sb = new ScriptC.Builder(mRS);
- sb.setType(mParamsType, "Params", 0);
- sb.setType(mPixelType, "InPixel", 1);
- sb.setType(mPixelType, "OutPixel", 2);
- sb.setType(true, 2);
- Script.Invokable invokable = sb.addInvokable("main");
- sb.setScript(getResources(), R.raw.threshold);
- //sb.setRoot(true);
-
- ScriptC script = sb.create();
- script.bindAllocation(mParamsAllocation, 0);
- script.bindAllocation(mInPixelsAllocation, 1);
- script.bindAllocation(mOutPixelsAllocation, 2);
-
- return invokable;
- }
-
- private Params createParams() {
- final Params params = new Params();
- params.inWidth = params.outWidth = mBitmap.getWidth();
- params.inHeight = params.outHeight = mBitmap.getHeight();
- params.threshold = 0.5f;
- return params;
+ mScript.bind_InPixel(mInPixelsAllocation);
+ mScript.bind_OutPixel(mOutPixelsAllocation);
+ mScript.bind_ScratchPixel(mScratchPixelsAllocation);
}
private Bitmap loadBitmap(int resource) {
@@ -229,4 +401,28 @@
source.recycle();
return b;
}
+
+ // button hook
+ public void benchmark(View v) {
+ android.util.Log.v("Img", "Benchmarking");
+ int oldRadius = mRadius;
+ mRadius = MAX_RADIUS;
+ mScript.set_radius(mRadius);
+
+ long t = java.lang.System.currentTimeMillis();
+
+ mScript.invokable_FilterBenchmark();
+
+ t = java.lang.System.currentTimeMillis() - t;
+ android.util.Log.v("Img", "Renderscript frame time core ms " + t);
+
+ long javaTime = javaFilter();
+
+ mBenchmarkResult.setText("RS: " + t + " ms Java: " + javaTime + " ms");
+
+ mRadius = oldRadius;
+ mScript.set_radius(mRadius);
+
+ mScript.invokable_Filter();
+ }
}
diff --git a/libs/rs/java/ImageProcessing/src/com/android/rs/image/ScriptC_Threshold.java b/libs/rs/java/ImageProcessing/src/com/android/rs/image/ScriptC_Threshold.java
new file mode 100644
index 0000000..dfed9e5
--- /dev/null
+++ b/libs/rs/java/ImageProcessing/src/com/android/rs/image/ScriptC_Threshold.java
@@ -0,0 +1,115 @@
+
+package com.android.rs.image;
+
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.util.Log;
+
+public class ScriptC_Threshold
+ extends android.renderscript.ScriptC
+{
+ private final static int mFieldIndex_height = 0;
+ private final static int mFieldIndex_width = 1;
+ private final static int mFieldIndex_radius = 2;
+ private final static int mFieldIndex_InPixel = 3;
+ private final static int mFieldIndex_OutPixel = 4;
+ private final static int mFieldIndex_ScratchPixel = 5;
+
+ private final static int mFieldIndex_inBlack = 6;
+ private final static int mFieldIndex_outBlack = 7;
+ private final static int mFieldIndex_inWhite = 8;
+ private final static int mFieldIndex_outWhite = 9;
+ private final static int mFieldIndex_gamma = 10;
+
+ private final static int mFieldIndex_saturation = 11;
+ private final static int mFieldIndex_hue = 12;
+
+ private Allocation mField_InPixel;
+ private Allocation mField_OutPixel;
+ private Allocation mField_ScratchPixel;
+
+ public ScriptC_Threshold(RenderScript rs, Resources resources, boolean isRoot) {
+ super(rs, resources, R.raw.threshold_bc, isRoot);
+ }
+
+ public void bind_InPixel(Allocation f) {
+ if (f != null) {
+ //if (f.getType().getElement() != Element.ATTRIB_COLOR_U8_4(mRS)) {
+ //throw new IllegalArgumentException("Element type mismatch.");
+ //}
+ }
+ bindAllocation(f, mFieldIndex_InPixel);
+ mField_InPixel = f;
+ }
+ public Allocation get_InPixel() {
+ return mField_InPixel;
+ }
+
+ public void bind_OutPixel(Allocation f) {
+ if (f != null) {
+ //if (f.getType().getElement() != Element.ATTRIB_COLOR_U8_4(mRS)) {
+ //throw new IllegalArgumentException("Element type mismatch.");
+ //}
+ }
+ bindAllocation(f, mFieldIndex_OutPixel);
+ mField_OutPixel = f;
+ }
+ public void bind_ScratchPixel(Allocation f) {
+ if (f != null) {
+ //if (f.getType().getElement() != Element.ATTRIB_COLOR_U8_4(mRS)) {
+ //throw new IllegalArgumentException("Element type mismatch.");
+ //}
+ }
+ bindAllocation(f, mFieldIndex_ScratchPixel);
+ mField_ScratchPixel = f;
+ }
+ public Allocation get_OutPixel() {
+ return mField_OutPixel;
+ }
+
+ public void set_height(int v) {
+ setVar(mFieldIndex_height, v);
+ }
+
+ public void set_width(int v) {
+ setVar(mFieldIndex_width, v);
+ }
+
+ public void set_radius(int v) {
+ setVar(mFieldIndex_radius, v);
+ }
+
+ public void set_inBlack(float v) {
+ setVar(mFieldIndex_inBlack, v);
+ }
+ public void set_outBlack(float v) {
+ setVar(mFieldIndex_outBlack, v);
+ }
+ public void set_inWhite(float v) {
+ setVar(mFieldIndex_inWhite, v);
+ }
+ public void set_outWhite(float v) {
+ setVar(mFieldIndex_outWhite, v);
+ }
+ public void set_gamma(float v) {
+ setVar(mFieldIndex_gamma, v);
+ }
+
+ public void set_saturation(float v) {
+ setVar(mFieldIndex_saturation, v);
+ }
+ public void set_hue(float v) {
+ setVar(mFieldIndex_hue, v);
+ }
+
+ private final static int mInvokableIndex_Filter = 2;
+ public void invokable_Filter() {
+ invokeData(mInvokableIndex_Filter);
+ }
+
+ private final static int mInvokableIndex_FilterBenchmark = 3;
+ public void invokable_FilterBenchmark() {
+ invokeData(mInvokableIndex_FilterBenchmark);
+ }
+}
+
diff --git a/libs/rs/java/ModelViewer/Android.mk b/libs/rs/java/ModelViewer/Android.mk
new file mode 100644
index 0000000..8bec6d6
--- /dev/null
+++ b/libs/rs/java/ModelViewer/Android.mk
@@ -0,0 +1,27 @@
+#
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+#LOCAL_STATIC_JAVA_LIBRARIES := android.renderscript
+
+LOCAL_PACKAGE_NAME := ModelViewer
+
+include $(BUILD_PACKAGE)
diff --git a/libs/rs/java/ModelViewer/AndroidManifest.xml b/libs/rs/java/ModelViewer/AndroidManifest.xml
new file mode 100644
index 0000000..ebbe743
--- /dev/null
+++ b/libs/rs/java/ModelViewer/AndroidManifest.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.modelviewer">
+ <application android:label="ModelViewer">
+ <activity android:name="ModelViewer"
+ android:screenOrientation="portrait"
+ android:theme="@android:style/Theme.Black.NoTitleBar">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/libs/rs/java/ModelViewer/res/drawable/robot.png b/libs/rs/java/ModelViewer/res/drawable/robot.png
new file mode 100644
index 0000000..7c85e56
--- /dev/null
+++ b/libs/rs/java/ModelViewer/res/drawable/robot.png
Binary files differ
diff --git a/libs/rs/java/ModelViewer/res/raw/modelviewer.rs b/libs/rs/java/ModelViewer/res/raw/modelviewer.rs
new file mode 100644
index 0000000..6a98f90
--- /dev/null
+++ b/libs/rs/java/ModelViewer/res/raw/modelviewer.rs
@@ -0,0 +1,59 @@
+// Copyright (C) 2009 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma version(1)
+
+#include "../../../../scriptc/rs_types.rsh"
+#include "../../../../scriptc/rs_math.rsh"
+#include "../../../../scriptc/rs_graphics.rsh"
+
+rs_program_vertex gPVBackground;
+rs_program_fragment gPFBackground;
+
+rs_allocation gTGrid;
+rs_mesh gTestMesh;
+
+rs_program_store gPFSBackground;
+
+float gRotate;
+
+#pragma rs export_var(gPVBackground, gPFBackground, gTGrid, gTestMesh, gPFSBackground, gRotate)
+
+void init() {
+ gRotate = 0.0f;
+}
+
+int root(int launchID) {
+
+ rsgClearColor(1.0f, 1.0f, 1.0f, 1.0f);
+ rsgClearDepth(1.0f);
+
+ rsgBindProgramVertex(gPVBackground);
+
+ rsgBindProgramFragment(gPFBackground);
+ rsgBindProgramStore(gPFSBackground);
+ rsgBindTexture(gPFBackground, 0, gTGrid);
+
+ rs_matrix4x4 matrix;
+ rsMatrixLoadIdentity(&matrix);
+ // Position our model on the screen
+ rsMatrixTranslate(&matrix, 0.0f, -0.3f, 1.2f);
+ rsMatrixScale(&matrix, 0.2f, 0.2f, 0.2f);
+ rsMatrixRotate(&matrix, gRotate, 0.0f, 1.0f, 0.0f);
+ rsgProgramVertexLoadModelMatrix(&matrix);
+
+ rsgDrawSimpleMesh(gTestMesh);
+
+ return 10;
+}
diff --git a/libs/rs/java/ModelViewer/res/raw/modelviewer_bc.bc b/libs/rs/java/ModelViewer/res/raw/modelviewer_bc.bc
new file mode 100644
index 0000000..b02250b
--- /dev/null
+++ b/libs/rs/java/ModelViewer/res/raw/modelviewer_bc.bc
Binary files differ
diff --git a/libs/rs/java/ModelViewer/res/raw/robot.a3d b/libs/rs/java/ModelViewer/res/raw/robot.a3d
new file mode 100644
index 0000000..c0c66ae
--- /dev/null
+++ b/libs/rs/java/ModelViewer/res/raw/robot.a3d
Binary files differ
diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/ModelViewer.java b/libs/rs/java/ModelViewer/src/com/android/modelviewer/ModelViewer.java
new file mode 100644
index 0000000..7491744
--- /dev/null
+++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/ModelViewer.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.modelviewer;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScript;
+
+import android.app.Activity;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.provider.Settings.System;
+import android.util.Config;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.Window;
+import android.widget.Button;
+import android.widget.ListView;
+
+import java.lang.Runtime;
+
+public class ModelViewer extends Activity {
+
+ private ModelViewerView mView;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ // Create our Preview view and set it as the content of our
+ // Activity
+ mView = new ModelViewerView(this);
+ setContentView(mView);
+ }
+
+ @Override
+ protected void onResume() {
+ // Ideally a game should implement onResume() and onPause()
+ // to take appropriate action when the activity looses focus
+ super.onResume();
+ mView.onResume();
+ }
+
+ @Override
+ protected void onPause() {
+ // Ideally a game should implement onResume() and onPause()
+ // to take appropriate action when the activity looses focus
+ super.onPause();
+ mView.onPause();
+ }
+
+}
+
diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/ModelViewerRS.java b/libs/rs/java/ModelViewer/src/com/android/modelviewer/ModelViewerRS.java
new file mode 100644
index 0000000..dd52955
--- /dev/null
+++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/ModelViewerRS.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.modelviewer;
+
+import java.io.Writer;
+
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.renderscript.ProgramStore.DepthFunc;
+import android.util.Log;
+
+
+public class ModelViewerRS {
+
+ private final int STATE_LAST_FOCUS = 1;
+
+ int mWidth;
+ int mHeight;
+ int mRotation;
+
+ public ModelViewerRS() {
+ }
+
+ public void init(RenderScriptGL rs, Resources res, int width, int height) {
+ mRS = rs;
+ mRes = res;
+ mWidth = width;
+ mHeight = height;
+ mRotation = 0;
+ initRS();
+ }
+
+ private Resources mRes;
+ private RenderScriptGL mRS;
+ private Sampler mSampler;
+ private ProgramStore mPSBackground;
+ private ProgramFragment mPFBackground;
+ private ProgramVertex mPVBackground;
+ private ProgramVertex.MatrixAllocation mPVA;
+
+ private Allocation mGridImage;
+ private Allocation mAllocPV;
+
+ private SimpleMesh mMesh;
+
+ private ScriptC_ModelViewer mScript;
+
+ int mLastX;
+ int mLastY;
+
+ public void touchEvent(int x, int y) {
+ int dx = mLastX - x;
+ if(Math.abs(dx) > 50 || Math.abs(dx) < 3) {
+ dx = 0;
+ }
+
+ mRotation -= dx;
+ if(mRotation > 360) {
+ mRotation -= 360;
+ }
+ if(mRotation < 0) {
+ mRotation += 360;
+ }
+
+ mScript.set_gRotate(-(float)mRotation);
+
+ mLastX = x;
+ mLastY = y;
+ }
+
+ private void initPFS() {
+ ProgramStore.Builder b = new ProgramStore.Builder(mRS, null, null);
+
+ b.setDepthFunc(ProgramStore.DepthFunc.LESS);
+ b.setDitherEnable(false);
+ b.setDepthMask(true);
+ mPSBackground = b.create();
+
+ mScript.set_gPFSBackground(mPSBackground);
+ }
+
+ private void initPF() {
+ Sampler.Builder bs = new Sampler.Builder(mRS);
+ bs.setMin(Sampler.Value.LINEAR);
+ bs.setMag(Sampler.Value.LINEAR);
+ bs.setWrapS(Sampler.Value.CLAMP);
+ bs.setWrapT(Sampler.Value.WRAP);
+ mSampler = bs.create();
+
+ ProgramFragment.Builder b = new ProgramFragment.Builder(mRS);
+ b.setTexture(ProgramFragment.Builder.EnvMode.REPLACE,
+ ProgramFragment.Builder.Format.RGBA, 0);
+ mPFBackground = b.create();
+ mPFBackground.bindSampler(mSampler, 0);
+
+ mScript.set_gPFBackground(mPFBackground);
+ }
+
+ private void initPV() {
+ ProgramVertex.Builder pvb = new ProgramVertex.Builder(mRS, null, null);
+ mPVBackground = pvb.create();
+
+ mPVA = new ProgramVertex.MatrixAllocation(mRS);
+ mPVBackground.bindAllocation(mPVA);
+ mPVA.setupProjectionNormalized(mWidth, mHeight);
+
+ mScript.set_gPVBackground(mPVBackground);
+ }
+
+ private void loadImage() {
+ mGridImage = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.robot, Element.RGB_565(mRS), true);
+ mGridImage.uploadToTexture(1);
+
+ mScript.set_gTGrid(mGridImage);
+ }
+
+ private void initRS() {
+
+ mScript = new ScriptC_ModelViewer(mRS, mRes, true);
+
+ initPFS();
+ initPF();
+ initPV();
+
+ loadImage();
+
+ FileA3D model = FileA3D.createFromResource(mRS, mRes, R.raw.robot);
+ FileA3D.IndexEntry entry = model.getIndexEntry(0);
+ if(entry == null || entry.getClassID() != FileA3D.ClassID.SIMPLE_MESH) {
+ Log.e("rs", "could not load model");
+ }
+ else {
+ mMesh = (SimpleMesh)entry.getObject();
+ mScript.set_gTestMesh(mMesh);
+ }
+
+ mRS.contextBindRootScript(mScript);
+ }
+}
+
+
+
diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/ModelViewerView.java b/libs/rs/java/ModelViewer/src/com/android/modelviewer/ModelViewerView.java
new file mode 100644
index 0000000..ce76e1a
--- /dev/null
+++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/ModelViewerView.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.modelviewer;
+
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.concurrent.Semaphore;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScript;
+import android.renderscript.RenderScriptGL;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Message;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+public class ModelViewerView extends RSSurfaceView {
+
+ public ModelViewerView(Context context) {
+ super(context);
+ //setFocusable(true);
+ }
+
+ private RenderScriptGL mRS;
+ private ModelViewerRS mRender;
+
+
+ public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
+ super.surfaceChanged(holder, format, w, h);
+ if (mRS == null) {
+ mRS = createRenderScript(true);
+ mRS.contextSetSurface(w, h, holder.getSurface());
+ mRender = new ModelViewerRS();
+ mRender.init(mRS, getResources(), w, h);
+ }
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ if(mRS != null) {
+ mRS = null;
+ destroyRenderScript();
+ }
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event)
+ {
+ // break point at here
+ // this method doesn't work when 'extends View' include 'extends ScrollView'.
+ return super.onKeyDown(keyCode, event);
+ }
+
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev)
+ {
+ boolean ret = true;
+ int act = ev.getAction();
+ if (act == ev.ACTION_UP) {
+ ret = false;
+ }
+
+ Log.v("rs", "Values " + (int)ev.getX() + " " + (int)ev.getY());
+ mRender.touchEvent((int)ev.getX(), (int)ev.getY());
+ return ret;
+ }
+}
+
+
diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/ScriptC_ModelViewer.java b/libs/rs/java/ModelViewer/src/com/android/modelviewer/ScriptC_ModelViewer.java
new file mode 100644
index 0000000..f617c77
--- /dev/null
+++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/ScriptC_ModelViewer.java
@@ -0,0 +1,42 @@
+
+package com.android.modelviewer;
+
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.util.Log;
+
+
+
+public class ScriptC_ModelViewer
+ extends android.renderscript.ScriptC
+{
+ public ScriptC_ModelViewer(RenderScript rs, Resources resources, boolean isRoot) {
+ super(rs, resources, R.raw.modelviewer_bc, isRoot);
+ }
+
+ public void set_gPVBackground(ProgramVertex v) {
+ setVar(0, v.getID());
+ }
+
+ public void set_gPFBackground(ProgramFragment v) {
+ setVar(1, v.getID());
+ }
+
+ public void set_gTGrid(Allocation v) {
+ setVar(2, v.getID());
+ }
+
+ public void set_gTestMesh(SimpleMesh v) {
+ setVar(3, v.getID());
+ }
+
+ public void set_gPFSBackground(ProgramStore v) {
+ setVar(4, v.getID());
+ }
+
+ public void set_gRotate(float v) {
+ setVar(5, v);
+ }
+
+}
+
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
index cb9937c..4867cad 100644
--- a/libs/rs/rs.spec
+++ b/libs/rs/rs.spec
@@ -4,8 +4,8 @@
param RsScript sampler
}
-ContextBindProgramFragmentStore {
- param RsProgramFragmentStore pgm
+ContextBindProgramStore {
+ param RsProgramStore pgm
}
ContextBindProgramFragment {
@@ -248,13 +248,6 @@
ScriptCBegin {
}
-ScriptSetClearColor {
- param RsScript s
- param float r
- param float g
- param float b
- param float a
- }
ScriptSetTimeZone {
param RsScript s
@@ -262,37 +255,47 @@
param uint32_t length
}
-ScriptSetClearDepth {
- param RsScript s
- param float depth
- }
-
-ScriptSetClearStencil {
- param RsScript s
- param uint32_t stencil
- }
-
-ScriptSetType {
- param RsType type
- param uint32_t slot
- param bool isWritable
- param const char * name
- }
-
-ScriptSetInvoke {
- param const char * name
- param uint32_t slot
- }
ScriptInvoke {
param RsScript s
param uint32_t slot
}
-ScriptSetRoot {
- param bool isRoot
+ScriptInvokeData {
+ param RsScript s
+ param uint32_t slot
+ param void * data
}
+ScriptInvokeV {
+ param RsScript s
+ param uint32_t slot
+ param const void * data
+ param uint32_t dataLen
+ handcodeApi
+ togglePlay
+ }
+
+ScriptSetVarI {
+ param RsScript s
+ param uint32_t slot
+ param int value
+ }
+
+ScriptSetVarF {
+ param RsScript s
+ param uint32_t slot
+ param float value
+ }
+
+ScriptSetVarV {
+ param RsScript s
+ param uint32_t slot
+ param const void * data
+ param uint32_t dataLen
+ handcodeApi
+ togglePlay
+ }
ScriptCSetScript {
@@ -308,47 +311,38 @@
ret RsScript
}
-ScriptCSetDefineF {
- param const char* name
- param float value
- }
-ScriptCSetDefineI32 {
- param const char* name
- param int32_t value
- }
-
-ProgramFragmentStoreBegin {
+ProgramStoreBegin {
param RsElement in
param RsElement out
}
-ProgramFragmentStoreColorMask {
+ProgramStoreColorMask {
param bool r
param bool g
param bool b
param bool a
}
-ProgramFragmentStoreBlendFunc {
+ProgramStoreBlendFunc {
param RsBlendSrcFunc srcFunc
param RsBlendDstFunc destFunc
}
-ProgramFragmentStoreDepthMask {
+ProgramStoreDepthMask {
param bool enable
}
-ProgramFragmentStoreDither {
+ProgramStoreDither {
param bool enable
}
-ProgramFragmentStoreDepthFunc {
+ProgramStoreDepthFunc {
param RsDepthFunc func
}
-ProgramFragmentStoreCreate {
- ret RsProgramFragmentStore
+ProgramStoreCreate {
+ ret RsProgramStore
}
ProgramRasterCreate {
@@ -447,12 +441,34 @@
param float b
}
+FileA3DCreateFromAssetStream {
+ param const void * data
+ param size_t len
+ ret RsFile
+ }
+
FileOpen {
ret RsFile
param const char *name
param size_t len
}
+FileA3DGetNumIndexEntries {
+ param int32_t * numEntries
+ param RsFile file
+ }
+
+FileA3DGetIndexEntries {
+ param RsFileIndexEntry * fileEntries
+ param uint32_t numEntries
+ param RsFile fileA3D
+ }
+
+FileA3DGetEntryByIndex {
+ param uint32_t index
+ param RsFile file
+ ret RsObjectBase
+ }
SimpleMeshCreate {
ret RsSimpleMesh
@@ -480,3 +496,13 @@
param uint32_t slot
}
+AnimationCreate {
+ param const float *inValues
+ param const float *outValues
+ param uint32_t valueCount
+ param RsAnimationInterpolation interp
+ param RsAnimationEdge pre
+ param RsAnimationEdge post
+ ret RsAnimation
+ }
+
diff --git a/libs/rs/rsAdapter.cpp b/libs/rs/rsAdapter.cpp
index 0d31fac..b4ec250 100644
--- a/libs/rs/rsAdapter.cpp
+++ b/libs/rs/rsAdapter.cpp
@@ -15,7 +15,11 @@
* limitations under the License.
*/
+#ifndef ANDROID_RS_BUILD_FOR_HOST
#include "rsContext.h"
+#else
+#include "rsContextHostStub.h"
+#endif
using namespace android;
using namespace android::renderscript;
@@ -70,6 +74,16 @@
mAllocation.get()->getType()->getSizeBytes());
}
+void Adapter1D::serialize(OStream *stream) const
+{
+
+}
+
+Adapter1D *Adapter1D::createFromStream(Context *rsc, IStream *stream)
+{
+ return NULL;
+}
+
namespace android {
namespace renderscript {
@@ -185,6 +199,15 @@
mAllocation.get()->getType()->getSizeBytes());
}
+void Adapter2D::serialize(OStream *stream) const
+{
+
+}
+
+Adapter2D *Adapter2D::createFromStream(Context *rsc, IStream *stream)
+{
+ return NULL;
+}
namespace android {
diff --git a/libs/rs/rsAdapter.h b/libs/rs/rsAdapter.h
index cb2872e..449e7ad 100644
--- a/libs/rs/rsAdapter.h
+++ b/libs/rs/rsAdapter.h
@@ -50,6 +50,10 @@
void subData(uint32_t xoff, uint32_t count, const void *data);
void data(const void *data);
+ virtual void serialize(OStream *stream) const;
+ virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_ADAPTER_1D; }
+ static Adapter1D *createFromStream(Context *rsc, IStream *stream);
+
protected:
ObjectBaseRef<Allocation> mAllocation;
uint32_t mY;
@@ -82,6 +86,10 @@
void data(const void *data);
void subData(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h, const void *data);
+ virtual void serialize(OStream *stream) const;
+ virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_ADAPTER_2D; }
+ static Adapter2D *createFromStream(Context *rsc, IStream *stream);
+
protected:
ObjectBaseRef<Allocation> mAllocation;
uint32_t mZ;
diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp
index 4e8278d..289cb30 100644
--- a/libs/rs/rsAllocation.cpp
+++ b/libs/rs/rsAllocation.cpp
@@ -13,12 +13,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
+#ifndef ANDROID_RS_BUILD_FOR_HOST
#include "rsContext.h"
#include <GLES/gl.h>
#include <GLES2/gl2.h>
#include <GLES/glext.h>
+#else
+#include "rsContextHostStub.h"
+
+#include <OpenGL/gl.h>
+#include <OpenGl/glext.h>
+#endif
using namespace android;
using namespace android::renderscript;
@@ -167,9 +173,12 @@
0, format, type, ptr);
}
if (mTextureGenMipmap) {
+#ifndef ANDROID_RS_BUILD_FOR_HOST
glGenerateMipmap(GL_TEXTURE_2D);
+#endif //ANDROID_RS_BUILD_FOR_HOST
}
+ rsc->checkError("Allocation::uploadToTexture");
}
void Allocation::deferedUploadToBufferObject(const Context *rsc)
@@ -201,6 +210,7 @@
glBindBuffer(GL_ARRAY_BUFFER, mBufferID);
glBufferData(GL_ARRAY_BUFFER, mType->getSizeBytes(), getPtr(), GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
+ rsc->checkError("Allocation::uploadToBufferObject");
}
void Allocation::uploadCheck(const Context *rsc)
@@ -284,7 +294,7 @@
void Allocation::addProgramToDirty(const Program *p)
{
- mToDirtyList.add(p);
+ mToDirtyList.push(p);
}
void Allocation::removeProgramToDirty(const Program *p)
@@ -316,6 +326,60 @@
}
+void Allocation::serialize(OStream *stream) const
+{
+ // Need to identify ourselves
+ stream->addU32((uint32_t)getClassId());
+
+ String8 name(getName());
+ stream->addString(&name);
+
+ // First thing we need to serialize is the type object since it will be needed
+ // to initialize the class
+ mType->serialize(stream);
+
+ uint32_t dataSize = mType->getSizeBytes();
+ // Write how much data we are storing
+ stream->addU32(dataSize);
+ // Now write the data
+ stream->addByteArray(mPtr, dataSize);
+}
+
+Allocation *Allocation::createFromStream(Context *rsc, IStream *stream)
+{
+ // First make sure we are reading the correct object
+ RsA3DClassID classID = (RsA3DClassID)stream->loadU32();
+ if(classID != RS_A3D_CLASS_ID_ALLOCATION) {
+ LOGE("allocation loading skipped due to invalid class id\n");
+ return NULL;
+ }
+
+ String8 name;
+ stream->loadString(&name);
+
+ Type *type = Type::createFromStream(rsc, stream);
+ if(!type) {
+ return NULL;
+ }
+ type->compute();
+
+ // Number of bytes we wrote out for this allocation
+ uint32_t dataSize = stream->loadU32();
+ if(dataSize != type->getSizeBytes()) {
+ LOGE("failed to read allocation because numbytes written is not the same loaded type wants\n");
+ delete type;
+ return NULL;
+ }
+
+ Allocation *alloc = new Allocation(rsc, type);
+ alloc->setName(name.string(), name.size());
+
+ // Read in all of our allocation data
+ stream->loadByteArray(alloc->getPtr(), dataSize);
+
+ return alloc;
+}
+
void Allocation::sendDirty() const
{
for (size_t ct=0; ct < mToDirtyList.size(); ct++) {
@@ -512,6 +576,8 @@
return 0;
}
+#ifndef ANDROID_RS_BUILD_FOR_HOST
+
RsAllocation rsi_AllocationCreateBitmapRef(Context *rsc, RsType vtype,
void *bmp, void *callbackData, RsBitmapCallback_t callback)
{
@@ -613,6 +679,7 @@
a->read(data);
}
+#endif //ANDROID_RS_BUILD_FOR_HOST
}
}
diff --git a/libs/rs/rsAllocation.h b/libs/rs/rsAllocation.h
index 516f8b7..a408a57 100644
--- a/libs/rs/rsAllocation.h
+++ b/libs/rs/rsAllocation.h
@@ -72,6 +72,9 @@
void removeProgramToDirty(const Program *);
virtual void dumpLOGV(const char *prefix) const;
+ virtual void serialize(OStream *stream) const;
+ virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_ALLOCATION; }
+ static Allocation *createFromStream(Context *rsc, IStream *stream);
virtual void uploadCheck(const Context *rsc);
diff --git a/libs/rs/rsAnimation.cpp b/libs/rs/rsAnimation.cpp
new file mode 100644
index 0000000..6200715
--- /dev/null
+++ b/libs/rs/rsAnimation.cpp
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_RS_BUILD_FOR_HOST
+#include "rsContext.h"
+#else
+#include "rsContextHostStub.h"
+#endif //ANDROID_RS_BUILD_FOR_HOST
+
+#include "rsAnimation.h"
+
+
+using namespace android;
+using namespace android::renderscript;
+
+void Animation::serialize(OStream *stream) const
+{
+
+}
+
+Animation *Animation::createFromStream(Context *rsc, IStream *stream)
+{
+ return NULL;
+}
+
+/*
+Animation::Animation(Context *rsc) : ObjectBase(rsc)
+{
+ mAllocFile = __FILE__;
+ mAllocLine = __LINE__;
+
+ mValuesInput = NULL;
+ mValuesOutput = NULL;
+ mValueCount = 0;
+ mInterpolation = RS_ANIMATION_INTERPOLATION_STEP;
+ mEdgePre = RS_ANIMATION_EDGE_UNDEFINED;
+ mEdgePost = RS_ANIMATION_EDGE_UNDEFINED;
+ mInputMin = 0;
+ mInputMax = 0;
+}
+
+Animation * Animation::create(Context *rsc,
+ const float *inValues, const float *outValues,
+ uint32_t valueCount, RsAnimationInterpolation interp,
+ RsAnimationEdge pre, RsAnimationEdge post)
+{
+ if (valueCount < 2) {
+ rsc->setError(RS_ERROR_BAD_VALUE, "Animations require more than 2 values.");
+ return NULL;
+ }
+ Animation *a = new Animation(rsc);
+ if (!a) {
+ rsc->setError(RS_ERROR_OUT_OF_MEMORY);
+ return NULL;
+ }
+
+ float *vin = (float *)malloc(valueCount * sizeof(float));
+ float *vout = (float *)malloc(valueCount * sizeof(float));
+ a->mValuesInput = vin;
+ a->mValuesOutput = vout;
+ if (a->mValuesInput == NULL || a->mValuesOutput == NULL) {
+ delete a;
+ rsc->setError(RS_ERROR_OUT_OF_MEMORY);
+ return NULL;
+ }
+
+ a->mEdgePre = pre;
+ a->mEdgePost = post;
+ a->mInterpolation = interp;
+ a->mValueCount = valueCount;
+
+ memcpy(vin, inValues, valueCount * sizeof(float));
+ memcpy(vout, outValues, valueCount * sizeof(float));
+ a->mInputMin = inValues[0];
+ a->mInputMax = inValues[0];
+
+ bool needSort = false;
+ for (uint32_t ct=1; ct < valueCount; ct++) {
+ if (a->mInputMin > vin[ct]) {
+ needSort = true;
+ a->mInputMin = vin[ct];
+ }
+ if (a->mInputMax < vin[ct]) {
+ a->mInputMax = vin[ct];
+ } else {
+ needSort = true;
+ }
+ }
+
+ while (1) {
+ bool changed = false;
+ for (uint32_t ct=1; ct < valueCount; ct++) {
+ if (vin[ct-1] > vin[ct]) {
+ float t = vin[ct-1];
+ vin[ct-1] = vin[ct];
+ vin[ct] = t;
+ t = vout[ct-1];
+ vout[ct-1] = vout[ct];
+ vout[ct] = t;
+ changed = true;
+ }
+ }
+ if (!changed) break;
+ }
+
+ return a;
+}
+*/
+
+
+/////////////////////////////////////////
+//
+
+namespace android {
+namespace renderscript {
+
+RsAnimation rsi_AnimationCreate(Context *rsc,
+ const float *inValues,
+ const float *outValues,
+ uint32_t valueCount,
+ RsAnimationInterpolation interp,
+ RsAnimationEdge pre,
+ RsAnimationEdge post)
+{
+ //LOGE("rsi_ElementCreate %i %i %i %i", dt, dk, norm, vecSize);
+ Animation *a = NULL;//Animation::create(rsc, inValues, outValues, valueCount, interp, pre, post);
+ if (a != NULL) {
+ a->incUserRef();
+ }
+ return (RsAnimation)a;
+}
+
+
+}
+}
+
diff --git a/libs/rs/rsAnimation.h b/libs/rs/rsAnimation.h
new file mode 100644
index 0000000..340314e
--- /dev/null
+++ b/libs/rs/rsAnimation.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_RS_ANIMATION_H
+#define ANDROID_RS_ANIMATION_H
+
+#include "rsUtils.h"
+#include "rsObjectBase.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+
+class Animation : public ObjectBase
+{
+public:
+ ~Animation();
+
+ static Animation * create(Context *rsc,
+ const float *inValues, const float *outValues,
+ uint32_t valueCount, RsAnimationInterpolation,
+ RsAnimationEdge pre, RsAnimationEdge post);
+
+ float eval(float) const;
+
+ virtual void serialize(OStream *stream) const;
+ virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_ANIMATION; }
+ static Animation *createFromStream(Context *rsc, IStream *stream);
+
+protected:
+ Animation(Context *rsc);
+
+
+
+ float evalInRange(float) const;
+
+
+
+ const float *mValuesInput;
+ const float *mValuesOutput;
+ uint32_t mValueCount;
+ RsAnimationInterpolation mInterpolation;
+ RsAnimationEdge mEdgePre;
+ RsAnimationEdge mEdgePost;
+
+ // derived
+ float mInputMin;
+ float mInputMax;
+};
+
+
+
+
+}
+}
+#endif //ANDROID_STRUCTURED_ELEMENT_H
+
diff --git a/libs/rs/rsComponent.cpp b/libs/rs/rsComponent.cpp
index 15a56f7..b120c21 100644
--- a/libs/rs/rsComponent.cpp
+++ b/libs/rs/rsComponent.cpp
@@ -16,7 +16,11 @@
#include "rsComponent.h"
+#ifndef ANDROID_RS_BUILD_FOR_HOST
#include <GLES/gl.h>
+#else
+#include <OpenGL/gl.h>
+#endif
using namespace android;
using namespace android::renderscript;
@@ -334,4 +338,25 @@
prefix, gTypeStrings[mType], gKindStrings[mKind], mVectorSize, mBits);
}
+void Component::serialize(OStream *stream) const
+{
+ stream->addU8((uint8_t)mType);
+ stream->addU8((uint8_t)mKind);
+ stream->addU8((uint8_t)(mNormalized ? 1 : 0));
+ stream->addU32(mVectorSize);
+}
+
+void Component::loadFromStream(IStream *stream)
+{
+ mType = (RsDataType)stream->loadU8();
+ mKind = (RsDataKind)stream->loadU8();
+ uint8_t temp = stream->loadU8();
+ mNormalized = temp != 0;
+ mVectorSize = stream->loadU32();
+
+ set(mType, mKind, mNormalized, mVectorSize);
+}
+
+
+
diff --git a/libs/rs/rsComponent.h b/libs/rs/rsComponent.h
index 71de324..0f93a91 100644
--- a/libs/rs/rsComponent.h
+++ b/libs/rs/rsComponent.h
@@ -48,6 +48,10 @@
bool getIsSigned() const {return mIsSigned;}
uint32_t getBits() const {return mBits;}
+ // Helpers for reading / writing this class out
+ void serialize(OStream *stream) const;
+ void loadFromStream(IStream *stream);
+
protected:
RsDataType mType;
RsDataKind mKind;
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index d8a9a99..449e5dc 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -127,14 +127,14 @@
}
-uint32_t Context::runScript(Script *s, uint32_t launchID)
+uint32_t Context::runScript(Script *s)
{
ObjectBaseRef<ProgramFragment> frag(mFragment);
ObjectBaseRef<ProgramVertex> vtx(mVertex);
- ObjectBaseRef<ProgramFragmentStore> store(mFragmentStore);
+ ObjectBaseRef<ProgramStore> store(mFragmentStore);
ObjectBaseRef<ProgramRaster> raster(mRaster);
- uint32_t ret = s->run(this, launchID);
+ uint32_t ret = s->run(this);
mFragment.set(frag);
mVertex.set(vtx);
@@ -153,29 +153,11 @@
uint32_t Context::runRootScript()
{
- timerSet(RS_TIMER_CLEAR_SWAP);
- rsAssert(mRootScript->mEnviroment.mIsRoot);
-
- eglQuerySurface(mEGL.mDisplay, mEGL.mSurface, EGL_WIDTH, &mEGL.mWidth);
- eglQuerySurface(mEGL.mDisplay, mEGL.mSurface, EGL_HEIGHT, &mEGL.mHeight);
- glViewport(0, 0, mEGL.mWidth, mEGL.mHeight);
- glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
-
- glClearColor(mRootScript->mEnviroment.mClearColor[0],
- mRootScript->mEnviroment.mClearColor[1],
- mRootScript->mEnviroment.mClearColor[2],
- mRootScript->mEnviroment.mClearColor[3]);
- if (mUseDepth) {
- glDepthMask(GL_TRUE);
- glClearDepthf(mRootScript->mEnviroment.mClearDepth);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- } else {
- glClear(GL_COLOR_BUFFER_BIT);
- }
+ glViewport(0, 0, mWidth, mHeight);
timerSet(RS_TIMER_SCRIPT);
mStateFragmentStore.mLast.clear();
- uint32_t ret = runScript(mRootScript.get(), 0);
+ uint32_t ret = runScript(mRootScript.get());
checkError("runRootScript");
if (mError != RS_ERROR_NONE) {
@@ -300,13 +282,13 @@
}
if (rsc->mIsGraphicsContext) {
- rsc->mStateRaster.init(rsc, rsc->mEGL.mWidth, rsc->mEGL.mHeight);
+ rsc->mStateRaster.init(rsc);
rsc->setRaster(NULL);
- rsc->mStateVertex.init(rsc, rsc->mEGL.mWidth, rsc->mEGL.mHeight);
+ rsc->mStateVertex.init(rsc);
rsc->setVertex(NULL);
- rsc->mStateFragment.init(rsc, rsc->mEGL.mWidth, rsc->mEGL.mHeight);
+ rsc->mStateFragment.init(rsc);
rsc->setFragment(NULL);
- rsc->mStateFragmentStore.init(rsc, rsc->mEGL.mWidth, rsc->mEGL.mHeight);
+ rsc->mStateFragmentStore.init(rsc);
rsc->setFragmentStore(NULL);
rsc->mStateVertexArray.init(rsc);
}
@@ -486,14 +468,14 @@
checkEglError("eglDestroySurface", ret);
mEGL.mSurface = NULL;
- mEGL.mWidth = 0;
- mEGL.mHeight = 0;
mWidth = 0;
mHeight = 0;
}
mWndSurface = sur;
if (mWndSurface != NULL) {
+ mWidth = w;
+ mHeight = h;
bool first = false;
if (!mEGL.mContext) {
first = true;
@@ -511,15 +493,7 @@
ret = eglMakeCurrent(mEGL.mDisplay, mEGL.mSurface, mEGL.mSurface, mEGL.mContext);
checkEglError("eglMakeCurrent", ret);
- eglQuerySurface(mEGL.mDisplay, mEGL.mSurface, EGL_WIDTH, &mEGL.mWidth);
- eglQuerySurface(mEGL.mDisplay, mEGL.mSurface, EGL_HEIGHT, &mEGL.mHeight);
- mWidth = w;
- mHeight = h;
- mStateVertex.updateSize(this, w, h);
-
- if ((int)mWidth != mEGL.mWidth || (int)mHeight != mEGL.mHeight) {
- LOGE("EGL/Surface mismatch EGL (%i x %i) SF (%i x %i)", mEGL.mWidth, mEGL.mHeight, mWidth, mHeight);
- }
+ mStateVertex.updateSize(this);
if (first) {
mGL.mVersion = glGetString(GL_VERSION);
@@ -583,7 +557,7 @@
mRootScript.set(s);
}
-void Context::setFragmentStore(ProgramFragmentStore *pfs)
+void Context::setFragmentStore(ProgramStore *pfs)
{
rsAssert(mIsGraphicsContext);
if (pfs == NULL) {
@@ -640,32 +614,9 @@
}
}
-ObjectBase * Context::lookupName(const char *name) const
-{
- for(size_t ct=0; ct < mNames.size(); ct++) {
- if (!strcmp(name, mNames[ct]->getName())) {
- return mNames[ct];
- }
- }
- return NULL;
-}
-
-void Context::appendNameDefines(String8 *str) const
-{
- char buf[256];
- for (size_t ct=0; ct < mNames.size(); ct++) {
- str->append("#define NAMED_");
- str->append(mNames[ct]->getName());
- str->append(" ");
- sprintf(buf, "%i\n", (int)mNames[ct]);
- str->append(buf);
- }
-}
-
bool Context::objDestroyOOBInit()
{
- int status = pthread_mutex_init(&mObjDestroy.mMutex, NULL);
- if (status) {
+ if (!mObjDestroy.mMutex.init()) {
LOGE("Context::ObjDestroyOOBInit mutex init failure");
return false;
}
@@ -675,9 +626,8 @@
void Context::objDestroyOOBRun()
{
if (mObjDestroy.mNeedToEmpty) {
- int status = pthread_mutex_lock(&mObjDestroy.mMutex);
- if (status) {
- LOGE("Context::ObjDestroyOOBRun: error %i locking for OOBRun.", status);
+ if (!mObjDestroy.mMutex.lock()) {
+ LOGE("Context::ObjDestroyOOBRun: error locking for OOBRun.");
return;
}
@@ -686,35 +636,25 @@
}
mObjDestroy.mDestroyList.clear();
mObjDestroy.mNeedToEmpty = false;
-
- status = pthread_mutex_unlock(&mObjDestroy.mMutex);
- if (status) {
- LOGE("Context::ObjDestroyOOBRun: error %i unlocking for set condition.", status);
- }
+ mObjDestroy.mMutex.unlock();
}
}
void Context::objDestroyOOBDestroy()
{
rsAssert(!mObjDestroy.mNeedToEmpty);
- pthread_mutex_destroy(&mObjDestroy.mMutex);
}
void Context::objDestroyAdd(ObjectBase *obj)
{
- int status = pthread_mutex_lock(&mObjDestroy.mMutex);
- if (status) {
- LOGE("Context::ObjDestroyOOBRun: error %i locking for OOBRun.", status);
+ if (!mObjDestroy.mMutex.lock()) {
+ LOGE("Context::ObjDestroyOOBRun: error locking for OOBRun.");
return;
}
mObjDestroy.mNeedToEmpty = true;
mObjDestroy.mDestroyList.add(obj);
-
- status = pthread_mutex_unlock(&mObjDestroy.mMutex);
- if (status) {
- LOGE("Context::ObjDestroyOOBRun: error %i unlocking for set condition.", status);
- }
+ mObjDestroy.mMutex.unlock();
}
uint32_t Context::getMessageToClient(void *data, size_t *receiveLen, size_t bufferLen, bool wait)
@@ -799,8 +739,7 @@
LOGE("RS Context debug");
LOGE(" EGL ver %i %i", mEGL.mMajorVersion, mEGL.mMinorVersion);
- LOGE(" EGL context %p surface %p, w=%i h=%i Display=%p", mEGL.mContext,
- mEGL.mSurface, mEGL.mWidth, mEGL.mHeight, mEGL.mDisplay);
+ LOGE(" EGL context %p surface %p, Display=%p", mEGL.mContext, mEGL.mSurface, mEGL.mDisplay);
LOGE(" GL vendor: %s", mGL.mVendor);
LOGE(" GL renderer: %s", mGL.mRenderer);
LOGE(" GL Version: %s", mGL.mVersion);
@@ -841,9 +780,9 @@
s->bindToContext(&rsc->mStateSampler, slot);
}
-void rsi_ContextBindProgramFragmentStore(Context *rsc, RsProgramFragmentStore vpfs)
+void rsi_ContextBindProgramStore(Context *rsc, RsProgramStore vpfs)
{
- ProgramFragmentStore *pfs = static_cast<ProgramFragmentStore *>(vpfs);
+ ProgramStore *pfs = static_cast<ProgramStore *>(vpfs);
rsc->setFragmentStore(pfs);
}
diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h
index 82c3687..31bf5d6 100644
--- a/libs/rs/rsContext.h
+++ b/libs/rs/rsContext.h
@@ -18,6 +18,7 @@
#define ANDROID_RS_CONTEXT_H
#include "rsUtils.h"
+#include "rsMutex.h"
#include "rsThreadIO.h"
#include "rsType.h"
@@ -32,7 +33,7 @@
#include "rsSampler.h"
#include "rsLight.h"
#include "rsProgramFragment.h"
-#include "rsProgramFragmentStore.h"
+#include "rsProgramStore.h"
#include "rsProgramRaster.h"
#include "rsProgramVertex.h"
#include "rsShaderCache.h"
@@ -70,7 +71,7 @@
TypeState mStateType;
SamplerState mStateSampler;
ProgramFragmentState mStateFragment;
- ProgramFragmentStoreState mStateFragmentStore;
+ ProgramStoreState mStateFragmentStore;
ProgramRasterState mStateRaster;
ProgramVertexState mStateVertex;
LightState mStateLight;
@@ -84,12 +85,12 @@
void setRaster(ProgramRaster *);
void setVertex(ProgramVertex *);
void setFragment(ProgramFragment *);
- void setFragmentStore(ProgramFragmentStore *);
+ void setFragmentStore(ProgramStore *);
void updateSurface(void *sur);
const ProgramFragment * getFragment() {return mFragment.get();}
- const ProgramFragmentStore * getFragmentStore() {return mFragmentStore.get();}
+ const ProgramStore * getFragmentStore() {return mFragmentStore.get();}
const ProgramRaster * getRaster() {return mRaster.get();}
const ProgramVertex * getVertex() {return mVertex.get();}
@@ -103,12 +104,10 @@
void assignName(ObjectBase *obj, const char *name, uint32_t len);
void removeName(ObjectBase *obj);
- ObjectBase * lookupName(const char *name) const;
- void appendNameDefines(String8 *str) const;
uint32_t getMessageToClient(void *data, size_t *receiveLen, size_t bufferLen, bool wait);
bool sendMessageToClient(void *data, uint32_t cmdID, size_t len, bool waitForSpace);
- uint32_t runScript(Script *s, uint32_t launchID);
+ uint32_t runScript(Script *s);
void initToClient();
void deinitToClient();
@@ -119,15 +118,15 @@
ProgramVertex * getDefaultProgramVertex() const {
return mStateVertex.mDefault.get();
}
- ProgramFragmentStore * getDefaultProgramFragmentStore() const {
+ ProgramStore * getDefaultProgramStore() const {
return mStateFragmentStore.mDefault.get();
}
ProgramRaster * getDefaultProgramRaster() const {
return mStateRaster.mDefault.get();
}
- uint32_t getWidth() const {return mEGL.mWidth;}
- uint32_t getHeight() const {return mEGL.mHeight;}
+ uint32_t getWidth() const {return mWidth;}
+ uint32_t getHeight() const {return mHeight;}
ThreadIO mIO;
@@ -161,7 +160,7 @@
void dumpDebug() const;
void checkError(const char *) const;
const char * getError(RsError *);
- void setError(RsError e, const char *msg);
+ void setError(RsError e, const char *msg = NULL);
mutable const ObjectBase * mObjHead;
@@ -177,8 +176,6 @@
EGLConfig mConfig;
EGLContext mContext;
EGLSurface mSurface;
- EGLint mWidth;
- EGLint mHeight;
EGLDisplay mDisplay;
} mEGL;
@@ -222,12 +219,12 @@
ObjectBaseRef<Script> mRootScript;
ObjectBaseRef<ProgramFragment> mFragment;
ObjectBaseRef<ProgramVertex> mVertex;
- ObjectBaseRef<ProgramFragmentStore> mFragmentStore;
+ ObjectBaseRef<ProgramStore> mFragmentStore;
ObjectBaseRef<ProgramRaster> mRaster;
struct ObjDestroyOOB {
- pthread_mutex_t mMutex;
+ Mutex mMutex;
Vector<ObjectBase *> mDestroyList;
bool mNeedToEmpty;
};
diff --git a/libs/rs/rsContextHostStub.h b/libs/rs/rsContextHostStub.h
new file mode 100644
index 0000000..be1fff6
--- /dev/null
+++ b/libs/rs/rsContextHostStub.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_RS_CONTEXT_HOST_STUB_H
+#define ANDROID_RS_CONTEXT_HOST_STUB_H
+
+#include "rsUtils.h"
+//#include "rsMutex.h"
+
+//#include "rsThreadIO.h"
+#include "rsType.h"
+#include "rsMatrix.h"
+#include "rsAllocation.h"
+#include "rsSimpleMesh.h"
+#include "rsMesh.h"
+//#include "rsDevice.h"
+#include "rsScriptC.h"
+#include "rsAllocation.h"
+#include "rsAdapter.h"
+#include "rsSampler.h"
+#include "rsLight.h"
+#include "rsProgramFragment.h"
+#include "rsProgramStore.h"
+#include "rsProgramRaster.h"
+#include "rsProgramVertex.h"
+#include "rsShaderCache.h"
+#include "rsVertexArray.h"
+
+//#include "rsgApiStructs.h"
+//#include "rsLocklessFifo.h"
+
+//#include <ui/egl/android_natives.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+namespace renderscript {
+
+class Device;
+
+class Context
+{
+public:
+ Context(Device *, bool isGraphics, bool useDepth) {
+ mObjHead = NULL;
+ }
+ ~Context() {
+ }
+
+
+ //StructuredAllocationContext mStateAllocation;
+ ElementState mStateElement;
+ TypeState mStateType;
+ SamplerState mStateSampler;
+ //ProgramFragmentState mStateFragment;
+ ProgramStoreState mStateFragmentStore;
+ //ProgramRasterState mStateRaster;
+ //ProgramVertexState mStateVertex;
+ LightState mStateLight;
+ VertexArrayState mStateVertexArray;
+
+ //ScriptCState mScriptC;
+ ShaderCache mShaderCache;
+
+
+ //bool setupCheck();
+ bool checkDriver() const {return false;}
+
+ ProgramFragment * getDefaultProgramFragment() const {
+ return NULL;
+ }
+ ProgramVertex * getDefaultProgramVertex() const {
+ return NULL;
+ }
+ ProgramStore * getDefaultProgramStore() const {
+ return NULL;
+ }
+ ProgramRaster * getDefaultProgramRaster() const {
+ return NULL;
+ }
+
+ uint32_t getWidth() const {return 0;}
+ uint32_t getHeight() const {return 0;}
+
+ // Timers
+ enum Timers {
+ RS_TIMER_IDLE,
+ RS_TIMER_INTERNAL,
+ RS_TIMER_SCRIPT,
+ RS_TIMER_CLEAR_SWAP,
+ _RS_TIMER_TOTAL
+ };
+
+ bool checkVersion1_1() const {return false; }
+ bool checkVersion2_0() const {return false; }
+
+ struct {
+ bool mLogTimes;
+ bool mLogScripts;
+ bool mLogObjects;
+ bool mLogShaders;
+ } props;
+
+ void dumpDebug() const { }
+ void checkError(const char *) const { };
+ void setError(RsError e, const char *msg = NULL) { }
+
+ mutable const ObjectBase * mObjHead;
+
+ bool ext_OES_texture_npot() const {return mGL.OES_texture_npot;}
+
+protected:
+
+ struct {
+ const uint8_t * mVendor;
+ const uint8_t * mRenderer;
+ const uint8_t * mVersion;
+ const uint8_t * mExtensions;
+
+ uint32_t mMajorVersion;
+ uint32_t mMinorVersion;
+
+ int32_t mMaxVaryingVectors;
+ int32_t mMaxTextureImageUnits;
+
+ int32_t mMaxFragmentTextureImageUnits;
+ int32_t mMaxFragmentUniformVectors;
+
+ int32_t mMaxVertexAttribs;
+ int32_t mMaxVertexUniformVectors;
+ int32_t mMaxVertexTextureUnits;
+
+ bool OES_texture_npot;
+ } mGL;
+
+};
+
+}
+}
+#endif
diff --git a/libs/rs/rsDevice.cpp b/libs/rs/rsDevice.cpp
index b670ad4..a96b114 100644
--- a/libs/rs/rsDevice.cpp
+++ b/libs/rs/rsDevice.cpp
@@ -15,7 +15,11 @@
*/
#include "rsDevice.h"
+#ifndef ANDROID_RS_BUILD_FOR_HOST
#include "rsContext.h"
+#else
+#include "rsContextHostStub.h"
+#endif
using namespace android;
using namespace android::renderscript;
@@ -33,7 +37,7 @@
void Device::addContext(Context *rsc)
{
- mContexts.add(rsc);
+ mContexts.push(rsc);
}
void Device::removeContext(Context *rsc)
diff --git a/libs/rs/rsElement.cpp b/libs/rs/rsElement.cpp
index 6288bc4..8fbf004 100644
--- a/libs/rs/rsElement.cpp
+++ b/libs/rs/rsElement.cpp
@@ -14,9 +14,14 @@
* limitations under the License.
*/
-#include "rsContext.h"
+#ifndef ANDROID_RS_BUILD_FOR_HOST
+#include "rsContext.h"
#include <GLES/gl.h>
+#else
+#include "rsContextHostStub.h"
+#include <OpenGL/gl.h>
+#endif
using namespace android;
using namespace android::renderscript;
@@ -83,6 +88,90 @@
}
}
+void Element::serialize(OStream *stream) const
+{
+ // Need to identify ourselves
+ stream->addU32((uint32_t)getClassId());
+
+ String8 name(getName());
+ stream->addString(&name);
+
+ mComponent.serialize(stream);
+
+ // Now serialize all the fields
+ stream->addU32(mFieldCount);
+ for(uint32_t ct = 0; ct < mFieldCount; ct++) {
+ stream->addString(&mFields[ct].name);
+ mFields[ct].e->serialize(stream);
+ }
+}
+
+Element *Element::createFromStream(Context *rsc, IStream *stream)
+{
+ // First make sure we are reading the correct object
+ RsA3DClassID classID = (RsA3DClassID)stream->loadU32();
+ if(classID != RS_A3D_CLASS_ID_ELEMENT) {
+ LOGE("element loading skipped due to invalid class id\n");
+ return NULL;
+ }
+
+ String8 name;
+ stream->loadString(&name);
+
+ Element *elem = new Element(rsc);
+ elem->mComponent.loadFromStream(stream);
+ elem->mBits = elem->mComponent.getBits();
+
+ elem->mFieldCount = stream->loadU32();
+ if(elem->mFieldCount) {
+ elem->mFields = new ElementField_t [elem->mFieldCount];
+ for(uint32_t ct = 0; ct < elem->mFieldCount; ct ++) {
+ stream->loadString(&elem->mFields[ct].name);
+ Element *fieldElem = Element::createFromStream(rsc, stream);
+ elem->mFields[ct].e.set(fieldElem);
+ }
+ }
+
+ // We need to check if this already exists
+ for (uint32_t ct=0; ct < rsc->mStateElement.mElements.size(); ct++) {
+ Element *ee = rsc->mStateElement.mElements[ct];
+
+ if (!ee->getFieldCount() ) {
+
+ if((ee->getComponent().getType() == elem->getComponent().getType()) &&
+ (ee->getComponent().getKind() == elem->getComponent().getKind()) &&
+ (ee->getComponent().getIsNormalized() == elem->getComponent().getIsNormalized()) &&
+ (ee->getComponent().getVectorSize() == elem->getComponent().getVectorSize())) {
+ // Match
+ delete elem;
+ ee->incUserRef();
+ return ee;
+ }
+
+ } else if (ee->getFieldCount() == elem->mFieldCount) {
+
+ bool match = true;
+ for (uint32_t i=0; i < elem->mFieldCount; i++) {
+ if ((ee->mFields[i].e.get() != elem->mFields[i].e.get()) ||
+ (ee->mFields[i].name.length() != elem->mFields[i].name.length()) ||
+ (ee->mFields[i].name != elem->mFields[i].name)) {
+ match = false;
+ break;
+ }
+ }
+ if (match) {
+ delete elem;
+ ee->incUserRef();
+ return ee;
+ }
+
+ }
+ }
+
+ rsc->mStateElement.mElements.push(elem);
+ return elem;
+}
+
const Element * Element::create(Context *rsc, RsDataType dt, RsDataKind dk,
bool isNorm, uint32_t vecSize)
diff --git a/libs/rs/rsElement.h b/libs/rs/rsElement.h
index 02a1ca2..5c4f5c4 100644
--- a/libs/rs/rsElement.h
+++ b/libs/rs/rsElement.h
@@ -59,6 +59,9 @@
String8 getGLSLType(uint32_t indent=0) const;
void dumpLOGV(const char *prefix) const;
+ virtual void serialize(OStream *stream) const;
+ virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_ELEMENT; }
+ static Element *createFromStream(Context *rsc, IStream *stream);
static const Element * create(Context *rsc, RsDataType dt, RsDataKind dk,
bool isNorm, uint32_t vecSize);
@@ -90,7 +93,7 @@
~ElementState();
// Cache of all existing elements.
- Vector<const Element *> mElements;
+ Vector<Element *> mElements;
};
diff --git a/libs/rs/rsFileA3D.cpp b/libs/rs/rsFileA3D.cpp
index e3272c5..23c0cf5 100644
--- a/libs/rs/rsFileA3D.cpp
+++ b/libs/rs/rsFileA3D.cpp
@@ -15,29 +15,155 @@
* limitations under the License.
*/
+#ifndef ANDROID_RS_BUILD_FOR_HOST
#include "rsContext.h"
+#else
+#include "rsContextHostStub.h"
+#endif
-
-#include <utils/String8.h>
#include "rsFileA3D.h"
#include "rsMesh.h"
+#include "rsAnimation.h"
using namespace android;
using namespace android::renderscript;
-
-
-FileA3D::FileA3D()
+FileA3D::FileA3D(Context *rsc) : ObjectBase(rsc)
{
- mRsc = NULL;
+ mAlloc = NULL;
+ mData = NULL;
+ mWriteStream = NULL;
+ mReadStream = NULL;
+
+ mMajorVersion = 0;
+ mMinorVersion = 1;
+ mDataSize = 0;
}
FileA3D::~FileA3D()
{
+ for(size_t i = 0; i < mIndex.size(); i ++) {
+ delete mIndex[i];
+ }
+ for(size_t i = 0; i < mWriteIndex.size(); i ++) {
+ delete mWriteIndex[i];
+ }
+ if(mWriteStream) {
+ delete mWriteStream;
+ }
+ if(mReadStream) {
+ delete mWriteStream;
+ }
+ if(mAlloc) {
+ free(mAlloc);
+ }
}
-bool FileA3D::load(Context *rsc, FILE *f)
+void FileA3D::parseHeader(IStream *headerStream)
+{
+ mMajorVersion = headerStream->loadU32();
+ mMinorVersion = headerStream->loadU32();
+ uint32_t flags = headerStream->loadU32();
+ mUse64BitOffsets = (flags & 1) != 0;
+
+ LOGE("file open 64bit = %i", mUse64BitOffsets);
+
+ uint32_t numIndexEntries = headerStream->loadU32();
+ for(uint32_t i = 0; i < numIndexEntries; i ++) {
+ A3DIndexEntry *entry = new A3DIndexEntry();
+ headerStream->loadString(&entry->mObjectName);
+ LOGE("Header data, entry name = %s", entry->mObjectName.string());
+ entry->mType = (RsA3DClassID)headerStream->loadU32();
+ if(mUse64BitOffsets){
+ entry->mOffset = headerStream->loadOffset();
+ entry->mLength = headerStream->loadOffset();
+ }
+ else {
+ entry->mOffset = headerStream->loadU32();
+ entry->mLength = headerStream->loadU32();
+ }
+ entry->mRsObj = NULL;
+ mIndex.push(entry);
+ }
+}
+
+bool FileA3D::load(const void *data, size_t length)
+{
+ LOGE("Loading data. Size: %u", length);
+ const uint8_t *localData = (const uint8_t *)data;
+
+ size_t lengthRemaining = length;
+ size_t magicStrLen = 12;
+ if ((length < magicStrLen) ||
+ memcmp(data, "Android3D_ff", magicStrLen)) {
+ return false;
+ }
+
+ localData += magicStrLen;
+ lengthRemaining -= magicStrLen;
+
+ // Next we get our header size
+ uint64_t headerSize = 0;
+ if(lengthRemaining < sizeof(headerSize)) {
+ return false;
+ }
+
+ memcpy(&headerSize, localData, sizeof(headerSize));
+ localData += sizeof(headerSize);
+ lengthRemaining -= sizeof(headerSize);
+
+ LOGE("Loading data, headerSize = %lli", headerSize);
+
+ if(lengthRemaining < headerSize) {
+ return false;
+ }
+
+ uint8_t *headerData = (uint8_t *)malloc(headerSize);
+ if(!headerData) {
+ return false;
+ }
+
+ memcpy(headerData, localData, headerSize);
+
+ // Now open the stream to parse the header
+ IStream headerStream(headerData, false);
+ parseHeader(&headerStream);
+
+ free(headerData);
+
+ localData += headerSize;
+ lengthRemaining -= headerSize;
+
+ if(lengthRemaining < sizeof(mDataSize)) {
+ return false;
+ }
+
+ // Read the size of the data
+ memcpy(&mDataSize, localData, sizeof(mDataSize));
+ localData += sizeof(mDataSize);
+ lengthRemaining -= sizeof(mDataSize);
+
+ LOGE("Loading data, mDataSize = %lli", mDataSize);
+
+ if(lengthRemaining < mDataSize) {
+ return false;
+ }
+
+ // We should know enough to read the file in at this point.
+ mAlloc = malloc(mDataSize);
+ if (!mAlloc) {
+ return false;
+ }
+ mData = (uint8_t *)mAlloc;
+ memcpy(mAlloc, localData, mDataSize);
+
+ mReadStream = new IStream(mData, mUse64BitOffsets);
+
+ return true;
+}
+
+bool FileA3D::load(FILE *f)
{
char magicString[12];
size_t len;
@@ -49,47 +175,39 @@
return false;
}
- LOGE("file open 2");
- len = fread(&mMajorVersion, 1, sizeof(mMajorVersion), f);
- if (len != sizeof(mMajorVersion)) {
+ // Next thing is the size of the header
+ uint64_t headerSize = 0;
+ len = fread(&headerSize, 1, sizeof(headerSize), f);
+ if (len != sizeof(headerSize) || headerSize == 0) {
return false;
}
- LOGE("file open 3");
- len = fread(&mMinorVersion, 1, sizeof(mMinorVersion), f);
- if (len != sizeof(mMinorVersion)) {
+ uint8_t *headerData = (uint8_t *)malloc(headerSize);
+ if(!headerData) {
return false;
}
- LOGE("file open 4");
- uint32_t flags;
- len = fread(&flags, 1, sizeof(flags), f);
- if (len != sizeof(flags)) {
+ len = fread(headerData, 1, headerSize, f);
+ if (len != headerSize) {
return false;
}
- mUse64BitOffsets = (flags & 1) != 0;
- LOGE("file open 64bit = %i", mUse64BitOffsets);
+ // Now open the stream to parse the header
+ IStream headerStream(headerData, false);
+ parseHeader(&headerStream);
- if (mUse64BitOffsets) {
- len = fread(&mDataSize, 1, sizeof(mDataSize), f);
- if (len != sizeof(mDataSize)) {
- return false;
- }
- } else {
- uint32_t tmp;
- len = fread(&tmp, 1, sizeof(tmp), f);
- if (len != sizeof(tmp)) {
- return false;
- }
- mDataSize = tmp;
+ free(headerData);
+
+ // Next thing is the size of the header
+ len = fread(&mDataSize, 1, sizeof(mDataSize), f);
+ if (len != sizeof(mDataSize) || mDataSize == 0) {
+ return false;
}
LOGE("file open size = %lli", mDataSize);
// We should know enough to read the file in at this point.
- fseek(f, SEEK_SET, 0);
- mAlloc= malloc(mDataSize);
+ mAlloc = malloc(mDataSize);
if (!mAlloc) {
return false;
}
@@ -99,282 +217,258 @@
return false;
}
- LOGE("file start processing");
- return process(rsc);
+ mReadStream = new IStream(mData, mUse64BitOffsets);
+
+ LOGE("Header is read an stream initialized");
+ return true;
}
-bool FileA3D::processIndex(Context *rsc, A3DIndexEntry *ie)
-{
- bool ret = false;
- IO io(mData + ie->mOffset, mUse64BitOffsets);
+size_t FileA3D::getNumIndexEntries() const {
+ return mIndex.size();
+}
- LOGE("process index, type %i", ie->mType);
-
- switch(ie->mType) {
- case CHUNK_ELEMENT:
- processChunk_Element(rsc, &io, ie);
- break;
- case CHUNK_ELEMENT_SOURCE:
- processChunk_ElementSource(rsc, &io, ie);
- break;
- case CHUNK_VERTICIES:
- processChunk_Verticies(rsc, &io, ie);
- break;
- case CHUNK_MESH:
- processChunk_Mesh(rsc, &io, ie);
- break;
- case CHUNK_PRIMITIVE:
- processChunk_Primitive(rsc, &io, ie);
- break;
- default:
- LOGE("FileA3D Unknown chunk type");
- break;
+const FileA3D::A3DIndexEntry *FileA3D::getIndexEntry(size_t index) const {
+ if(index < mIndex.size()) {
+ return mIndex[index];
}
- return (ie->mRsObj != NULL);
+ return NULL;
}
-bool FileA3D::process(Context *rsc)
-{
- LOGE("process");
- IO io(mData + 12, mUse64BitOffsets);
- bool ret = true;
-
- // Build the index first
- LOGE("process 1");
- io.loadU32(); // major version, already loaded
- io.loadU32(); // minor version, already loaded
- LOGE("process 2");
-
- io.loadU32(); // flags
- io.loadOffset(); // filesize, already loaded.
- LOGE("process 4");
- uint64_t mIndexOffset = io.loadOffset();
- uint64_t mStringOffset = io.loadOffset();
-
- LOGE("process mIndexOffset= 0x%016llx", mIndexOffset);
- LOGE("process mStringOffset= 0x%016llx", mStringOffset);
-
- IO index(mData + mIndexOffset, mUse64BitOffsets);
- IO stringTable(mData + mStringOffset, mUse64BitOffsets);
-
- uint32_t stringEntryCount = stringTable.loadU32();
- LOGE("stringEntryCount %i", stringEntryCount);
- mStrings.setCapacity(stringEntryCount);
- mStringIndexValues.setCapacity(stringEntryCount);
- if (stringEntryCount) {
- uint32_t stringType = stringTable.loadU32();
- LOGE("stringType %i", stringType);
- rsAssert(stringType==0);
- for (uint32_t ct = 0; ct < stringEntryCount; ct++) {
- uint64_t offset = stringTable.loadOffset();
- LOGE("string offset 0x%016llx", offset);
- IO tmp(mData + offset, mUse64BitOffsets);
- String8 s;
- tmp.loadString(&s);
- LOGE("string %s", s.string());
- mStrings.push(s);
- }
+ObjectBase *FileA3D::initializeFromEntry(size_t index) {
+ if(index >= mIndex.size()) {
+ return NULL;
}
- LOGE("strings done");
- uint32_t indexEntryCount = index.loadU32();
- LOGE("index count %i", indexEntryCount);
- mIndex.setCapacity(indexEntryCount);
- for (uint32_t ct = 0; ct < indexEntryCount; ct++) {
- A3DIndexEntry e;
- uint32_t stringIndex = index.loadU32();
- LOGE("index %i", ct);
- LOGE(" string index %i", stringIndex);
- e.mType = (A3DChunkType)index.loadU32();
- LOGE(" type %i", e.mType);
- e.mOffset = index.loadOffset();
- LOGE(" offset 0x%016llx", e.mOffset);
-
- if (stringIndex && (stringIndex < mStrings.size())) {
- e.mID = mStrings[stringIndex];
- mStringIndexValues.editItemAt(stringIndex) = ct;
- LOGE(" id %s", e.mID.string());
- }
-
- mIndex.push(e);
- }
- LOGE("index done");
-
- // At this point the index should be fully populated.
- // We can now walk though it and load all the objects.
- for (uint32_t ct = 0; ct < indexEntryCount; ct++) {
- LOGE("processing index entry %i", ct);
- processIndex(rsc, &mIndex.editItemAt(ct));
+ FileA3D::A3DIndexEntry *entry = mIndex[index];
+ if(!entry) {
+ return NULL;
}
- return ret;
-}
-
-
-FileA3D::IO::IO(const uint8_t *buf, bool use64)
-{
- mData = buf;
- mPos = 0;
- mUse64 = use64;
-}
-
-uint64_t FileA3D::IO::loadOffset()
-{
- uint64_t tmp;
- if (mUse64) {
- mPos = (mPos + 7) & (~7);
- tmp = reinterpret_cast<const uint64_t *>(&mData[mPos])[0];
- mPos += sizeof(uint64_t);
- return tmp;
+ if(entry->mRsObj) {
+ entry->mRsObj->incUserRef();
+ return entry->mRsObj;
}
- return loadU32();
-}
-void FileA3D::IO::loadString(String8 *s)
-{
- LOGE("loadString");
- uint32_t len = loadU32();
- LOGE("loadString len %i", len);
- s->setTo((const char *)&mData[mPos], len);
- mPos += len;
-}
-
-
-void FileA3D::processChunk_Mesh(Context *rsc, IO *io, A3DIndexEntry *ie)
-{
- Mesh * m = new Mesh(rsc);
-
- m->mPrimitivesCount = io->loadU32();
- m->mPrimitives = new Mesh::Primitive_t *[m->mPrimitivesCount];
-
- for (uint32_t ct = 0; ct < m->mPrimitivesCount; ct++) {
- uint32_t index = io->loadU32();
-
- m->mPrimitives[ct] = (Mesh::Primitive_t *)mIndex[index].mRsObj;
- }
- ie->mRsObj = m;
-}
-
-void FileA3D::processChunk_Primitive(Context *rsc, IO *io, A3DIndexEntry *ie)
-{
- Mesh::Primitive_t * p = new Mesh::Primitive_t;
-
- p->mIndexCount = io->loadU32();
- uint32_t vertIdx = io->loadU32();
- p->mRestartCounts = io->loadU16();
- uint32_t bits = io->loadU8();
- p->mType = (RsPrimitive)io->loadU8();
-
- LOGE("processChunk_Primitive count %i, bits %i", p->mIndexCount, bits);
-
- p->mVerticies = (Mesh::Verticies_t *)mIndex[vertIdx].mRsObj;
-
- p->mIndicies = new uint16_t[p->mIndexCount];
- for (uint32_t ct = 0; ct < p->mIndexCount; ct++) {
- switch(bits) {
- case 8:
- p->mIndicies[ct] = io->loadU8();
+ // Seek to the beginning of object
+ mReadStream->reset(entry->mOffset);
+ switch (entry->mType) {
+ case RS_A3D_CLASS_ID_UNKNOWN:
+ return NULL;
+ case RS_A3D_CLASS_ID_MESH:
+ entry->mRsObj = Mesh::createFromStream(mRSC, mReadStream);
break;
- case 16:
- p->mIndicies[ct] = io->loadU16();
+ case RS_A3D_CLASS_ID_SIMPLE_MESH:
+ entry->mRsObj = SimpleMesh::createFromStream(mRSC, mReadStream);
break;
- case 32:
- p->mIndicies[ct] = io->loadU32();
+ case RS_A3D_CLASS_ID_TYPE:
+ entry->mRsObj = Type::createFromStream(mRSC, mReadStream);
break;
+ case RS_A3D_CLASS_ID_ELEMENT:
+ entry->mRsObj = Element::createFromStream(mRSC, mReadStream);
+ break;
+ case RS_A3D_CLASS_ID_ALLOCATION:
+ entry->mRsObj = Allocation::createFromStream(mRSC, mReadStream);
+ break;
+ case RS_A3D_CLASS_ID_PROGRAM_VERTEX:
+ entry->mRsObj = ProgramVertex::createFromStream(mRSC, mReadStream);
+ break;
+ case RS_A3D_CLASS_ID_PROGRAM_RASTER:
+ entry->mRsObj = ProgramRaster::createFromStream(mRSC, mReadStream);
+ break;
+ case RS_A3D_CLASS_ID_PROGRAM_FRAGMENT:
+ entry->mRsObj = ProgramFragment::createFromStream(mRSC, mReadStream);
+ break;
+ case RS_A3D_CLASS_ID_PROGRAM_STORE:
+ entry->mRsObj = ProgramStore::createFromStream(mRSC, mReadStream);
+ break;
+ case RS_A3D_CLASS_ID_SAMPLER:
+ entry->mRsObj = Sampler::createFromStream(mRSC, mReadStream);
+ break;
+ case RS_A3D_CLASS_ID_ANIMATION:
+ entry->mRsObj = Animation::createFromStream(mRSC, mReadStream);
+ break;
+ case RS_A3D_CLASS_ID_LIGHT:
+ entry->mRsObj = Light::createFromStream(mRSC, mReadStream);
+ break;
+ case RS_A3D_CLASS_ID_ADAPTER_1D:
+ entry->mRsObj = Adapter1D::createFromStream(mRSC, mReadStream);
+ break;
+ case RS_A3D_CLASS_ID_ADAPTER_2D:
+ entry->mRsObj = Adapter2D::createFromStream(mRSC, mReadStream);
+ break;
+ case RS_A3D_CLASS_ID_SCRIPT_C:
+ return NULL;
+ }
+ if(entry->mRsObj) {
+ entry->mRsObj->incUserRef();
+ }
+ return entry->mRsObj;
+}
+
+bool FileA3D::writeFile(const char *filename)
+{
+ if(!mWriteStream) {
+ LOGE("No objects to write\n");
+ return false;
+ }
+ if(mWriteStream->getPos() == 0) {
+ LOGE("No objects to write\n");
+ return false;
+ }
+
+ FILE *writeHandle = fopen(filename, "wb");
+ if(!writeHandle) {
+ LOGE("Couldn't open the file for writing\n");
+ return false;
+ }
+
+ // Open a new stream to make writing the header easier
+ OStream headerStream(5*1024, false);
+ headerStream.addU32(mMajorVersion);
+ headerStream.addU32(mMinorVersion);
+ uint32_t is64Bit = 0;
+ headerStream.addU32(is64Bit);
+
+ uint32_t writeIndexSize = mWriteIndex.size();
+ headerStream.addU32(writeIndexSize);
+ for(uint32_t i = 0; i < writeIndexSize; i ++) {
+ headerStream.addString(&mWriteIndex[i]->mObjectName);
+ headerStream.addU32((uint32_t)mWriteIndex[i]->mType);
+ if(mUse64BitOffsets){
+ headerStream.addOffset(mWriteIndex[i]->mOffset);
+ headerStream.addOffset(mWriteIndex[i]->mLength);
}
- LOGE(" idx %i", p->mIndicies[ct]);
- }
-
- if (p->mRestartCounts) {
- p->mRestarts = new uint16_t[p->mRestartCounts];
- for (uint32_t ct = 0; ct < p->mRestartCounts; ct++) {
- switch(bits) {
- case 8:
- p->mRestarts[ct] = io->loadU8();
- break;
- case 16:
- p->mRestarts[ct] = io->loadU16();
- break;
- case 32:
- p->mRestarts[ct] = io->loadU32();
- break;
- }
- LOGE(" idx %i", p->mRestarts[ct]);
+ else {
+ uint32_t offset = (uint32_t)mWriteIndex[i]->mOffset;
+ headerStream.addU32(offset);
+ offset = (uint32_t)mWriteIndex[i]->mLength;
+ headerStream.addU32(offset);
}
- } else {
- p->mRestarts = NULL;
}
- ie->mRsObj = p;
+ // Write our magic string so we know we are reading the right file
+ String8 magicString(A3D_MAGIC_KEY);
+ fwrite(magicString.string(), sizeof(char), magicString.size(), writeHandle);
+
+ // Store the size of the header to make it easier to parse when we read it
+ uint64_t headerSize = headerStream.getPos();
+ fwrite(&headerSize, sizeof(headerSize), 1, writeHandle);
+
+ // Now write our header
+ fwrite(headerStream.getPtr(), sizeof(uint8_t), headerStream.getPos(), writeHandle);
+
+ // Now write the size of the data part of the file for easier parsing later
+ uint64_t fileDataSize = mWriteStream->getPos();
+ fwrite(&fileDataSize, sizeof(fileDataSize), 1, writeHandle);
+
+ fwrite(mWriteStream->getPtr(), sizeof(uint8_t), mWriteStream->getPos(), writeHandle);
+
+ int status = fclose(writeHandle);
+
+ if(status != 0) {
+ LOGE("Couldn't close file\n");
+ return false;
+ }
+
+ return true;
}
-void FileA3D::processChunk_Verticies(Context *rsc, IO *io, A3DIndexEntry *ie)
-{
- Mesh::Verticies_t *cv = new Mesh::Verticies_t;
- cv->mAllocationCount = io->loadU32();
- cv->mAllocations = new Allocation *[cv->mAllocationCount];
- LOGE("processChunk_Verticies count %i", cv->mAllocationCount);
- for (uint32_t ct = 0; ct < cv->mAllocationCount; ct++) {
- uint32_t i = io->loadU32();
- cv->mAllocations[ct] = (Allocation *)mIndex[i].mRsObj;
- LOGE(" idx %i", i);
+void FileA3D::appendToFile(ObjectBase *obj) {
+ if(!obj) {
+ return;
}
- ie->mRsObj = cv;
-}
-
-void FileA3D::processChunk_Element(Context *rsc, IO *io, A3DIndexEntry *ie)
-{
- /*
- rsi_ElementBegin(rsc);
-
- uint32_t count = io->loadU32();
- LOGE("processChunk_Element count %i", count);
- while (count--) {
- RsDataKind dk = (RsDataKind)io->loadU8();
- RsDataType dt = (RsDataType)io->loadU8();
- uint32_t bits = io->loadU8();
- bool isNorm = io->loadU8() != 0;
- LOGE(" %i %i %i %i", dk, dt, bits, isNorm);
- rsi_ElementAdd(rsc, dk, dt, isNorm, bits, 0);
+ if(!mWriteStream) {
+ const uint64_t initialStreamSize = 256*1024;
+ mWriteStream = new OStream(initialStreamSize, false);
}
- LOGE("processChunk_Element create");
- ie->mRsObj = rsi_ElementCreate(rsc);
- */
-}
-
-void FileA3D::processChunk_ElementSource(Context *rsc, IO *io, A3DIndexEntry *ie)
-{
- uint32_t index = io->loadU32();
- uint32_t count = io->loadU32();
-
- LOGE("processChunk_ElementSource count %i, index %i", count, index);
-
- RsElement e = (RsElement)mIndex[index].mRsObj;
-
- RsAllocation a = rsi_AllocationCreateSized(rsc, e, count);
- Allocation * alloc = static_cast<Allocation *>(a);
-
- float * data = (float *)alloc->getPtr();
- while(count--) {
- *data = io->loadF();
- LOGE(" %f", *data);
- data++;
- }
- ie->mRsObj = alloc;
+ A3DIndexEntry *indexEntry = new A3DIndexEntry();
+ indexEntry->mObjectName.setTo(obj->getName());
+ indexEntry->mType = obj->getClassId();
+ indexEntry->mOffset = mWriteStream->getPos();
+ indexEntry->mRsObj = obj;
+ mWriteIndex.push(indexEntry);
+ obj->serialize(mWriteStream);
+ indexEntry->mLength = mWriteStream->getPos() - indexEntry->mOffset;
+ mWriteStream->align(4);
}
namespace android {
namespace renderscript {
+void rsi_FileA3DGetNumIndexEntries(Context *rsc, int32_t *numEntries, RsFile file)
+{
+ FileA3D *fa3d = static_cast<FileA3D *>(file);
+
+ if(fa3d) {
+ *numEntries = fa3d->getNumIndexEntries();
+ }
+ else {
+ *numEntries = 0;
+ }
+}
+
+void rsi_FileA3DGetIndexEntries(Context *rsc, RsFileIndexEntry *fileEntries, uint32_t numEntries, RsFile file)
+{
+ FileA3D *fa3d = static_cast<FileA3D *>(file);
+
+ if(!fa3d) {
+ LOGE("Can't load index entries. No valid file");
+ return;
+ }
+
+ uint32_t numFileEntries = fa3d->getNumIndexEntries();
+ if(numFileEntries != numEntries || numEntries == 0 || fileEntries == NULL) {
+ LOGE("Can't load index entries. Invalid number requested");
+ return;
+ }
+
+ for(uint32_t i = 0; i < numFileEntries; i ++) {
+ const FileA3D::A3DIndexEntry *entry = fa3d->getIndexEntry(i);
+ fileEntries[i].classID = entry->getType();
+ fileEntries[i].objectName = entry->getObjectName().string();
+ }
+
+}
+
+RsObjectBase rsi_FileA3DGetEntryByIndex(Context *rsc, uint32_t index, RsFile file)
+{
+ FileA3D *fa3d = static_cast<FileA3D *>(file);
+ if(!fa3d) {
+ LOGE("Can't load entry. No valid file");
+ return NULL;
+ }
+
+ ObjectBase *obj = fa3d->initializeFromEntry(index);
+ LOGE("Returning object with name %s", obj->getName());
+
+ return obj;
+}
+
+RsFile rsi_FileA3DCreateFromAssetStream(Context *rsc, const void *data, uint32_t len)
+{
+ if (data == NULL) {
+ LOGE("File load failed. Asset stream is NULL");
+ return NULL;
+ }
+
+ FileA3D *fa3d = new FileA3D(rsc);
+
+ fa3d->load(data, len);
+ fa3d->incUserRef();
+
+ return fa3d;
+}
+
RsFile rsi_FileOpen(Context *rsc, char const *path, unsigned int len)
{
- FileA3D *fa3d = new FileA3D;
+ FileA3D *fa3d = new FileA3D(rsc);
FILE *f = fopen("/sdcard/test.a3d", "rb");
if (f) {
- fa3d->load(rsc, f);
+ fa3d->load(f);
fclose(f);
+ fa3d->incUserRef();
return fa3d;
}
delete fa3d;
diff --git a/libs/rs/rsFileA3D.h b/libs/rs/rsFileA3D.h
index 9ee08ec..b985907 100644
--- a/libs/rs/rsFileA3D.h
+++ b/libs/rs/rsFileA3D.h
@@ -18,20 +18,23 @@
#define ANDROID_RS_FILE_A3D_H
#include "RenderScript.h"
-#include "rsFileA3DDecls.h"
#include "rsMesh.h"
#include <utils/String8.h>
+#include "rsStream.h"
#include <stdio.h>
+#define A3D_MAGIC_KEY "Android3D_ff"
+
// ---------------------------------------------------------------------------
namespace android {
+
namespace renderscript {
-class FileA3D
+class FileA3D : public ObjectBase
{
public:
- FileA3D();
+ FileA3D(Context *rsc);
~FileA3D();
uint32_t mMajorVersion;
@@ -40,78 +43,53 @@
uint64_t mStringTableOffset;
bool mUse64BitOffsets;
- struct A3DIndexEntry {
- String8 mID;
- A3DChunkType mType;
+ class A3DIndexEntry {
+ String8 mObjectName;
+ RsA3DClassID mType;
uint64_t mOffset;
- void * mRsObj;
+ uint64_t mLength;
+ ObjectBase *mRsObj;
+ public:
+ friend class FileA3D;
+ const String8 &getObjectName() const {
+ return mObjectName;
+ }
+ RsA3DClassID getType() const {
+ return mType;
+ }
};
- bool load(Context *rsc, FILE *f);
+ bool load(FILE *f);
+ bool load(const void *data, size_t length);
+
+ size_t getNumIndexEntries() const;
+ const A3DIndexEntry* getIndexEntry(size_t index) const;
+ ObjectBase *initializeFromEntry(size_t index);
+
+ void appendToFile(ObjectBase *obj);
+ bool writeFile(const char *filename);
+
+ // Currently files do not get serialized,
+ // but we need to inherit from ObjectBase for ref tracking
+ virtual void serialize(OStream *stream) const {
+ }
+ virtual RsA3DClassID getClassId() const {
+ return RS_A3D_CLASS_ID_UNKNOWN;
+ }
protected:
- class IO
- {
- public:
- IO(const uint8_t *, bool use64);
-
- float loadF() {
- mPos = (mPos + 3) & (~3);
- float tmp = reinterpret_cast<const float *>(&mData[mPos])[0];
- mPos += sizeof(float);
- return tmp;
- }
- int32_t loadI32() {
- mPos = (mPos + 3) & (~3);
- int32_t tmp = reinterpret_cast<const int32_t *>(&mData[mPos])[0];
- mPos += sizeof(int32_t);
- return tmp;
- }
- uint32_t loadU32() {
- mPos = (mPos + 3) & (~3);
- uint32_t tmp = reinterpret_cast<const uint32_t *>(&mData[mPos])[0];
- mPos += sizeof(uint32_t);
- return tmp;
- }
- uint16_t loadU16() {
- mPos = (mPos + 1) & (~1);
- uint16_t tmp = reinterpret_cast<const uint16_t *>(&mData[mPos])[0];
- mPos += sizeof(uint16_t);
- return tmp;
- }
- uint8_t loadU8() {
- uint8_t tmp = reinterpret_cast<const uint8_t *>(&mData[mPos])[0];
- mPos += sizeof(uint8_t);
- return tmp;
- }
- uint64_t loadOffset();
- void loadString(String8 *s);
- uint64_t getPos() const {return mPos;}
- const uint8_t * getPtr() const;
- protected:
- const uint8_t * mData;
- uint64_t mPos;
- bool mUse64;
- };
-
- bool process(Context *rsc);
- bool processIndex(Context *rsc, A3DIndexEntry *);
- void processChunk_Mesh(Context *rsc, IO *io, A3DIndexEntry *ie);
- void processChunk_Primitive(Context *rsc, IO *io, A3DIndexEntry *ie);
- void processChunk_Verticies(Context *rsc, IO *io, A3DIndexEntry *ie);
- void processChunk_Element(Context *rsc, IO *io, A3DIndexEntry *ie);
- void processChunk_ElementSource(Context *rsc, IO *io, A3DIndexEntry *ie);
+ void parseHeader(IStream *headerStream);
const uint8_t * mData;
void * mAlloc;
uint64_t mDataSize;
- Context * mRsc;
- Vector<A3DIndexEntry> mIndex;
- Vector<String8> mStrings;
- Vector<uint32_t> mStringIndexValues;
+ OStream *mWriteStream;
+ Vector<A3DIndexEntry*> mWriteIndex;
+ IStream *mReadStream;
+ Vector<A3DIndexEntry*> mIndex;
};
diff --git a/libs/rs/rsHandcode.h b/libs/rs/rsHandcode.h
index 800eddd..f6e56ac 100644
--- a/libs/rs/rsHandcode.h
+++ b/libs/rs/rsHandcode.h
@@ -1,6 +1,49 @@
#define DATA_SYNC_SIZE 1024
+static inline void rsHCAPI_ScriptInvokeV (RsContext rsc, RsScript va, uint32_t slot, const void * data, uint32_t sizeBytes)
+{
+ ThreadIO *io = &((Context *)rsc)->mIO;
+ uint32_t size = sizeof(RS_CMD_ScriptInvokeV);
+ if (sizeBytes < DATA_SYNC_SIZE) {
+ size += (sizeBytes + 3) & ~3;
+ }
+ RS_CMD_ScriptInvokeV *cmd = static_cast<RS_CMD_ScriptInvokeV *>(io->mToCore.reserve(size));
+ cmd->s = va;
+ cmd->slot = slot;
+ cmd->dataLen = sizeBytes;
+ cmd->data = data;
+ if (sizeBytes < DATA_SYNC_SIZE) {
+ cmd->data = (void *)(cmd+1);
+ memcpy(cmd+1, data, sizeBytes);
+ io->mToCore.commit(RS_CMD_ID_ScriptInvokeV, size);
+ } else {
+ io->mToCore.commitSync(RS_CMD_ID_ScriptInvokeV, size);
+ }
+}
+
+
+static inline void rsHCAPI_ScriptSetVarV (RsContext rsc, RsScript va, uint32_t slot, const void * data, uint32_t sizeBytes)
+{
+ ThreadIO *io = &((Context *)rsc)->mIO;
+ uint32_t size = sizeof(RS_CMD_ScriptSetVarV);
+ if (sizeBytes < DATA_SYNC_SIZE) {
+ size += (sizeBytes + 3) & ~3;
+ }
+ RS_CMD_ScriptSetVarV *cmd = static_cast<RS_CMD_ScriptSetVarV *>(io->mToCore.reserve(size));
+ cmd->s = va;
+ cmd->slot = slot;
+ cmd->dataLen = sizeBytes;
+ cmd->data = data;
+ if (sizeBytes < DATA_SYNC_SIZE) {
+ cmd->data = (void *)(cmd+1);
+ memcpy(cmd+1, data, sizeBytes);
+ io->mToCore.commit(RS_CMD_ID_ScriptSetVarV, size);
+ } else {
+ io->mToCore.commitSync(RS_CMD_ID_ScriptSetVarV, size);
+ }
+}
+
static inline void rsHCAPI_AllocationData (RsContext rsc, RsAllocation va, const void * data, uint32_t sizeBytes)
{
ThreadIO *io = &((Context *)rsc)->mIO;
diff --git a/libs/rs/rsLight.cpp b/libs/rs/rsLight.cpp
index 6f2cf3e..eab9a07 100644
--- a/libs/rs/rsLight.cpp
+++ b/libs/rs/rsLight.cpp
@@ -14,9 +14,13 @@
* limitations under the License.
*/
+#ifndef ANDROID_RS_BUILD_FOR_HOST
#include "rsContext.h"
-
#include <GLES/gl.h>
+#else
+#include "rsContextHostStub.h"
+#include <OpenGL/gl.h>
+#endif //ANDROID_RS_BUILD_FOR_HOST
using namespace android;
using namespace android::renderscript;
@@ -65,6 +69,16 @@
glLightfv(GL_LIGHT0 + num, GL_POSITION, mPosition);
}
+void Light::serialize(OStream *stream) const
+{
+
+}
+
+Light *Light::createFromStream(Context *rsc, IStream *stream)
+{
+ return NULL;
+}
+
////////////////////////////////////////////
LightState::LightState()
diff --git a/libs/rs/rsLight.h b/libs/rs/rsLight.h
index d8796e6..bd58979 100644
--- a/libs/rs/rsLight.h
+++ b/libs/rs/rsLight.h
@@ -37,6 +37,9 @@
void setColor(float r, float g, float b);
void setupGL(uint32_t num) const;
+ virtual void serialize(OStream *stream) const;
+ virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_LIGHT; }
+ static Light *createFromStream(Context *rsc, IStream *stream);
protected:
float mColor[4];
diff --git a/libs/rs/rsLocklessFifo.cpp b/libs/rs/rsLocklessFifo.cpp
index c796520..76ca32e 100644
--- a/libs/rs/rsLocklessFifo.cpp
+++ b/libs/rs/rsLocklessFifo.cpp
@@ -17,7 +17,7 @@
#include "rsLocklessFifo.h"
using namespace android;
-
+using namespace android::renderscript;
LocklessCommandFifo::LocklessCommandFifo()
{
@@ -128,15 +128,19 @@
//dumpState("flush 2");
}
+void LocklessCommandFifo::wait()
+{
+ while(isEmpty() && !mInShutdown) {
+ mSignalToControl.set();
+ mSignalToWorker.wait();
+ }
+}
+
const void * LocklessCommandFifo::get(uint32_t *command, uint32_t *bytesData)
{
while(1) {
//dumpState("get");
- while(isEmpty() && !mInShutdown) {
- mSignalToControl.set();
- mSignalToWorker.wait();
- }
-
+ wait();
if (mInShutdown) {
*command = 0;
*bytesData = 0;
@@ -192,79 +196,3 @@
LOGV("%s put %p, get %p, buf %p, end %p", s, mPut, mGet, mBuffer, mEnd);
}
-LocklessCommandFifo::Signal::Signal()
-{
- mSet = true;
-}
-
-LocklessCommandFifo::Signal::~Signal()
-{
- pthread_mutex_destroy(&mMutex);
- pthread_cond_destroy(&mCondition);
-}
-
-bool LocklessCommandFifo::Signal::init()
-{
- int status = pthread_mutex_init(&mMutex, NULL);
- if (status) {
- LOGE("LocklessFifo mutex init failure");
- return false;
- }
-
- status = pthread_cond_init(&mCondition, NULL);
- if (status) {
- LOGE("LocklessFifo condition init failure");
- pthread_mutex_destroy(&mMutex);
- return false;
- }
-
- return true;
-}
-
-void LocklessCommandFifo::Signal::set()
-{
- int status;
-
- status = pthread_mutex_lock(&mMutex);
- if (status) {
- LOGE("LocklessCommandFifo: error %i locking for set condition.", status);
- return;
- }
-
- mSet = true;
-
- status = pthread_cond_signal(&mCondition);
- if (status) {
- LOGE("LocklessCommandFifo: error %i on set condition.", status);
- }
-
- status = pthread_mutex_unlock(&mMutex);
- if (status) {
- LOGE("LocklessCommandFifo: error %i unlocking for set condition.", status);
- }
-}
-
-void LocklessCommandFifo::Signal::wait()
-{
- int status;
-
- status = pthread_mutex_lock(&mMutex);
- if (status) {
- LOGE("LocklessCommandFifo: error %i locking for condition.", status);
- return;
- }
-
- if (!mSet) {
- status = pthread_cond_wait(&mCondition, &mMutex);
- if (status) {
- LOGE("LocklessCommandFifo: error %i waiting on condition.", status);
- }
- }
- mSet = false;
-
- status = pthread_mutex_unlock(&mMutex);
- if (status) {
- LOGE("LocklessCommandFifo: error %i unlocking for condition.", status);
- }
-}
-
diff --git a/libs/rs/rsLocklessFifo.h b/libs/rs/rsLocklessFifo.h
index d0a4356..ae906ca 100644
--- a/libs/rs/rsLocklessFifo.h
+++ b/libs/rs/rsLocklessFifo.h
@@ -19,8 +19,10 @@
#include "rsUtils.h"
+#include "rsSignal.h"
namespace android {
+namespace renderscript {
// A simple FIFO to be used as a producer / consumer between two
@@ -37,24 +39,7 @@
LocklessCommandFifo();
~LocklessCommandFifo();
-
protected:
- class Signal {
- public:
- Signal();
- ~Signal();
-
- bool init();
-
- void set();
- void wait();
-
- protected:
- bool mSet;
- pthread_mutex_t mMutex;
- pthread_cond_t mCondition;
- };
-
uint8_t * volatile mPut;
uint8_t * volatile mGet;
uint8_t * mBuffer;
@@ -65,14 +50,14 @@
Signal mSignalToWorker;
Signal mSignalToControl;
-
-
public:
void * reserve(uint32_t bytes);
void commit(uint32_t command, uint32_t bytes);
void commitSync(uint32_t command, uint32_t bytes);
void flush();
+ void wait();
+
const void * get(uint32_t *command, uint32_t *bytesData);
void next();
@@ -88,4 +73,5 @@
}
+}
#endif
diff --git a/libs/rs/rsMesh.cpp b/libs/rs/rsMesh.cpp
index d595b4e..bd9cd27 100644
--- a/libs/rs/rsMesh.cpp
+++ b/libs/rs/rsMesh.cpp
@@ -14,14 +14,23 @@
* limitations under the License.
*/
+#ifndef ANDROID_RS_BUILD_FOR_HOST
#include "rsContext.h"
+#include <GLES/gl.h>
+#include <GLES2/gl2.h>
+#include <GLES/glext.h>
+#else
+#include "rsContextHostStub.h"
+
+#include <OpenGL/gl.h>
+#include <OpenGl/glext.h>
+#endif
+
+
using namespace android;
using namespace android::renderscript;
-#include <GLES/gl.h>
-#include <GLES/glext.h>
-
Mesh::Mesh(Context *rsc) : ObjectBase(rsc)
{
mAllocFile = __FILE__;
@@ -36,6 +45,162 @@
{
}
+void Mesh::serialize(OStream *stream) const
+{
+ // Need to identify ourselves
+ stream->addU32((uint32_t)getClassId());
+
+ String8 name(getName());
+ stream->addString(&name);
+
+ stream->addU32(mVerticiesCount);
+
+ for(uint32_t vCount = 0; vCount < mVerticiesCount; vCount ++) {
+ Verticies_t *verts = mVerticies[vCount];
+
+ stream->addU32(verts->mAllocationCount);
+
+ for (uint32_t aCount = 0; aCount < verts->mAllocationCount; aCount++) {
+ verts->mAllocations[aCount]->serialize(stream);
+ }
+ stream->addU32(verts->mVertexDataSize);
+
+ stream->addU32(verts->mOffsetCoord);
+ stream->addU32(verts->mOffsetTex);
+ stream->addU32(verts->mOffsetNorm);
+
+ stream->addU32(verts->mSizeCoord);
+ stream->addU32(verts->mSizeTex);
+ stream->addU32(verts->mSizeNorm );
+ }
+
+ stream->addU32(mPrimitivesCount);
+ // Store the primitives
+ for (uint32_t pCount = 0; pCount < mPrimitivesCount; pCount ++) {
+ Primitive_t * prim = mPrimitives[pCount];
+
+ stream->addU8((uint8_t)prim->mType);
+
+ // We store the index to the vertices
+ // So iterate over our vertices to find which one we point to
+ uint32_t vertexIndex = 0;
+ for(uint32_t vCount = 0; vCount < mVerticiesCount; vCount ++) {
+ if(prim->mVerticies == mVerticies[vCount]) {
+ vertexIndex = vCount;
+ break;
+ }
+ }
+ stream->addU32(vertexIndex);
+
+ stream->addU32(prim->mIndexCount);
+ for (uint32_t ct = 0; ct < prim->mIndexCount; ct++) {
+ stream->addU16(prim->mIndicies[ct]);
+ }
+
+ stream->addU32(prim->mRestartCounts);
+ for (uint32_t ct = 0; ct < prim->mRestartCounts; ct++) {
+ stream->addU16(prim->mRestarts[ct]);
+ }
+ }
+}
+
+Mesh *Mesh::createFromStream(Context *rsc, IStream *stream)
+{
+ // First make sure we are reading the correct object
+ RsA3DClassID classID = (RsA3DClassID)stream->loadU32();
+ if(classID != RS_A3D_CLASS_ID_MESH) {
+ LOGE("mesh loading skipped due to invalid class id");
+ return NULL;
+ }
+
+ Mesh * mesh = new Mesh(rsc);
+
+ String8 name;
+ stream->loadString(&name);
+ mesh->setName(name.string(), name.size());
+
+ mesh->mVerticiesCount = stream->loadU32();
+ if(mesh->mVerticiesCount) {
+ mesh->mVerticies = new Verticies_t *[mesh->mVerticiesCount];
+ }
+ else {
+ mesh->mVerticies = NULL;
+ }
+
+ for(uint32_t vCount = 0; vCount < mesh->mVerticiesCount; vCount ++) {
+ Verticies_t *verts = new Verticies_t();
+ // Store our vertices one the mesh
+ mesh->mVerticies[vCount] = verts;
+
+ verts->mAllocationCount = stream->loadU32();
+ verts->mAllocations = new Allocation *[verts->mAllocationCount];
+
+ LOGE("processChunk_Verticies count %i", verts->mAllocationCount);
+ for (uint32_t aCount = 0; aCount < verts->mAllocationCount; aCount++) {
+ verts->mAllocations[aCount] = Allocation::createFromStream(rsc, stream);
+ }
+ verts->mVertexDataSize = stream->loadU32();
+
+ verts->mOffsetCoord = stream->loadU32();
+ verts->mOffsetTex = stream->loadU32();
+ verts->mOffsetNorm = stream->loadU32();
+
+ verts->mSizeCoord = stream->loadU32();
+ verts->mSizeTex = stream->loadU32();
+ verts->mSizeNorm = stream->loadU32();
+ }
+
+ mesh->mPrimitivesCount = stream->loadU32();
+ if(mesh->mPrimitivesCount) {
+ mesh->mPrimitives = new Primitive_t *[mesh->mPrimitivesCount];
+ }
+ else {
+ mesh->mPrimitives = NULL;
+ }
+
+ // load all primitives
+ for (uint32_t pCount = 0; pCount < mesh->mPrimitivesCount; pCount ++) {
+ Primitive_t * prim = new Primitive_t;
+ mesh->mPrimitives[pCount] = prim;
+
+ prim->mType = (RsPrimitive)stream->loadU8();
+
+ // We store the index to the vertices
+ uint32_t vertexIndex = stream->loadU32();
+ if(vertexIndex < mesh->mVerticiesCount) {
+ prim->mVerticies = mesh->mVerticies[vertexIndex];
+ }
+ else {
+ prim->mVerticies = NULL;
+ }
+
+ prim->mIndexCount = stream->loadU32();
+ if(prim->mIndexCount){
+ prim->mIndicies = new uint16_t[prim->mIndexCount];
+ for (uint32_t ct = 0; ct < prim->mIndexCount; ct++) {
+ prim->mIndicies[ct] = stream->loadU16();
+ }
+ }
+ else {
+ prim->mIndicies = NULL;
+ }
+
+ prim->mRestartCounts = stream->loadU32();
+ if (prim->mRestartCounts) {
+ prim->mRestarts = new uint16_t[prim->mRestartCounts];
+ for (uint32_t ct = 0; ct < prim->mRestartCounts; ct++) {
+ prim->mRestarts[ct] = stream->loadU16();
+
+ }
+ }
+ else {
+ prim->mRestarts = NULL;
+ }
+
+ }
+
+ return mesh;
+}
MeshContext::MeshContext()
diff --git a/libs/rs/rsMesh.h b/libs/rs/rsMesh.h
index 5201abd..8c7e8a4 100644
--- a/libs/rs/rsMesh.h
+++ b/libs/rs/rsMesh.h
@@ -62,15 +62,17 @@
uint16_t *mRestarts;
};
- Verticies_t * mVerticies;
+ Verticies_t ** mVerticies;
uint32_t mVerticiesCount;
Primitive_t ** mPrimitives;
uint32_t mPrimitivesCount;
-
-
void analyzeElement();
+ virtual void serialize(OStream *stream) const;
+ virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_MESH; }
+ static Mesh *createFromStream(Context *rsc, IStream *stream);
+
protected:
};
diff --git a/libs/rs/rsMutex.cpp b/libs/rs/rsMutex.cpp
new file mode 100644
index 0000000..37752f2
--- /dev/null
+++ b/libs/rs/rsMutex.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "rsMutex.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+
+Mutex::Mutex()
+{
+}
+
+Mutex::~Mutex()
+{
+ pthread_mutex_destroy(&mMutex);
+}
+
+bool Mutex::init()
+{
+ int status = pthread_mutex_init(&mMutex, NULL);
+ if (status) {
+ LOGE("Mutex::Mutex init failure");
+ return false;
+ }
+ return true;
+}
+
+bool Mutex::lock()
+{
+ int status;
+ status = pthread_mutex_lock(&mMutex);
+ if (status) {
+ LOGE("Mutex: error %i locking.", status);
+ return false;
+ }
+ return true;
+}
+
+bool Mutex::unlock()
+{
+ int status;
+ status = pthread_mutex_unlock(&mMutex);
+ if (status) {
+ LOGE("Mutex error %i unlocking.", status);
+ return false;
+ }
+ return true;
+}
+
+
diff --git a/graphics/java/android/renderscript/Vector2f.java b/libs/rs/rsMutex.h
similarity index 69%
copy from graphics/java/android/renderscript/Vector2f.java
copy to libs/rs/rsMutex.h
index 567d57fa..47725d7 100644
--- a/graphics/java/android/renderscript/Vector2f.java
+++ b/libs/rs/rsMutex.h
@@ -14,24 +14,30 @@
* limitations under the License.
*/
-package android.renderscript;
-
-import java.lang.Math;
-import android.util.Log;
+#ifndef ANDROID_RS_MUTEX_H
+#define ANDROID_RS_MUTEX_H
-/**
- * @hide
- *
- **/
-public class Vector2f {
- public Vector2f() {
- }
+#include "rsUtils.h"
- public float x;
- public float y;
+namespace android {
+namespace renderscript {
+
+class Mutex {
+public:
+ Mutex();
+ ~Mutex();
+
+ bool init();
+ bool lock();
+ bool unlock();
+
+protected:
+ pthread_mutex_t mMutex;
+};
+
+}
}
-
-
+#endif
diff --git a/libs/rs/rsNoise.cpp b/libs/rs/rsNoise.cpp
deleted file mode 100644
index 764dc1a..0000000
--- a/libs/rs/rsNoise.cpp
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * This implementation of the noise functions was ported from the Java
- * implementation by Jerry Huxtable (http://www.jhlabs.com) under
- * Apache License 2.0 (see http://jhlabs.com/ip/filters/download.html)
- *
- * Original header:
- *
- * Copyright 2006 Jerry Huxtable
- *
- * 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 "rsNoise.h"
-
-#include <math.h>
-#include <stdlib.h>
-#include <time.h>
-
-namespace android {
-namespace renderscript {
-
-#define B 0x100
-#define BM 0xff
-#define N 0x1000
-
-static int p[B + B + 2];
-static float g3[B + B + 2][3];
-static float g2[B + B + 2][2];
-static float g1[B + B + 2];
-static bool noise_start = true;
-
-#define lerpf(start, stop, amount) start + (stop - start) * amount
-
-static inline float noise_sCurve(float t)
-{
- return t * t * (3.0f - 2.0f * t);
-}
-
-inline void SC_normalizef2(float v[])
-{
- float s = (float)sqrtf(v[0] * v[0] + v[1] * v[1]);
- v[0] = v[0] / s;
- v[1] = v[1] / s;
-}
-
-inline void SC_normalizef3(float v[])
-{
- float s = (float)sqrtf(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
- v[0] = v[0] / s;
- v[1] = v[1] / s;
- v[2] = v[2] / s;
-}
-
-static void noise_init()
-{
- int i, j, k;
-
- for (i = 0; i < B; i++) {
- p[i] = i;
-
- g1[i] = (float)((rand() % (B + B)) - B) / B;
-
- for (j = 0; j < 2; j++)
- g2[i][j] = (float)((rand() % (B + B)) - B) / B;
- SC_normalizef2(g2[i]);
-
- for (j = 0; j < 3; j++)
- g3[i][j] = (float)((rand() % (B + B)) - B) / B;
- SC_normalizef3(g3[i]);
- }
-
- for (i = B-1; i >= 0; i--) {
- k = p[i];
- p[i] = p[j = rand() % B];
- p[j] = k;
- }
-
- for (i = 0; i < B + 2; i++) {
- p[B + i] = p[i];
- g1[B + i] = g1[i];
- for (j = 0; j < 2; j++)
- g2[B + i][j] = g2[i][j];
- for (j = 0; j < 3; j++)
- g3[B + i][j] = g3[i][j];
- }
-}
-
-float SC_noisef(float x)
-{
- srand(time(NULL));
- int bx0, bx1;
- float rx0, rx1, sx, t, u, v;
-
- if (noise_start) {
- noise_start = false;
- noise_init();
- }
-
- t = x + N;
- bx0 = ((int)t) & BM;
- bx1 = (bx0+1) & BM;
- rx0 = t - (int)t;
- rx1 = rx0 - 1.0f;
-
- sx = noise_sCurve(rx0);
-
- u = rx0 * g1[p[bx0]];
- v = rx1 * g1[p[bx1]];
- return 2.3f * lerpf(u, v, sx);
-}
-
-float SC_noisef2(float x, float y)
-{
- srand(time(NULL));
- int bx0, bx1, by0, by1, b00, b10, b01, b11;
- float rx0, rx1, ry0, ry1, sx, sy, a, b, t, u, v;
- float *q;
- int i, j;
-
- if (noise_start) {
- noise_start = false;
- noise_init();
- }
-
- t = x + N;
- bx0 = ((int)t) & BM;
- bx1 = (bx0+1) & BM;
- rx0 = t - (int)t;
- rx1 = rx0 - 1.0f;
-
- t = y + N;
- by0 = ((int)t) & BM;
- by1 = (by0+1) & BM;
- ry0 = t - (int)t;
- ry1 = ry0 - 1.0f;
-
- i = p[bx0];
- j = p[bx1];
-
- b00 = p[i + by0];
- b10 = p[j + by0];
- b01 = p[i + by1];
- b11 = p[j + by1];
-
- sx = noise_sCurve(rx0);
- sy = noise_sCurve(ry0);
-
- q = g2[b00]; u = rx0 * q[0] + ry0 * q[1];
- q = g2[b10]; v = rx1 * q[0] + ry0 * q[1];
- a = lerpf(u, v, sx);
-
- q = g2[b01]; u = rx0 * q[0] + ry1 * q[1];
- q = g2[b11]; v = rx1 * q[0] + ry1 * q[1];
- b = lerpf(u, v, sx);
-
- return 1.5f*lerpf(a, b, sy);
-}
-
-float SC_noisef3(float x, float y, float z)
-{
- srand(time(NULL));
- int bx0, bx1, by0, by1, bz0, bz1, b00, b10, b01, b11;
- float rx0, rx1, ry0, ry1, rz0, rz1, sy, sz, a, b, c, d, t, u, v;
- float *q;
- int i, j;
-
- if (noise_start) {
- noise_start = false;
- noise_init();
- }
-
- t = x + N;
- bx0 = ((int)t) & BM;
- bx1 = (bx0+1) & BM;
- rx0 = t - (int)t;
- rx1 = rx0 - 1.0f;
-
- t = y + N;
- by0 = ((int)t) & BM;
- by1 = (by0+1) & BM;
- ry0 = t - (int)t;
- ry1 = ry0 - 1.0f;
-
- t = z + N;
- bz0 = ((int)t) & BM;
- bz1 = (bz0+1) & BM;
- rz0 = t - (int)t;
- rz1 = rz0 - 1.0f;
-
- i = p[bx0];
- j = p[bx1];
-
- b00 = p[i + by0];
- b10 = p[j + by0];
- b01 = p[i + by1];
- b11 = p[j + by1];
-
- t = noise_sCurve(rx0);
- sy = noise_sCurve(ry0);
- sz = noise_sCurve(rz0);
-
- q = g3[b00 + bz0]; u = rx0 * q[0] + ry0 * q[1] + rz0 * q[2];
- q = g3[b10 + bz0]; v = rx1 * q[0] + ry0 * q[1] + rz0 * q[2];
- a = lerpf(u, v, t);
-
- q = g3[b01 + bz0]; u = rx0 * q[0] + ry1 * q[1] + rz0 * q[2];
- q = g3[b11 + bz0]; v = rx1 * q[0] + ry1 * q[1] + rz0 * q[2];
- b = lerpf(u, v, t);
-
- c = lerpf(a, b, sy);
-
- q = g3[b00 + bz1]; u = rx0 * q[0] + ry0 * q[1] + rz1 * q[2];
- q = g3[b10 + bz1]; v = rx1 * q[0] + ry0 * q[1] + rz1 * q[2];
- a = lerpf(u, v, t);
-
- q = g3[b01 + bz1]; u = rx0 * q[0] + ry1 * q[1] + rz1 * q[2];
- q = g3[b11 + bz1]; v = rx1 * q[0] + ry1 * q[1] + rz1 * q[2];
- b = lerpf(u, v, t);
-
- d = lerpf(a, b, sy);
-
- return 1.5f*lerpf(c, d, sz);
-}
-
-float SC_turbulencef2(float x, float y, float octaves)
-{
- srand(time(NULL));
- float t = 0.0f;
-
- for (float f = 1.0f; f <= octaves; f *= 2)
- t += fabs(SC_noisef2(f * x, f * y)) / f;
- return t;
-}
-
-float SC_turbulencef3(float x, float y, float z, float octaves)
-{
- srand(time(NULL));
- float t = 0.0f;
-
- for (float f = 1.0f; f <= octaves; f *= 2)
- t += fabs(SC_noisef3(f * x, f * y, f * z)) / f;
- return t;
-}
-
-}
-}
\ No newline at end of file
diff --git a/libs/rs/rsNoise.h b/libs/rs/rsNoise.h
deleted file mode 100644
index 9040751..0000000
--- a/libs/rs/rsNoise.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_RS_NOISE_H
-#define ANDROID_RS_NOISE_H
-
-// ---------------------------------------------------------------------------
-namespace android {
-namespace renderscript {
-
-void SC_normalizef2(float v[]);
-void SC_normalizef3(float v[]);
-float SC_noisef(float x);
-float SC_noisef2(float x, float y);
-float SC_noisef3(float x, float y, float z);
-float SC_turbulencef2(float x, float y, float octaves);
-float SC_turbulencef3(float x, float y, float z, float octaves);
-
-}
-}
-
-#endif
diff --git a/libs/rs/rsObjectBase.cpp b/libs/rs/rsObjectBase.cpp
index 677413e..48f1fee 100644
--- a/libs/rs/rsObjectBase.cpp
+++ b/libs/rs/rsObjectBase.cpp
@@ -15,7 +15,12 @@
*/
#include "rsObjectBase.h"
+
+#ifndef ANDROID_RS_BUILD_FOR_HOST
#include "rsContext.h"
+#else
+#include "rsContextHostStub.h"
+#endif
using namespace android;
using namespace android::renderscript;
@@ -24,7 +29,6 @@
{
mUserRefCount = 0;
mSysRefCount = 0;
- mName = NULL;
mRSC = NULL;
mNext = NULL;
mPrev = NULL;
@@ -39,14 +43,13 @@
rsAssert(!mUserRefCount);
rsAssert(!mSysRefCount);
remove();
- delete[] mName;
}
void ObjectBase::dumpLOGV(const char *op) const
{
- if (mName) {
+ if (mName.size()) {
LOGV("%s RSobj %p, name %s, refs %i,%i from %s,%i links %p,%p,%p",
- op, this, mName, mUserRefCount, mSysRefCount, mAllocFile, mAllocLine, mNext, mPrev, mRSC);
+ op, this, mName.string(), mUserRefCount, mSysRefCount, mAllocFile, mAllocLine, mNext, mPrev, mRSC);
} else {
LOGV("%s RSobj %p, no-name, refs %i,%i from %s,%i links %p,%p,%p",
op, this, mUserRefCount, mSysRefCount, mAllocFile, mAllocLine, mNext, mPrev, mRSC);
@@ -113,18 +116,12 @@
void ObjectBase::setName(const char *name)
{
- setName(name, strlen(name));
+ mName.setTo(name);
}
void ObjectBase::setName(const char *name, uint32_t len)
{
- delete mName;
- mName = NULL;
- if (name) {
- mName = new char[len + 1];
- memcpy(mName, name, len);
- mName[len] = 0;
- }
+ mName.setTo(name, len);
}
void ObjectBase::add() const
diff --git a/libs/rs/rsObjectBase.h b/libs/rs/rsObjectBase.h
index bb03b87..ad95b81 100644
--- a/libs/rs/rsObjectBase.h
+++ b/libs/rs/rsObjectBase.h
@@ -24,6 +24,7 @@
namespace renderscript {
class Context;
+class OStream;
// An element is a group of Components that occupies one cell in a structure.
class ObjectBase
@@ -40,7 +41,7 @@
bool zeroUserRef() const;
const char * getName() const {
- return mName;
+ return mName.string();
}
void setName(const char *);
void setName(const char *, uint32_t len);
@@ -52,6 +53,8 @@
static void dumpAll(Context *rsc);
virtual void dumpLOGV(const char *prefix) const;
+ virtual void serialize(OStream *stream) const = 0;
+ virtual RsA3DClassID getClassId() const = 0;
protected:
const char *mAllocFile;
@@ -64,7 +67,7 @@
bool checkDelete() const;
- char * mName;
+ String8 mName;
mutable int32_t mSysRefCount;
mutable int32_t mUserRefCount;
diff --git a/libs/rs/rsProgram.cpp b/libs/rs/rsProgram.cpp
index 70e2868..c4f8b2e 100644
--- a/libs/rs/rsProgram.cpp
+++ b/libs/rs/rsProgram.cpp
@@ -14,11 +14,17 @@
* limitations under the License.
*/
+#ifndef ANDROID_RS_BUILD_FOR_HOST
#include "rsContext.h"
-#include "rsProgram.h"
-
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
+#else
+#include "rsContextHostStub.h"
+#include <OpenGL/gl.h>
+#include <OpenGL/glext.h>
+#endif //ANDROID_RS_BUILD_FOR_HOST
+
+#include "rsProgram.h"
using namespace android;
using namespace android::renderscript;
diff --git a/libs/rs/rsProgramFragment.cpp b/libs/rs/rsProgramFragment.cpp
index c17b94c..8151f06 100644
--- a/libs/rs/rsProgramFragment.cpp
+++ b/libs/rs/rsProgramFragment.cpp
@@ -14,13 +14,19 @@
* limitations under the License.
*/
+#ifndef ANDROID_RS_BUILD_FOR_HOST
#include "rsContext.h"
-#include "rsProgramFragment.h"
-
#include <GLES/gl.h>
#include <GLES/glext.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
+#else
+#include "rsContextHostStub.h"
+#include <OpenGL/gl.h>
+#include <OpenGL/glext.h>
+#endif //ANDROID_RS_BUILD_FOR_HOST
+
+#include "rsProgramFragment.h"
using namespace android;
using namespace android::renderscript;
@@ -83,12 +89,15 @@
glEnable(GL_TEXTURE_2D);
if (rsc->checkVersion1_1()) {
+#ifndef ANDROID_RS_BUILD_FOR_HOST // These are GLES only
if (mPointSpriteEnable) {
glEnable(GL_POINT_SPRITE_OES);
} else {
glDisable(GL_POINT_SPRITE_OES);
}
glTexEnvi(GL_POINT_SPRITE_OES, GL_COORD_REPLACE_OES, mPointSpriteEnable);
+#endif //ANDROID_RS_BUILD_FOR_HOST
+
}
mTextures[ct]->uploadCheck(rsc);
glBindTexture(GL_TEXTURE_2D, mTextures[ct]->getTextureID());
@@ -289,6 +298,16 @@
createShader();
}
+void ProgramFragment::serialize(OStream *stream) const
+{
+
+}
+
+ProgramFragment *ProgramFragment::createFromStream(Context *rsc, IStream *stream)
+{
+ return NULL;
+}
+
ProgramFragmentState::ProgramFragmentState()
{
mPF = NULL;
@@ -300,7 +319,7 @@
}
-void ProgramFragmentState::init(Context *rsc, int32_t w, int32_t h)
+void ProgramFragmentState::init(Context *rsc)
{
uint32_t tmp[5] = {
RS_TEX_ENV_MODE_NONE, 0,
@@ -328,6 +347,7 @@
{
ProgramFragment *pf = new ProgramFragment(rsc, params, paramLength);
pf->incUserRef();
+ //LOGE("rsi_ProgramFragmentCreate %p", pf);
return pf;
}
@@ -337,6 +357,7 @@
{
ProgramFragment *pf = new ProgramFragment(rsc, shaderText, shaderLength, params, paramLength);
pf->incUserRef();
+ //LOGE("rsi_ProgramFragmentCreate2 %p", pf);
return pf;
}
diff --git a/libs/rs/rsProgramFragment.h b/libs/rs/rsProgramFragment.h
index 9fa565d..e5bbe1b 100644
--- a/libs/rs/rsProgramFragment.h
+++ b/libs/rs/rsProgramFragment.h
@@ -40,6 +40,9 @@
virtual void createShader();
virtual void loadShader(Context *rsc);
virtual void init(Context *rsc);
+ virtual void serialize(OStream *stream) const;
+ virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_PROGRAM_FRAGMENT; }
+ static ProgramFragment *createFromStream(Context *rsc, IStream *stream);
protected:
// Hacks to create a program for now
@@ -57,7 +60,7 @@
~ProgramFragmentState();
ProgramFragment *mPF;
- void init(Context *rsc, int32_t w, int32_t h);
+ void init(Context *rsc);
void deinit(Context *rsc);
ObjectBaseRef<Type> mTextureTypes[ProgramFragment::MAX_TEXTURE];
diff --git a/libs/rs/rsProgramRaster.cpp b/libs/rs/rsProgramRaster.cpp
index 13887d1..66f6ef8 100644
--- a/libs/rs/rsProgramRaster.cpp
+++ b/libs/rs/rsProgramRaster.cpp
@@ -14,11 +14,17 @@
* limitations under the License.
*/
+#ifndef ANDROID_RS_BUILD_FOR_HOST
#include "rsContext.h"
-#include "rsProgramRaster.h"
-
#include <GLES/gl.h>
#include <GLES/glext.h>
+#else
+#include "rsContextHostStub.h"
+#include <OpenGL/gl.h>
+#include <OpenGl/glext.h>
+#endif //ANDROID_RS_BUILD_FOR_HOST
+
+#include "rsProgramRaster.h"
using namespace android;
using namespace android::renderscript;
@@ -76,11 +82,13 @@
}
if (rsc->checkVersion1_1()) {
+#ifndef ANDROID_RS_BUILD_FOR_HOST
if (mPointSprite) {
glEnable(GL_POINT_SPRITE_OES);
} else {
glDisable(GL_POINT_SPRITE_OES);
}
+#endif //ANDROID_RS_BUILD_FOR_HOST
}
}
@@ -92,7 +100,15 @@
state->mLast.set(this);
}
+void ProgramRaster::serialize(OStream *stream) const
+{
+
+}
+ProgramRaster *ProgramRaster::createFromStream(Context *rsc, IStream *stream)
+{
+ return NULL;
+}
ProgramRasterState::ProgramRasterState()
{
@@ -102,7 +118,7 @@
{
}
-void ProgramRasterState::init(Context *rsc, int32_t w, int32_t h)
+void ProgramRasterState::init(Context *rsc)
{
ProgramRaster *pr = new ProgramRaster(rsc, false, false, false);
mDefault.set(pr);
diff --git a/libs/rs/rsProgramRaster.h b/libs/rs/rsProgramRaster.h
index c3a9c90..79b14753 100644
--- a/libs/rs/rsProgramRaster.h
+++ b/libs/rs/rsProgramRaster.h
@@ -36,6 +36,9 @@
virtual void setupGL(const Context *, ProgramRasterState *);
virtual void setupGL2(const Context *, ProgramRasterState *);
+ virtual void serialize(OStream *stream) const;
+ virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_PROGRAM_RASTER; }
+ static ProgramRaster *createFromStream(Context *rsc, IStream *stream);
void setLineWidth(float w);
void setPointSize(float s);
@@ -56,7 +59,7 @@
public:
ProgramRasterState();
~ProgramRasterState();
- void init(Context *rsc, int32_t w, int32_t h);
+ void init(Context *rsc);
void deinit(Context *rsc);
ObjectBaseRef<ProgramRaster> mDefault;
diff --git a/libs/rs/rsProgramFragmentStore.cpp b/libs/rs/rsProgramStore.cpp
similarity index 78%
rename from libs/rs/rsProgramFragmentStore.cpp
rename to libs/rs/rsProgramStore.cpp
index 8a2157f..e741c0a 100644
--- a/libs/rs/rsProgramFragmentStore.cpp
+++ b/libs/rs/rsProgramStore.cpp
@@ -14,17 +14,23 @@
* limitations under the License.
*/
+#ifndef ANDROID_RS_BUILD_FOR_HOST
#include "rsContext.h"
-#include "rsProgramFragmentStore.h"
-
#include <GLES/gl.h>
#include <GLES/glext.h>
+#else
+#include "rsContextHostStub.h"
+#include <OpenGL/gl.h>
+#include <OpenGl/glext.h>
+#endif //ANDROID_RS_BUILD_FOR_HOST
+
+#include "rsProgramStore.h"
using namespace android;
using namespace android::renderscript;
-ProgramFragmentStore::ProgramFragmentStore(Context *rsc) :
+ProgramStore::ProgramStore(Context *rsc) :
Program(rsc)
{
mAllocFile = __FILE__;
@@ -46,11 +52,11 @@
}
-ProgramFragmentStore::~ProgramFragmentStore()
+ProgramStore::~ProgramStore()
{
}
-void ProgramFragmentStore::setupGL(const Context *rsc, ProgramFragmentStoreState *state)
+void ProgramStore::setupGL(const Context *rsc, ProgramStoreState *state)
{
if (state->mLast.get() == this) {
return;
@@ -85,7 +91,7 @@
}
}
-void ProgramFragmentStore::setupGL2(const Context *rsc, ProgramFragmentStoreState *state)
+void ProgramStore::setupGL2(const Context *rsc, ProgramStoreState *state)
{
if (state->mLast.get() == this) {
return;
@@ -121,12 +127,23 @@
}
-void ProgramFragmentStore::setDitherEnable(bool enable)
+void ProgramStore::setDitherEnable(bool enable)
{
mDitherEnable = enable;
}
-void ProgramFragmentStore::setDepthFunc(RsDepthFunc func)
+void ProgramStore::serialize(OStream *stream) const
+{
+
+}
+
+ProgramStore *ProgramStore::createFromStream(Context *rsc, IStream *stream)
+{
+ return NULL;
+}
+
+
+void ProgramStore::setDepthFunc(RsDepthFunc func)
{
mDepthTestEnable = true;
@@ -156,12 +173,12 @@
}
}
-void ProgramFragmentStore::setDepthMask(bool mask)
+void ProgramStore::setDepthMask(bool mask)
{
mDepthWriteEnable = mask;
}
-void ProgramFragmentStore::setBlendFunc(RsBlendSrcFunc src, RsBlendDstFunc dst)
+void ProgramStore::setBlendFunc(RsBlendSrcFunc src, RsBlendDstFunc dst)
{
mBlendEnable = true;
if ((src == RS_BLEND_SRC_ONE) &&
@@ -227,7 +244,7 @@
}
}
-void ProgramFragmentStore::setColorMask(bool r, bool g, bool b, bool a)
+void ProgramStore::setColorMask(bool r, bool g, bool b, bool a)
{
mColorRWriteEnable = r;
mColorGWriteEnable = g;
@@ -236,24 +253,24 @@
}
-ProgramFragmentStoreState::ProgramFragmentStoreState()
+ProgramStoreState::ProgramStoreState()
{
mPFS = NULL;
}
-ProgramFragmentStoreState::~ProgramFragmentStoreState()
+ProgramStoreState::~ProgramStoreState()
{
delete mPFS;
}
-void ProgramFragmentStoreState::init(Context *rsc, int32_t w, int32_t h)
+void ProgramStoreState::init(Context *rsc)
{
- ProgramFragmentStore *pfs = new ProgramFragmentStore(rsc);
+ ProgramStore *pfs = new ProgramStore(rsc);
mDefault.set(pfs);
}
-void ProgramFragmentStoreState::deinit(Context *rsc)
+void ProgramStoreState::deinit(Context *rsc)
{
mDefault.clear();
mLast.clear();
@@ -263,42 +280,42 @@
namespace android {
namespace renderscript {
-void rsi_ProgramFragmentStoreBegin(Context * rsc, RsElement in, RsElement out)
+void rsi_ProgramStoreBegin(Context * rsc, RsElement in, RsElement out)
{
delete rsc->mStateFragmentStore.mPFS;
- rsc->mStateFragmentStore.mPFS = new ProgramFragmentStore(rsc);
+ rsc->mStateFragmentStore.mPFS = new ProgramStore(rsc);
}
-void rsi_ProgramFragmentStoreDepthFunc(Context *rsc, RsDepthFunc func)
+void rsi_ProgramStoreDepthFunc(Context *rsc, RsDepthFunc func)
{
rsc->mStateFragmentStore.mPFS->setDepthFunc(func);
}
-void rsi_ProgramFragmentStoreDepthMask(Context *rsc, bool mask)
+void rsi_ProgramStoreDepthMask(Context *rsc, bool mask)
{
rsc->mStateFragmentStore.mPFS->setDepthMask(mask);
}
-void rsi_ProgramFragmentStoreColorMask(Context *rsc, bool r, bool g, bool b, bool a)
+void rsi_ProgramStoreColorMask(Context *rsc, bool r, bool g, bool b, bool a)
{
rsc->mStateFragmentStore.mPFS->setColorMask(r, g, b, a);
}
-void rsi_ProgramFragmentStoreBlendFunc(Context *rsc, RsBlendSrcFunc src, RsBlendDstFunc dst)
+void rsi_ProgramStoreBlendFunc(Context *rsc, RsBlendSrcFunc src, RsBlendDstFunc dst)
{
rsc->mStateFragmentStore.mPFS->setBlendFunc(src, dst);
}
-RsProgramFragmentStore rsi_ProgramFragmentStoreCreate(Context *rsc)
+RsProgramStore rsi_ProgramStoreCreate(Context *rsc)
{
- ProgramFragmentStore *pfs = rsc->mStateFragmentStore.mPFS;
+ ProgramStore *pfs = rsc->mStateFragmentStore.mPFS;
pfs->incUserRef();
rsc->mStateFragmentStore.mPFS = 0;
return pfs;
}
-void rsi_ProgramFragmentStoreDither(Context *rsc, bool enable)
+void rsi_ProgramStoreDither(Context *rsc, bool enable)
{
rsc->mStateFragmentStore.mPFS->setDitherEnable(enable);
}
diff --git a/libs/rs/rsProgramFragmentStore.h b/libs/rs/rsProgramStore.h
similarity index 68%
rename from libs/rs/rsProgramFragmentStore.h
rename to libs/rs/rsProgramStore.h
index 3412c99..fe8d78e 100644
--- a/libs/rs/rsProgramFragmentStore.h
+++ b/libs/rs/rsProgramStore.h
@@ -18,21 +18,22 @@
#define ANDROID_RS_PROGRAM_FRAGMENT_STORE_H
#include "rsProgram.h"
+#include "rsStream.h"
// ---------------------------------------------------------------------------
namespace android {
namespace renderscript {
-class ProgramFragmentStoreState;
+class ProgramStoreState;
-class ProgramFragmentStore : public Program
+class ProgramStore : public Program
{
public:
- ProgramFragmentStore(Context *);
- virtual ~ProgramFragmentStore();
+ ProgramStore(Context *);
+ virtual ~ProgramStore();
- virtual void setupGL(const Context *, ProgramFragmentStoreState *);
- virtual void setupGL2(const Context *, ProgramFragmentStoreState *);
+ virtual void setupGL(const Context *, ProgramStoreState *);
+ virtual void setupGL2(const Context *, ProgramStoreState *);
void setDepthFunc(RsDepthFunc);
void setDepthMask(bool);
@@ -42,6 +43,10 @@
void setDitherEnable(bool);
+ virtual void serialize(OStream *stream) const;
+ virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_PROGRAM_STORE; }
+ static ProgramStore *createFromStream(Context *rsc, IStream *stream);
+
protected:
bool mDitherEnable;
@@ -60,19 +65,19 @@
bool mStencilTestEnable;
};
-class ProgramFragmentStoreState
+class ProgramStoreState
{
public:
- ProgramFragmentStoreState();
- ~ProgramFragmentStoreState();
- void init(Context *rsc, int32_t w, int32_t h);
+ ProgramStoreState();
+ ~ProgramStoreState();
+ void init(Context *rsc);
void deinit(Context *rsc);
- ObjectBaseRef<ProgramFragmentStore> mDefault;
- ObjectBaseRef<ProgramFragmentStore> mLast;
+ ObjectBaseRef<ProgramStore> mDefault;
+ ObjectBaseRef<ProgramStore> mLast;
- ProgramFragmentStore *mPFS;
+ ProgramStore *mPFS;
};
diff --git a/libs/rs/rsProgramVertex.cpp b/libs/rs/rsProgramVertex.cpp
index a2b2df4..d667c86 100644
--- a/libs/rs/rsProgramVertex.cpp
+++ b/libs/rs/rsProgramVertex.cpp
@@ -14,13 +14,19 @@
* limitations under the License.
*/
+#ifndef ANDROID_RS_BUILD_FOR_HOST
#include "rsContext.h"
-#include "rsProgramVertex.h"
-
#include <GLES/gl.h>
#include <GLES/glext.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
+#else
+#include "rsContextHostStub.h"
+#include <OpenGL/gl.h>
+#include <OpenGL/glext.h>
+#endif //ANDROID_RS_BUILD_FOR_HOST
+
+#include "rsProgramVertex.h"
using namespace android;
using namespace android::renderscript;
@@ -81,9 +87,12 @@
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
if (mLightCount) {
+#ifndef ANDROID_RS_BUILD_FOR_HOST // GLES Only
int v = 0;
glEnable(GL_LIGHTING);
+
glLightModelxv(GL_LIGHT_MODEL_TWO_SIDE, &v);
+
for (uint32_t ct = 0; ct < mLightCount; ct++) {
const Light *l = mLights[ct].get();
glEnable(GL_LIGHT0 + ct);
@@ -92,6 +101,7 @@
for (uint32_t ct = mLightCount; ct < MAX_LIGHTS; ct++) {
glDisable(GL_LIGHT0 + ct);
}
+#endif //ANDROID_RS_BUILD_FOR_HOST
} else {
glDisable(GL_LIGHTING);
}
@@ -168,11 +178,11 @@
}
mShader.append(mUserShader);
} else {
- mShader.append("attribute vec4 ATTRIB_LegacyPosition;\n");
- mShader.append("attribute vec4 ATTRIB_LegacyColor;\n");
- mShader.append("attribute vec3 ATTRIB_LegacyNormal;\n");
- mShader.append("attribute float ATTRIB_LegacyPointSize;\n");
- mShader.append("attribute vec4 ATTRIB_LegacyTexture;\n");
+ mShader.append("attribute vec4 ATTRIB_position;\n");
+ mShader.append("attribute vec4 ATTRIB_color;\n");
+ mShader.append("attribute vec3 ATTRIB_normal;\n");
+ mShader.append("attribute float ATTRIB_pointSize;\n");
+ mShader.append("attribute vec4 ATTRIB_texture0;\n");
for (uint32_t ct=0; ct < mUniformCount; ct++) {
mShader.append("uniform mat4 ");
@@ -181,14 +191,14 @@
}
mShader.append("void main() {\n");
- mShader.append(" gl_Position = UNI_MVP * ATTRIB_LegacyPosition;\n");
- mShader.append(" gl_PointSize = ATTRIB_LegacyPointSize;\n");
+ mShader.append(" gl_Position = UNI_MVP * ATTRIB_position;\n");
+ mShader.append(" gl_PointSize = ATTRIB_pointSize;\n");
- mShader.append(" varColor = ATTRIB_LegacyColor;\n");
+ mShader.append(" varColor = ATTRIB_color;\n");
if (mTextureMatrixEnable) {
- mShader.append(" varTex0 = UNI_TexMatrix * ATTRIB_LegacyTexture;\n");
+ mShader.append(" varTex0 = UNI_TexMatrix * ATTRIB_texture0;\n");
} else {
- mShader.append(" varTex0 = ATTRIB_LegacyTexture;\n");
+ mShader.append(" varTex0 = ATTRIB_texture0;\n");
}
//mShader.append(" pos.x = pos.x / 480.0;\n");
//mShader.append(" pos.y = pos.y / 800.0;\n");
@@ -351,6 +361,16 @@
createShader();
}
+void ProgramVertex::serialize(OStream *stream) const
+{
+
+}
+
+ProgramVertex *ProgramVertex::createFromStream(Context *rsc, IStream *stream)
+{
+ return NULL;
+}
+
///////////////////////////////////////////////////////////////////////
@@ -362,8 +382,9 @@
{
}
-void ProgramVertexState::init(Context *rsc, int32_t w, int32_t h)
+void ProgramVertexState::init(Context *rsc)
{
+#ifndef ANDROID_RS_BUILD_FOR_HOST
RsElement e = (RsElement) Element::create(rsc, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 1);
rsi_TypeBegin(rsc, e);
@@ -372,6 +393,7 @@
ProgramVertex *pv = new ProgramVertex(rsc, false);
Allocation *alloc = (Allocation *)rsi_AllocationCreateTyped(rsc, mAllocType.get());
+
mDefaultAlloc.set(alloc);
mDefault.set(pv);
pv->init(rsc);
@@ -382,13 +404,15 @@
color[2] = 1.f;
color[3] = 1.f;
- updateSize(rsc, w, h);
+ updateSize(rsc);
+#endif //ANDROID_RS_BUILD_FOR_HOST
+
}
-void ProgramVertexState::updateSize(Context *rsc, int32_t w, int32_t h)
+void ProgramVertexState::updateSize(Context *rsc)
{
Matrix m;
- m.loadOrtho(0,w, h,0, -1,1);
+ m.loadOrtho(0,rsc->getWidth(), rsc->getHeight(),0, -1,1);
mDefaultAlloc->subData(RS_PROGRAM_VERTEX_PROJECTION_OFFSET, 16, &m.m[0], 16*4);
m.loadIdentity();
diff --git a/libs/rs/rsProgramVertex.h b/libs/rs/rsProgramVertex.h
index 28554cc..cb93eaf 100644
--- a/libs/rs/rsProgramVertex.h
+++ b/libs/rs/rsProgramVertex.h
@@ -52,6 +52,9 @@
virtual void loadShader(Context *);
virtual void init(Context *);
+ virtual void serialize(OStream *stream) const;
+ virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_PROGRAM_VERTEX; }
+ static ProgramVertex *createFromStream(Context *rsc, IStream *stream);
protected:
uint32_t mLightCount;
@@ -71,9 +74,9 @@
ProgramVertexState();
~ProgramVertexState();
- void init(Context *rsc, int32_t w, int32_t h);
+ void init(Context *rsc);
void deinit(Context *rsc);
- void updateSize(Context *rsc, int32_t w, int32_t h);
+ void updateSize(Context *rsc);
ObjectBaseRef<ProgramVertex> mDefault;
ObjectBaseRef<ProgramVertex> mLast;
diff --git a/libs/rs/rsSampler.cpp b/libs/rs/rsSampler.cpp
index 71f508f..f41f295 100644
--- a/libs/rs/rsSampler.cpp
+++ b/libs/rs/rsSampler.cpp
@@ -14,10 +14,16 @@
* limitations under the License.
*/
+#ifndef ANDROID_RS_BUILD_FOR_HOST
#include <GLES/gl.h>
#include <GLES/glext.h>
-
#include "rsContext.h"
+#else
+#include "rsContextHostStub.h"
+#include <OpenGL/gl.h>
+#include <OpenGL/glext.h>
+#endif //ANDROID_RS_BUILD_FOR_HOST
+
#include "rsSampler.h"
@@ -94,6 +100,17 @@
mBoundSlot = -1;
ss->mSamplers[slot].clear();
}
+
+void Sampler::serialize(OStream *stream) const
+{
+
+}
+
+Sampler *Sampler::createFromStream(Context *rsc, IStream *stream)
+{
+ return NULL;
+}
+
/*
void SamplerState::setupGL()
{
diff --git a/libs/rs/rsSampler.h b/libs/rs/rsSampler.h
index 0506081..3786439 100644
--- a/libs/rs/rsSampler.h
+++ b/libs/rs/rsSampler.h
@@ -46,6 +46,10 @@
void bindToContext(SamplerState *, uint32_t slot);
void unbindFromContext(SamplerState *);
+ virtual void serialize(OStream *stream) const;
+ virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_SAMPLER; }
+ static Sampler *createFromStream(Context *rsc, IStream *stream);
+
protected:
RsSamplerValue mMagFilter;
RsSamplerValue mMinFilter;
diff --git a/libs/rs/rsScript.cpp b/libs/rs/rsScript.cpp
index a33933b..fc22fc3 100644
--- a/libs/rs/rsScript.cpp
+++ b/libs/rs/rsScript.cpp
@@ -24,19 +24,25 @@
mAllocFile = __FILE__;
mAllocLine = __LINE__;
memset(&mEnviroment, 0, sizeof(mEnviroment));
- mEnviroment.mClearColor[0] = 0;
- mEnviroment.mClearColor[1] = 0;
- mEnviroment.mClearColor[2] = 0;
- mEnviroment.mClearColor[3] = 1;
- mEnviroment.mClearDepth = 1;
- mEnviroment.mClearStencil = 0;
- mEnviroment.mIsRoot = false;
}
Script::~Script()
{
}
+void Script::setVar(uint32_t slot, const void *val, uint32_t len)
+{
+ int32_t *destPtr = ((int32_t **)mEnviroment.mFieldAddress)[slot];
+ if (destPtr) {
+ //LOGE("setVar f1 %f", ((const float *)destPtr)[0]);
+ //LOGE("setVar %p %i", destPtr, len);
+ memcpy(destPtr, val, len);
+ //LOGE("setVar f2 %f", ((const float *)destPtr)[0]);
+ } else {
+ LOGE("Calling setVar on slot = %i which is null", slot);
+ }
+}
+
namespace android {
namespace renderscript {
@@ -44,16 +50,9 @@
void rsi_ScriptBindAllocation(Context * rsc, RsScript vs, RsAllocation va, uint32_t slot)
{
Script *s = static_cast<Script *>(vs);
- s->mSlots[slot].set(static_cast<Allocation *>(va));
-}
-
-void rsi_ScriptSetClearColor(Context * rsc, RsScript vs, float r, float g, float b, float a)
-{
- Script *s = static_cast<Script *>(vs);
- s->mEnviroment.mClearColor[0] = r;
- s->mEnviroment.mClearColor[1] = g;
- s->mEnviroment.mClearColor[2] = b;
- s->mEnviroment.mClearColor[3] = a;
+ Allocation *a = static_cast<Allocation *>(va);
+ s->mSlots[slot].set(a);
+ //LOGE("rsi_ScriptBindAllocation %i %p %p", slot, a, a->getPtr());
}
void rsi_ScriptSetTimeZone(Context * rsc, RsScript vs, const char * timeZone, uint32_t length)
@@ -62,53 +61,51 @@
s->mEnviroment.mTimeZone = timeZone;
}
-void rsi_ScriptSetClearDepth(Context * rsc, RsScript vs, float v)
-{
- Script *s = static_cast<Script *>(vs);
- s->mEnviroment.mClearDepth = v;
-}
-
-void rsi_ScriptSetClearStencil(Context * rsc, RsScript vs, uint32_t v)
-{
- Script *s = static_cast<Script *>(vs);
- s->mEnviroment.mClearStencil = v;
-}
-
void rsi_ScriptSetType(Context * rsc, RsType vt, uint32_t slot, bool writable, const char *name)
{
ScriptCState *ss = &rsc->mScriptC;
const Type *t = static_cast<const Type *>(vt);
ss->mConstantBufferTypes[slot].set(t);
ss->mSlotWritable[slot] = writable;
- if (name) {
- ss->mSlotNames[slot].setTo(name);
- } else {
- ss->mSlotNames[slot].setTo("");
- }
-}
-
-void rsi_ScriptSetInvoke(Context *rsc, const char *name, uint32_t slot)
-{
- ScriptCState *ss = &rsc->mScriptC;
- ss->mInvokableNames[slot] = name;
+ LOGE("rsi_ScriptSetType");
}
void rsi_ScriptInvoke(Context *rsc, RsScript vs, uint32_t slot)
{
Script *s = static_cast<Script *>(vs);
- if (s->mEnviroment.mInvokables[slot] == NULL) {
- rsc->setError(RS_ERROR_BAD_SCRIPT, "Calling invoke on bad script");
- return;
- }
- s->setupScript();
- s->mEnviroment.mInvokables[slot]();
+ s->Invoke(rsc, slot, NULL, 0);
}
-void rsi_ScriptSetRoot(Context * rsc, bool isRoot)
+void rsi_ScriptInvokeData(Context *rsc, RsScript vs, uint32_t slot, void *data)
{
- ScriptCState *ss = &rsc->mScriptC;
- ss->mScript->mEnviroment.mIsRoot = isRoot;
+ Script *s = static_cast<Script *>(vs);
+ s->Invoke(rsc, slot, NULL, 0);
+}
+
+void rsi_ScriptInvokeV(Context *rsc, RsScript vs, uint32_t slot, const void *data, uint32_t len)
+{
+ Script *s = static_cast<Script *>(vs);
+ s->Invoke(rsc, slot, data, len);
+}
+
+void rsi_ScriptSetVarI(Context *rsc, RsScript vs, uint32_t slot, int value)
+{
+ Script *s = static_cast<Script *>(vs);
+ s->setVar(slot, &value, sizeof(value));
+}
+
+void rsi_ScriptSetVarF(Context *rsc, RsScript vs, uint32_t slot, float value)
+{
+ Script *s = static_cast<Script *>(vs);
+ s->setVar(slot, &value, sizeof(value));
+}
+
+void rsi_ScriptSetVarV(Context *rsc, RsScript vs, uint32_t slot, const void *data, uint32_t len)
+{
+ const float *fp = (const float *)data;
+ Script *s = static_cast<Script *>(vs);
+ s->setVar(slot, data, len);
}
diff --git a/libs/rs/rsScript.h b/libs/rs/rsScript.h
index 5f4a536..ea6aec5 100644
--- a/libs/rs/rsScript.h
+++ b/libs/rs/rsScript.h
@@ -27,9 +27,9 @@
class ProgramVertex;
class ProgramFragment;
class ProgramRaster;
-class ProgramFragmentStore;
+class ProgramStore;
-#define MAX_SCRIPT_BANKS 16
+#define MAX_SCRIPT_BANKS 32
class Script : public ObjectBase
{
@@ -39,38 +39,38 @@
Script(Context *);
virtual ~Script();
-
struct Enviroment_t {
- bool mIsRoot;
- float mClearColor[4];
- float mClearDepth;
- uint32_t mClearStencil;
-
uint32_t mStartTimeMillis;
const char* mTimeZone;
ObjectBaseRef<ProgramVertex> mVertex;
ObjectBaseRef<ProgramFragment> mFragment;
ObjectBaseRef<ProgramRaster> mRaster;
- ObjectBaseRef<ProgramFragmentStore> mFragmentStore;
- InvokeFunc_t mInvokables[MAX_SCRIPT_BANKS];
+ ObjectBaseRef<ProgramStore> mFragmentStore;
+
+ uint32_t mInvokeFunctionCount;
+ InvokeFunc_t *mInvokeFunctions;
+ uint32_t mFieldCount;
+ void ** mFieldAddress;
+
char * mScriptText;
uint32_t mScriptTextLength;
};
Enviroment_t mEnviroment;
- uint32_t mCounstantBufferCount;
-
-
ObjectBaseRef<Allocation> mSlots[MAX_SCRIPT_BANKS];
ObjectBaseRef<const Type> mTypes[MAX_SCRIPT_BANKS];
- String8 mSlotNames[MAX_SCRIPT_BANKS];
bool mSlotWritable[MAX_SCRIPT_BANKS];
+ void setVar(uint32_t slot, const void *val, uint32_t len);
+ virtual void runForEach(Context *rsc, const Allocation *ain, Allocation *aout) = 0;
+ virtual void runForEach(Context *rsc, const Allocation *ain, Allocation *aout, uint32_t xStart, uint32_t xEnd) = 0;
+ virtual void runForEach(Context *rsc, const Allocation *ain, Allocation *aout, uint32_t xStart, uint32_t yStart, uint32_t xEnd, uint32_t yEnd) = 0;
- virtual void setupScript() = 0;
- virtual uint32_t run(Context *, uint32_t launchID) = 0;
+ virtual void Invoke(Context *rsc, uint32_t slot, const void *data, uint32_t len) = 0;
+ virtual void setupScript(Context *rsc) = 0;
+ virtual uint32_t run(Context *) = 0;
};
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index f4d2451..ef37286 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -17,8 +17,7 @@
#include "rsContext.h"
#include "rsScriptC.h"
#include "rsMatrix.h"
-
-#include "acc/acc.h"
+#include "../../../external/llvm/libbcc/include/bcc/bcc.h"
#include "utils/Timers.h"
#include <GLES/gl.h>
@@ -37,40 +36,74 @@
{
mAllocFile = __FILE__;
mAllocLine = __LINE__;
- mAccScript = NULL;
+ mBccScript = NULL;
memset(&mProgram, 0, sizeof(mProgram));
}
ScriptC::~ScriptC()
{
- if (mAccScript) {
- accDeleteScript(mAccScript);
+ if (mBccScript) {
+ bccDeleteScript(mBccScript);
}
free(mEnviroment.mScriptText);
mEnviroment.mScriptText = NULL;
}
-void ScriptC::setupScript()
+void ScriptC::setupScript(Context *rsc)
{
- for (int ct=0; ct < MAX_SCRIPT_BANKS; ct++) {
- if (mProgram.mSlotPointers[ct]) {
- *mProgram.mSlotPointers[ct] = mSlots[ct]->getPtr();
+ setupGLState(rsc);
+ mEnviroment.mStartTimeMillis
+ = nanoseconds_to_milliseconds(systemTime(SYSTEM_TIME_MONOTONIC));
+
+ for (uint32_t ct=0; ct < mEnviroment.mFieldCount; ct++) {
+ if (!mSlots[ct].get())
+ continue;
+ void *ptr = mSlots[ct]->getPtr();
+ void **dest = ((void ***)mEnviroment.mFieldAddress)[ct];
+ //LOGE("setupScript %i %p = %p %p %i", ct, dest, ptr, mSlots[ct]->getType(), mSlots[ct]->getType()->getDimX());
+
+ //const uint32_t *p32 = (const uint32_t *)ptr;
+ //for (uint32_t ct2=0; ct2 < mSlots[ct]->getType()->getDimX(); ct2++) {
+ //LOGE(" %i = 0x%08x ", ct2, p32[ct2]);
+ //}
+
+ if (dest) {
+ *dest = ptr;
+ } else {
+ LOGE("ScriptC::setupScript, NULL var binding address.");
}
}
}
-
-uint32_t ScriptC::run(Context *rsc, uint32_t launchIndex)
+const Allocation *ScriptC::ptrToAllocation(const void *ptr) const
{
- if (mProgram.mScript == NULL) {
- rsc->setError(RS_ERROR_BAD_SCRIPT, "Attempted to run bad script");
- return 0;
+ if (!ptr) {
+ return NULL;
}
+ for (uint32_t ct=0; ct < mEnviroment.mFieldCount; ct++) {
+ if (!mSlots[ct].get())
+ continue;
+ if (mSlots[ct]->getPtr() == ptr) {
+ return mSlots[ct].get();
+ }
+ }
+ LOGE("ScriptC::ptrToAllocation, failed to find %p", ptr);
+ return NULL;
+}
- Context::ScriptTLSStruct * tls =
- (Context::ScriptTLSStruct *)pthread_getspecific(Context::gThreadTLSKey);
+Script * ScriptC::setTLS(Script *sc)
+{
+ Context::ScriptTLSStruct * tls = (Context::ScriptTLSStruct *)
+ pthread_getspecific(Context::gThreadTLSKey);
rsAssert(tls);
+ Script *old = tls->mScript;
+ tls->mScript = sc;
+ return old;
+}
+
+void ScriptC::setupGLState(Context *rsc)
+{
if (mEnviroment.mFragmentStore.get()) {
rsc->setFragmentStore(mEnviroment.mFragmentStore.get());
}
@@ -83,20 +116,92 @@
if (mEnviroment.mRaster.get()) {
rsc->setRaster(mEnviroment.mRaster.get());
}
+}
- if (launchIndex == 0) {
- mEnviroment.mStartTimeMillis
- = nanoseconds_to_milliseconds(systemTime(SYSTEM_TIME_MONOTONIC));
+uint32_t ScriptC::run(Context *rsc)
+{
+ if (mProgram.mRoot == NULL) {
+ rsc->setError(RS_ERROR_BAD_SCRIPT, "Attempted to run bad script");
+ return 0;
}
- setupScript();
+
+ setupScript(rsc);
uint32_t ret = 0;
- tls->mScript = this;
- ret = mProgram.mScript(launchIndex);
- tls->mScript = NULL;
+ Script * oldTLS = setTLS(this);
+ //LOGE("ScriptC::run %p", mProgram.mRoot);
+ ret = mProgram.mRoot();
+ setTLS(oldTLS);
+ //LOGE("ScriptC::run ret %i", ret);
return ret;
}
+void ScriptC::runForEach(Context *rsc, const Allocation *ain, Allocation *aout,
+ uint32_t xStart, uint32_t yStart, uint32_t xEnd, uint32_t yEnd)
+{
+ LOGE("ScriptC::runForEach not implemented");
+}
+
+void ScriptC::runForEach(Context *rsc, const Allocation *ain, Allocation *aout, uint32_t xStart, uint32_t xEnd)
+{
+ uint32_t dimX = ain->getType()->getDimX();
+ rsAssert(xStart < dimX);
+ rsAssert(xEnd <= dimX);
+ rsAssert(ain->getType()->getDimY() == 0);
+ rsAssert(ain->getType()->getDimZ() == 0);
+
+ if (xStart >= dimX) xStart = dimX - 1;
+ if (xEnd >= dimX) xEnd = dimX - 1;
+ if (xStart > xEnd) return;
+
+ setupScript(rsc);
+ Script * oldTLS = setTLS(this);
+
+ typedef int (*rs_t)(const void *, void *, uint32_t);
+ const uint8_t *ptrIn = (const uint8_t *)ain->getPtr();
+ uint32_t strideIn = ain->getType()->getElementSizeBytes();
+
+ uint8_t *ptrOut = NULL;
+ uint32_t strideOut = 0;
+ if (aout) {
+ ptrOut = (uint8_t *)aout->getPtr();
+ strideOut = aout->getType()->getElementSizeBytes();
+ }
+
+ for (uint32_t ct=xStart; ct < xEnd; ct++) {
+ ((rs_t)mProgram.mRoot) (ptrIn + (strideIn * ct), ptrOut + (strideOut * ct), ct);
+ }
+
+ setTLS(oldTLS);
+}
+
+void ScriptC::runForEach(Context *rsc, const Allocation *ain, Allocation *aout)
+{
+ if (ain->getType()->getDimY()) {
+ runForEach(rsc, ain, aout, 0, 0, 0xffffffff, 0xffffffff);
+ } else {
+ runForEach(rsc, ain, aout, 0, 0xffffffff);
+ }
+}
+
+
+void ScriptC::Invoke(Context *rsc, uint32_t slot, const void *data, uint32_t len)
+{
+ //LOGE("rsi_ScriptInvoke %i", slot);
+ if ((slot >= mEnviroment.mInvokeFunctionCount) ||
+ (mEnviroment.mInvokeFunctions[slot] == NULL)) {
+ rsc->setError(RS_ERROR_BAD_SCRIPT, "Calling invoke on bad script");
+ return;
+ }
+ setupScript(rsc);
+ Script * oldTLS = setTLS(this);
+
+ ((void (*)(const void *, uint32_t))
+ mEnviroment.mInvokeFunctions[slot])(data, len);
+
+ setTLS(oldTLS);
+}
+
ScriptCState::ScriptCState()
{
mScript = NULL;
@@ -113,21 +218,25 @@
{
for (uint32_t ct=0; ct < MAX_SCRIPT_BANKS; ct++) {
mConstantBufferTypes[ct].clear();
- mSlotNames[ct].setTo("");
- mInvokableNames[ct].setTo("");
mSlotWritable[ct] = false;
}
delete mScript;
mScript = new ScriptC(NULL);
-
- mInt32Defines.clear();
- mFloatDefines.clear();
}
-static ACCvoid* symbolLookup(ACCvoid* pContext, const ACCchar* name)
+static BCCvoid* symbolLookup(BCCvoid* pContext, const BCCchar* name)
{
- const ScriptCState::SymbolTable_t *sym = ScriptCState::lookupSymbol(name);
+ const ScriptCState::SymbolTable_t *sym;
+ sym = ScriptCState::lookupSymbol(name);
+ if (sym) {
+ return sym->mPtr;
+ }
+ sym = ScriptCState::lookupSymbolCL(name);
+ if (sym) {
+ return sym->mPtr;
+ }
+ sym = ScriptCState::lookupSymbolGL(name);
if (sym) {
return sym->mPtr;
}
@@ -137,65 +246,52 @@
void ScriptCState::runCompiler(Context *rsc, ScriptC *s)
{
- s->mAccScript = accCreateScript();
- String8 tmp;
+ LOGE("ScriptCState::runCompiler ");
- rsc->appendNameDefines(&tmp);
- appendDecls(&tmp);
- appendVarDefines(rsc, &tmp);
- appendTypes(rsc, &tmp);
- tmp.append("#line 1\n");
-
- const char* scriptSource[] = {tmp.string(), s->mEnviroment.mScriptText};
- int scriptLength[] = {tmp.length(), s->mEnviroment.mScriptTextLength} ;
- accScriptSource(s->mAccScript, sizeof(scriptLength) / sizeof(int), scriptSource, scriptLength);
- accRegisterSymbolCallback(s->mAccScript, symbolLookup, NULL);
- accCompileScript(s->mAccScript);
- accGetScriptLabel(s->mAccScript, "main", (ACCvoid**) &s->mProgram.mScript);
- accGetScriptLabel(s->mAccScript, "init", (ACCvoid**) &s->mProgram.mInit);
- rsAssert(s->mProgram.mScript);
-
- if (!s->mProgram.mScript) {
- ACCchar buf[4096];
- ACCsizei len;
- accGetScriptInfoLog(s->mAccScript, sizeof(buf), &len, buf);
- LOGE("%s", buf);
- rsc->setError(RS_ERROR_BAD_SCRIPT, "Error compiling user script.");
- return;
- }
+ s->mBccScript = bccCreateScript();
+ bccScriptBitcode(s->mBccScript, s->mEnviroment.mScriptText, s->mEnviroment.mScriptTextLength);
+ bccRegisterSymbolCallback(s->mBccScript, symbolLookup, NULL);
+ bccCompileScript(s->mBccScript);
+ bccGetScriptLabel(s->mBccScript, "root", (BCCvoid**) &s->mProgram.mRoot);
+ bccGetScriptLabel(s->mBccScript, "init", (BCCvoid**) &s->mProgram.mInit);
+ LOGE("root %p, init %p", s->mProgram.mRoot, s->mProgram.mInit);
if (s->mProgram.mInit) {
s->mProgram.mInit();
}
- for (int ct=0; ct < MAX_SCRIPT_BANKS; ct++) {
- if (mSlotNames[ct].length() > 0) {
- accGetScriptLabel(s->mAccScript,
- mSlotNames[ct].string(),
- (ACCvoid**) &s->mProgram.mSlotPointers[ct]);
- }
+ s->mEnviroment.mInvokeFunctions = (Script::InvokeFunc_t *)calloc(100, sizeof(void *));
+ BCCchar **labels = new char*[100];
+ bccGetFunctions(s->mBccScript, (BCCsizei *)&s->mEnviroment.mInvokeFunctionCount,
+ 100, (BCCchar **)labels);
+ //LOGE("func count %i", s->mEnviroment.mInvokeFunctionCount);
+ for (uint32_t i=0; i < s->mEnviroment.mInvokeFunctionCount; i++) {
+ BCCsizei length;
+ bccGetFunctionBinary(s->mBccScript, labels[i], (BCCvoid **)&(s->mEnviroment.mInvokeFunctions[i]), &length);
+ //LOGE("func %i %p", i, s->mEnviroment.mInvokeFunctions[i]);
}
- for (int ct=0; ct < MAX_SCRIPT_BANKS; ct++) {
- if (mInvokableNames[ct].length() > 0) {
- accGetScriptLabel(s->mAccScript,
- mInvokableNames[ct].string(),
- (ACCvoid**) &s->mEnviroment.mInvokables[ct]);
- }
+ s->mEnviroment.mFieldAddress = (void **)calloc(100, sizeof(void *));
+ bccGetExportVars(s->mBccScript, (BCCsizei *)&s->mEnviroment.mFieldCount,
+ 100, s->mEnviroment.mFieldAddress);
+ //LOGE("var count %i", s->mEnviroment.mFieldCount);
+ for (uint32_t i=0; i < s->mEnviroment.mFieldCount; i++) {
+ //LOGE("var %i %p", i, s->mEnviroment.mFieldAddress[i]);
}
s->mEnviroment.mFragment.set(rsc->getDefaultProgramFragment());
s->mEnviroment.mVertex.set(rsc->getDefaultProgramVertex());
- s->mEnviroment.mFragmentStore.set(rsc->getDefaultProgramFragmentStore());
+ s->mEnviroment.mFragmentStore.set(rsc->getDefaultProgramStore());
s->mEnviroment.mRaster.set(rsc->getDefaultProgramRaster());
- if (s->mProgram.mScript) {
+ if (s->mProgram.mRoot) {
const static int pragmaMax = 16;
- ACCsizei pragmaCount;
- ACCchar * str[pragmaMax];
- accGetPragmas(s->mAccScript, &pragmaCount, pragmaMax, &str[0]);
+ BCCsizei pragmaCount;
+ BCCchar * str[pragmaMax];
+ bccGetPragmas(s->mBccScript, &pragmaCount, pragmaMax, &str[0]);
for (int ct=0; ct < pragmaCount; ct+=2) {
+ //LOGE("pragme %s %s", str[ct], str[ct+1]);
if (!strcmp(str[ct], "version")) {
continue;
}
@@ -208,11 +304,6 @@
s->mEnviroment.mVertex.clear();
continue;
}
- ProgramVertex * pv = (ProgramVertex *)rsc->lookupName(str[ct+1]);
- if (pv != NULL) {
- s->mEnviroment.mVertex.set(pv);
- continue;
- }
LOGE("Unreconized value %s passed to stateVertex", str[ct+1]);
}
@@ -224,11 +315,6 @@
s->mEnviroment.mRaster.clear();
continue;
}
- ProgramRaster * pr = (ProgramRaster *)rsc->lookupName(str[ct+1]);
- if (pr != NULL) {
- s->mEnviroment.mRaster.set(pr);
- continue;
- }
LOGE("Unreconized value %s passed to stateRaster", str[ct+1]);
}
@@ -240,11 +326,6 @@
s->mEnviroment.mFragment.clear();
continue;
}
- ProgramFragment * pf = (ProgramFragment *)rsc->lookupName(str[ct+1]);
- if (pf != NULL) {
- s->mEnviroment.mFragment.set(pf);
- continue;
- }
LOGE("Unreconized value %s passed to stateFragment", str[ct+1]);
}
@@ -256,12 +337,6 @@
s->mEnviroment.mFragmentStore.clear();
continue;
}
- ProgramFragmentStore * pfs =
- (ProgramFragmentStore *)rsc->lookupName(str[ct+1]);
- if (pfs != NULL) {
- s->mEnviroment.mFragmentStore.set(pfs);
- continue;
- }
LOGE("Unreconized value %s passed to stateStore", str[ct+1]);
}
@@ -273,111 +348,6 @@
}
}
-static void appendElementBody(String8 *s, const Element *e)
-{
- s->append(" {\n");
- for (size_t ct2=0; ct2 < e->getFieldCount(); ct2++) {
- const Element *c = e->getField(ct2);
- s->append(" ");
- s->append(c->getCType());
- s->append(" ");
- s->append(e->getFieldName(ct2));
- s->append(";\n");
- }
- s->append("}");
-}
-
-void ScriptCState::appendVarDefines(const Context *rsc, String8 *str)
-{
- char buf[256];
- if (rsc->props.mLogScripts) {
- LOGD("appendVarDefines mInt32Defines.size()=%d mFloatDefines.size()=%d\n",
- mInt32Defines.size(), mFloatDefines.size());
- }
- for (size_t ct=0; ct < mInt32Defines.size(); ct++) {
- str->append("#define ");
- str->append(mInt32Defines.keyAt(ct));
- str->append(" ");
- sprintf(buf, "%i\n", (int)mInt32Defines.valueAt(ct));
- str->append(buf);
- }
- for (size_t ct=0; ct < mFloatDefines.size(); ct++) {
- str->append("#define ");
- str->append(mFloatDefines.keyAt(ct));
- str->append(" ");
- sprintf(buf, "%ff\n", mFloatDefines.valueAt(ct));
- str->append(buf);
- }
-}
-
-
-
-void ScriptCState::appendTypes(const Context *rsc, String8 *str)
-{
- char buf[256];
- String8 tmp;
-
- str->append("struct vecF32_2_s {float x; float y;};\n");
- str->append("struct vecF32_3_s {float x; float y; float z;};\n");
- str->append("struct vecF32_4_s {float x; float y; float z; float w;};\n");
- str->append("struct vecU8_4_s {char r; char g; char b; char a;};\n");
- str->append("#define vecF32_2_t struct vecF32_2_s\n");
- str->append("#define vecF32_3_t struct vecF32_3_s\n");
- str->append("#define vecF32_4_t struct vecF32_4_s\n");
- str->append("#define vecU8_4_t struct vecU8_4_s\n");
- str->append("#define vecI8_4_t struct vecU8_4_s\n");
-
- for (size_t ct=0; ct < MAX_SCRIPT_BANKS; ct++) {
- const Type *t = mConstantBufferTypes[ct].get();
- if (!t) {
- continue;
- }
- const Element *e = t->getElement();
- if (e->getName() && (e->getFieldCount() > 1)) {
- String8 s("struct struct_");
- s.append(e->getName());
- s.append(e->getCStructBody());
- s.append(";\n");
-
- s.append("#define ");
- s.append(e->getName());
- s.append("_t struct struct_");
- s.append(e->getName());
- s.append("\n\n");
- if (rsc->props.mLogScripts) {
- LOGV("%s", static_cast<const char*>(s));
- }
- str->append(s);
- }
-
- if (mSlotNames[ct].length() > 0) {
- String8 s;
- if (e->getName()) {
- // Use the named struct
- s.setTo(e->getName());
- } else {
- // create an struct named from the slot.
- s.setTo("struct ");
- s.append(mSlotNames[ct]);
- s.append("_s");
- s.append(e->getCStructBody());
- //appendElementBody(&s, e);
- s.append(";\n");
- s.append("struct ");
- s.append(mSlotNames[ct]);
- s.append("_s");
- }
-
- s.append(" * ");
- s.append(mSlotNames[ct]);
- s.append(";\n");
- if (rsc->props.mLogScripts) {
- LOGV("%s", static_cast<const char*>(s));
- }
- str->append(s);
- }
- }
-}
namespace android {
@@ -420,7 +390,6 @@
s->setContext(rsc);
for (int ct=0; ct < MAX_SCRIPT_BANKS; ct++) {
s->mTypes[ct].set(ss->mConstantBufferTypes[ct].get());
- s->mSlotNames[ct] = ss->mSlotNames[ct];
s->mSlotWritable[ct] = ss->mSlotWritable[ct];
}
@@ -428,18 +397,6 @@
return s;
}
-void rsi_ScriptCSetDefineF(Context *rsc, const char* name, float value)
-{
- ScriptCState *ss = &rsc->mScriptC;
- ss->mFloatDefines.add(String8(name), value);
-}
-
-void rsi_ScriptCSetDefineI32(Context *rsc, const char* name, int32_t value)
-{
- ScriptCState *ss = &rsc->mScriptC;
- ss->mInt32Defines.add(String8(name), value);
-}
-
}
}
diff --git a/libs/rs/rsScriptC.h b/libs/rs/rsScriptC.h
index 35abadf..50e8a4c 100644
--- a/libs/rs/rsScriptC.h
+++ b/libs/rs/rsScriptC.h
@@ -21,9 +21,7 @@
#include "RenderScriptEnv.h"
-#include <utils/KeyedVector.h>
-
-struct ACCscript;
+struct BCCscript;
// ---------------------------------------------------------------------------
namespace android {
@@ -34,7 +32,7 @@
class ScriptC : public Script
{
public:
- typedef int (*RunScript_t)(uint32_t launchIndex);
+ typedef int (*RunScript_t)();
typedef void (*VoidFunc_t)();
ScriptC(Context *);
@@ -44,18 +42,33 @@
int mVersionMajor;
int mVersionMinor;
- RunScript_t mScript;
+ RunScript_t mRoot;
VoidFunc_t mInit;
-
- void ** mSlotPointers[MAX_SCRIPT_BANKS];
};
Program_t mProgram;
- ACCscript* mAccScript;
+ BCCscript* mBccScript;
- virtual void setupScript();
- virtual uint32_t run(Context *, uint32_t launchID);
+ const Allocation *ptrToAllocation(const void *) const;
+
+
+ virtual void Invoke(Context *rsc, uint32_t slot, const void *data, uint32_t len);
+
+ virtual uint32_t run(Context *);
+
+ virtual void runForEach(Context *rsc, const Allocation *ain, Allocation *aout);
+ virtual void runForEach(Context *rsc, const Allocation *ain, Allocation *aout, uint32_t xStart, uint32_t xEnd);
+ virtual void runForEach(Context *rsc, const Allocation *ain, Allocation *aout, uint32_t xStart, uint32_t yStart, uint32_t xEnd, uint32_t yEnd);
+
+ virtual void serialize(OStream *stream) const { }
+ virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_SCRIPT_C; }
+ static Type *createFromStream(Context *rsc, IStream *stream) { return NULL; }
+
+protected:
+ void setupScript(Context *);
+ void setupGLState(Context *);
+ Script * setTLS(Script *);
};
class ScriptCState
@@ -67,27 +80,21 @@
ScriptC *mScript;
ObjectBaseRef<const Type> mConstantBufferTypes[MAX_SCRIPT_BANKS];
- String8 mSlotNames[MAX_SCRIPT_BANKS];
+ //String8 mSlotNames[MAX_SCRIPT_BANKS];
bool mSlotWritable[MAX_SCRIPT_BANKS];
- String8 mInvokableNames[MAX_SCRIPT_BANKS];
+ //String8 mInvokableNames[MAX_SCRIPT_BANKS];
void clear();
void runCompiler(Context *rsc, ScriptC *s);
- void appendVarDefines(const Context *rsc, String8 *str);
- void appendTypes(const Context *rsc, String8 *str);
struct SymbolTable_t {
const char * mName;
void * mPtr;
- const char * mRet;
- const char * mParam;
};
- static SymbolTable_t gSyms[];
+ //static SymbolTable_t gSyms[];
static const SymbolTable_t * lookupSymbol(const char *);
- static void appendDecls(String8 *str);
-
- KeyedVector<String8,int> mInt32Defines;
- KeyedVector<String8,float> mFloatDefines;
+ static const SymbolTable_t * lookupSymbolCL(const char *);
+ static const SymbolTable_t * lookupSymbolGL(const char *);
};
diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp
index 202ca3d..3f3ff23 100644
--- a/libs/rs/rsScriptC_Lib.cpp
+++ b/libs/rs/rsScriptC_Lib.cpp
@@ -17,18 +17,10 @@
#include "rsContext.h"
#include "rsScriptC.h"
#include "rsMatrix.h"
-#include "rsNoise.h"
#include "acc/acc.h"
#include "utils/Timers.h"
-#define GL_GLEXT_PROTOTYPES
-
-#include <GLES/gl.h>
-#include <GLES/glext.h>
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-
#include <time.h>
using namespace android;
@@ -39,6 +31,13 @@
Context * rsc = tls->mContext; \
ScriptC * sc = (ScriptC *) tls->mScript
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Non-Updated code below
+//////////////////////////////////////////////////////////////////////////////
+
typedef struct {
float x;
float y;
@@ -57,123 +56,6 @@
float y;
} vec2_t;
-//////////////////////////////////////////////////////////////////////////////
-// IO routines
-//////////////////////////////////////////////////////////////////////////////
-
-static float SC_loadF(uint32_t bank, uint32_t offset)
-{
- GET_TLS();
- const void *vp = sc->mSlots[bank]->getPtr();
- const float *f = static_cast<const float *>(vp);
- //LOGE("loadF %i %i = %f %x", bank, offset, f, ((int *)&f)[0]);
- return f[offset];
-}
-
-static int32_t SC_loadI32(uint32_t bank, uint32_t offset)
-{
- GET_TLS();
- const void *vp = sc->mSlots[bank]->getPtr();
- const int32_t *i = static_cast<const int32_t *>(vp);
- //LOGE("loadI32 %i %i = %i", bank, offset, t);
- return i[offset];
-}
-
-static float* SC_loadArrayF(uint32_t bank, uint32_t offset)
-{
- GET_TLS();
- void *vp = sc->mSlots[bank]->getPtr();
- float *f = static_cast<float *>(vp);
- return f + offset;
-}
-
-static int32_t* SC_loadArrayI32(uint32_t bank, uint32_t offset)
-{
- GET_TLS();
- void *vp = sc->mSlots[bank]->getPtr();
- int32_t *i = static_cast<int32_t *>(vp);
- return i + offset;
-}
-
-static float* SC_loadSimpleMeshVerticesF(RsSimpleMesh mesh, uint32_t idx)
-{
- SimpleMesh *tm = static_cast<SimpleMesh *>(mesh);
- void *vp = tm->mVertexBuffers[idx]->getPtr();;
- return static_cast<float *>(vp);
-}
-
-static void SC_updateSimpleMesh(RsSimpleMesh mesh)
-{
- GET_TLS();
- SimpleMesh *sm = static_cast<SimpleMesh *>(mesh);
- sm->uploadAll(rsc);
-}
-
-static uint32_t SC_loadU32(uint32_t bank, uint32_t offset)
-{
- GET_TLS();
- const void *vp = sc->mSlots[bank]->getPtr();
- const uint32_t *i = static_cast<const uint32_t *>(vp);
- return i[offset];
-}
-
-static void SC_loadVec4(uint32_t bank, uint32_t offset, rsc_Vector4 *v)
-{
- GET_TLS();
- const void *vp = sc->mSlots[bank]->getPtr();
- const float *f = static_cast<const float *>(vp);
- memcpy(v, &f[offset], sizeof(rsc_Vector4));
-}
-
-static void SC_loadMatrix(uint32_t bank, uint32_t offset, rsc_Matrix *m)
-{
- GET_TLS();
- const void *vp = sc->mSlots[bank]->getPtr();
- const float *f = static_cast<const float *>(vp);
- memcpy(m, &f[offset], sizeof(rsc_Matrix));
-}
-
-
-static void SC_storeF(uint32_t bank, uint32_t offset, float v)
-{
- //LOGE("storeF %i %i %f", bank, offset, v);
- GET_TLS();
- void *vp = sc->mSlots[bank]->getPtr();
- float *f = static_cast<float *>(vp);
- f[offset] = v;
-}
-
-static void SC_storeI32(uint32_t bank, uint32_t offset, int32_t v)
-{
- GET_TLS();
- void *vp = sc->mSlots[bank]->getPtr();
- int32_t *f = static_cast<int32_t *>(vp);
- static_cast<int32_t *>(sc->mSlots[bank]->getPtr())[offset] = v;
-}
-
-static void SC_storeU32(uint32_t bank, uint32_t offset, uint32_t v)
-{
- GET_TLS();
- void *vp = sc->mSlots[bank]->getPtr();
- uint32_t *f = static_cast<uint32_t *>(vp);
- static_cast<uint32_t *>(sc->mSlots[bank]->getPtr())[offset] = v;
-}
-
-static void SC_storeVec4(uint32_t bank, uint32_t offset, const rsc_Vector4 *v)
-{
- GET_TLS();
- void *vp = sc->mSlots[bank]->getPtr();
- float *f = static_cast<float *>(vp);
- memcpy(&f[offset], v, sizeof(rsc_Vector4));
-}
-
-static void SC_storeMatrix(uint32_t bank, uint32_t offset, const rsc_Matrix *m)
-{
- GET_TLS();
- void *vp = sc->mSlots[bank]->getPtr();
- float *f = static_cast<float *>(vp);
- memcpy(&f[offset], m, sizeof(rsc_Matrix));
-}
//////////////////////////////////////////////////////////////////////////////
// Vec3 routines
@@ -281,10 +163,6 @@
// Math routines
//////////////////////////////////////////////////////////////////////////////
-#define PI 3.1415926f
-#define DEG_TO_RAD PI / 180.0f
-#define RAD_TO_DEG 180.0f / PI
-
static float SC_sinf_fast(float x)
{
const float A = 1.0f / (2.0f * M_PI);
@@ -323,6 +201,7 @@
return 0.2215f * (y * fabsf(y) - y) + y;
}
+
static float SC_randf(float max)
{
float r = (float)rand();
@@ -335,19 +214,14 @@
return r / RAND_MAX * (max - min) + min;
}
-static int SC_sign(int value)
+static int SC_randi(int max)
{
- return (value > 0) - (value < 0);
+ return (int)SC_randf(max);
}
-static float SC_signf(float value)
+static int SC_randi2(int min, int max)
{
- return (value > 0) - (value < 0);
-}
-
-static float SC_clampf(float amount, float low, float high)
-{
- return amount < low ? low : (amount > high ? high : amount);
+ return (int)SC_randf2(min, max);
}
static int SC_clamp(int amount, int low, int high)
@@ -355,31 +229,6 @@
return amount < low ? low : (amount > high ? high : amount);
}
-static float SC_maxf(float a, float b)
-{
- return a > b ? a : b;
-}
-
-static float SC_minf(float a, float b)
-{
- return a < b ? a : b;
-}
-
-static float SC_sqrf(float v)
-{
- return v * v;
-}
-
-static int SC_sqr(int v)
-{
- return v * v;
-}
-
-static float SC_fracf(float v)
-{
- return v - floorf(v);
-}
-
static float SC_roundf(float v)
{
return floorf(v + 0.4999999999);
@@ -410,29 +259,10 @@
return sqrtf(a * a + b * b + c * c);
}
-static float SC_radf(float degrees)
+static float SC_frac(float v)
{
- return degrees * DEG_TO_RAD;
-}
-
-static float SC_degf(float radians)
-{
- return radians * RAD_TO_DEG;
-}
-
-static float SC_lerpf(float start, float stop, float amount)
-{
- return start + (stop - start) * amount;
-}
-
-static float SC_normf(float start, float stop, float value)
-{
- return (value - start) / (stop - start);
-}
-
-static float SC_mapf(float minStart, float minStop, float maxStart, float maxStop, float value)
-{
- return maxStart + (maxStart - maxStop) * ((value - minStart) / (minStop - minStart));
+ int i = (int)floor(v);
+ return fmin(v - i, 0x1.fffffep-1f);
}
//////////////////////////////////////////////////////////////////////////////
@@ -511,6 +341,24 @@
return timeinfo->tm_year;
}
+static int64_t SC_uptimeMillis2()
+{
+ return nanoseconds_to_milliseconds(systemTime(SYSTEM_TIME_MONOTONIC));
+}
+
+static int64_t SC_startTimeMillis2()
+{
+ GET_TLS();
+ return sc->mEnviroment.mStartTimeMillis;
+}
+
+static int64_t SC_elapsedTimeMillis2()
+{
+ GET_TLS();
+ return nanoseconds_to_milliseconds(systemTime(SYSTEM_TIME_MONOTONIC))
+ - sc->mEnviroment.mStartTimeMillis;
+}
+
static int32_t SC_uptimeMillis()
{
return nanoseconds_to_milliseconds(systemTime(SYSTEM_TIME_MONOTONIC));
@@ -602,477 +450,161 @@
}
-static void SC_vec2Rand(float *vec, float maxLen)
-{
- float angle = SC_randf(PI * 2);
- float len = SC_randf(maxLen);
- vec[0] = len * sinf(angle);
- vec[1] = len * cosf(angle);
-}
-
-
-
-//////////////////////////////////////////////////////////////////////////////
-// Context
-//////////////////////////////////////////////////////////////////////////////
-
-static void SC_bindTexture(RsProgramFragment vpf, uint32_t slot, RsAllocation va)
-{
- GET_TLS();
- rsi_ProgramBindTexture(rsc,
- static_cast<ProgramFragment *>(vpf),
- slot,
- static_cast<Allocation *>(va));
-
-}
-
-static void SC_bindSampler(RsProgramFragment vpf, uint32_t slot, RsSampler vs)
-{
- GET_TLS();
- rsi_ProgramBindSampler(rsc,
- static_cast<ProgramFragment *>(vpf),
- slot,
- static_cast<Sampler *>(vs));
-
-}
-
-static void SC_bindProgramFragmentStore(RsProgramFragmentStore pfs)
-{
- GET_TLS();
- rsi_ContextBindProgramFragmentStore(rsc, pfs);
-
-}
-
-static void SC_bindProgramFragment(RsProgramFragment pf)
-{
- GET_TLS();
- rsi_ContextBindProgramFragment(rsc, pf);
-
-}
-
-static void SC_bindProgramVertex(RsProgramVertex pv)
-{
- GET_TLS();
- rsi_ContextBindProgramVertex(rsc, pv);
-
-}
-
-//////////////////////////////////////////////////////////////////////////////
-// VP
-//////////////////////////////////////////////////////////////////////////////
-
-static void SC_vpLoadModelMatrix(const rsc_Matrix *m)
-{
- GET_TLS();
- rsc->getVertex()->setModelviewMatrix(m);
-}
-
-static void SC_vpLoadTextureMatrix(const rsc_Matrix *m)
-{
- GET_TLS();
- rsc->getVertex()->setTextureMatrix(m);
-}
-
-
-
-//////////////////////////////////////////////////////////////////////////////
-// Drawing
-//////////////////////////////////////////////////////////////////////////////
-
-static void SC_drawLine(float x1, float y1, float z1,
- float x2, float y2, float z2)
-{
- GET_TLS();
- if (!rsc->setupCheck()) {
- return;
- }
-
- float vtx[] = { x1, y1, z1, x2, y2, z2 };
- VertexArray va;
- va.addLegacy(GL_FLOAT, 3, 12, RS_KIND_POSITION, false, (uint32_t)vtx);
- if (rsc->checkVersion2_0()) {
- va.setupGL2(rsc, &rsc->mStateVertexArray, &rsc->mShaderCache);
- } else {
- va.setupGL(rsc, &rsc->mStateVertexArray);
- }
-
- glDrawArrays(GL_LINES, 0, 2);
-}
-
-static void SC_drawPoint(float x, float y, float z)
-{
- GET_TLS();
- if (!rsc->setupCheck()) {
- return;
- }
-
- float vtx[] = { x, y, z };
-
- VertexArray va;
- va.addLegacy(GL_FLOAT, 3, 12, RS_KIND_POSITION, false, (uint32_t)vtx);
- if (rsc->checkVersion2_0()) {
- va.setupGL2(rsc, &rsc->mStateVertexArray, &rsc->mShaderCache);
- } else {
- va.setupGL(rsc, &rsc->mStateVertexArray);
- }
-
- glDrawArrays(GL_POINTS, 0, 1);
-}
-
-static void SC_drawQuadTexCoords(float x1, float y1, float z1,
- float u1, float v1,
- float x2, float y2, float z2,
- float u2, float v2,
- float x3, float y3, float z3,
- float u3, float v3,
- float x4, float y4, float z4,
- float u4, float v4)
-{
- GET_TLS();
- if (!rsc->setupCheck()) {
- return;
- }
-
- //LOGE("Quad");
- //LOGE("%4.2f, %4.2f, %4.2f", x1, y1, z1);
- //LOGE("%4.2f, %4.2f, %4.2f", x2, y2, z2);
- //LOGE("%4.2f, %4.2f, %4.2f", x3, y3, z3);
- //LOGE("%4.2f, %4.2f, %4.2f", x4, y4, z4);
-
- float vtx[] = {x1,y1,z1, x2,y2,z2, x3,y3,z3, x4,y4,z4};
- const float tex[] = {u1,v1, u2,v2, u3,v3, u4,v4};
-
- VertexArray va;
- va.addLegacy(GL_FLOAT, 3, 12, RS_KIND_POSITION, false, (uint32_t)vtx);
- va.addLegacy(GL_FLOAT, 2, 8, RS_KIND_TEXTURE, false, (uint32_t)tex);
- if (rsc->checkVersion2_0()) {
- va.setupGL2(rsc, &rsc->mStateVertexArray, &rsc->mShaderCache);
- } else {
- va.setupGL(rsc, &rsc->mStateVertexArray);
- }
-
-
- glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
-}
-
-static void SC_drawQuad(float x1, float y1, float z1,
- float x2, float y2, float z2,
- float x3, float y3, float z3,
- float x4, float y4, float z4)
-{
- SC_drawQuadTexCoords(x1, y1, z1, 0, 1,
- x2, y2, z2, 1, 1,
- x3, y3, z3, 1, 0,
- x4, y4, z4, 0, 0);
-}
-
-static void SC_drawSpriteScreenspace(float x, float y, float z, float w, float h)
-{
- GET_TLS();
- ObjectBaseRef<const ProgramVertex> tmp(rsc->getVertex());
- rsc->setVertex(rsc->getDefaultProgramVertex());
- //rsc->setupCheck();
-
- //GLint crop[4] = {0, h, w, -h};
-
- float sh = rsc->getHeight();
-
- SC_drawQuad(x, sh - y, z,
- x+w, sh - y, z,
- x+w, sh - (y+h), z,
- x, sh - (y+h), z);
- rsc->setVertex((ProgramVertex *)tmp.get());
-}
-
-static void SC_drawSpriteScreenspaceCropped(float x, float y, float z, float w, float h,
- float cx0, float cy0, float cx1, float cy1)
-{
- GET_TLS();
- if (!rsc->setupCheck()) {
- return;
- }
-
- GLint crop[4] = {cx0, cy0, cx1, cy1};
- glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
- glDrawTexfOES(x, y, z, w, h);
-}
-
-static void SC_drawSprite(float x, float y, float z, float w, float h)
-{
- GET_TLS();
- float vin[3] = {x, y, z};
- float vout[4];
-
- //LOGE("ds in %f %f %f", x, y, z);
- rsc->getVertex()->transformToScreen(rsc, vout, vin);
- //LOGE("ds out %f %f %f %f", vout[0], vout[1], vout[2], vout[3]);
- vout[0] /= vout[3];
- vout[1] /= vout[3];
- vout[2] /= vout[3];
-
- vout[0] *= rsc->getWidth() / 2;
- vout[1] *= rsc->getHeight() / 2;
- vout[0] += rsc->getWidth() / 2;
- vout[1] += rsc->getHeight() / 2;
-
- vout[0] -= w/2;
- vout[1] -= h/2;
-
- //LOGE("ds out2 %f %f %f", vout[0], vout[1], vout[2]);
-
- // U, V, W, H
- SC_drawSpriteScreenspace(vout[0], vout[1], z, h, w);
- //rsc->setupCheck();
-}
-
-
-static void SC_drawRect(float x1, float y1,
- float x2, float y2, float z)
-{
- SC_drawQuad(x1, y2, z,
- x2, y2, z,
- x2, y1, z,
- x1, y1, z);
-}
-
-static void SC_drawSimpleMesh(RsSimpleMesh vsm)
-{
- GET_TLS();
- SimpleMesh *sm = static_cast<SimpleMesh *>(vsm);
- if (!rsc->setupCheck()) {
- return;
- }
- sm->render(rsc);
-}
-
-static void SC_drawSimpleMeshRange(RsSimpleMesh vsm, uint32_t start, uint32_t len)
-{
- GET_TLS();
- SimpleMesh *sm = static_cast<SimpleMesh *>(vsm);
- if (!rsc->setupCheck()) {
- return;
- }
- sm->renderRange(rsc, start, len);
-}
-
-
//////////////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////////////
-static void SC_color(float r, float g, float b, float a)
+static uint32_t SC_allocGetDimX(RsAllocation va)
{
GET_TLS();
- rsc->mStateVertex.color[0] = r;
- rsc->mStateVertex.color[1] = g;
- rsc->mStateVertex.color[2] = b;
- rsc->mStateVertex.color[3] = a;
- if (!rsc->checkVersion2_0()) {
- glColor4f(r, g, b, a);
- }
+ const Allocation *a = static_cast<const Allocation *>(va);
+ //LOGE("SC_allocGetDimX a=%p", a);
+ //LOGE(" type=%p", a->getType());
+ return a->getType()->getDimX();
}
-static void SC_ambient(float r, float g, float b, float a)
-{
- GLfloat params[] = { r, g, b, a };
- glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, params);
-}
-
-static void SC_diffuse(float r, float g, float b, float a)
-{
- GLfloat params[] = { r, g, b, a };
- glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, params);
-}
-
-static void SC_specular(float r, float g, float b, float a)
-{
- GLfloat params[] = { r, g, b, a };
- glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, params);
-}
-
-static void SC_emission(float r, float g, float b, float a)
-{
- GLfloat params[] = { r, g, b, a };
- glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, params);
-}
-
-static void SC_shininess(float s)
-{
- glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, s);
-}
-
-static void SC_pointAttenuation(float a, float b, float c)
-{
- GLfloat params[] = { a, b, c };
- glPointParameterfv(GL_POINT_DISTANCE_ATTENUATION, params);
-}
-
-static void SC_hsbToRgb(float h, float s, float b, float* rgb)
-{
- float red = 0.0f;
- float green = 0.0f;
- float blue = 0.0f;
-
- float x = h;
- float y = s;
- float z = b;
-
- float hf = (x - (int) x) * 6.0f;
- int ihf = (int) hf;
- float f = hf - ihf;
- float pv = z * (1.0f - y);
- float qv = z * (1.0f - y * f);
- float tv = z * (1.0f - y * (1.0f - f));
-
- switch (ihf) {
- case 0: // Red is the dominant color
- red = z;
- green = tv;
- blue = pv;
- break;
- case 1: // Green is the dominant color
- red = qv;
- green = z;
- blue = pv;
- break;
- case 2:
- red = pv;
- green = z;
- blue = tv;
- break;
- case 3: // Blue is the dominant color
- red = pv;
- green = qv;
- blue = z;
- break;
- case 4:
- red = tv;
- green = pv;
- blue = z;
- break;
- case 5: // Red is the dominant color
- red = z;
- green = pv;
- blue = qv;
- break;
- }
-
- rgb[0] = red;
- rgb[1] = green;
- rgb[2] = blue;
-}
-
-static int SC_hsbToAbgr(float h, float s, float b, float a)
-{
- float rgb[3];
- SC_hsbToRgb(h, s, b, rgb);
- return int(a * 255.0f) << 24 |
- int(rgb[2] * 255.0f) << 16 |
- int(rgb[1] * 255.0f) << 8 |
- int(rgb[0] * 255.0f);
-}
-
-static void SC_hsb(float h, float s, float b, float a)
+static uint32_t SC_allocGetDimY(RsAllocation va)
{
GET_TLS();
- float rgb[3];
- SC_hsbToRgb(h, s, b, rgb);
- if (rsc->checkVersion2_0()) {
- glVertexAttrib4f(1, rgb[0], rgb[1], rgb[2], a);
- } else {
- glColor4f(rgb[0], rgb[1], rgb[2], a);
- }
+ const Allocation *a = static_cast<const Allocation *>(va);
+ return a->getType()->getDimY();
}
-static void SC_uploadToTexture(RsAllocation va, uint32_t baseMipLevel)
+static uint32_t SC_allocGetDimZ(RsAllocation va)
{
GET_TLS();
- rsi_AllocationUploadToTexture(rsc, va, false, baseMipLevel);
+ const Allocation *a = static_cast<const Allocation *>(va);
+ return a->getType()->getDimZ();
}
-static void SC_uploadToBufferObject(RsAllocation va)
+static uint32_t SC_allocGetDimLOD(RsAllocation va)
{
GET_TLS();
- rsi_AllocationUploadToBufferObject(rsc, va);
+ const Allocation *a = static_cast<const Allocation *>(va);
+ return a->getType()->getDimLOD();
}
-static void SC_syncToGL(RsAllocation va)
+static uint32_t SC_allocGetDimFaces(RsAllocation va)
{
GET_TLS();
- Allocation *a = static_cast<Allocation *>(va);
-
+ const Allocation *a = static_cast<const Allocation *>(va);
+ return a->getType()->getDimFaces();
}
-static void SC_ClearColor(float r, float g, float b, float a)
-{
- //LOGE("c %f %f %f %f", r, g, b, a);
- GET_TLS();
- sc->mEnviroment.mClearColor[0] = r;
- sc->mEnviroment.mClearColor[1] = g;
- sc->mEnviroment.mClearColor[2] = b;
- sc->mEnviroment.mClearColor[3] = a;
+
+
+static void SC_debugF(const char *s, float f) {
+ LOGE("%s %f, 0x%08x", s, f, *((int *) (&f)));
+}
+static void SC_debugFv2(const char *s, rsvF_2 fv) {
+ float *f = (float *)&fv;
+ LOGE("%s {%f, %f}", s, f[0], f[1]);
+}
+static void SC_debugFv3(const char *s, rsvF_4 fv) {
+ float *f = (float *)&fv;
+ LOGE("%s {%f, %f, %f}", s, f[0], f[1], f[2]);
+}
+static void SC_debugFv4(const char *s, rsvF_4 fv) {
+ float *f = (float *)&fv;
+ LOGE("%s {%f, %f, %f, %f}", s, f[0], f[1], f[2], f[3]);
+}
+static void SC_debugI32(const char *s, int32_t i) {
+ LOGE("%s %i 0x%x", s, i, i);
}
-static void SC_debugF(const char *s, float f)
-{
- LOGE("%s %f", s, f);
+static uchar4 SC_convertColorTo8888_f3(float r, float g, float b) {
+ uchar4 t;
+ t.f[0] = (uint8_t)(r * 255.f);
+ t.f[1] = (uint8_t)(g * 255.f);
+ t.f[2] = (uint8_t)(b * 255.f);
+ t.f[3] = 0xff;
+ return t;
}
-static void SC_debugHexF(const char *s, float f)
-{
- LOGE("%s 0x%x", s, *((int *) (&f)));
-}
-
-static void SC_debugI32(const char *s, int32_t i)
-{
- LOGE("%s %i", s, i);
-}
-
-static void SC_debugHexI32(const char *s, int32_t i)
-{
- LOGE("%s 0x%x", s, i);
-}
-
-static uint32_t SC_getWidth()
-{
- GET_TLS();
- return rsc->getWidth();
-}
-
-static uint32_t SC_getHeight()
-{
- GET_TLS();
- return rsc->getHeight();
-}
-
-static uint32_t SC_colorFloatRGBAtoUNorm8(float r, float g, float b, float a)
-{
- uint32_t c = 0;
- c |= (uint32_t)(r * 255.f + 0.5f);
- c |= ((uint32_t)(g * 255.f + 0.5f)) << 8;
- c |= ((uint32_t)(b * 255.f + 0.5f)) << 16;
- c |= ((uint32_t)(a * 255.f + 0.5f)) << 24;
- return c;
-}
-
-static uint32_t SC_colorFloatRGBAto565(float r, float g, float b)
-{
- uint32_t ir = (uint32_t)(r * 255.f + 0.5f);
- uint32_t ig = (uint32_t)(g * 255.f + 0.5f);
- uint32_t ib = (uint32_t)(b * 255.f + 0.5f);
- return rs888to565(ir, ig, ib);
+static uchar4 SC_convertColorTo8888_f4(float r, float g, float b, float a) {
+ uchar4 t;
+ t.f[0] = (uint8_t)(r * 255.f);
+ t.f[1] = (uint8_t)(g * 255.f);
+ t.f[2] = (uint8_t)(b * 255.f);
+ t.f[3] = (uint8_t)(a * 255.f);
+ return t;
}
static uint32_t SC_toClient(void *data, int cmdID, int len, int waitForSpace)
{
GET_TLS();
+ //LOGE("SC_toClient %i %i %i", cmdID, len, waitForSpace);
return rsc->sendMessageToClient(data, cmdID, len, waitForSpace != 0);
}
static void SC_scriptCall(int scriptID)
{
GET_TLS();
- rsc->runScript((Script *)scriptID, 0);
+ rsc->runScript((Script *)scriptID);
+}
+
+int SC_divsi3(int a, int b)
+{
+ return a / b;
+}
+
+int SC_getAllocation(const void *ptr)
+{
+ GET_TLS();
+ const Allocation *alloc = sc->ptrToAllocation(ptr);
+ return (int)alloc;
+}
+
+
+void SC_ForEachii(RsScript vs, RsAllocation vin)
+{
+ GET_TLS();
+ Script *s = static_cast<Script *>(vs);
+ Allocation *ain = static_cast<Allocation *>(vin);
+ s->runForEach(rsc, ain, NULL);
+}
+
+void SC_ForEachiii(RsScript vs, RsAllocation vin, RsAllocation vout)
+{
+ GET_TLS();
+ Script *s = static_cast<Script *>(vs);
+ Allocation *ain = static_cast<Allocation *>(vin);
+ Allocation *aout = static_cast<Allocation *>(vout);
+ s->runForEach(rsc, ain, aout);
+}
+
+void SC_ForEachiiii(RsScript vs, RsAllocation vin, int xStart, int xEnd)
+{
+ GET_TLS();
+ Script *s = static_cast<Script *>(vs);
+ Allocation *ain = static_cast<Allocation *>(vin);
+ s->runForEach(rsc, ain, NULL, xStart, xEnd);
+}
+
+void SC_ForEachiiiii(RsScript vs, RsAllocation vin, RsAllocation vout, int xStart, int xEnd)
+{
+ GET_TLS();
+ Script *s = static_cast<Script *>(vs);
+ Allocation *ain = static_cast<Allocation *>(vin);
+ Allocation *aout = static_cast<Allocation *>(vout);
+ s->runForEach(rsc, ain, aout, xStart, xEnd);
+}
+
+void SC_ForEachiiiiii(RsScript vs, RsAllocation vin, int xStart, int yStart, int xEnd, int yEnd)
+{
+ GET_TLS();
+ Script *s = static_cast<Script *>(vs);
+ Allocation *ain = static_cast<Allocation *>(vin);
+ s->runForEach(rsc, ain, NULL, xStart, yStart, xEnd, yEnd);
+}
+
+void SC_ForEachiiiiiii(RsScript vs, RsAllocation vin, RsAllocation vout, int xStart, int yStart, int xEnd, int yEnd)
+{
+ GET_TLS();
+ Script *s = static_cast<Script *>(vs);
+ Allocation *ain = static_cast<Allocation *>(vin);
+ Allocation *aout = static_cast<Allocation *>(vout);
+ s->runForEach(rsc, ain, aout, xStart, yStart, xEnd, yEnd);
}
@@ -1080,311 +612,108 @@
// Class implementation
//////////////////////////////////////////////////////////////////////////////
-ScriptCState::SymbolTable_t ScriptCState::gSyms[] = {
- // IO
- { "loadI32", (void *)&SC_loadI32,
- "int", "(int, int)" },
- //{ "loadU32", (void *)&SC_loadU32, "unsigned int", "(int, int)" },
- { "loadF", (void *)&SC_loadF,
- "float", "(int, int)" },
- { "loadArrayF", (void *)&SC_loadArrayF,
- "float*", "(int, int)" },
- { "loadArrayI32", (void *)&SC_loadArrayI32,
- "int*", "(int, int)" },
- { "loadVec4", (void *)&SC_loadVec4,
- "void", "(int, int, float *)" },
- { "loadMatrix", (void *)&SC_loadMatrix,
- "void", "(int, int, float *)" },
- { "storeI32", (void *)&SC_storeI32,
- "void", "(int, int, int)" },
- //{ "storeU32", (void *)&SC_storeU32, "void", "(int, int, unsigned int)" },
- { "storeF", (void *)&SC_storeF,
- "void", "(int, int, float)" },
- { "storeVec4", (void *)&SC_storeVec4,
- "void", "(int, int, float *)" },
- { "storeMatrix", (void *)&SC_storeMatrix,
- "void", "(int, int, float *)" },
- { "loadSimpleMeshVerticesF", (void *)&SC_loadSimpleMeshVerticesF,
- "float*", "(int, int)" },
- { "updateSimpleMesh", (void *)&SC_updateSimpleMesh,
- "void", "(int)" },
+// llvm name mangling ref
+// <builtin-type> ::= v # void
+// ::= b # bool
+// ::= c # char
+// ::= a # signed char
+// ::= h # unsigned char
+// ::= s # short
+// ::= t # unsigned short
+// ::= i # int
+// ::= j # unsigned int
+// ::= l # long
+// ::= m # unsigned long
+// ::= x # long long, __int64
+// ::= y # unsigned long long, __int64
+// ::= f # float
+// ::= d # double
- // math
- { "modf", (void *)&fmod,
- "float", "(float, float)" },
- { "abs", (void *)&abs,
- "int", "(int)" },
- { "absf", (void *)&fabsf,
- "float", "(float)" },
- { "sinf_fast", (void *)&SC_sinf_fast,
- "float", "(float)" },
- { "cosf_fast", (void *)&SC_cosf_fast,
- "float", "(float)" },
- { "sinf", (void *)&sinf,
- "float", "(float)" },
- { "cosf", (void *)&cosf,
- "float", "(float)" },
- { "asinf", (void *)&asinf,
- "float", "(float)" },
- { "acosf", (void *)&acosf,
- "float", "(float)" },
- { "atanf", (void *)&atanf,
- "float", "(float)" },
- { "atan2f", (void *)&atan2f,
- "float", "(float, float)" },
- { "fabsf", (void *)&fabsf,
- "float", "(float)" },
- { "randf", (void *)&SC_randf,
- "float", "(float)" },
- { "randf2", (void *)&SC_randf2,
- "float", "(float, float)" },
- { "floorf", (void *)&floorf,
- "float", "(float)" },
- { "fracf", (void *)&SC_fracf,
- "float", "(float)" },
- { "ceilf", (void *)&ceilf,
- "float", "(float)" },
- { "roundf", (void *)&SC_roundf,
- "float", "(float)" },
- { "expf", (void *)&expf,
- "float", "(float)" },
- { "logf", (void *)&logf,
- "float", "(float)" },
- { "powf", (void *)&powf,
- "float", "(float, float)" },
- { "maxf", (void *)&SC_maxf,
- "float", "(float, float)" },
- { "minf", (void *)&SC_minf,
- "float", "(float, float)" },
- { "sqrt", (void *)&sqrt,
- "int", "(int)" },
- { "sqrtf", (void *)&sqrtf,
- "float", "(float)" },
- { "sqr", (void *)&SC_sqr,
- "int", "(int)" },
- { "sqrf", (void *)&SC_sqrf,
- "float", "(float)" },
- { "sign", (void *)&SC_sign,
- "int", "(int)" },
- { "signf", (void *)&SC_signf,
- "float", "(float)" },
- { "clamp", (void *)&SC_clamp,
- "int", "(int, int, int)" },
- { "clampf", (void *)&SC_clampf,
- "float", "(float, float, float)" },
- { "distf2", (void *)&SC_distf2,
- "float", "(float, float, float, float)" },
- { "distf3", (void *)&SC_distf3,
- "float", "(float, float, float, float, float, float)" },
- { "magf2", (void *)&SC_magf2,
- "float", "(float, float)" },
- { "magf3", (void *)&SC_magf3,
- "float", "(float, float, float)" },
- { "radf", (void *)&SC_radf,
- "float", "(float)" },
- { "degf", (void *)&SC_degf,
- "float", "(float)" },
- { "lerpf", (void *)&SC_lerpf,
- "float", "(float, float, float)" },
- { "normf", (void *)&SC_normf,
- "float", "(float, float, float)" },
- { "mapf", (void *)&SC_mapf,
- "float", "(float, float, float, float, float)" },
- { "noisef", (void *)&SC_noisef,
- "float", "(float)" },
- { "noisef2", (void *)&SC_noisef2,
- "float", "(float, float)" },
- { "noisef3", (void *)&SC_noisef3,
- "float", "(float, float, float)" },
- { "turbulencef2", (void *)&SC_turbulencef2,
- "float", "(float, float, float)" },
- { "turbulencef3", (void *)&SC_turbulencef3,
- "float", "(float, float, float, float)" },
+static ScriptCState::SymbolTable_t gSyms[] = {
+ { "__divsi3", (void *)&SC_divsi3 },
+
+ // allocation
+ { "rsAllocationGetDimX", (void *)&SC_allocGetDimX },
+ { "rsAllocationGetDimY", (void *)&SC_allocGetDimY },
+ { "rsAllocationGetDimZ", (void *)&SC_allocGetDimZ },
+ { "rsAllocationGetDimLOD", (void *)&SC_allocGetDimLOD },
+ { "rsAllocationGetDimFaces", (void *)&SC_allocGetDimFaces },
+ { "rsGetAllocation", (void *)&SC_getAllocation },
+
+ // color
+ { "_Z17rsPackColorTo8888fff", (void *)&SC_convertColorTo8888_f3 },
+ { "_Z17rsPackColorTo8888ffff", (void *)&SC_convertColorTo8888_f4 },
+ //extern uchar4 __attribute__((overloadable)) rsPackColorTo8888(float3);
+ //extern uchar4 __attribute__((overloadable)) rsPackColorTo8888(float4);
+ //extern float4 rsUnpackColor8888(uchar4);
+ //extern uchar4 __attribute__((overloadable)) rsPackColorTo565(float r, float g, float b);
+ //extern uchar4 __attribute__((overloadable)) rsPackColorTo565(float3);
+ //extern float4 rsUnpackColor565(uchar4);
+
+ // Debug
+ { "_Z7rsDebugPKcf", (void *)&SC_debugF },
+ { "_Z7rsDebugPKcDv2_f", (void *)&SC_debugFv2 },
+ { "_Z7rsDebugPKcDv3_f", (void *)&SC_debugFv3 },
+ { "_Z7rsDebugPKcDv4_f", (void *)&SC_debugFv4 },
+ { "_Z7rsDebugPKci", (void *)&SC_debugI32 },
+ //extern void __attribute__((overloadable))rsDebug(const char *, const void *);
+
+
+ // RS Math
+ { "_Z6rsRandi", (void *)&SC_randi },
+ { "_Z6rsRandii", (void *)&SC_randi2 },
+ { "_Z6rsRandf", (void *)&SC_randf },
+ { "_Z6rsRandff", (void *)&SC_randf2 },
+ { "_Z6rsFracf", (void *)&SC_frac },
// time
- { "second", (void *)&SC_second,
- "int", "()" },
- { "minute", (void *)&SC_minute,
- "int", "()" },
- { "hour", (void *)&SC_hour,
- "int", "()" },
- { "day", (void *)&SC_day,
- "int", "()" },
- { "month", (void *)&SC_month,
- "int", "()" },
- { "year", (void *)&SC_year,
- "int", "()" },
- { "uptimeMillis", (void*)&SC_uptimeMillis,
- "int", "()" }, // TODO: use long instead
- { "startTimeMillis", (void*)&SC_startTimeMillis,
- "int", "()" }, // TODO: use long instead
- { "elapsedTimeMillis", (void*)&SC_elapsedTimeMillis,
- "int", "()" }, // TODO: use long instead
+ { "rsSecond", (void *)&SC_second },
+ { "rsMinute", (void *)&SC_minute },
+ { "rsHour", (void *)&SC_hour },
+ { "rsDay", (void *)&SC_day },
+ { "rsMonth", (void *)&SC_month },
+ { "rsYear", (void *)&SC_year },
+ { "rsUptimeMillis", (void*)&SC_uptimeMillis2 },
+ { "rsStartTimeMillis", (void*)&SC_startTimeMillis2 },
+ { "rsElapsedTimeMillis", (void*)&SC_elapsedTimeMillis2 },
+
+ { "rsSendToClient", (void *)&SC_toClient },
// matrix
- { "matrixLoadIdentity", (void *)&SC_matrixLoadIdentity,
- "void", "(float *mat)" },
- { "matrixLoadFloat", (void *)&SC_matrixLoadFloat,
- "void", "(float *mat, float *f)" },
- { "matrixLoadMat", (void *)&SC_matrixLoadMat,
- "void", "(float *mat, float *newmat)" },
- { "matrixLoadRotate", (void *)&SC_matrixLoadRotate,
- "void", "(float *mat, float rot, float x, float y, float z)" },
- { "matrixLoadScale", (void *)&SC_matrixLoadScale,
- "void", "(float *mat, float x, float y, float z)" },
- { "matrixLoadTranslate", (void *)&SC_matrixLoadTranslate,
- "void", "(float *mat, float x, float y, float z)" },
- { "matrixLoadMultiply", (void *)&SC_matrixLoadMultiply,
- "void", "(float *mat, float *lhs, float *rhs)" },
- { "matrixMultiply", (void *)&SC_matrixMultiply,
- "void", "(float *mat, float *rhs)" },
- { "matrixRotate", (void *)&SC_matrixRotate,
- "void", "(float *mat, float rot, float x, float y, float z)" },
- { "matrixScale", (void *)&SC_matrixScale,
- "void", "(float *mat, float x, float y, float z)" },
- { "matrixTranslate", (void *)&SC_matrixTranslate,
- "void", "(float *mat, float x, float y, float z)" },
+ { "rsMatrixLoadIdentity", (void *)&SC_matrixLoadIdentity },
+ { "rsMatrixLoadFloat", (void *)&SC_matrixLoadFloat },
+ { "rsMatrixLoadMat", (void *)&SC_matrixLoadMat },
+ { "rsMatrixLoadRotate", (void *)&SC_matrixLoadRotate },
+ { "rsMatrixLoadScale", (void *)&SC_matrixLoadScale },
+ { "rsMatrixLoadTranslate", (void *)&SC_matrixLoadTranslate },
+ { "rsMatrixLoadMultiply", (void *)&SC_matrixLoadMultiply },
+ { "rsMatrixMultiply", (void *)&SC_matrixMultiply },
+ { "rsMatrixRotate", (void *)&SC_matrixRotate },
+ { "rsMatrixScale", (void *)&SC_matrixScale },
+ { "rsMatrixTranslate", (void *)&SC_matrixTranslate },
- // vector
- { "vec2Rand", (void *)&SC_vec2Rand,
- "void", "(float *vec, float maxLen)" },
+ { "_Z9rsForEachii", (void *)&SC_ForEachii },
+ { "_Z9rsForEachiii", (void *)&SC_ForEachiii },
+ { "_Z9rsForEachiiii", (void *)&SC_ForEachiiii },
+ { "_Z9rsForEachiiiii", (void *)&SC_ForEachiiiii },
+ { "_Z9rsForEachiiiiii", (void *)&SC_ForEachiiiiii },
+ { "_Z9rsForEachiiiiiii", (void *)&SC_ForEachiiiiiii },
- // vec3
- { "vec3Norm", (void *)&SC_vec3Norm,
- "void", "(struct vecF32_3_s *)" },
- { "vec3Length", (void *)&SC_vec3Length,
- "float", "(struct vecF32_3_s *)" },
- { "vec3Add", (void *)&SC_vec3Add,
- "void", "(struct vecF32_3_s *dest, struct vecF32_3_s *lhs, struct vecF32_3_s *rhs)" },
- { "vec3Sub", (void *)&SC_vec3Sub,
- "void", "(struct vecF32_3_s *dest, struct vecF32_3_s *lhs, struct vecF32_3_s *rhs)" },
- { "vec3Cross", (void *)&SC_vec3Cross,
- "void", "(struct vecF32_3_s *dest, struct vecF32_3_s *lhs, struct vecF32_3_s *rhs)" },
- { "vec3Dot", (void *)&SC_vec3Dot,
- "float", "(struct vecF32_3_s *lhs, struct vecF32_3_s *rhs)" },
- { "vec3Scale", (void *)&SC_vec3Scale,
- "void", "(struct vecF32_3_s *lhs, float scale)" },
+////////////////////////////////////////////////////////////////////
- // vec4
- { "vec4Norm", (void *)&SC_vec4Norm,
- "void", "(struct vecF32_4_s *)" },
- { "vec4Length", (void *)&SC_vec4Length,
- "float", "(struct vecF32_4_s *)" },
- { "vec4Add", (void *)&SC_vec4Add,
- "void", "(struct vecF32_4_s *dest, struct vecF32_4_s *lhs, struct vecF32_4_s *rhs)" },
- { "vec4Sub", (void *)&SC_vec4Sub,
- "void", "(struct vecF32_4_s *dest, struct vecF32_4_s *lhs, struct vecF32_4_s *rhs)" },
- { "vec4Dot", (void *)&SC_vec4Dot,
- "float", "(struct vecF32_4_s *lhs, struct vecF32_4_s *rhs)" },
- { "vec4Scale", (void *)&SC_vec4Scale,
- "void", "(struct vecF32_4_s *lhs, float scale)" },
+ //{ "sinf_fast", (void *)&SC_sinf_fast },
+ //{ "cosf_fast", (void *)&SC_cosf_fast },
+ //{ "clamp", (void *)&SC_clamp },
+ //{ "distf2", (void *)&SC_distf2 },
+ //{ "distf3", (void *)&SC_distf3 },
+ //{ "magf2", (void *)&SC_magf2 },
+ //{ "magf3", (void *)&SC_magf3 },
+ //{ "mapf", (void *)&SC_mapf },
- // context
- { "bindProgramFragment", (void *)&SC_bindProgramFragment,
- "void", "(int)" },
- { "bindProgramFragmentStore", (void *)&SC_bindProgramFragmentStore,
- "void", "(int)" },
- { "bindProgramStore", (void *)&SC_bindProgramFragmentStore,
- "void", "(int)" },
- { "bindProgramVertex", (void *)&SC_bindProgramVertex,
- "void", "(int)" },
- { "bindSampler", (void *)&SC_bindSampler,
- "void", "(int, int, int)" },
- { "bindTexture", (void *)&SC_bindTexture,
- "void", "(int, int, int)" },
-
- // vp
- { "vpLoadModelMatrix", (void *)&SC_vpLoadModelMatrix,
- "void", "(void *)" },
- { "vpLoadTextureMatrix", (void *)&SC_vpLoadTextureMatrix,
- "void", "(void *)" },
+ { "scriptCall", (void *)&SC_scriptCall },
-
- // drawing
- { "drawRect", (void *)&SC_drawRect,
- "void", "(float x1, float y1, float x2, float y2, float z)" },
- { "drawQuad", (void *)&SC_drawQuad,
- "void", "(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float x4, float y4, float z4)" },
- { "drawQuadTexCoords", (void *)&SC_drawQuadTexCoords,
- "void", "(float x1, float y1, float z1, float u1, float v1, float x2, float y2, float z2, float u2, float v2, float x3, float y3, float z3, float u3, float v3, float x4, float y4, float z4, float u4, float v4)" },
- { "drawSprite", (void *)&SC_drawSprite,
- "void", "(float x, float y, float z, float w, float h)" },
- { "drawSpriteScreenspace", (void *)&SC_drawSpriteScreenspace,
- "void", "(float x, float y, float z, float w, float h)" },
- { "drawSpriteScreenspaceCropped", (void *)&SC_drawSpriteScreenspaceCropped,
- "void", "(float x, float y, float z, float w, float h, float cx0, float cy0, float cx1, float cy1)" },
- { "drawLine", (void *)&SC_drawLine,
- "void", "(float x1, float y1, float z1, float x2, float y2, float z2)" },
- { "drawPoint", (void *)&SC_drawPoint,
- "void", "(float x1, float y1, float z1)" },
- { "drawSimpleMesh", (void *)&SC_drawSimpleMesh,
- "void", "(int ism)" },
- { "drawSimpleMeshRange", (void *)&SC_drawSimpleMeshRange,
- "void", "(int ism, int start, int len)" },
-
-
- // misc
- { "pfClearColor", (void *)&SC_ClearColor,
- "void", "(float, float, float, float)" },
- { "color", (void *)&SC_color,
- "void", "(float, float, float, float)" },
- { "hsb", (void *)&SC_hsb,
- "void", "(float, float, float, float)" },
- { "hsbToRgb", (void *)&SC_hsbToRgb,
- "void", "(float, float, float, float*)" },
- { "hsbToAbgr", (void *)&SC_hsbToAbgr,
- "int", "(float, float, float, float)" },
- { "ambient", (void *)&SC_ambient,
- "void", "(float, float, float, float)" },
- { "diffuse", (void *)&SC_diffuse,
- "void", "(float, float, float, float)" },
- { "specular", (void *)&SC_specular,
- "void", "(float, float, float, float)" },
- { "emission", (void *)&SC_emission,
- "void", "(float, float, float, float)" },
- { "shininess", (void *)&SC_shininess,
- "void", "(float)" },
- { "pointAttenuation", (void *)&SC_pointAttenuation,
- "void", "(float, float, float)" },
-
- { "uploadToTexture", (void *)&SC_uploadToTexture,
- "void", "(int, int)" },
- { "uploadToBufferObject", (void *)&SC_uploadToBufferObject,
- "void", "(int)" },
-
- { "syncToGL", (void *)&SC_syncToGL,
- "void", "(int)" },
-
- { "colorFloatRGBAtoUNorm8", (void *)&SC_colorFloatRGBAtoUNorm8,
- "int", "(float, float, float, float)" },
- { "colorFloatRGBto565", (void *)&SC_colorFloatRGBAto565,
- "int", "(float, float, float)" },
-
-
- { "getWidth", (void *)&SC_getWidth,
- "int", "()" },
- { "getHeight", (void *)&SC_getHeight,
- "int", "()" },
-
- { "sendToClient", (void *)&SC_toClient,
- "int", "(void *data, int cmdID, int len, int waitForSpace)" },
-
-
- { "debugF", (void *)&SC_debugF,
- "void", "(void *, float)" },
- { "debugI32", (void *)&SC_debugI32,
- "void", "(void *, int)" },
- { "debugHexF", (void *)&SC_debugHexF,
- "void", "(void *, float)" },
- { "debugHexI32", (void *)&SC_debugHexI32,
- "void", "(void *, int)" },
-
- { "scriptCall", (void *)&SC_scriptCall,
- "void", "(int)" },
-
-
- { NULL, NULL, NULL, NULL }
+ { NULL, NULL }
};
const ScriptCState::SymbolTable_t * ScriptCState::lookupSymbol(const char *sym)
@@ -1400,17 +729,3 @@
return NULL;
}
-void ScriptCState::appendDecls(String8 *str)
-{
- ScriptCState::SymbolTable_t *syms = gSyms;
- while (syms->mPtr) {
- str->append(syms->mRet);
- str->append(" ");
- str->append(syms->mName);
- str->append(syms->mParam);
- str->append(";\n");
- syms++;
- }
-}
-
-
diff --git a/libs/rs/rsScriptC_LibCL.cpp b/libs/rs/rsScriptC_LibCL.cpp
new file mode 100644
index 0000000..ce8e7b2
--- /dev/null
+++ b/libs/rs/rsScriptC_LibCL.cpp
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "rsContext.h"
+#include "rsScriptC.h"
+
+// Implements rs_cl.rsh
+
+
+using namespace android;
+using namespace android::renderscript;
+
+
+static float SC_acospi(float v) {
+ return acosf(v)/ M_PI;
+}
+
+static float SC_asinpi(float v) {
+ return asinf(v) / M_PI;
+}
+
+static float SC_atanpi(float v) {
+ return atanf(v) / M_PI;
+}
+
+static float SC_atan2pi(float y, float x) {
+ return atan2f(y, x) / M_PI;
+}
+
+static float SC_cospi(float v) {
+ return cosf(v * M_PI);
+}
+
+static float SC_exp10(float v) {
+ return pow(10.f, v);
+
+}
+
+static float SC_fract(float v, int *iptr) {
+ int i = (int)floor(v);
+ iptr[0] = i;
+ return fmin(v - i, 0x1.fffffep-1f);
+}
+
+static float SC_log2(float v) {
+ return log10(v) / log10(2.f);
+}
+
+static float SC_pown(float v, int p) {
+ return powf(v, (float)p);
+}
+
+static float SC_powr(float v, float p) {
+ return powf(v, p);
+}
+
+float SC_rootn(float v, int r) {
+ return pow(v, 1.f / r);
+}
+
+float SC_rsqrt(float v) {
+ return 1.f / sqrtf(v);
+}
+
+float SC_sincos(float v, float *cosptr) {
+ *cosptr = cosf(v);
+ return sinf(v);
+}
+
+static float SC_sinpi(float v) {
+ return sinf(v * M_PI);
+}
+
+static float SC_tanpi(float v) {
+ return tanf(v * M_PI);
+}
+
+ //{ "logb", (void *)& },
+ //{ "mad", (void *)& },
+ //{ "nan", (void *)& },
+ //{ "tgamma", (void *)& },
+
+//////////////////////////////////////////////////////////////////////////////
+// Integer
+//////////////////////////////////////////////////////////////////////////////
+
+
+static uint32_t SC_abs_i32(int32_t v) {return abs(v);}
+static uint16_t SC_abs_i16(int16_t v) {return (uint16_t)abs(v);}
+static uint8_t SC_abs_i8(int8_t v) {return (uint8_t)abs(v);}
+
+static uint32_t SC_clz_u32(uint32_t v) {return __builtin_clz(v);}
+static uint16_t SC_clz_u16(uint16_t v) {return (uint16_t)__builtin_clz(v);}
+static uint8_t SC_clz_u8(uint8_t v) {return (uint8_t)__builtin_clz(v);}
+static int32_t SC_clz_i32(int32_t v) {return (int32_t)__builtin_clz((uint32_t)v);}
+static int16_t SC_clz_i16(int16_t v) {return (int16_t)__builtin_clz(v);}
+static int8_t SC_clz_i8(int8_t v) {return (int8_t)__builtin_clz(v);}
+
+static uint32_t SC_max_u32(uint32_t v, uint32_t v2) {return rsMax(v, v2);}
+static uint16_t SC_max_u16(uint16_t v, uint16_t v2) {return rsMax(v, v2);}
+static uint8_t SC_max_u8(uint8_t v, uint8_t v2) {return rsMax(v, v2);}
+static int32_t SC_max_i32(int32_t v, int32_t v2) {return rsMax(v, v2);}
+static int16_t SC_max_i16(int16_t v, int16_t v2) {return rsMax(v, v2);}
+static int8_t SC_max_i8(int8_t v, int8_t v2) {return rsMax(v, v2);}
+
+static uint32_t SC_min_u32(uint32_t v, uint32_t v2) {return rsMin(v, v2);}
+static uint16_t SC_min_u16(uint16_t v, uint16_t v2) {return rsMin(v, v2);}
+static uint8_t SC_min_u8(uint8_t v, uint8_t v2) {return rsMin(v, v2);}
+static int32_t SC_min_i32(int32_t v, int32_t v2) {return rsMin(v, v2);}
+static int16_t SC_min_i16(int16_t v, int16_t v2) {return rsMin(v, v2);}
+static int8_t SC_min_i8(int8_t v, int8_t v2) {return rsMin(v, v2);}
+
+//////////////////////////////////////////////////////////////////////////////
+// Float util
+//////////////////////////////////////////////////////////////////////////////
+
+static float SC_clamp_f32(float amount, float low, float high)
+{
+ return amount < low ? low : (amount > high ? high : amount);
+}
+
+static float SC_degrees(float radians)
+{
+ return radians * (180.f / M_PI);
+}
+
+static float SC_max_f32(float v, float v2)
+{
+ return rsMax(v, v2);
+}
+
+static float SC_min_f32(float v, float v2)
+{
+ return rsMin(v, v2);
+}
+
+static float SC_mix_f32(float start, float stop, float amount)
+{
+ //LOGE("lerpf %f %f %f", start, stop, amount);
+ return start + (stop - start) * amount;
+}
+
+static float SC_radians(float degrees)
+{
+ return degrees * (M_PI / 180.f);
+}
+
+static float SC_step_f32(float edge, float v)
+{
+ if (v < edge) return 0.f;
+ return 1.f;
+}
+
+static float SC_sign_f32(float value)
+{
+ if (value > 0) return 1.f;
+ if (value < 0) return -1.f;
+ return value;
+}
+
+
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Class implementation
+//////////////////////////////////////////////////////////////////////////////
+
+// llvm name mangling ref
+// <builtin-type> ::= v # void
+// ::= b # bool
+// ::= c # char
+// ::= a # signed char
+// ::= h # unsigned char
+// ::= s # short
+// ::= t # unsigned short
+// ::= i # int
+// ::= j # unsigned int
+// ::= l # long
+// ::= m # unsigned long
+// ::= x # long long, __int64
+// ::= y # unsigned long long, __int64
+// ::= f # float
+// ::= d # double
+
+static ScriptCState::SymbolTable_t gSyms[] = {
+ // OpenCL math
+ { "_Z4acosf", (void *)&acosf },
+ { "_Z5acoshf", (void *)&acoshf },
+ { "_Z6acospif", (void *)&SC_acospi },
+ { "_Z4asinf", (void *)&asinf },
+ { "_Z5asinhf", (void *)&asinhf },
+ { "_Z6asinpif", (void *)&SC_asinpi },
+ { "_Z4atanf", (void *)&atanf },
+ { "_Z5atan2f", (void *)&atan2f },
+ { "_Z6atanpif", (void *)&SC_atanpi },
+ { "_Z7atan2pif", (void *)&SC_atan2pi },
+ { "_Z4cbrtf", (void *)&cbrtf },
+ { "_Z4ceilf", (void *)&ceilf },
+ { "_Z8copysignff", (void *)©signf },
+ { "_Z3cosf", (void *)&cosf },
+ { "_Z4coshf", (void *)&coshf },
+ { "_Z5cospif", (void *)&SC_cospi },
+ { "_Z4erfcf", (void *)&erfcf },
+ { "_Z3erff", (void *)&erff },
+ { "_Z3expf", (void *)&expf },
+ { "_Z4exp2f", (void *)&exp2f },
+ { "_Z5exp10f", (void *)&SC_exp10 },
+ { "_Z5expm1f", (void *)&expm1f },
+ { "_Z4fabsf", (void *)&fabsf },
+ { "_Z4fdimff", (void *)&fdimf },
+ { "_Z5floorf", (void *)&floorf },
+ { "_Z3fmafff", (void *)&fmaf },
+ { "_Z4fmaxff", (void *)&fmaxf },
+ { "_Z4fminff", (void *)&fminf }, // float fmin(float, float)
+ { "_Z4fmodff", (void *)&fmodf },
+ { "_Z5fractfPf", (void *)&SC_fract },
+ { "_Z5frexpfPi", (void *)&frexpf },
+ { "_Z5hypotff", (void *)&hypotf },
+ { "_Z5ilogbf", (void *)&ilogbf },
+ { "_Z5ldexpfi", (void *)&ldexpf },
+ { "_Z6lgammaf", (void *)&lgammaf },
+ { "_Z3logf", (void *)&logf },
+ { "_Z4log2f", (void *)&SC_log2 },
+ { "_Z5log10f", (void *)&log10f },
+ { "_Z5log1pf", (void *)&log1pf },
+ //{ "logb", (void *)& },
+ //{ "mad", (void *)& },
+ { "modf", (void *)&modff },
+ //{ "nan", (void *)& },
+ { "_Z9nextafterff", (void *)&nextafterf },
+ { "_Z3powff", (void *)&powf },
+ { "_Z4pownfi", (void *)&SC_pown },
+ { "_Z4powrff", (void *)&SC_powr },
+ { "_Z9remainderff", (void *)&remainderf },
+ { "remquo", (void *)&remquof },
+ { "_Z4rintf", (void *)&rintf },
+ { "_Z5rootnfi", (void *)&SC_rootn },
+ { "_Z5roundf", (void *)&roundf },
+ { "_Z5rsqrtf", (void *)&SC_rsqrt },
+ { "_Z3sinf", (void *)&sinf },
+ { "sincos", (void *)&SC_sincos },
+ { "_Z4sinhf", (void *)&sinhf },
+ { "_Z5sinpif", (void *)&SC_sinpi },
+ { "_Z4sqrtf", (void *)&sqrtf },
+ { "_Z3tanf", (void *)&tanf },
+ { "_Z4tanhf", (void *)&tanhf },
+ { "_Z5tanpif", (void *)&SC_tanpi },
+ //{ "tgamma", (void *)& },
+ { "_Z5truncf", (void *)&truncf },
+
+ // OpenCL Int
+ { "_Z3absi", (void *)&SC_abs_i32 },
+ { "_Z3abss", (void *)&SC_abs_i16 },
+ { "_Z3absc", (void *)&SC_abs_i8 },
+ { "_Z3clzj", (void *)&SC_clz_u32 },
+ { "_Z3clzt", (void *)&SC_clz_u16 },
+ { "_Z3clzh", (void *)&SC_clz_u8 },
+ { "_Z3clzi", (void *)&SC_clz_i32 },
+ { "_Z3clzs", (void *)&SC_clz_i16 },
+ { "_Z3clzc", (void *)&SC_clz_i8 },
+ { "_Z3maxjj", (void *)&SC_max_u32 },
+ { "_Z3maxtt", (void *)&SC_max_u16 },
+ { "_Z3maxhh", (void *)&SC_max_u8 },
+ { "_Z3maxii", (void *)&SC_max_i32 },
+ { "_Z3maxss", (void *)&SC_max_i16 },
+ { "_Z3maxcc", (void *)&SC_max_i8 },
+ { "_Z3minjj", (void *)&SC_min_u32 },
+ { "_Z3mintt", (void *)&SC_min_u16 },
+ { "_Z3minhh", (void *)&SC_min_u8 },
+ { "_Z3minii", (void *)&SC_min_i32 },
+ { "_Z3minss", (void *)&SC_min_i16 },
+ { "_Z3mincc", (void *)&SC_min_i8 },
+
+ // OpenCL 6.11.4
+ { "_Z5clampfff", (void *)&SC_clamp_f32 },
+ { "_Z7degreesf", (void *)&SC_degrees },
+ { "_Z3maxff", (void *)&SC_max_f32 },
+ { "_Z3minff", (void *)&SC_min_f32 },
+ { "_Z3mixfff", (void *)&SC_mix_f32 },
+ { "_Z7radiansf", (void *)&SC_radians },
+ { "_Z4stepff", (void *)&SC_step_f32 },
+ //{ "smoothstep", (void *)& },
+ { "_Z4signf", (void *)&SC_sign_f32 },
+
+ { NULL, NULL }
+};
+
+const ScriptCState::SymbolTable_t * ScriptCState::lookupSymbolCL(const char *sym)
+{
+ ScriptCState::SymbolTable_t *syms = gSyms;
+
+ while (syms->mPtr) {
+ if (!strcmp(syms->mName, sym)) {
+ return syms;
+ }
+ syms++;
+ }
+ return NULL;
+}
+
diff --git a/libs/rs/rsScriptC_LibGL.cpp b/libs/rs/rsScriptC_LibGL.cpp
new file mode 100644
index 0000000..8f650f8
--- /dev/null
+++ b/libs/rs/rsScriptC_LibGL.cpp
@@ -0,0 +1,524 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "rsContext.h"
+#include "rsScriptC.h"
+#include "rsMatrix.h"
+
+#include "acc/acc.h"
+#include "utils/Timers.h"
+
+#define GL_GLEXT_PROTOTYPES
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <time.h>
+
+using namespace android;
+using namespace android::renderscript;
+
+#define GET_TLS() Context::ScriptTLSStruct * tls = \
+ (Context::ScriptTLSStruct *)pthread_getspecific(Context::gThreadTLSKey); \
+ Context * rsc = tls->mContext; \
+ ScriptC * sc = (ScriptC *) tls->mScript
+
+
+//////////////////////////////////////////////////////////////////////////////
+// IO routines
+//////////////////////////////////////////////////////////////////////////////
+
+static void SC_updateSimpleMesh(RsSimpleMesh mesh)
+{
+ GET_TLS();
+ SimpleMesh *sm = static_cast<SimpleMesh *>(mesh);
+ sm->uploadAll(rsc);
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Context
+//////////////////////////////////////////////////////////////////////////////
+
+static void SC_bindTexture(RsProgramFragment vpf, uint32_t slot, RsAllocation va)
+{
+ GET_TLS();
+ rsi_ProgramBindTexture(rsc,
+ static_cast<ProgramFragment *>(vpf),
+ slot,
+ static_cast<Allocation *>(va));
+
+}
+
+static void SC_bindSampler(RsProgramFragment vpf, uint32_t slot, RsSampler vs)
+{
+ GET_TLS();
+ rsi_ProgramBindSampler(rsc,
+ static_cast<ProgramFragment *>(vpf),
+ slot,
+ static_cast<Sampler *>(vs));
+
+}
+
+static void SC_bindProgramStore(RsProgramStore pfs)
+{
+ GET_TLS();
+ rsi_ContextBindProgramStore(rsc, pfs);
+}
+
+static void SC_bindProgramFragment(RsProgramFragment pf)
+{
+ GET_TLS();
+ rsi_ContextBindProgramFragment(rsc, pf);
+}
+
+static void SC_bindProgramVertex(RsProgramVertex pv)
+{
+ GET_TLS();
+ rsi_ContextBindProgramVertex(rsc, pv);
+}
+
+static void SC_bindProgramRaster(RsProgramRaster pv)
+{
+ GET_TLS();
+ rsi_ContextBindProgramRaster(rsc, pv);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// VP
+//////////////////////////////////////////////////////////////////////////////
+
+static void SC_vpLoadModelMatrix(const rsc_Matrix *m)
+{
+ GET_TLS();
+ rsc->getVertex()->setModelviewMatrix(m);
+}
+
+static void SC_vpLoadTextureMatrix(const rsc_Matrix *m)
+{
+ GET_TLS();
+ rsc->getVertex()->setTextureMatrix(m);
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Drawing
+//////////////////////////////////////////////////////////////////////////////
+
+static void SC_drawLine(float x1, float y1, float z1,
+ float x2, float y2, float z2)
+{
+ GET_TLS();
+ if (!rsc->setupCheck()) {
+ return;
+ }
+
+ float vtx[] = { x1, y1, z1, x2, y2, z2 };
+ VertexArray va;
+ va.add(GL_FLOAT, 3, 12, false, (uint32_t)vtx, "position");
+ va.setupGL2(rsc, &rsc->mStateVertexArray, &rsc->mShaderCache);
+
+ glDrawArrays(GL_LINES, 0, 2);
+}
+
+static void SC_drawPoint(float x, float y, float z)
+{
+ GET_TLS();
+ if (!rsc->setupCheck()) {
+ return;
+ }
+
+ float vtx[] = { x, y, z };
+
+ VertexArray va;
+ va.add(GL_FLOAT, 3, 12, false, (uint32_t)vtx, "position");
+ va.setupGL2(rsc, &rsc->mStateVertexArray, &rsc->mShaderCache);
+
+ glDrawArrays(GL_POINTS, 0, 1);
+}
+
+static void SC_drawQuadTexCoords(float x1, float y1, float z1,
+ float u1, float v1,
+ float x2, float y2, float z2,
+ float u2, float v2,
+ float x3, float y3, float z3,
+ float u3, float v3,
+ float x4, float y4, float z4,
+ float u4, float v4)
+{
+ GET_TLS();
+ if (!rsc->setupCheck()) {
+ return;
+ }
+
+ //LOGE("Quad");
+ //LOGE("%4.2f, %4.2f, %4.2f", x1, y1, z1);
+ //LOGE("%4.2f, %4.2f, %4.2f", x2, y2, z2);
+ //LOGE("%4.2f, %4.2f, %4.2f", x3, y3, z3);
+ //LOGE("%4.2f, %4.2f, %4.2f", x4, y4, z4);
+
+ float vtx[] = {x1,y1,z1, x2,y2,z2, x3,y3,z3, x4,y4,z4};
+ const float tex[] = {u1,v1, u2,v2, u3,v3, u4,v4};
+
+ VertexArray va;
+ va.add(GL_FLOAT, 3, 12, false, (uint32_t)vtx, "position");
+ va.add(GL_FLOAT, 2, 8, false, (uint32_t)tex, "texture0");
+ va.setupGL2(rsc, &rsc->mStateVertexArray, &rsc->mShaderCache);
+
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+}
+
+static void SC_drawQuad(float x1, float y1, float z1,
+ float x2, float y2, float z2,
+ float x3, float y3, float z3,
+ float x4, float y4, float z4)
+{
+ SC_drawQuadTexCoords(x1, y1, z1, 0, 1,
+ x2, y2, z2, 1, 1,
+ x3, y3, z3, 1, 0,
+ x4, y4, z4, 0, 0);
+}
+
+static void SC_drawSpriteScreenspace(float x, float y, float z, float w, float h)
+{
+ GET_TLS();
+ ObjectBaseRef<const ProgramVertex> tmp(rsc->getVertex());
+ rsc->setVertex(rsc->getDefaultProgramVertex());
+ //rsc->setupCheck();
+
+ //GLint crop[4] = {0, h, w, -h};
+
+ float sh = rsc->getHeight();
+
+ SC_drawQuad(x, sh - y, z,
+ x+w, sh - y, z,
+ x+w, sh - (y+h), z,
+ x, sh - (y+h), z);
+ rsc->setVertex((ProgramVertex *)tmp.get());
+}
+
+static void SC_drawSpriteScreenspaceCropped(float x, float y, float z, float w, float h,
+ float cx0, float cy0, float cx1, float cy1)
+{
+ GET_TLS();
+ if (!rsc->setupCheck()) {
+ return;
+ }
+
+ GLint crop[4] = {cx0, cy0, cx1, cy1};
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+ glDrawTexfOES(x, y, z, w, h);
+}
+
+static void SC_drawSprite(float x, float y, float z, float w, float h)
+{
+ GET_TLS();
+ float vin[3] = {x, y, z};
+ float vout[4];
+
+ //LOGE("ds in %f %f %f", x, y, z);
+ rsc->getVertex()->transformToScreen(rsc, vout, vin);
+ //LOGE("ds out %f %f %f %f", vout[0], vout[1], vout[2], vout[3]);
+ vout[0] /= vout[3];
+ vout[1] /= vout[3];
+ vout[2] /= vout[3];
+
+ vout[0] *= rsc->getWidth() / 2;
+ vout[1] *= rsc->getHeight() / 2;
+ vout[0] += rsc->getWidth() / 2;
+ vout[1] += rsc->getHeight() / 2;
+
+ vout[0] -= w/2;
+ vout[1] -= h/2;
+
+ //LOGE("ds out2 %f %f %f", vout[0], vout[1], vout[2]);
+
+ // U, V, W, H
+ SC_drawSpriteScreenspace(vout[0], vout[1], z, h, w);
+ //rsc->setupCheck();
+}
+
+
+static void SC_drawRect(float x1, float y1,
+ float x2, float y2, float z)
+{
+ //LOGE("SC_drawRect %f,%f %f,%f %f", x1, y1, x2, y2, z);
+ SC_drawQuad(x1, y2, z,
+ x2, y2, z,
+ x2, y1, z,
+ x1, y1, z);
+}
+
+static void SC_drawSimpleMesh(RsSimpleMesh vsm)
+{
+ GET_TLS();
+ SimpleMesh *sm = static_cast<SimpleMesh *>(vsm);
+ if (!rsc->setupCheck()) {
+ return;
+ }
+ sm->render(rsc);
+}
+
+static void SC_drawSimpleMeshRange(RsSimpleMesh vsm, uint32_t start, uint32_t len)
+{
+ GET_TLS();
+ SimpleMesh *sm = static_cast<SimpleMesh *>(vsm);
+ if (!rsc->setupCheck()) {
+ return;
+ }
+ sm->renderRange(rsc, start, len);
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+//////////////////////////////////////////////////////////////////////////////
+
+
+static void SC_color(float r, float g, float b, float a)
+{
+ GET_TLS();
+ rsc->mStateVertex.color[0] = r;
+ rsc->mStateVertex.color[1] = g;
+ rsc->mStateVertex.color[2] = b;
+ rsc->mStateVertex.color[3] = a;
+ if (!rsc->checkVersion2_0()) {
+ glColor4f(r, g, b, a);
+ }
+}
+
+static void SC_pointAttenuation(float a, float b, float c)
+{
+ GLfloat params[] = { a, b, c };
+ glPointParameterfv(GL_POINT_DISTANCE_ATTENUATION, params);
+}
+
+static void SC_hsbToRgb(float h, float s, float b, float* rgb)
+{
+ float red = 0.0f;
+ float green = 0.0f;
+ float blue = 0.0f;
+
+ float x = h;
+ float y = s;
+ float z = b;
+
+ float hf = (x - (int) x) * 6.0f;
+ int ihf = (int) hf;
+ float f = hf - ihf;
+ float pv = z * (1.0f - y);
+ float qv = z * (1.0f - y * f);
+ float tv = z * (1.0f - y * (1.0f - f));
+
+ switch (ihf) {
+ case 0: // Red is the dominant color
+ red = z;
+ green = tv;
+ blue = pv;
+ break;
+ case 1: // Green is the dominant color
+ red = qv;
+ green = z;
+ blue = pv;
+ break;
+ case 2:
+ red = pv;
+ green = z;
+ blue = tv;
+ break;
+ case 3: // Blue is the dominant color
+ red = pv;
+ green = qv;
+ blue = z;
+ break;
+ case 4:
+ red = tv;
+ green = pv;
+ blue = z;
+ break;
+ case 5: // Red is the dominant color
+ red = z;
+ green = pv;
+ blue = qv;
+ break;
+ }
+
+ rgb[0] = red;
+ rgb[1] = green;
+ rgb[2] = blue;
+}
+
+static int SC_hsbToAbgr(float h, float s, float b, float a)
+{
+ //LOGE("hsb a %f, %f, %f %f", h, s, b, a);
+ float rgb[3];
+ SC_hsbToRgb(h, s, b, rgb);
+ //LOGE("rgb %f, %f, %f ", rgb[0], rgb[1], rgb[2]);
+ return int(a * 255.0f) << 24 |
+ int(rgb[2] * 255.0f) << 16 |
+ int(rgb[1] * 255.0f) << 8 |
+ int(rgb[0] * 255.0f);
+}
+
+static void SC_hsb(float h, float s, float b, float a)
+{
+ GET_TLS();
+ float rgb[3];
+ SC_hsbToRgb(h, s, b, rgb);
+ if (rsc->checkVersion2_0()) {
+ glVertexAttrib4f(1, rgb[0], rgb[1], rgb[2], a);
+ } else {
+ glColor4f(rgb[0], rgb[1], rgb[2], a);
+ }
+}
+
+static void SC_uploadToTexture2(RsAllocation va, uint32_t baseMipLevel)
+{
+ GET_TLS();
+ rsi_AllocationUploadToTexture(rsc, va, false, baseMipLevel);
+}
+static void SC_uploadToTexture(RsAllocation va)
+{
+ GET_TLS();
+ rsi_AllocationUploadToTexture(rsc, va, false, 0);
+}
+
+static void SC_uploadToBufferObject(RsAllocation va)
+{
+ GET_TLS();
+ rsi_AllocationUploadToBufferObject(rsc, va);
+}
+
+static void SC_ClearColor(float r, float g, float b, float a)
+{
+ GET_TLS();
+ if (!rsc->setupCheck()) {
+ return;
+ }
+
+ glClearColor(r, g, b, a);
+ glClear(GL_COLOR_BUFFER_BIT);
+}
+
+static void SC_ClearDepth(float v)
+{
+ GET_TLS();
+ if (!rsc->setupCheck()) {
+ return;
+ }
+
+ glClearDepthf(v);
+ glClear(GL_DEPTH_BUFFER_BIT);
+}
+
+static uint32_t SC_getWidth()
+{
+ GET_TLS();
+ return rsc->getWidth();
+}
+
+static uint32_t SC_getHeight()
+{
+ GET_TLS();
+ return rsc->getHeight();
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Class implementation
+//////////////////////////////////////////////////////////////////////////////
+
+// llvm name mangling ref
+// <builtin-type> ::= v # void
+// ::= b # bool
+// ::= c # char
+// ::= a # signed char
+// ::= h # unsigned char
+// ::= s # short
+// ::= t # unsigned short
+// ::= i # int
+// ::= j # unsigned int
+// ::= l # long
+// ::= m # unsigned long
+// ::= x # long long, __int64
+// ::= y # unsigned long long, __int64
+// ::= f # float
+// ::= d # double
+
+static ScriptCState::SymbolTable_t gSyms[] = {
+ { "rsgBindProgramFragment", (void *)&SC_bindProgramFragment },
+ { "rsgBindProgramStore", (void *)&SC_bindProgramStore },
+ { "rsgBindProgramVertex", (void *)&SC_bindProgramVertex },
+ { "rsgBindProgramRaster", (void *)&SC_bindProgramRaster },
+ { "rsgBindSampler", (void *)&SC_bindSampler },
+ { "rsgBindTexture", (void *)&SC_bindTexture },
+
+ { "rsgProgramVertexLoadModelMatrix", (void *)&SC_vpLoadModelMatrix },
+ { "rsgProgramVertexLoadTextureMatrix", (void *)&SC_vpLoadTextureMatrix },
+
+ { "rsgGetWidth", (void *)&SC_getWidth },
+ { "rsgGetHeight", (void *)&SC_getHeight },
+
+ { "_Z18rsgUploadToTextureii", (void *)&SC_uploadToTexture2 },
+ { "_Z18rsgUploadToTexturei", (void *)&SC_uploadToTexture },
+ { "rsgUploadToBufferObject", (void *)&SC_uploadToBufferObject },
+
+ { "rsgDrawRect", (void *)&SC_drawRect },
+ { "rsgDrawQuad", (void *)&SC_drawQuad },
+ { "rsgDrawQuadTexCoords", (void *)&SC_drawQuadTexCoords },
+ //{ "drawSprite", (void *)&SC_drawSprite },
+ { "rsgDrawSpriteScreenspace", (void *)&SC_drawSpriteScreenspace },
+ { "rsgDrawSpriteScreenspaceCropped", (void *)&SC_drawSpriteScreenspaceCropped },
+ { "rsgDrawLine", (void *)&SC_drawLine },
+ { "rsgDrawPoint", (void *)&SC_drawPoint },
+ { "_Z17rsgDrawSimpleMeshi", (void *)&SC_drawSimpleMesh },
+ { "_Z17rsgDrawSimpleMeshiii", (void *)&SC_drawSimpleMeshRange },
+
+ { "rsgClearColor", (void *)&SC_ClearColor },
+ { "rsgClearDepth", (void *)&SC_ClearDepth },
+
+
+ //////////////////////////////////////
+ // IO
+ { "updateSimpleMesh", (void *)&SC_updateSimpleMesh },
+
+ // misc
+ //{ "pfClearColor", (void *)&SC_ClearColor },
+ { "color", (void *)&SC_color },
+ { "hsb", (void *)&SC_hsb },
+ { "hsbToRgb", (void *)&SC_hsbToRgb },
+ { "hsbToAbgr", (void *)&SC_hsbToAbgr },
+ { "pointAttenuation", (void *)&SC_pointAttenuation },
+
+ { NULL, NULL }
+};
+
+const ScriptCState::SymbolTable_t * ScriptCState::lookupSymbolGL(const char *sym)
+{
+ ScriptCState::SymbolTable_t *syms = gSyms;
+
+ while (syms->mPtr) {
+ if (!strcmp(syms->mName, sym)) {
+ return syms;
+ }
+ syms++;
+ }
+ return NULL;
+}
+
diff --git a/libs/rs/rsShaderCache.cpp b/libs/rs/rsShaderCache.cpp
index 4711d1b..504ffba 100644
--- a/libs/rs/rsShaderCache.cpp
+++ b/libs/rs/rsShaderCache.cpp
@@ -14,10 +14,14 @@
* limitations under the License.
*/
+#ifndef ANDROID_RS_BUILD_FOR_HOST
#include "rsContext.h"
-
#include <GLES/gl.h>
#include <GLES2/gl2.h>
+#else
+#include "rsContextHostStub.h"
+#include <OpenGL/gl.h>
+#endif //ANDROID_RS_BUILD_FOR_HOST
using namespace android;
using namespace android::renderscript;
@@ -94,16 +98,11 @@
glAttachShader(pgm, frag->getShaderID());
if (!vtx->isUserProgram()) {
- glBindAttribLocation(pgm, 0, "ATTRIB_LegacyPosition");
- glBindAttribLocation(pgm, 1, "ATTRIB_LegacyColor");
- glBindAttribLocation(pgm, 2, "ATTRIB_LegacyNormal");
- glBindAttribLocation(pgm, 3, "ATTRIB_LegacyPointSize");
- glBindAttribLocation(pgm, 4, "ATTRIB_LegacyTexture");
- e->mVtxAttribSlots[RS_KIND_POSITION] = 0;
- e->mVtxAttribSlots[RS_KIND_COLOR] = 1;
- e->mVtxAttribSlots[RS_KIND_NORMAL] = 2;
- e->mVtxAttribSlots[RS_KIND_POINT_SIZE] = 3;
- e->mVtxAttribSlots[RS_KIND_TEXTURE] = 4;
+ glBindAttribLocation(pgm, 0, "ATTRIB_position");
+ glBindAttribLocation(pgm, 1, "ATTRIB_color");
+ glBindAttribLocation(pgm, 2, "ATTRIB_normal");
+ glBindAttribLocation(pgm, 3, "ATTRIB_pointSize");
+ glBindAttribLocation(pgm, 4, "ATTRIB_texture0");
}
//LOGE("e2 %x", glGetError());
diff --git a/libs/rs/rsSignal.cpp b/libs/rs/rsSignal.cpp
new file mode 100644
index 0000000..9239bfd
--- /dev/null
+++ b/libs/rs/rsSignal.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "rsSignal.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+
+Signal::Signal()
+{
+ mSet = true;
+}
+
+Signal::~Signal()
+{
+ pthread_mutex_destroy(&mMutex);
+ pthread_cond_destroy(&mCondition);
+}
+
+bool Signal::init()
+{
+ int status = pthread_mutex_init(&mMutex, NULL);
+ if (status) {
+ LOGE("LocklessFifo mutex init failure");
+ return false;
+ }
+
+ status = pthread_cond_init(&mCondition, NULL);
+ if (status) {
+ LOGE("LocklessFifo condition init failure");
+ pthread_mutex_destroy(&mMutex);
+ return false;
+ }
+
+ return true;
+}
+
+void Signal::set()
+{
+ int status;
+
+ status = pthread_mutex_lock(&mMutex);
+ if (status) {
+ LOGE("LocklessCommandFifo: error %i locking for set condition.", status);
+ return;
+ }
+
+ mSet = true;
+
+ status = pthread_cond_signal(&mCondition);
+ if (status) {
+ LOGE("LocklessCommandFifo: error %i on set condition.", status);
+ }
+
+ status = pthread_mutex_unlock(&mMutex);
+ if (status) {
+ LOGE("LocklessCommandFifo: error %i unlocking for set condition.", status);
+ }
+}
+
+void Signal::wait()
+{
+ int status;
+
+ status = pthread_mutex_lock(&mMutex);
+ if (status) {
+ LOGE("LocklessCommandFifo: error %i locking for condition.", status);
+ return;
+ }
+
+ if (!mSet) {
+ status = pthread_cond_wait(&mCondition, &mMutex);
+ if (status) {
+ LOGE("LocklessCommandFifo: error %i waiting on condition.", status);
+ }
+ }
+ mSet = false;
+
+ status = pthread_mutex_unlock(&mMutex);
+ if (status) {
+ LOGE("LocklessCommandFifo: error %i unlocking for condition.", status);
+ }
+}
+
diff --git a/libs/rs/rsFileA3DDecls.h b/libs/rs/rsSignal.h
similarity index 66%
rename from libs/rs/rsFileA3DDecls.h
rename to libs/rs/rsSignal.h
index 2a08bd3..2e760f1 100644
--- a/libs/rs/rsFileA3DDecls.h
+++ b/libs/rs/rsSignal.h
@@ -14,31 +14,33 @@
* limitations under the License.
*/
-#ifndef ANDROID_RS_FILE_A3D_DECLS_H
-#define ANDROID_RS_FILE_A3D_DECLS_H
+#ifndef ANDROID_RS_SIGNAL_H
+#define ANDROID_RS_SIGNAL_H
-#define A3D_MAGIC_KEY "Android3D_ff"
+#include "rsUtils.h"
namespace android {
namespace renderscript {
- enum A3DChunkType {
- CHUNK_EMPTY,
+class Signal {
+public:
+ Signal();
+ ~Signal();
- CHUNK_ELEMENT,
- CHUNK_ELEMENT_SOURCE,
- CHUNK_VERTICIES,
- CHUNK_MESH,
- CHUNK_PRIMITIVE,
+ bool init();
- CHUNK_LAST
- };
+ void set();
+ void wait();
+protected:
+ bool mSet;
+ pthread_mutex_t mMutex;
+ pthread_cond_t mCondition;
+};
}
}
-#endif //ANDROID_RS_FILE_A3D_H
-
+#endif
diff --git a/libs/rs/rsSimpleMesh.cpp b/libs/rs/rsSimpleMesh.cpp
index 53ce5cd..6ec1a3b 100644
--- a/libs/rs/rsSimpleMesh.cpp
+++ b/libs/rs/rsSimpleMesh.cpp
@@ -14,13 +14,24 @@
* limitations under the License.
*/
+#ifndef ANDROID_RS_BUILD_FOR_HOST
#include "rsContext.h"
+#include <GLES/gl.h>
+#include <GLES2/gl2.h>
+#include <GLES/glext.h>
+#else
+#include "rsContextHostStub.h"
+
+#include <OpenGL/gl.h>
+#include <OpenGl/glext.h>
+#endif
+
using namespace android;
using namespace android::renderscript;
-#include <GLES/gl.h>
-#include <GLES/glext.h>
+
+
SimpleMesh::SimpleMesh(Context *rsc) : ObjectBase(rsc)
{
@@ -57,21 +68,12 @@
rsc->checkError("SimpleMesh::renderRange 1");
VertexArray va;
- if (rsc->checkVersion2_0()) {
- for (uint32_t ct=0; ct < mVertexTypeCount; ct++) {
- mVertexBuffers[ct]->uploadCheck(rsc);
- va.setActiveBuffer(mVertexBuffers[ct]->getBufferObjectID());
- mVertexTypes[ct]->enableGLVertexBuffer2(&va);
- }
- va.setupGL2(rsc, &rsc->mStateVertexArray, &rsc->mShaderCache);
- } else {
- for (uint32_t ct=0; ct < mVertexTypeCount; ct++) {
- mVertexBuffers[ct]->uploadCheck(rsc);
- va.setActiveBuffer(mVertexBuffers[ct]->getBufferObjectID());
- mVertexTypes[ct]->enableGLVertexBuffer(&va);
- }
- va.setupGL(rsc, 0);
+ for (uint32_t ct=0; ct < mVertexTypeCount; ct++) {
+ mVertexBuffers[ct]->uploadCheck(rsc);
+ va.setActiveBuffer(mVertexBuffers[ct]->getBufferObjectID());
+ mVertexTypes[ct]->enableGLVertexBuffer(&va);
}
+ va.setupGL2(rsc, &rsc->mStateVertexArray, &rsc->mShaderCache);
rsc->checkError("SimpleMesh::renderRange 2");
if (mIndexType.get()) {
@@ -101,6 +103,97 @@
rsc->checkError("SimpleMesh::uploadAll");
}
+void SimpleMesh::updateGLPrimitive()
+{
+ switch(mPrimitive) {
+ case RS_PRIMITIVE_POINT: mGLPrimitive = GL_POINTS; break;
+ case RS_PRIMITIVE_LINE: mGLPrimitive = GL_LINES; break;
+ case RS_PRIMITIVE_LINE_STRIP: mGLPrimitive = GL_LINE_STRIP; break;
+ case RS_PRIMITIVE_TRIANGLE: mGLPrimitive = GL_TRIANGLES; break;
+ case RS_PRIMITIVE_TRIANGLE_STRIP: mGLPrimitive = GL_TRIANGLE_STRIP; break;
+ case RS_PRIMITIVE_TRIANGLE_FAN: mGLPrimitive = GL_TRIANGLE_FAN; break;
+ }
+}
+
+void SimpleMesh::serialize(OStream *stream) const
+{
+ // Need to identify ourselves
+ stream->addU32((uint32_t)getClassId());
+
+ String8 name(getName());
+ stream->addString(&name);
+
+ // Add primitive type
+ stream->addU8((uint8_t)mPrimitive);
+
+ // And now serialize the allocations
+ mIndexBuffer->serialize(stream);
+
+ // We need to indicate if the primitive buffer is present
+ if(mPrimitiveBuffer.get() != NULL) {
+ // Write if the primitive buffer is present
+ stream->addU32(1);
+ mPrimitiveBuffer->serialize(stream);
+ }
+ else {
+ // No buffer present, will need this when we read
+ stream->addU32(0);
+ }
+
+ // Store number of vertex streams
+ stream->addU32(mVertexTypeCount);
+ for(uint32_t vCount = 0; vCount < mVertexTypeCount; vCount ++) {
+ mVertexBuffers[vCount]->serialize(stream);
+ }
+}
+
+SimpleMesh *SimpleMesh::createFromStream(Context *rsc, IStream *stream)
+{
+ // First make sure we are reading the correct object
+ RsA3DClassID classID = (RsA3DClassID)stream->loadU32();
+ if(classID != RS_A3D_CLASS_ID_SIMPLE_MESH) {
+ LOGE("simple mesh loading skipped due to invalid class id");
+ return NULL;
+ }
+
+ SimpleMesh * mesh = new SimpleMesh(rsc);
+
+ String8 name;
+ stream->loadString(&name);
+ mesh->setName(name.string(), name.size());
+
+ mesh->mPrimitive = (RsPrimitive)stream->loadU8();
+ mesh->updateGLPrimitive();
+
+ Allocation *indexAlloc = Allocation::createFromStream(rsc, stream);
+ const Type *indexType = indexAlloc->getType();
+ mesh->mIndexBuffer.set(indexAlloc);
+ mesh->mIndexType.set(indexType);
+
+ bool isPrimitivePresent = stream->loadU32() != 0;
+ if(isPrimitivePresent) {
+ mesh->mPrimitiveBuffer.set(Allocation::createFromStream(rsc, stream));
+ mesh->mPrimitiveType.set(mesh->mPrimitiveBuffer->getType());
+ }
+
+ mesh->mVertexTypeCount = stream->loadU32();
+ if(mesh->mVertexTypeCount) {
+ mesh->mVertexTypes = new ObjectBaseRef<const Type>[mesh->mVertexTypeCount];
+ mesh->mVertexBuffers = new ObjectBaseRef<Allocation>[mesh->mVertexTypeCount];
+
+ for(uint32_t vCount = 0; vCount < mesh->mVertexTypeCount; vCount ++) {
+ Allocation *vertexAlloc = Allocation::createFromStream(rsc, stream);
+ const Type *vertexType = vertexAlloc->getType();
+ mesh->mVertexBuffers[vCount].set(vertexAlloc);
+ mesh->mVertexTypes[vCount].set(vertexType);
+ }
+ }
+
+ mesh->uploadAll(rsc);
+
+ return mesh;
+}
+
SimpleMeshContext::SimpleMeshContext()
{
@@ -131,14 +224,7 @@
}
sm->mPrimitive = (RsPrimitive)primType;
- switch(sm->mPrimitive) {
- case RS_PRIMITIVE_POINT: sm->mGLPrimitive = GL_POINTS; break;
- case RS_PRIMITIVE_LINE: sm->mGLPrimitive = GL_LINES; break;
- case RS_PRIMITIVE_LINE_STRIP: sm->mGLPrimitive = GL_LINE_STRIP; break;
- case RS_PRIMITIVE_TRIANGLE: sm->mGLPrimitive = GL_TRIANGLES; break;
- case RS_PRIMITIVE_TRIANGLE_STRIP: sm->mGLPrimitive = GL_TRIANGLE_STRIP; break;
- case RS_PRIMITIVE_TRIANGLE_FAN: sm->mGLPrimitive = GL_TRIANGLE_FAN; break;
- }
+ sm->updateGLPrimitive();
return sm;
}
diff --git a/libs/rs/rsSimpleMesh.h b/libs/rs/rsSimpleMesh.h
index 6defbda..362c7fb 100644
--- a/libs/rs/rsSimpleMesh.h
+++ b/libs/rs/rsSimpleMesh.h
@@ -48,7 +48,11 @@
void render(Context *) const;
void renderRange(Context *, uint32_t start, uint32_t len) const;
void uploadAll(Context *);
+ void updateGLPrimitive();
+ virtual void serialize(OStream *stream) const;
+ virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_SIMPLE_MESH; }
+ static SimpleMesh *createFromStream(Context *rsc, IStream *stream);
protected:
};
diff --git a/libs/rs/rsStream.cpp b/libs/rs/rsStream.cpp
new file mode 100644
index 0000000..39874a9
--- /dev/null
+++ b/libs/rs/rsStream.cpp
@@ -0,0 +1,132 @@
+
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_RS_BUILD_FOR_HOST
+#include "rsContext.h"
+#else
+#include "rsContextHostStub.h"
+#endif
+
+#include "rsStream.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+IStream::IStream(const uint8_t *buf, bool use64)
+{
+ mData = buf;
+ mPos = 0;
+ mUse64 = use64;
+}
+
+void IStream::loadByteArray(void *dest, size_t numBytes)
+{
+ memcpy(dest, mData + mPos, numBytes);
+ mPos += numBytes;
+}
+
+uint64_t IStream::loadOffset()
+{
+ uint64_t tmp;
+ if (mUse64) {
+ mPos = (mPos + 7) & (~7);
+ tmp = reinterpret_cast<const uint64_t *>(&mData[mPos])[0];
+ mPos += sizeof(uint64_t);
+ return tmp;
+ }
+ return loadU32();
+}
+
+void IStream::loadString(String8 *s)
+{
+ uint32_t len = loadU32();
+ s->setTo((const char *)&mData[mPos], len);
+ LOGE("loadString %s", s->string());
+ mPos += len;
+}
+
+
+// Output stream implementation
+
+OStream::OStream(uint64_t len, bool use64)
+{
+ mData = (uint8_t*)malloc(len);
+ mLength = len;
+ mPos = 0;
+ mUse64 = use64;
+}
+
+OStream::~OStream()
+{
+ free(mData);
+}
+
+void OStream::addByteArray(const void *src, size_t numBytes)
+{
+ // We need to potentially grow more than once if the number of byes we write is substantial
+ while(mPos + numBytes >= mLength) {
+ growSize();
+ }
+ memcpy(mData + mPos, src, numBytes);
+ mPos += numBytes;
+}
+
+void OStream::addOffset(uint64_t v)
+{
+ if (mUse64) {
+ mPos = (mPos + 7) & (~7);
+ if(mPos + sizeof(v) >= mLength) {
+ growSize();
+ }
+ mData[mPos++] = (uint8_t)(v & 0xff);
+ mData[mPos++] = (uint8_t)((v >> 8) & 0xff);
+ mData[mPos++] = (uint8_t)((v >> 16) & 0xff);
+ mData[mPos++] = (uint8_t)((v >> 24) & 0xff);
+ mData[mPos++] = (uint8_t)((v >> 32) & 0xff);
+ mData[mPos++] = (uint8_t)((v >> 40) & 0xff);
+ mData[mPos++] = (uint8_t)((v >> 48) & 0xff);
+ mData[mPos++] = (uint8_t)((v >> 56) & 0xff);
+ }
+ else {
+ addU32(v);
+ }
+}
+
+void OStream::addString(String8 *s)
+{
+ uint32_t len = s->size();
+ addU32(len);
+ if(mPos + len*sizeof(char) >= mLength) {
+ growSize();
+ }
+ char *stringData = reinterpret_cast<char *>(&mData[mPos]);
+ for(uint32_t i = 0; i < len; i ++) {
+ stringData[i] = s->string()[i];
+ }
+ mPos += len*sizeof(char);
+}
+
+void OStream::growSize()
+{
+ uint8_t *newData = (uint8_t*)malloc(mLength*2);
+ memcpy(newData, mData, mLength*sizeof(uint8_t));
+ mLength = mLength * 2;
+ free(mData);
+ mData = newData;
+}
+
+
diff --git a/libs/rs/rsStream.h b/libs/rs/rsStream.h
new file mode 100644
index 0000000..d401cd12
--- /dev/null
+++ b/libs/rs/rsStream.h
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_RS_STREAM_H
+#define ANDROID_RS_STREAM_H
+
+#include <utils/String8.h>
+#include <stdio.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+class IStream
+{
+public:
+ IStream(const uint8_t *, bool use64);
+
+ float loadF() {
+ mPos = (mPos + 3) & (~3);
+ float tmp = reinterpret_cast<const float *>(&mData[mPos])[0];
+ mPos += sizeof(float);
+ return tmp;
+ }
+ int32_t loadI32() {
+ mPos = (mPos + 3) & (~3);
+ int32_t tmp = reinterpret_cast<const int32_t *>(&mData[mPos])[0];
+ mPos += sizeof(int32_t);
+ return tmp;
+ }
+ uint32_t loadU32() {
+ mPos = (mPos + 3) & (~3);
+ uint32_t tmp = reinterpret_cast<const uint32_t *>(&mData[mPos])[0];
+ mPos += sizeof(uint32_t);
+ return tmp;
+ }
+ uint16_t loadU16() {
+ mPos = (mPos + 1) & (~1);
+ uint16_t tmp = reinterpret_cast<const uint16_t *>(&mData[mPos])[0];
+ mPos += sizeof(uint16_t);
+ return tmp;
+ }
+ inline uint8_t loadU8() {
+ uint8_t tmp = reinterpret_cast<const uint8_t *>(&mData[mPos])[0];
+ mPos += sizeof(uint8_t);
+ return tmp;
+ }
+ void loadByteArray(void *dest, size_t numBytes);
+ uint64_t loadOffset();
+ void loadString(String8 *s);
+ uint64_t getPos() const {
+ return mPos;
+ }
+ void reset(uint64_t pos) {
+ mPos = pos;
+ }
+ void reset() {
+ mPos = 0;
+ }
+
+ const uint8_t * getPtr() const {
+ return mData;
+ }
+protected:
+ const uint8_t * mData;
+ uint64_t mPos;
+ bool mUse64;
+};
+
+class OStream
+{
+public:
+ OStream(uint64_t length, bool use64);
+ ~OStream();
+
+ void align(uint32_t bytes) {
+ mPos = (mPos + (bytes - 1)) & (~(bytes - 1));
+ if(mPos >= mLength) {
+ growSize();
+ }
+ }
+
+ void addF(float v) {
+ uint32_t uintV = *reinterpret_cast<uint32_t*> (&v);
+ addU32(uintV);
+ }
+ void addI32(int32_t v) {
+ mPos = (mPos + 3) & (~3);
+ if(mPos + sizeof(v) >= mLength) {
+ growSize();
+ }
+ mData[mPos++] = (uint8_t)(v & 0xff);
+ mData[mPos++] = (uint8_t)((v >> 8) & 0xff);
+ mData[mPos++] = (uint8_t)((v >> 16) & 0xff);
+ mData[mPos++] = (uint8_t)((v >> 24) & 0xff);
+ }
+ void addU32(uint32_t v) {
+ mPos = (mPos + 3) & (~3);
+ if(mPos + sizeof(v) >= mLength) {
+ growSize();
+ }
+ mData[mPos++] = (uint8_t)(v & 0xff);
+ mData[mPos++] = (uint8_t)((v >> 8) & 0xff);
+ mData[mPos++] = (uint8_t)((v >> 16) & 0xff);
+ mData[mPos++] = (uint8_t)((v >> 24) & 0xff);
+ }
+ void addU16(uint16_t v) {
+ mPos = (mPos + 1) & (~1);
+ if(mPos + sizeof(v) >= mLength) {
+ growSize();
+ }
+ mData[mPos++] = (uint8_t)(v & 0xff);
+ mData[mPos++] = (uint8_t)(v >> 8);
+ }
+ inline void addU8(uint8_t v) {
+ if(mPos + 1 >= mLength) {
+ growSize();
+ }
+ reinterpret_cast<uint8_t *>(&mData[mPos])[0] = v;
+ mPos ++;
+ }
+ void addByteArray(const void *src, size_t numBytes);
+ void addOffset(uint64_t v);
+ void addString(String8 *s);
+ uint64_t getPos() const {
+ return mPos;
+ }
+ void reset(uint64_t pos) {
+ mPos = pos;
+ }
+ void reset() {
+ mPos = 0;
+ }
+ const uint8_t * getPtr() const {
+ return mData;
+ }
+protected:
+ void growSize();
+ uint8_t * mData;
+ uint64_t mLength;
+ uint64_t mPos;
+ bool mUse64;
+};
+
+
+} // renderscript
+} // android
+#endif //ANDROID_RS_STREAM_H
+
+
diff --git a/libs/rs/rsType.cpp b/libs/rs/rsType.cpp
index c09e979..75abc76 100644
--- a/libs/rs/rsType.cpp
+++ b/libs/rs/rsType.cpp
@@ -14,8 +14,13 @@
* limitations under the License.
*/
+#ifndef ANDROID_RS_BUILD_FOR_HOST
#include "rsContext.h"
#include <GLES/gl.h>
+#else
+#include "rsContextHostStub.h"
+#include <OpenGL/gl.h>
+#endif
using namespace android;
using namespace android::renderscript;
@@ -143,131 +148,22 @@
for (uint32_t ct=0; ct < getElement()->getFieldCount(); ct++) {
const Component &c = getElement()->getField(ct)->getComponent();
- switch(c.getKind()) {
- case RS_KIND_USER:
- mGL.mUser[userNum].size = c.getVectorSize();
- mGL.mUser[userNum].offset = mElement->getFieldOffsetBytes(ct);
- mGL.mUser[userNum].type = c.getGLType();
- mGL.mUser[userNum].normalized = c.getType() != RS_TYPE_FLOAT_32;//c.getIsNormalized();
- mGL.mUser[userNum].name.setTo(getElement()->getFieldName(ct));
- userNum ++;
- break;
-
- case RS_KIND_POSITION:
- rsAssert(mGL.mVtx.size == 0);
- mGL.mVtx.size = c.getVectorSize();
- mGL.mVtx.offset = mElement->getFieldOffsetBytes(ct);
- mGL.mVtx.type = c.getGLType();
- mGL.mVtx.normalized = false;
- mGL.mVtx.name.setTo("Position");
- break;
-
- case RS_KIND_COLOR:
- rsAssert(mGL.mColor.size == 0);
- mGL.mColor.size = c.getVectorSize();
- mGL.mColor.offset = mElement->getFieldOffsetBytes(ct);
- mGL.mColor.type = c.getGLType();
- mGL.mColor.normalized = c.getType() != RS_TYPE_FLOAT_32;
- mGL.mColor.name.setTo("Color");
- break;
-
- case RS_KIND_NORMAL:
- rsAssert(mGL.mNorm.size == 0);
- mGL.mNorm.size = c.getVectorSize();
- mGL.mNorm.offset = mElement->getFieldOffsetBytes(ct);
- mGL.mNorm.type = c.getGLType();
- mGL.mNorm.normalized = false;
- mGL.mNorm.name.setTo("Normal");
- break;
-
- case RS_KIND_TEXTURE:
- rsAssert(mGL.mTex.size == 0);
- mGL.mTex.size = c.getVectorSize();
- mGL.mTex.offset = mElement->getFieldOffsetBytes(ct);
- mGL.mTex.type = c.getGLType();
- mGL.mTex.normalized = false;
- mGL.mTex.name.setTo("Texture");
- break;
-
- case RS_KIND_POINT_SIZE:
- rsAssert(!mGL.mPointSize.size);
- mGL.mPointSize.size = c.getVectorSize();
- mGL.mPointSize.offset = mElement->getFieldOffsetBytes(ct);
- mGL.mPointSize.type = c.getGLType();
- mGL.mPointSize.normalized = false;
- mGL.mPointSize.name.setTo("PointSize");
- break;
-
- default:
- break;
- }
+ mAttribs[userNum].size = c.getVectorSize();
+ mAttribs[userNum].offset = mElement->getFieldOffsetBytes(ct);
+ mAttribs[userNum].type = c.getGLType();
+ mAttribs[userNum].normalized = c.getType() != RS_TYPE_FLOAT_32;//c.getIsNormalized();
+ mAttribs[userNum].name.setTo(getElement()->getFieldName(ct));
+ userNum ++;
}
}
+
void Type::enableGLVertexBuffer(VertexArray *va) const
{
- // Note: We are only going to enable buffers and never disable them
- // here. The reason is more than one Allocation may be used as a vertex
- // source. So we cannot disable arrays that may have been in use by
- // another allocation.
-
- uint32_t stride = mElement->getSizeBytes();
- if (mGL.mVtx.size) {
- va->addLegacy(mGL.mVtx.type,
- mGL.mVtx.size,
- stride,
- RS_KIND_POSITION,
- false,
- mGL.mVtx.offset);
- }
-
- if (mGL.mNorm.size) {
- va->addLegacy(mGL.mNorm.type,
- 3,
- stride,
- RS_KIND_NORMAL,
- false,
- mGL.mNorm.offset);
- }
-
- if (mGL.mColor.size) {
- va->addLegacy(mGL.mColor.type,
- mGL.mColor.size,
- stride,
- RS_KIND_COLOR,
- true,
- mGL.mColor.offset);
- }
-
- if (mGL.mTex.size) {
- va->addLegacy(mGL.mTex.type,
- mGL.mTex.size,
- stride,
- RS_KIND_TEXTURE,
- false,
- mGL.mTex.offset);
- }
-
- if (mGL.mPointSize.size) {
- va->addLegacy(mGL.mPointSize.type,
- 1,
- stride,
- RS_KIND_POINT_SIZE,
- false,
- mGL.mPointSize.offset);
- }
-
-}
-
-void Type::enableGLVertexBuffer2(VertexArray *va) const
-{
- // Do legacy buffers
- enableGLVertexBuffer(va);
-
uint32_t stride = mElement->getSizeBytes();
for (uint32_t ct=0; ct < RS_MAX_ATTRIBS; ct++) {
- if (mGL.mUser[ct].size) {
- va->addUser(mGL.mUser[ct], stride);
+ if (mAttribs[ct].size) {
+ va->add(mAttribs[ct], stride);
}
}
}
@@ -283,6 +179,57 @@
mElement->dumpLOGV(buf);
}
+void Type::serialize(OStream *stream) const
+{
+ // Need to identify ourselves
+ stream->addU32((uint32_t)getClassId());
+
+ String8 name(getName());
+ stream->addString(&name);
+
+ mElement->serialize(stream);
+
+ stream->addU32(mDimX);
+ stream->addU32(mDimY);
+ stream->addU32(mDimZ);
+
+ stream->addU8((uint8_t)(mDimLOD ? 1 : 0));
+ stream->addU8((uint8_t)(mFaces ? 1 : 0));
+}
+
+Type *Type::createFromStream(Context *rsc, IStream *stream)
+{
+ // First make sure we are reading the correct object
+ RsA3DClassID classID = (RsA3DClassID)stream->loadU32();
+ if(classID != RS_A3D_CLASS_ID_TYPE) {
+ LOGE("type loading skipped due to invalid class id\n");
+ return NULL;
+ }
+
+ String8 name;
+ stream->loadString(&name);
+
+ Element *elem = Element::createFromStream(rsc, stream);
+ if(!elem) {
+ return NULL;
+ }
+
+ Type *type = new Type(rsc);
+ type->mDimX = stream->loadU32();
+ type->mDimY = stream->loadU32();
+ type->mDimZ = stream->loadU32();
+
+ uint8_t temp = stream->loadU8();
+ type->mDimLOD = temp != 0;
+
+ temp = stream->loadU8();
+ type->mFaces = temp != 0;
+
+ type->setElement(elem);
+
+ return type;
+}
+
bool Type::getIsNp2() const
{
uint32_t x = getDimX();
diff --git a/libs/rs/rsType.h b/libs/rs/rsType.h
index c25577c..5b51e20 100644
--- a/libs/rs/rsType.h
+++ b/libs/rs/rsType.h
@@ -71,9 +71,11 @@
void compute();
void enableGLVertexBuffer(class VertexArray *) const;
- void enableGLVertexBuffer2(class VertexArray *) const;
void dumpLOGV(const char *prefix) const;
+ virtual void serialize(OStream *stream) const;
+ virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_TYPE; }
+ static Type *createFromStream(Context *rsc, IStream *stream);
protected:
struct LOD {
@@ -112,15 +114,7 @@
LOD *mLODs;
uint32_t mLODCount;
- struct GLState_t {
- VertexArray::Attrib mUser[RS_MAX_ATTRIBS];
- VertexArray::Attrib mVtx;
- VertexArray::Attrib mNorm;
- VertexArray::Attrib mColor;
- VertexArray::Attrib mTex;
- VertexArray::Attrib mPointSize;
- };
- GLState_t mGL;
+ VertexArray::Attrib mAttribs[RS_MAX_ATTRIBS];
void makeGLComponents();
private:
diff --git a/libs/rs/rsUtils.h b/libs/rs/rsUtils.h
index 07f8933..b0eb520 100644
--- a/libs/rs/rsUtils.h
+++ b/libs/rs/rsUtils.h
@@ -19,15 +19,22 @@
#define LOG_NDEBUG 0
#define LOG_TAG "RenderScript"
+
#include <utils/Log.h>
-#include <utils/Vector.h>
-#include <utils/KeyedVector.h>
+
+#include "rsStream.h"
+
#include <utils/String8.h>
+#include <utils/Vector.h>
+
#include <stdlib.h>
#include <pthread.h>
#include <time.h>
+#ifndef ANDROID_RS_BUILD_FOR_HOST
#include <EGL/egl.h>
+#endif
+
#include <math.h>
#include "RenderScript.h"
@@ -41,6 +48,38 @@
#define rsAssert(v) while(0)
#endif
+typedef float rsvF_2 __attribute__ ((vector_size (8)));
+typedef float rsvF_4 __attribute__ ((vector_size (16)));
+typedef float rsvF_8 __attribute__ ((vector_size (32)));
+typedef float rsvF_16 __attribute__ ((vector_size (64)));
+typedef uint8_t rsvU8_4 __attribute__ ((vector_size (4)));
+
+union float2 {
+ rsvF_2 v;
+ float f[2];
+};
+
+union float4 {
+ rsvF_4 v;
+ float f[4];
+};
+
+union float8 {
+ rsvF_8 v;
+ float f[8];
+};
+
+union float16 {
+ rsvF_16 v;
+ float f[16];
+};
+
+union uchar4 {
+ rsvU8_4 v;
+ uint8_t f[4];
+ uint32_t packed;
+};
+
template<typename T>
T rsMin(T in1, T in2)
{
diff --git a/libs/rs/rsVertexArray.cpp b/libs/rs/rsVertexArray.cpp
index 6c2002d..6f15db0 100644
--- a/libs/rs/rsVertexArray.cpp
+++ b/libs/rs/rsVertexArray.cpp
@@ -14,10 +14,15 @@
* limitations under the License.
*/
+#ifndef ANDROID_RS_BUILD_FOR_HOST
#include "rsContext.h"
-
#include <GLES/gl.h>
#include <GLES2/gl2.h>
+#else
+#include "rsContextHostStub.h"
+#include <OpenGL/gl.h>
+#endif
+
using namespace android;
using namespace android::renderscript;
@@ -55,7 +60,6 @@
size = a.size;
stride = a.stride;
normalized = a.normalized;
- kind = RS_KIND_USER;
name.setTo(a.name);
}
@@ -75,19 +79,18 @@
mAttribs[n].clear();
}
-void VertexArray::addUser(const Attrib &a, uint32_t stride)
+void VertexArray::add(const Attrib &a, uint32_t stride)
{
- assert(mCount < RS_MAX_ATTRIBS);
+ rsAssert(mCount < RS_MAX_ATTRIBS);
mAttribs[mCount].set(a);
mAttribs[mCount].buffer = mActiveBuffer;
mAttribs[mCount].stride = stride;
- mAttribs[mCount].kind = RS_KIND_USER;
mCount ++;
}
-void VertexArray::addLegacy(uint32_t type, uint32_t size, uint32_t stride, RsDataKind kind, bool normalized, uint32_t offset)
+void VertexArray::add(uint32_t type, uint32_t size, uint32_t stride, bool normalized, uint32_t offset, const char *name)
{
- assert(mCount < RS_MAX_ATTRIBS);
+ rsAssert(mCount < RS_MAX_ATTRIBS);
mAttribs[mCount].clear();
mAttribs[mCount].type = type;
mAttribs[mCount].size = size;
@@ -95,93 +98,25 @@
mAttribs[mCount].normalized = normalized;
mAttribs[mCount].buffer = mActiveBuffer;
mAttribs[mCount].stride = stride;
- mAttribs[mCount].kind = kind;
+ mAttribs[mCount].name.setTo(name);
mCount ++;
}
void VertexArray::logAttrib(uint32_t idx, uint32_t slot) const {
- LOGE("va %i: slot=%i name=%s buf=%i size=%i type=0x%x kind=%i stride=0x%x norm=%i offset=0x%x", idx, slot,
+ LOGE("va %i: slot=%i name=%s buf=%i size=%i type=0x%x stride=0x%x norm=%i offset=0x%x", idx, slot,
mAttribs[idx].name.string(),
mAttribs[idx].buffer,
mAttribs[idx].size,
mAttribs[idx].type,
- mAttribs[idx].kind,
mAttribs[idx].stride,
mAttribs[idx].normalized,
mAttribs[idx].offset);
}
-void VertexArray::setupGL(const Context *rsc, class VertexArrayState *state) const
-{
- glClientActiveTexture(GL_TEXTURE0);
- glDisableClientState(GL_NORMAL_ARRAY);
- glDisableClientState(GL_COLOR_ARRAY);
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- glDisableClientState(GL_POINT_SIZE_ARRAY_OES);
-
- for (uint32_t ct=0; ct < mCount; ct++) {
- switch(mAttribs[ct].kind) {
- case RS_KIND_POSITION:
- //logAttrib(POSITION);
- glEnableClientState(GL_VERTEX_ARRAY);
- glBindBuffer(GL_ARRAY_BUFFER, mAttribs[ct].buffer);
- glVertexPointer(mAttribs[ct].size,
- mAttribs[ct].type,
- mAttribs[ct].stride,
- (void *)mAttribs[ct].offset);
- break;
-
- case RS_KIND_NORMAL:
- //logAttrib(NORMAL);
- glEnableClientState(GL_NORMAL_ARRAY);
- rsAssert(mAttribs[ct].size == 3);
- glBindBuffer(GL_ARRAY_BUFFER, mAttribs[ct].buffer);
- glNormalPointer(mAttribs[ct].type,
- mAttribs[ct].stride,
- (void *)mAttribs[ct].offset);
- break;
-
- case RS_KIND_COLOR:
- //logAttrib(COLOR);
- glEnableClientState(GL_COLOR_ARRAY);
- glBindBuffer(GL_ARRAY_BUFFER, mAttribs[ct].buffer);
- glColorPointer(mAttribs[ct].size,
- mAttribs[ct].type,
- mAttribs[ct].stride,
- (void *)mAttribs[ct].offset);
- break;
-
- case RS_KIND_TEXTURE:
- //logAttrib(TEXTURE);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glBindBuffer(GL_ARRAY_BUFFER, mAttribs[ct].buffer);
- glTexCoordPointer(mAttribs[ct].size,
- mAttribs[ct].type,
- mAttribs[ct].stride,
- (void *)mAttribs[ct].offset);
- break;
-
- case RS_KIND_POINT_SIZE:
- //logAttrib(POINT_SIZE);
- glEnableClientState(GL_POINT_SIZE_ARRAY_OES);
- glBindBuffer(GL_ARRAY_BUFFER, mAttribs[ct].buffer);
- glPointSizePointerOES(mAttribs[ct].type,
- mAttribs[ct].stride,
- (void *)mAttribs[ct].offset);
- break;
-
- default:
- rsAssert(0);
- }
- }
-
- rsc->checkError("VertexArray::setupGL");
-}
-
void VertexArray::setupGL2(const Context *rsc, class VertexArrayState *state, ShaderCache *sc) const
{
rsc->checkError("VertexArray::setupGL2 start");
- for (uint32_t ct=1; ct <= state->mLastEnableCount; ct++) {
+ for (uint32_t ct=1; ct <= 0xf/*state->mLastEnableCount*/; ct++) {
glDisableVertexAttribArray(ct);
}
@@ -191,16 +126,24 @@
if (sc->isUserVertexProgram()) {
slot = sc->vtxAttribSlot(ct);
} else {
- if (mAttribs[ct].kind == RS_KIND_USER) {
+ if (mAttribs[ct].name == "position") {
+ slot = 0;
+ } else if (mAttribs[ct].name == "color") {
+ slot = 1;
+ } else if (mAttribs[ct].name == "normal") {
+ slot = 2;
+ } else if (mAttribs[ct].name == "pointSize") {
+ slot = 3;
+ } else if (mAttribs[ct].name == "texture0") {
+ slot = 4;
+ } else {
continue;
}
- slot = sc->vtxAttribSlot(mAttribs[ct].kind);
}
//logAttrib(ct, slot);
glEnableVertexAttribArray(slot);
glBindBuffer(GL_ARRAY_BUFFER, mAttribs[ct].buffer);
-
glVertexAttribPointer(slot,
mAttribs[ct].size,
mAttribs[ct].type,
diff --git a/libs/rs/rsVertexArray.h b/libs/rs/rsVertexArray.h
index 3904cb6..e5b51d7 100644
--- a/libs/rs/rsVertexArray.h
+++ b/libs/rs/rsVertexArray.h
@@ -43,7 +43,6 @@
uint32_t stride;
bool normalized;
String8 name;
- RsDataKind kind;
Attrib();
void set(const Attrib &);
@@ -53,8 +52,9 @@
void clearAll();
void setActiveBuffer(uint32_t id) {mActiveBuffer = id;}
- void addUser(const Attrib &, uint32_t stride);
- void addLegacy(uint32_t type, uint32_t size, uint32_t stride, RsDataKind kind, bool normalized, uint32_t offset);
+ void add(const Attrib &, uint32_t stride);
+ //void addLegacy(uint32_t type, uint32_t size, uint32_t stride, bool normalized, uint32_t offset);
+ void add(uint32_t type, uint32_t size, uint32_t stride, bool normalized, uint32_t offset, const char *name);
void setupGL(const Context *rsc, class VertexArrayState *) const;
void setupGL2(const Context *rsc, class VertexArrayState *, ShaderCache *) const;
diff --git a/libs/rs/rsg_ScriptJavaClass.cpp b/libs/rs/rsg_ScriptJavaClass.cpp
index cee9f52..0169b98 100644
--- a/libs/rs/rsg_ScriptJavaClass.cpp
+++ b/libs/rs/rsg_ScriptJavaClass.cpp
@@ -7,8 +7,12 @@
struct Element;
struct ElementField {
+ // An Element Field is a combination of an Element with a name assigned.
+
const char *name;
Element *e;
+
+
ElementField(const char *n, Element *_e) {
name = n;
e = _e;
@@ -20,12 +24,21 @@
};
struct Element {
+ // An Element can take one of two forms.
+ // 1: Basic. It contains a single basic type and vector size.
+ // 2: Complex. It contains a list of fields with names. Each field
+ // will in turn be another element.
+
ElementField *fields;
- size_t fieldCount;
+ size_t fieldCount; // If field count is 0, the element is a Basic type.
const char *name;
bool generated;
+ // The basic data type from RenderScript.h
RsDataType compType;
+
+ // The vector size of the data type for float2, float3, ....
+ // Allowed sizes are 2,3,4,8,16
uint32_t compVectorSize;
Element() {
diff --git a/libs/rs/scriptc/rs_cl.rsh b/libs/rs/scriptc/rs_cl.rsh
new file mode 100644
index 0000000..6d578db
--- /dev/null
+++ b/libs/rs/scriptc/rs_cl.rsh
@@ -0,0 +1,620 @@
+// Float ops, 6.11.2
+
+extern float __attribute__((overloadable)) acos(float);
+extern float2 __attribute__((overloadable)) acos(float2);
+extern float3 __attribute__((overloadable)) acos(float3);
+extern float4 __attribute__((overloadable)) acos(float4);
+extern float8 __attribute__((overloadable)) acos(float8);
+extern float16 __attribute__((overloadable)) acos(float16);
+
+extern float __attribute__((overloadable)) acosh(float);
+extern float2 __attribute__((overloadable)) acosh(float2);
+extern float3 __attribute__((overloadable)) acosh(float3);
+extern float4 __attribute__((overloadable)) acosh(float4);
+extern float8 __attribute__((overloadable)) acosh(float8);
+extern float16 __attribute__((overloadable)) acosh(float16);
+
+extern float __attribute__((overloadable)) acospi(float);
+extern float2 __attribute__((overloadable)) acospi(float2);
+extern float3 __attribute__((overloadable)) acospi(float3);
+extern float4 __attribute__((overloadable)) acospi(float4);
+extern float8 __attribute__((overloadable)) acospi(float8);
+extern float16 __attribute__((overloadable)) acospi(float16);
+
+extern float __attribute__((overloadable)) asin(float);
+extern float2 __attribute__((overloadable)) asin(float2);
+extern float3 __attribute__((overloadable)) asin(float3);
+extern float4 __attribute__((overloadable)) asin(float4);
+extern float8 __attribute__((overloadable)) asin(float8);
+extern float16 __attribute__((overloadable)) asin(float16);
+
+extern float __attribute__((overloadable)) asinh(float);
+extern float2 __attribute__((overloadable)) asinh(float2);
+extern float3 __attribute__((overloadable)) asinh(float3);
+extern float4 __attribute__((overloadable)) asinh(float4);
+extern float8 __attribute__((overloadable)) asinh(float8);
+extern float16 __attribute__((overloadable)) asinh(float16);
+
+extern float __attribute__((overloadable)) asinpi(float);
+extern float2 __attribute__((overloadable)) asinpi(float2);
+extern float3 __attribute__((overloadable)) asinpi(float3);
+extern float4 __attribute__((overloadable)) asinpi(float4);
+extern float8 __attribute__((overloadable)) asinpi(float8);
+extern float16 __attribute__((overloadable)) asinpi(float16);
+
+extern float __attribute__((overloadable)) atan(float);
+extern float2 __attribute__((overloadable)) atan(float2);
+extern float3 __attribute__((overloadable)) atan(float3);
+extern float4 __attribute__((overloadable)) atan(float4);
+extern float8 __attribute__((overloadable)) atan(float8);
+extern float16 __attribute__((overloadable)) atan(float16);
+
+extern float __attribute__((overloadable)) atan2(float, float);
+extern float2 __attribute__((overloadable)) atan2(float2, float2);
+extern float3 __attribute__((overloadable)) atan2(float3, float3);
+extern float4 __attribute__((overloadable)) atan2(float4, float4);
+extern float8 __attribute__((overloadable)) atan2(float8, float8);
+extern float16 __attribute__((overloadable)) atan2(float16, float16);
+
+extern float __attribute__((overloadable)) atanh(float);
+extern float2 __attribute__((overloadable)) atanh(float2);
+extern float3 __attribute__((overloadable)) atanh(float3);
+extern float4 __attribute__((overloadable)) atanh(float4);
+extern float8 __attribute__((overloadable)) atanh(float8);
+extern float16 __attribute__((overloadable)) atanh(float16);
+
+extern float __attribute__((overloadable)) atanpi(float);
+extern float2 __attribute__((overloadable)) atanpi(float2);
+extern float3 __attribute__((overloadable)) atanpi(float3);
+extern float4 __attribute__((overloadable)) atanpi(float4);
+extern float8 __attribute__((overloadable)) atanpi(float8);
+extern float16 __attribute__((overloadable)) atanpi(float16);
+
+extern float __attribute__((overloadable)) atan2pi(float, float);
+extern float2 __attribute__((overloadable)) atan2pi(float2, float2);
+extern float3 __attribute__((overloadable)) atan2pi(float3, float3);
+extern float4 __attribute__((overloadable)) atan2pi(float4, float4);
+extern float8 __attribute__((overloadable)) atan2pi(float8, float8);
+extern float16 __attribute__((overloadable)) atan2pi(float16, float16);
+
+extern float __attribute__((overloadable)) cbrt(float);
+extern float2 __attribute__((overloadable)) cbrt(float2);
+extern float3 __attribute__((overloadable)) cbrt(float3);
+extern float4 __attribute__((overloadable)) cbrt(float4);
+extern float8 __attribute__((overloadable)) cbrt(float8);
+extern float16 __attribute__((overloadable)) cbrt(float16);
+
+extern float __attribute__((overloadable)) ceil(float);
+extern float2 __attribute__((overloadable)) ceil(float2);
+extern float3 __attribute__((overloadable)) ceil(float3);
+extern float4 __attribute__((overloadable)) ceil(float4);
+extern float8 __attribute__((overloadable)) ceil(float8);
+extern float16 __attribute__((overloadable)) ceil(float16);
+
+extern float __attribute__((overloadable)) copysign(float, float);
+extern float2 __attribute__((overloadable)) copysign(float2, float2);
+extern float3 __attribute__((overloadable)) copysign(float3, float3);
+extern float4 __attribute__((overloadable)) copysign(float4, float4);
+extern float8 __attribute__((overloadable)) copysign(float8, float8);
+extern float16 __attribute__((overloadable)) copysign(float16, float16);
+
+extern float __attribute__((overloadable)) cos(float);
+extern float2 __attribute__((overloadable)) cos(float2);
+extern float3 __attribute__((overloadable)) cos(float3);
+extern float4 __attribute__((overloadable)) cos(float4);
+extern float8 __attribute__((overloadable)) cos(float8);
+extern float16 __attribute__((overloadable)) cos(float16);
+
+extern float __attribute__((overloadable)) cosh(float);
+extern float2 __attribute__((overloadable)) cosh(float2);
+extern float3 __attribute__((overloadable)) cosh(float3);
+extern float4 __attribute__((overloadable)) cosh(float4);
+extern float8 __attribute__((overloadable)) cosh(float8);
+extern float16 __attribute__((overloadable)) cosh(float16);
+
+extern float __attribute__((overloadable)) cospi(float);
+extern float2 __attribute__((overloadable)) cospi(float2);
+extern float3 __attribute__((overloadable)) cospi(float3);
+extern float4 __attribute__((overloadable)) cospi(float4);
+extern float8 __attribute__((overloadable)) cospi(float8);
+extern float16 __attribute__((overloadable)) cospi(float16);
+
+extern float __attribute__((overloadable)) erfc(float);
+extern float2 __attribute__((overloadable)) erfc(float2);
+extern float3 __attribute__((overloadable)) erfc(float3);
+extern float4 __attribute__((overloadable)) erfc(float4);
+extern float8 __attribute__((overloadable)) erfc(float8);
+extern float16 __attribute__((overloadable)) erfc(float16);
+
+extern float __attribute__((overloadable)) erf(float);
+extern float2 __attribute__((overloadable)) erf(float2);
+extern float3 __attribute__((overloadable)) erf(float3);
+extern float4 __attribute__((overloadable)) erf(float4);
+extern float8 __attribute__((overloadable)) erf(float8);
+extern float16 __attribute__((overloadable)) erf(float16);
+
+extern float __attribute__((overloadable)) exp(float);
+extern float2 __attribute__((overloadable)) exp(float2);
+extern float3 __attribute__((overloadable)) exp(float3);
+extern float4 __attribute__((overloadable)) exp(float4);
+extern float8 __attribute__((overloadable)) exp(float8);
+extern float16 __attribute__((overloadable)) exp(float16);
+
+extern float __attribute__((overloadable)) exp2(float);
+extern float2 __attribute__((overloadable)) exp2(float2);
+extern float3 __attribute__((overloadable)) exp2(float3);
+extern float4 __attribute__((overloadable)) exp2(float4);
+extern float8 __attribute__((overloadable)) exp2(float8);
+extern float16 __attribute__((overloadable)) exp2(float16);
+
+extern float __attribute__((overloadable)) exp10(float);
+extern float2 __attribute__((overloadable)) exp10(float2);
+extern float3 __attribute__((overloadable)) exp10(float3);
+extern float4 __attribute__((overloadable)) exp10(float4);
+extern float8 __attribute__((overloadable)) exp10(float8);
+extern float16 __attribute__((overloadable)) exp10(float16);
+
+extern float __attribute__((overloadable)) expm1(float);
+extern float2 __attribute__((overloadable)) expm1(float2);
+extern float3 __attribute__((overloadable)) expm1(float3);
+extern float4 __attribute__((overloadable)) expm1(float4);
+extern float8 __attribute__((overloadable)) expm1(float8);
+extern float16 __attribute__((overloadable)) expm1(float16);
+
+extern float __attribute__((overloadable)) fabs(float);
+extern float2 __attribute__((overloadable)) fabs(float2);
+extern float3 __attribute__((overloadable)) fabs(float3);
+extern float4 __attribute__((overloadable)) fabs(float4);
+extern float8 __attribute__((overloadable)) fabs(float8);
+extern float16 __attribute__((overloadable)) fabs(float16);
+
+extern float __attribute__((overloadable)) fdim(float, float);
+extern float2 __attribute__((overloadable)) fdim(float2, float2);
+extern float3 __attribute__((overloadable)) fdim(float3, float3);
+extern float4 __attribute__((overloadable)) fdim(float4, float4);
+extern float8 __attribute__((overloadable)) fdim(float8, float8);
+extern float16 __attribute__((overloadable)) fdim(float16, float16);
+
+extern float __attribute__((overloadable)) floor(float);
+extern float2 __attribute__((overloadable)) floor(float2);
+extern float3 __attribute__((overloadable)) floor(float3);
+extern float4 __attribute__((overloadable)) floor(float4);
+extern float8 __attribute__((overloadable)) floor(float8);
+extern float16 __attribute__((overloadable)) floor(float16);
+
+extern float __attribute__((overloadable)) fma(float, float, float);
+extern float2 __attribute__((overloadable)) fma(float2, float2, float2);
+extern float3 __attribute__((overloadable)) fma(float3, float3, float3);
+extern float4 __attribute__((overloadable)) fma(float4, float4, float4);
+extern float8 __attribute__((overloadable)) fma(float8, float8, float8);
+extern float16 __attribute__((overloadable)) fma(float16, float16, float16);
+
+extern float __attribute__((overloadable)) fmax(float, float);
+extern float2 __attribute__((overloadable)) fmax(float2, float2);
+extern float3 __attribute__((overloadable)) fmax(float3, float3);
+extern float4 __attribute__((overloadable)) fmax(float4, float4);
+extern float8 __attribute__((overloadable)) fmax(float8, float8);
+extern float16 __attribute__((overloadable)) fmax(float16, float16);
+extern float2 __attribute__((overloadable)) fmax(float2, float);
+extern float3 __attribute__((overloadable)) fmax(float3, float);
+extern float4 __attribute__((overloadable)) fmax(float4, float);
+extern float8 __attribute__((overloadable)) fmax(float8, float);
+extern float16 __attribute__((overloadable)) fmax(float16, float);
+
+extern float __attribute__((overloadable)) fmin(float, float);
+extern float2 __attribute__((overloadable)) fmin(float2, float2);
+extern float3 __attribute__((overloadable)) fmin(float3, float3);
+extern float4 __attribute__((overloadable)) fmin(float4, float4);
+extern float8 __attribute__((overloadable)) fmin(float8, float8);
+extern float16 __attribute__((overloadable)) fmin(float16, float16);
+extern float2 __attribute__((overloadable)) fmin(float2, float);
+extern float3 __attribute__((overloadable)) fmin(float3, float);
+extern float4 __attribute__((overloadable)) fmin(float4, float);
+extern float8 __attribute__((overloadable)) fmin(float8, float);
+extern float16 __attribute__((overloadable)) fmin(float16, float);
+
+extern float __attribute__((overloadable)) fmod(float, float);
+extern float2 __attribute__((overloadable)) fmod(float2, float2);
+extern float3 __attribute__((overloadable)) fmod(float3, float3);
+extern float4 __attribute__((overloadable)) fmod(float4, float4);
+extern float8 __attribute__((overloadable)) fmod(float8, float8);
+extern float16 __attribute__((overloadable)) fmod(float16, float16);
+
+extern float __attribute__((overloadable)) fract(float, float *);
+extern float2 __attribute__((overloadable)) fract(float2, float2 *);
+extern float3 __attribute__((overloadable)) fract(float3, float3 *);
+extern float4 __attribute__((overloadable)) fract(float4, float4 *);
+extern float8 __attribute__((overloadable)) fract(float8, float8 *);
+extern float16 __attribute__((overloadable)) fract(float16, float16 *);
+
+extern float __attribute__((overloadable)) frexp(float, float *);
+extern float2 __attribute__((overloadable)) frexp(float2, float2 *);
+extern float3 __attribute__((overloadable)) frexp(float3, float3 *);
+extern float4 __attribute__((overloadable)) frexp(float4, float4 *);
+extern float8 __attribute__((overloadable)) frexp(float8, float8 *);
+extern float16 __attribute__((overloadable)) frexp(float16, float16 *);
+
+extern float __attribute__((overloadable)) hypot(float, float);
+extern float2 __attribute__((overloadable)) hypot(float2, float2);
+extern float3 __attribute__((overloadable)) hypot(float3, float3);
+extern float4 __attribute__((overloadable)) hypot(float4, float4);
+extern float8 __attribute__((overloadable)) hypot(float8, float8);
+extern float16 __attribute__((overloadable)) hypot(float16, float16);
+
+extern int __attribute__((overloadable)) ilogb(float);
+extern int2 __attribute__((overloadable)) ilogb(float2);
+extern int3 __attribute__((overloadable)) ilogb(float3);
+extern int4 __attribute__((overloadable)) ilogb(float4);
+extern int8 __attribute__((overloadable)) ilogb(float8);
+extern int16 __attribute__((overloadable)) ilogb(float16);
+
+extern float __attribute__((overloadable)) ldexp(float, int);
+extern float2 __attribute__((overloadable)) ldexp(float2, int2);
+extern float3 __attribute__((overloadable)) ldexp(float3, int3);
+extern float4 __attribute__((overloadable)) ldexp(float4, int4);
+extern float8 __attribute__((overloadable)) ldexp(float8, int8);
+extern float16 __attribute__((overloadable)) ldexp(float16, int16);
+extern float2 __attribute__((overloadable)) ldexp(float2, int);
+extern float3 __attribute__((overloadable)) ldexp(float3, int);
+extern float4 __attribute__((overloadable)) ldexp(float4, int);
+extern float8 __attribute__((overloadable)) ldexp(float8, int);
+extern float16 __attribute__((overloadable)) ldexp(float16, int);
+
+extern float __attribute__((overloadable)) lgamma(float);
+extern float2 __attribute__((overloadable)) lgamma(float2);
+extern float3 __attribute__((overloadable)) lgamma(float3);
+extern float4 __attribute__((overloadable)) lgamma(float4);
+extern float8 __attribute__((overloadable)) lgamma(float8);
+extern float16 __attribute__((overloadable)) lgamma(float16);
+extern float __attribute__((overloadable)) lgamma(float, float *);
+extern float2 __attribute__((overloadable)) lgamma(float2, float2 *);
+extern float3 __attribute__((overloadable)) lgamma(float3, float3 *);
+extern float4 __attribute__((overloadable)) lgamma(float4, float4 *);
+extern float8 __attribute__((overloadable)) lgamma(float8, float8 *);
+extern float16 __attribute__((overloadable)) lgamma(float16, float16 *);
+
+extern float __attribute__((overloadable)) log(float);
+extern float2 __attribute__((overloadable)) log(float2);
+extern float3 __attribute__((overloadable)) log(float3);
+extern float4 __attribute__((overloadable)) log(float4);
+extern float8 __attribute__((overloadable)) log(float8);
+extern float16 __attribute__((overloadable)) log(float16);
+
+extern float __attribute__((overloadable)) log2(float);
+extern float2 __attribute__((overloadable)) log2(float2);
+extern float3 __attribute__((overloadable)) log2(float3);
+extern float4 __attribute__((overloadable)) log2(float4);
+extern float8 __attribute__((overloadable)) log2(float8);
+extern float16 __attribute__((overloadable)) log2(float16);
+
+extern float __attribute__((overloadable)) log10(float);
+extern float2 __attribute__((overloadable)) log10(float2);
+extern float3 __attribute__((overloadable)) log10(float3);
+extern float4 __attribute__((overloadable)) log10(float4);
+extern float8 __attribute__((overloadable)) log10(float8);
+extern float16 __attribute__((overloadable)) log10(float16);
+
+extern float __attribute__((overloadable)) log1p(float);
+extern float2 __attribute__((overloadable)) log1p(float2);
+extern float3 __attribute__((overloadable)) log1p(float3);
+extern float4 __attribute__((overloadable)) log1p(float4);
+extern float8 __attribute__((overloadable)) log1p(float8);
+extern float16 __attribute__((overloadable)) log1p(float16);
+
+extern float __attribute__((overloadable)) logb(float);
+extern float2 __attribute__((overloadable)) logb(float2);
+extern float3 __attribute__((overloadable)) logb(float3);
+extern float4 __attribute__((overloadable)) logb(float4);
+extern float8 __attribute__((overloadable)) logb(float8);
+extern float16 __attribute__((overloadable)) logb(float16);
+
+extern float __attribute__((overloadable)) mad(float, float, float);
+extern float2 __attribute__((overloadable)) mad(float2, float2, float2);
+extern float3 __attribute__((overloadable)) mad(float3, float3, float3);
+extern float4 __attribute__((overloadable)) mad(float4, float4, float4);
+extern float8 __attribute__((overloadable)) mad(float8, float8, float8);
+extern float16 __attribute__((overloadable)) mad(float16, float16, float16);
+
+extern float __attribute__((overloadable)) modf(float, float *);
+extern float2 __attribute__((overloadable)) modf(float2, float2 *);
+extern float3 __attribute__((overloadable)) modf(float3, float3 *);
+extern float4 __attribute__((overloadable)) modf(float4, float4 *);
+extern float8 __attribute__((overloadable)) modf(float8, float8 *);
+extern float16 __attribute__((overloadable)) modf(float16, float16 *);
+
+extern float __attribute__((overloadable)) nan(uint);
+extern float2 __attribute__((overloadable)) nan(uint2);
+extern float3 __attribute__((overloadable)) nan(uint3);
+extern float4 __attribute__((overloadable)) nan(uint4);
+extern float8 __attribute__((overloadable)) nan(uint8);
+extern float16 __attribute__((overloadable)) nan(uint16);
+
+extern float __attribute__((overloadable)) nextafter(float, float);
+extern float2 __attribute__((overloadable)) nextafter(float2, float2);
+extern float3 __attribute__((overloadable)) nextafter(float3, float3);
+extern float4 __attribute__((overloadable)) nextafter(float4, float4);
+extern float8 __attribute__((overloadable)) nextafter(float8, float8);
+extern float16 __attribute__((overloadable)) nextafter(float16, float16);
+
+extern float __attribute__((overloadable)) pow(float, float);
+extern float2 __attribute__((overloadable)) pow(float2, float2);
+extern float3 __attribute__((overloadable)) pow(float3, float3);
+extern float4 __attribute__((overloadable)) pow(float4, float4);
+extern float8 __attribute__((overloadable)) pow(float8, float8);
+extern float16 __attribute__((overloadable)) pow(float16, float16);
+
+extern float __attribute__((overloadable)) pown(float, int);
+extern float2 __attribute__((overloadable)) pown(float2, int2);
+extern float3 __attribute__((overloadable)) pown(float3, int3);
+extern float4 __attribute__((overloadable)) pown(float4, int4);
+extern float8 __attribute__((overloadable)) pown(float8, int8);
+extern float16 __attribute__((overloadable)) pown(float16, int16);
+
+extern float __attribute__((overloadable)) powr(float, float);
+extern float2 __attribute__((overloadable)) powr(float2, float2);
+extern float3 __attribute__((overloadable)) powr(float3, float3);
+extern float4 __attribute__((overloadable)) powr(float4, float4);
+extern float8 __attribute__((overloadable)) powr(float8, float8);
+extern float16 __attribute__((overloadable)) powr(float16, float16);
+
+extern float __attribute__((overloadable)) remainder(float, float);
+extern float2 __attribute__((overloadable)) remainder(float2, float2);
+extern float3 __attribute__((overloadable)) remainder(float3, float3);
+extern float4 __attribute__((overloadable)) remainder(float4, float4);
+extern float8 __attribute__((overloadable)) remainder(float8, float8);
+extern float16 __attribute__((overloadable)) remainder(float16, float16);
+
+extern float __attribute__((overloadable)) remquo(float, float, float *);
+extern float2 __attribute__((overloadable)) remquo(float2, float2, float2 *);
+extern float3 __attribute__((overloadable)) remquo(float3, float3, float3 *);
+extern float4 __attribute__((overloadable)) remquo(float4, float4, float4 *);
+extern float8 __attribute__((overloadable)) remquo(float8, float8, float8 *);
+extern float16 __attribute__((overloadable)) remquo(float16, float16, float16 *);
+
+extern float __attribute__((overloadable)) rint(float);
+extern float2 __attribute__((overloadable)) rint(float2);
+extern float3 __attribute__((overloadable)) rint(float3);
+extern float4 __attribute__((overloadable)) rint(float4);
+extern float8 __attribute__((overloadable)) rint(float8);
+extern float16 __attribute__((overloadable)) rint(float16);
+
+extern float __attribute__((overloadable)) rootn(float, int);
+extern float2 __attribute__((overloadable)) rootn(float2, int2);
+extern float3 __attribute__((overloadable)) rootn(float3, int3);
+extern float4 __attribute__((overloadable)) rootn(float4, int4);
+extern float8 __attribute__((overloadable)) rootn(float8, int8);
+extern float16 __attribute__((overloadable)) rootn(float16, int16);
+
+extern float __attribute__((overloadable)) round(float);
+extern float2 __attribute__((overloadable)) round(float2);
+extern float3 __attribute__((overloadable)) round(float3);
+extern float4 __attribute__((overloadable)) round(float4);
+extern float8 __attribute__((overloadable)) round(float8);
+extern float16 __attribute__((overloadable)) round(float16);
+
+extern float __attribute__((overloadable)) rsqrt(float);
+extern float2 __attribute__((overloadable)) rsqrt(float2);
+extern float3 __attribute__((overloadable)) rsqrt(float3);
+extern float4 __attribute__((overloadable)) rsqrt(float4);
+extern float8 __attribute__((overloadable)) rsqrt(float8);
+extern float16 __attribute__((overloadable)) rsqrt(float16);
+
+extern float __attribute__((overloadable)) sin(float);
+extern float2 __attribute__((overloadable)) sin(float2);
+extern float3 __attribute__((overloadable)) sin(float3);
+extern float4 __attribute__((overloadable)) sin(float4);
+extern float8 __attribute__((overloadable)) sin(float8);
+extern float16 __attribute__((overloadable)) sin(float16);
+
+extern float __attribute__((overloadable)) sincos(float, float *);
+extern float2 __attribute__((overloadable)) sincos(float2, float2 *);
+extern float3 __attribute__((overloadable)) sincos(float3, float3 *);
+extern float4 __attribute__((overloadable)) sincos(float4, float4 *);
+extern float8 __attribute__((overloadable)) sincos(float8, float8 *);
+extern float16 __attribute__((overloadable)) sincos(float16, float16 *);
+
+extern float __attribute__((overloadable)) sinh(float);
+extern float2 __attribute__((overloadable)) sinh(float2);
+extern float3 __attribute__((overloadable)) sinh(float3);
+extern float4 __attribute__((overloadable)) sinh(float4);
+extern float8 __attribute__((overloadable)) sinh(float8);
+extern float16 __attribute__((overloadable)) sinh(float16);
+
+extern float __attribute__((overloadable)) sinpi(float);
+extern float2 __attribute__((overloadable)) sinpi(float2);
+extern float3 __attribute__((overloadable)) sinpi(float3);
+extern float4 __attribute__((overloadable)) sinpi(float4);
+extern float8 __attribute__((overloadable)) sinpi(float8);
+extern float16 __attribute__((overloadable)) sinpi(float16);
+
+extern float __attribute__((overloadable)) sqrt(float);
+extern float2 __attribute__((overloadable)) sqrt(float2);
+extern float3 __attribute__((overloadable)) sqrt(float3);
+extern float4 __attribute__((overloadable)) sqrt(float4);
+extern float8 __attribute__((overloadable)) sqrt(float8);
+extern float16 __attribute__((overloadable)) sqrt(float16);
+
+extern float __attribute__((overloadable)) tan(float);
+extern float2 __attribute__((overloadable)) tan(float2);
+extern float3 __attribute__((overloadable)) tan(float3);
+extern float4 __attribute__((overloadable)) tan(float4);
+extern float8 __attribute__((overloadable)) tan(float8);
+extern float16 __attribute__((overloadable)) tan(float16);
+
+extern float __attribute__((overloadable)) tanh(float);
+extern float2 __attribute__((overloadable)) tanh(float2);
+extern float3 __attribute__((overloadable)) tanh(float3);
+extern float4 __attribute__((overloadable)) tanh(float4);
+extern float8 __attribute__((overloadable)) tanh(float8);
+extern float16 __attribute__((overloadable)) tanh(float16);
+
+extern float __attribute__((overloadable)) tanpi(float);
+extern float2 __attribute__((overloadable)) tanpi(float2);
+extern float3 __attribute__((overloadable)) tanpi(float3);
+extern float4 __attribute__((overloadable)) tanpi(float4);
+extern float8 __attribute__((overloadable)) tanpi(float8);
+extern float16 __attribute__((overloadable)) tanpi(float16);
+
+extern float __attribute__((overloadable)) tgamma(float);
+extern float2 __attribute__((overloadable)) tgamma(float2);
+extern float3 __attribute__((overloadable)) tgamma(float3);
+extern float4 __attribute__((overloadable)) tgamma(float4);
+extern float8 __attribute__((overloadable)) tgamma(float8);
+extern float16 __attribute__((overloadable)) tgamma(float16);
+
+extern float __attribute__((overloadable)) trunc(float);
+extern float2 __attribute__((overloadable)) trunc(float2);
+extern float3 __attribute__((overloadable)) trunc(float3);
+extern float4 __attribute__((overloadable)) trunc(float4);
+extern float8 __attribute__((overloadable)) trunc(float8);
+extern float16 __attribute__((overloadable)) trunc(float16);
+
+// Int ops (partial), 6.11.3
+extern uint __attribute__((overloadable)) abs(int);
+extern ushort __attribute__((overloadable)) abs(short);
+extern uchar __attribute__((overloadable)) abs(char);
+
+extern uint __attribute__((overloadable)) clz(uint);
+extern int __attribute__((overloadable)) clz(int);
+extern ushort __attribute__((overloadable)) clz(ushort);
+extern short __attribute__((overloadable)) clz(short);
+extern uchar __attribute__((overloadable)) clz(uchar);
+extern char __attribute__((overloadable)) clz(char);
+
+extern uint __attribute__((overloadable)) min(uint, uint);
+extern int __attribute__((overloadable)) min(int, int);
+extern ushort __attribute__((overloadable)) min(ushort, ushort);
+extern short __attribute__((overloadable)) min(short, short);
+extern uchar __attribute__((overloadable)) min(uchar, uchar);
+extern char __attribute__((overloadable)) min(char, char);
+
+extern uint __attribute__((overloadable)) max(uint, uint);
+extern int __attribute__((overloadable)) max(int, int);
+extern ushort __attribute__((overloadable)) max(ushort, ushort);
+extern short __attribute__((overloadable)) max(short, short);
+extern uchar __attribute__((overloadable)) max(uchar, uchar);
+extern char __attribute__((overloadable)) max(char, char);
+
+
+
+
+// 6.11.4
+
+extern float __attribute__((overloadable)) clamp(float, float, float);
+extern float2 __attribute__((overloadable)) clamp(float2, float2, float2);
+extern float3 __attribute__((overloadable)) clamp(float3, float3, float3);
+extern float4 __attribute__((overloadable)) clamp(float4, float4, float4);
+extern float8 __attribute__((overloadable)) clamp(float8, float8, float8);
+extern float16 __attribute__((overloadable)) clamp(float16, float16, float16);
+extern float2 __attribute__((overloadable)) clamp(float2, float, float);
+extern float3 __attribute__((overloadable)) clamp(float3, float, float);
+extern float4 __attribute__((overloadable)) clamp(float4, float, float);
+extern float8 __attribute__((overloadable)) clamp(float8, float, float);
+extern float16 __attribute__((overloadable)) clamp(float16, float, float);
+
+extern float __attribute__((overloadable)) degrees(float);
+extern float2 __attribute__((overloadable)) degrees(float2);
+extern float3 __attribute__((overloadable)) degrees(float3);
+extern float4 __attribute__((overloadable)) degrees(float4);
+extern float8 __attribute__((overloadable)) degrees(float8);
+extern float16 __attribute__((overloadable)) degrees(float16);
+
+extern float __attribute__((overloadable)) max(float, float);
+extern float2 __attribute__((overloadable)) max(float2, float2);
+extern float3 __attribute__((overloadable)) max(float3, float3);
+extern float4 __attribute__((overloadable)) max(float4, float4);
+extern float8 __attribute__((overloadable)) max(float8, float8);
+extern float16 __attribute__((overloadable)) max(float16, float16);
+extern float2 __attribute__((overloadable)) max(float2, float);
+extern float3 __attribute__((overloadable)) max(float3, float);
+extern float4 __attribute__((overloadable)) max(float4, float);
+extern float8 __attribute__((overloadable)) max(float8, float);
+extern float16 __attribute__((overloadable)) max(float16, float);
+
+extern float __attribute__((overloadable)) min(float, float);
+extern float2 __attribute__((overloadable)) min(float2, float2);
+extern float3 __attribute__((overloadable)) min(float3, float3);
+extern float4 __attribute__((overloadable)) min(float4, float4);
+extern float8 __attribute__((overloadable)) min(float8, float8);
+extern float16 __attribute__((overloadable)) min(float16, float16);
+extern float2 __attribute__((overloadable)) min(float2, float);
+extern float3 __attribute__((overloadable)) min(float3, float);
+extern float4 __attribute__((overloadable)) min(float4, float);
+extern float8 __attribute__((overloadable)) min(float8, float);
+extern float16 __attribute__((overloadable)) min(float16, float);
+
+extern float __attribute__((overloadable)) mix(float, float, float);
+extern float2 __attribute__((overloadable)) mix(float2, float2, float2);
+extern float3 __attribute__((overloadable)) mix(float3, float3, float3);
+extern float4 __attribute__((overloadable)) mix(float4, float4, float4);
+extern float8 __attribute__((overloadable)) mix(float8, float8, float8);
+extern float16 __attribute__((overloadable)) mix(float16, float16, float16);
+extern float2 __attribute__((overloadable)) mix(float2, float2, float);
+extern float3 __attribute__((overloadable)) mix(float3, float3, float);
+extern float4 __attribute__((overloadable)) mix(float4, float4, float);
+extern float8 __attribute__((overloadable)) mix(float8, float8, float);
+extern float16 __attribute__((overloadable)) mix(float16, float16, float);
+
+extern float __attribute__((overloadable)) radians(float);
+extern float2 __attribute__((overloadable)) radians(float2);
+extern float3 __attribute__((overloadable)) radians(float3);
+extern float4 __attribute__((overloadable)) radians(float4);
+extern float8 __attribute__((overloadable)) radians(float8);
+extern float16 __attribute__((overloadable)) radians(float16);
+
+extern float __attribute__((overloadable)) step(float, float);
+extern float2 __attribute__((overloadable)) step(float2, float2);
+extern float3 __attribute__((overloadable)) step(float3, float3);
+extern float4 __attribute__((overloadable)) step(float4, float4);
+extern float8 __attribute__((overloadable)) step(float8, float8);
+extern float16 __attribute__((overloadable)) step(float16, float16);
+extern float2 __attribute__((overloadable)) step(float, float2);
+extern float3 __attribute__((overloadable)) step(float, float3);
+extern float4 __attribute__((overloadable)) step(float, float4);
+extern float8 __attribute__((overloadable)) step(float, float8);
+extern float16 __attribute__((overloadable)) step(float, float16);
+
+extern float __attribute__((overloadable)) smoothstep(float, float, float);
+extern float2 __attribute__((overloadable)) smoothstep(float2, float2, float2);
+extern float3 __attribute__((overloadable)) smoothstep(float3, float3, float3);
+extern float4 __attribute__((overloadable)) smoothstep(float4, float4, float4);
+extern float8 __attribute__((overloadable)) smoothstep(float8, float8, float8);
+extern float16 __attribute__((overloadable)) smoothstep(float16, float16, float16);
+extern float2 __attribute__((overloadable)) smoothstep(float, float, float2);
+extern float3 __attribute__((overloadable)) smoothstep(float, float, float3);
+extern float4 __attribute__((overloadable)) smoothstep(float, float, float4);
+extern float8 __attribute__((overloadable)) smoothstep(float, float, float8);
+extern float16 __attribute__((overloadable)) smoothstep(float, float, float16);
+
+extern float __attribute__((overloadable)) sign(float);
+extern float2 __attribute__((overloadable)) sign(float2);
+extern float3 __attribute__((overloadable)) sign(float3);
+extern float4 __attribute__((overloadable)) sign(float4);
+extern float8 __attribute__((overloadable)) sign(float8);
+extern float16 __attribute__((overloadable)) sign(float16);
+
+// 6.11.5
+extern float3 __attribute__((overloadable)) cross(float2, float2);
+extern float3 __attribute__((overloadable)) cross(float3, float3);
+extern float4 __attribute__((overloadable)) cross(float4, float4);
+
+extern float __attribute__((overloadable)) dot(float, float);
+extern float __attribute__((overloadable)) dot(float2, float2);
+extern float __attribute__((overloadable)) dot(float3, float3);
+extern float __attribute__((overloadable)) dot(float4, float4);
+
+extern float __attribute__((overloadable)) distance(float, float);
+extern float __attribute__((overloadable)) distance(float2, float2);
+extern float __attribute__((overloadable)) distance(float3, float3);
+extern float __attribute__((overloadable)) distance(float4, float4);
+
+extern float __attribute__((overloadable)) length(float);
+extern float __attribute__((overloadable)) length(float2);
+extern float __attribute__((overloadable)) length(float3);
+extern float __attribute__((overloadable)) length(float4);
+
+extern float __attribute__((overloadable)) normalize(float);
+extern float2 __attribute__((overloadable)) normalize(float2);
+extern float3 __attribute__((overloadable)) normalize(float3);
+extern float4 __attribute__((overloadable)) normalize(float4);
+
diff --git a/libs/rs/scriptc/rs_core.rsh b/libs/rs/scriptc/rs_core.rsh
new file mode 100644
index 0000000..8005a70
--- /dev/null
+++ b/libs/rs/scriptc/rs_core.rsh
@@ -0,0 +1,58 @@
+#ifndef __RS_CORE_RSH__
+#define __RS_CORE_RSH__
+
+
+static uchar4 __attribute__((overloadable)) rsPackColorTo8888(float r, float g, float b)
+{
+ uchar4 c;
+ c.x = (uchar)(r * 255.f);
+ c.y = (uchar)(g * 255.f);
+ c.z = (uchar)(b * 255.f);
+ c.w = 255;
+ return c;
+}
+
+static uchar4 __attribute__((overloadable)) rsPackColorTo8888(float r, float g, float b, float a)
+{
+ uchar4 c;
+ c.x = (uchar)(r * 255.f);
+ c.y = (uchar)(g * 255.f);
+ c.z = (uchar)(b * 255.f);
+ c.w = (uchar)(a * 255.f);
+ return c;
+}
+
+static uchar4 __attribute__((overloadable)) rsPackColorTo8888(float3 color)
+{
+ color *= 255.f;
+ uchar4 c = {color.x, color.y, color.z, 255};
+ return c;
+}
+
+static uchar4 __attribute__((overloadable)) rsPackColorTo8888(float4 color)
+{
+ color *= 255.f;
+ uchar4 c = {color.x, color.y, color.z, color.w};
+ return c;
+}
+
+static float4 rsUnpackColor8888(uchar4 c)
+{
+ float4 ret = {
+ c.x * (1.f / 255.f),
+ c.y * (1.f / 255.f),
+ c.z * (1.f / 255.f),
+ c.w * (1.f / 255.f),
+ };
+ return ret;
+}
+
+//extern uchar4 __attribute__((overloadable)) rsPackColorTo565(float r, float g, float b);
+//extern uchar4 __attribute__((overloadable)) rsPackColorTo565(float3);
+//extern float4 rsUnpackColor565(uchar4);
+
+
+
+
+#endif
+
diff --git a/libs/rs/scriptc/rs_graphics.rsh b/libs/rs/scriptc/rs_graphics.rsh
index 70cd562..626f267 100644
--- a/libs/rs/scriptc/rs_graphics.rsh
+++ b/libs/rs/scriptc/rs_graphics.rsh
@@ -1,65 +1,45 @@
+#include "rs_math.rsh"
-extern float2 vec2Rand(float len);
+// context
+extern void rsgBindProgramFragment(rs_program_fragment);
+extern void rsgBindProgramStore(rs_program_store);
+extern void rsgBindProgramVertex(rs_program_vertex);
+extern void rsgBindProgramRaster(rs_program_raster);
-extern float3 float3Norm(float3);
-extern float float3Length(float3);
-extern float3 float3Add(float3 lhs, float3 rhs);
-extern float3 float3Sub(float3 lhs, float3 rhs);
-extern float3 float3Cross(float3 lhs, float3 rhs);
-extern float float3Dot(float3 lhs, float3 rhs);
-extern float3 float3Scale(float3 v, float scale);
+extern void rsgBindSampler(rs_program_fragment, int slot, rs_sampler);
+extern void rsgBindTexture(rs_program_fragment, int slot, rs_allocation);
-extern float4 float4Add(float4 lhs, float4 rhs);
-extern float4 float4Sub(float4 lhs, float4 rhs);
-extern float4 float4Cross(float4 lhs, float4 rhs);
-extern float float4Dot(float4 lhs, float4 rhs);
-extern float4 float4Scale(float4 v, float scale);
+extern void rsgProgramVertexLoadModelMatrix(const rs_matrix4x4 *);
+extern void rsgProgramVertexLoadTextureMatrix(const rs_matrix4x4 *);
- // context
-extern void bindProgramFragment(rs_program_fragment);
-extern void bindProgramStore(rs_program_store);
-extern void bindProgramVertex(rs_program_vertex);
+extern int rsgGetWidth();
+extern int rsgGetHeight();
-extern void bindSampler(rs_program_fragment, int slot, rs_sampler);
-extern void bindSampler(rs_program_fragment, int slot, rs_allocation);
+extern void __attribute__((overloadable)) rsgUploadToTexture(rs_allocation);
+extern void __attribute__((overloadable)) rsgUploadToTexture(rs_allocation, int mipLevel);
+extern void rsgUploadToBufferObject(rs_allocation);
+//extern void rsgUploadMesh(rs_mesh);
-extern void vpLoadModelMatrix(const float *);
-extern void vpLoadTextureMatrix(const float *);
+extern void rsgDrawRect(float x1, float y1, float x2, float y2, float z);
+extern void rsgDrawQuad(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float x4, float y4, float z4);
+extern void rsgDrawQuadTexCoords(float x1, float y1, float z1, float u1, float v1, float x2, float y2, float z2, float u2, float v2, float x3, float y3, float z3, float u3, float v3, float x4, float y4, float z4, float u4, float v4);
+//extern void rsgDrawSprite(float x, float y, float z, float w, float h);
+extern void rsgDrawSpriteScreenspace(float x, float y, float z, float w, float h);
+extern void rsgDrawLine(float x1, float y1, float z1, float x2, float y2, float z2);
+extern void rsgDrawPoint(float x1, float y1, float z1);
+extern void __attribute__((overloadable)) rsgDrawSimpleMesh(rs_mesh ism);
+extern void __attribute__((overloadable)) rsgDrawSimpleMesh(rs_mesh ism, int start, int len);
+extern void rsgClearColor(float, float, float, float);
+extern void rsgClearDepth(float);
-// drawing
-extern void drawRect(float x1, float y1, float x2, float y2, float z);
-extern void drawQuad(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float x4, float y4, float z4);
-extern void drawQuadTexCoords(float x1, float y1, float z1, float u1, float v1, float x2, float y2, float z2, float u2, float v2, float x3, float y3, float z3, float u3, float v3, float x4, float y4, float z4, float u4, float v4);
-extern void drawSprite(float x, float y, float z, float w, float h);
-extern void drawSpriteScreenspace(float x, float y, float z, float w, float h);
-extern void drawLine(float x1, float y1, float z1, float x2, float y2, float z2);
-extern void drawPoint(float x1, float y1, float z1);
-extern void drawSimpleMesh(int ism);
-extern void drawSimpleMeshRange(int ism, int start, int len);
-
+///////////////////////////////////////////////////////
// misc
-extern void pfClearColor(float, float, float, float);
extern void color(float, float, float, float);
extern void hsb(float, float, float, float);
extern void hsbToRgb(float, float, float, float*);
extern int hsbToAbgr(float, float, float, float);
-extern void uploadToTexture(int, int);
-extern void uploadToBufferObject(int);
-
-extern int colorFloatRGBAtoUNorm8(float, float, float, float);
-extern int colorFloatRGBto565(float, float, float);
-
-extern int getWidth();
-extern int getHeight();
-
-extern int sendToClient(void *data, int cmdID, int len, int waitForSpace);
-
-extern void debugF(const char *, float);
-extern void debugI32(const char *, int);
-extern void debugHexI32(const char *, int);
-
diff --git a/libs/rs/scriptc/rs_math.rsh b/libs/rs/scriptc/rs_math.rsh
index 613c7ca..a26491f 100644
--- a/libs/rs/scriptc/rs_math.rsh
+++ b/libs/rs/scriptc/rs_math.rsh
@@ -1,287 +1,87 @@
-// Float ops
-
-extern float __attribute__((overloadable)) abs(float);
-extern float2 __attribute__((overloadable)) abs(float2);
-extern float3 __attribute__((overloadable)) abs(float3);
-extern float4 __attribute__((overloadable)) abs(float4);
-extern float8 __attribute__((overloadable)) abs(float8);
-extern float16 __attribute__((overloadable)) abs(float16);
-
-extern float __attribute__((overloadable)) acos(float);
-extern float2 __attribute__((overloadable)) acos(float2);
-extern float3 __attribute__((overloadable)) acos(float3);
-extern float4 __attribute__((overloadable)) acos(float4);
-extern float8 __attribute__((overloadable)) acos(float8);
-extern float16 __attribute__((overloadable)) acos(float16);
-
-extern float __attribute__((overloadable)) asin(float);
-extern float2 __attribute__((overloadable)) asin(float2);
-extern float3 __attribute__((overloadable)) asin(float3);
-extern float4 __attribute__((overloadable)) asin(float4);
-extern float8 __attribute__((overloadable)) asin(float8);
-extern float16 __attribute__((overloadable)) asin(float16);
-
-extern float __attribute__((overloadable)) atan(float);
-extern float2 __attribute__((overloadable)) atan(float2);
-extern float3 __attribute__((overloadable)) atan(float3);
-extern float4 __attribute__((overloadable)) atan(float4);
-extern float8 __attribute__((overloadable)) atan(float8);
-extern float16 __attribute__((overloadable)) atan(float16);
-
-extern float __attribute__((overloadable)) atan2(float, float);
-extern float2 __attribute__((overloadable)) atan2(float2, float2);
-extern float3 __attribute__((overloadable)) atan2(float3, float3);
-extern float4 __attribute__((overloadable)) atan2(float4, float4);
-extern float8 __attribute__((overloadable)) atan2(float8, float8);
-extern float16 __attribute__((overloadable)) atan2(float16, float16);
-
-extern float __attribute__((overloadable)) ceil(float);
-extern float2 __attribute__((overloadable)) ceil(float2);
-extern float3 __attribute__((overloadable)) ceil(float3);
-extern float4 __attribute__((overloadable)) ceil(float4);
-extern float8 __attribute__((overloadable)) ceil(float8);
-extern float16 __attribute__((overloadable)) ceil(float16);
-
-extern float __attribute__((overloadable)) clamp(float, float, float);
-extern float2 __attribute__((overloadable)) clamp(float2, float2, float2);
-extern float3 __attribute__((overloadable)) clamp(float3, float3, float3);
-extern float4 __attribute__((overloadable)) clamp(float4, float4, float4);
-extern float8 __attribute__((overloadable)) clamp(float8, float8, float8);
-extern float16 __attribute__((overloadable)) clamp(float16, float16, float16);
-extern float __attribute__((overloadable)) clamp(float, float, float);
-extern float2 __attribute__((overloadable)) clamp(float2, float, float);
-extern float3 __attribute__((overloadable)) clamp(float3, float, float);
-extern float4 __attribute__((overloadable)) clamp(float4, float, float);
-extern float8 __attribute__((overloadable)) clamp(float8, float, float);
-extern float16 __attribute__((overloadable)) clamp(float16, float, float);
-
-extern float __attribute__((overloadable)) copysign(float, float);
-extern float2 __attribute__((overloadable)) copysign(float2, float2);
-extern float3 __attribute__((overloadable)) copysign(float3, float3);
-extern float4 __attribute__((overloadable)) copysign(float4, float4);
-extern float8 __attribute__((overloadable)) copysign(float8, float8);
-extern float16 __attribute__((overloadable)) copysign(float16, float16);
-
-extern float __attribute__((overloadable)) cos(float);
-extern float2 __attribute__((overloadable)) cos(float2);
-extern float3 __attribute__((overloadable)) cos(float3);
-extern float4 __attribute__((overloadable)) cos(float4);
-extern float8 __attribute__((overloadable)) cos(float8);
-extern float16 __attribute__((overloadable)) cos(float16);
-
-extern float __attribute__((overloadable)) degrees(float);
-extern float2 __attribute__((overloadable)) degrees(float2);
-extern float3 __attribute__((overloadable)) degrees(float3);
-extern float4 __attribute__((overloadable)) degrees(float4);
-extern float8 __attribute__((overloadable)) degrees(float8);
-extern float16 __attribute__((overloadable)) degrees(float16);
-
-extern float __attribute__((overloadable)) exp(float);
-extern float2 __attribute__((overloadable)) exp(float2);
-extern float3 __attribute__((overloadable)) exp(float3);
-extern float4 __attribute__((overloadable)) exp(float4);
-extern float8 __attribute__((overloadable)) exp(float8);
-extern float16 __attribute__((overloadable)) exp(float16);
-
-extern float __attribute__((overloadable)) exp2(float);
-extern float2 __attribute__((overloadable)) exp2(float2);
-extern float3 __attribute__((overloadable)) exp2(float3);
-extern float4 __attribute__((overloadable)) exp2(float4);
-extern float8 __attribute__((overloadable)) exp2(float8);
-extern float16 __attribute__((overloadable)) exp2(float16);
-
-extern float __attribute__((overloadable)) exp10(float);
-extern float2 __attribute__((overloadable)) exp10(float2);
-extern float3 __attribute__((overloadable)) exp10(float3);
-extern float4 __attribute__((overloadable)) exp10(float4);
-extern float8 __attribute__((overloadable)) exp10(float8);
-extern float16 __attribute__((overloadable)) exp10(float16);
-
-extern float __attribute__((overloadable)) fabs(float);
-extern float2 __attribute__((overloadable)) fabs(float2);
-extern float3 __attribute__((overloadable)) fabs(float3);
-extern float4 __attribute__((overloadable)) fabs(float4);
-extern float8 __attribute__((overloadable)) fabs(float8);
-extern float16 __attribute__((overloadable)) fabs(float16);
-
-extern float __attribute__((overloadable)) floor(float);
-extern float2 __attribute__((overloadable)) floor(float2);
-extern float3 __attribute__((overloadable)) floor(float3);
-extern float4 __attribute__((overloadable)) floor(float4);
-extern float8 __attribute__((overloadable)) floor(float8);
-extern float16 __attribute__((overloadable)) floor(float16);
-
-extern float __attribute__((overloadable)) fmax(float, float);
-extern float2 __attribute__((overloadable)) fmax(float2, float2);
-extern float3 __attribute__((overloadable)) fmax(float3, float3);
-extern float4 __attribute__((overloadable)) fmax(float4, float4);
-extern float8 __attribute__((overloadable)) fmax(float8, float8);
-extern float16 __attribute__((overloadable)) fmax(float16, float16);
-extern float2 __attribute__((overloadable)) fmax(float2, float);
-extern float3 __attribute__((overloadable)) fmax(float3, float);
-extern float4 __attribute__((overloadable)) fmax(float4, float);
-extern float8 __attribute__((overloadable)) fmax(float8, float);
-extern float16 __attribute__((overloadable)) fmax(float16, float);
-
-extern float __attribute__((overloadable)) fmin(float, float);
-extern float2 __attribute__((overloadable)) fmin(float2, float2);
-extern float3 __attribute__((overloadable)) fmin(float3, float3);
-extern float4 __attribute__((overloadable)) fmin(float4, float4);
-extern float8 __attribute__((overloadable)) fmin(float8, float8);
-extern float16 __attribute__((overloadable)) fmin(float16, float16);
-extern float2 __attribute__((overloadable)) fmin(float2, float);
-extern float3 __attribute__((overloadable)) fmin(float3, float);
-extern float4 __attribute__((overloadable)) fmin(float4, float);
-extern float8 __attribute__((overloadable)) fmin(float8, float);
-extern float16 __attribute__((overloadable)) fmin(float16, float);
-
-extern float __attribute__((overloadable)) fmod(float, float);
-extern float2 __attribute__((overloadable)) fmod(float2, float2);
-extern float3 __attribute__((overloadable)) fmod(float3, float3);
-extern float4 __attribute__((overloadable)) fmod(float4, float4);
-extern float8 __attribute__((overloadable)) fmod(float8, float8);
-extern float16 __attribute__((overloadable)) fmod(float16, float16);
-
-extern float __attribute__((overloadable)) log(float);
-extern float2 __attribute__((overloadable)) log(float2);
-extern float3 __attribute__((overloadable)) log(float3);
-extern float4 __attribute__((overloadable)) log(float4);
-extern float8 __attribute__((overloadable)) log(float8);
-extern float16 __attribute__((overloadable)) log(float16);
-
-extern float __attribute__((overloadable)) log2(float);
-extern float2 __attribute__((overloadable)) log2(float2);
-extern float3 __attribute__((overloadable)) log2(float3);
-extern float4 __attribute__((overloadable)) log2(float4);
-extern float8 __attribute__((overloadable)) log2(float8);
-extern float16 __attribute__((overloadable)) log2(float16);
-
-extern float __attribute__((overloadable)) log10(float);
-extern float2 __attribute__((overloadable)) log10(float2);
-extern float3 __attribute__((overloadable)) log10(float3);
-extern float4 __attribute__((overloadable)) log10(float4);
-extern float8 __attribute__((overloadable)) log10(float8);
-extern float16 __attribute__((overloadable)) log10(float16);
-
-extern float __attribute__((overloadable)) max(float, float);
-extern float2 __attribute__((overloadable)) max(float2, float2);
-extern float3 __attribute__((overloadable)) max(float3, float3);
-extern float4 __attribute__((overloadable)) max(float4, float4);
-extern float8 __attribute__((overloadable)) max(float8, float8);
-extern float16 __attribute__((overloadable)) max(float16, float16);
-
-extern float __attribute__((overloadable)) min(float, float);
-extern float2 __attribute__((overloadable)) min(float2, float2);
-extern float3 __attribute__((overloadable)) min(float3, float3);
-extern float4 __attribute__((overloadable)) min(float4, float4);
-extern float8 __attribute__((overloadable)) min(float8, float8);
-extern float16 __attribute__((overloadable)) min(float16, float16);
-
-extern float __attribute__((overloadable)) mix(float, float, float);
-extern float2 __attribute__((overloadable)) mix(float2, float2, float2);
-extern float3 __attribute__((overloadable)) mix(float3, float3, float3);
-extern float4 __attribute__((overloadable)) mix(float4, float4, float4);
-extern float8 __attribute__((overloadable)) mix(float8, float8, float8);
-extern float16 __attribute__((overloadable)) mix(float16, float16, float16);
-extern float __attribute__((overloadable)) mix(float, float, float);
-extern float2 __attribute__((overloadable)) mix(float2, float2, float);
-extern float3 __attribute__((overloadable)) mix(float3, float3, float);
-extern float4 __attribute__((overloadable)) mix(float4, float4, float);
-extern float8 __attribute__((overloadable)) mix(float8, float8, float);
-extern float16 __attribute__((overloadable)) mix(float16, float16, float);
-
-extern float __attribute__((overloadable)) pow(float, float);
-extern float2 __attribute__((overloadable)) pow(float2, float2);
-extern float3 __attribute__((overloadable)) pow(float3, float3);
-extern float4 __attribute__((overloadable)) pow(float4, float4);
-extern float8 __attribute__((overloadable)) pow(float8, float8);
-extern float16 __attribute__((overloadable)) pow(float16, float16);
-
-extern float __attribute__((overloadable)) radians(float);
-extern float2 __attribute__((overloadable)) radians(float2);
-extern float3 __attribute__((overloadable)) radians(float3);
-extern float4 __attribute__((overloadable)) radians(float4);
-extern float8 __attribute__((overloadable)) radians(float8);
-extern float16 __attribute__((overloadable)) radians(float16);
-
-extern float __attribute__((overloadable)) rint(float);
-extern float2 __attribute__((overloadable)) rint(float2);
-extern float3 __attribute__((overloadable)) rint(float3);
-extern float4 __attribute__((overloadable)) rint(float4);
-extern float8 __attribute__((overloadable)) rint(float8);
-extern float16 __attribute__((overloadable)) rint(float16);
-
-extern float __attribute__((overloadable)) round(float);
-extern float2 __attribute__((overloadable)) round(float2);
-extern float3 __attribute__((overloadable)) round(float3);
-extern float4 __attribute__((overloadable)) round(float4);
-extern float8 __attribute__((overloadable)) round(float8);
-extern float16 __attribute__((overloadable)) round(float16);
-
-extern float __attribute__((overloadable)) rsqrt(float);
-extern float2 __attribute__((overloadable)) rsqrt(float2);
-extern float3 __attribute__((overloadable)) rsqrt(float3);
-extern float4 __attribute__((overloadable)) rsqrt(float4);
-extern float8 __attribute__((overloadable)) rsqrt(float8);
-extern float16 __attribute__((overloadable)) rsqrt(float16);
-
-extern float __attribute__((overloadable)) sign(float);
-extern float2 __attribute__((overloadable)) sign(float2);
-extern float3 __attribute__((overloadable)) sign(float3);
-extern float4 __attribute__((overloadable)) sign(float4);
-extern float8 __attribute__((overloadable)) sign(float8);
-extern float16 __attribute__((overloadable)) sign(float16);
-
-extern float __attribute__((overloadable)) sin(float);
-extern float2 __attribute__((overloadable)) sin(float2);
-extern float3 __attribute__((overloadable)) sin(float3);
-extern float4 __attribute__((overloadable)) sin(float4);
-extern float8 __attribute__((overloadable)) sin(float8);
-extern float16 __attribute__((overloadable)) sin(float16);
-
-extern float __attribute__((overloadable)) sqrt(float);
-extern float2 __attribute__((overloadable)) sqrt(float2);
-extern float3 __attribute__((overloadable)) sqrt(float3);
-extern float4 __attribute__((overloadable)) sqrt(float4);
-extern float8 __attribute__((overloadable)) sqrt(float8);
-extern float16 __attribute__((overloadable)) sqrt(float16);
-
-extern float __attribute__((overloadable)) tan(float);
-extern float2 __attribute__((overloadable)) tan(float2);
-extern float3 __attribute__((overloadable)) tan(float3);
-extern float4 __attribute__((overloadable)) tan(float4);
-extern float8 __attribute__((overloadable)) tan(float8);
-extern float16 __attribute__((overloadable)) tan(float16);
-
-extern float __attribute__((overloadable)) trunc(float);
-extern float2 __attribute__((overloadable)) trunc(float2);
-extern float3 __attribute__((overloadable)) trunc(float3);
-extern float4 __attribute__((overloadable)) trunc(float4);
-extern float8 __attribute__((overloadable)) trunc(float8);
-extern float16 __attribute__((overloadable)) trunc(float16);
+#include "rs_cl.rsh"
+#include "rs_core.rsh"
+// Allocations
+extern rs_allocation rsGetAllocation(const void *);
+extern uint32_t rsAllocationGetDimX(rs_allocation);
+extern uint32_t rsAllocationGetDimY(rs_allocation);
+extern uint32_t rsAllocationGetDimZ(rs_allocation);
+extern uint32_t rsAllocationGetDimLOD(rs_allocation);
+extern uint32_t rsAllocationGetDimFaces(rs_allocation);
-// Int ops
+// Debugging
+extern void __attribute__((overloadable))rsDebug(const char *, float);
+extern void __attribute__((overloadable))rsDebug(const char *, float2);
+extern void __attribute__((overloadable))rsDebug(const char *, float3);
+extern void __attribute__((overloadable))rsDebug(const char *, float4);
+extern void __attribute__((overloadable))rsDebug(const char *, int);
+extern void __attribute__((overloadable))rsDebug(const char *, const void *);
+#define RS_DEBUG(a) rsDebug(#a, a)
+#define RS_DEBUG_MARKER rsDebug(__FILE__, __LINE__)
-extern int __attribute__((overloadable)) abs(int);
-extern int2 __attribute__((overloadable)) abs(int2);
-extern int3 __attribute__((overloadable)) abs(int3);
-extern int4 __attribute__((overloadable)) abs(int4);
-extern int8 __attribute__((overloadable)) abs(int8);
-extern int16 __attribute__((overloadable)) abs(int16);
+// RS Math
+extern int __attribute__((overloadable)) rsRand(int);
+extern int __attribute__((overloadable)) rsRand(int, int);
+extern float __attribute__((overloadable)) rsRand(float);
+extern float __attribute__((overloadable)) rsRand(float, float);
+
+extern float __attribute__((overloadable)) rsFrac(float);
+
+// time
+extern int32_t rsSecond();
+extern int32_t rsMinute();
+extern int32_t rsHour();
+extern int32_t rsDay();
+extern int32_t rsMonth();
+extern int32_t rsYear();
+extern int64_t rsUptimeMillis();
+extern int64_t rsStartTimeMillis();
+extern int64_t rsElapsedTimeMillis();
+
+extern int rsSendToClient(void *data, int cmdID, int len, int waitForSpace);
+
+extern void rsMatrixLoadIdentity(rs_matrix4x4 *mat);
+extern void rsMatrixLoadFloat(rs_matrix4x4 *mat, const float *f);
+extern void rsMatrixLoadMat(rs_matrix4x4 *mat, const rs_matrix4x4 *newmat);
+extern void rsMatrixLoadRotate(rs_matrix4x4 *mat, float rot, float x, float y, float z);
+extern void rsMatrixLoadScale(rs_matrix4x4*mat, float x, float y, float z);
+extern void rsMatrixLoadTranslate(rs_matrix4x4 *mat, float x, float y, float z);
+extern void rsMatrixLoadMultiply(rs_matrix4x4 *mat, const rs_matrix4x4 *lhs, const rs_matrix4x4 *rhs);
+extern void rsMatrixMultiply(rs_matrix4x4 *mat, const rs_matrix4x4 *rhs);
+extern void rsMatrixRotate(rs_matrix4x4 *mat, float rot, float x, float y, float z);
+extern void rsMatrixScale(rs_matrix4x4 *mat, float x, float y, float z);
+extern void rsMatrixTranslate(rs_matrix4x4 *mat, float x, float y, float z);
+
+// Script to Script
+extern void __attribute__((overloadable))rsForEach(rs_script, rs_allocation input);
+extern void __attribute__((overloadable))rsForEach(rs_script, rs_allocation input, rs_allocation output);
+extern void __attribute__((overloadable))rsForEach(rs_script, rs_allocation input, int xStart, int xEnd);
+extern void __attribute__((overloadable))rsForEach(rs_script, rs_allocation input, rs_allocation output, int xStart, int xEnd);
+extern void __attribute__((overloadable))rsForEach(rs_script, rs_allocation input, int xStart, int yStart, int xEnd, int yEnd);
+extern void __attribute__((overloadable))rsForEach(rs_script, rs_allocation input, rs_allocation output, int xStart, int yStart, int xEnd, int yEnd);
+///////////////////////////////////////////////////////////////////
+// non update funcs
/*
-extern float modf(float, float);
-extern float randf(float);
-extern float randf2(float, float);
-extern float fracf(float);
-extern float lerpf(float, float, float);
-extern float mapf(float, float, float, float, float);
+extern float3 float3Norm(float3);
+extern float float3Length(float3);
+extern float3 float3Add(float3 lhs, float3 rhs);
+extern float3 float3Sub(float3 lhs, float3 rhs);
+extern float3 float3Cross(float3 lhs, float3 rhs);
+extern float float3Dot(float3 lhs, float3 rhs);
+extern float3 float3Scale(float3 v, float scale);
+
+extern float4 float4Add(float4 lhs, float4 rhs);
+extern float4 float4Sub(float4 lhs, float4 rhs);
+extern float4 float4Cross(float4 lhs, float4 rhs);
+extern float float4Dot(float4 lhs, float4 rhs);
+extern float4 float4Scale(float4 v, float scale);
*/
+
diff --git a/libs/rs/scriptc/rs_types.rsh b/libs/rs/scriptc/rs_types.rsh
index 4198a74..2ac81e5 100644
--- a/libs/rs/scriptc/rs_types.rsh
+++ b/libs/rs/scriptc/rs_types.rsh
@@ -2,17 +2,17 @@
typedef char int8_t;
typedef short int16_t;
typedef int int32_t;
-//typedef long int64_t;
+typedef long long int64_t;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
-//typedef long uint64_t;
+typedef unsigned long long uint64_t;
typedef uint8_t uchar;
typedef uint16_t ushort;
typedef uint32_t uint;
-//typedef uint64_t ulong;
+typedef uint64_t ulong;
typedef int rs_element;
typedef int rs_type;
@@ -68,4 +68,7 @@
typedef int int16 __attribute__((ext_vector_type(16)));
+typedef struct {
+ float m[16];
+} rs_matrix4x4;
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index a1401ad..4362d14 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -317,6 +317,12 @@
mStringPoolSize =
(mHeader->header.size-mHeader->stringsStart)/charSize;
} else {
+ // check invariant: styles starts before end of data
+ if (mHeader->stylesStart >= (mHeader->header.size-sizeof(uint16_t))) {
+ LOGW("Bad style block: style block starts at %d past data size of %d\n",
+ (int)mHeader->stylesStart, (int)mHeader->header.size);
+ return (mError=BAD_TYPE);
+ }
// check invariant: styles follow the strings
if (mHeader->stylesStart <= mHeader->stringsStart) {
LOGW("Bad style block: style block starts at %d, before strings at %d\n",
@@ -1878,6 +1884,12 @@
outName->type = grp->basePackage->typeStrings.stringAt(t, &outName->typeLen);
outName->name = grp->basePackage->keyStrings.stringAt(
dtohl(entry->key.index), &outName->nameLen);
+
+ // If we have a bad index for some reason, we should abort.
+ if (outName->type == NULL || outName->name == NULL) {
+ return false;
+ }
+
return true;
}
@@ -2609,6 +2621,24 @@
*outType = *defType;
}
*outName = String16(p, end-p);
+ if(**outPackage == 0) {
+ if(outErrorMsg) {
+ *outErrorMsg = "Resource package cannot be an empty string";
+ }
+ return false;
+ }
+ if(**outType == 0) {
+ if(outErrorMsg) {
+ *outErrorMsg = "Resource type cannot be an empty string";
+ }
+ return false;
+ }
+ if(**outName == 0) {
+ if(outErrorMsg) {
+ *outErrorMsg = "Resource id cannot be an empty string";
+ }
+ return false;
+ }
return true;
}
@@ -4127,13 +4157,16 @@
| (0x00ff0000 & ((typeIndex+1)<<16))
| (0x0000ffff & (entryIndex));
resource_name resName;
- this->getResourceName(resID, &resName);
- printf(" spec resource 0x%08x %s:%s/%s: flags=0x%08x\n",
- resID,
- CHAR16_TO_CSTR(resName.package, resName.packageLen),
- CHAR16_TO_CSTR(resName.type, resName.typeLen),
- CHAR16_TO_CSTR(resName.name, resName.nameLen),
- dtohl(typeConfigs->typeSpecFlags[entryIndex]));
+ if (this->getResourceName(resID, &resName)) {
+ printf(" spec resource 0x%08x %s:%s/%s: flags=0x%08x\n",
+ resID,
+ CHAR16_TO_CSTR(resName.package, resName.packageLen),
+ CHAR16_TO_CSTR(resName.type, resName.typeLen),
+ CHAR16_TO_CSTR(resName.name, resName.nameLen),
+ dtohl(typeConfigs->typeSpecFlags[entryIndex]));
+ } else {
+ printf(" INVALID TYPE CONFIG FOR RESOURCE 0x%08x\n", resID);
+ }
}
}
for (size_t configIndex=0; configIndex<NTC; configIndex++) {
@@ -4340,11 +4373,14 @@
| (0x00ff0000 & ((typeIndex+1)<<16))
| (0x0000ffff & (entryIndex));
resource_name resName;
- this->getResourceName(resID, &resName);
- printf(" resource 0x%08x %s:%s/%s: ", resID,
- CHAR16_TO_CSTR(resName.package, resName.packageLen),
- CHAR16_TO_CSTR(resName.type, resName.typeLen),
- CHAR16_TO_CSTR(resName.name, resName.nameLen));
+ if (this->getResourceName(resID, &resName)) {
+ printf(" resource 0x%08x %s:%s/%s: ", resID,
+ CHAR16_TO_CSTR(resName.package, resName.packageLen),
+ CHAR16_TO_CSTR(resName.type, resName.typeLen),
+ CHAR16_TO_CSTR(resName.name, resName.nameLen));
+ } else {
+ printf(" INVALID RESOURCE 0x%08x: ", resID);
+ }
if ((thisOffset&0x3) != 0) {
printf("NON-INTEGER OFFSET: %p\n", (void*)thisOffset);
continue;
@@ -4402,18 +4438,19 @@
print_value(pkg, value);
} else if (bagPtr != NULL) {
const int N = dtohl(bagPtr->count);
- const ResTable_map* mapPtr = (const ResTable_map*)
- (((const uint8_t*)ent) + esize);
+ const uint8_t* baseMapPtr = (const uint8_t*)ent;
+ size_t mapOffset = esize;
+ const ResTable_map* mapPtr = (ResTable_map*)(baseMapPtr+mapOffset);
printf(" Parent=0x%08x, Count=%d\n",
dtohl(bagPtr->parent.ident), N);
- for (int i=0; i<N; i++) {
+ for (int i=0; i<N && mapOffset < (typeSize-sizeof(ResTable_map)); i++) {
printf(" #%i (Key=0x%08x): ",
i, dtohl(mapPtr->name.ident));
value.copyFrom_dtoh(mapPtr->value);
print_value(pkg, value);
const size_t size = dtohs(mapPtr->value.size);
- mapPtr = (ResTable_map*)(((const uint8_t*)mapPtr)
- + size + sizeof(*mapPtr)-sizeof(mapPtr->value));
+ mapOffset += size + sizeof(*mapPtr)-sizeof(mapPtr->value);
+ mapPtr = (ResTable_map*)(baseMapPtr+mapOffset);
}
}
}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index bbbba74..b23dcde 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1525,4 +1525,22 @@
* {@hide}
*/
private IBinder mICallBack = new Binder();
+
+ /**
+ * Checks whether the phone is in silent mode, with or without vibrate.
+ *
+ * @return true if phone is in silent mode, with or without vibrate.
+ *
+ * @see #getRingerMode()
+ *
+ * @hide pending API Council approval
+ */
+ public boolean isSilentMode() {
+ int ringerMode = getRingerMode();
+ boolean silentMode =
+ (ringerMode == RINGER_MODE_SILENT) ||
+ (ringerMode == RINGER_MODE_VIBRATE);
+ return silentMode;
+ }
+
}
diff --git a/media/java/android/media/MtpClient.java b/media/java/android/media/MtpClient.java
new file mode 100644
index 0000000..946a400
--- /dev/null
+++ b/media/java/android/media/MtpClient.java
@@ -0,0 +1,80 @@
+/*
+ * 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.media;
+
+import android.util.Log;
+
+/**
+ * {@hide}
+ */
+public class MtpClient {
+
+ private static final String TAG = "MtpClient";
+
+ static {
+ System.loadLibrary("media_jni");
+ }
+
+ public MtpClient() {
+ native_setup();
+ }
+
+ @Override
+ protected void finalize() {
+ native_finalize();
+ }
+
+ public void start() {
+ mEventThread = new MtpEventThread();
+ mEventThread.start();
+ }
+
+ private class MtpEventThread extends Thread {
+
+ private boolean mDone;
+
+ public MtpEventThread() {
+ super("MtpEventThread");
+ }
+
+ public void run() {
+ Log.d(TAG, "MtpEventThread starting");
+ while (!mDone) {
+ // this will wait for an event from an MTP device
+ native_wait_for_event();
+ }
+ Log.d(TAG, "MtpEventThread exiting");
+ }
+ }
+
+ private void deviceAdded(int id) {
+ Log.d(TAG, "deviceAdded " + id);
+ }
+
+ private void deviceRemoved(int id) {
+ Log.d(TAG, "deviceRemoved " + id);
+ }
+
+ private MtpEventThread mEventThread;
+
+ // used by the JNI code
+ private int mNativeContext;
+
+ private native final void native_setup();
+ private native final void native_finalize();
+ private native void native_wait_for_event();
+}
\ No newline at end of file
diff --git a/media/java/android/media/MtpCursor.java b/media/java/android/media/MtpCursor.java
new file mode 100644
index 0000000..67ca31b
--- /dev/null
+++ b/media/java/android/media/MtpCursor.java
@@ -0,0 +1,170 @@
+/*
+ * 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.media;
+
+import android.database.AbstractWindowedCursor;
+import android.database.CursorWindow;
+import android.provider.Mtp;
+import android.util.Log;
+
+import java.util.HashMap;
+
+/**
+ * Cursor class for MTP content provider
+ * @hide
+ */
+public final class MtpCursor extends AbstractWindowedCursor {
+ static final String TAG = "MtpCursor";
+ static final int NO_COUNT = -1;
+
+ /* constants for mQueryType */
+ public static final int DEVICE = 1;
+ public static final int DEVICE_ID = 2;
+ public static final int STORAGE = 3;
+ public static final int STORAGE_ID = 4;
+ public static final int OBJECT = 5;
+ public static final int OBJECT_ID = 6;
+ public static final int STORAGE_CHILDREN = 7;
+ public static final int OBJECT_CHILDREN = 8;
+
+ private int mQueryType;
+ private int mDeviceID;
+ private int mStorageID;
+ private int mQbjectID;
+
+ /** The names of the columns in the projection */
+ private String[] mColumns;
+
+ /** The number of rows in the cursor */
+ private int mCount = NO_COUNT;
+
+ private final MtpClient mClient;
+
+ public MtpCursor(MtpClient client, int queryType, int deviceID, int storageID, int objectID,
+ String[] projection) {
+
+ mClient = client;
+ mQueryType = queryType;
+ mDeviceID = deviceID;
+ mStorageID = storageID;
+ mQbjectID = objectID;
+ mColumns = projection;
+
+ HashMap<String, Integer> map;
+ switch (queryType) {
+ case DEVICE:
+ case DEVICE_ID:
+ map = sDeviceProjectionMap;
+ break;
+ case STORAGE:
+ case STORAGE_ID:
+ map = sStorageProjectionMap;
+ break;
+ case OBJECT:
+ case OBJECT_ID:
+ case STORAGE_CHILDREN:
+ case OBJECT_CHILDREN:
+ map = sObjectProjectionMap;
+ break;
+ default:
+ throw new IllegalArgumentException("unknown query type " + queryType);
+ }
+
+ int[] columns = new int[projection.length];
+ for (int i = 0; i < projection.length; i++) {
+ Integer id = map.get(projection[i]);
+ if (id == null) {
+ throw new IllegalArgumentException("unknown column " + projection[i]);
+ }
+ columns[i] = id.intValue();
+ }
+ native_setup(client, queryType, deviceID, storageID, objectID, columns);
+ }
+
+ @Override
+ protected void finalize() {
+ native_finalize();
+ }
+
+ @Override
+ public int getCount() {
+ if (mCount == NO_COUNT) {
+ fillWindow(0);
+ }
+ return mCount;
+ }
+
+ private void fillWindow(int startPos) {
+ if (mWindow == null) {
+ // If there isn't a window set already it will only be accessed locally
+ mWindow = new CursorWindow(true /* the window is local only */);
+ } else {
+ mWindow.clear();
+ }
+ mWindow.setStartPosition(startPos);
+ mCount = native_fill_window(mWindow, startPos);
+ }
+
+ @Override
+ public String[] getColumnNames() {
+ Log.d(TAG, "getColumnNames returning " + mColumns);
+ return mColumns;
+ }
+
+ /* Device Column IDs */
+ private static final int DEVICE_ROW_ID = 1;
+ private static final int DEVICE_MANUFACTURER = 2;
+ private static final int DEVICE_MODEL = 3;
+
+ /* Storage Column IDs */
+ private static final int STORAGE_ROW_ID = 101;
+ private static final int STORAGE_IDENTIFIER = 102;
+ private static final int STORAGE_DESCRIPTION = 103;
+
+ /* Object Column IDs */
+ private static final int OBJECT_ROW_ID = 201;
+ private static final int OBJECT_NAME = 202;
+
+ private static HashMap<String, Integer> sDeviceProjectionMap;
+ private static HashMap<String, Integer> sStorageProjectionMap;
+ private static HashMap<String, Integer> sObjectProjectionMap;
+
+ static {
+ sDeviceProjectionMap = new HashMap<String, Integer>();
+ sDeviceProjectionMap.put(Mtp.Device._ID, new Integer(DEVICE_ROW_ID));
+ sDeviceProjectionMap.put(Mtp.Device.MANUFACTURER, new Integer(DEVICE_MANUFACTURER));
+ sDeviceProjectionMap.put(Mtp.Device.MODEL, new Integer(DEVICE_MODEL));
+
+ sStorageProjectionMap = new HashMap<String, Integer>();
+ sStorageProjectionMap.put(Mtp.Storage._ID, new Integer(STORAGE_ROW_ID));
+ sStorageProjectionMap.put(Mtp.Storage.IDENTIFIER, new Integer(STORAGE_IDENTIFIER));
+ sStorageProjectionMap.put(Mtp.Storage.DESCRIPTION, new Integer(STORAGE_DESCRIPTION));
+
+ sObjectProjectionMap = new HashMap<String, Integer>();
+ sObjectProjectionMap.put(Mtp.Object._ID, new Integer(OBJECT_ROW_ID));
+ sObjectProjectionMap.put(Mtp.Object.NAME, new Integer(OBJECT_NAME));
+ }
+
+ // used by the JNI code
+ private int mNativeContext;
+
+ private native final void native_setup(MtpClient client, int queryType,
+ int deviceID, int storageID, int objectID, int[] columns);
+ private native final void native_finalize();
+ private native void native_wait_for_event();
+ private native int native_fill_window(CursorWindow window, int startPos);
+}
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index c77f551..372a927 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -727,7 +727,8 @@
if ((popCount(device) == 1 ) &&
(device & (AudioSystem::DEVICE_OUT_BLUETOOTH_SCO |
AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET |
- AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT))) {
+ AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT |
+ AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET))) {
return true;
} else {
return false;
diff --git a/media/mtp/Android.mk b/media/mtp/Android.mk
new file mode 100644
index 0000000..9f684e1
--- /dev/null
+++ b/media/mtp/Android.mk
@@ -0,0 +1,102 @@
+#
+# 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.
+#
+LOCAL_PATH:= $(call my-dir)
+
+ifneq ($(TARGET_SIMULATOR),true)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ mtptest.cpp \
+ MtpDatabase.cpp \
+ MtpDataPacket.cpp \
+ MtpDebug.cpp \
+ MtpMediaScanner.cpp \
+ MtpPacket.cpp \
+ MtpRequestPacket.cpp \
+ MtpResponsePacket.cpp \
+ MtpServer.cpp \
+ MtpStringBuffer.cpp \
+ MtpStorage.cpp \
+ MtpUtils.cpp \
+ SqliteDatabase.cpp \
+ SqliteStatement.cpp \
+
+LOCAL_MODULE:= mtptest
+
+LOCAL_C_INCLUDES := external/sqlite/dist
+
+LOCAL_CFLAGS := -DMTP_DEVICE
+
+LOCAL_SHARED_LIBRARIES := libutils libsqlite libstagefright libcutils \
+ libmedia
+
+include $(BUILD_EXECUTABLE)
+
+endif
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libmtphost
+
+LOCAL_SRC_FILES:= \
+ MtpClient.cpp \
+ MtpCursor.cpp \
+ MtpDataPacket.cpp \
+ MtpDebug.cpp \
+ MtpDevice.cpp \
+ MtpDeviceInfo.cpp \
+ MtpObjectInfo.cpp \
+ MtpPacket.cpp \
+ MtpProperty.cpp \
+ MtpRequestPacket.cpp \
+ MtpResponsePacket.cpp \
+ MtpStorageInfo.cpp \
+ MtpStringBuffer.cpp \
+ MtpUtils.cpp \
+
+
+LOCAL_CFLAGS := -g -DMTP_HOST
+LOCAL_LDFLAGS := -g
+
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := scantest
+LOCAL_SRC_FILES:= \
+ scantest.cpp \
+ MtpMediaScanner.cpp \
+ MtpDatabase.cpp \
+ MtpDataPacket.cpp \
+ MtpPacket.cpp \
+ MtpStringBuffer.cpp \
+ MtpUtils.cpp \
+ SqliteDatabase.cpp \
+ SqliteStatement.cpp \
+
+
+#LOCAL_STATIC_LIBRARIES := libusbhost
+#LOCAL_LDLIBS := -lpthread
+
+LOCAL_C_INCLUDES := external/sqlite/dist
+LOCAL_SHARED_LIBRARIES := libutils libsqlite libstagefright libmedia
+
+
+LOCAL_CFLAGS := -g
+LOCAL_LDFLAGS := -g
+
+include $(BUILD_EXECUTABLE)
diff --git a/media/mtp/MtpClient.cpp b/media/mtp/MtpClient.cpp
new file mode 100644
index 0000000..31874e9
--- /dev/null
+++ b/media/mtp/MtpClient.cpp
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "MtpClient"
+#include "utils/Log.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <usbhost/usbhost.h>
+#include <linux/version.h>
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20)
+#include <linux/usb/ch9.h>
+#else
+#include <linux/usb_ch9.h>
+#endif
+
+#include "MtpClient.h"
+#include "MtpDevice.h"
+#include "MtpDebug.h"
+
+namespace android {
+
+MtpClient::MtpClient()
+ : mStarted(false)
+{
+}
+
+MtpClient::~MtpClient() {
+}
+
+bool MtpClient::start() {
+ if (mStarted)
+ return true;
+
+ if (usb_host_init(usb_device_added, usb_device_removed, this)) {
+ LOGE("MtpClient::start failed\n");
+ return false;
+ }
+ mStarted = true;
+ return true;
+}
+
+void MtpClient::usbDeviceAdded(const char *devname) {
+ struct usb_descriptor_header* desc;
+ struct usb_descriptor_iter iter;
+
+ struct usb_device *device = usb_device_open(devname);
+ if (!device) {
+ LOGE("usb_device_open failed\n");
+ return;
+ }
+
+ usb_descriptor_iter_init(device, &iter);
+
+ while ((desc = usb_descriptor_iter_next(&iter)) != NULL) {
+ if (desc->bDescriptorType == USB_DT_INTERFACE) {
+ struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)desc;
+
+ if (interface->bInterfaceClass == USB_CLASS_STILL_IMAGE &&
+ interface->bInterfaceSubClass == 1 && // Still Image Capture
+ interface->bInterfaceProtocol == 1) // Picture Transfer Protocol (PIMA 15470)
+ {
+ LOGD("Found camera: \"%s\" \"%s\"\n", usb_device_get_manufacturer_name(device),
+ usb_device_get_product_name(device));
+
+ // interface should be followed by three endpoints
+ struct usb_endpoint_descriptor *ep;
+ struct usb_endpoint_descriptor *ep_in_desc = NULL;
+ struct usb_endpoint_descriptor *ep_out_desc = NULL;
+ struct usb_endpoint_descriptor *ep_intr_desc = NULL;
+ for (int i = 0; i < 3; i++) {
+ ep = (struct usb_endpoint_descriptor *)usb_descriptor_iter_next(&iter);
+ if (!ep || ep->bDescriptorType != USB_DT_ENDPOINT) {
+ LOGE("endpoints not found\n");
+ return;
+ }
+ if (ep->bmAttributes == USB_ENDPOINT_XFER_BULK) {
+ if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+ ep_in_desc = ep;
+ else
+ ep_out_desc = ep;
+ } else if (ep->bmAttributes == USB_ENDPOINT_XFER_INT &&
+ ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
+ ep_intr_desc = ep;
+ }
+ }
+ if (!ep_in_desc || !ep_out_desc || !ep_intr_desc) {
+ LOGE("endpoints not found\n");
+ return;
+ }
+
+ struct usb_endpoint *ep_in = usb_endpoint_open(device, ep_in_desc);
+ struct usb_endpoint *ep_out = usb_endpoint_open(device, ep_out_desc);
+ struct usb_endpoint *ep_intr = usb_endpoint_open(device, ep_intr_desc);
+
+ if (usb_device_claim_interface(device, interface->bInterfaceNumber)) {
+ LOGE("usb_device_claim_interface failed\n");
+ usb_endpoint_close(ep_in);
+ usb_endpoint_close(ep_out);
+ usb_endpoint_close(ep_intr);
+ return;
+ }
+
+ MtpDevice* mtpDevice = new MtpDevice(device, interface->bInterfaceNumber,
+ ep_in, ep_out, ep_intr);
+ mDeviceList.add(mtpDevice);
+ mtpDevice->initialize();
+ deviceAdded(mtpDevice);
+ return;
+ }
+ }
+ }
+
+ usb_device_close(device);
+}
+
+MtpDevice* MtpClient::getDevice(int id) {
+ for (int i = 0; i < mDeviceList.size(); i++) {
+ MtpDevice* device = mDeviceList[i];
+ if (device->getID() == id)
+ return device;
+ }
+ return NULL;
+}
+
+void MtpClient::usbDeviceRemoved(const char *devname) {
+ for (int i = 0; i < mDeviceList.size(); i++) {
+ MtpDevice* device = mDeviceList[i];
+ if (!strcmp(devname, device->getDeviceName())) {
+ deviceRemoved(device);
+ mDeviceList.removeAt(i);
+ delete device;
+ LOGD("Camera removed!\n");
+ break;
+ }
+ }
+}
+
+void MtpClient::usb_device_added(const char *devname, void* client_data) {
+ LOGD("usb_device_added %s\n", devname);
+ ((MtpClient *)client_data)->usbDeviceAdded(devname);
+}
+
+void MtpClient::usb_device_removed(const char *devname, void* client_data) {
+ LOGD("usb_device_removed %s\n", devname);
+ ((MtpClient *)client_data)->usbDeviceRemoved(devname);
+}
+
+} // namespace android
diff --git a/media/mtp/MtpClient.h b/media/mtp/MtpClient.h
new file mode 100644
index 0000000..d87c226
--- /dev/null
+++ b/media/mtp/MtpClient.h
@@ -0,0 +1,51 @@
+/*
+ * 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 _MTP_CLIENT_H
+#define _MTP_CLIENT_H
+
+#include "MtpTypes.h"
+
+namespace android {
+
+class MtpClient {
+private:
+ MtpDeviceList mDeviceList;
+ bool mStarted;
+
+public:
+ MtpClient();
+ virtual ~MtpClient();
+
+ bool start();
+
+ inline MtpDeviceList& getDeviceList() { return mDeviceList; }
+ MtpDevice* getDevice(int id);
+
+
+ virtual void deviceAdded(MtpDevice *device) = 0;
+ virtual void deviceRemoved(MtpDevice *device) = 0;
+
+private:
+ void usbDeviceAdded(const char *devname);
+ void usbDeviceRemoved(const char *devname);
+ static void usb_device_added(const char *devname, void* client_data);
+ static void usb_device_removed(const char *devname, void* client_data);
+};
+
+}; // namespace android
+
+#endif // _MTP_CLIENT_H
diff --git a/media/mtp/MtpCursor.cpp b/media/mtp/MtpCursor.cpp
new file mode 100644
index 0000000..9c9ce64
--- /dev/null
+++ b/media/mtp/MtpCursor.cpp
@@ -0,0 +1,332 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "MtpCursor"
+#include "utils/Log.h"
+
+#include "MtpClient.h"
+#include "MtpCursor.h"
+#include "MtpDevice.h"
+#include "MtpDeviceInfo.h"
+#include "MtpObjectInfo.h"
+#include "MtpStorageInfo.h"
+
+#include "binder/CursorWindow.h"
+
+namespace android {
+
+/* Device Column IDs */
+#define DEVICE_ROW_ID 1
+#define DEVICE_MANUFACTURER 2
+#define DEVICE_MODEL 3
+
+/* Storage Column IDs */
+#define STORAGE_ROW_ID 101
+#define STORAGE_IDENTIFIER 102
+#define STORAGE_DESCRIPTION 103
+
+/* Object Column IDs */
+#define OBJECT_ROW_ID 201
+#define OBJECT_NAME 202
+
+MtpCursor::MtpCursor(MtpClient* client, int queryType, int deviceID,
+ int storageID, int objectID, int columnCount, int* columns)
+ : mClient(client),
+ mQueryType(queryType),
+ mDeviceID(deviceID),
+ mStorageID(storageID),
+ mQbjectID(objectID),
+ mColumnCount(columnCount),
+ mColumns(NULL)
+{
+ if (columns) {
+ mColumns = new int[columnCount];
+ memcpy(mColumns, columns, columnCount * sizeof(int));
+ }
+}
+
+MtpCursor::~MtpCursor() {
+ delete[] mColumns;
+}
+
+int MtpCursor::fillWindow(CursorWindow* window, int startPos) {
+ LOGD("MtpCursor::fillWindow mQueryType: %d\n", mQueryType);
+
+ switch (mQueryType) {
+ case DEVICE:
+ return fillDevices(window, startPos);
+ case DEVICE_ID:
+ return fillDevice(window, startPos);
+ case STORAGE:
+ return fillStorages(window, startPos);
+ case STORAGE_ID:
+ return fillStorage(window, startPos);
+ case OBJECT:
+ return fillObjects(window, 0, startPos);
+ case OBJECT_ID:
+ return fillObject(window, startPos);
+ case STORAGE_CHILDREN:
+ return fillObjects(window, -1, startPos);
+ case OBJECT_CHILDREN:
+ return fillObjects(window, mQbjectID, startPos);
+ default:
+ LOGE("MtpCursor::fillWindow: unknown query type %d\n", mQueryType);
+ return 0;
+ }
+}
+
+int MtpCursor::fillDevices(CursorWindow* window, int startPos) {
+ int count = 0;
+ MtpDeviceList& deviceList = mClient->getDeviceList();
+ for (int i = 0; i < deviceList.size(); i++) {
+ MtpDevice* device = deviceList[i];
+ if (fillDevice(window, device, startPos)) {
+ count++;
+ startPos++;
+ } else {
+ break;
+ }
+ }
+ return count;
+}
+
+int MtpCursor::fillDevice(CursorWindow* window, int startPos) {
+ MtpDevice* device = mClient->getDevice(mDeviceID);
+ if (device && fillDevice(window, device, startPos))
+ return 1;
+ else
+ return 0;
+}
+
+int MtpCursor::fillStorages(CursorWindow* window, int startPos) {
+ int count = 0;
+ MtpDevice* device = mClient->getDevice(mDeviceID);
+ if (!device)
+ return 0;
+ MtpStorageIDList* storageIDs = device->getStorageIDs();
+ if (!storageIDs)
+ return 0;
+
+ for (int i = 0; i < storageIDs->size(); i++) {
+ MtpStorageID storageID = (*storageIDs)[i];
+ if (fillStorage(window, device, storageID, startPos)) {
+ count++;
+ startPos++;
+ } else {
+ break;
+ }
+ }
+ delete storageIDs;
+ return count;
+}
+
+int MtpCursor::fillStorage(CursorWindow* window, int startPos) {
+ MtpDevice* device = mClient->getDevice(mDeviceID);
+ if (device && fillStorage(window, device, mStorageID, startPos))
+ return 1;
+ else
+ return 0;
+}
+
+int MtpCursor::fillObjects(CursorWindow* window, int parent, int startPos) {
+ int count = 0;
+ MtpDevice* device = mClient->getDevice(mDeviceID);
+ if (!device)
+ return 0;
+ MtpObjectHandleList* handles = device->getObjectHandles(mStorageID, 0, parent);
+ if (!handles)
+ return 0;
+
+ for (int i = 0; i < handles->size(); i++) {
+ MtpObjectHandle handle = (*handles)[i];
+ if (fillObject(window, device, handle, startPos)) {
+ count++;
+ startPos++;
+ } else {
+ break;
+ }
+ }
+ delete handles;
+ return count;
+}
+
+int MtpCursor::fillObject(CursorWindow* window, int startPos) {
+ MtpDevice* device = mClient->getDevice(mDeviceID);
+ if (device && fillObject(window, device, mQbjectID, startPos))
+ return 1;
+ else
+ return 0;
+}
+
+bool MtpCursor::fillDevice(CursorWindow* window, MtpDevice* device, int row) {
+ MtpDeviceInfo* deviceInfo = device->getDeviceInfo();
+ if (!deviceInfo)
+ return false;
+ if (!prepareRow(window))
+ return false;
+
+ for (int i = 0; i < mColumnCount; i++) {
+ switch (mColumns[i]) {
+ case DEVICE_ROW_ID:
+ if (!putLong(window, device->getID(), row, i))
+ return false;
+ break;
+ case DEVICE_MANUFACTURER:
+ if (!putString(window, deviceInfo->mManufacturer, row, i))
+ return false;
+ break;
+ case DEVICE_MODEL:
+ if (!putString(window, deviceInfo->mModel, row, i))
+ return false;
+ break;
+ default:
+ LOGE("fillDevice: unknown column %d\n", mColumns[i]);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool MtpCursor::fillStorage(CursorWindow* window, MtpDevice* device,
+ MtpStorageID storageID, int row) {
+
+LOGD("fillStorage %d\n", storageID);
+
+ MtpStorageInfo* storageInfo = device->getStorageInfo(storageID);
+ if (!storageInfo)
+ return false;
+ if (!prepareRow(window)) {
+ delete storageInfo;
+ return false;
+ }
+
+ const char* text;
+ for (int i = 0; i < mColumnCount; i++) {
+ switch (mColumns[i]) {
+ case STORAGE_ROW_ID:
+ if (!putLong(window, storageID, row, i))
+ goto fail;
+ break;
+ case STORAGE_IDENTIFIER:
+ text = storageInfo->mVolumeIdentifier;
+ if (!text || !text[0])
+ text = "Camera Storage";
+ if (!putString(window, text, row, i))
+ goto fail;
+ break;
+ case STORAGE_DESCRIPTION:
+ text = storageInfo->mStorageDescription;
+ if (!text || !text[0])
+ text = "Storage Description";
+ if (!putString(window, text, row, i))
+ goto fail;
+ break;
+ default:
+ LOGE("fillStorage: unknown column %d\n", mColumns[i]);
+ goto fail;
+ }
+ }
+
+ delete storageInfo;
+ return true;
+
+fail:
+ delete storageInfo;
+ return false;
+}
+
+bool MtpCursor::fillObject(CursorWindow* window, MtpDevice* device,
+ MtpObjectHandle objectID, int row) {
+
+LOGD("fillObject %d\n", objectID);
+
+ MtpObjectInfo* objectInfo = device->getObjectInfo(objectID);
+ if (!objectInfo)
+ return false;
+ if (!prepareRow(window)) {
+ delete objectInfo;
+ return false;
+ }
+
+ for (int i = 0; i < mColumnCount; i++) {
+ switch (mColumns[i]) {
+ case OBJECT_ROW_ID:
+ if (!putLong(window, objectID, row, i))
+ goto fail;
+ break;
+ case OBJECT_NAME:
+ if (!putString(window, objectInfo->mName, row, i))
+ goto fail;
+ break;
+ default:
+ LOGE("fillStorage: unknown column %d\n", mColumns[i]);
+ goto fail;
+ }
+ }
+
+ delete objectInfo;
+ return true;
+
+fail:
+ delete objectInfo;
+ return false;
+}
+
+bool MtpCursor::prepareRow(CursorWindow* window) {
+ if (!window->setNumColumns(mColumnCount)) {
+ LOGE("Failed to change column count from %d to %d", window->getNumColumns(), mColumnCount);
+ return false;
+ }
+ field_slot_t * fieldDir = window->allocRow();
+ if (!fieldDir) {
+ LOGE("Failed allocating fieldDir");
+ return false;
+ }
+ return true;
+}
+
+
+bool MtpCursor::putLong(CursorWindow* window, int value, int row, int column) {
+
+ if (!window->putLong(row, column, value)) {
+ window->freeLastRow();
+ LOGE("Failed allocating space for a long in column %d", column);
+ return false;
+ }
+ return true;
+}
+
+bool MtpCursor::putString(CursorWindow* window, const char* text, int row, int column) {
+ int size = strlen(text) + 1;
+ int offset = window->alloc(size);
+ if (!offset) {
+ window->freeLastRow();
+ LOGE("Failed allocating %u bytes for text/blob %s", size, text);
+ return false;
+ }
+ window->copyIn(offset, (const uint8_t*)text, size);
+
+ // This must be updated after the call to alloc(), since that
+ // may move the field around in the window
+ field_slot_t * fieldSlot = window->getFieldSlot(row, column);
+ fieldSlot->type = FIELD_TYPE_STRING;
+ fieldSlot->data.buffer.offset = offset;
+ fieldSlot->data.buffer.size = size;
+ return true;
+}
+
+} // namespace android
diff --git a/media/mtp/MtpCursor.h b/media/mtp/MtpCursor.h
new file mode 100644
index 0000000..422f0c92
--- /dev/null
+++ b/media/mtp/MtpCursor.h
@@ -0,0 +1,75 @@
+/*
+ * 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 _MTP_CURSOR_H
+#define _MTP_CURSOR_H
+
+#include "MtpTypes.h"
+
+namespace android {
+
+class CursorWindow;
+
+class MtpCursor {
+private:
+ enum {
+ DEVICE = 1,
+ DEVICE_ID = 2,
+ STORAGE = 3,
+ STORAGE_ID = 4,
+ OBJECT = 5,
+ OBJECT_ID = 6,
+ STORAGE_CHILDREN = 7,
+ OBJECT_CHILDREN = 8,
+ };
+
+ MtpClient* mClient;
+ int mQueryType;
+ int mDeviceID;
+ int mStorageID;
+ int mQbjectID;
+ int mColumnCount;
+ int* mColumns;
+
+public:
+ MtpCursor(MtpClient* client, int queryType, int deviceID,
+ int storageID, int objectID, int columnCount, int* columns);
+ virtual ~MtpCursor();
+
+ int fillWindow(CursorWindow* window, int startPos);
+
+private:
+ int fillDevices(CursorWindow* window, int startPos);
+ int fillDevice(CursorWindow* window, int startPos);
+ int fillStorages(CursorWindow* window, int startPos);
+ int fillStorage(CursorWindow* window, int startPos);
+ int fillObjects(CursorWindow* window, int parent, int startPos);
+ int fillObject(CursorWindow* window, int startPos);
+
+ bool fillDevice(CursorWindow* window, MtpDevice* device, int startPos);
+ bool fillStorage(CursorWindow* window, MtpDevice* device,
+ MtpStorageID storageID, int row);
+ bool fillObject(CursorWindow* window, MtpDevice* device,
+ MtpObjectHandle objectID, int row);
+
+ bool prepareRow(CursorWindow* window);
+ bool putLong(CursorWindow* window, int value, int row, int column);
+ bool putString(CursorWindow* window, const char* text, int row, int column);
+};
+
+}; // namespace android
+
+#endif // _MTP_CURSOR_H
diff --git a/media/mtp/MtpDataPacket.cpp b/media/mtp/MtpDataPacket.cpp
new file mode 100644
index 0000000..f96284c
--- /dev/null
+++ b/media/mtp/MtpDataPacket.cpp
@@ -0,0 +1,385 @@
+/*
+ * 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 <stdio.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+#include "MtpDataPacket.h"
+#include "MtpStringBuffer.h"
+
+namespace android {
+
+MtpDataPacket::MtpDataPacket()
+ : MtpPacket(512),
+ mOffset(MTP_CONTAINER_HEADER_SIZE)
+{
+}
+
+MtpDataPacket::~MtpDataPacket() {
+}
+
+void MtpDataPacket::reset() {
+ MtpPacket::reset();
+ mOffset = MTP_CONTAINER_HEADER_SIZE;
+}
+
+void MtpDataPacket::setOperationCode(MtpOperationCode code) {
+ MtpPacket::putUInt16(MTP_CONTAINER_CODE_OFFSET, code);
+}
+
+void MtpDataPacket::setTransactionID(MtpTransactionID id) {
+ MtpPacket::putUInt32(MTP_CONTAINER_TRANSACTION_ID_OFFSET, id);
+}
+
+uint16_t MtpDataPacket::getUInt16() {
+ int offset = mOffset;
+ uint16_t result = (uint16_t)mBuffer[offset] | ((uint16_t)mBuffer[offset + 1] << 8);
+ mOffset += 2;
+ return result;
+}
+
+uint32_t MtpDataPacket::getUInt32() {
+ int offset = mOffset;
+ uint32_t result = (uint32_t)mBuffer[offset] | ((uint32_t)mBuffer[offset + 1] << 8) |
+ ((uint32_t)mBuffer[offset + 2] << 16) | ((uint32_t)mBuffer[offset + 3] << 24);
+ mOffset += 4;
+ return result;
+}
+
+uint64_t MtpDataPacket::getUInt64() {
+ int offset = mOffset;
+ uint64_t result = (uint64_t)mBuffer[offset] | ((uint64_t)mBuffer[offset + 1] << 8) |
+ ((uint64_t)mBuffer[offset + 2] << 16) | ((uint64_t)mBuffer[offset + 3] << 24) |
+ ((uint64_t)mBuffer[offset + 4] << 32) | ((uint64_t)mBuffer[offset + 5] << 40) |
+ ((uint64_t)mBuffer[offset + 6] << 48) | ((uint64_t)mBuffer[offset + 7] << 56);
+ mOffset += 8;
+ return result;
+}
+
+void MtpDataPacket::getUInt128(uint128_t& value) {
+ value[0] = getUInt32();
+ value[1] = getUInt32();
+ value[2] = getUInt32();
+ value[3] = getUInt32();
+}
+
+void MtpDataPacket::getString(MtpStringBuffer& string)
+{
+ string.readFromPacket(this);
+}
+
+Int8List* MtpDataPacket::getAInt8() {
+ Int8List* result = new Int8List;
+ int count = getUInt32();
+ for (int i = 0; i < count; i++)
+ result->push(getInt8());
+ return result;
+}
+
+UInt8List* MtpDataPacket::getAUInt8() {
+ UInt8List* result = new UInt8List;
+ int count = getUInt32();
+ for (int i = 0; i < count; i++)
+ result->push(getUInt8());
+ return result;
+}
+
+Int16List* MtpDataPacket::getAInt16() {
+ Int16List* result = new Int16List;
+ int count = getUInt32();
+ for (int i = 0; i < count; i++)
+ result->push(getInt16());
+ return result;
+}
+
+UInt16List* MtpDataPacket::getAUInt16() {
+ UInt16List* result = new UInt16List;
+ int count = getUInt32();
+ for (int i = 0; i < count; i++)
+ result->push(getUInt16());
+ return result;
+}
+
+Int32List* MtpDataPacket::getAInt32() {
+ Int32List* result = new Int32List;
+ int count = getUInt32();
+ for (int i = 0; i < count; i++)
+ result->push(getInt32());
+ return result;
+}
+
+UInt32List* MtpDataPacket::getAUInt32() {
+ UInt32List* result = new UInt32List;
+ int count = getUInt32();
+ for (int i = 0; i < count; i++)
+ result->push(getUInt32());
+ return result;
+}
+
+Int64List* MtpDataPacket::getAInt64() {
+ Int64List* result = new Int64List;
+ int count = getUInt32();
+ for (int i = 0; i < count; i++)
+ result->push(getInt64());
+ return result;
+}
+
+UInt64List* MtpDataPacket::getAUInt64() {
+ UInt64List* result = new UInt64List;
+ int count = getUInt32();
+ for (int i = 0; i < count; i++)
+ result->push(getUInt64());
+ return result;
+}
+
+void MtpDataPacket::putInt8(int8_t value) {
+ allocate(mOffset + 1);
+ mBuffer[mOffset++] = (uint8_t)value;
+ if (mPacketSize < mOffset)
+ mPacketSize = mOffset;
+}
+
+void MtpDataPacket::putUInt8(uint8_t value) {
+ allocate(mOffset + 1);
+ mBuffer[mOffset++] = (uint8_t)value;
+ if (mPacketSize < mOffset)
+ mPacketSize = mOffset;
+}
+
+void MtpDataPacket::putInt16(int16_t value) {
+ allocate(mOffset + 2);
+ mBuffer[mOffset++] = (uint8_t)(value & 0xFF);
+ mBuffer[mOffset++] = (uint8_t)((value >> 8) & 0xFF);
+ if (mPacketSize < mOffset)
+ mPacketSize = mOffset;
+}
+
+void MtpDataPacket::putUInt16(uint16_t value) {
+ allocate(mOffset + 2);
+ mBuffer[mOffset++] = (uint8_t)(value & 0xFF);
+ mBuffer[mOffset++] = (uint8_t)((value >> 8) & 0xFF);
+ if (mPacketSize < mOffset)
+ mPacketSize = mOffset;
+}
+
+void MtpDataPacket::putInt32(int32_t value) {
+ allocate(mOffset + 4);
+ mBuffer[mOffset++] = (uint8_t)(value & 0xFF);
+ mBuffer[mOffset++] = (uint8_t)((value >> 8) & 0xFF);
+ mBuffer[mOffset++] = (uint8_t)((value >> 16) & 0xFF);
+ mBuffer[mOffset++] = (uint8_t)((value >> 24) & 0xFF);
+ if (mPacketSize < mOffset)
+ mPacketSize = mOffset;
+}
+
+void MtpDataPacket::putUInt32(uint32_t value) {
+ allocate(mOffset + 4);
+ mBuffer[mOffset++] = (uint8_t)(value & 0xFF);
+ mBuffer[mOffset++] = (uint8_t)((value >> 8) & 0xFF);
+ mBuffer[mOffset++] = (uint8_t)((value >> 16) & 0xFF);
+ mBuffer[mOffset++] = (uint8_t)((value >> 24) & 0xFF);
+ if (mPacketSize < mOffset)
+ mPacketSize = mOffset;
+}
+
+void MtpDataPacket::putInt64(int64_t value) {
+ allocate(mOffset + 8);
+ mBuffer[mOffset++] = (uint8_t)(value & 0xFF);
+ mBuffer[mOffset++] = (uint8_t)((value >> 8) & 0xFF);
+ mBuffer[mOffset++] = (uint8_t)((value >> 16) & 0xFF);
+ mBuffer[mOffset++] = (uint8_t)((value >> 24) & 0xFF);
+ mBuffer[mOffset++] = (uint8_t)((value >> 32) & 0xFF);
+ mBuffer[mOffset++] = (uint8_t)((value >> 40) & 0xFF);
+ mBuffer[mOffset++] = (uint8_t)((value >> 48) & 0xFF);
+ mBuffer[mOffset++] = (uint8_t)((value >> 56) & 0xFF);
+ if (mPacketSize < mOffset)
+ mPacketSize = mOffset;
+}
+
+void MtpDataPacket::putUInt64(uint64_t value) {
+ allocate(mOffset + 8);
+ mBuffer[mOffset++] = (uint8_t)(value & 0xFF);
+ mBuffer[mOffset++] = (uint8_t)((value >> 8) & 0xFF);
+ mBuffer[mOffset++] = (uint8_t)((value >> 16) & 0xFF);
+ mBuffer[mOffset++] = (uint8_t)((value >> 24) & 0xFF);
+ mBuffer[mOffset++] = (uint8_t)((value >> 32) & 0xFF);
+ mBuffer[mOffset++] = (uint8_t)((value >> 40) & 0xFF);
+ mBuffer[mOffset++] = (uint8_t)((value >> 48) & 0xFF);
+ mBuffer[mOffset++] = (uint8_t)((value >> 56) & 0xFF);
+ if (mPacketSize < mOffset)
+ mPacketSize = mOffset;
+}
+
+void MtpDataPacket::putInt128(const int128_t& value) {
+ putInt32(value[0]);
+ putInt32(value[1]);
+ putInt32(value[2]);
+ putInt32(value[3]);
+}
+
+void MtpDataPacket::putUInt128(const uint128_t& value) {
+ putUInt32(value[0]);
+ putUInt32(value[1]);
+ putUInt32(value[2]);
+ putUInt32(value[3]);
+}
+
+void MtpDataPacket::putAInt8(const int8_t* values, int count) {
+ putUInt32(count);
+ for (int i = 0; i < count; i++)
+ putInt8(*values++);
+}
+
+void MtpDataPacket::putAUInt8(const uint8_t* values, int count) {
+ putUInt32(count);
+ for (int i = 0; i < count; i++)
+ putUInt8(*values++);
+}
+
+void MtpDataPacket::putAInt16(const int16_t* values, int count) {
+ putUInt32(count);
+ for (int i = 0; i < count; i++)
+ putInt16(*values++);
+}
+
+void MtpDataPacket::putAUInt16(const uint16_t* values, int count) {
+ putUInt32(count);
+ for (int i = 0; i < count; i++)
+ putUInt16(*values++);
+}
+
+void MtpDataPacket::putAInt32(const int32_t* values, int count) {
+ putUInt32(count);
+ for (int i = 0; i < count; i++)
+ putInt32(*values++);
+}
+
+void MtpDataPacket::putAUInt32(const uint32_t* values, int count) {
+ putUInt32(count);
+ for (int i = 0; i < count; i++)
+ putUInt32(*values++);
+}
+
+void MtpDataPacket::putAUInt32(const UInt32List* list) {
+ if (!list) {
+ putEmptyArray();
+ } else {
+ size_t size = list->size();
+ putUInt32(size);
+ for (size_t i = 0; i < size; i++)
+ putUInt32((*list)[i]);
+ }
+}
+
+void MtpDataPacket::putAInt64(const int64_t* values, int count) {
+ putUInt32(count);
+ for (int i = 0; i < count; i++)
+ putInt64(*values++);
+}
+
+void MtpDataPacket::putAUInt64(const uint64_t* values, int count) {
+ putUInt32(count);
+ for (int i = 0; i < count; i++)
+ putUInt64(*values++);
+}
+
+void MtpDataPacket::putString(const MtpStringBuffer& string)
+{
+ string.writeToPacket(this);
+}
+
+void MtpDataPacket::putString(const char* s)
+{
+ MtpStringBuffer string(s);
+ string.writeToPacket(this);
+}
+
+#ifdef MTP_DEVICE
+int MtpDataPacket::read(int fd) {
+ // first read the header
+ int ret = ::read(fd, mBuffer, MTP_CONTAINER_HEADER_SIZE);
+printf("MtpDataPacket::read 1 returned %d\n", ret);
+ if (ret != MTP_CONTAINER_HEADER_SIZE)
+ return -1;
+ // then the following data
+ int total = MtpPacket::getUInt32(MTP_CONTAINER_LENGTH_OFFSET);
+ int remaining = total - MTP_CONTAINER_HEADER_SIZE;
+printf("total: %d, remaining: %d\n", total, remaining);
+ ret = ::read(fd, &mBuffer[0] + MTP_CONTAINER_HEADER_SIZE, remaining);
+printf("MtpDataPacket::read 2 returned %d\n", ret);
+ if (ret != remaining)
+ return -1;
+
+ mPacketSize = total;
+ mOffset = MTP_CONTAINER_HEADER_SIZE;
+ return total;
+}
+
+int MtpDataPacket::readDataHeader(int fd) {
+ int ret = ::read(fd, mBuffer, MTP_CONTAINER_HEADER_SIZE);
+ if (ret > 0)
+ mPacketSize = ret;
+ else
+ mPacketSize = 0;
+ return ret;
+}
+
+int MtpDataPacket::write(int fd) {
+ MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, mPacketSize);
+ MtpPacket::putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_DATA);
+
+ // send header separately from data
+ int ret = ::write(fd, mBuffer, MTP_CONTAINER_HEADER_SIZE);
+ if (ret == MTP_CONTAINER_HEADER_SIZE)
+ ret = ::write(fd, mBuffer + MTP_CONTAINER_HEADER_SIZE,
+ mPacketSize - MTP_CONTAINER_HEADER_SIZE);
+ return (ret < 0 ? ret : 0);
+}
+
+int MtpDataPacket::writeDataHeader(int fd, uint32_t length) {
+ MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, length);
+ MtpPacket::putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_DATA);
+ int ret = ::write(fd, mBuffer, MTP_CONTAINER_HEADER_SIZE);
+ return (ret < 0 ? ret : 0);
+}
+#endif // MTP_DEVICE
+
+#ifdef MTP_HOST
+int MtpDataPacket::read(struct usb_endpoint *ep) {
+ // first read the header
+ int ret = transfer(ep, mBuffer, mBufferSize);
+printf("MtpDataPacket::transfer returned %d\n", ret);
+ if (ret >= 0)
+ mPacketSize = ret;
+ return ret;
+}
+
+int MtpDataPacket::write(struct usb_endpoint *ep) {
+ MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, mPacketSize);
+ MtpPacket::putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_DATA);
+
+ // send header separately from data
+ int ret = transfer(ep, mBuffer, MTP_CONTAINER_HEADER_SIZE);
+ if (ret == MTP_CONTAINER_HEADER_SIZE)
+ ret = transfer(ep, mBuffer + MTP_CONTAINER_HEADER_SIZE,
+ mPacketSize - MTP_CONTAINER_HEADER_SIZE);
+ return (ret < 0 ? ret : 0);
+}
+
+#endif // MTP_HOST
+
+} // namespace android
diff --git a/media/mtp/MtpDataPacket.h b/media/mtp/MtpDataPacket.h
new file mode 100644
index 0000000..4e743b2
--- /dev/null
+++ b/media/mtp/MtpDataPacket.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _MTP_DATA_PACKET_H
+#define _MTP_DATA_PACKET_H
+
+#include "MtpPacket.h"
+#include "mtp.h"
+
+namespace android {
+
+class MtpDataPacket : public MtpPacket {
+private:
+ // current offset for get/put methods
+ int mOffset;
+
+public:
+ MtpDataPacket();
+ virtual ~MtpDataPacket();
+
+ virtual void reset();
+
+ void setOperationCode(MtpOperationCode code);
+ void setTransactionID(MtpTransactionID id);
+
+ inline uint8_t getUInt8() { return (uint8_t)mBuffer[mOffset++]; }
+ inline int8_t getInt8() { return (int8_t)mBuffer[mOffset++]; }
+ uint16_t getUInt16();
+ inline int16_t getInt16() { return (int16_t)getUInt16(); }
+ uint32_t getUInt32();
+ inline int32_t getInt32() { return (int32_t)getUInt32(); }
+ uint64_t getUInt64();
+ inline int64_t getInt64() { return (int64_t)getUInt64(); }
+ void getUInt128(uint128_t& value);
+ inline void getInt128(int128_t& value) { getUInt128((uint128_t&)value); }
+ void getString(MtpStringBuffer& string);
+
+ Int8List* getAInt8();
+ UInt8List* getAUInt8();
+ Int16List* getAInt16();
+ UInt16List* getAUInt16();
+ Int32List* getAInt32();
+ UInt32List* getAUInt32();
+ Int64List* getAInt64();
+ UInt64List* getAUInt64();
+
+ void putInt8(int8_t value);
+ void putUInt8(uint8_t value);
+ void putInt16(int16_t value);
+ void putUInt16(uint16_t value);
+ void putInt32(int32_t value);
+ void putUInt32(uint32_t value);
+ void putInt64(int64_t value);
+ void putUInt64(uint64_t value);
+ void putInt128(const int128_t& value);
+ void putUInt128(const uint128_t& value);
+
+ void putAInt8(const int8_t* values, int count);
+ void putAUInt8(const uint8_t* values, int count);
+ void putAInt16(const int16_t* values, int count);
+ void putAUInt16(const uint16_t* values, int count);
+ void putAInt32(const int32_t* values, int count);
+ void putAUInt32(const uint32_t* values, int count);
+ void putAUInt32(const UInt32List* list);
+ void putAInt64(const int64_t* values, int count);
+ void putAUInt64(const uint64_t* values, int count);
+ void putString(const MtpStringBuffer& string);
+ void putString(const char* string);
+ inline void putEmptyString() { putUInt16(0); }
+ inline void putEmptyArray() { putUInt32(0); }
+
+
+#ifdef MTP_DEVICE
+ // fill our buffer with data from the given file descriptor
+ int read(int fd);
+ int readDataHeader(int fd);
+
+ // write our data to the given file descriptor
+ int write(int fd);
+ int writeDataHeader(int fd, uint32_t length);
+#endif
+
+#ifdef MTP_HOST
+ int read(struct usb_endpoint *ep);
+ int write(struct usb_endpoint *ep);
+#endif
+
+ inline bool hasData() const { return mPacketSize > MTP_CONTAINER_HEADER_SIZE; }
+};
+
+}; // namespace android
+
+#endif // _MTP_DATA_PACKET_H
diff --git a/media/mtp/MtpDatabase.cpp b/media/mtp/MtpDatabase.cpp
new file mode 100644
index 0000000..775a070
--- /dev/null
+++ b/media/mtp/MtpDatabase.cpp
@@ -0,0 +1,577 @@
+/*
+ * 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 "MtpDatabase.h"
+#include "MtpDataPacket.h"
+#include "MtpUtils.h"
+#include "SqliteDatabase.h"
+#include "SqliteStatement.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sqlite3.h>
+
+namespace android {
+
+#define FILE_ID_COLUMN 1
+#define FILE_PATH_COLUMN 2
+#define FILE_FORMAT_COLUMN 3
+#define FILE_PARENT_COLUMN 4
+#define FILE_STORAGE_COLUMN 5
+#define FILE_SIZE_COLUMN 6
+#define FILE_MODIFIED_COLUMN 7
+
+#define AUDIO_ID_COLUMN 1
+#define AUDIO_TITLE_COLUMN 2
+#define AUDIO_ARTIST_COLUMN 3
+#define AUDIO_ALBUM_COLUMN 4
+#define AUDIO_ALBUM_ARTIST_COLUMN 5
+#define AUDIO_GENRE_COLUMN 6
+#define AUDIO_COMPOSER_COLUMN 7
+#define AUDIO_TRACK_NUMBER_COLUMN 8
+#define AUDIO_YEAR_COLUMN 9
+#define AUDIO_DURATION_COLUMN 10
+#define AUDIO_USE_COUNT_COLUMN 11
+#define AUDIO_SAMPLE_RATE_COLUMN 12
+#define AUDIO_NUM_CHANNELS_COLUMN 13
+#define AUDIO_AUDIO_WAVE_CODEC_COLUMN 14
+#define AUDIO_AUDIO_BIT_RATE_COLUMN 15
+
+#define FILE_TABLE_CREATE "CREATE TABLE IF NOT EXISTS files (" \
+ "_id INTEGER PRIMARY KEY," \
+ "path TEXT," \
+ "format INTEGER," \
+ "parent INTEGER," \
+ "storage INTEGER," \
+ "size INTEGER," \
+ "date_modified INTEGER" \
+ ");"
+
+#define AUDIO_TABLE_CREATE "CREATE TABLE IF NOT EXISTS audio (" \
+ "id INTEGER PRIMARY KEY," \
+ "title TEXT," \
+ "artist TEXT," \
+ "album TEXT," \
+ "album_artist TEXT," \
+ "genre TEXT," \
+ "composer TEXT," \
+ "track_number INTEGER," \
+ "year INTEGER," \
+ "duration INTEGER," \
+ "use_count INTEGER," \
+ "sample_rate INTEGER," \
+ "num_channels INTEGER," \
+ "audio_wave_codec TEXT," \
+ "audio_bit_rate INTEGER" \
+ ");"
+
+#define PATH_INDEX_CREATE "CREATE INDEX IF NOT EXISTS path_index on files(path);"
+
+#define FILE_ID_QUERY "SELECT _id,format FROM files WHERE path = ?;"
+#define FILE_PATH_QUERY "SELECT path,size FROM files WHERE _id = ?"
+
+#define GET_OBJECT_INFO_QUERY "SELECT storage,format,parent,path,size,date_modified FROM files WHERE _id = ?;"
+#define FILE_INSERT "INSERT INTO files VALUES(?,?,?,?,?,?,?);"
+#define FILE_DELETE "DELETE FROM files WHERE _id = ?;"
+
+#define AUDIO_INSERT "INSERT INTO audio VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?);"
+#define AUDIO_DELETE "DELETE FROM audio WHERE id = ?;"
+
+struct PropertyTableEntry {
+ MtpObjectProperty property;
+ int type;
+ const char* columnName;
+};
+
+static const PropertyTableEntry kPropertyTable[] = {
+ { MTP_PROPERTY_PARENT_OBJECT, MTP_TYPE_UINT32, "parent" },
+ { MTP_PROPERTY_STORAGE_ID, MTP_TYPE_UINT32, "storage" },
+ { MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT32, "format" },
+ { MTP_PROPERTY_OBJECT_FILE_NAME, MTP_TYPE_STR, "path" },
+ { MTP_PROPERTY_OBJECT_SIZE, MTP_TYPE_UINT64, "size" },
+ { MTP_PROPERTY_DATE_MODIFIED, MTP_TYPE_STR, "date_modified" },
+};
+
+static bool getPropertyInfo(MtpObjectProperty property, int& type, const char*& columnName) {
+ int count = sizeof(kPropertyTable) / sizeof(kPropertyTable[0]);
+ const PropertyTableEntry* entry = kPropertyTable;
+ for (int i = 0; i < count; i++, entry++) {
+ if (entry->property == property) {
+ type = entry->type;
+ columnName = entry->columnName;
+ return true;
+ }
+ }
+ return false;
+}
+
+
+
+MtpDatabase::MtpDatabase()
+ : mFileIdQuery(NULL),
+ mObjectInfoQuery(NULL),
+ mFileInserter(NULL),
+ mFileDeleter(NULL),
+ mAudioInserter(NULL),
+ mAudioDeleter(NULL)
+{
+}
+
+MtpDatabase::~MtpDatabase() {
+}
+
+bool MtpDatabase::open(const char* path, bool create) {
+ if (!SqliteDatabase::open(path, create))
+ return false;
+
+ // create tables and indices if necessary
+ if (!exec(FILE_TABLE_CREATE)) {
+ fprintf(stderr, "could not create file table\n");
+ return false;
+ }
+ if (!exec(PATH_INDEX_CREATE)) {
+ fprintf(stderr, "could not path index on file table\n");
+ return false;
+ }
+ if (!exec(AUDIO_TABLE_CREATE)) {
+ fprintf(stderr, "could not create file table\n");
+ return false;
+ }
+
+ if (!mFileIdQuery) {
+ mFileIdQuery = new SqliteStatement(this);
+ if (!mFileIdQuery->prepare(FILE_ID_QUERY)) {
+ fprintf(stderr, "could not compile FILE_ID_QUERY\n");
+ exit(-1);
+ }
+ }
+ if (!mFilePathQuery) {
+ mFilePathQuery = new SqliteStatement(this);
+ if (!mFilePathQuery->prepare(FILE_PATH_QUERY)) {
+ fprintf(stderr, "could not compile FILE_PATH_QUERY\n");
+ exit(-1);
+ }
+ }
+ if (!mObjectInfoQuery) {
+ mObjectInfoQuery = new SqliteStatement(this);
+ if (!mObjectInfoQuery->prepare(GET_OBJECT_INFO_QUERY)) {
+ fprintf(stderr, "could not compile GET_OBJECT_INFO_QUERY\n");
+ exit(-1);
+ }
+ }
+ if (!mFileInserter) {
+ mFileInserter = new SqliteStatement(this);
+ if (!mFileInserter->prepare(FILE_INSERT)) {
+ fprintf(stderr, "could not compile FILE_INSERT\n");
+ exit(-1);
+ }
+ }
+ if (!mFileDeleter) {
+ mFileDeleter = new SqliteStatement(this);
+ if (!mFileDeleter->prepare(FILE_DELETE)) {
+ fprintf(stderr, "could not compile FILE_DELETE\n");
+ exit(-1);
+ }
+ }
+ if (!mAudioInserter) {
+ mAudioInserter = new SqliteStatement(this);
+ if (!mAudioInserter->prepare(AUDIO_INSERT)) {
+ fprintf(stderr, "could not compile AUDIO_INSERT\n");
+ exit(-1);
+ }
+ }
+ if (!mAudioDeleter) {
+ mAudioDeleter = new SqliteStatement(this);
+ if (!mAudioDeleter->prepare(AUDIO_DELETE)) {
+ fprintf(stderr, "could not compile AUDIO_DELETE\n");
+ exit(-1);
+ }
+ }
+
+ return true;
+}
+
+uint32_t MtpDatabase::getTableForFile(MtpObjectFormat format) {
+ switch (format) {
+ case MTP_FORMAT_AIFF:
+ case MTP_FORMAT_WAV:
+ case MTP_FORMAT_MP3:
+ case MTP_FORMAT_FLAC:
+ case MTP_FORMAT_UNDEFINED_AUDIO:
+ case MTP_FORMAT_WMA:
+ case MTP_FORMAT_OGG:
+ case MTP_FORMAT_AAC:
+ case MTP_FORMAT_AUDIBLE:
+ return kObjectHandleTableAudio;
+ case MTP_FORMAT_AVI:
+ case MTP_FORMAT_MPEG:
+ case MTP_FORMAT_ASF:
+ case MTP_FORMAT_UNDEFINED_VIDEO:
+ case MTP_FORMAT_WMV:
+ case MTP_FORMAT_MP4_CONTAINER:
+ case MTP_FORMAT_MP2:
+ case MTP_FORMAT_3GP_CONTAINER:
+ return kObjectHandleTableVideo;
+ case MTP_FORMAT_DEFINED:
+ case MTP_FORMAT_EXIF_JPEG:
+ case MTP_FORMAT_TIFF_EP:
+ case MTP_FORMAT_FLASHPIX:
+ case MTP_FORMAT_BMP:
+ case MTP_FORMAT_CIFF:
+ case MTP_FORMAT_GIF:
+ case MTP_FORMAT_JFIF:
+ case MTP_FORMAT_CD:
+ case MTP_FORMAT_PICT:
+ case MTP_FORMAT_PNG:
+ case MTP_FORMAT_TIFF:
+ case MTP_FORMAT_TIFF_IT:
+ case MTP_FORMAT_JP2:
+ case MTP_FORMAT_JPX:
+ case MTP_FORMAT_WINDOWS_IMAGE_FORMAT:
+ return kObjectHandleTableImage;
+ case MTP_FORMAT_ABSTRACT_AUDIO_PLAYLIST:
+ case MTP_FORMAT_ABSTRACT_AV_PLAYLIST:
+ case MTP_FORMAT_ABSTRACT_VIDEO_PLAYLIST:
+ case MTP_FORMAT_WPL_PLAYLIST:
+ case MTP_FORMAT_M3U_PLAYLIST:
+ case MTP_FORMAT_MPL_PLAYLIST:
+ case MTP_FORMAT_ASX_PLAYLIST:
+ case MTP_FORMAT_PLS_PLAYLIST:
+ return kObjectHandleTablePlaylist;
+ default:
+ return kObjectHandleTableFile;
+ }
+}
+
+MtpObjectHandle MtpDatabase::getObjectHandle(const char* path) {
+ mFileIdQuery->reset();
+ mFileIdQuery->bind(1, path);
+ if (mFileIdQuery->step()) {
+ int row = mFileIdQuery->getColumnInt(0);
+ if (row > 0) {
+ MtpObjectFormat format = mFileIdQuery->getColumnInt(1);
+ row |= getTableForFile(format);
+ return row;
+ }
+ }
+
+ return 0;
+}
+
+MtpObjectHandle MtpDatabase::addFile(const char* path,
+ MtpObjectFormat format,
+ MtpObjectHandle parent,
+ MtpStorageID storage,
+ uint64_t size,
+ time_t modified) {
+ mFileInserter->bind(FILE_PATH_COLUMN, path);
+ mFileInserter->bind(FILE_FORMAT_COLUMN, format);
+ mFileInserter->bind(FILE_PARENT_COLUMN, parent);
+ mFileInserter->bind(FILE_STORAGE_COLUMN, storage);
+ mFileInserter->bind(FILE_SIZE_COLUMN, size);
+ mFileInserter->bind(FILE_MODIFIED_COLUMN, modified);
+ mFileInserter->step();
+ mFileInserter->reset();
+ int result = lastInsertedRow();
+ return (result <= 0 ? kInvalidObjectHandle : result);
+}
+
+MtpObjectHandle MtpDatabase::addAudioFile(MtpObjectHandle handle) {
+ mAudioInserter->bind(AUDIO_ID_COLUMN, handle);
+ mAudioInserter->step();
+ mAudioInserter->reset();
+ int result = lastInsertedRow();
+ handle |= kObjectHandleTableAudio;
+ return (result > 0 ? handle : kInvalidObjectHandle);
+}
+
+MtpObjectHandle MtpDatabase::addAudioFile(MtpObjectHandle handle,
+ const char* title,
+ const char* artist,
+ const char* album,
+ const char* albumArtist,
+ const char* genre,
+ const char* composer,
+ const char* mimeType,
+ int track,
+ int year,
+ int duration) {
+ mAudioInserter->bind(AUDIO_ID_COLUMN, handle);
+ if (title) mAudioInserter->bind(AUDIO_TITLE_COLUMN, title);
+ if (artist) mAudioInserter->bind(AUDIO_ARTIST_COLUMN, artist);
+ if (album) mAudioInserter->bind(AUDIO_ALBUM_COLUMN, album);
+ if (albumArtist) mAudioInserter->bind(AUDIO_ALBUM_ARTIST_COLUMN, albumArtist);
+ if (genre) mAudioInserter->bind(AUDIO_GENRE_COLUMN, genre);
+ if (composer) mAudioInserter->bind(AUDIO_COMPOSER_COLUMN, composer);
+ if (track) mAudioInserter->bind(AUDIO_TRACK_NUMBER_COLUMN, track);
+ if (year) mAudioInserter->bind(AUDIO_YEAR_COLUMN, year);
+ if (duration) mAudioInserter->bind(AUDIO_DURATION_COLUMN, duration);
+ mAudioInserter->step();
+ mAudioInserter->reset();
+ int result = lastInsertedRow();
+ if (result <= 0)
+ return kInvalidObjectHandle;
+ result |= kObjectHandleTableAudio;
+ return result;
+}
+
+MtpObjectHandleList* MtpDatabase::getObjectList(MtpStorageID storageID,
+ MtpObjectFormat format,
+ MtpObjectHandle parent) {
+ bool whereStorage = (storageID != 0xFFFFFFFF);
+ bool whereFormat = (format != 0);
+ bool whereParent = (parent != 0);
+ char intBuffer[20];
+
+ MtpString query("SELECT _id,format FROM files");
+ if (whereStorage || whereFormat || whereParent)
+ query += " WHERE";
+ if (whereStorage) {
+ snprintf(intBuffer, sizeof(intBuffer), "%d", storageID);
+ query += " storage = ";
+ query += intBuffer;
+ }
+ if (whereFormat) {
+ snprintf(intBuffer, sizeof(intBuffer), "%d", format);
+ if (whereStorage)
+ query += " AND";
+ query += " format = ";
+ query += intBuffer;
+ }
+ if (whereParent) {
+ if (parent != MTP_PARENT_ROOT)
+ parent &= kObjectHandleIndexMask;
+ snprintf(intBuffer, sizeof(intBuffer), "%d", parent);
+ if (whereStorage || whereFormat)
+ query += " AND";
+ query += " parent = ";
+ query += intBuffer;
+ }
+ query += ";";
+
+ SqliteStatement stmt(this);
+ printf("%s\n", (const char *)query);
+ stmt.prepare(query);
+
+ MtpObjectHandleList* list = new MtpObjectHandleList();
+ while (!stmt.isDone()) {
+ if (stmt.step()) {
+ int index = stmt.getColumnInt(0);
+ printf("stmt.getColumnInt returned %d\n", index);
+ if (index > 0) {
+ MtpObjectFormat format = stmt.getColumnInt(1);
+ index |= getTableForFile(format);
+ list->push(index);
+ }
+ }
+ }
+ printf("list size: %d\n", list->size());
+ return list;
+}
+
+
+MtpResponseCode MtpDatabase::getObjectProperty(MtpObjectHandle handle,
+ MtpObjectProperty property,
+ MtpDataPacket& packet) {
+ int type;
+ const char* columnName;
+ char intBuffer[20];
+
+ if (handle != MTP_PARENT_ROOT)
+ handle &= kObjectHandleIndexMask;
+
+ if (!getPropertyInfo(property, type, columnName))
+ return MTP_RESPONSE_INVALID_OBJECT_PROP_CODE;
+ snprintf(intBuffer, sizeof(intBuffer), "%d", handle);
+
+ MtpString query("SELECT ");
+ query += columnName;
+ query += " FROM files WHERE _id = ";
+ query += intBuffer;
+ query += ";";
+
+ SqliteStatement stmt(this);
+ printf("%s\n", (const char *)query);
+ stmt.prepare(query);
+
+ if (!stmt.step())
+ return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
+
+ switch (type) {
+ case MTP_TYPE_INT8:
+ packet.putInt8(stmt.getColumnInt(0));
+ break;
+ case MTP_TYPE_UINT8:
+ packet.putUInt8(stmt.getColumnInt(0));
+ break;
+ case MTP_TYPE_INT16:
+ packet.putInt16(stmt.getColumnInt(0));
+ break;
+ case MTP_TYPE_UINT16:
+ packet.putUInt16(stmt.getColumnInt(0));
+ break;
+ case MTP_TYPE_INT32:
+ packet.putInt32(stmt.getColumnInt(0));
+ break;
+ case MTP_TYPE_UINT32:
+ packet.putUInt32(stmt.getColumnInt(0));
+ break;
+ case MTP_TYPE_INT64:
+ packet.putInt64(stmt.getColumnInt64(0));
+ break;
+ case MTP_TYPE_UINT64:
+ packet.putUInt64(stmt.getColumnInt64(0));
+ break;
+ case MTP_TYPE_STR:
+ packet.putString(stmt.getColumnString(0));
+ break;
+ default:
+ fprintf(stderr, "unsupported object type\n");
+ return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
+ }
+ return MTP_RESPONSE_OK;
+}
+
+MtpResponseCode MtpDatabase::getObjectInfo(MtpObjectHandle handle,
+ MtpDataPacket& packet) {
+ char date[20];
+
+ if (handle != MTP_PARENT_ROOT)
+ handle &= kObjectHandleIndexMask;
+
+ mObjectInfoQuery->reset();
+ mObjectInfoQuery->bind(1, handle);
+ if (!mObjectInfoQuery->step())
+ return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
+
+ MtpStorageID storageID = mObjectInfoQuery->getColumnInt(0);
+ MtpObjectFormat format = mObjectInfoQuery->getColumnInt(1);
+ MtpObjectHandle parent = mObjectInfoQuery->getColumnInt(2);
+ // extract name from path. do we want a separate database entry for this?
+ const char* name = mObjectInfoQuery->getColumnString(3);
+ const char* lastSlash = strrchr(name, '/');
+ if (lastSlash)
+ name = lastSlash + 1;
+ int64_t size = mObjectInfoQuery->getColumnInt64(4);
+ time_t modified = mObjectInfoQuery->getColumnInt(5);
+ int associationType = (format == MTP_FORMAT_ASSOCIATION ?
+ MTP_ASSOCIATION_TYPE_GENERIC_FOLDER :
+ MTP_ASSOCIATION_TYPE_UNDEFINED);
+
+ printf("storageID: %d, format: %d, parent: %d\n", storageID, format, parent);
+
+ packet.putUInt32(storageID);
+ packet.putUInt16(format);
+ packet.putUInt16(0); // protection status
+ packet.putUInt32((size > 0xFFFFFFFFLL ? 0xFFFFFFFF : size));
+ packet.putUInt16(0); // thumb format
+ packet.putUInt32(0); // thumb compressed size
+ packet.putUInt32(0); // thumb pix width
+ packet.putUInt32(0); // thumb pix height
+ packet.putUInt32(0); // image pix width
+ packet.putUInt32(0); // image pix height
+ packet.putUInt32(0); // image bit depth
+ packet.putUInt32(parent);
+ packet.putUInt16(associationType);
+ packet.putUInt32(0); // association desc
+ packet.putUInt32(0); // sequence number
+ packet.putString(name); // file name
+ packet.putEmptyString();
+ formatDateTime(modified, date, sizeof(date));
+ packet.putString(date); // date modified
+ packet.putEmptyString(); // keywords
+
+ return MTP_RESPONSE_OK;
+}
+
+bool MtpDatabase::getObjectFilePath(MtpObjectHandle handle,
+ MtpString& filePath,
+ int64_t& fileLength) {
+ if (handle != MTP_PARENT_ROOT)
+ handle &= kObjectHandleIndexMask;
+ mFilePathQuery->reset();
+ mFilePathQuery->bind(1, handle);
+ if (!mFilePathQuery->step())
+ return false;
+
+ const char* path = mFilePathQuery->getColumnString(0);
+ if (!path)
+ return false;
+ filePath = path;
+ fileLength = mFilePathQuery->getColumnInt64(1);
+ return true;
+}
+
+bool MtpDatabase::deleteFile(MtpObjectHandle handle) {
+ uint32_t table = handle & kObjectHandleTableMask;
+ handle &= kObjectHandleIndexMask;
+ mFileDeleter->bind(1, handle);
+ mFileDeleter->step();
+ mFileDeleter->reset();
+ if (table == kObjectHandleTableAudio) {
+ mAudioDeleter->bind(1, handle);
+ mAudioDeleter->step();
+ mAudioDeleter->reset();
+ }
+
+ return true;
+}
+
+MtpObjectHandle* MtpDatabase::getFileList(int& outCount) {
+ MtpObjectHandle* result = NULL;
+ int count = 0;
+ SqliteStatement stmt(this);
+ stmt.prepare("SELECT count(*) FROM files;");
+
+ MtpObjectHandleList* list = new MtpObjectHandleList();
+ if (stmt.step())
+ count = stmt.getColumnInt(0);
+
+ if (count > 0) {
+ result = new MtpObjectHandle[count];
+ memset(result, 0, count * sizeof(*result));
+ SqliteStatement stmt2(this);
+ stmt2.prepare("SELECT _id,format FROM files;");
+
+ for (int i = 0; i < count; i++) {
+ if (!stmt2.step()) {
+ printf("getFileList ended early\n");
+ count = i;
+ break;
+ }
+ MtpObjectHandle handle = stmt2.getColumnInt(0);
+ MtpObjectFormat format = stmt2.getColumnInt(1);
+ handle |= getTableForFile(format);
+ result[i] = handle;
+ }
+ }
+ outCount = count;
+ return result;
+}
+
+/*
+ for getObjectPropDesc
+
+ packet.putUInt16(property);
+ packet.putUInt16(dataType);
+ packet.putUInt8(getSet);
+ // default value DTS
+ packet.putUInt32(groupCode);
+ packet.putUInt8(formFlag);
+ // form, variable
+*/
+
+} // namespace android
diff --git a/media/mtp/MtpDatabase.h b/media/mtp/MtpDatabase.h
new file mode 100644
index 0000000..51d5fb1
--- /dev/null
+++ b/media/mtp/MtpDatabase.h
@@ -0,0 +1,89 @@
+/*
+ * 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 _MTP_DATABASE_H
+#define _MTP_DATABASE_H
+
+#include "MtpTypes.h"
+#include "SqliteDatabase.h"
+
+namespace android {
+
+class MtpDataPacket;
+class SqliteStatement;
+
+class MtpDatabase : public SqliteDatabase {
+private:
+ SqliteStatement* mFileIdQuery;
+ SqliteStatement* mFilePathQuery;
+ SqliteStatement* mObjectInfoQuery;
+ SqliteStatement* mFileInserter;
+ SqliteStatement* mFileDeleter;
+ SqliteStatement* mAudioInserter;
+ SqliteStatement* mAudioDeleter;
+
+public:
+ MtpDatabase();
+ virtual ~MtpDatabase();
+
+ static uint32_t getTableForFile(MtpObjectFormat format);
+
+ bool open(const char* path, bool create);
+ MtpObjectHandle getObjectHandle(const char* path);
+ MtpObjectHandle addFile(const char* path,
+ MtpObjectFormat format,
+ MtpObjectHandle parent,
+ MtpStorageID storage,
+ uint64_t size,
+ time_t modified);
+
+ MtpObjectHandle addAudioFile(MtpObjectHandle id);
+
+ MtpObjectHandle addAudioFile(MtpObjectHandle id,
+ const char* title,
+ const char* artist,
+ const char* album,
+ const char* albumArtist,
+ const char* genre,
+ const char* composer,
+ const char* mimeType,
+ int track,
+ int year,
+ int duration);
+
+ MtpObjectHandleList* getObjectList(MtpStorageID storageID,
+ MtpObjectFormat format,
+ MtpObjectHandle parent);
+
+ MtpResponseCode getObjectProperty(MtpObjectHandle handle,
+ MtpObjectProperty property,
+ MtpDataPacket& packet);
+
+ MtpResponseCode getObjectInfo(MtpObjectHandle handle,
+ MtpDataPacket& packet);
+
+ bool getObjectFilePath(MtpObjectHandle handle,
+ MtpString& filePath,
+ int64_t& fileLength);
+ bool deleteFile(MtpObjectHandle handle);
+
+ // helper for media scanner
+ MtpObjectHandle* getFileList(int& outCount);
+};
+
+}; // namespace android
+
+#endif // _MTP_DATABASE_H
diff --git a/media/mtp/MtpDebug.cpp b/media/mtp/MtpDebug.cpp
new file mode 100644
index 0000000..9ded6e2
--- /dev/null
+++ b/media/mtp/MtpDebug.cpp
@@ -0,0 +1,76 @@
+/*
+ * 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 "MtpDebug.h"
+
+namespace android {
+
+struct OperationCodeEntry {
+ const char* name;
+ MtpOperationCode code;
+};
+
+static const OperationCodeEntry sOperationCodes[] = {
+ { "MTP_OPERATION_GET_DEVICE_INFO", 0x1001 },
+ { "MTP_OPERATION_OPEN_SESSION", 0x1002 },
+ { "MTP_OPERATION_CLOSE_SESSION", 0x1003 },
+ { "MTP_OPERATION_GET_STORAGE_IDS", 0x1004 },
+ { "MTP_OPERATION_GET_STORAGE_INFO", 0x1005 },
+ { "MTP_OPERATION_GET_NUM_OBJECTS", 0x1006 },
+ { "MTP_OPERATION_GET_OBJECT_HANDLES", 0x1007 },
+ { "MTP_OPERATION_GET_OBJECT_INFO", 0x1008 },
+ { "MTP_OPERATION_GET_OBJECT", 0x1009 },
+ { "MTP_OPERATION_GET_THUMB", 0x100A },
+ { "MTP_OPERATION_DELETE_OBJECT", 0x100B },
+ { "MTP_OPERATION_SEND_OBJECT_INFO", 0x100C },
+ { "MTP_OPERATION_SEND_OBJECT", 0x100D },
+ { "MTP_OPERATION_INITIATE_CAPTURE", 0x100E },
+ { "MTP_OPERATION_FORMAT_STORE", 0x100F },
+ { "MTP_OPERATION_RESET_DEVICE", 0x1010 },
+ { "MTP_OPERATION_SELF_TEST", 0x1011 },
+ { "MTP_OPERATION_SET_OBJECT_PROTECTION", 0x1012 },
+ { "MTP_OPERATION_POWER_DOWN", 0x1013 },
+ { "MTP_OPERATION_GET_DEVICE_PROP_DESC", 0x1014 },
+ { "MTP_OPERATION_GET_DEVICE_PROP_VALUE", 0x1015 },
+ { "MTP_OPERATION_SET_DEVICE_PROP_VALUE", 0x1016 },
+ { "MTP_OPERATION_RESET_DEVICE_PROP_VALUE", 0x1017 },
+ { "MTP_OPERATION_TERMINATE_OPEN_CAPTURE", 0x1018 },
+ { "MTP_OPERATION_MOVE_OBJECT", 0x1019 },
+ { "MTP_OPERATION_COPY_OBJECT", 0x101A },
+ { "MTP_OPERATION_GET_PARTIAL_OBJECT", 0x101B },
+ { "MTP_OPERATION_INITIATE_OPEN_CAPTURE", 0x101C },
+ { "MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED", 0x9801 },
+ { "MTP_OPERATION_GET_OBJECT_PROP_DESC", 0x9802 },
+ { "MTP_OPERATION_GET_OBJECT_PROP_VALUE", 0x9803 },
+ { "MTP_OPERATION_SET_OBJECT_PROP_VALUE", 0x9804 },
+ { "MTP_OPERATION_GET_OBJECT_REFERENCES", 0x9810 },
+ { "MTP_OPERATION_SET_OBJECT_REFERENCES", 0x9811 },
+ { "MTP_OPERATION_SKIP", 0x9820 },
+ { 0, 0 },
+};
+
+
+const char* MtpDebug::getOperationCodeName(MtpOperationCode code) {
+ const OperationCodeEntry* entry = sOperationCodes;
+ while (entry->name) {
+ if (entry->code == code)
+ return entry->name;
+ entry++;
+ }
+ return "*** UNKNOWN OPERATION ***";
+}
+
+} // namespace android
diff --git a/graphics/java/android/renderscript/Vector2f.java b/media/mtp/MtpDebug.h
similarity index 66%
copy from graphics/java/android/renderscript/Vector2f.java
copy to media/mtp/MtpDebug.h
index 567d57fa..3cbc209 100644
--- a/graphics/java/android/renderscript/Vector2f.java
+++ b/media/mtp/MtpDebug.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,24 +14,18 @@
* limitations under the License.
*/
-package android.renderscript;
+#ifndef _MTP_DEBUG_H
+#define _MTP_DEBUG_H
-import java.lang.Math;
-import android.util.Log;
+#include "MtpTypes.h"
+namespace android {
-/**
- * @hide
- *
- **/
-public class Vector2f {
- public Vector2f() {
- }
+class MtpDebug {
+public:
+ static const char* getOperationCodeName(MtpOperationCode code);
+};
- public float x;
- public float y;
-}
+}; // namespace android
-
-
-
+#endif // _MTP_DEBUG_H
diff --git a/media/mtp/MtpDevice.cpp b/media/mtp/MtpDevice.cpp
new file mode 100644
index 0000000..5c39628
--- /dev/null
+++ b/media/mtp/MtpDevice.cpp
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "MtpDevice"
+#include "utils/Log.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <usbhost/usbhost.h>
+
+#include "MtpDevice.h"
+#include "MtpDebug.h"
+#include "MtpDeviceInfo.h"
+#include "MtpObjectInfo.h"
+#include "MtpProperty.h"
+#include "MtpStorageInfo.h"
+#include "MtpStringBuffer.h"
+
+namespace android {
+
+MtpDevice::MtpDevice(struct usb_device* device, int interface,
+ struct usb_endpoint *ep_in, struct usb_endpoint *ep_out,
+ struct usb_endpoint *ep_intr)
+ : mDevice(device),
+ mInterface(interface),
+ mEndpointIn(ep_in),
+ mEndpointOut(ep_out),
+ mEndpointIntr(ep_intr),
+ mDeviceInfo(NULL),
+ mID(usb_device_get_unique_id(device)),
+ mSessionID(0),
+ mTransactionID(0)
+{
+}
+
+MtpDevice::~MtpDevice() {
+ close();
+ for (int i = 0; i < mDeviceProperties.size(); i++)
+ delete mDeviceProperties[i];
+}
+
+void MtpDevice::initialize() {
+ openSession();
+ mDeviceInfo = getDeviceInfo();
+ if (mDeviceInfo) {
+ mDeviceInfo->print();
+
+ if (mDeviceInfo->mDeviceProperties) {
+ int count = mDeviceInfo->mDeviceProperties->size();
+ for (int i = 0; i < count; i++) {
+ MtpDeviceProperty propCode = (*mDeviceInfo->mDeviceProperties)[i];
+ MtpProperty* property = getDevicePropDesc(propCode);
+ if (property) {
+ property->print();
+ mDeviceProperties.push(property);
+ }
+ }
+ }
+ }
+}
+
+void MtpDevice::close() {
+ if (mDevice) {
+ usb_device_release_interface(mDevice, mInterface);
+ usb_device_close(mDevice);
+ mDevice = NULL;
+ }
+}
+
+const char* MtpDevice::getDeviceName() {
+ if (mDevice)
+ return usb_device_get_name(mDevice);
+ else
+ return "???";
+}
+
+bool MtpDevice::openSession() {
+ mSessionID = 0;
+ mTransactionID = 0;
+ MtpSessionID newSession = 1;
+ mRequest.reset();
+ mRequest.setParameter(1, newSession);
+ if (!sendRequest(MTP_OPERATION_OPEN_SESSION))
+ return false;
+ MtpResponseCode ret = readResponse();
+ if (ret == MTP_RESPONSE_SESSION_ALREADY_OPEN)
+ newSession = mResponse.getParameter(1);
+ else if (ret != MTP_RESPONSE_OK)
+ return false;
+
+ mSessionID = newSession;
+ mTransactionID = 1;
+ return true;
+}
+
+bool MtpDevice::closeSession() {
+ // FIXME
+ return true;
+}
+
+MtpDeviceInfo* MtpDevice::getDeviceInfo() {
+ mRequest.reset();
+ if (!sendRequest(MTP_OPERATION_GET_DEVICE_INFO))
+ return NULL;
+ if (!readData())
+ return NULL;
+ MtpResponseCode ret = readResponse();
+ if (ret == MTP_RESPONSE_OK) {
+ MtpDeviceInfo* info = new MtpDeviceInfo;
+ info->read(mData);
+ return info;
+ }
+ return NULL;
+}
+
+MtpStorageIDList* MtpDevice::getStorageIDs() {
+ mRequest.reset();
+ if (!sendRequest(MTP_OPERATION_GET_STORAGE_IDS))
+ return NULL;
+ if (!readData())
+ return NULL;
+ MtpResponseCode ret = readResponse();
+ if (ret == MTP_RESPONSE_OK) {
+ return mData.getAUInt32();
+ }
+ return NULL;
+}
+
+MtpStorageInfo* MtpDevice::getStorageInfo(MtpStorageID storageID) {
+ mRequest.reset();
+ mRequest.setParameter(1, storageID);
+ if (!sendRequest(MTP_OPERATION_GET_STORAGE_INFO))
+ return NULL;
+ if (!readData())
+ return NULL;
+ MtpResponseCode ret = readResponse();
+ if (ret == MTP_RESPONSE_OK) {
+ MtpStorageInfo* info = new MtpStorageInfo(storageID);
+ info->read(mData);
+ return info;
+ }
+ return NULL;
+}
+
+MtpObjectHandleList* MtpDevice::getObjectHandles(MtpStorageID storageID,
+ MtpObjectFormat format, MtpObjectHandle parent) {
+ mRequest.reset();
+ mRequest.setParameter(1, storageID);
+ mRequest.setParameter(2, format);
+ mRequest.setParameter(3, parent);
+ if (!sendRequest(MTP_OPERATION_GET_OBJECT_HANDLES))
+ return NULL;
+ if (!readData())
+ return NULL;
+ MtpResponseCode ret = readResponse();
+ if (ret == MTP_RESPONSE_OK) {
+ return mData.getAUInt32();
+ }
+ return NULL;
+}
+
+MtpObjectInfo* MtpDevice::getObjectInfo(MtpObjectHandle handle) {
+ mRequest.reset();
+ mRequest.setParameter(1, handle);
+ if (!sendRequest(MTP_OPERATION_GET_OBJECT_INFO))
+ return NULL;
+ if (!readData())
+ return NULL;
+ MtpResponseCode ret = readResponse();
+ if (ret == MTP_RESPONSE_OK) {
+ MtpObjectInfo* info = new MtpObjectInfo(handle);
+ info->read(mData);
+ return info;
+ }
+ return NULL;
+}
+
+MtpProperty* MtpDevice::getDevicePropDesc(MtpDeviceProperty code) {
+ mRequest.reset();
+ mRequest.setParameter(1, code);
+ if (!sendRequest(MTP_OPERATION_GET_DEVICE_PROP_DESC))
+ return NULL;
+ if (!readData())
+ return NULL;
+ MtpResponseCode ret = readResponse();
+ if (ret == MTP_RESPONSE_OK) {
+ MtpProperty* property = new MtpProperty;
+ property->read(mData);
+ return property;
+ }
+ return NULL;
+}
+
+
+bool MtpDevice::sendRequest(MtpOperationCode operation) {
+ LOGD("sendRequest: %s\n", MtpDebug::getOperationCodeName(operation));
+ mRequest.setOperationCode(operation);
+ if (mTransactionID > 0)
+ mRequest.setTransactionID(mTransactionID++);
+ int ret = mRequest.write(mEndpointOut);
+ mRequest.dump();
+ return (ret > 0);
+}
+
+bool MtpDevice::sendData(MtpOperationCode operation) {
+ LOGD("sendData\n");
+ mData.setOperationCode(mRequest.getOperationCode());
+ mData.setTransactionID(mRequest.getTransactionID());
+ int ret = mData.write(mEndpointOut);
+ mData.dump();
+ return (ret > 0);
+}
+
+bool MtpDevice::readData() {
+ mData.reset();
+ int ret = mData.read(mEndpointIn);
+ LOGD("readData returned %d\n", ret);
+ if (ret >= MTP_CONTAINER_HEADER_SIZE) {
+ mData.dump();
+ return true;
+ }
+ else {
+ LOGD("readResponse failed\n");
+ return false;
+ }
+}
+
+MtpResponseCode MtpDevice::readResponse() {
+ LOGD("readResponse\n");
+ int ret = mResponse.read(mEndpointIn);
+ if (ret >= MTP_CONTAINER_HEADER_SIZE) {
+ mResponse.dump();
+ return mResponse.getResponseCode();
+ }
+ else {
+ LOGD("readResponse failed\n");
+ return -1;
+ }
+}
+
+} // namespace android
diff --git a/media/mtp/MtpDevice.h b/media/mtp/MtpDevice.h
new file mode 100644
index 0000000..226b247
--- /dev/null
+++ b/media/mtp/MtpDevice.h
@@ -0,0 +1,86 @@
+/*
+ * 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 _MTP_DEVICE_H
+#define _MTP_DEVICE_H
+
+#include "MtpRequestPacket.h"
+#include "MtpDataPacket.h"
+#include "MtpResponsePacket.h"
+#include "MtpTypes.h"
+
+namespace android {
+
+class MtpDeviceInfo;
+class MtpObjectInfo;
+class MtpStorageInfo;
+
+class MtpDevice {
+private:
+ struct usb_device* mDevice;
+ int mInterface;
+ struct usb_endpoint* mEndpointIn;
+ struct usb_endpoint* mEndpointOut;
+ struct usb_endpoint* mEndpointIntr;
+ MtpDeviceInfo* mDeviceInfo;
+ MtpPropertyList mDeviceProperties;
+
+ // a unique ID for the device
+ int mID;
+
+ // current session ID
+ MtpSessionID mSessionID;
+ // current transaction ID
+ MtpTransactionID mTransactionID;
+
+ MtpRequestPacket mRequest;
+ MtpDataPacket mData;
+ MtpResponsePacket mResponse;
+
+public:
+ MtpDevice(struct usb_device* device, int interface,
+ struct usb_endpoint *ep_in, struct usb_endpoint *ep_out,
+ struct usb_endpoint *ep_intr);
+ virtual ~MtpDevice();
+
+ inline int getID() const { return mID; }
+
+ void initialize();
+ void close();
+ const char* getDeviceName();
+
+ bool openSession();
+ bool closeSession();
+
+ MtpDeviceInfo* getDeviceInfo();
+ MtpStorageIDList* getStorageIDs();
+ MtpStorageInfo* getStorageInfo(MtpStorageID storageID);
+ MtpObjectHandleList* getObjectHandles(MtpStorageID storageID, MtpObjectFormat format, MtpObjectHandle parent);
+ MtpObjectInfo* getObjectInfo(MtpObjectHandle handle);
+
+ MtpProperty* getDevicePropDesc(MtpDeviceProperty code);
+
+private:
+ bool sendRequest(MtpOperationCode operation);
+ bool sendData(MtpOperationCode operation);
+ bool readData();
+ MtpResponseCode readResponse();
+
+};
+
+}; // namespace android
+
+#endif // _MTP_DEVICE_H
diff --git a/media/mtp/MtpDeviceInfo.cpp b/media/mtp/MtpDeviceInfo.cpp
new file mode 100644
index 0000000..eb25fb3
--- /dev/null
+++ b/media/mtp/MtpDeviceInfo.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "MtpDeviceInfo"
+#include "utils/Log.h"
+
+#include "MtpDataPacket.h"
+#include "MtpDeviceInfo.h"
+#include "MtpStringBuffer.h"
+
+namespace android {
+
+MtpDeviceInfo::MtpDeviceInfo()
+ : mStandardVersion(0),
+ mVendorExtensionID(0),
+ mVendorExtensionVersion(0),
+ mVendorExtensionDesc(NULL),
+ mFunctionalCode(0),
+ mOperations(NULL),
+ mEvents(NULL),
+ mDeviceProperties(NULL),
+ mCaptureFormats(NULL),
+ mPlaybackFormats(NULL),
+ mManufacturer(NULL),
+ mModel(NULL),
+ mVersion(NULL),
+ mSerial(NULL)
+{
+}
+
+MtpDeviceInfo::~MtpDeviceInfo() {
+ if (mVendorExtensionDesc)
+ free(mVendorExtensionDesc);
+ delete mOperations;
+ delete mEvents;
+ delete mDeviceProperties;
+ delete mCaptureFormats;
+ delete mPlaybackFormats;
+ if (mManufacturer)
+ free(mManufacturer);
+ if (mModel)
+ free(mModel);
+ if (mVersion)
+ free(mVersion);
+ if (mSerial)
+ free(mSerial);
+}
+
+void MtpDeviceInfo::read(MtpDataPacket& packet) {
+ MtpStringBuffer string;
+
+ // read the device info
+ mStandardVersion = packet.getUInt16();
+ mVendorExtensionID = packet.getUInt32();
+ mVendorExtensionVersion = packet.getUInt16();
+
+ packet.getString(string);
+ mVendorExtensionDesc = strdup((const char *)string);
+
+ mFunctionalCode = packet.getUInt16();
+ mOperations = packet.getAUInt16();
+ mEvents = packet.getAUInt16();
+ mDeviceProperties = packet.getAUInt16();
+ mCaptureFormats = packet.getAUInt16();
+ mPlaybackFormats = packet.getAUInt16();
+
+ packet.getString(string);
+ mManufacturer = strdup((const char *)string);
+ packet.getString(string);
+ mModel = strdup((const char *)string);
+ packet.getString(string);
+ mVersion = strdup((const char *)string);
+ packet.getString(string);
+ mSerial = strdup((const char *)string);
+}
+
+void MtpDeviceInfo::print() {
+ LOGD("Device Info:\n\tmStandardVersion: %d\n\tmVendorExtensionID: %d\n\tmVendorExtensionVersiony: %d\n",
+ mStandardVersion, mVendorExtensionID, mVendorExtensionVersion);
+ LOGD("\tmVendorExtensionDesc: %s\n\tmFunctionalCode: %d\n\tmManufacturer: %s\n\tmModel: %s\n\tmVersion: %s\n\tmSerial: %s\n",
+ mVendorExtensionDesc, mFunctionalCode, mManufacturer, mModel, mVersion, mSerial);
+}
+
+} // namespace android
diff --git a/media/mtp/MtpDeviceInfo.h b/media/mtp/MtpDeviceInfo.h
new file mode 100644
index 0000000..2abaa10
--- /dev/null
+++ b/media/mtp/MtpDeviceInfo.h
@@ -0,0 +1,54 @@
+/*
+ * 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 _MTP_DEVICE_INFO_H
+#define _MTP_DEVICE_INFO_H
+
+struct stat;
+
+namespace android {
+
+class MtpDataPacket;
+
+class MtpDeviceInfo {
+public:
+ uint16_t mStandardVersion;
+ uint32_t mVendorExtensionID;
+ uint16_t mVendorExtensionVersion;
+ char* mVendorExtensionDesc;
+ uint16_t mFunctionalCode;
+ UInt16List* mOperations;
+ UInt16List* mEvents;
+ MtpDevicePropertyList* mDeviceProperties;
+ MtpObjectFormatList* mCaptureFormats;
+ MtpObjectFormatList* mPlaybackFormats;
+ char* mManufacturer;
+ char* mModel;
+ char* mVersion;
+ char* mSerial;
+
+public:
+ MtpDeviceInfo();
+ virtual ~MtpDeviceInfo();
+
+ void read(MtpDataPacket& packet);
+
+ void print();
+};
+
+}; // namespace android
+
+#endif // _MTP_DEVICE_INFO_H
diff --git a/media/mtp/MtpMediaScanner.cpp b/media/mtp/MtpMediaScanner.cpp
new file mode 100644
index 0000000..4e566f1
--- /dev/null
+++ b/media/mtp/MtpMediaScanner.cpp
@@ -0,0 +1,378 @@
+/*
+ * 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 "MtpDatabase.h"
+#include "MtpMediaScanner.h"
+#include "mtp.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <limits.h>
+
+#include <media/mediascanner.h>
+#include <media/stagefright/StagefrightMediaScanner.h>
+
+namespace android {
+
+class MtpMediaScannerClient : public MediaScannerClient
+{
+public:
+ MtpMediaScannerClient()
+ {
+ reset();
+ }
+
+ virtual ~MtpMediaScannerClient()
+ {
+ }
+
+ // returns true if it succeeded, false if an exception occured in the Java code
+ virtual bool scanFile(const char* path, long long lastModified, long long fileSize)
+ {
+ printf("scanFile %s\n", path);
+ return true;
+ }
+
+ // returns true if it succeeded, false if an exception occured in the Java code
+ virtual bool handleStringTag(const char* name, const char* value)
+ {
+ int temp;
+
+ if (!strcmp(name, "title")) {
+ mTitle = value;
+ mHasTitle = true;
+ } else if (!strcmp(name, "artist")) {
+ mArtist = value;
+ mHasArtist = true;
+ } else if (!strcmp(name, "album")) {
+ mAlbum = value;
+ mHasAlbum = true;
+ } else if (!strcmp(name, "albumartist")) {
+ mAlbumArtist = value;
+ mHasAlbumArtist = true;
+ } else if (!strcmp(name, "genre")) {
+ // FIXME - handle numeric values here
+ mGenre = value;
+ mHasGenre = true;
+ } else if (!strcmp(name, "composer")) {
+ mComposer = value;
+ mHasComposer = true;
+ } else if (!strcmp(name, "tracknumber")) {
+ if (sscanf(value, "%d", &temp) == 1)
+ mTrack = temp;
+ } else if (!strcmp(name, "discnumber")) {
+ // currently unused
+ } else if (!strcmp(name, "year") || !strcmp(name, "date")) {
+ if (sscanf(value, "%d", &temp) == 1)
+ mYear = temp;
+ } else if (!strcmp(name, "duration")) {
+ if (sscanf(value, "%d", &temp) == 1)
+ mDuration = temp;
+ } else {
+ printf("handleStringTag %s : %s\n", name, value);
+ }
+ return true;
+ }
+
+ // returns true if it succeeded, false if an exception occured in the Java code
+ virtual bool setMimeType(const char* mimeType)
+ {
+ mMimeType = mimeType;
+ mHasMimeType = true;
+ return true;
+ }
+
+ // returns true if it succeeded, false if an exception occured in the Java code
+ virtual bool addNoMediaFolder(const char* path)
+ {
+ printf("addNoMediaFolder %s\n", path);
+ return true;
+ }
+
+ void reset()
+ {
+ mHasTitle = false;
+ mHasArtist = false;
+ mHasAlbum = false;
+ mHasAlbumArtist = false;
+ mHasGenre = false;
+ mHasComposer = false;
+ mHasMimeType = false;
+ mTrack = mYear = mDuration = 0;
+ }
+
+ inline const char* getTitle() const { return mHasTitle ? (const char *)mTitle : NULL; }
+ inline const char* getArtist() const { return mHasArtist ? (const char *)mArtist : NULL; }
+ inline const char* getAlbum() const { return mHasAlbum ? (const char *)mAlbum : NULL; }
+ inline const char* getAlbumArtist() const { return mHasAlbumArtist ? (const char *)mAlbumArtist : NULL; }
+ inline const char* getGenre() const { return mHasGenre ? (const char *)mGenre : NULL; }
+ inline const char* getComposer() const { return mHasComposer ? (const char *)mComposer : NULL; }
+ inline const char* getMimeType() const { return mHasMimeType ? (const char *)mMimeType : NULL; }
+ inline int getTrack() const { return mTrack; }
+ inline int getYear() const { return mYear; }
+ inline int getDuration() const { return mDuration; }
+
+private:
+ MtpString mTitle;
+ MtpString mArtist;
+ MtpString mAlbum;
+ MtpString mAlbumArtist;
+ MtpString mGenre;
+ MtpString mComposer;
+ MtpString mMimeType;
+
+ bool mHasTitle;
+ bool mHasArtist;
+ bool mHasAlbum;
+ bool mHasAlbumArtist;
+ bool mHasGenre;
+ bool mHasComposer;
+ bool mHasMimeType;
+
+ int mTrack;
+ int mYear;
+ int mDuration;
+};
+
+
+MtpMediaScanner::MtpMediaScanner(MtpStorageID id, const char* filePath, MtpDatabase* db)
+ : mStorageID(id),
+ mFilePath(filePath),
+ mDatabase(db),
+ mMediaScanner(NULL),
+ mMediaScannerClient(NULL),
+ mFileList(NULL),
+ mFileCount(0)
+{
+ mMediaScanner = new StagefrightMediaScanner;
+ mMediaScannerClient = new MtpMediaScannerClient;
+}
+
+MtpMediaScanner::~MtpMediaScanner() {
+}
+
+bool MtpMediaScanner::scanFiles() {
+ mDatabase->beginTransaction();
+ mFileCount = 0;
+ mFileList = mDatabase->getFileList(mFileCount);
+
+ int ret = scanDirectory(mFilePath, MTP_PARENT_ROOT);
+
+ for (int i = 0; i < mFileCount; i++) {
+ MtpObjectHandle test = mFileList[i];
+ if (! (test & kObjectHandleMarkBit)) {
+ printf("delete missing file %08X\n", test);
+ mDatabase->deleteFile(test);
+ }
+ }
+
+ delete[] mFileList;
+ mFileCount = 0;
+ mDatabase->commitTransaction();
+ return (ret == 0);
+}
+
+
+static const struct MediaFileTypeEntry
+{
+ const char* extension;
+ MtpObjectFormat format;
+ uint32_t table;
+} sFileTypes[] =
+{
+ { "MP3", MTP_FORMAT_MP3, kObjectHandleTableAudio },
+ { "M4A", MTP_FORMAT_UNDEFINED_AUDIO, kObjectHandleTableAudio },
+ { "WAV", MTP_FORMAT_WAV, kObjectHandleTableAudio },
+ { "AMR", MTP_FORMAT_UNDEFINED_AUDIO, kObjectHandleTableAudio },
+ { "AWB", MTP_FORMAT_UNDEFINED_AUDIO, kObjectHandleTableAudio },
+ { "WMA", MTP_FORMAT_WMA, kObjectHandleTableAudio },
+ { "OGG", MTP_FORMAT_OGG, kObjectHandleTableAudio },
+ { "OGA", MTP_FORMAT_UNDEFINED_AUDIO, kObjectHandleTableAudio },
+ { "AAC", MTP_FORMAT_AAC, kObjectHandleTableAudio },
+ { "MID", MTP_FORMAT_UNDEFINED_AUDIO, kObjectHandleTableAudio },
+ { "MIDI", MTP_FORMAT_UNDEFINED_AUDIO, kObjectHandleTableAudio },
+ { "XMF", MTP_FORMAT_UNDEFINED_AUDIO, kObjectHandleTableAudio },
+ { "RTTTL", MTP_FORMAT_UNDEFINED_AUDIO, kObjectHandleTableAudio },
+ { "SMF", MTP_FORMAT_UNDEFINED_AUDIO, kObjectHandleTableAudio },
+ { "IMY", MTP_FORMAT_UNDEFINED_AUDIO, kObjectHandleTableAudio },
+ { "RTX", MTP_FORMAT_UNDEFINED_AUDIO, kObjectHandleTableAudio },
+ { "OTA", MTP_FORMAT_UNDEFINED_AUDIO, kObjectHandleTableAudio },
+ { "MPEG", MTP_FORMAT_UNDEFINED_VIDEO, kObjectHandleTableVideo },
+ { "MP4", MTP_FORMAT_UNDEFINED_VIDEO, kObjectHandleTableVideo },
+ { "M4V", MTP_FORMAT_UNDEFINED_VIDEO, kObjectHandleTableVideo },
+ { "3GP", MTP_FORMAT_UNDEFINED_VIDEO, kObjectHandleTableVideo },
+ { "3GPP", MTP_FORMAT_UNDEFINED_VIDEO, kObjectHandleTableVideo },
+ { "3G2", MTP_FORMAT_UNDEFINED_VIDEO, kObjectHandleTableVideo },
+ { "3GPP2", MTP_FORMAT_UNDEFINED_VIDEO, kObjectHandleTableVideo },
+ { "WMV", MTP_FORMAT_UNDEFINED_VIDEO, kObjectHandleTableVideo },
+ { "ASF", MTP_FORMAT_UNDEFINED_VIDEO, kObjectHandleTableVideo },
+ { "JPG", MTP_FORMAT_EXIF_JPEG, kObjectHandleTableImage },
+ { "JPEG", MTP_FORMAT_EXIF_JPEG, kObjectHandleTableImage },
+ { "GIF", MTP_FORMAT_GIF, kObjectHandleTableImage },
+ { "PNG", MTP_FORMAT_PNG, kObjectHandleTableImage },
+ { "BMP", MTP_FORMAT_BMP, kObjectHandleTableImage },
+ { "WBMP", MTP_FORMAT_BMP, kObjectHandleTableImage },
+ { "M3U", MTP_FORMAT_M3U_PLAYLIST, kObjectHandleTablePlaylist },
+ { "PLS", MTP_FORMAT_PLS_PLAYLIST, kObjectHandleTablePlaylist },
+ { "WPL", MTP_FORMAT_WPL_PLAYLIST, kObjectHandleTablePlaylist },
+};
+
+MtpObjectFormat MtpMediaScanner::getFileFormat(const char* path, uint32_t& table)
+{
+ const char* extension = strrchr(path, '.');
+ if (!extension)
+ return MTP_FORMAT_UNDEFINED;
+ extension++; // skip the dot
+
+ for (unsigned i = 0; i < sizeof(sFileTypes) / sizeof(sFileTypes[0]); i++) {
+ if (!strcasecmp(extension, sFileTypes[i].extension)) {
+ table = sFileTypes[i].table;
+ return sFileTypes[i].format;
+ }
+ }
+ table = kObjectHandleTableFile;
+ return MTP_FORMAT_UNDEFINED;
+}
+
+int MtpMediaScanner::scanDirectory(const char* path, MtpObjectHandle parent)
+{
+ char buffer[PATH_MAX];
+ struct dirent* entry;
+
+ unsigned length = strlen(path);
+ if (length > sizeof(buffer) + 2) {
+ fprintf(stderr, "path too long: %s\n", path);
+ }
+
+ DIR* dir = opendir(path);
+ if (!dir) {
+ fprintf(stderr, "opendir %s failed, errno: %d", path, errno);
+ return -1;
+ }
+
+ strncpy(buffer, path, sizeof(buffer));
+ char* fileStart = buffer + length;
+ // make sure we have a trailing slash
+ if (fileStart[-1] != '/') {
+ *(fileStart++) = '/';
+ }
+ int fileNameLength = sizeof(buffer) + fileStart - buffer;
+
+ while ((entry = readdir(dir))) {
+ const char* name = entry->d_name;
+
+ // ignore "." and "..", as well as any files or directories staring with dot
+ if (name[0] == '.') {
+ continue;
+ }
+ if (strlen(name) + 1 > fileNameLength) {
+ fprintf(stderr, "path too long for %s\n", name);
+ continue;
+ }
+ strcpy(fileStart, name);
+
+ struct stat statbuf;
+ memset(&statbuf, 0, sizeof(statbuf));
+ stat(buffer, &statbuf);
+
+ if (entry->d_type == DT_DIR) {
+ MtpObjectHandle handle = mDatabase->getObjectHandle(buffer);
+ if (handle) {
+ markFile(handle);
+ } else {
+ handle = mDatabase->addFile(buffer, MTP_FORMAT_ASSOCIATION,
+ parent, mStorageID, 0, statbuf.st_mtime);
+ }
+ scanDirectory(buffer, handle);
+ } else if (entry->d_type == DT_REG) {
+ scanFile(buffer, parent, statbuf);
+ }
+ }
+
+ closedir(dir);
+ return 0;
+}
+
+void MtpMediaScanner::scanFile(const char* path, MtpObjectHandle parent, struct stat& statbuf) {
+ uint32_t table;
+ MtpObjectFormat format = getFileFormat(path, table);
+ // don't scan unknown file types
+ if (format == MTP_FORMAT_UNDEFINED)
+ return;
+ MtpObjectHandle handle = mDatabase->getObjectHandle(path);
+ // fixme - rescan if mod date changed
+ if (handle) {
+ markFile(handle);
+ } else {
+ mDatabase->beginTransaction();
+ handle = mDatabase->addFile(path, format, parent, mStorageID,
+ statbuf.st_size, statbuf.st_mtime);
+ if (handle <= 0) {
+ fprintf(stderr, "addFile failed in MtpMediaScanner::scanFile()\n");
+ mDatabase->rollbackTransaction();
+ return;
+ }
+
+ if (table == kObjectHandleTableAudio) {
+ mMediaScannerClient->reset();
+ mMediaScanner->processFile(path, NULL, *mMediaScannerClient);
+ handle = mDatabase->addAudioFile(handle,
+ mMediaScannerClient->getTitle(),
+ mMediaScannerClient->getArtist(),
+ mMediaScannerClient->getAlbum(),
+ mMediaScannerClient->getAlbumArtist(),
+ mMediaScannerClient->getGenre(),
+ mMediaScannerClient->getComposer(),
+ mMediaScannerClient->getMimeType(),
+ mMediaScannerClient->getTrack(),
+ mMediaScannerClient->getYear(),
+ mMediaScannerClient->getDuration());
+ }
+ mDatabase->commitTransaction();
+ }
+}
+
+void MtpMediaScanner::markFile(MtpObjectHandle handle) {
+ if (mFileList) {
+ handle &= kObjectHandleIndexMask;
+ // binary search for the file in mFileList
+ int low = 0;
+ int high = mFileCount;
+ int index;
+
+ while (low < high) {
+ index = (low + high) >> 1;
+ MtpObjectHandle test = (mFileList[index] & kObjectHandleIndexMask);
+ if (handle < test)
+ high = index; // item is less than index
+ else if (handle > test)
+ low = index + 1; // item is greater than index
+ else {
+ mFileList[index] |= kObjectHandleMarkBit;
+ return;
+ }
+ }
+ fprintf(stderr, "file %d not found in mFileList\n", handle);
+ }
+}
+
+} // namespace android
diff --git a/media/mtp/MtpMediaScanner.h b/media/mtp/MtpMediaScanner.h
new file mode 100644
index 0000000..53d5063
--- /dev/null
+++ b/media/mtp/MtpMediaScanner.h
@@ -0,0 +1,56 @@
+/*
+ * 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 _MTP_MEDIA_SCANNER_H
+#define _MTP_MEDIA_SCANNER_H
+
+struct stat;
+
+namespace android {
+
+class MtpDatabase;
+class SqliteStatement;
+class MediaScanner;
+class MtpMediaScannerClient;
+
+class MtpMediaScanner {
+private:
+ MtpStorageID mStorageID;
+ const char* mFilePath;
+ MtpDatabase* mDatabase;
+ MediaScanner* mMediaScanner;
+ MtpMediaScannerClient* mMediaScannerClient;
+
+ // for garbage collecting missing files
+ MtpObjectHandle* mFileList;
+ int mFileCount;
+
+public:
+ MtpMediaScanner(MtpStorageID id, const char* filePath, MtpDatabase* db);
+ virtual ~MtpMediaScanner();
+
+ bool scanFiles();
+
+private:
+ MtpObjectFormat getFileFormat(const char* path, uint32_t& table);
+ int scanDirectory(const char* path, MtpObjectHandle parent);
+ void scanFile(const char* path, MtpObjectHandle parent, struct stat& statbuf);
+ void markFile(MtpObjectHandle handle);
+};
+
+}; // namespace android
+
+#endif // _MTP_MEDIA_SCANNER_H
diff --git a/media/mtp/MtpObjectInfo.cpp b/media/mtp/MtpObjectInfo.cpp
new file mode 100644
index 0000000..a0ee2b6
--- /dev/null
+++ b/media/mtp/MtpObjectInfo.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "MtpObjectInfo"
+#include "utils/Log.h"
+
+#include "MtpDataPacket.h"
+#include "MtpObjectInfo.h"
+#include "MtpStringBuffer.h"
+#include "MtpUtils.h"
+
+namespace android {
+
+MtpObjectInfo::MtpObjectInfo(MtpObjectHandle handle)
+ : mHandle(handle),
+ mStorageID(0),
+ mFormat(0),
+ mProtectionStatus(0),
+ mCompressedSize(0),
+ mThumbFormat(0),
+ mThumbCompressedSize(0),
+ mThumbPixWidth(0),
+ mThumbPixHeight(0),
+ mImagePixWidth(0),
+ mImagePixHeight(0),
+ mImagePixDepth(0),
+ mParent(0),
+ mAssociationType(0),
+ mAssociationDesc(0),
+ mSequenceNumber(0),
+ mName(NULL),
+ mDateCreated(0),
+ mDateModified(0),
+ mKeywords(NULL)
+{
+}
+
+MtpObjectInfo::~MtpObjectInfo() {
+ if (mName)
+ free(mName);
+ if (mKeywords)
+ free(mKeywords);
+}
+
+void MtpObjectInfo::read(MtpDataPacket& packet) {
+ MtpStringBuffer string;
+ time_t time;
+
+ mStorageID = packet.getUInt32();
+ mFormat = packet.getUInt16();
+ mProtectionStatus = packet.getUInt16();
+ mCompressedSize = packet.getUInt32();
+ mThumbFormat = packet.getUInt16();
+ mCompressedSize = packet.getUInt32();
+ mThumbPixWidth = packet.getUInt32();
+ mThumbPixHeight = packet.getUInt32();
+ mImagePixWidth = packet.getUInt32();
+ mImagePixHeight = packet.getUInt32();
+ mImagePixDepth = packet.getUInt32();
+ mParent = packet.getUInt32();
+ mAssociationType = packet.getUInt16();
+ mAssociationDesc = packet.getUInt32();
+ mSequenceNumber = packet.getUInt32();
+
+ packet.getString(string);
+ mName = strdup((const char *)string);
+
+ packet.getString(string);
+ if (parseDateTime((const char*)string, time))
+ mDateCreated = time;
+
+ packet.getString(string);
+ if (parseDateTime((const char*)string, time))
+ mDateModified = time;
+
+ packet.getString(string);
+ mKeywords = strdup((const char *)string);
+}
+
+void MtpObjectInfo::print() {
+ LOGD("MtpObject Info %08X: %s\n", mHandle, mName);
+}
+
+} // namespace android
diff --git a/media/mtp/MtpObjectInfo.h b/media/mtp/MtpObjectInfo.h
new file mode 100644
index 0000000..c7a449ca
--- /dev/null
+++ b/media/mtp/MtpObjectInfo.h
@@ -0,0 +1,60 @@
+/*
+ * 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 _MTP_OBJECT_INFO_H
+#define _MTP_OBJECT_INFO_H
+
+#include "MtpTypes.h"
+
+namespace android {
+
+class MtpDataPacket;
+
+class MtpObjectInfo {
+public:
+ MtpObjectHandle mHandle;
+ MtpStorageID mStorageID;
+ MtpObjectFormat mFormat;
+ uint16_t mProtectionStatus;
+ uint32_t mCompressedSize;
+ MtpObjectFormat mThumbFormat;
+ uint32_t mThumbCompressedSize;
+ uint32_t mThumbPixWidth;
+ uint32_t mThumbPixHeight;
+ uint32_t mImagePixWidth;
+ uint32_t mImagePixHeight;
+ uint32_t mImagePixDepth;
+ MtpObjectHandle mParent;
+ uint16_t mAssociationType;
+ uint32_t mAssociationDesc;
+ uint32_t mSequenceNumber;
+ char* mName;
+ time_t mDateCreated;
+ time_t mDateModified;
+ char* mKeywords;
+
+public:
+ MtpObjectInfo(MtpObjectHandle handle);
+ virtual ~MtpObjectInfo();
+
+ void read(MtpDataPacket& packet);
+
+ void print();
+};
+
+}; // namespace android
+
+#endif // _MTP_OBJECT_INFO_H
diff --git a/media/mtp/MtpPacket.cpp b/media/mtp/MtpPacket.cpp
new file mode 100644
index 0000000..3db6abb
--- /dev/null
+++ b/media/mtp/MtpPacket.cpp
@@ -0,0 +1,140 @@
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <usbhost/usbhost.h>
+
+#include "MtpPacket.h"
+#include "mtp.h"
+
+namespace android {
+
+MtpPacket::MtpPacket(int bufferSize)
+ : mBuffer(NULL),
+ mBufferSize(bufferSize),
+ mAllocationIncrement(bufferSize),
+ mPacketSize(0)
+{
+ mBuffer = (uint8_t *)malloc(bufferSize);
+ if (!mBuffer) {
+ fprintf(stderr, "out of memory!\n");
+ abort();
+ }
+}
+
+MtpPacket::~MtpPacket() {
+ if (mBuffer)
+ free(mBuffer);
+}
+
+void MtpPacket::reset() {
+ allocate(MTP_CONTAINER_HEADER_SIZE);
+ mPacketSize = MTP_CONTAINER_HEADER_SIZE;
+ memset(mBuffer, 0, mBufferSize);
+}
+
+void MtpPacket::allocate(int length) {
+ if (length > mBufferSize) {
+ int newLength = length + mAllocationIncrement;
+ mBuffer = (uint8_t *)realloc(mBuffer, newLength);
+ if (!mBuffer) {
+ fprintf(stderr, "out of memory!\n");
+ abort();
+ }
+ mBufferSize = newLength;
+ }
+}
+
+void MtpPacket::dump() {
+ for (int i = 0; i < mPacketSize; i++) {
+ printf("%02X ", mBuffer[i]);
+ if (i % 16 == 15)
+ printf("\n");
+ }
+ printf("\n\n");
+}
+
+uint16_t MtpPacket::getUInt16(int offset) const {
+ return ((uint16_t)mBuffer[offset + 1] << 8) | (uint16_t)mBuffer[offset];
+}
+
+uint32_t MtpPacket::getUInt32(int offset) const {
+ return ((uint32_t)mBuffer[offset + 3] << 24) | ((uint32_t)mBuffer[offset + 2] << 16) |
+ ((uint32_t)mBuffer[offset + 1] << 8) | (uint32_t)mBuffer[offset];
+}
+
+void MtpPacket::putUInt16(int offset, uint16_t value) {
+ mBuffer[offset++] = (uint8_t)(value & 0xFF);
+ mBuffer[offset++] = (uint8_t)((value >> 8) & 0xFF);
+}
+
+void MtpPacket::putUInt32(int offset, uint32_t value) {
+ mBuffer[offset++] = (uint8_t)(value & 0xFF);
+ mBuffer[offset++] = (uint8_t)((value >> 8) & 0xFF);
+ mBuffer[offset++] = (uint8_t)((value >> 16) & 0xFF);
+ mBuffer[offset++] = (uint8_t)((value >> 24) & 0xFF);
+}
+
+uint16_t MtpPacket::getContainerCode() const {
+ return getUInt16(MTP_CONTAINER_CODE_OFFSET);
+}
+
+void MtpPacket::setContainerCode(uint16_t code) {
+ putUInt16(MTP_CONTAINER_CODE_OFFSET, code);
+}
+
+MtpTransactionID MtpPacket::getTransactionID() const {
+ return getUInt32(MTP_CONTAINER_TRANSACTION_ID_OFFSET);
+}
+
+void MtpPacket::setTransactionID(MtpTransactionID id) {
+ putUInt32(MTP_CONTAINER_TRANSACTION_ID_OFFSET, id);
+}
+
+uint32_t MtpPacket::getParameter(int index) const {
+ if (index < 1 || index > 5) {
+ fprintf(stderr, "index %d out of range in MtpRequestPacket::getParameter\n", index);
+ return 0;
+ }
+ return getUInt32(MTP_CONTAINER_PARAMETER_OFFSET + (index - 1) * sizeof(uint32_t));
+}
+
+void MtpPacket::setParameter(int index, uint32_t value) {
+ if (index < 1 || index > 5) {
+ fprintf(stderr, "index %d out of range in MtpResponsePacket::setParameter\n", index);
+ return;
+ }
+ int offset = MTP_CONTAINER_PARAMETER_OFFSET + (index - 1) * sizeof(uint32_t);
+ if (mPacketSize < offset + sizeof(uint32_t))
+ mPacketSize = offset + sizeof(uint32_t);
+ putUInt32(offset, value);
+}
+
+#ifdef MTP_HOST
+int MtpPacket::transfer(struct usb_endpoint *ep, void* buffer, int length) {
+ if (usb_endpoint_queue(ep, buffer, length)) {
+ printf("usb_endpoint_queue failed, errno: %d\n", errno);
+ return -1;
+ }
+ int ep_num;
+ return usb_endpoint_wait(usb_endpoint_get_device(ep), &ep_num);
+}
+#endif
+
+} // namespace android
diff --git a/media/mtp/MtpPacket.h b/media/mtp/MtpPacket.h
new file mode 100644
index 0000000..a624a71
--- /dev/null
+++ b/media/mtp/MtpPacket.h
@@ -0,0 +1,71 @@
+/*
+ * 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 _MTP_PACKET_H
+#define _MTP_PACKET_H
+
+#include "MtpTypes.h"
+
+struct usb_endpoint;
+
+namespace android {
+
+class MtpStringBuffer;
+
+class MtpPacket {
+
+protected:
+ uint8_t* mBuffer;
+ // current size of the buffer
+ int mBufferSize;
+ // number of bytes to add when resizing the buffer
+ int mAllocationIncrement;
+ // size of the data in the packet
+ int mPacketSize;
+
+public:
+ MtpPacket(int bufferSize);
+ virtual ~MtpPacket();
+
+ // sets packet size to the default container size and sets buffer to zero
+ virtual void reset();
+
+ void allocate(int length);
+ void dump();
+
+ uint16_t getContainerCode() const;
+ void setContainerCode(uint16_t code);
+
+ MtpTransactionID getTransactionID() const;
+ void setTransactionID(MtpTransactionID id);
+
+ uint32_t getParameter(int index) const;
+ void setParameter(int index, uint32_t value);
+
+#ifdef MTP_HOST
+ int transfer(struct usb_endpoint *ep, void* buffer, int length);
+#endif
+
+protected:
+ uint16_t getUInt16(int offset) const;
+ uint32_t getUInt32(int offset) const;
+ void putUInt16(int offset, uint16_t value);
+ void putUInt32(int offset, uint32_t value);
+};
+
+}; // namespace android
+
+#endif // _MTP_PACKET_H
diff --git a/media/mtp/MtpProperty.cpp b/media/mtp/MtpProperty.cpp
new file mode 100644
index 0000000..65ce4d4
--- /dev/null
+++ b/media/mtp/MtpProperty.cpp
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "MtpProperty"
+#include "utils/Log.h"
+
+#include "MtpDataPacket.h"
+#include "MtpProperty.h"
+#include "MtpStringBuffer.h"
+#include "MtpUtils.h"
+
+namespace android {
+
+MtpProperty::MtpProperty()
+ : mCode(0),
+ mType(0),
+ mWriteable(false),
+ mDefaultArrayLength(0),
+ mDefaultArrayValues(NULL),
+ mCurrentArrayLength(0),
+ mCurrentArrayValues(NULL),
+ mFormFlag(kFormNone),
+ mEnumLength(0),
+ mEnumValues(NULL)
+{
+ mDefaultValue.str = NULL;
+ mCurrentValue.str = NULL;
+ mMinimumValue.str = NULL;
+ mMaximumValue.str = NULL;
+}
+
+MtpProperty::~MtpProperty() {
+ if (mType == MTP_TYPE_STR) {
+ // free all strings
+ free(mDefaultValue.str);
+ free(mCurrentValue.str);
+ free(mMinimumValue.str);
+ free(mMaximumValue.str);
+ if (mDefaultArrayValues) {
+ for (int i = 0; i < mDefaultArrayLength; i++)
+ free(mDefaultArrayValues[i].str);
+ }
+ if (mCurrentArrayValues) {
+ for (int i = 0; i < mCurrentArrayLength; i++)
+ free(mCurrentArrayValues[i].str);
+ }
+ if (mEnumValues) {
+ for (int i = 0; i < mEnumLength; i++)
+ free(mEnumValues[i].str);
+ }
+ }
+ delete[] mDefaultArrayValues;
+ delete[] mCurrentArrayValues;
+ delete[] mEnumValues;
+}
+
+void MtpProperty::read(MtpDataPacket& packet) {
+ MtpStringBuffer string;
+
+ mCode = packet.getUInt16();
+ mType = packet.getUInt16();
+ mWriteable = (packet.getUInt8() == 1);
+ switch (mType) {
+ case MTP_TYPE_AINT8:
+ case MTP_TYPE_AUINT8:
+ case MTP_TYPE_AINT16:
+ case MTP_TYPE_AUINT16:
+ case MTP_TYPE_AINT32:
+ case MTP_TYPE_AUINT32:
+ case MTP_TYPE_AINT64:
+ case MTP_TYPE_AUINT64:
+ case MTP_TYPE_AINT128:
+ case MTP_TYPE_AUINT128:
+ mDefaultArrayValues = readArrayValues(packet, mDefaultArrayLength);
+ mCurrentArrayValues = readArrayValues(packet, mCurrentArrayLength);
+ break;
+ default:
+ readValue(packet, mDefaultValue);
+ readValue(packet, mCurrentValue);
+ }
+ mFormFlag = packet.getUInt8();
+
+ if (mFormFlag == kFormRange) {
+ readValue(packet, mMinimumValue);
+ readValue(packet, mMaximumValue);
+ readValue(packet, mStepSize);
+ } else if (mFormFlag == kFormEnum) {
+ mEnumLength = packet.getUInt16();
+ mEnumValues = new MtpPropertyValue[mEnumLength];
+ for (int i = 0; i < mEnumLength; i++)
+ readValue(packet, mEnumValues[i]);
+ }
+}
+
+void MtpProperty::print() {
+ LOGD("MtpProperty %04X\n", mCode);
+ LOGD(" type %04X\n", mType);
+ LOGD(" writeable %s\n", (mWriteable ? "true" : "false"));
+}
+
+void MtpProperty::readValue(MtpDataPacket& packet, MtpPropertyValue& value) {
+ switch (mType) {
+ case MTP_TYPE_INT8:
+ value.i8 = packet.getInt8();
+ break;
+ case MTP_TYPE_UINT8:
+ value.u8 = packet.getUInt8();
+ break;
+ case MTP_TYPE_INT16:
+ value.i16 = packet.getInt16();
+ break;
+ case MTP_TYPE_UINT16:
+ value.u16 = packet.getUInt16();
+ break;
+ case MTP_TYPE_INT32:
+ value.i32 = packet.getInt32();
+ break;
+ case MTP_TYPE_UINT32:
+ value.u32 = packet.getUInt32();
+ break;
+ case MTP_TYPE_INT64:
+ value.i64 = packet.getInt64();
+ break;
+ case MTP_TYPE_UINT64:
+ value.u64 = packet.getUInt64();
+ break;
+ case MTP_TYPE_INT128:
+ packet.getInt128(value.i128);
+ break;
+ case MTP_TYPE_UINT128:
+ packet.getUInt128(value.u128);
+ break;
+ default:
+ fprintf(stderr, "unknown type %d in MtpProperty::readValue\n", mType);
+ }
+}
+
+MtpPropertyValue* MtpProperty::readArrayValues(MtpDataPacket& packet, int& length) {
+ length = packet.getUInt32();
+ if (length == 0)
+ return NULL;
+ MtpPropertyValue* result = new MtpPropertyValue[length];
+ for (int i = 0; i < length; i++)
+ readValue(packet, result[i]);
+ return result;
+}
+
+} // namespace android
diff --git a/media/mtp/MtpProperty.h b/media/mtp/MtpProperty.h
new file mode 100644
index 0000000..6372290
--- /dev/null
+++ b/media/mtp/MtpProperty.h
@@ -0,0 +1,71 @@
+/*
+ * 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 _MTP_PROPERTY_H
+#define _MTP_PROPERTY_H
+
+#include "MtpTypes.h"
+
+namespace android {
+
+class MtpDataPacket;
+
+class MtpProperty {
+public:
+ MtpPropertyCode mCode;
+ MtpDataType mType;
+ bool mWriteable;
+ MtpPropertyValue mDefaultValue;
+ MtpPropertyValue mCurrentValue;
+
+ // for array types
+ int mDefaultArrayLength;
+ MtpPropertyValue* mDefaultArrayValues;
+ int mCurrentArrayLength;
+ MtpPropertyValue* mCurrentArrayValues;
+
+ enum {
+ kFormNone = 0,
+ kFormRange = 1,
+ kFormEnum = 2,
+ };
+ uint8_t mFormFlag;
+
+ // for range form
+ MtpPropertyValue mMinimumValue;
+ MtpPropertyValue mMaximumValue;
+ MtpPropertyValue mStepSize;
+
+ // for enum form
+ int mEnumLength;
+ MtpPropertyValue* mEnumValues;
+
+public:
+ MtpProperty();
+ virtual ~MtpProperty();
+
+ void read(MtpDataPacket& packet);
+
+ void print();
+
+private:
+ void readValue(MtpDataPacket& packet, MtpPropertyValue& value);
+ MtpPropertyValue* readArrayValues(MtpDataPacket& packet, int& length);
+};
+
+}; // namespace android
+
+#endif // _MTP_PROPERTY_H
diff --git a/media/mtp/MtpRequestPacket.cpp b/media/mtp/MtpRequestPacket.cpp
new file mode 100644
index 0000000..e3a720c
--- /dev/null
+++ b/media/mtp/MtpRequestPacket.cpp
@@ -0,0 +1,54 @@
+/*
+ * 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 <stdio.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+#include "MtpRequestPacket.h"
+
+namespace android {
+
+MtpRequestPacket::MtpRequestPacket()
+ : MtpPacket(512)
+{
+}
+
+MtpRequestPacket::~MtpRequestPacket() {
+}
+
+#ifdef MTP_DEVICE
+int MtpRequestPacket::read(int fd) {
+ int ret = ::read(fd, mBuffer, mBufferSize);
+ if (ret >= 0)
+ mPacketSize = ret;
+ else
+ mPacketSize = 0;
+ return ret;
+}
+#endif
+
+#ifdef MTP_HOST
+ // write our buffer to the given endpoint (host mode)
+int MtpRequestPacket::write(struct usb_endpoint *ep)
+{
+ putUInt32(MTP_CONTAINER_LENGTH_OFFSET, mPacketSize);
+ putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_COMMAND);
+ return transfer(ep, mBuffer, mPacketSize);
+}
+#endif
+
+} // namespace android
diff --git a/media/mtp/MtpRequestPacket.h b/media/mtp/MtpRequestPacket.h
new file mode 100644
index 0000000..df518f2
--- /dev/null
+++ b/media/mtp/MtpRequestPacket.h
@@ -0,0 +1,48 @@
+/*
+ * 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 _MTP_REQUEST_PACKET_H
+#define _MTP_REQUEST_PACKET_H
+
+#include "MtpPacket.h"
+#include "mtp.h"
+
+namespace android {
+
+class MtpRequestPacket : public MtpPacket {
+
+public:
+ MtpRequestPacket();
+ virtual ~MtpRequestPacket();
+
+#ifdef MTP_DEVICE
+ // fill our buffer with data from the given file descriptor
+ int read(int fd);
+#endif
+
+#ifdef MTP_HOST
+ // write our buffer to the given endpoint
+ int write(struct usb_endpoint *ep);
+#endif
+
+ inline MtpOperationCode getOperationCode() const { return getContainerCode(); }
+ inline void setOperationCode(MtpOperationCode code)
+ { return setContainerCode(code); }
+};
+
+}; // namespace android
+
+#endif // _MTP_REQUEST_PACKET_H
diff --git a/media/mtp/MtpResponsePacket.cpp b/media/mtp/MtpResponsePacket.cpp
new file mode 100644
index 0000000..a1979d7
--- /dev/null
+++ b/media/mtp/MtpResponsePacket.cpp
@@ -0,0 +1,55 @@
+/*
+ * 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 <stdio.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+#include "MtpResponsePacket.h"
+
+namespace android {
+
+MtpResponsePacket::MtpResponsePacket()
+ : MtpPacket(512)
+{
+}
+
+MtpResponsePacket::~MtpResponsePacket() {
+}
+
+#ifdef MTP_DEVICE
+int MtpResponsePacket::write(int fd) {
+ putUInt32(MTP_CONTAINER_LENGTH_OFFSET, mPacketSize);
+ putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_RESPONSE);
+ int ret = ::write(fd, mBuffer, mPacketSize);
+ return (ret < 0 ? ret : 0);
+}
+#endif
+
+#ifdef MTP_HOST
+ // read our buffer from the given endpoint
+int MtpResponsePacket::read(struct usb_endpoint *ep) {
+ int ret = transfer(ep, mBuffer, mBufferSize);
+ if (ret >= 0)
+ mPacketSize = ret;
+ else
+ mPacketSize = 0;
+ return ret;
+}
+#endif
+
+} // namespace android
+
diff --git a/media/mtp/MtpResponsePacket.h b/media/mtp/MtpResponsePacket.h
new file mode 100644
index 0000000..373f8f9
--- /dev/null
+++ b/media/mtp/MtpResponsePacket.h
@@ -0,0 +1,48 @@
+/*
+ * 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 _MTP_RESPONSE_PACKET_H
+#define _MTP_RESPONSE_PACKET_H
+
+#include "MtpPacket.h"
+#include "mtp.h"
+
+namespace android {
+
+class MtpResponsePacket : public MtpPacket {
+
+public:
+ MtpResponsePacket();
+ virtual ~MtpResponsePacket();
+
+#ifdef MTP_DEVICE
+ // write our data to the given file descriptor
+ int write(int fd);
+#endif
+
+#ifdef MTP_HOST
+ // read our buffer from the given endpoint
+ int read(struct usb_endpoint *ep);
+#endif
+
+ inline MtpResponseCode getResponseCode() const { return getContainerCode(); }
+ inline void setResponseCode(MtpResponseCode code)
+ { return setContainerCode(code); }
+};
+
+}; // namespace android
+
+#endif // _MTP_RESPONSE_PACKET_H
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
new file mode 100644
index 0000000..73dee0d
--- /dev/null
+++ b/media/mtp/MtpServer.cpp
@@ -0,0 +1,580 @@
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "MtpDebug.h"
+#include "MtpServer.h"
+#include "MtpStorage.h"
+#include "MtpStringBuffer.h"
+#include "MtpDatabase.h"
+
+#include "f_mtp.h"
+
+namespace android {
+
+static const MtpOperationCode kSupportedOperationCodes[] = {
+ MTP_OPERATION_GET_DEVICE_INFO,
+ MTP_OPERATION_OPEN_SESSION,
+ MTP_OPERATION_CLOSE_SESSION,
+ MTP_OPERATION_GET_STORAGE_IDS,
+ MTP_OPERATION_GET_STORAGE_INFO,
+ MTP_OPERATION_GET_NUM_OBJECTS,
+ MTP_OPERATION_GET_OBJECT_HANDLES,
+ MTP_OPERATION_GET_OBJECT_INFO,
+ MTP_OPERATION_GET_OBJECT,
+// MTP_OPERATION_GET_THUMB,
+ MTP_OPERATION_DELETE_OBJECT,
+ MTP_OPERATION_SEND_OBJECT_INFO,
+ MTP_OPERATION_SEND_OBJECT,
+// MTP_OPERATION_INITIATE_CAPTURE,
+// MTP_OPERATION_FORMAT_STORE,
+// MTP_OPERATION_RESET_DEVICE,
+// MTP_OPERATION_SELF_TEST,
+// MTP_OPERATION_SET_OBJECT_PROTECTION,
+// MTP_OPERATION_POWER_DOWN,
+ MTP_OPERATION_GET_DEVICE_PROP_DESC,
+ MTP_OPERATION_GET_DEVICE_PROP_VALUE,
+ MTP_OPERATION_SET_DEVICE_PROP_VALUE,
+ MTP_OPERATION_RESET_DEVICE_PROP_VALUE,
+// MTP_OPERATION_TERMINATE_OPEN_CAPTURE,
+// MTP_OPERATION_MOVE_OBJECT,
+// MTP_OPERATION_COPY_OBJECT,
+// MTP_OPERATION_GET_PARTIAL_OBJECT,
+// MTP_OPERATION_INITIATE_OPEN_CAPTURE,
+ MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED,
+// MTP_OPERATION_GET_OBJECT_PROP_DESC,
+ MTP_OPERATION_GET_OBJECT_PROP_VALUE,
+ MTP_OPERATION_SET_OBJECT_PROP_VALUE,
+// MTP_OPERATION_GET_OBJECT_REFERENCES,
+// MTP_OPERATION_SET_OBJECT_REFERENCES,
+// MTP_OPERATION_SKIP,
+};
+
+static const MtpObjectProperty kSupportedObjectProperties[] = {
+ MTP_PROPERTY_STORAGE_ID,
+ MTP_PROPERTY_OBJECT_FORMAT,
+ MTP_PROPERTY_OBJECT_SIZE,
+ MTP_PROPERTY_OBJECT_FILE_NAME,
+ MTP_PROPERTY_PARENT_OBJECT,
+};
+
+static const MtpObjectFormat kSupportedPlaybackFormats[] = {
+ // MTP_FORMAT_UNDEFINED,
+ MTP_FORMAT_ASSOCIATION,
+ // MTP_FORMAT_TEXT,
+ // MTP_FORMAT_HTML,
+ MTP_FORMAT_MP3,
+ //MTP_FORMAT_AVI,
+ MTP_FORMAT_MPEG,
+ // MTP_FORMAT_ASF,
+ MTP_FORMAT_EXIF_JPEG,
+ MTP_FORMAT_TIFF_EP,
+ // MTP_FORMAT_BMP,
+ MTP_FORMAT_GIF,
+ MTP_FORMAT_JFIF,
+ MTP_FORMAT_PNG,
+ MTP_FORMAT_TIFF,
+ MTP_FORMAT_WMA,
+ MTP_FORMAT_OGG,
+ MTP_FORMAT_AAC,
+ // MTP_FORMAT_FLAC,
+ // MTP_FORMAT_WMV,
+ MTP_FORMAT_MP4_CONTAINER,
+ MTP_FORMAT_MP2,
+ MTP_FORMAT_3GP_CONTAINER,
+ // MTP_FORMAT_ABSTRACT_AUDIO_ALBUM,
+ // MTP_FORMAT_ABSTRACT_AV_PLAYLIST,
+ // MTP_FORMAT_WPL_PLAYLIST,
+ // MTP_FORMAT_M3U_PLAYLIST,
+ // MTP_FORMAT_MPL_PLAYLIST,
+ // MTP_FORMAT_PLS_PLAYLIST,
+};
+
+MtpServer::MtpServer(int fd, const char* databasePath)
+ : mFD(fd),
+ mDatabasePath(databasePath),
+ mDatabase(NULL),
+ mSessionID(0),
+ mSessionOpen(false),
+ mSendObjectHandle(kInvalidObjectHandle),
+ mSendObjectFileSize(0)
+{
+ mDatabase = new MtpDatabase();
+ mDatabase->open(databasePath, true);
+}
+
+MtpServer::~MtpServer() {
+}
+
+void MtpServer::addStorage(const char* filePath) {
+ int index = mStorages.size() + 1;
+ index |= index << 16; // set high and low part to our index
+ MtpStorage* storage = new MtpStorage(index, filePath, mDatabase);
+ addStorage(storage);
+}
+
+MtpStorage* MtpServer::getStorage(MtpStorageID id) {
+ for (int i = 0; i < mStorages.size(); i++) {
+ MtpStorage* storage = mStorages[i];
+ if (storage->getStorageID() == id)
+ return storage;
+ }
+ return NULL;
+}
+
+void MtpServer::scanStorage() {
+ for (int i = 0; i < mStorages.size(); i++) {
+ MtpStorage* storage = mStorages[i];
+ storage->scanFiles();
+ }
+}
+
+void MtpServer::run() {
+ int fd = mFD;
+
+ printf("MtpServer::run fd: %d\n", fd);
+
+ while (1) {
+ int ret = mRequest.read(fd);
+ if (ret < 0) {
+ fprintf(stderr, "request read returned %d, errno: %d\n", ret, errno);
+ if (errno == ECANCELED) {
+ // return to top of loop and wait for next command
+ continue;
+ }
+ break;
+ }
+ MtpOperationCode operation = mRequest.getOperationCode();
+ MtpTransactionID transaction = mRequest.getTransactionID();
+
+ printf("operation: %s\n", MtpDebug::getOperationCodeName(operation));
+ mRequest.dump();
+
+ // FIXME need to generalize this
+ bool dataIn = (operation == MTP_OPERATION_SEND_OBJECT_INFO);
+ if (dataIn) {
+ int ret = mData.read(fd);
+ if (ret < 0) {
+ fprintf(stderr, "data read returned %d, errno: %d\n", ret, errno);
+ if (errno == ECANCELED) {
+ // return to top of loop and wait for next command
+ continue;
+ }
+ break;
+ }
+ printf("received data:\n");
+ mData.dump();
+ } else {
+ mData.reset();
+ }
+
+ if (handleRequest()) {
+ if (!dataIn && mData.hasData()) {
+ mData.setOperationCode(operation);
+ mData.setTransactionID(transaction);
+ printf("sending data:\n");
+ mData.dump();
+ ret = mData.write(fd);
+ if (ret < 0) {
+ fprintf(stderr, "request write returned %d, errno: %d\n", ret, errno);
+ if (errno == ECANCELED) {
+ // return to top of loop and wait for next command
+ continue;
+ }
+ break;
+ }
+ }
+
+ mResponse.setTransactionID(transaction);
+ printf("sending response %04X\n", mResponse.getResponseCode());
+ ret = mResponse.write(fd);
+ if (ret < 0) {
+ fprintf(stderr, "request write returned %d, errno: %d\n", ret, errno);
+ if (errno == ECANCELED) {
+ // return to top of loop and wait for next command
+ continue;
+ }
+ break;
+ }
+ } else {
+ printf("skipping response\n");
+ }
+ }
+}
+
+bool MtpServer::handleRequest() {
+ MtpOperationCode operation = mRequest.getOperationCode();
+ MtpResponseCode response;
+
+ mResponse.reset();
+
+ if (mSendObjectHandle != kInvalidObjectHandle && operation != MTP_OPERATION_SEND_OBJECT) {
+ // FIXME - need to delete mSendObjectHandle from the database
+ fprintf(stderr, "expected SendObject after SendObjectInfo\n");
+ mSendObjectHandle = kInvalidObjectHandle;
+ }
+
+ switch (operation) {
+ case MTP_OPERATION_GET_DEVICE_INFO:
+ response = doGetDeviceInfo();
+ break;
+ case MTP_OPERATION_OPEN_SESSION:
+ response = doOpenSession();
+ break;
+ case MTP_OPERATION_CLOSE_SESSION:
+ response = doCloseSession();
+ break;
+ case MTP_OPERATION_GET_STORAGE_IDS:
+ response = doGetStorageIDs();
+ break;
+ case MTP_OPERATION_GET_STORAGE_INFO:
+ response = doGetStorageInfo();
+ break;
+ case MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED:
+ response = doGetObjectPropsSupported();
+ break;
+ case MTP_OPERATION_GET_OBJECT_HANDLES:
+ response = doGetObjectHandles();
+ break;
+ case MTP_OPERATION_GET_OBJECT_PROP_VALUE:
+ response = doGetObjectPropValue();
+ break;
+ case MTP_OPERATION_GET_OBJECT_INFO:
+ response = doGetObjectInfo();
+ break;
+ case MTP_OPERATION_GET_OBJECT:
+ response = doGetObject();
+ break;
+ case MTP_OPERATION_SEND_OBJECT_INFO:
+ response = doSendObjectInfo();
+ break;
+ case MTP_OPERATION_SEND_OBJECT:
+ response = doSendObject();
+ break;
+ case MTP_OPERATION_DELETE_OBJECT:
+ response = doDeleteObject();
+ break;
+ case MTP_OPERATION_GET_OBJECT_PROP_DESC:
+ default:
+ response = MTP_RESPONSE_OPERATION_NOT_SUPPORTED;
+ break;
+ }
+
+ if (response == MTP_RESPONSE_TRANSACTION_CANCELLED)
+ return false;
+ mResponse.setResponseCode(response);
+ return true;
+}
+
+MtpResponseCode MtpServer::doGetDeviceInfo() {
+ MtpStringBuffer string;
+
+ // fill in device info
+ mData.putUInt16(MTP_STANDARD_VERSION);
+ mData.putUInt32(6); // MTP Vendor Extension ID
+ mData.putUInt16(MTP_STANDARD_VERSION);
+ string.set("microsoft.com: 1.0;");
+ mData.putString(string); // MTP Extensions
+ mData.putUInt16(0); //Functional Mode
+ mData.putAUInt16(kSupportedOperationCodes,
+ sizeof(kSupportedOperationCodes) / sizeof(uint16_t)); // Operations Supported
+ mData.putEmptyArray(); // Events Supported
+ mData.putEmptyArray(); // Device Properties Supported
+ mData.putEmptyArray(); // Capture Formats
+ mData.putAUInt16(kSupportedPlaybackFormats,
+ sizeof(kSupportedPlaybackFormats) / sizeof(uint16_t)); // Playback Formats
+ // FIXME
+ string.set("Google, Inc.");
+ mData.putString(string); // Manufacturer
+ string.set("Just an Ordinary MTP Device");
+ mData.putString(string); // Model
+ string.set("1.0");
+ mData.putString(string); // Device Version
+ string.set("123456789012345678AA");
+ mData.putString(string); // Serial Number
+
+ return MTP_RESPONSE_OK;
+}
+
+MtpResponseCode MtpServer::doOpenSession() {
+ if (mSessionOpen) {
+ mResponse.setParameter(1, mSessionID);
+ return MTP_RESPONSE_SESSION_ALREADY_OPEN;
+ }
+ mSessionID = mRequest.getParameter(1);
+ mSessionOpen = true;
+ return MTP_RESPONSE_OK;
+}
+
+MtpResponseCode MtpServer::doCloseSession() {
+ if (!mSessionOpen)
+ return MTP_RESPONSE_SESSION_NOT_OPEN;
+ mSessionID = 0;
+ mSessionOpen = false;
+ return MTP_RESPONSE_OK;
+}
+
+MtpResponseCode MtpServer::doGetStorageIDs() {
+ if (!mSessionOpen)
+ return MTP_RESPONSE_SESSION_NOT_OPEN;
+
+ int count = mStorages.size();
+ mData.putUInt32(count);
+ for (int i = 0; i < count; i++)
+ mData.putUInt32(mStorages[i]->getStorageID());
+
+ return MTP_RESPONSE_OK;
+}
+
+MtpResponseCode MtpServer::doGetStorageInfo() {
+ MtpStringBuffer string;
+
+ if (!mSessionOpen)
+ return MTP_RESPONSE_SESSION_NOT_OPEN;
+ MtpStorageID id = mRequest.getParameter(1);
+ MtpStorage* storage = getStorage(id);
+ if (!storage)
+ return MTP_RESPONSE_INVALID_STORAGE_ID;
+
+ mData.putUInt16(storage->getType());
+ mData.putUInt16(storage->getFileSystemType());
+ mData.putUInt16(storage->getAccessCapability());
+ mData.putUInt64(storage->getMaxCapacity());
+ mData.putUInt64(storage->getFreeSpace());
+ mData.putUInt32(1024*1024*1024); // Free Space in Objects
+ string.set(storage->getDescription());
+ mData.putString(string);
+ mData.putEmptyString(); // Volume Identifier
+
+ return MTP_RESPONSE_OK;
+}
+
+MtpResponseCode MtpServer::doGetObjectPropsSupported() {
+ if (!mSessionOpen)
+ return MTP_RESPONSE_SESSION_NOT_OPEN;
+ MtpObjectFormat format = mRequest.getParameter(1);
+ mData.putAUInt16(kSupportedObjectProperties,
+ sizeof(kSupportedObjectProperties) / sizeof(uint16_t));
+ return MTP_RESPONSE_OK;
+}
+
+MtpResponseCode MtpServer::doGetObjectHandles() {
+ if (!mSessionOpen)
+ return MTP_RESPONSE_SESSION_NOT_OPEN;
+ MtpStorageID storageID = mRequest.getParameter(1); // 0xFFFFFFFF for all storage
+ MtpObjectFormat format = mRequest.getParameter(2); // 0 for all formats
+ MtpObjectHandle parent = mRequest.getParameter(3); // 0xFFFFFFFF for objects with no parent
+ // 0x00000000 for all objects?
+
+ MtpObjectHandleList* handles = mDatabase->getObjectList(storageID, format, parent);
+ mData.putAUInt32(handles);
+ delete handles;
+ return MTP_RESPONSE_OK;
+}
+
+MtpResponseCode MtpServer::doGetObjectPropValue() {
+ MtpObjectHandle handle = mRequest.getParameter(1);
+ MtpObjectProperty property = mRequest.getParameter(2);
+
+ return mDatabase->getObjectProperty(handle, property, mData);
+}
+
+MtpResponseCode MtpServer::doGetObjectInfo() {
+ MtpObjectHandle handle = mRequest.getParameter(1);
+ return mDatabase->getObjectInfo(handle, mData);
+}
+
+MtpResponseCode MtpServer::doGetObject() {
+ MtpObjectHandle handle = mRequest.getParameter(1);
+ MtpString filePath;
+ int64_t fileLength;
+ if (!mDatabase->getObjectFilePath(handle, filePath, fileLength))
+ return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
+
+ mtp_file_range mfr;
+ mfr.path = filePath;
+ mfr.path_length = strlen(mfr.path);
+ mfr.offset = 0;
+ mfr.length = fileLength;
+
+ // send data header
+ mData.setOperationCode(mRequest.getOperationCode());
+ mData.setTransactionID(mRequest.getTransactionID());
+ mData.writeDataHeader(mFD, fileLength);
+
+ // then transfer the file
+ int ret = ioctl(mFD, MTP_SEND_FILE, (unsigned long)&mfr);
+ if (ret < 0) {
+ if (errno == ECANCELED)
+ return MTP_RESPONSE_TRANSACTION_CANCELLED;
+ else
+ return MTP_RESPONSE_GENERAL_ERROR;
+ }
+ return MTP_RESPONSE_OK;
+}
+
+MtpResponseCode MtpServer::doSendObjectInfo() {
+ MtpString path;
+ MtpStorageID storageID = mRequest.getParameter(1);
+ MtpStorage* storage = getStorage(storageID);
+ MtpObjectHandle parent = mRequest.getParameter(2);
+ if (!storage)
+ return MTP_RESPONSE_INVALID_STORAGE_ID;
+
+ // special case the root
+ if (parent == MTP_PARENT_ROOT)
+ path = storage->getPath();
+ else {
+ int64_t dummy;
+ if (!mDatabase->getObjectFilePath(parent, path, dummy))
+ return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
+ }
+
+ // read only the fields we need
+ mData.getUInt32(); // storage ID
+ MtpObjectFormat format = mData.getUInt16();
+ mData.getUInt16(); // protection status
+ mSendObjectFileSize = mData.getUInt32();
+ mData.getUInt16(); // thumb format
+ mData.getUInt32(); // thumb compressed size
+ mData.getUInt32(); // thumb pix width
+ mData.getUInt32(); // thumb pix height
+ mData.getUInt32(); // image pix width
+ mData.getUInt32(); // image pix height
+ mData.getUInt32(); // image bit depth
+ mData.getUInt32(); // parent
+ uint16_t associationType = mData.getUInt16();
+ uint32_t associationDesc = mData.getUInt32(); // association desc
+ mData.getUInt32(); // sequence number
+ MtpStringBuffer name, created, modified;
+ mData.getString(name); // file name
+ mData.getString(created); // date created
+ mData.getString(modified); // date modified
+ // keywords follow
+
+ time_t modifiedTime;
+ if (!parseDateTime(modified, modifiedTime))
+ modifiedTime = 0;
+printf("SendObjectInfo format: %04X size: %d name: %s, created: %s, modified: %s\n",
+format, mSendObjectFileSize, (const char*)name, (const char*)created, (const char*)modified);
+
+ if (path[path.size() - 1] != '/')
+ path += "/";
+ path += (const char *)name;
+
+ mDatabase->beginTransaction();
+ MtpObjectHandle handle = mDatabase->addFile((const char*)path, format, parent, storageID,
+ mSendObjectFileSize, modifiedTime);
+ if (handle == kInvalidObjectHandle) {
+ mDatabase->rollbackTransaction();
+ return MTP_RESPONSE_GENERAL_ERROR;
+ }
+ uint32_t table = MtpDatabase::getTableForFile(format);
+ if (table == kObjectHandleTableAudio)
+ handle = mDatabase->addAudioFile(handle);
+ mDatabase->commitTransaction();
+
+ if (format == MTP_FORMAT_ASSOCIATION) {
+ mode_t mask = umask(0);
+ int ret = mkdir((const char *)path, S_IRWXU | S_IRWXG | S_IRWXO);
+ umask(mask);
+ if (ret && ret != -EEXIST)
+ return MTP_RESPONSE_GENERAL_ERROR;
+ } else {
+ mSendObjectFilePath = path;
+ // save the handle for the SendObject call, which should follow
+ mSendObjectHandle = handle;
+ }
+
+ mResponse.setParameter(1, storageID);
+ mResponse.setParameter(2, parent);
+ mResponse.setParameter(3, handle);
+
+ return MTP_RESPONSE_OK;
+}
+
+MtpResponseCode MtpServer::doSendObject() {
+ if (mSendObjectHandle == kInvalidObjectHandle) {
+ fprintf(stderr, "Expected SendObjectInfo before SendObject\n");
+ return MTP_RESPONSE_NO_VALID_OBJECT_INFO;
+ }
+
+ // read the header
+ int ret = mData.readDataHeader(mFD);
+ // FIXME - check for errors here.
+
+ // reset so we don't attempt to send this back
+ mData.reset();
+
+ mtp_file_range mfr;
+ mfr.path = (const char*)mSendObjectFilePath;
+ mfr.path_length = strlen(mfr.path);
+ mfr.offset = 0;
+ mfr.length = mSendObjectFileSize;
+
+ // transfer the file
+ ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
+ // FIXME - we need to delete mSendObjectHandle from the database if this fails.
+ printf("MTP_RECEIVE_FILE returned %d\n", ret);
+ mSendObjectHandle = kInvalidObjectHandle;
+
+ if (ret < 0) {
+ unlink(mSendObjectFilePath);
+ if (errno == ECANCELED)
+ return MTP_RESPONSE_TRANSACTION_CANCELLED;
+ else
+ return MTP_RESPONSE_GENERAL_ERROR;
+ }
+ return MTP_RESPONSE_OK;
+}
+
+MtpResponseCode MtpServer::doDeleteObject() {
+ MtpObjectHandle handle = mRequest.getParameter(1);
+ MtpObjectFormat format = mRequest.getParameter(1);
+ // FIXME - support deleting all objects if handle is 0xFFFFFFFF
+ // FIXME - implement deleting objects by format
+ // FIXME - handle non-empty directories
+
+ MtpString filePath;
+ int64_t fileLength;
+ if (!mDatabase->getObjectFilePath(handle, filePath, fileLength))
+ return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
+
+printf("deleting %s\n", (const char *)filePath);
+ // one of these should work
+ rmdir((const char *)filePath);
+ unlink((const char *)filePath);
+
+ mDatabase->deleteFile(handle);
+
+ return MTP_RESPONSE_OK;
+}
+
+MtpResponseCode MtpServer::doGetObjectPropDesc() {
+ MtpObjectProperty property = mRequest.getParameter(1);
+ MtpObjectFormat format = mRequest.getParameter(2);
+
+ return -1;
+}
+
+} // namespace android
diff --git a/media/mtp/MtpServer.h b/media/mtp/MtpServer.h
new file mode 100644
index 0000000..40f3c52
--- /dev/null
+++ b/media/mtp/MtpServer.h
@@ -0,0 +1,90 @@
+/*
+ * 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 _MTP_SERVER_H
+#define _MTP_SERVER_H
+
+#include "MtpRequestPacket.h"
+#include "MtpDataPacket.h"
+#include "MtpResponsePacket.h"
+#include "mtp.h"
+
+#include "MtpUtils.h"
+
+namespace android {
+
+class MtpStorage;
+class MtpDatabase;
+
+class MtpServer {
+
+private:
+ // file descriptor for MTP kernel driver
+ int mFD;
+
+ // path to our sqlite3 database
+ const char* mDatabasePath;
+
+ MtpDatabase* mDatabase;
+
+ // current session ID
+ MtpSessionID mSessionID;
+ // true if we have an open session and mSessionID is valid
+ bool mSessionOpen;
+
+ MtpRequestPacket mRequest;
+ MtpDataPacket mData;
+ MtpResponsePacket mResponse;
+
+ MtpStorageList mStorages;
+
+ // handle for new object, set by SendObjectInfo and used by SendObject
+ MtpObjectHandle mSendObjectHandle;
+ MtpString mSendObjectFilePath;
+ size_t mSendObjectFileSize;
+
+public:
+ MtpServer(int fd, const char* databasePath);
+ virtual ~MtpServer();
+
+ void addStorage(const char* filePath);
+ inline void addStorage(MtpStorage* storage) { mStorages.push(storage); }
+ MtpStorage* getStorage(MtpStorageID id);
+ void scanStorage();
+ void run();
+
+private:
+ bool handleRequest();
+
+ MtpResponseCode doGetDeviceInfo();
+ MtpResponseCode doOpenSession();
+ MtpResponseCode doCloseSession();
+ MtpResponseCode doGetStorageIDs();
+ MtpResponseCode doGetStorageInfo();
+ MtpResponseCode doGetObjectPropsSupported();
+ MtpResponseCode doGetObjectHandles();
+ MtpResponseCode doGetObjectPropValue();
+ MtpResponseCode doGetObjectInfo();
+ MtpResponseCode doGetObject();
+ MtpResponseCode doSendObjectInfo();
+ MtpResponseCode doSendObject();
+ MtpResponseCode doDeleteObject();
+ MtpResponseCode doGetObjectPropDesc();
+};
+
+}; // namespace android
+
+#endif // _MTP_SERVER_H
diff --git a/media/mtp/MtpStorage.cpp b/media/mtp/MtpStorage.cpp
new file mode 100644
index 0000000..f176148
--- /dev/null
+++ b/media/mtp/MtpStorage.cpp
@@ -0,0 +1,82 @@
+/*
+ * 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 "MtpDatabase.h"
+#include "MtpStorage.h"
+#include "MtpMediaScanner.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <limits.h>
+
+namespace android {
+
+MtpStorage::MtpStorage(MtpStorageID id, const char* filePath, MtpDatabase* db)
+ : mStorageID(id),
+ mFilePath(filePath),
+ mDatabase(db),
+ mMaxCapacity(0)
+{
+}
+
+MtpStorage::~MtpStorage() {
+}
+
+int MtpStorage::getType() const {
+ return MTP_STORAGE_FIXED_RAM;
+}
+
+int MtpStorage::getFileSystemType() const {
+ return MTP_STORAGE_FILESYSTEM_HIERARCHICAL;
+}
+
+int MtpStorage::getAccessCapability() const {
+ return MTP_STORAGE_READ_WRITE;
+}
+
+uint64_t MtpStorage::getMaxCapacity() {
+ if (mMaxCapacity == 0) {
+ struct statfs stat;
+ if (statfs(mFilePath, &stat))
+ return -1;
+ mMaxCapacity = (uint64_t)stat.f_blocks * (uint64_t)stat.f_bsize;
+ }
+ return mMaxCapacity;
+}
+
+uint64_t MtpStorage::getFreeSpace() {
+ struct statfs stat;
+ if (statfs(mFilePath, &stat))
+ return -1;
+ return (uint64_t)stat.f_bavail * (uint64_t)stat.f_bsize;
+}
+
+const char* MtpStorage::getDescription() const {
+ return "Phone Storage";
+}
+
+bool MtpStorage::scanFiles() {
+ MtpMediaScanner scanner(mStorageID, mFilePath, mDatabase);
+ return scanner.scanFiles();
+}
+
+} // namespace android
diff --git a/media/mtp/MtpStorage.h b/media/mtp/MtpStorage.h
new file mode 100644
index 0000000..6097272
--- /dev/null
+++ b/media/mtp/MtpStorage.h
@@ -0,0 +1,53 @@
+/*
+ * 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 _MTP_STORAGE_H
+#define _MTP_STORAGE_H
+
+#include "mtp.h"
+
+namespace android {
+
+class MtpDatabase;
+class SqliteStatement;
+
+class MtpStorage {
+
+private:
+ MtpStorageID mStorageID;
+ const char* mFilePath;
+ MtpDatabase* mDatabase;
+ uint64_t mMaxCapacity;
+
+public:
+ MtpStorage(MtpStorageID id, const char* filePath, MtpDatabase* db);
+ virtual ~MtpStorage();
+
+ inline MtpStorageID getStorageID() const { return mStorageID; }
+ int getType() const;
+ int getFileSystemType() const;
+ int getAccessCapability() const;
+ uint64_t getMaxCapacity();
+ uint64_t getFreeSpace();
+ const char* getDescription() const;
+ inline const char* getPath() const { return mFilePath; }
+
+ bool scanFiles();
+};
+
+}; // namespace android
+
+#endif // _MTP_STORAGE_H
diff --git a/media/mtp/MtpStorageInfo.cpp b/media/mtp/MtpStorageInfo.cpp
new file mode 100644
index 0000000..5a5306b
--- /dev/null
+++ b/media/mtp/MtpStorageInfo.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "MtpStorageInfo"
+#include "utils/Log.h"
+
+#include "MtpDataPacket.h"
+#include "MtpStorageInfo.h"
+#include "MtpStringBuffer.h"
+
+namespace android {
+
+MtpStorageInfo::MtpStorageInfo(MtpStorageID id)
+ : mStorageID(id),
+ mStorageType(0),
+ mFileSystemType(0),
+ mAccessCapability(0),
+ mMaxCapacity(0),
+ mFreeSpaceBytes(0),
+ mFreeSpaceObjects(0),
+ mStorageDescription(NULL),
+ mVolumeIdentifier(NULL)
+{
+}
+
+MtpStorageInfo::~MtpStorageInfo() {
+ if (mStorageDescription)
+ free(mStorageDescription);
+ if (mVolumeIdentifier)
+ free(mVolumeIdentifier);
+}
+
+void MtpStorageInfo::read(MtpDataPacket& packet) {
+ MtpStringBuffer string;
+
+ // read the device info
+ mStorageType = packet.getUInt16();
+ mFileSystemType = packet.getUInt16();
+ mAccessCapability = packet.getUInt16();
+ mMaxCapacity = packet.getUInt64();
+ mFreeSpaceBytes = packet.getUInt64();
+ mFreeSpaceObjects = packet.getUInt32();
+
+ packet.getString(string);
+ mStorageDescription = strdup((const char *)string);
+ packet.getString(string);
+ mVolumeIdentifier = strdup((const char *)string);
+}
+
+void MtpStorageInfo::print() {
+ LOGD("Storage Info %08X:\n\tmStorageType: %d\n\tmFileSystemType: %d\n\tmAccessCapability: %d\n",
+ mStorageID, mStorageType, mFileSystemType, mAccessCapability);
+ LOGD("\tmMaxCapacity: %lld\n\tmFreeSpaceBytes: %lld\n\tmFreeSpaceObjects: %d\n",
+ mMaxCapacity, mFreeSpaceBytes, mFreeSpaceObjects);
+ LOGD("\tmStorageDescription: %s\n\tmVolumeIdentifier: %s\n",
+ mStorageDescription, mVolumeIdentifier);
+}
+
+} // namespace android
diff --git a/media/mtp/MtpStorageInfo.h b/media/mtp/MtpStorageInfo.h
new file mode 100644
index 0000000..2cb626e
--- /dev/null
+++ b/media/mtp/MtpStorageInfo.h
@@ -0,0 +1,49 @@
+/*
+ * 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 _MTP_STORAGE_INFO_H
+#define _MTP_STORAGE_INFO_H
+
+#include "MtpTypes.h"
+
+namespace android {
+
+class MtpDataPacket;
+
+class MtpStorageInfo {
+public:
+ MtpStorageID mStorageID;
+ uint16_t mStorageType;
+ uint16_t mFileSystemType;
+ uint16_t mAccessCapability;
+ uint64_t mMaxCapacity;
+ uint64_t mFreeSpaceBytes;
+ uint32_t mFreeSpaceObjects;
+ char* mStorageDescription;
+ char* mVolumeIdentifier;
+
+public:
+ MtpStorageInfo(MtpStorageID id);
+ virtual ~MtpStorageInfo();
+
+ void read(MtpDataPacket& packet);
+
+ void print();
+};
+
+}; // namespace android
+
+#endif // _MTP_STORAGE_INFO_H
diff --git a/media/mtp/MtpStringBuffer.cpp b/media/mtp/MtpStringBuffer.cpp
new file mode 100644
index 0000000..8694575
--- /dev/null
+++ b/media/mtp/MtpStringBuffer.cpp
@@ -0,0 +1,136 @@
+/*
+ * 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 <string.h>
+
+#include "MtpDataPacket.h"
+#include "MtpStringBuffer.h"
+
+namespace android {
+
+MtpStringBuffer::MtpStringBuffer()
+ : mCharCount(0),
+ mByteCount(1)
+{
+ mBuffer[0] = 0;
+}
+
+MtpStringBuffer::MtpStringBuffer(const char* src)
+ : mCharCount(0),
+ mByteCount(1)
+{
+ set(src);
+}
+
+MtpStringBuffer::MtpStringBuffer(const MtpStringBuffer& src)
+ : mCharCount(src.mCharCount),
+ mByteCount(src.mByteCount)
+{
+ memcpy(mBuffer, src.mBuffer, mByteCount);
+}
+
+
+MtpStringBuffer::~MtpStringBuffer() {
+}
+
+void MtpStringBuffer::set(const char* src) {
+ int length = strlen(src);
+ if (length >= sizeof(mBuffer))
+ length = sizeof(mBuffer) - 1;
+ memcpy(mBuffer, src, length);
+
+ // count the characters
+ int count = 0;
+ char ch;
+ while ((ch = *src++) != 0) {
+ if ((ch & 0x80) == 0) {
+ // single byte character
+ } else if ((ch & 0xE0) == 0xC0) {
+ // two byte character
+ if (! *src++) {
+ // last character was truncated, so ignore last byte
+ length--;
+ break;
+ }
+ } else if ((ch & 0xF0) == 0xE0) {
+ // 3 byte char
+ if (! *src++) {
+ // last character was truncated, so ignore last byte
+ length--;
+ break;
+ }
+ if (! *src++) {
+ // last character was truncated, so ignore last two bytes
+ length -= 2;
+ break;
+ }
+ }
+ count++;
+ }
+
+ mByteCount = length + 1;
+ mBuffer[length] = 0;
+ mCharCount = count;
+}
+
+void MtpStringBuffer::readFromPacket(MtpDataPacket* packet) {
+ int count = packet->getUInt8();
+ uint8_t* dest = mBuffer;
+ for (int i = 0; i < count; i++) {
+ uint16_t ch = packet->getUInt16();
+ if (ch >= 0x0800) {
+ *dest++ = (uint8_t)(0xE0 | (ch >> 12));
+ *dest++ = (uint8_t)(0x80 | ((ch >> 6) & 0x3F));
+ *dest++ = (uint8_t)(0x80 | (ch & 0x3F));
+ } else if (ch >= 0x80) {
+ *dest++ = (uint8_t)(0xC0 | (ch >> 6));
+ *dest++ = (uint8_t)(0x80 | (ch & 0x3F));
+ } else {
+ *dest++ = ch;
+ }
+ }
+ *dest++ = 0;
+ mCharCount = count;
+ mByteCount = dest - mBuffer;
+}
+
+void MtpStringBuffer::writeToPacket(MtpDataPacket* packet) const {
+ int count = mCharCount;
+ const uint8_t* src = mBuffer;
+ packet->putUInt8(count);
+
+ // expand utf8 to 16 bit chars
+ for (int i = 0; i < count; i++) {
+ uint16_t ch;
+ uint16_t ch1 = *src++;
+ if ((ch1 & 0x80) == 0) {
+ // single byte character
+ ch = ch1;
+ } else if ((ch1 & 0xE0) == 0xC0) {
+ // two byte character
+ uint16_t ch2 = *src++;
+ ch = ((ch1 & 0x1F) << 6) | (ch2 & 0x3F);
+ } else {
+ // three byte character
+ uint16_t ch2 = *src++;
+ uint16_t ch3 = *src++;
+ ch = ((ch1 & 0x0F) << 12) | ((ch2 & 0x3F) << 6) | (ch3 & 0x3F);
+ }
+ packet->putUInt16(ch);
+ }
+}
+
+} // namespace android
diff --git a/media/mtp/MtpStringBuffer.h b/media/mtp/MtpStringBuffer.h
new file mode 100644
index 0000000..4641c3f
--- /dev/null
+++ b/media/mtp/MtpStringBuffer.h
@@ -0,0 +1,54 @@
+/*
+ * 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 _MTP_STRING_BUFFER_H
+#define _MTP_STRING_BUFFER_H
+
+#include <stdint.h>
+
+namespace android {
+
+class MtpDataPacket;
+
+// Represents a utf8 string, with a maximum of 255 characters
+class MtpStringBuffer {
+
+private:
+ // maximum 3 bytes/character, with 1 extra for zero termination
+ uint8_t mBuffer[255 * 3 + 1];
+ int mCharCount;
+ int mByteCount;
+
+public:
+ MtpStringBuffer();
+ MtpStringBuffer(const char* src);
+ MtpStringBuffer(const MtpStringBuffer& src);
+ virtual ~MtpStringBuffer();
+
+ void set(const char* src);
+
+ void readFromPacket(MtpDataPacket* packet);
+ void writeToPacket(MtpDataPacket* packet) const;
+
+ inline int getCharCount() const { return mCharCount; }
+ inline int getByteCount() const { return mByteCount; }
+
+ inline operator const char*() const { return (const char *)mBuffer; }
+};
+
+}; // namespace android
+
+#endif // _MTP_STRING_BUFFER_H
diff --git a/media/mtp/MtpTypes.h b/media/mtp/MtpTypes.h
new file mode 100644
index 0000000..6a33a2b
--- /dev/null
+++ b/media/mtp/MtpTypes.h
@@ -0,0 +1,100 @@
+/*
+ * 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 _MTP_TYPES_H
+#define _MTP_TYPES_H
+
+#include <stdint.h>
+#include "utils/String8.h"
+#include "utils/Vector.h"
+
+namespace android {
+
+typedef int32_t int128_t[4];
+typedef uint32_t uint128_t[4];
+
+typedef uint16_t MtpOperationCode;
+typedef uint16_t MtpResponseCode;
+typedef uint32_t MtpSessionID;
+typedef uint32_t MtpStorageID;
+typedef uint32_t MtpTransactionID;
+typedef uint16_t MtpPropertyCode;
+typedef uint16_t MtpDataType;
+typedef uint16_t MtpObjectFormat;
+typedef MtpPropertyCode MtpDeviceProperty;
+typedef MtpPropertyCode MtpObjectProperty;
+
+// object handles are unique across all storage but only within a single session.
+// object handles cannot be reused after an object is deleted.
+// values 0x00000000 and 0xFFFFFFFF are reserved for special purposes.
+typedef uint32_t MtpObjectHandle;
+
+typedef union MtpPropertyValue {
+ int8_t i8;
+ uint8_t u8;
+ int16_t i16;
+ uint16_t u16;
+ int32_t i32;
+ uint32_t u32;
+ int64_t i64;
+ uint64_t u64;
+ int128_t i128;
+ uint128_t u128;
+ char* str;
+};
+
+// Special values
+#define MTP_PARENT_ROOT 0xFFFFFFFF // parent is root of the storage
+#define kInvalidObjectHandle 0xFFFFFFFF
+
+// MtpObjectHandle bits and masks
+#define kObjectHandleMarkBit 0x80000000 // used for mark & sweep by MtpMediaScanner
+#define kObjectHandleTableMask 0x70000000 // mask for object table
+#define kObjectHandleTableFile 0x00000000 // object is only in the file table
+#define kObjectHandleTableAudio 0x10000000 // object is in the audio table
+#define kObjectHandleTableVideo 0x20000000 // object is in the video table
+#define kObjectHandleTableImage 0x30000000 // object is in the images table
+#define kObjectHandleTablePlaylist 0x40000000 // object is in the playlist table
+#define kObjectHandleIndexMask 0x0FFFFFFF // mask for object index in file table
+
+class MtpStorage;
+class MtpDevice;
+class MtpProperty;
+
+typedef Vector<MtpStorage *> MtpStorageList;
+typedef Vector<MtpDevice*> MtpDeviceList;
+typedef Vector<MtpProperty*> MtpPropertyList;
+
+typedef Vector<uint8_t> UInt8List;
+typedef Vector<uint16_t> UInt16List;
+typedef Vector<uint32_t> UInt32List;
+typedef Vector<uint64_t> UInt64List;
+typedef Vector<int8_t> Int8List;
+typedef Vector<int16_t> Int16List;
+typedef Vector<int32_t> Int32List;
+typedef Vector<int64_t> Int64List;
+
+typedef UInt16List MtpDevicePropertyList;
+typedef UInt16List MtpObjectFormatList;
+typedef UInt32List MtpObjectHandleList;
+typedef UInt16List MtpObjectPropertyList;
+typedef UInt32List MtpStorageIDList;
+
+typedef String8 MtpString;
+
+}; // namespace android
+
+#endif // _MTP_TYPES_H
diff --git a/media/mtp/MtpUtils.cpp b/media/mtp/MtpUtils.cpp
new file mode 100644
index 0000000..10ca166
--- /dev/null
+++ b/media/mtp/MtpUtils.cpp
@@ -0,0 +1,76 @@
+/*
+ * 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 <stdio.h>
+#include <time.h>
+
+#include <cutils/tztime.h>
+#include "MtpUtils.h"
+
+namespace android {
+
+/*
+DateTime strings follow a compatible subset of the definition found in ISO 8601, and
+take the form of a Unicode string formatted as: "YYYYMMDDThhmmss.s". In this
+representation, YYYY shall be replaced by the year, MM replaced by the month (01-12),
+DD replaced by the day (01-31), T is a constant character 'T' delimiting time from date,
+hh is replaced by the hour (00-23), mm is replaced by the minute (00-59), and ss by the
+second (00-59). The ".s" is optional, and represents tenths of a second.
+*/
+
+bool parseDateTime(const char* dateTime, time_t& outSeconds) {
+ int year, month, day, hour, minute, second;
+ struct tm tm;
+
+ if (sscanf(dateTime, "%04d%02d%02dT%02d%02d%02d",
+ &year, &month, &day, &hour, &minute, &second) != 6)
+ return false;
+ const char* tail = dateTime + 15;
+ // skip optional tenth of second
+ if (tail[0] == '.' && tail[1])
+ tail += 2;
+ //FIXME - support +/-hhmm
+ bool useUTC = (tail[0] == 'Z');
+
+ // hack to compute timezone
+ time_t dummy;
+ localtime_r(&dummy, &tm);
+
+ tm.tm_sec = second;
+ tm.tm_min = minute;
+ tm.tm_hour = hour;
+ tm.tm_mday = day;
+ tm.tm_mon = month;
+ tm.tm_year = year - 1900;
+ tm.tm_wday = 0;
+ tm.tm_isdst = -1;
+ if (useUTC)
+ outSeconds = mktime(&tm);
+ else
+ outSeconds = mktime_tz(&tm, tm.tm_zone);
+
+ return true;
+}
+
+void formatDateTime(time_t seconds, char* buffer, int bufferLength) {
+ struct tm tm;
+
+ localtime_r(&seconds, &tm);
+ snprintf(buffer, bufferLength, "%04d%02d%02dT%02d%02d%02d",
+ tm.tm_year + 1900, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
+}
+
+} // namespace android
diff --git a/graphics/java/android/renderscript/Vector2f.java b/media/mtp/MtpUtils.h
similarity index 63%
copy from graphics/java/android/renderscript/Vector2f.java
copy to media/mtp/MtpUtils.h
index 567d57fa..61f9055 100644
--- a/graphics/java/android/renderscript/Vector2f.java
+++ b/media/mtp/MtpUtils.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,24 +14,16 @@
* limitations under the License.
*/
-package android.renderscript;
+#ifndef _MTP_UTILS_H
+#define _MTP_UTILS_H
-import java.lang.Math;
-import android.util.Log;
+#include <stdint.h>
+namespace android {
-/**
- * @hide
- *
- **/
-public class Vector2f {
- public Vector2f() {
- }
+bool parseDateTime(const char* dateTime, time_t& outSeconds);
+void formatDateTime(time_t seconds, char* buffer, int bufferLength);
- public float x;
- public float y;
-}
+}; // namespace android
-
-
-
+#endif // _MTP_UTILS_H
diff --git a/media/mtp/SqliteDatabase.cpp b/media/mtp/SqliteDatabase.cpp
new file mode 100644
index 0000000..e115630
--- /dev/null
+++ b/media/mtp/SqliteDatabase.cpp
@@ -0,0 +1,85 @@
+/*
+ * 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 "SqliteDatabase.h"
+#include "SqliteStatement.h"
+
+#include <stdio.h>
+#include <sqlite3.h>
+
+namespace android {
+
+SqliteDatabase::SqliteDatabase()
+ : mDatabaseHandle(NULL)
+{
+}
+
+SqliteDatabase::~SqliteDatabase() {
+ close();
+}
+
+bool SqliteDatabase::open(const char* path, bool create) {
+ int flags = SQLITE_OPEN_READWRITE;
+ if (create) flags |= SQLITE_OPEN_CREATE;
+ // SQLITE_OPEN_NOMUTEX?
+ int ret = sqlite3_open_v2(path, &mDatabaseHandle, flags, NULL);
+ if (ret) {
+ fprintf(stderr, "could not open database\n");
+ return false;
+ }
+ return true;
+}
+
+void SqliteDatabase::close() {
+ if (mDatabaseHandle) {
+ sqlite3_close(mDatabaseHandle);
+ mDatabaseHandle = NULL;
+ }
+}
+
+bool SqliteDatabase::exec(const char* sql) {
+ return (sqlite3_exec(mDatabaseHandle, sql, NULL, NULL, NULL) == 0);
+}
+
+int SqliteDatabase::lastInsertedRow() {
+ return sqlite3_last_insert_rowid(mDatabaseHandle);
+}
+
+void SqliteDatabase::beginTransaction() {
+ exec("BEGIN TRANSACTION");
+}
+
+void SqliteDatabase::commitTransaction() {
+ exec("COMMIT TRANSACTION");
+}
+
+void SqliteDatabase::rollbackTransaction() {
+ exec("ROLLBACK TRANSACTION");
+}
+
+int SqliteDatabase::getVersion() {
+ SqliteStatement stmt(this);
+ stmt.prepare("PRAGMA user_version;");
+ stmt.step();
+ return stmt.getColumnInt(0);
+}
+void SqliteDatabase::setVersion(int version) {
+ char buffer[40];
+ snprintf(buffer, sizeof(buffer), "PRAGMA user_version = %d", version);
+ exec(buffer);
+}
+
+} // namespace android
diff --git a/media/mtp/SqliteDatabase.h b/media/mtp/SqliteDatabase.h
new file mode 100644
index 0000000..56dd9dd
--- /dev/null
+++ b/media/mtp/SqliteDatabase.h
@@ -0,0 +1,50 @@
+/*
+ * 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 _SQLITE_DATABASE_H
+#define _SQLITE_DATABASE_H
+
+typedef struct sqlite3 sqlite3;
+
+namespace android {
+
+class SqliteDatabase {
+private:
+ sqlite3* mDatabaseHandle;
+
+public:
+ SqliteDatabase();
+ virtual ~SqliteDatabase();
+
+ virtual bool open(const char* path, bool create);
+ virtual void close();
+
+ bool exec(const char* sql);
+ int lastInsertedRow();
+
+ void beginTransaction();
+ void commitTransaction();
+ void rollbackTransaction();
+
+ int getVersion();
+ void setVersion(int version);
+
+ inline sqlite3* getDatabaseHandle() const { return mDatabaseHandle; }
+};
+
+}; // namespace android
+
+#endif // _SQLITE_DATABASE_H
diff --git a/media/mtp/SqliteStatement.cpp b/media/mtp/SqliteStatement.cpp
new file mode 100644
index 0000000..e1300b6
--- /dev/null
+++ b/media/mtp/SqliteStatement.cpp
@@ -0,0 +1,81 @@
+/*
+ * 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 "SqliteStatement.h"
+#include "SqliteDatabase.h"
+
+#include <stdio.h>
+#include <sqlite3.h>
+
+namespace android {
+
+SqliteStatement::SqliteStatement(SqliteDatabase* db)
+ : mDatabaseHandle(db->getDatabaseHandle()),
+ mStatement(NULL),
+ mDone(false)
+{
+}
+
+SqliteStatement::~SqliteStatement() {
+ finalize();
+}
+
+bool SqliteStatement::prepare(const char* sql) {
+ return (sqlite3_prepare_v2(mDatabaseHandle, sql, -1, &mStatement, NULL) == 0);
+}
+
+bool SqliteStatement::step() {
+ int ret = sqlite3_step(mStatement);
+ if (ret == SQLITE_DONE) {
+ mDone = true;
+ return true;
+ }
+ return (ret == SQLITE_OK || ret == SQLITE_ROW);
+}
+
+void SqliteStatement::reset() {
+ sqlite3_reset(mStatement);
+ mDone = false;
+}
+
+void SqliteStatement::finalize() {
+ if (mStatement) {
+ sqlite3_finalize(mStatement);
+ mStatement = NULL;
+ }
+}
+
+void SqliteStatement::bind(int column, int value) {
+ sqlite3_bind_int(mStatement, column, value);
+}
+
+void SqliteStatement::bind(int column, const char* value) {
+ sqlite3_bind_text(mStatement, column, value, -1, SQLITE_TRANSIENT);
+}
+
+int SqliteStatement::getColumnInt(int column) {
+ return sqlite3_column_int(mStatement, column);
+}
+
+int64_t SqliteStatement::getColumnInt64(int column) {
+ return sqlite3_column_int64(mStatement, column);
+}
+
+const char* SqliteStatement::getColumnString(int column) {
+ return (const char *)sqlite3_column_text(mStatement, column);
+}
+
+} // namespace android
diff --git a/media/mtp/SqliteStatement.h b/media/mtp/SqliteStatement.h
new file mode 100644
index 0000000..c0ebfff
--- /dev/null
+++ b/media/mtp/SqliteStatement.h
@@ -0,0 +1,56 @@
+/*
+ * 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 _SQLITE_STATEMENT_H
+#define _SQLITE_STATEMENT_H
+
+#include <stdint.h>
+
+typedef struct sqlite3 sqlite3;
+typedef struct sqlite3_stmt sqlite3_stmt;
+
+namespace android {
+
+class SqliteDatabase;
+
+class SqliteStatement {
+private:
+ sqlite3* mDatabaseHandle;
+ sqlite3_stmt* mStatement;
+ bool mDone;
+
+public:
+ SqliteStatement(SqliteDatabase* db);
+ virtual ~SqliteStatement();
+
+ bool prepare(const char* sql);
+ bool step();
+ void reset();
+ void finalize();
+
+ void bind(int column, int value);
+ void bind(int column, const char* value);
+
+ int getColumnInt(int column);
+ int64_t getColumnInt64(int column);
+ const char* getColumnString(int column);
+
+ inline bool isDone() const { return mDone; }
+};
+
+}; // namespace android
+
+#endif // _SQLITE_STATEMENT_H
diff --git a/media/mtp/f_mtp.h b/media/mtp/f_mtp.h
new file mode 100644
index 0000000..82015a0
--- /dev/null
+++ b/media/mtp/f_mtp.h
@@ -0,0 +1,46 @@
+/*
+ * Gadget Function Driver for MTP
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Author: Mike Lockwood <lockwood@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __LINUX_USB_F_MTP_H
+#define __LINUX_USB_F_MTP_H
+
+/* Constants for MTP_SET_INTERFACE_MODE */
+#define MTP_INTERFACE_MODE_MTP 0
+#define MTP_INTERFACE_MODE_PTP 1
+
+
+struct mtp_file_range {
+ /* path for file to transfer */
+ const char *path;
+ /* strlen(path) */
+ int path_length;
+ /* offset in file for start of transfer */
+ loff_t offset;
+ /* number of bytes to transfer */
+ size_t length;
+};
+
+/* Sends the specified file range to the host */
+#define MTP_SEND_FILE _IOW('M', 0, struct mtp_file_range)
+/* Receives data from the host and writes it to a file.
+ * The file is created if it does not exist.
+ */
+#define MTP_RECEIVE_FILE _IOW('M', 1, struct mtp_file_range)
+/* Sets the driver mode to either MTP or PTP */
+#define MTP_SET_INTERFACE_MODE _IOW('M', 2, int)
+
+#endif /* __LINUX_USB_F_MTP_H */
diff --git a/media/mtp/mtp.h b/media/mtp/mtp.h
new file mode 100644
index 0000000..224cfb9
--- /dev/null
+++ b/media/mtp/mtp.h
@@ -0,0 +1,475 @@
+/*
+ * 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 _MTP_H
+#define _MTP_H
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#define MTP_STANDARD_VERSION 100
+
+// Container Types
+#define MTP_CONTAINER_TYPE_UNDEFINED 0
+#define MTP_CONTAINER_TYPE_COMMAND 1
+#define MTP_CONTAINER_TYPE_DATA 2
+#define MTP_CONTAINER_TYPE_RESPONSE 3
+#define MTP_CONTAINER_TYPE_EVENT 4
+
+// Container Offsets
+#define MTP_CONTAINER_LENGTH_OFFSET 0
+#define MTP_CONTAINER_TYPE_OFFSET 4
+#define MTP_CONTAINER_CODE_OFFSET 6
+#define MTP_CONTAINER_TRANSACTION_ID_OFFSET 8
+#define MTP_CONTAINER_PARAMETER_OFFSET 12
+#define MTP_CONTAINER_HEADER_SIZE 12
+
+// MTP Types
+#define MTP_TYPE_UNDEFINED 0x0000 // Undefined
+#define MTP_TYPE_INT8 0x0001 // Signed 8-bit integer
+#define MTP_TYPE_UINT8 0x0002 // Unsigned 8-bit integer
+#define MTP_TYPE_INT16 0x0003 // Signed 16-bit integer
+#define MTP_TYPE_UINT16 0x0004 // Unsigned 16-bit integer
+#define MTP_TYPE_INT32 0x0005 // Signed 32-bit integer
+#define MTP_TYPE_UINT32 0x0006 // Unsigned 32-bit integer
+#define MTP_TYPE_INT64 0x0007 // Signed 64-bit integer
+#define MTP_TYPE_UINT64 0x0008 // Unsigned 64-bit integer
+#define MTP_TYPE_INT128 0x0009 // Signed 128-bit integer
+#define MTP_TYPE_UINT128 0x000A // Unsigned 128-bit integer
+#define MTP_TYPE_AINT8 0x4001 // Array of signed 8-bit integers
+#define MTP_TYPE_AUINT8 0x4002 // Array of unsigned 8-bit integers
+#define MTP_TYPE_AINT16 0x4003 // Array of signed 16-bit integers
+#define MTP_TYPE_AUINT16 0x4004 // Array of unsigned 16-bit integers
+#define MTP_TYPE_AINT32 0x4005 // Array of signed 32-bit integers
+#define MTP_TYPE_AUINT32 0x4006 // Array of unsigned 32-bit integers
+#define MTP_TYPE_AINT64 0x4007 // Array of signed 64-bit integers
+#define MTP_TYPE_AUINT64 0x4008 // Array of unsigned 64-bit integers
+#define MTP_TYPE_AINT128 0x4009 // Array of signed 128-bit integers
+#define MTP_TYPE_AUINT128 0x400A // Array of unsigned 128-bit integers
+#define MTP_TYPE_STR 0xFFFF // Variable-length Unicode string
+
+// MTP Format Codes
+#define MTP_FORMAT_UNDEFINED 0x3000 // Undefined object
+#define MTP_FORMAT_ASSOCIATION 0x3001 // Association (for example, a folder)
+#define MTP_FORMAT_SCRIPT 0x3002 // Device model-specific script
+#define MTP_FORMAT_EXECUTABLE 0x3003 // Device model-specific binary executable
+#define MTP_FORMAT_TEXT 0x3004 // Text file
+#define MTP_FORMAT_HTML 0x3005 // Hypertext Markup Language file (text)
+#define MTP_FORMAT_DPOF 0x3006 // Digital Print Order Format file (text)
+#define MTP_FORMAT_AIFF 0x3007 // Audio clip
+#define MTP_FORMAT_WAV 0x3008 // Audio clip
+#define MTP_FORMAT_MP3 0x3009 // Audio clip
+#define MTP_FORMAT_AVI 0x300A // Video clip
+#define MTP_FORMAT_MPEG 0x300B // Video clip
+#define MTP_FORMAT_ASF 0x300C // Microsoft Advanced Streaming Format (video)
+#define MTP_FORMAT_DEFINED 0x3800 // Unknown image object
+#define MTP_FORMAT_EXIF_JPEG 0x3801 // Exchangeable File Format, JEIDA standard
+#define MTP_FORMAT_TIFF_EP 0x3802 // Tag Image File Format for Electronic Photography
+#define MTP_FORMAT_FLASHPIX 0x3803 // Structured Storage Image Format
+#define MTP_FORMAT_BMP 0x3804 // Microsoft Windows Bitmap file
+#define MTP_FORMAT_CIFF 0x3805 // Canon Camera Image File Format
+#define MTP_FORMAT_GIF 0x3807 // Graphics Interchange Format
+#define MTP_FORMAT_JFIF 0x3808 // JPEG File Interchange Format
+#define MTP_FORMAT_CD 0x3809 // PhotoCD Image Pac
+#define MTP_FORMAT_PICT 0x380A // Quickdraw Image Format
+#define MTP_FORMAT_PNG 0x380B // Portable Network Graphics
+#define MTP_FORMAT_TIFF 0x380D // Tag Image File Format
+#define MTP_FORMAT_TIFF_IT 0x380E // Tag Image File Format for Information Technology (graphic arts)
+#define MTP_FORMAT_JP2 0x380F // JPEG2000 Baseline File Format
+#define MTP_FORMAT_JPX 0x3810 // JPEG2000 Extended File Format
+#define MTP_FORMAT_UNDEFINED_FIRMWARE 0xB802
+#define MTP_FORMAT_WINDOWS_IMAGE_FORMAT 0xB881
+#define MTP_FORMAT_UNDEFINED_AUDIO 0xB900
+#define MTP_FORMAT_WMA 0xB901
+#define MTP_FORMAT_OGG 0xB902
+#define MTP_FORMAT_AAC 0xB903
+#define MTP_FORMAT_AUDIBLE 0xB904
+#define MTP_FORMAT_FLAC 0xB906
+#define MTP_FORMAT_UNDEFINED_VIDEO 0xB980
+#define MTP_FORMAT_WMV 0xB981
+#define MTP_FORMAT_MP4_CONTAINER 0xB982 // ISO 14496-1
+#define MTP_FORMAT_MP2 0xB983
+#define MTP_FORMAT_3GP_CONTAINER 0xB984 // 3GPP file format. Details: http://www.3gpp.org/ftp/Specs/html-info/26244.htm (page title - \u201cTransparent end-to-end packet switched streaming service, 3GPP file format\u201d).
+#define MTP_FORMAT_UNDEFINED_COLLECTION 0xBA00
+#define MTP_FORMAT_ABSTRACT_MULTIMEDIA_ALBUM 0xBA01
+#define MTP_FORMAT_ABSTRACT_IMAGE_ALBUM 0xBA02
+#define MTP_FORMAT_ABSTRACT_AUDIO_ALBUM 0xBA03
+#define MTP_FORMAT_ABSTRACT_VIDEO_ALBUM 0xBA04
+#define MTP_FORMAT_ABSTRACT_AV_PLAYLIST 0xBA05
+#define MTP_FORMAT_ABSTRACT_CONTACT_GROUP 0xBA06
+#define MTP_FORMAT_ABSTRACT_MESSAGE_FOLDER 0xBA07
+#define MTP_FORMAT_ABSTRACT_CHAPTERED_PRODUCTION 0xBA08
+#define MTP_FORMAT_ABSTRACT_AUDIO_PLAYLIST 0xBA09
+#define MTP_FORMAT_ABSTRACT_VIDEO_PLAYLIST 0xBA0A
+#define MTP_FORMAT_ABSTRACT_MEDIACAST 0xBA0B // For use with mediacasts; references multimedia enclosures of RSS feeds or episodic content
+#define MTP_FORMAT_WPL_PLAYLIST 0xBA10
+#define MTP_FORMAT_M3U_PLAYLIST 0xBA11
+#define MTP_FORMAT_MPL_PLAYLIST 0xBA12
+#define MTP_FORMAT_ASX_PLAYLIST 0xBA13
+#define MTP_FORMAT_PLS_PLAYLIST 0xBA14
+#define MTP_FORMAT_UNDEFINED_DOCUMENT 0xBA80
+#define MTP_FORMAT_ABSTRACT_DOCUMENT 0xBA81
+#define MTP_FORMAT_XML_DOCUMENT 0xBA82
+#define MTP_FORMAT_MS_WORD_DOCUMENT 0xBA83
+#define MTP_FORMAT_MHT_COMPILED_HTML_DOCUMENT 0xBA84
+#define MTP_FORMAT_MS_EXCEL_SPREADSHEET 0xBA85
+#define MTP_FORMAT_MS_POWERPOINT_PRESENTATION 0xBA86
+#define MTP_FORMAT_UNDEFINED_MESSAGE 0xBB00
+#define MTP_FORMAT_ABSTRACT_MESSSAGE 0xBB01
+#define MTP_FORMAT_UNDEFINED_CONTACT 0xBB80
+#define MTP_FORMAT_ABSTRACT_CONTACT 0xBB81
+#define MTP_FORMAT_VCARD_2 0xBB82
+
+// MTP Object Property Codes
+#define MTP_PROPERTY_STORAGE_ID 0xDC01
+#define MTP_PROPERTY_OBJECT_FORMAT 0xDC02
+#define MTP_PROPERTY_PROTECTION_STATUS 0xDC03
+#define MTP_PROPERTY_OBJECT_SIZE 0xDC04
+#define MTP_PROPERTY_ASSOCIATION_TYPE 0xDC05
+#define MTP_PROPERTY_ASSOCIATION_DESC 0xDC06
+#define MTP_PROPERTY_OBJECT_FILE_NAME 0xDC07
+#define MTP_PROPERTY_DATE_CREATED 0xDC08
+#define MTP_PROPERTY_DATE_MODIFIED 0xDC09
+#define MTP_PROPERTY_KEYWORDS 0xDC0A
+#define MTP_PROPERTY_PARENT_OBJECT 0xDC0B
+#define MTP_PROPERTY_ALLOWED_FOLDER_CONTENTS 0xDC0C
+#define MTP_PROPERTY_HIDDEN 0xDC0D
+#define MTP_PROPERTY_SYSTEM_OBJECT 0xDC0E
+#define MTP_PROPERTY_PERSISTENT_UID 0xDC41
+#define MTP_PROPERTY_SYNC_ID 0xDC42
+#define MTP_PROPERTY_PROPERTY_BAG 0xDC43
+#define MTP_PROPERTY_NAME 0xDC44
+#define MTP_PROPERTY_CREATED_BY 0xDC45
+#define MTP_PROPERTY_ARTIST 0xDC46
+#define MTP_PROPERTY_DATE_AUTHORED 0xDC47
+#define MTP_PROPERTY_DESCRIPTION 0xDC48
+#define MTP_PROPERTY_URL_REFERENCE 0xDC49
+#define MTP_PROPERTY_LANGUAGE_LOCALE 0xDC4A
+#define MTP_PROPERTY_COPYRIGHT_INFORMATION 0xDC4B
+#define MTP_PROPERTY_SOURCE 0xDC4C
+#define MTP_PROPERTY_ORIGIN_LOCATION 0xDC4D
+#define MTP_PROPERTY_DATE_ADDED 0xDC4E
+#define MTP_PROPERTY_NON_CONSUMABLE 0xDC4F
+#define MTP_PROPERTY_CORRUPT_UNPLAYABLE 0xDC50
+#define MTP_PROPERTY_PRODUCER_SERIAL_NUMBER 0xDC51
+#define MTP_PROPERTY_REPRESENTATIVE_SAMPLE_FORMAT 0xDC81
+#define MTP_PROPERTY_REPRESENTATIVE_SAMPLE_SIZE 0xDC82
+#define MTP_PROPERTY_REPRESENTATIVE_SAMPLE_HEIGHT 0xDC83
+#define MTP_PROPERTY_REPRESENTATIVE_SAMPLE_WIDTH 0xDC84
+#define MTP_PROPERTY_REPRESENTATIVE_SAMPLE_DURATION 0xDC85
+#define MTP_PROPERTY_REPRESENTATIVE_SAMPLE_DATA 0xDC86
+#define MTP_PROPERTY_WIDTH 0xDC87
+#define MTP_PROPERTY_HEIGHT 0xDC88
+#define MTP_PROPERTY_DURATION 0xDC89
+#define MTP_PROPERTY_RATING 0xDC8A
+#define MTP_PROPERTY_TRACK 0xDC8B
+#define MTP_PROPERTY_GENRE 0xDC8C
+#define MTP_PROPERTY_CREDITS 0xDC8D
+#define MTP_PROPERTY_LYRICS 0xDC8E
+#define MTP_PROPERTY_SUBSCRIPTION_CONTENT_ID 0xDC8F
+#define MTP_PROPERTY_PRODUCED_BY 0xDC90
+#define MTP_PROPERTY_USE_COUNT 0xDC91
+#define MTP_PROPERTY_SKIP_COUNT 0xDC92
+#define MTP_PROPERTY_LAST_ACCESSED 0xDC93
+#define MTP_PROPERTY_PARENTAL_RATING 0xDC94
+#define MTP_PROPERTY_META_GENRE 0xDC95
+#define MTP_PROPERTY_COMPOSER 0xDC96
+#define MTP_PROPERTY_EFFECTIVE_RATING 0xDC97
+#define MTP_PROPERTY_SUBTITLE 0xDC98
+#define MTP_PROPERTY_ORIGINAL_RELEASE_DATE 0xDC99
+#define MTP_PROPERTY_ALBUM_NAME 0xDC9A
+#define MTP_PROPERTY_ALBUM_ARTIST 0xDC9B
+#define MTP_PROPERTY_MOOD 0xDC9C
+#define MTP_PROPERTY_DRM_STATUS 0xDC9D
+#define MTP_PROPERTY_SUB_DESCRIPTION 0xDC9E
+#define MTP_PROPERTY_IS_CROPPED 0xDCD1
+#define MTP_PROPERTY_IS_COLOUR_CORRECTED 0xDCD2
+#define MTP_PROPERTY_IMAGE_BIT_DEPTH 0xDCD3
+#define MTP_PROPERTY_F_NUMBER 0xDCD4
+#define MTP_PROPERTY_EXPOSURE_TIME 0xDCD5
+#define MTP_PROPERTY_EXPOSURE_INDEX 0xDCD6
+#define MTP_PROPERTY_TOTAL_BITRATE 0xDE91
+#define MTP_PROPERTY_BITRATE_TYPE 0xDE92
+#define MTP_PROPERTY_SAMPLE_RATE 0xDE93
+#define MTP_PROPERTY_NUMBER_OF_CHANNELS 0xDE94
+#define MTP_PROPERTY_AUDIO_BIT_DEPTH 0xDE95
+#define MTP_PROPERTY_SCAN_TYPE 0xDE97
+#define MTP_PROPERTY_AUDIO_WAVE_CODEC 0xDE99
+#define MTP_PROPERTY_AUDIO_BITRATE 0xDE9A
+#define MTP_PROPERTY_VIDEO_FOURCC_CODEC 0xDE9B
+#define MTP_PROPERTY_VIDEO_BITRATE 0xDE9C
+#define MTP_PROPERTY_FRAMES_PER_THOUSAND_SECONDS 0xDE9D
+#define MTP_PROPERTY_KEYFRAME_DISTANCE 0xDE9E
+#define MTP_PROPERTY_BUFFER_SIZE 0xDE9F
+#define MTP_PROPERTY_ENCODING_QUALITY 0xDEA0
+#define MTP_PROPERTY_ENCODING_PROFILE 0xDEA1
+#define MTP_PROPERTY_DISPLAY_NAME 0xDCE0
+#define MTP_PROPERTY_BODY_TEXT 0xDCE1
+#define MTP_PROPERTY_SUBJECT 0xDCE2
+#define MTP_PROPERTY_PRIORITY 0xDCE3
+#define MTP_PROPERTY_GIVEN_NAME 0xDD00
+#define MTP_PROPERTY_MIDDLE_NAMES 0xDD01
+#define MTP_PROPERTY_FAMILY_NAME 0xDD02
+#define MTP_PROPERTY_PREFIX 0xDD03
+#define MTP_PROPERTY_SUFFIX 0xDD04
+#define MTP_PROPERTY_PHONETIC_GIVEN_NAME 0xDD05
+#define MTP_PROPERTY_PHONETIC_FAMILY_NAME 0xDD06
+#define MTP_PROPERTY_EMAIL_PRIMARY 0xDD07
+#define MTP_PROPERTY_EMAIL_PERSONAL_1 0xDD08
+#define MTP_PROPERTY_EMAIL_PERSONAL_2 0xDD09
+#define MTP_PROPERTY_EMAIL_BUSINESS_1 0xDD0A
+#define MTP_PROPERTY_EMAIL_BUSINESS_2 0xDD0B
+#define MTP_PROPERTY_EMAIL_OTHERS 0xDD0C
+#define MTP_PROPERTY_PHONE_NUMBER_PRIMARY 0xDD0D
+#define MTP_PROPERTY_PHONE_NUMBER_PERSONAL 0xDD0E
+#define MTP_PROPERTY_PHONE_NUMBER_PERSONAL_2 0xDD0F
+#define MTP_PROPERTY_PHONE_NUMBER_BUSINESS 0xDD10
+#define MTP_PROPERTY_PHONE_NUMBER_BUSINESS_2 0xDD11
+#define MTP_PROPERTY_PHONE_NUMBER_MOBILE 0xDD12
+#define MTP_PROPERTY_PHONE_NUMBER_MOBILE_2 0xDD13
+#define MTP_PROPERTY_FAX_NUMBER_PRIMARY 0xDD14
+#define MTP_PROPERTY_FAX_NUMBER_PERSONAL 0xDD15
+#define MTP_PROPERTY_FAX_NUMBER_BUSINESS 0xDD16
+#define MTP_PROPERTY_PAGER_NUMBER 0xDD17
+#define MTP_PROPERTY_PHONE_NUMBER_OTHERS 0xDD18
+#define MTP_PROPERTY_PRIMARY_WEB_ADDRESS 0xDD19
+#define MTP_PROPERTY_PERSONAL_WEB_ADDRESS 0xDD1A
+#define MTP_PROPERTY_BUSINESS_WEB_ADDRESS 0xDD1B
+#define MTP_PROPERTY_INSTANT_MESSANGER_ADDRESS 0xDD1C
+#define MTP_PROPERTY_INSTANT_MESSANGER_ADDRESS_2 0xDD1D
+#define MTP_PROPERTY_INSTANT_MESSANGER_ADDRESS_3 0xDD1E
+#define MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_FULL 0xDD1F
+#define MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_LINE_1 0xDD20
+#define MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_LINE_2 0xDD21
+#define MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_CITY 0xDD22
+#define MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_REGION 0xDD23
+#define MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_POSTAL_CODE 0xDD24
+#define MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_COUNTRY 0xDD25
+#define MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_FULL 0xDD26
+#define MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_LINE_1 0xDD27
+#define MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_LINE_2 0xDD28
+#define MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_CITY 0xDD29
+#define MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_REGION 0xDD2A
+#define MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_POSTAL_CODE 0xDD2B
+#define MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_COUNTRY 0xDD2C
+#define MTP_PROPERTY_POSTAL_ADDRESS_OTHER_FULL 0xDD2D
+#define MTP_PROPERTY_POSTAL_ADDRESS_OTHER_LINE_1 0xDD2E
+#define MTP_PROPERTY_POSTAL_ADDRESS_OTHER_LINE_2 0xDD2F
+#define MTP_PROPERTY_POSTAL_ADDRESS_OTHER_CITY 0xDD30
+#define MTP_PROPERTY_POSTAL_ADDRESS_OTHER_REGION 0xDD31
+#define MTP_PROPERTY_POSTAL_ADDRESS_OTHER_POSTAL_CODE 0xDD32
+#define MTP_PROPERTY_POSTAL_ADDRESS_OTHER_COUNTRY 0xDD33
+#define MTP_PROPERTY_ORGANIZATION_NAME 0xDD34
+#define MTP_PROPERTY_PHONETIC_ORGANIZATION_NAME 0xDD35
+#define MTP_PROPERTY_ROLE 0xDD36
+#define MTP_PROPERTY_BIRTHDATE 0xDD37
+#define MTP_PROPERTY_MESSAGE_TO 0xDD40
+#define MTP_PROPERTY_MESSAGE_CC 0xDD41
+#define MTP_PROPERTY_MESSAGE_BCC 0xDD42
+#define MTP_PROPERTY_MESSAGE_READ 0xDD43
+#define MTP_PROPERTY_MESSAGE_RECEIVED_TIME 0xDD44
+#define MTP_PROPERTY_MESSAGE_SENDER 0xDD45
+#define MTP_PROPERTY_ACTIVITY_BEGIN_TIME 0xDD50
+#define MTP_PROPERTY_ACTIVITY_END_TIME 0xDD51
+#define MTP_PROPERTY_ACTIVITY_LOCATION 0xDD52
+#define MTP_PROPERTY_ACTIVITY_REQUIRED_ATTENDEES 0xDD54
+#define MTP_PROPERTY_ACTIVITY_OPTIONAL_ATTENDEES 0xDD55
+#define MTP_PROPERTY_ACTIVITY_RESOURCES 0xDD56
+#define MTP_PROPERTY_ACTIVITY_ACCEPTED 0xDD57
+#define MTP_PROPERTY_ACTIVITY_TENTATIVE 0xDD58
+#define MTP_PROPERTY_ACTIVITY_DECLINED 0xDD59
+#define MTP_PROPERTY_ACTIVITY_REMAINDER_TIME 0xDD5A
+#define MTP_PROPERTY_ACTIVITY_OWNER 0xDD5B
+#define MTP_PROPERTY_ACTIVITY_STATUS 0xDD5C
+#define MTP_PROPERTY_OWNER 0xDD5D
+#define MTP_PROPERTY_EDITOR 0xDD5E
+#define MTP_PROPERTY_WEBMASTER 0xDD5F
+#define MTP_PROPERTY_URL_SOURCE 0xDD60
+#define MTP_PROPERTY_URL_DESTINATION 0xDD61
+#define MTP_PROPERTY_TIME_BOOKMARK 0xDD62
+#define MTP_PROPERTY_OBJECT_BOOKMARK 0xDD63
+#define MTP_PROPERTY_BYTE_BOOKMARK 0xDD64
+#define MTP_PROPERTY_LAST_BUILD_DATE 0xDD70
+#define MTP_PROPERTY_TIME_TO_LIVE 0xDD71
+#define MTP_PROPERTY_MEDIA_GUID 0xDD72
+
+// MTP Device Property Codes
+#define MTP_DEVICE_PROPERTY_UNDEFINED 0x5000
+#define MTP_DEVICE_PROPERTY_BATTERY_LEVEL 0x5001
+#define MTP_DEVICE_PROPERTY_FUNCTIONAL_MODE 0x5002
+#define MTP_DEVICE_PROPERTY_IMAGE_SIZE 0x5003
+#define MTP_DEVICE_PROPERTY_COMPRESSION_SETTING 0x5004
+#define MTP_DEVICE_PROPERTY_WHITE_BALANCE 0x5005
+#define MTP_DEVICE_PROPERTY_RGB_GAIN 0x5006
+#define MTP_DEVICE_PROPERTY_F_NUMBER 0x5007
+#define MTP_DEVICE_PROPERTY_FOCAL_LENGTH 0x5008
+#define MTP_DEVICE_PROPERTY_FOCUS_DISTANCE 0x5009
+#define MTP_DEVICE_PROPERTY_FOCUS_MODE 0x500A
+#define MTP_DEVICE_PROPERTY_EXPOSURE_METERING_MODE 0x500B
+#define MTP_DEVICE_PROPERTY_FLASH_MODE 0x500C
+#define MTP_DEVICE_PROPERTY_EXPOSURE_TIME 0x500D
+#define MTP_DEVICE_PROPERTY_EXPOSURE_PROGRAM_MODE 0x500E
+#define MTP_DEVICE_PROPERTY_EXPOSURE_INDEX 0x500F
+#define MTP_DEVICE_PROPERTY_EXPOSURE_BIAS_COMPENSATION 0x5010
+#define MTP_DEVICE_PROPERTY_DATETIME 0x5011
+#define MTP_DEVICE_PROPERTY_CAPTURE_DELAY 0x5012
+#define MTP_DEVICE_PROPERTY_STILL_CAPTURE_MODE 0x5013
+#define MTP_DEVICE_PROPERTY_CONTRAST 0x5014
+#define MTP_DEVICE_PROPERTY_SHARPNESS 0x5015
+#define MTP_DEVICE_PROPERTY_DIGITAL_ZOOM 0x5016
+#define MTP_DEVICE_PROPERTY_EFFECT_MODE 0x5017
+#define MTP_DEVICE_PROPERTY_BURST_NUMBER 0x5018
+#define MTP_DEVICE_PROPERTY_BURST_INTERVAL 0x5019
+#define MTP_DEVICE_PROPERTY_TIMELAPSE_NUMBER 0x501A
+#define MTP_DEVICE_PROPERTY_TIMELAPSE_INTERVAL 0x501B
+#define MTP_DEVICE_PROPERTY_FOCUS_METERING_MODE 0x501C
+#define MTP_DEVICE_PROPERTY_UPLOAD_URL 0x501D
+#define MTP_DEVICE_PROPERTY_ARTIST 0x501E
+#define MTP_DEVICE_PROPERTY_COPYRIGHT_INFO 0x501F
+#define MTP_DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER 0xD401
+#define MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME 0xD402
+#define MTP_DEVICE_PROPERTY_VOLUME 0xD403
+#define MTP_DEVICE_PROPERTY_SUPPORTED_FORMATS_ORDERED 0xD404
+#define MTP_DEVICE_PROPERTY_DEVICE_ICON 0xD405
+#define MTP_DEVICE_PROPERTY_PLAYBACK_RATE 0xD410
+#define MTP_DEVICE_PROPERTY_PLAYBACK_OBJECT 0xD411
+#define MTP_DEVICE_PROPERTY_PLAYBACK_CONTAINER_INDEX 0xD412
+#define MTP_DEVICE_PROPERTY_SESSION_INITIATOR_VERSION_INFO 0xD406
+#define MTP_DEVICE_PROPERTY_PERCEIVED_DEVICE_TYPE 0xD407
+
+// MTP Operation Codes
+#define MTP_OPERATION_GET_DEVICE_INFO 0x1001
+#define MTP_OPERATION_OPEN_SESSION 0x1002
+#define MTP_OPERATION_CLOSE_SESSION 0x1003
+#define MTP_OPERATION_GET_STORAGE_IDS 0x1004
+#define MTP_OPERATION_GET_STORAGE_INFO 0x1005
+#define MTP_OPERATION_GET_NUM_OBJECTS 0x1006
+#define MTP_OPERATION_GET_OBJECT_HANDLES 0x1007
+#define MTP_OPERATION_GET_OBJECT_INFO 0x1008
+#define MTP_OPERATION_GET_OBJECT 0x1009
+#define MTP_OPERATION_GET_THUMB 0x100A
+#define MTP_OPERATION_DELETE_OBJECT 0x100B
+#define MTP_OPERATION_SEND_OBJECT_INFO 0x100C
+#define MTP_OPERATION_SEND_OBJECT 0x100D
+#define MTP_OPERATION_INITIATE_CAPTURE 0x100E
+#define MTP_OPERATION_FORMAT_STORE 0x100F
+#define MTP_OPERATION_RESET_DEVICE 0x1010
+#define MTP_OPERATION_SELF_TEST 0x1011
+#define MTP_OPERATION_SET_OBJECT_PROTECTION 0x1012
+#define MTP_OPERATION_POWER_DOWN 0x1013
+#define MTP_OPERATION_GET_DEVICE_PROP_DESC 0x1014
+#define MTP_OPERATION_GET_DEVICE_PROP_VALUE 0x1015
+#define MTP_OPERATION_SET_DEVICE_PROP_VALUE 0x1016
+#define MTP_OPERATION_RESET_DEVICE_PROP_VALUE 0x1017
+#define MTP_OPERATION_TERMINATE_OPEN_CAPTURE 0x1018
+#define MTP_OPERATION_MOVE_OBJECT 0x1019
+#define MTP_OPERATION_COPY_OBJECT 0x101A
+#define MTP_OPERATION_GET_PARTIAL_OBJECT 0x101B
+#define MTP_OPERATION_INITIATE_OPEN_CAPTURE 0x101C
+#define MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED 0x9801
+#define MTP_OPERATION_GET_OBJECT_PROP_DESC 0x9802
+#define MTP_OPERATION_GET_OBJECT_PROP_VALUE 0x9803
+#define MTP_OPERATION_SET_OBJECT_PROP_VALUE 0x9804
+#define MTP_OPERATION_GET_OBJECT_REFERENCES 0x9810
+#define MTP_OPERATION_SET_OBJECT_REFERENCES 0x9811
+#define MTP_OPERATION_SKIP 0x9820
+
+// MTP Response Codes
+#define MTP_RESPONSE_UNDEFINED 0x2000
+#define MTP_RESPONSE_OK 0x2001
+#define MTP_RESPONSE_GENERAL_ERROR 0x2002
+#define MTP_RESPONSE_SESSION_NOT_OPEN 0x2003
+#define MTP_RESPONSE_INVALID_TRANSACTION_ID 0x2004
+#define MTP_RESPONSE_OPERATION_NOT_SUPPORTED 0x2005
+#define MTP_RESPONSE_PARAMETER_NOT_SUPPORTED 0x2006
+#define MTP_RESPONSE_INCOMPLETE_TRANSFER 0x2007
+#define MTP_RESPONSE_INVALID_STORAGE_ID 0x2008
+#define MTP_RESPONSE_INVALID_OBJECT_HANDLE 0x2009
+#define MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED 0x200A
+#define MTP_RESPONSE_INVALID_OBJECT_FORMAT_CODE 0x200B
+#define MTP_RESPONSE_STORAGE_FULL 0x200C
+#define MTP_RESPONSE_OBJECT_WRITE_PROTECTED 0x200D
+#define MTP_RESPONSE_STORE_READ_ONLY 0x200E
+#define MTP_RESPONSE_ACCESS_DENIED 0x200F
+#define MTP_RESPONSE_NO_THUMBNAIL_PRESENT 0x2010
+#define MTP_RESPONSE_SELF_TEST_FAILED 0x2011
+#define MTP_RESPONSE_PARTIAL_DELETION 0x2012
+#define MTP_RESPONSE_STORE_NOT_AVAILABLE 0x2013
+#define MTP_RESPONSE_SPECIFICATION_BY_FORMAT_UNSUPPORTED 0x2014
+#define MTP_RESPONSE_NO_VALID_OBJECT_INFO 0x2015
+#define MTP_RESPONSE_INVALID_CODE_FORMAT 0x2016
+#define MTP_RESPONSE_UNKNOWN_VENDOR_CODE 0x2017
+#define MTP_RESPONSE_CAPTURE_ALREADY_TERMINATED 0x2018
+#define MTP_RESPONSE_DEVICE_BUSY 0x2019
+#define MTP_RESPONSE_INVALID_PARENT_OBJECT 0x201A
+#define MTP_RESPONSE_INVALID_DEVICE_PROP_FORMAT 0x201B
+#define MTP_RESPONSE_INVALID_DEVICE_PROP_VALUE 0x201C
+#define MTP_RESPONSE_INVALID_PARAMETER 0x201D
+#define MTP_RESPONSE_SESSION_ALREADY_OPEN 0x201E
+#define MTP_RESPONSE_TRANSACTION_CANCELLED 0x201F
+#define MTP_RESPONSE_SPECIFICATION_OF_DESTINATION_UNSUPPORTED 0x2020
+#define MTP_RESPONSE_INVALID_OBJECT_PROP_CODE 0xA801
+#define MTP_RESPONSE_INVALID_OBJECT_PROP_FORMAT 0xA802
+#define MTP_RESPONSE_INVALID_OBJECT_PROP_VALUE 0xA803
+#define MTP_RESPONSE_INVALID_OBJECT_REFERENCE 0xA804
+#define MTP_RESPONSE_GROUP_NOT_SUPPORTED 0xA805
+#define MTP_RESPONSE_INVALID_DATASET 0xA806
+#define MTP_RESPONSE_SPECIFICATION_BY_GROUP_UNSUPPORTED 0xA807
+#define MTP_RESPONSE_SPECIFICATION_BY_DEPTH_UNSUPPORTED 0xA808
+#define MTP_RESPONSE_OBJECT_TOO_LARGE 0xA809
+#define MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED 0xA80A
+
+// MTP Event Codes
+#define MTP_EVENT_UNDEFINED 0x4000
+#define MTP_EVENT_CANCEL_TRANSACTION 0x4001
+#define MTP_EVENT_OBJECT_ADDED 0x4002
+#define MTP_EVENT_OBJECT_REMOVED 0x4003
+#define MTP_EVENT_STORE_ADDED 0x4004
+#define MTP_EVENT_STORE_REMOVED 0x4005
+#define MTP_EVENT_DEVICE_PROP_CHANGED 0x4006
+#define MTP_EVENT_OBJECT_INFO_CHANGED 0x4007
+#define MTP_EVENT_DEVICE_INFO_CHANGED 0x4008
+#define MTP_EVENT_REQUEST_OBJECT_TRANSFER 0x4009
+#define MTP_EVENT_STORE_FULL 0x400A
+#define MTP_EVENT_DEVICE_RESET 0x400B
+#define MTP_EVENT_STORAGE_INFO_CHANGED 0x400C
+#define MTP_EVENT_CAPTURE_COMPLETE 0x400D
+#define MTP_EVENT_UNREPORTED_STATUS 0x400E
+#define MTP_EVENT_OBJECT_PROP_CHANGED 0xC801
+#define MTP_EVENT_OBJECT_PROP_DESC_CHANGED 0xC802
+#define MTP_EVENT_OBJECT_REFERENCES_CHANGED 0xC803
+
+// Storage Type
+#define MTP_STORAGE_FIXED_ROM 0x0001
+#define MTP_STORAGE_REMOVABLE_ROM 0x0002
+#define MTP_STORAGE_FIXED_RAM 0x0003
+#define MTP_STORAGE_REMOVABLE_RAM 0x0004
+
+// Storage File System
+#define MTP_STORAGE_FILESYSTEM_FLAT 0x0001
+#define MTP_STORAGE_FILESYSTEM_HIERARCHICAL 0x0002
+#define MTP_STORAGE_FILESYSTEM_DCF 0x0003
+
+// Storage Access Capability
+#define MTP_STORAGE_READ_WRITE 0x0000
+#define MTP_STORAGE_READ_ONLY_WITHOUT_DELETE 0x0000
+#define MTP_STORAGE_READ_ONLY_WITH_DELETE 0x0000
+
+// Association Type
+#define MTP_ASSOCIATION_TYPE_UNDEFINED 0x0000
+#define MTP_ASSOCIATION_TYPE_GENERIC_FOLDER 0x0001
+
+#endif // _MTP_H
diff --git a/media/mtp/mtptest.cpp b/media/mtp/mtptest.cpp
new file mode 100644
index 0000000..0d9d45a
--- /dev/null
+++ b/media/mtp/mtptest.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "mtp_usb"
+#include "cutils/log.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+#include "MtpServer.h"
+#include "MtpStorage.h"
+#include "f_mtp.h"
+
+using namespace android;
+
+static void enable_usb_function(const char* name, bool enable) {
+ char path[PATH_MAX];
+
+ snprintf(path, sizeof(path), "/sys/class/usb_composite/%s/enable", name);
+ int fd = open(path, O_RDWR);
+ if (fd < 0) {
+ fprintf(stderr, "could not open %s in enable_usb_function\n", path);
+ exit(1);
+ }
+ write(fd, enable ? "1" : "0", 2);
+ close(fd);
+}
+
+int main(int argc, char* argv[]) {
+ bool usePTP = false;
+
+ for (int i = 1; i < argc; i++) {
+ if (!strcmp(argv[i], "-p"))
+ usePTP = true;
+ }
+
+ int fd = open("/dev/mtp_usb", O_RDWR);
+ printf("open returned %d\n", fd);
+ if (fd < 0) {
+ fprintf(stderr, "could not open MTP driver\n");
+ return -1;
+ }
+
+ if (usePTP) {
+ // set driver mode to PTP
+ int ret = ioctl(fd, MTP_SET_INTERFACE_MODE, MTP_INTERFACE_MODE_PTP);
+ if (ret) {
+ fprintf(stderr, "MTP_SET_INTERFACE_MODE failed\n");
+ return -1;
+ }
+ }
+
+ // disable UMS and enable MTP USB functions
+ enable_usb_function("usb_mass_storage", false);
+ enable_usb_function("mtp", true);
+
+ MtpServer server(fd, "/data/data/mtp/mtp.db");
+ server.addStorage("/sdcard");
+ server.scanStorage();
+ server.run();
+
+ close(fd);
+ return 0;
+}
+
diff --git a/media/mtp/scantest.cpp b/media/mtp/scantest.cpp
new file mode 100644
index 0000000..f910bb6
--- /dev/null
+++ b/media/mtp/scantest.cpp
@@ -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.
+ */
+
+#include <stdio.h>
+
+#include "MtpDatabase.h"
+#include "MtpMediaScanner.h"
+
+using namespace android;
+
+int main(int argc, char* argv[]) {
+ if (argc != 2) {
+ fprintf(stderr, "usage: %s <storage path>\n", argv[0]);
+ return -1;
+ }
+
+ MtpDatabase* database = new MtpDatabase();
+ database->open("scantest.db", true);
+
+ MtpMediaScanner scanner(1, argv[1], database);
+ scanner.scanFiles();
+ database->close();
+
+ return 0;
+}
diff --git a/opengl/tests/testViewport/Android.mk b/opengl/tests/testViewport/Android.mk
new file mode 100644
index 0000000..ab37809
--- /dev/null
+++ b/opengl/tests/testViewport/Android.mk
@@ -0,0 +1,26 @@
+#########################################################################
+# OpenGL ES JNI sample
+# This makefile builds both an activity and a shared library.
+#########################################################################
+ifneq ($(TARGET_SIMULATOR),true) # not 64 bit clean
+
+TOP_LOCAL_PATH:= $(call my-dir)
+
+# Build activity
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := TestViewport
+
+# Set a specific SDK version so we can run on Froyo.
+
+LOCAL_SDK_VERSION := 8
+
+include $(BUILD_PACKAGE)
+
+endif # TARGET_SIMULATOR
diff --git a/opengl/tests/testViewport/AndroidManifest.xml b/opengl/tests/testViewport/AndroidManifest.xml
new file mode 100644
index 0000000..90a9d2d
--- /dev/null
+++ b/opengl/tests/testViewport/AndroidManifest.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.test">
+ <uses-sdk android:targetSdkVersion="8" android:minSdkVersion="8" />
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <application
+ android:label="@string/test_activity">
+ <activity android:name="TestActivity"
+ android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
+ android:configChanges="orientation|keyboardHidden">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/opengl/tests/testViewport/README b/opengl/tests/testViewport/README
new file mode 100644
index 0000000..c06abc9
--- /dev/null
+++ b/opengl/tests/testViewport/README
@@ -0,0 +1,28 @@
+Repro steps:
+
+build, install and run the attached test program TestViewport.apk
+
+Run on Sapphire with Froyo.
+
+The program clears the screen to blue, then draws a full screen white quad that
+is alligned to the screen.
+(Therefore the whole screen should appear to be white.)
+
+
+Note that screen is all white.
+
+Rotate screen 90 degrees.
+
+Expected: screen is still all white.
+
+Actual: screen is blue with offset white rectangle.
+
+This bug only happens on Sapphire, it works correctly on Passion.
+
+What happens:
+
+I think the bug is that the gl.glViewport() call in onSurfaceChanged() is
+being ignored by the OpenGL driver.
+
+NOTE: If a gl.glViewport call is added at the beginning of the onDrawFrame()
+call (which means it is called before every draw), the program runs correctly.
diff --git a/opengl/tests/testViewport/res/values/strings.xml b/opengl/tests/testViewport/res/values/strings.xml
new file mode 100644
index 0000000..f4b8bbb
--- /dev/null
+++ b/opengl/tests/testViewport/res/values/strings.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- This file contains resource definitions for displayed strings, allowing
+ them to be changed based on the locale and options. -->
+
+<resources>
+ <!-- Simple strings. -->
+ <string name="test_activity">Test Viewport</string>
+
+</resources>
+
diff --git a/opengl/tests/testViewport/src/com/android/test/TestActivity.java b/opengl/tests/testViewport/src/com/android/test/TestActivity.java
new file mode 100644
index 0000000..cc7e450
--- /dev/null
+++ b/opengl/tests/testViewport/src/com/android/test/TestActivity.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+
+public class TestActivity extends Activity {
+ private final static String TAG = "TestActivity";
+ TestView mView;
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ mView = new TestView(getApplication());
+ mView.setFocusableInTouchMode(true);
+ setContentView(mView);
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ mView.onPause();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mView.onResume();
+ }
+}
diff --git a/opengl/tests/testViewport/src/com/android/test/TestView.java b/opengl/tests/testViewport/src/com/android/test/TestView.java
new file mode 100644
index 0000000..23cc37d
--- /dev/null
+++ b/opengl/tests/testViewport/src/com/android/test/TestView.java
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test;
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.CharBuffer;
+import java.nio.FloatBuffer;
+
+import android.content.Context;
+import android.opengl.GLSurfaceView;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL;
+import javax.microedition.khronos.opengles.GL10;
+import javax.microedition.khronos.opengles.GL11;
+/**
+ * An implementation of SurfaceView that uses the dedicated surface for
+ * displaying an OpenGL animation. This allows the animation to run in a
+ * separate thread, without requiring that it be driven by the update mechanism
+ * of the view hierarchy.
+ *
+ * The application-specific rendering code is delegated to a GLView.Renderer
+ * instance.
+ */
+class TestView extends GLSurfaceView {
+ TestView(Context context) {
+ super(context);
+ init();
+ }
+
+ public TestView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ private void init() {
+ setRenderer(new Renderer());
+ setRenderMode(RENDERMODE_WHEN_DIRTY);
+ }
+
+ /** A grid is a topologically rectangular array of vertices.
+ *
+ * The vertex and index data are held in VBO objects because on most
+ * GPUs VBO objects are the fastest way of rendering static vertex
+ * and index data.
+ *
+ */
+
+ private static class Grid {
+ // Size of vertex data elements in bytes:
+ final static int FLOAT_SIZE = 4;
+ final static int CHAR_SIZE = 2;
+
+ // Vertex structure:
+ // float x, y, z;
+
+ final static int VERTEX_SIZE = 3 * FLOAT_SIZE;
+
+ private int mVertexBufferObjectId;
+ private int mElementBufferObjectId;
+
+ // These buffers are used to hold the vertex and index data while
+ // constructing the grid. Once createBufferObjects() is called
+ // the buffers are nulled out to save memory.
+
+ private ByteBuffer mVertexByteBuffer;
+ private FloatBuffer mVertexBuffer;
+ private CharBuffer mIndexBuffer;
+
+ private int mW;
+ private int mH;
+ private int mIndexCount;
+
+ public Grid(int w, int h) {
+ if (w < 0 || w >= 65536) {
+ throw new IllegalArgumentException("w");
+ }
+ if (h < 0 || h >= 65536) {
+ throw new IllegalArgumentException("h");
+ }
+ if (w * h >= 65536) {
+ throw new IllegalArgumentException("w * h >= 65536");
+ }
+
+ mW = w;
+ mH = h;
+ int size = w * h;
+
+ mVertexByteBuffer = ByteBuffer.allocateDirect(VERTEX_SIZE * size)
+ .order(ByteOrder.nativeOrder());
+ mVertexBuffer = mVertexByteBuffer.asFloatBuffer();
+
+ int quadW = mW - 1;
+ int quadH = mH - 1;
+ int quadCount = quadW * quadH;
+ int indexCount = quadCount * 6;
+ mIndexCount = indexCount;
+ mIndexBuffer = ByteBuffer.allocateDirect(CHAR_SIZE * indexCount)
+ .order(ByteOrder.nativeOrder()).asCharBuffer();
+
+ /*
+ * Initialize triangle list mesh.
+ *
+ * [0]-----[ 1] ...
+ * | / |
+ * | / |
+ * | / |
+ * [w]-----[w+1] ...
+ * | |
+ *
+ */
+
+ {
+ int i = 0;
+ for (int y = 0; y < quadH; y++) {
+ for (int x = 0; x < quadW; x++) {
+ char a = (char) (y * mW + x);
+ char b = (char) (y * mW + x + 1);
+ char c = (char) ((y + 1) * mW + x);
+ char d = (char) ((y + 1) * mW + x + 1);
+
+ mIndexBuffer.put(i++, a);
+ mIndexBuffer.put(i++, c);
+ mIndexBuffer.put(i++, b);
+
+ mIndexBuffer.put(i++, b);
+ mIndexBuffer.put(i++, c);
+ mIndexBuffer.put(i++, d);
+ }
+ }
+ }
+
+ }
+
+ public void set(int i, int j, float x, float y, float z) {
+ if (i < 0 || i >= mW) {
+ throw new IllegalArgumentException("i");
+ }
+ if (j < 0 || j >= mH) {
+ throw new IllegalArgumentException("j");
+ }
+
+ int index = mW * j + i;
+
+ mVertexBuffer.position(index * VERTEX_SIZE / FLOAT_SIZE);
+ mVertexBuffer.put(x);
+ mVertexBuffer.put(y);
+ mVertexBuffer.put(z);
+ }
+
+ public void createBufferObjects(GL gl) {
+ // Generate a the vertex and element buffer IDs
+ int[] vboIds = new int[2];
+ GL11 gl11 = (GL11) gl;
+ gl11.glGenBuffers(2, vboIds, 0);
+ mVertexBufferObjectId = vboIds[0];
+ mElementBufferObjectId = vboIds[1];
+
+ // Upload the vertex data
+ gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, mVertexBufferObjectId);
+ mVertexByteBuffer.position(0);
+ gl11.glBufferData(GL11.GL_ARRAY_BUFFER, mVertexByteBuffer.capacity(), mVertexByteBuffer, GL11.GL_STATIC_DRAW);
+
+ gl11.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, mElementBufferObjectId);
+ mIndexBuffer.position(0);
+ gl11.glBufferData(GL11.GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer.capacity() * CHAR_SIZE, mIndexBuffer, GL11.GL_STATIC_DRAW);
+
+ // We don't need the in-memory data any more
+ mVertexBuffer = null;
+ mVertexByteBuffer = null;
+ mIndexBuffer = null;
+ }
+
+ public void draw(GL10 gl) {
+ GL11 gl11 = (GL11) gl;
+
+ gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
+
+ gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, mVertexBufferObjectId);
+ gl11.glVertexPointer(3, GL10.GL_FLOAT, VERTEX_SIZE, 0);
+
+ gl11.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, mElementBufferObjectId);
+ gl11.glDrawElements(GL10.GL_TRIANGLES, mIndexCount, GL10.GL_UNSIGNED_SHORT, 0);
+ gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
+ gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, 0);
+ gl11.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, 0);
+ }
+ }
+
+
+ private class Renderer implements GLSurfaceView.Renderer {
+ private static final String TAG = "Renderer";
+ private Grid mGrid;
+
+ public void onDrawFrame(GL10 gl) {
+ gl.glClearColor(0,0,1,1);
+ gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
+ mGrid.draw(gl);
+ }
+
+ public void onSurfaceChanged(GL10 gl, int width, int height) {
+ gl.glViewport(0, 0, width, height);
+ gl.glMatrixMode(GL11.GL_PROJECTION);
+ gl.glLoadIdentity();
+ gl.glOrthof(0, width, height, 0, -1, 1);
+ gl.glMatrixMode(GL11.GL_MODELVIEW);
+ createGrid(gl, width, height);
+ }
+
+ public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+ }
+
+ private void createGrid(GL10 gl, float w, float h) {
+ mGrid = new Grid(2, 2);
+ for (int j = 0; j < 2; j++) {
+ for (int i = 0; i < 2; i++) {
+ float x = w * i;
+ float y = h * j;
+ float z = 0.0f;
+ mGrid.set(i,j, x, y, z);
+ }
+ }
+ mGrid.createBufferObjects(gl);
+ }
+ }
+}
+
diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java
index 27706ef..8693294 100644
--- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java
+++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java
@@ -667,6 +667,7 @@
case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
+ case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
currentMode = UnlockMode.Password;
break;
case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
@@ -687,8 +688,17 @@
private void showTimeoutDialog() {
int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000;
+ int messageId = R.string.lockscreen_too_many_failed_attempts_dialog_message;;
+ if(getUnlockMode() == UnlockMode.Password) {
+ if(mLockPatternUtils.getKeyguardStoredPasswordQuality() ==
+ DevicePolicyManager.PASSWORD_QUALITY_NUMERIC) {
+ messageId = R.string.lockscreen_too_many_failed_pin_attempts_dialog_message;
+ } else {
+ messageId = R.string.lockscreen_too_many_failed_password_attempts_dialog_message;
+ }
+ }
String message = mContext.getString(
- R.string.lockscreen_too_many_failed_attempts_dialog_message,
+ messageId,
mUpdateMonitor.getFailedAttempts(),
timeoutInSeconds);
final AlertDialog dialog = new AlertDialog.Builder(mContext)
diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java
index a5ef1fa..b3707b0 100644
--- a/policy/com/android/internal/policy/impl/LockScreen.java
+++ b/policy/com/android/internal/policy/impl/LockScreen.java
@@ -220,7 +220,6 @@
}
});
-
setFocusable(true);
setFocusableInTouchMode(true);
setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
@@ -518,7 +517,7 @@
mScreenLocked.setText("");
// layout
- mScreenLocked.setVisibility(View.VISIBLE);
+ mScreenLocked.setVisibility(View.INVISIBLE);
mSelector.setVisibility(View.VISIBLE);
mEmergencyCallText.setVisibility(View.GONE);
break;
@@ -658,7 +657,6 @@
/** {@inheritDoc} */
public void onResume() {
resetStatusInfo(mUpdateMonitor);
- mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton);
}
/** {@inheritDoc} */
@@ -676,6 +674,5 @@
}
public void onPhoneStateChanged(String newState) {
- mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton);
}
}
diff --git a/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java b/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java
index 39f2917..60cd56c 100644
--- a/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java
+++ b/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java
@@ -53,6 +53,8 @@
private final KeyguardUpdateMonitor mUpdateMonitor;
private final KeyguardScreenCallback mCallback;
+ private boolean mIsAlpha;
+
private EditText mPasswordEntry;
private Button mEmergencyCallButton;
private LockPatternUtils mLockPatternUtils;
@@ -87,8 +89,9 @@
}
final int quality = lockPatternUtils.getKeyguardStoredPasswordQuality();
- final boolean isAlpha = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC == quality
- || DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC == quality;
+ mIsAlpha = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC == quality
+ || DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC == quality
+ || DevicePolicyManager.PASSWORD_QUALITY_COMPLEX == quality;
mKeyboardView = (PasswordEntryKeyboardView) findViewById(R.id.keyboard);
mPasswordEntry = (EditText) findViewById(R.id.passwordEntry);
@@ -99,7 +102,7 @@
mTitle = (TextView) findViewById(R.id.enter_password_label);
mKeyboardHelper = new PasswordEntryKeyboardHelper(context, mKeyboardView, this);
- mKeyboardHelper.setKeyboardMode(isAlpha ? PasswordEntryKeyboardHelper.KEYBOARD_MODE_ALPHA
+ mKeyboardHelper.setKeyboardMode(mIsAlpha ? PasswordEntryKeyboardHelper.KEYBOARD_MODE_ALPHA
: PasswordEntryKeyboardHelper.KEYBOARD_MODE_NUMERIC);
mKeyboardView.setVisibility(mCreationHardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO
@@ -108,10 +111,11 @@
// This allows keyboards with overlapping qwerty/numeric keys to choose just the
// numeric keys.
- if (isAlpha) {
+ if (mIsAlpha) {
mPasswordEntry.setKeyListener(TextKeyListener.getInstance());
} else {
mPasswordEntry.setKeyListener(DigitsKeyListener.getInstance());
+ mTitle.setText(R.string.keyguard_password_enter_pin_password_code);
}
mKeyboardHelper.setVibratePattern(mLockPatternUtils.isTactileFeedbackEnabled() ?
@@ -138,6 +142,7 @@
public void onResume() {
// start fresh
mPasswordEntry.setText("");
+ resetStatusInfo();
mPasswordEntry.requestFocus();
mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton);
@@ -174,6 +179,9 @@
long deadline = mLockPatternUtils.setLockoutAttemptDeadline();
handleAttemptLockout(deadline);
}
+ mTitle.setText(R.string.lockscreen_password_wrong);
+ } else if (entry.length() > 0) {
+ mTitle.setText(R.string.lockscreen_password_wrong);
}
mPasswordEntry.setText("");
}
@@ -197,8 +205,8 @@
@Override
public void onFinish() {
mPasswordEntry.setEnabled(true);
- mTitle.setText(R.string.keyguard_password_enter_password_code);
mKeyboardView.setEnabled(true);
+ resetStatusInfo();
}
}.start();
}
@@ -264,4 +272,12 @@
}
+ private void resetStatusInfo() {
+ if(mIsAlpha) {
+ mTitle.setText(R.string.keyguard_password_enter_password_code);
+ } else {
+ mTitle.setText(R.string.keyguard_password_enter_pin_password_code);
+ }
+ }
+
}
diff --git a/policy/com/android/internal/policy/impl/PhoneWindow.java b/policy/com/android/internal/policy/impl/PhoneWindow.java
index 0cb0efc..0bf0d52 100644
--- a/policy/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/com/android/internal/policy/impl/PhoneWindow.java
@@ -54,6 +54,7 @@
import android.util.EventLog;
import android.util.Log;
import android.util.SparseArray;
+import android.view.ActionBarView;
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
import android.view.KeyCharacterMap;
@@ -80,6 +81,12 @@
import android.widget.ProgressBar;
import android.widget.TextView;
+import com.android.internal.view.menu.ContextMenuBuilder;
+import com.android.internal.view.menu.MenuBuilder;
+import com.android.internal.view.menu.MenuDialogHelper;
+import com.android.internal.view.menu.MenuView;
+import com.android.internal.view.menu.SubMenuBuilder;
+
/**
* Android-specific Window.
* <p>
@@ -113,6 +120,8 @@
private LayoutInflater mLayoutInflater;
private TextView mTitleView;
+
+ private ActionBarView mActionBar;
private DrawableFeatureState[] mDrawables;
@@ -271,6 +280,8 @@
public void setTitle(CharSequence title) {
if (mTitleView != null) {
mTitleView.setText(title);
+ } else if (mActionBar != null) {
+ mActionBar.setTitle(title);
}
mTitle = title;
}
@@ -2097,6 +2108,9 @@
if (a.getBoolean(com.android.internal.R.styleable.Window_windowNoTitle, false)) {
requestFeature(FEATURE_NO_TITLE);
+ } else if (a.getBoolean(com.android.internal.R.styleable.Window_windowActionBar, false)) {
+ // Don't allow an action bar if there is no title.
+ requestFeature(FEATURE_ACTION_BAR);
}
if (a.getBoolean(com.android.internal.R.styleable.Window_windowFullscreen, false)) {
@@ -2180,6 +2194,8 @@
// If the window is floating, we need a dialog layout
if (mIsFloating) {
layoutResource = com.android.internal.R.layout.dialog_title;
+ } else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) {
+ layoutResource = com.android.internal.R.layout.screen_action_bar;
} else {
layoutResource = com.android.internal.R.layout.screen_title;
}
@@ -2264,6 +2280,13 @@
} else {
mTitleView.setText(mTitle);
}
+ } else {
+ mActionBar = (ActionBarView) findViewById(com.android.internal.R.id.action_bar);
+ if (mActionBar != null) {
+ if (mActionBar.getTitle() == null) {
+ mActionBar.setTitle(mTitle);
+ }
+ }
}
}
}
diff --git a/preloaded-classes b/preloaded-classes
index b602039..da5502d 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -563,8 +563,6 @@
android.widget.AdapterView
android.widget.ArrayAdapter
android.widget.AutoCompleteTextView
-android.widget.AutoCompleteTextView$DropDownItemClickListener
-android.widget.AutoCompleteTextView$DropDownListView
android.widget.BaseAdapter
android.widget.BaseExpandableListAdapter
android.widget.CheckBox
@@ -582,6 +580,7 @@
android.widget.ImageView
android.widget.ImageView$ScaleType
android.widget.LinearLayout
+android.widget.ListPopupWindow
android.widget.ListView
android.widget.ListView$SavedState
android.widget.MediaController
@@ -697,7 +696,6 @@
com.ibm.icu4jni.charset.CharsetDecoderICU
com.ibm.icu4jni.charset.CharsetEncoderICU
com.ibm.icu4jni.charset.CharsetICU
-com.ibm.icu4jni.charset.CharsetProviderICU
com.ibm.icu4jni.charset.NativeConverter
com.ibm.icu4jni.common.ErrorCode
com.ibm.icu4jni.lang.UCharacter
@@ -707,9 +705,6 @@
com.ibm.icu4jni.text.NativeCollation
com.ibm.icu4jni.text.NativeDecimalFormat
com.ibm.icu4jni.text.RuleBasedCollator
-com.ibm.icu4jni.text.RuleBasedNumberFormat
-com.ibm.icu4jni.util.Resources
-com.ibm.icu4jni.util.Resources$DefaultTimeZones
dalvik.system.DalvikLogHandler
dalvik.system.DalvikLogging
dalvik.system.NativeStart
@@ -733,7 +728,6 @@
java.io.File
java.io.FileDescriptor
java.io.FileInputStream
-java.io.FileInputStream$RepositioningLock
java.io.FileNotFoundException
java.io.FileOutputStream
java.io.FilterInputStream
@@ -758,7 +752,6 @@
java.io.PrintWriter
java.io.PushbackReader
java.io.RandomAccessFile
-java.io.RandomAccessFile$RepositionLock
java.io.Reader
java.io.Serializable
java.io.StreamCorruptedException
@@ -930,7 +923,6 @@
java.security.cert.X509Certificate
java.text.AttributedCharacterIterator$Attribute
java.text.Collator
-java.text.Collator$1
java.text.DateFormat
java.text.DateFormat$Field
java.text.DecimalFormat
@@ -1126,7 +1118,6 @@
org.apache.harmony.luni.util.InputStreamHelper$1
org.apache.harmony.luni.util.InputStreamHelper$ExposedByteArrayInputStream
org.apache.harmony.luni.util.LocaleCache
-org.apache.harmony.luni.util.Msg
org.apache.harmony.luni.util.NumberConverter
org.apache.harmony.luni.util.PriviAction
org.apache.harmony.luni.util.ThreadLocalCache
@@ -1139,7 +1130,6 @@
org.apache.harmony.nio.FileChannelFactory
org.apache.harmony.nio.internal.DirectBuffer
org.apache.harmony.nio.internal.FileChannelImpl
-org.apache.harmony.nio.internal.FileChannelImpl$RepositioningLock
org.apache.harmony.nio.internal.FileLockImpl
org.apache.harmony.nio.internal.LockManager
org.apache.harmony.nio.internal.LockManager$1
diff --git a/services/java/com/android/server/AccessibilityManagerService.java b/services/java/com/android/server/AccessibilityManagerService.java
index 87de79a..83ce3e3 100644
--- a/services/java/com/android/server/AccessibilityManagerService.java
+++ b/services/java/com/android/server/AccessibilityManagerService.java
@@ -269,14 +269,10 @@
});
}
- public void addClient(IAccessibilityManagerClient client) {
+ public boolean addClient(IAccessibilityManagerClient client) {
synchronized (mLock) {
- try {
- client.setEnabled(mIsEnabled);
- mClients.add(client);
- } catch (RemoteException re) {
- Slog.w(LOG_TAG, "Dead AccessibilityManagerClient: " + client, re);
- }
+ mClients.add(client);
+ return mIsEnabled;
}
}
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index 19d146d..c0ea68d 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -67,37 +67,50 @@
*/
public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
static final String TAG = "DevicePolicyManagerService";
-
+
final Context mContext;
final MyPackageMonitor mMonitor;
IPowerManager mIPowerManager;
-
+
int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
int mActivePasswordLength = 0;
+ int mActivePasswordUpperCase = 0;
+ int mActivePasswordLowerCase = 0;
+ int mActivePasswordLetters = 0;
+ int mActivePasswordNumeric = 0;
+ int mActivePasswordSymbols = 0;
+ int mActivePasswordNonLetter = 0;
int mFailedPasswordAttempts = 0;
-
+
int mPasswordOwner = -1;
-
+
final HashMap<ComponentName, ActiveAdmin> mAdminMap
= new HashMap<ComponentName, ActiveAdmin>();
final ArrayList<ActiveAdmin> mAdminList
= new ArrayList<ActiveAdmin>();
-
+
static class ActiveAdmin {
final DeviceAdminInfo info;
-
+
int passwordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
int minimumPasswordLength = 0;
+ int passwordHistoryLength = 0;
+ int minimumPasswordUpperCase = 0;
+ int minimumPasswordLowerCase = 0;
+ int minimumPasswordLetters = 1;
+ int minimumPasswordNumeric = 1;
+ int minimumPasswordSymbols = 1;
+ int minimumPasswordNonLetter = 0;
long maximumTimeToUnlock = 0;
int maximumFailedPasswordsForWipe = 0;
-
+
ActiveAdmin(DeviceAdminInfo _info) {
info = _info;
}
-
+
int getUid() { return info.getActivityInfo().applicationInfo.uid; }
-
+
void writeToXml(XmlSerializer out)
throws IllegalArgumentException, IllegalStateException, IOException {
out.startTag(null, "policies");
@@ -110,7 +123,42 @@
if (minimumPasswordLength > 0) {
out.startTag(null, "min-password-length");
out.attribute(null, "value", Integer.toString(minimumPasswordLength));
- out.endTag(null, "mn-password-length");
+ out.endTag(null, "min-password-length");
+ }
+ if(passwordHistoryLength > 0) {
+ out.startTag(null, "password-history-length");
+ out.attribute(null, "value", Integer.toString(passwordHistoryLength));
+ out.endTag(null, "password-history-length");
+ }
+ if (minimumPasswordUpperCase > 0) {
+ out.startTag(null, "min-password-uppercase");
+ out.attribute(null, "value", Integer.toString(minimumPasswordUpperCase));
+ out.endTag(null, "min-password-uppercase");
+ }
+ if (minimumPasswordLowerCase > 0) {
+ out.startTag(null, "min-password-lowercase");
+ out.attribute(null, "value", Integer.toString(minimumPasswordLowerCase));
+ out.endTag(null, "min-password-lowercase");
+ }
+ if (minimumPasswordLetters > 0) {
+ out.startTag(null, "min-password-letters");
+ out.attribute(null, "value", Integer.toString(minimumPasswordLetters));
+ out.endTag(null, "min-password-letters");
+ }
+ if (minimumPasswordNumeric > 0) {
+ out.startTag(null, "min-password-numeric");
+ out.attribute(null, "value", Integer.toString(minimumPasswordNumeric));
+ out.endTag(null, "min-password-numeric");
+ }
+ if (minimumPasswordSymbols > 0) {
+ out.startTag(null, "min-password-symbols");
+ out.attribute(null, "value", Integer.toString(minimumPasswordSymbols));
+ out.endTag(null, "min-password-symbols");
+ }
+ if (minimumPasswordNonLetter > 0) {
+ out.startTag(null, "min-password-nonletter");
+ out.attribute(null, "value", Integer.toString(minimumPasswordNonLetter));
+ out.endTag(null, "min-password-nonletter");
}
}
if (maximumTimeToUnlock != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
@@ -124,7 +172,7 @@
out.endTag(null, "max-failed-password-wipe");
}
}
-
+
void readFromXml(XmlPullParser parser)
throws XmlPullParserException, IOException {
int outerDepth = parser.getDepth();
@@ -143,6 +191,27 @@
} else if ("min-password-length".equals(tag)) {
minimumPasswordLength = Integer.parseInt(
parser.getAttributeValue(null, "value"));
+ } else if ("password-history-length".equals(tag)) {
+ passwordHistoryLength = Integer.parseInt(
+ parser.getAttributeValue(null, "value"));
+ } else if ("min-password-uppercase".equals(tag)) {
+ minimumPasswordUpperCase = Integer.parseInt(
+ parser.getAttributeValue(null, "value"));
+ } else if ("min-password-lowercase".equals(tag)) {
+ minimumPasswordLowerCase = Integer.parseInt(
+ parser.getAttributeValue(null, "value"));
+ } else if ("min-password-letters".equals(tag)) {
+ minimumPasswordLetters = Integer.parseInt(
+ parser.getAttributeValue(null, "value"));
+ } else if ("min-password-numeric".equals(tag)) {
+ minimumPasswordNumeric = Integer.parseInt(
+ parser.getAttributeValue(null, "value"));
+ } else if ("min-password-symbols".equals(tag)) {
+ minimumPasswordSymbols = Integer.parseInt(
+ parser.getAttributeValue(null, "value"));
+ } else if ("min-password-nonletter".equals(tag)) {
+ minimumPasswordNonLetter = Integer.parseInt(
+ parser.getAttributeValue(null, "value"));
} else if ("max-time-to-unlock".equals(tag)) {
maximumTimeToUnlock = Long.parseLong(
parser.getAttributeValue(null, "value"));
@@ -155,7 +224,7 @@
XmlUtils.skipCurrentTag(parser);
}
}
-
+
void dump(String prefix, PrintWriter pw) {
pw.print(prefix); pw.print("uid="); pw.println(getUid());
pw.print(prefix); pw.println("policies:");
@@ -166,23 +235,37 @@
}
}
pw.print(prefix); pw.print("passwordQuality=0x");
- pw.print(Integer.toHexString(passwordQuality));
- pw.print(" minimumPasswordLength=");
+ pw.println(Integer.toHexString(passwordQuality));
+ pw.print(prefix); pw.print("minimumPasswordLength=");
pw.println(minimumPasswordLength);
+ pw.print(prefix); pw.print("passwordHistoryLength=");
+ pw.println(passwordHistoryLength);
+ pw.print(prefix); pw.print("minimumPasswordUpperCase=");
+ pw.println(minimumPasswordUpperCase);
+ pw.print(prefix); pw.print("minimumPasswordLowerCase=");
+ pw.println(minimumPasswordLowerCase);
+ pw.print(prefix); pw.print("minimumPasswordLetters=");
+ pw.println(minimumPasswordLetters);
+ pw.print(prefix); pw.print("minimumPasswordNumeric=");
+ pw.println(minimumPasswordNumeric);
+ pw.print(prefix); pw.print("minimumPasswordSymbols=");
+ pw.println(minimumPasswordSymbols);
+ pw.print(prefix); pw.print("minimumPasswordNonLetter=");
+ pw.println(minimumPasswordNonLetter);
pw.print(prefix); pw.print("maximumTimeToUnlock=");
pw.println(maximumTimeToUnlock);
pw.print(prefix); pw.print("maximumFailedPasswordsForWipe=");
pw.println(maximumFailedPasswordsForWipe);
}
}
-
+
class MyPackageMonitor extends PackageMonitor {
public void onSomePackagesChanged() {
synchronized (DevicePolicyManagerService.this) {
boolean removed = false;
for (int i=mAdminList.size()-1; i>=0; i--) {
ActiveAdmin aa = mAdminList.get(i);
- int change = isPackageDisappearing(aa.info.getPackageName());
+ int change = isPackageDisappearing(aa.info.getPackageName());
if (change == PACKAGE_PERMANENT_CHANGE
|| change == PACKAGE_TEMPORARY_CHANGE) {
Slog.w(TAG, "Admin unexpectedly uninstalled: "
@@ -207,7 +290,7 @@
}
}
}
-
+
/**
* Instantiates the service.
*/
@@ -224,7 +307,7 @@
}
return mIPowerManager;
}
-
+
ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who) {
ActiveAdmin admin = mAdminMap.get(who);
if (admin != null
@@ -234,7 +317,7 @@
}
return null;
}
-
+
ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
throws SecurityException {
final int callingUid = Binder.getCallingUid();
@@ -265,13 +348,13 @@
+ Binder.getCallingUid() + " for policy #" + reqPolicy);
}
}
-
+
void sendAdminCommandLocked(ActiveAdmin admin, String action) {
Intent intent = new Intent(action);
intent.setComponent(admin.info.getComponent());
mContext.sendBroadcast(intent);
}
-
+
void sendAdminCommandLocked(String action, int reqPolicy) {
final int N = mAdminList.size();
if (N > 0) {
@@ -283,7 +366,7 @@
}
}
}
-
+
void removeActiveAdminLocked(ComponentName adminReceiver) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
if (admin != null) {
@@ -295,7 +378,7 @@
validatePasswordOwnerLocked();
}
}
-
+
public DeviceAdminInfo findAdmin(ComponentName adminName) {
Intent resolveIntent = new Intent();
resolveIntent.setComponent(adminName);
@@ -304,7 +387,7 @@
if (infos == null || infos.size() <= 0) {
throw new IllegalArgumentException("Unknown admin: " + adminName);
}
-
+
try {
return new DeviceAdminInfo(mContext, infos.get(0));
} catch (XmlPullParserException e) {
@@ -315,7 +398,7 @@
return null;
}
}
-
+
private static JournaledFile makeJournaledFile() {
final String base = "/data/system/device_policies.xml";
return new JournaledFile(new File(base), new File(base + ".tmp"));
@@ -331,7 +414,7 @@
out.startDocument(null, true);
out.startTag(null, "policies");
-
+
final int N = mAdminList.size();
for (int i=0; i<N; i++) {
ActiveAdmin ap = mAdminList.get(i);
@@ -342,26 +425,36 @@
out.endTag(null, "admin");
}
}
-
+
if (mPasswordOwner >= 0) {
out.startTag(null, "password-owner");
out.attribute(null, "value", Integer.toString(mPasswordOwner));
out.endTag(null, "password-owner");
}
-
+
if (mFailedPasswordAttempts != 0) {
out.startTag(null, "failed-password-attempts");
out.attribute(null, "value", Integer.toString(mFailedPasswordAttempts));
out.endTag(null, "failed-password-attempts");
}
-
- if (mActivePasswordQuality != 0 || mActivePasswordLength != 0) {
+
+ if (mActivePasswordQuality != 0 || mActivePasswordLength != 0
+ || mActivePasswordUpperCase != 0 || mActivePasswordLowerCase != 0
+ || mActivePasswordLetters != 0 || mActivePasswordNumeric != 0
+ || mActivePasswordSymbols != 0 || mActivePasswordNonLetter != 0) {
out.startTag(null, "active-password");
out.attribute(null, "quality", Integer.toString(mActivePasswordQuality));
out.attribute(null, "length", Integer.toString(mActivePasswordLength));
+ out.attribute(null, "uppercase", Integer.toString(mActivePasswordUpperCase));
+ out.attribute(null, "lowercase", Integer.toString(mActivePasswordLowerCase));
+ out.attribute(null, "letters", Integer.toString(mActivePasswordLetters));
+ out.attribute(null, "numeric", Integer
+ .toString(mActivePasswordNumeric));
+ out.attribute(null, "symbols", Integer.toString(mActivePasswordSymbols));
+ out.attribute(null, "nonletter", Integer.toString(mActivePasswordNonLetter));
out.endTag(null, "active-password");
}
-
+
out.endTag(null, "policies");
out.endDocument();
@@ -439,6 +532,18 @@
parser.getAttributeValue(null, "quality"));
mActivePasswordLength = Integer.parseInt(
parser.getAttributeValue(null, "length"));
+ mActivePasswordUpperCase = Integer.parseInt(
+ parser.getAttributeValue(null, "uppercase"));
+ mActivePasswordLowerCase = Integer.parseInt(
+ parser.getAttributeValue(null, "lowercase"));
+ mActivePasswordLetters = Integer.parseInt(
+ parser.getAttributeValue(null, "letters"));
+ mActivePasswordNumeric = Integer.parseInt(
+ parser.getAttributeValue(null, "numeric"));
+ mActivePasswordSymbols = Integer.parseInt(
+ parser.getAttributeValue(null, "symbols"));
+ mActivePasswordNonLetter = Integer.parseInt(
+ parser.getAttributeValue(null, "nonletter"));
XmlUtils.skipCurrentTag(parser);
} else {
Slog.w(TAG, "Unknown tag: " + tag);
@@ -476,10 +581,16 @@
+ Integer.toHexString(utils.getActivePasswordQuality()));
mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
mActivePasswordLength = 0;
+ mActivePasswordUpperCase = 0;
+ mActivePasswordLowerCase = 0;
+ mActivePasswordLetters = 0;
+ mActivePasswordNumeric = 0;
+ mActivePasswordSymbols = 0;
+ mActivePasswordNonLetter = 0;
}
-
+
validatePasswordOwnerLocked();
-
+
long timeMs = getMaximumTimeToLock(null);
if (timeMs <= 0) {
timeMs = Integer.MAX_VALUE;
@@ -498,12 +609,13 @@
case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
+ case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
return;
}
throw new IllegalArgumentException("Invalid quality constant: 0x"
+ Integer.toHexString(quality));
}
-
+
void validatePasswordOwnerLocked() {
if (mPasswordOwner >= 0) {
boolean haveOwner = false;
@@ -520,17 +632,17 @@
}
}
}
-
+
public void systemReady() {
synchronized (this) {
loadSettingsLocked();
}
}
-
+
public void setActiveAdmin(ComponentName adminReceiver) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.BIND_DEVICE_ADMIN, null);
-
+
DeviceAdminInfo info = findAdmin(adminReceiver);
if (info == null) {
throw new IllegalArgumentException("Bad admin: " + adminReceiver);
@@ -552,13 +664,13 @@
}
}
}
-
+
public boolean isAdminActive(ComponentName adminReceiver) {
synchronized (this) {
return getActiveAdminUncheckedLocked(adminReceiver) != null;
}
}
-
+
public List<ComponentName> getActiveAdmins() {
synchronized (this) {
final int N = mAdminList.size();
@@ -572,7 +684,7 @@
return res;
}
}
-
+
public boolean packageHasActiveAdmins(String packageName) {
synchronized (this) {
final int N = mAdminList.size();
@@ -584,7 +696,7 @@
return false;
}
}
-
+
public void removeActiveAdmin(ComponentName adminReceiver) {
synchronized (this) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
@@ -603,10 +715,10 @@
}
}
}
-
+
public void setPasswordQuality(ComponentName who, int quality) {
validateQualityConstant(quality);
-
+
synchronized (this) {
if (who == null) {
throw new NullPointerException("ComponentName is null");
@@ -619,16 +731,16 @@
}
}
}
-
+
public int getPasswordQuality(ComponentName who) {
synchronized (this) {
int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
-
+
if (who != null) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
return admin != null ? admin.passwordQuality : mode;
}
-
+
final int N = mAdminList.size();
for (int i=0; i<N; i++) {
ActiveAdmin admin = mAdminList.get(i);
@@ -639,7 +751,7 @@
return mode;
}
}
-
+
public void setPasswordMinimumLength(ComponentName who, int length) {
synchronized (this) {
if (who == null) {
@@ -653,16 +765,16 @@
}
}
}
-
+
public int getPasswordMinimumLength(ComponentName who) {
synchronized (this) {
int length = 0;
-
+
if (who != null) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
return admin != null ? admin.minimumPasswordLength : length;
}
-
+
final int N = mAdminList.size();
for (int i=0; i<N; i++) {
ActiveAdmin admin = mAdminList.get(i);
@@ -673,18 +785,267 @@
return length;
}
}
-
+
+ public void setPasswordHistoryLength(ComponentName who, int length) {
+ synchronized (this) {
+ if (who == null) {
+ throw new NullPointerException("ComponentName is null");
+ }
+ ActiveAdmin ap = getActiveAdminForCallerLocked(who,
+ DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
+ if (ap.passwordHistoryLength != length) {
+ ap.passwordHistoryLength = length;
+ saveSettingsLocked();
+ }
+ }
+ }
+
+ public int getPasswordHistoryLength(ComponentName who) {
+ synchronized (this) {
+ int length = 0;
+
+ if (who != null) {
+ ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
+ return admin != null ? admin.passwordHistoryLength : length;
+ }
+
+ final int N = mAdminList.size();
+ for (int i = 0; i < N; i++) {
+ ActiveAdmin admin = mAdminList.get(i);
+ if (length < admin.passwordHistoryLength) {
+ length = admin.passwordHistoryLength;
+ }
+ }
+ return length;
+ }
+ }
+
+ public void setPasswordMinimumUpperCase(ComponentName who, int length) {
+ synchronized (this) {
+ if (who == null) {
+ throw new NullPointerException("ComponentName is null");
+ }
+ ActiveAdmin ap = getActiveAdminForCallerLocked(who,
+ DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
+ if (ap.minimumPasswordUpperCase != length) {
+ ap.minimumPasswordUpperCase = length;
+ saveSettingsLocked();
+ }
+ }
+ }
+
+ public int getPasswordMinimumUpperCase(ComponentName who) {
+ synchronized (this) {
+ int length = 0;
+
+ if (who != null) {
+ ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
+ return admin != null ? admin.minimumPasswordUpperCase : length;
+ }
+
+ final int N = mAdminList.size();
+ for (int i=0; i<N; i++) {
+ ActiveAdmin admin = mAdminList.get(i);
+ if (length < admin.minimumPasswordUpperCase) {
+ length = admin.minimumPasswordUpperCase;
+ }
+ }
+ return length;
+ }
+ }
+
+ public void setPasswordMinimumLowerCase(ComponentName who, int length) {
+ synchronized (this) {
+ if (who == null) {
+ throw new NullPointerException("ComponentName is null");
+ }
+ ActiveAdmin ap = getActiveAdminForCallerLocked(who,
+ DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
+ if (ap.minimumPasswordLowerCase != length) {
+ ap.minimumPasswordLowerCase = length;
+ saveSettingsLocked();
+ }
+ }
+ }
+
+ public int getPasswordMinimumLowerCase(ComponentName who) {
+ synchronized (this) {
+ int length = 0;
+
+ if (who != null) {
+ ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
+ return admin != null ? admin.minimumPasswordLowerCase : length;
+ }
+
+ final int N = mAdminList.size();
+ for (int i=0; i<N; i++) {
+ ActiveAdmin admin = mAdminList.get(i);
+ if (length < admin.minimumPasswordLowerCase) {
+ length = admin.minimumPasswordLowerCase;
+ }
+ }
+ return length;
+ }
+ }
+
+ public void setPasswordMinimumLetters(ComponentName who, int length) {
+ synchronized (this) {
+ if (who == null) {
+ throw new NullPointerException("ComponentName is null");
+ }
+ ActiveAdmin ap = getActiveAdminForCallerLocked(who,
+ DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
+ if (ap.minimumPasswordLetters != length) {
+ ap.minimumPasswordLetters = length;
+ saveSettingsLocked();
+ }
+ }
+ }
+
+ public int getPasswordMinimumLetters(ComponentName who) {
+ synchronized (this) {
+ int length = 0;
+
+ if (who != null) {
+ ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
+ return admin != null ? admin.minimumPasswordLetters : length;
+ }
+
+ final int N = mAdminList.size();
+ for (int i=0; i<N; i++) {
+ ActiveAdmin admin = mAdminList.get(i);
+ if (length < admin.minimumPasswordLetters) {
+ length = admin.minimumPasswordLetters;
+ }
+ }
+ return length;
+ }
+ }
+
+ public void setPasswordMinimumNumeric(ComponentName who, int length) {
+ synchronized (this) {
+ if (who == null) {
+ throw new NullPointerException("ComponentName is null");
+ }
+ ActiveAdmin ap = getActiveAdminForCallerLocked(who,
+ DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
+ if (ap.minimumPasswordNumeric != length) {
+ ap.minimumPasswordNumeric = length;
+ saveSettingsLocked();
+ }
+ }
+ }
+
+ public int getPasswordMinimumNumeric(ComponentName who) {
+ synchronized (this) {
+ int length = 0;
+
+ if (who != null) {
+ ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
+ return admin != null ? admin.minimumPasswordNumeric : length;
+ }
+
+ final int N = mAdminList.size();
+ for (int i = 0; i < N; i++) {
+ ActiveAdmin admin = mAdminList.get(i);
+ if (length < admin.minimumPasswordNumeric) {
+ length = admin.minimumPasswordNumeric;
+ }
+ }
+ return length;
+ }
+ }
+
+ public void setPasswordMinimumSymbols(ComponentName who, int length) {
+ synchronized (this) {
+ if (who == null) {
+ throw new NullPointerException("ComponentName is null");
+ }
+ ActiveAdmin ap = getActiveAdminForCallerLocked(who,
+ DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
+ if (ap.minimumPasswordSymbols != length) {
+ ap.minimumPasswordSymbols = length;
+ saveSettingsLocked();
+ }
+ }
+ }
+
+ public int getPasswordMinimumSymbols(ComponentName who) {
+ synchronized (this) {
+ int length = 0;
+
+ if (who != null) {
+ ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
+ return admin != null ? admin.minimumPasswordSymbols : length;
+ }
+
+ final int N = mAdminList.size();
+ for (int i=0; i<N; i++) {
+ ActiveAdmin admin = mAdminList.get(i);
+ if (length < admin.minimumPasswordSymbols) {
+ length = admin.minimumPasswordSymbols;
+ }
+ }
+ return length;
+ }
+ }
+
+ public void setPasswordMinimumNonLetter(ComponentName who, int length) {
+ synchronized (this) {
+ if (who == null) {
+ throw new NullPointerException("ComponentName is null");
+ }
+ ActiveAdmin ap = getActiveAdminForCallerLocked(who,
+ DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
+ if (ap.minimumPasswordNonLetter != length) {
+ ap.minimumPasswordNonLetter = length;
+ saveSettingsLocked();
+ }
+ }
+ }
+
+ public int getPasswordMinimumNonLetter(ComponentName who) {
+ synchronized (this) {
+ int length = 0;
+
+ if (who != null) {
+ ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
+ return admin != null ? admin.minimumPasswordNonLetter : length;
+ }
+
+ final int N = mAdminList.size();
+ for (int i=0; i<N; i++) {
+ ActiveAdmin admin = mAdminList.get(i);
+ if (length < admin.minimumPasswordNonLetter) {
+ length = admin.minimumPasswordNonLetter;
+ }
+ }
+ return length;
+ }
+ }
+
public boolean isActivePasswordSufficient() {
synchronized (this) {
// This API can only be called by an active device admin,
// so try to retrieve it to check that the caller is one.
getActiveAdminForCallerLocked(null,
DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
- return mActivePasswordQuality >= getPasswordQuality(null)
- && mActivePasswordLength >= getPasswordMinimumLength(null);
+ if (mActivePasswordQuality < getPasswordQuality(null)
+ || mActivePasswordLength < getPasswordMinimumLength(null)) {
+ return false;
+ }
+ if(mActivePasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
+ return true;
+ }
+ return mActivePasswordUpperCase >= getPasswordMinimumUpperCase(null)
+ && mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null)
+ && mActivePasswordLetters >= getPasswordMinimumLetters(null)
+ && mActivePasswordNumeric >= getPasswordMinimumNumeric(null)
+ && mActivePasswordSymbols >= getPasswordMinimumSymbols(null)
+ && mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null);
}
}
-
+
public int getCurrentFailedPasswordAttempts() {
synchronized (this) {
// This API can only be called by an active device admin,
@@ -694,7 +1055,7 @@
return mFailedPasswordAttempts;
}
}
-
+
public void setMaximumFailedPasswordsForWipe(ComponentName who, int num) {
synchronized (this) {
// This API can only be called by an active device admin,
@@ -709,16 +1070,16 @@
}
}
}
-
+
public int getMaximumFailedPasswordsForWipe(ComponentName who) {
synchronized (this) {
int count = 0;
-
+
if (who != null) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
return admin != null ? admin.maximumFailedPasswordsForWipe : count;
}
-
+
final int N = mAdminList.size();
for (int i=0; i<N; i++) {
ActiveAdmin admin = mAdminList.get(i);
@@ -732,7 +1093,7 @@
return count;
}
}
-
+
public boolean resetPassword(String password, int flags) {
int quality;
synchronized (this) {
@@ -743,14 +1104,15 @@
quality = getPasswordQuality(null);
if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
int realQuality = LockPatternUtils.computePasswordQuality(password);
- if (realQuality < quality) {
+ if (realQuality < quality
+ && quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
Slog.w(TAG, "resetPassword: password quality 0x"
+ Integer.toHexString(quality)
+ " does not meet required quality 0x"
+ Integer.toHexString(quality));
return false;
}
- quality = realQuality;
+ quality = Math.max(realQuality, quality);
}
int length = getPasswordMinimumLength(null);
if (password.length() < length) {
@@ -758,14 +1120,86 @@
+ " does not meet required length " + length);
return false;
}
+ if (quality == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
+ int letters = 0;
+ int uppercase = 0;
+ int lowercase = 0;
+ int numbers = 0;
+ int symbols = 0;
+ int nonletter = 0;
+ for (int i = 0; i < password.length(); i++) {
+ char c = password.charAt(i);
+ if (c >= 'A' && c <= 'Z') {
+ letters++;
+ uppercase++;
+ } else if (c >= 'a' && c <= 'z') {
+ letters++;
+ lowercase++;
+ } else if (c >= '0' && c <= '9') {
+ numbers++;
+ nonletter++;
+ } else {
+ symbols++;
+ nonletter++;
+ }
+ }
+ int neededLetters = getPasswordMinimumLetters(null);
+ if(letters < neededLetters) {
+ Slog.w(TAG, "resetPassword: number of letters " + letters
+ + " does not meet required number of letters " + neededLetters);
+ return false;
+ }
+ int neededNumbers = getPasswordMinimumNumeric(null);
+ if (numbers < neededNumbers) {
+ Slog
+ .w(TAG, "resetPassword: number of numerical digits " + numbers
+ + " does not meet required number of numerical digits "
+ + neededNumbers);
+ return false;
+ }
+ int neededLowerCase = getPasswordMinimumLowerCase(null);
+ if (lowercase < neededLowerCase) {
+ Slog.w(TAG, "resetPassword: number of lowercase letters " + lowercase
+ + " does not meet required number of lowercase letters "
+ + neededLowerCase);
+ return false;
+ }
+ int neededUpperCase = getPasswordMinimumUpperCase(null);
+ if (uppercase < neededUpperCase) {
+ Slog.w(TAG, "resetPassword: number of uppercase letters " + uppercase
+ + " does not meet required number of uppercase letters "
+ + neededUpperCase);
+ return false;
+ }
+ int neededSymbols = getPasswordMinimumSymbols(null);
+ if (symbols < neededSymbols) {
+ Slog.w(TAG, "resetPassword: number of special symbols " + symbols
+ + " does not meet required number of special symbols " + neededSymbols);
+ return false;
+ }
+ int neededNonLetter = getPasswordMinimumNonLetter(null);
+ if (nonletter < neededNonLetter) {
+ Slog.w(TAG, "resetPassword: number of non-letter characters " + nonletter
+ + " does not meet required number of non-letter characters "
+ + neededNonLetter);
+ return false;
+ }
+ }
+
+ LockPatternUtils utils = new LockPatternUtils(mContext);
+ if(utils.checkPasswordHistory(password)) {
+ Slog.w(TAG, "resetPassword: password is the same as one of the last "
+ + getPasswordHistoryLength(null) + " passwords");
+ return false;
+ }
}
-
+
int callingUid = Binder.getCallingUid();
if (mPasswordOwner >= 0 && mPasswordOwner != callingUid) {
Slog.w(TAG, "resetPassword: already set by another uid and not entered by user");
return false;
}
-
+
// Don't do this with the lock held, because it is going to call
// back in to the service.
long ident = Binder.clearCallingIdentity();
@@ -783,10 +1217,10 @@
} finally {
Binder.restoreCallingIdentity(ident);
}
-
+
return true;
}
-
+
public void setMaximumTimeToLock(ComponentName who, long timeMs) {
synchronized (this) {
if (who == null) {
@@ -796,16 +1230,16 @@
DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
if (ap.maximumTimeToUnlock != timeMs) {
ap.maximumTimeToUnlock = timeMs;
-
+
long ident = Binder.clearCallingIdentity();
try {
saveSettingsLocked();
-
+
timeMs = getMaximumTimeToLock(null);
if (timeMs <= 0) {
timeMs = Integer.MAX_VALUE;
}
-
+
try {
getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
} catch (RemoteException e) {
@@ -817,16 +1251,16 @@
}
}
}
-
+
public long getMaximumTimeToLock(ComponentName who) {
synchronized (this) {
long time = 0;
-
+
if (who != null) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
return admin != null ? admin.maximumTimeToUnlock : time;
}
-
+
final int N = mAdminList.size();
for (int i=0; i<N; i++) {
ActiveAdmin admin = mAdminList.get(i);
@@ -840,7 +1274,7 @@
return time;
}
}
-
+
public void lockNow() {
synchronized (this) {
// This API can only be called by an active device admin,
@@ -857,7 +1291,7 @@
}
}
}
-
+
void wipeDataLocked(int flags) {
try {
RecoverySystem.rebootWipeUserData(mContext);
@@ -865,7 +1299,7 @@
Slog.w(TAG, "Failed requesting data wipe", e);
}
}
-
+
public void wipeData(int flags) {
synchronized (this) {
// This API can only be called by an active device admin,
@@ -880,11 +1314,11 @@
}
}
}
-
+
public void getRemoveWarning(ComponentName comp, final RemoteCallback result) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.BIND_DEVICE_ADMIN, null);
-
+
synchronized (this) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(comp);
if (admin == null) {
@@ -907,20 +1341,30 @@
}, null, Activity.RESULT_OK, null, null);
}
}
-
- public void setActivePasswordState(int quality, int length) {
+
+ public void setActivePasswordState(int quality, int length, int letters, int uppercase,
+ int lowercase, int numbers, int symbols, int nonletter) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.BIND_DEVICE_ADMIN, null);
-
+
validateQualityConstant(quality);
-
+
synchronized (this) {
if (mActivePasswordQuality != quality || mActivePasswordLength != length
- || mFailedPasswordAttempts != 0) {
+ || mFailedPasswordAttempts != 0 || mActivePasswordLetters != letters
+ || mActivePasswordUpperCase != uppercase
+ || mActivePasswordLowerCase != lowercase || mActivePasswordNumeric != numbers
+ || mActivePasswordSymbols != symbols || mActivePasswordNonLetter != nonletter) {
long ident = Binder.clearCallingIdentity();
try {
mActivePasswordQuality = quality;
mActivePasswordLength = length;
+ mActivePasswordLetters = letters;
+ mActivePasswordLowerCase = lowercase;
+ mActivePasswordUpperCase = uppercase;
+ mActivePasswordNumeric = numbers;
+ mActivePasswordSymbols = symbols;
+ mActivePasswordNonLetter = nonletter;
mFailedPasswordAttempts = 0;
saveSettingsLocked();
sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
@@ -931,11 +1375,11 @@
}
}
}
-
+
public void reportFailedPasswordAttempt() {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.BIND_DEVICE_ADMIN, null);
-
+
synchronized (this) {
long ident = Binder.clearCallingIdentity();
try {
@@ -952,11 +1396,11 @@
}
}
}
-
+
public void reportSuccessfulPasswordAttempt() {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.BIND_DEVICE_ADMIN, null);
-
+
synchronized (this) {
if (mFailedPasswordAttempts != 0 || mPasswordOwner >= 0) {
long ident = Binder.clearCallingIdentity();
@@ -972,7 +1416,7 @@
}
}
}
-
+
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
@@ -983,12 +1427,12 @@
+ ", uid=" + Binder.getCallingUid());
return;
}
-
+
final Printer p = new PrintWriterPrinter(pw);
-
+
synchronized (this) {
p.println("Current Device Policy Manager state:");
-
+
p.println(" Enabled Device Admins:");
final int N = mAdminList.size();
for (int i=0; i<N; i++) {
@@ -999,11 +1443,17 @@
ap.dump(" ", pw);
}
}
-
+
pw.println(" ");
pw.print(" mActivePasswordQuality=0x");
pw.println(Integer.toHexString(mActivePasswordQuality));
pw.print(" mActivePasswordLength="); pw.println(mActivePasswordLength);
+ pw.print(" mActivePasswordUpperCase="); pw.println(mActivePasswordUpperCase);
+ pw.print(" mActivePasswordLowerCase="); pw.println(mActivePasswordLowerCase);
+ pw.print(" mActivePasswordLetters="); pw.println(mActivePasswordLetters);
+ pw.print(" mActivePasswordNumeric="); pw.println(mActivePasswordNumeric);
+ pw.print(" mActivePasswordSymbols="); pw.println(mActivePasswordSymbols);
+ pw.print(" mActivePasswordNonLetter="); pw.println(mActivePasswordNonLetter);
pw.print(" mFailedPasswordAttempts="); pw.println(mFailedPasswordAttempts);
pw.print(" mPasswordOwner="); pw.println(mPasswordOwner);
}
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index a1f26f2..4b86135 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -469,8 +469,10 @@
mContext.getContentResolver(),
Settings.Secure.ENABLED_INPUT_METHODS);
Slog.i(TAG, "Enabled input methods: " + enabledStr);
- if (enabledStr == null) {
- Slog.i(TAG, "Enabled input methods has not been set, enabling all");
+ final String defaultIme = Settings.Secure.getString(mContext
+ .getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
+ if (enabledStr == null || TextUtils.isEmpty(defaultIme)) {
+ Slog.i(TAG, "Enabled input methods or default IME has not been set, enabling all");
InputMethodInfo defIm = null;
StringBuilder sb = new StringBuilder(256);
final int N = mMethodList.size();
@@ -1476,7 +1478,7 @@
String defaultIme = Settings.Secure.getString(mContext
.getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
- if (!map.containsKey(defaultIme)) {
+ if (!TextUtils.isEmpty(defaultIme) && !map.containsKey(defaultIme)) {
if (chooseNewDefaultIMELocked()) {
updateFromSettingsLocked();
}
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 8519e2c..b5e1659 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -465,10 +465,11 @@
mEnabledProviders.add(passiveProvider.getName());
// initialize external network location and geocoder services
+ PackageManager pm = mContext. getPackageManager();
Resources resources = mContext.getResources();
String serviceName = resources.getString(
com.android.internal.R.string.config_networkLocationProvider);
- if (serviceName != null) {
+ if (serviceName != null && pm.resolveService(new Intent(serviceName), 0) != null) {
mNetworkLocationProvider =
new LocationProviderProxy(mContext, LocationManager.NETWORK_PROVIDER,
serviceName, mLocationHandler);
@@ -476,7 +477,7 @@
}
serviceName = resources.getString(com.android.internal.R.string.config_geocodeProvider);
- if (serviceName != null) {
+ if (serviceName != null && pm.resolveService(new Intent(serviceName), 0) != null) {
mGeocodeProvider = new GeocoderProxy(mContext, serviceName);
}
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index b4fc15a..1fd053f 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -9551,7 +9551,8 @@
* Update media status on PackageManager.
*/
public void updateExternalMediaStatus(final boolean mediaStatus, final boolean reportStatus) {
- if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ int callingUid = Binder.getCallingUid();
+ if (callingUid != 0 && callingUid != Process.SYSTEM_UID) {
throw new SecurityException("Media status can only be updated by the system");
}
synchronized (mPackages) {
diff --git a/services/java/com/android/server/ThrottleService.java b/services/java/com/android/server/ThrottleService.java
index a93a6ee..2645e42 100644
--- a/services/java/com/android/server/ThrottleService.java
+++ b/services/java/com/android/server/ThrottleService.java
@@ -60,6 +60,8 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Calendar;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
import java.util.GregorianCalendar;
import java.util.Properties;
import java.util.Random;
@@ -83,8 +85,8 @@
private static final long TESTING_THRESHOLD = 1 * 1024 * 1024;
private int mPolicyPollPeriodSec;
- private long mPolicyThreshold;
- private int mPolicyThrottleValue;
+ private AtomicLong mPolicyThreshold;
+ private AtomicInteger mPolicyThrottleValue;
private int mPolicyResetDay; // 1-28
private int mPolicyNotificationsAllowedMask;
@@ -114,7 +116,7 @@
private InterfaceObserver mInterfaceObserver;
private SettingsObserver mSettingsObserver;
- private int mThrottleIndex; // 0 for none, 1 for first throttle val, 2 for next, etc
+ private AtomicInteger mThrottleIndex; // 0 for none, 1 for first throttle val, 2 for next, etc
private static final int THROTTLE_INDEX_UNINITIALIZED = -1;
private static final int THROTTLE_INDEX_UNTHROTTLED = 0;
@@ -126,6 +128,10 @@
if (VDBG) Slog.v(TAG, "Starting ThrottleService");
mContext = context;
+ mPolicyThreshold = new AtomicLong();
+ mPolicyThrottleValue = new AtomicInteger();
+ mThrottleIndex = new AtomicInteger();
+
mNtpActive = false;
mIface = mContext.getResources().getString(R.string.config_datause_iface);
@@ -214,7 +220,7 @@
}
private long ntpToWallTime(long ntpTime) {
- long bestNow = getBestTime();
+ long bestNow = getBestTime(true); // do it quickly
long localNow = System.currentTimeMillis();
return localNow + (ntpTime - bestNow);
}
@@ -222,40 +228,42 @@
// TODO - fetch for the iface
// return time in the local, system wall time, correcting for the use of ntp
- public synchronized long getResetTime(String iface) {
+ public long getResetTime(String iface) {
enforceAccessPermission();
long resetTime = 0;
if (mRecorder != null) {
- resetTime = ntpToWallTime(mRecorder.getPeriodEnd());
+ resetTime = mRecorder.getPeriodEnd();
}
+ resetTime = ntpToWallTime(resetTime);
return resetTime;
}
// TODO - fetch for the iface
// return time in the local, system wall time, correcting for the use of ntp
- public synchronized long getPeriodStartTime(String iface) {
- enforceAccessPermission();
+ public long getPeriodStartTime(String iface) {
long startTime = 0;
+ enforceAccessPermission();
if (mRecorder != null) {
- startTime = ntpToWallTime(mRecorder.getPeriodStart());
+ startTime = mRecorder.getPeriodStart();
}
+ startTime = ntpToWallTime(startTime);
return startTime;
}
//TODO - a better name? getCliffByteCountThreshold?
// TODO - fetch for the iface
- public synchronized long getCliffThreshold(String iface, int cliff) {
+ public long getCliffThreshold(String iface, int cliff) {
enforceAccessPermission();
if (cliff == 1) {
- return mPolicyThreshold;
+ return mPolicyThreshold.get();
}
return 0;
}
// TODO - a better name? getThrottleRate?
// TODO - fetch for the iface
- public synchronized int getCliffLevel(String iface, int cliff) {
+ public int getCliffLevel(String iface, int cliff) {
enforceAccessPermission();
if (cliff == 1) {
- return mPolicyThrottleValue;
+ return mPolicyThrottleValue.get();
}
return 0;
}
@@ -267,10 +275,9 @@
}
// TODO - fetch for the iface
- public synchronized long getByteCount(String iface, int dir, int period, int ago) {
+ public long getByteCount(String iface, int dir, int period, int ago) {
enforceAccessPermission();
- if ((period == ThrottleManager.PERIOD_CYCLE) &&
- (mRecorder != null)) {
+ if ((period == ThrottleManager.PERIOD_CYCLE) && (mRecorder != null)) {
if (dir == ThrottleManager.DIRECTION_TX) return mRecorder.getPeriodTx(ago);
if (dir == ThrottleManager.DIRECTION_RX) return mRecorder.getPeriodRx(ago);
}
@@ -279,10 +286,10 @@
// TODO - a better name - getCurrentThrottleRate?
// TODO - fetch for the iface
- public synchronized int getThrottle(String iface) {
+ public int getThrottle(String iface) {
enforceAccessPermission();
- if (mThrottleIndex == 1) {
- return mPolicyThrottleValue;
+ if (mThrottleIndex.get() == 1) {
+ return mPolicyThrottleValue.get();
}
return 0;
}
@@ -375,7 +382,7 @@
// check for sim change TODO
// reregister for notification of policy change
- mThrottleIndex = THROTTLE_INDEX_UNINITIALIZED;
+ mThrottleIndex.set(THROTTLE_INDEX_UNINITIALIZED);
mRecorder = new DataRecorder(mContext, ThrottleService.this);
@@ -403,15 +410,16 @@
R.integer.config_datause_threshold_bytes);
int defaultValue = mContext.getResources().getInteger(
R.integer.config_datause_throttle_kbitsps);
- synchronized (ThrottleService.this) {
- mPolicyThreshold = Settings.Secure.getLong(mContext.getContentResolver(),
- Settings.Secure.THROTTLE_THRESHOLD_BYTES, defaultThreshold);
- mPolicyThrottleValue = Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.THROTTLE_VALUE_KBITSPS, defaultValue);
- if (testing) {
- mPolicyPollPeriodSec = TESTING_POLLING_PERIOD_SEC;
- mPolicyThreshold = TESTING_THRESHOLD;
- }
+ long threshold = Settings.Secure.getLong(mContext.getContentResolver(),
+ Settings.Secure.THROTTLE_THRESHOLD_BYTES, defaultThreshold);
+ int value = Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.THROTTLE_VALUE_KBITSPS, defaultValue);
+
+ mPolicyThreshold.set(threshold);
+ mPolicyThrottleValue.set(value);
+ if (testing) {
+ mPolicyPollPeriodSec = TESTING_POLLING_PERIOD_SEC;
+ mPolicyThreshold.set(TESTING_THRESHOLD);
}
mPolicyResetDay = Settings.Secure.getInt(mContext.getContentResolver(),
@@ -423,10 +431,8 @@
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.THROTTLE_RESET_DAY, mPolicyResetDay);
}
- synchronized (ThrottleService.this) {
- if (mIface == null) {
- mPolicyThreshold = 0;
- }
+ if (mIface == null) {
+ mPolicyThreshold.set(0);
}
int defaultNotificationType = mContext.getResources().getInteger(
@@ -437,15 +443,16 @@
mMaxNtpCacheAgeSec = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.THROTTLE_MAX_NTP_CACHE_AGE_SEC, MAX_NTP_CACHE_AGE_SEC);
- if (VDBG || (mPolicyThreshold != 0)) {
+ if (VDBG || (mPolicyThreshold.get() != 0)) {
Slog.d(TAG, "onPolicyChanged testing=" + testing +", period=" +
- mPolicyPollPeriodSec + ", threshold=" + mPolicyThreshold + ", value=" +
- mPolicyThrottleValue + ", resetDay=" + mPolicyResetDay + ", noteType=" +
- mPolicyNotificationsAllowedMask + ", maxNtpCacheAge=" + mMaxNtpCacheAgeSec);
+ mPolicyPollPeriodSec + ", threshold=" + mPolicyThreshold.get() +
+ ", value=" + mPolicyThrottleValue.get() + ", resetDay=" + mPolicyResetDay +
+ ", noteType=" + mPolicyNotificationsAllowedMask + ", maxNtpCacheAge=" +
+ mMaxNtpCacheAgeSec);
}
// force updates
- mThrottleIndex = THROTTLE_INDEX_UNINITIALIZED;
+ mThrottleIndex.set(THROTTLE_INDEX_UNINITIALIZED);
onResetAlarm();
@@ -487,7 +494,7 @@
long periodRx = mRecorder.getPeriodRx(0);
long periodTx = mRecorder.getPeriodTx(0);
long total = periodRx + periodTx;
- if (VDBG || (mPolicyThreshold != 0)) {
+ if (VDBG || (mPolicyThreshold.get() != 0)) {
Slog.d(TAG, "onPollAlarm - roaming =" + roaming +
", read =" + incRead + ", written =" + incWrite + ", new total =" + total);
}
@@ -510,11 +517,11 @@
private void onIfaceUp() {
// if we were throttled before, be sure and set it again - the iface went down
// (and may have disappeared all together) and these settings were lost
- if (mThrottleIndex == 1) {
+ if (mThrottleIndex.get() == 1) {
try {
mNMService.setInterfaceThrottle(mIface, -1, -1);
mNMService.setInterfaceThrottle(mIface,
- mPolicyThrottleValue, mPolicyThrottleValue);
+ mPolicyThrottleValue.get(), mPolicyThrottleValue.get());
} catch (Exception e) {
Slog.e(TAG, "error setting Throttle: " + e);
}
@@ -523,7 +530,8 @@
private void checkThrottleAndPostNotification(long currentTotal) {
// is throttling enabled?
- if (mPolicyThreshold == 0) {
+ long threshold = mPolicyThreshold.get();
+ if (threshold == 0) {
clearThrottleAndNotification();
return;
}
@@ -535,15 +543,13 @@
}
// check if we need to throttle
- if (currentTotal > mPolicyThreshold) {
- if (mThrottleIndex != 1) {
- synchronized (ThrottleService.this) {
- mThrottleIndex = 1;
- }
- if (DBG) Slog.d(TAG, "Threshold " + mPolicyThreshold + " exceeded!");
+ if (currentTotal > threshold) {
+ if (mThrottleIndex.get() != 1) {
+ mThrottleIndex.set(1);
+ if (DBG) Slog.d(TAG, "Threshold " + threshold + " exceeded!");
try {
mNMService.setInterfaceThrottle(mIface,
- mPolicyThrottleValue, mPolicyThrottleValue);
+ mPolicyThrottleValue.get(), mPolicyThrottleValue.get());
} catch (Exception e) {
Slog.e(TAG, "error setting Throttle: " + e);
}
@@ -556,7 +562,8 @@
Notification.FLAG_ONGOING_EVENT);
Intent broadcast = new Intent(ThrottleManager.THROTTLE_ACTION);
- broadcast.putExtra(ThrottleManager.EXTRA_THROTTLE_LEVEL, mPolicyThrottleValue);
+ broadcast.putExtra(ThrottleManager.EXTRA_THROTTLE_LEVEL,
+ mPolicyThrottleValue.get());
mContext.sendStickyBroadcast(broadcast);
} // else already up!
@@ -579,8 +586,8 @@
long periodLength = end - start;
long now = System.currentTimeMillis();
long timeUsed = now - start;
- long warningThreshold = 2*mPolicyThreshold*timeUsed/(timeUsed+periodLength);
- if ((currentTotal > warningThreshold) && (currentTotal > mPolicyThreshold/4)) {
+ long warningThreshold = 2*threshold*timeUsed/(timeUsed+periodLength);
+ if ((currentTotal > warningThreshold) && (currentTotal > threshold/4)) {
if (mWarningNotificationSent == false) {
mWarningNotificationSent = true;
mNotificationManager.cancel(R.drawable.stat_sys_throttled);
@@ -625,11 +632,9 @@
}
- private synchronized void clearThrottleAndNotification() {
- if (mThrottleIndex != THROTTLE_INDEX_UNTHROTTLED) {
- synchronized (ThrottleService.this) {
- mThrottleIndex = THROTTLE_INDEX_UNTHROTTLED;
- }
+ private void clearThrottleAndNotification() {
+ if (mThrottleIndex.get() != THROTTLE_INDEX_UNTHROTTLED) {
+ mThrottleIndex.set(THROTTLE_INDEX_UNTHROTTLED);
try {
mNMService.setInterfaceThrottle(mIface, -1, -1);
} catch (Exception e) {
@@ -687,12 +692,12 @@
}
private void onResetAlarm() {
- if (VDBG || (mPolicyThreshold != 0)) {
+ if (VDBG || (mPolicyThreshold.get() != 0)) {
Slog.d(TAG, "onResetAlarm - last period had " + mRecorder.getPeriodRx(0) +
" bytes read and " + mRecorder.getPeriodTx(0) + " written");
}
- long now = getBestTime();
+ long now = getBestTime(false);
if (mNtpActive || (mNtpServer == null)) {
Calendar end = calculatePeriodEnd(now);
@@ -719,20 +724,23 @@
// will try to get the ntp time and switch to it if found.
// will also cache the time so we don't fetch it repeatedly.
- getBestTime();
+ getBestTime(false);
}
private static final int MAX_NTP_CACHE_AGE_SEC = 60 * 60 * 24; // 1 day
- private static final int MAX_NTP_FETCH_WAIT = 10 * 1000;
+ private static final int MAX_NTP_FETCH_WAIT = 20 * 1000;
private int mMaxNtpCacheAgeSec = MAX_NTP_CACHE_AGE_SEC;
private long cachedNtp;
private long cachedNtpTimestamp;
- private long getBestTime() {
+ // if the request is tied to UI and ANR's are a danger, request a fast result
+ // the regular polling should have updated the cached time recently using the
+ // slower method (!fast)
+ private long getBestTime(boolean fast) {
if (mNtpServer != null) {
if (mNtpActive) {
long ntpAge = SystemClock.elapsedRealtime() - cachedNtpTimestamp;
- if (ntpAge < mMaxNtpCacheAgeSec * 1000) {
+ if (ntpAge < mMaxNtpCacheAgeSec * 1000 || fast) {
if (VDBG) Slog.v(TAG, "using cached time");
return cachedNtp + ntpAge;
}
@@ -1025,39 +1033,57 @@
if (DBG) Slog.d(TAG, "data file empty");
return;
}
- synchronized (mParent) {
- String[] parsed = data.split(":");
- int parsedUsed = 0;
- if (parsed.length < 6) {
- Slog.e(TAG, "reading data file with insufficient length - ignoring");
- return;
- }
+ String[] parsed = data.split(":");
+ int parsedUsed = 0;
+ if (parsed.length < 6) {
+ Slog.e(TAG, "reading data file with insufficient length - ignoring");
+ return;
+ }
+ int periodCount;
+ long[] periodRxData;
+ long[] periodTxData;
+ int currentPeriod;
+ Calendar periodStart;
+ Calendar periodEnd;
+ try {
if (Integer.parseInt(parsed[parsedUsed++]) != DATA_FILE_VERSION) {
Slog.e(TAG, "reading data file with bad version - ignoring");
return;
}
- mPeriodCount = Integer.parseInt(parsed[parsedUsed++]);
- if (parsed.length != 5 + (2 * mPeriodCount)) {
+ periodCount = Integer.parseInt(parsed[parsedUsed++]);
+ if (parsed.length != 5 + (2 * periodCount)) {
Slog.e(TAG, "reading data file with bad length (" + parsed.length +
- " != " + (5+(2*mPeriodCount)) + ") - ignoring");
+ " != " + (5 + (2 * periodCount)) + ") - ignoring");
return;
}
+ periodRxData = new long[periodCount];
+ for (int i = 0; i < periodCount; i++) {
+ periodRxData[i] = Long.parseLong(parsed[parsedUsed++]);
+ }
+ periodTxData = new long[periodCount];
+ for (int i = 0; i < periodCount; i++) {
+ periodTxData[i] = Long.parseLong(parsed[parsedUsed++]);
+ }
- mPeriodRxData = new long[mPeriodCount];
- for(int i = 0; i < mPeriodCount; i++) {
- mPeriodRxData[i] = Long.parseLong(parsed[parsedUsed++]);
- }
- mPeriodTxData = new long[mPeriodCount];
- for(int i = 0; i < mPeriodCount; i++) {
- mPeriodTxData[i] = Long.parseLong(parsed[parsedUsed++]);
- }
- mCurrentPeriod = Integer.parseInt(parsed[parsedUsed++]);
- mPeriodStart = new GregorianCalendar();
- mPeriodStart.setTimeInMillis(Long.parseLong(parsed[parsedUsed++]));
- mPeriodEnd = new GregorianCalendar();
- mPeriodEnd.setTimeInMillis(Long.parseLong(parsed[parsedUsed++]));
+ currentPeriod = Integer.parseInt(parsed[parsedUsed++]);
+
+ periodStart = new GregorianCalendar();
+ periodStart.setTimeInMillis(Long.parseLong(parsed[parsedUsed++]));
+ periodEnd = new GregorianCalendar();
+ periodEnd.setTimeInMillis(Long.parseLong(parsed[parsedUsed++]));
+ } catch (Exception e) {
+ Slog.e(TAG, "Error parsing data file - ignoring");
+ return;
+ }
+ synchronized (mParent) {
+ mPeriodCount = periodCount;
+ mPeriodRxData = periodRxData;
+ mPeriodTxData = periodTxData;
+ mCurrentPeriod = currentPeriod;
+ mPeriodStart = periodStart;
+ mPeriodEnd = periodEnd;
}
}
@@ -1091,15 +1117,15 @@
}
pw.println();
- pw.println("The threshold is " + mPolicyThreshold +
+ pw.println("The threshold is " + mPolicyThreshold.get() +
", after which you experince throttling to " +
- mPolicyThrottleValue + "kbps");
+ mPolicyThrottleValue.get() + "kbps");
pw.println("Current period is " +
(mRecorder.getPeriodEnd() - mRecorder.getPeriodStart())/1000 + " seconds long " +
"and ends in " + (getResetTime(mIface) - System.currentTimeMillis()) / 1000 +
" seconds.");
pw.println("Polling every " + mPolicyPollPeriodSec + " seconds");
- pw.println("Current Throttle Index is " + mThrottleIndex);
+ pw.println("Current Throttle Index is " + mThrottleIndex.get());
pw.println("Max NTP Cache Age is " + mMaxNtpCacheAgeSec);
for (int i = 0; i < mRecorder.getPeriodCount(); i++) {
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index ac5e3f1..97d0f9b 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -153,7 +153,6 @@
static final boolean DEBUG_STARTING_WINDOW = false;
static final boolean DEBUG_REORDER = false;
static final boolean DEBUG_WALLPAPER = false;
- static final boolean DEBUG_FREEZE = false;
static final boolean SHOW_TRANSACTIONS = false;
static final boolean HIDE_STACK_CRAWLS = true;
static final boolean MEASURE_LATENCY = false;
@@ -4468,8 +4467,7 @@
final int N = mWindows.size();
for (int i=0; i<N; i++) {
WindowState w = (WindowState)mWindows.get(i);
- if (w.isVisibleLw() && !w.mObscured
- && (w.mOrientationChanging || !w.isDrawnLw())) {
+ if (w.isVisibleLw() && !w.mObscured && !w.isDrawnLw()) {
return;
}
}
@@ -5236,19 +5234,24 @@
WindowState out = mKeyWaiter.mOutsideTouchTargets;
if (out != null) {
MotionEvent oev = MotionEvent.obtain(ev);
- oev.setAction(MotionEvent.ACTION_OUTSIDE);
- do {
- final Rect frame = out.mFrame;
- oev.offsetLocation(-(float)frame.left, -(float)frame.top);
- try {
- out.mClient.dispatchPointer(oev, eventTime, false);
- } catch (android.os.RemoteException e) {
- Slog.i(TAG, "WINDOW DIED during outside motion dispatch: " + out);
- }
- oev.offsetLocation((float)frame.left, (float)frame.top);
- out = out.mNextOutsideTouch;
- } while (out != null);
- mKeyWaiter.mOutsideTouchTargets = null;
+ try {
+ oev.setAction(MotionEvent.ACTION_OUTSIDE);
+ do {
+ final Rect frame = out.mFrame;
+ oev.offsetLocation(-(float)frame.left, -(float)frame.top);
+ try {
+ out.mClient.dispatchPointer(oev, eventTime, false);
+ } catch (android.os.RemoteException e) {
+ Slog.i(TAG,
+ "WINDOW DIED during outside motion dispatch: " + out);
+ }
+ oev.offsetLocation((float)frame.left, (float)frame.top);
+ out = out.mNextOutsideTouch;
+ } while (out != null);
+ mKeyWaiter.mOutsideTouchTargets = null;
+ } finally {
+ oev.recycle();
+ }
}
}
@@ -7999,7 +8002,7 @@
final AppWindowToken atoken = mAppToken;
return mSurface != null && !mAttachedHidden
&& (atoken == null ? mPolicyVisibility : !atoken.hiddenRequested)
- && (mOrientationChanging || (!mDrawPending && !mCommitDrawPending))
+ && !mDrawPending && !mCommitDrawPending
&& !mExiting && !mDestroying;
}
@@ -8103,14 +8106,12 @@
/**
* Returns true if the window has a surface that it has drawn a
- * complete UI in to. Note that this returns true if the orientation
- * is changing even if the window hasn't redrawn because we don't want
- * to stop things from executing during that time.
+ * complete UI in to.
*/
public boolean isDrawnLw() {
final AppWindowToken atoken = mAppToken;
return mSurface != null && !mDestroying
- && (mOrientationChanging || (!mDrawPending && !mCommitDrawPending));
+ && !mDrawPending && !mCommitDrawPending;
}
public boolean fillsScreenLw(int screenWidth, int screenHeight,
@@ -10368,12 +10369,6 @@
if (w.mAttachedHidden || !w.isReadyForDisplay()) {
if (!w.mLastHidden) {
//dump();
- if (DEBUG_CONFIGURATION) Slog.v(TAG, "Window hiding: waitingToShow="
- + w.mRootToken.waitingToShow + " polvis="
- + w.mPolicyVisibility + " atthid="
- + w.mAttachedHidden + " tokhid="
- + w.mRootToken.hidden + " vis="
- + w.mViewVisibility);
w.mLastHidden = true;
if (SHOW_TRANSACTIONS) logSurface(w,
"HIDE (performLayout)", null);
@@ -10769,28 +10764,23 @@
} else if (animating) {
requestAnimationLocked(currentTime+(1000/60)-SystemClock.uptimeMillis());
}
-
- if (DEBUG_FREEZE) Slog.v(TAG, "Layout: mDisplayFrozen=" + mDisplayFrozen
- + " holdScreen=" + holdScreen);
- if (!mDisplayFrozen) {
- mQueue.setHoldScreenLocked(holdScreen != null);
- if (screenBrightness < 0 || screenBrightness > 1.0f) {
- mPowerManager.setScreenBrightnessOverride(-1);
- } else {
- mPowerManager.setScreenBrightnessOverride((int)
- (screenBrightness * Power.BRIGHTNESS_ON));
- }
- if (buttonBrightness < 0 || buttonBrightness > 1.0f) {
- mPowerManager.setButtonBrightnessOverride(-1);
- } else {
- mPowerManager.setButtonBrightnessOverride((int)
- (buttonBrightness * Power.BRIGHTNESS_ON));
- }
- if (holdScreen != mHoldingScreenOn) {
- mHoldingScreenOn = holdScreen;
- Message m = mH.obtainMessage(H.HOLD_SCREEN_CHANGED, holdScreen);
- mH.sendMessage(m);
- }
+ mQueue.setHoldScreenLocked(holdScreen != null);
+ if (screenBrightness < 0 || screenBrightness > 1.0f) {
+ mPowerManager.setScreenBrightnessOverride(-1);
+ } else {
+ mPowerManager.setScreenBrightnessOverride((int)
+ (screenBrightness * Power.BRIGHTNESS_ON));
+ }
+ if (buttonBrightness < 0 || buttonBrightness > 1.0f) {
+ mPowerManager.setButtonBrightnessOverride(-1);
+ } else {
+ mPowerManager.setButtonBrightnessOverride((int)
+ (buttonBrightness * Power.BRIGHTNESS_ON));
+ }
+ if (holdScreen != mHoldingScreenOn) {
+ mHoldingScreenOn = holdScreen;
+ Message m = mH.obtainMessage(H.HOLD_SCREEN_CHANGED, holdScreen);
+ mH.sendMessage(m);
}
if (mTurnOnScreen) {
@@ -11067,8 +11057,6 @@
mFreezeGcPending = now;
}
- if (DEBUG_FREEZE) Slog.v(TAG, "*** FREEZING DISPLAY", new RuntimeException());
-
mDisplayFrozen = true;
if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET;
@@ -11092,8 +11080,6 @@
return;
}
- if (DEBUG_FREEZE) Slog.v(TAG, "*** UNFREEZING DISPLAY", new RuntimeException());
-
mDisplayFrozen = false;
mH.removeMessages(H.APP_FREEZE_TIMEOUT);
if (PROFILE_ORIENTATION) {
diff --git a/services/jni/com_android_server_location_GpsLocationProvider.cpp b/services/jni/com_android_server_location_GpsLocationProvider.cpp
index afd6ca8..28cefd4 100755
--- a/services/jni/com_android_server_location_GpsLocationProvider.cpp
+++ b/services/jni/com_android_server_location_GpsLocationProvider.cpp
@@ -276,9 +276,9 @@
sAGpsInterface->init(&sAGpsCallbacks);
if (!sGpsNiInterface)
- sGpsNiInterface = (const GpsNiInterface*)sGpsInterface->get_extension(GPS_NI_INTERFACE);
+ sGpsNiInterface = (const GpsNiInterface*)sGpsInterface->get_extension(GPS_NI_INTERFACE);
if (sGpsNiInterface)
- sGpsNiInterface->init(&sGpsNiCallbacks);
+ sGpsNiInterface->init(&sGpsNiCallbacks);
if (!sGpsDebugInterface)
sGpsDebugInterface = (const GpsDebugInterface*)sGpsInterface->get_extension(GPS_DEBUG_INTERFACE);
@@ -533,12 +533,10 @@
static void android_location_GpsLocationProvider_send_ni_response(JNIEnv* env, jobject obj,
jint notifId, jint response)
{
- if (!sGpsNiInterface) {
+ if (!sGpsNiInterface)
sGpsNiInterface = (const GpsNiInterface*)sGpsInterface->get_extension(GPS_NI_INTERFACE);
- }
- if (sGpsNiInterface) {
+ if (sGpsNiInterface)
sGpsNiInterface->respond(notifId, response);
- }
}
static jstring android_location_GpsLocationProvider_get_internal_state(JNIEnv* env, jobject obj)
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index b07a10b..186b349 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -7,8 +7,10 @@
# Include all test java files.
LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_STATIC_JAVA_LIBRARIES := easymocklib
LOCAL_JAVA_LIBRARIES := android.test.runner services
+
LOCAL_PACKAGE_NAME := FrameworksServicesTests
LOCAL_CERTIFICATE := platform
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 5ce109f..f115f42 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -23,6 +23,19 @@
<application>
<uses-library android:name="android.test.runner" />
+
+ <service android:name="com.android.server.AccessibilityManagerServiceTest$MyFirstMockAccessibilityService">
+ <intent-filter>
+ <action android:name="android.accessibilityservice.AccessibilityService"/>
+ </intent-filter>
+ </service>
+
+ <service android:name="com.android.server.AccessibilityManagerServiceTest$MySecondMockAccessibilityService">
+ <intent-filter>
+ <action android:name="android.accessibilityservice.AccessibilityService"/>
+ </intent-filter>
+ </service>
+
</application>
<instrumentation
diff --git a/services/tests/servicestests/src/com/android/server/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/AccessibilityManagerServiceTest.java
new file mode 100644
index 0000000..f6e3a82
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/AccessibilityManagerServiceTest.java
@@ -0,0 +1,729 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.accessibilityservice.AccessibilityService;
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ServiceInfo;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.provider.Settings;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.IAccessibilityManager;
+import android.view.accessibility.IAccessibilityManagerClient;
+
+/**
+ * This test exercises the
+ * {@link com.android.server.AccessibilityManagerService} by mocking the
+ * {@link android.view.accessibility.AccessibilityManager} which talks to to the
+ * service. The service itself is interacting with the platform. Note: Testing
+ * the service in full isolation would require significant amount of work for
+ * mocking all system interactions. It would also require a lot of mocking code.
+ */
+public class AccessibilityManagerServiceTest extends AndroidTestCase {
+
+ /**
+ * Timeout required for pending Binder calls or event processing to
+ * complete.
+ */
+ private static final long TIMEOUT_BINDER_CALL = 100;
+
+ /**
+ * Timeout in which we are waiting for the system to start the mock
+ * accessibility services.
+ */
+ private static final long TIMEOUT_START_MOCK_ACCESSIBILITY_SERVICES = 300;
+
+ /**
+ * Timeout used for testing that a service is notified only upon a
+ * notification timeout.
+ */
+ private static final long TIMEOUT_TEST_NOTIFICATION_TIMEOUT = 300;
+
+ /**
+ * The package name.
+ */
+ private static String sPackageName;
+
+ /**
+ * The interface used to talk to the tested service.
+ */
+ private IAccessibilityManager mManagerService;
+
+ @Override
+ public void setContext(Context context) {
+ super.setContext(context);
+ if (sPackageName == null) {
+ sPackageName = context.getPackageName();
+ }
+ }
+
+ /**
+ * Creates a new instance.
+ */
+ public AccessibilityManagerServiceTest() {
+ IBinder iBinder = ServiceManager.getService(Context.ACCESSIBILITY_SERVICE);
+ mManagerService = IAccessibilityManager.Stub.asInterface(iBinder);
+ }
+
+ @LargeTest
+ public void testAddClient_AccessibilityDisabledThenEnabled() throws Exception {
+ // make sure accessibility is disabled
+ ensureAccessibilityEnabled(mContext, false);
+
+ // create a client mock instance
+ MyMockAccessibilityManagerClient mockClient = new MyMockAccessibilityManagerClient();
+
+ // invoke the method under test
+ boolean enabledAccessibilityDisabled = mManagerService.addClient(mockClient);
+
+ // check expected result
+ assertFalse("The client must be disabled since accessibility is disabled.",
+ enabledAccessibilityDisabled);
+
+ // enable accessibility
+ ensureAccessibilityEnabled(mContext, true);
+
+ // invoke the method under test
+ boolean enabledAccessibilityEnabled = mManagerService.addClient(mockClient);
+
+ // check expected result
+ assertTrue("The client must be enabled since accessibility is enabled.",
+ enabledAccessibilityEnabled);
+ }
+
+ @LargeTest
+ public void testAddClient_AccessibilityEnabledThenDisabled() throws Exception {
+ // enable accessibility before registering the client
+ ensureAccessibilityEnabled(mContext, true);
+
+ // create a client mock instance
+ MyMockAccessibilityManagerClient mockClient = new MyMockAccessibilityManagerClient();
+
+ // invoke the method under test
+ boolean enabledAccessibilityEnabled = mManagerService.addClient(mockClient);
+
+ // check expected result
+ assertTrue("The client must be enabled since accessibility is enabled.",
+ enabledAccessibilityEnabled);
+
+ // disable accessibility
+ ensureAccessibilityEnabled(mContext, false);
+
+ // invoke the method under test
+ boolean enabledAccessibilityDisabled = mManagerService.addClient(mockClient);
+
+ // check expected result
+ assertFalse("The client must be disabled since accessibility is disabled.",
+ enabledAccessibilityDisabled);
+ }
+
+ @LargeTest
+ public void testGetAccessibilityServicesList() throws Exception {
+ boolean firstMockServiceInstalled = false;
+ boolean secondMockServiceInstalled = false;
+
+ String packageName = getContext().getPackageName();
+ String firstMockServiceClassName = MyFirstMockAccessibilityService.class.getName();
+ String secondMockServiceClassName = MySecondMockAccessibilityService.class.getName();
+
+ // look for the two mock services
+ for (ServiceInfo serviceInfo : mManagerService.getAccessibilityServiceList()) {
+ if (packageName.equals(serviceInfo.packageName)) {
+ if (firstMockServiceClassName.equals(serviceInfo.name)) {
+ firstMockServiceInstalled = true;
+ } else if (secondMockServiceClassName.equals(serviceInfo.name)) {
+ secondMockServiceInstalled = true;
+ }
+ }
+ }
+
+ // check expected result
+ assertTrue("First mock service must be installed", firstMockServiceInstalled);
+ assertTrue("Second mock service must be installed", secondMockServiceInstalled);
+ }
+
+ @LargeTest
+ public void testSendAccessibilityEvent_OneService_MatchingPackageAndEventType()
+ throws Exception {
+ // set the accessibility setting value
+ ensureAccessibilityEnabled(mContext, true);
+
+ // enable the mock accessibility service
+ ensureOnlyMockServicesEnabled(mContext, true, false);
+
+ // configure the mock service
+ MockAccessibilityService service = MyFirstMockAccessibilityService.sInstance;
+ service.setServiceInfo(MockAccessibilityService.createDefaultInfo());
+
+ // wait for the binder call to #setService to complete
+ Thread.sleep(TIMEOUT_BINDER_CALL);
+
+ // create and populate an event to be sent
+ AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
+ fullyPopulateDefaultAccessibilityEvent(sentEvent);
+
+ // set expectations
+ service.expectEvent(sentEvent);
+ service.replay();
+
+ // send the event
+ mManagerService.sendAccessibilityEvent(sentEvent);
+
+ // verify if all expected methods have been called
+ assertMockServiceVerifiedWithinTimeout(service);
+ }
+
+ @LargeTest
+ public void testSendAccessibilityEvent_OneService_NotMatchingPackage() throws Exception {
+ // set the accessibility setting value
+ ensureAccessibilityEnabled(mContext, true);
+
+ // enable the mock accessibility service
+ ensureOnlyMockServicesEnabled(mContext, true, false);
+
+ // configure the mock service
+ MockAccessibilityService service = MyFirstMockAccessibilityService.sInstance;
+ service.setServiceInfo(MockAccessibilityService.createDefaultInfo());
+
+ // wait for the binder call to #setService to complete
+ Thread.sleep(TIMEOUT_BINDER_CALL);
+
+ // create and populate an event to be sent
+ AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
+ fullyPopulateDefaultAccessibilityEvent(sentEvent);
+ sentEvent.setPackageName("no.service.registered.for.this.package");
+
+ // set expectations
+ service.replay();
+
+ // send the event
+ mManagerService.sendAccessibilityEvent(sentEvent);
+
+ // verify if all expected methods have been called
+ assertMockServiceVerifiedWithinTimeout(service);
+ }
+
+ @LargeTest
+ public void testSendAccessibilityEvent_OneService_NotMatchingEventType() throws Exception {
+ // set the accessibility setting value
+ ensureAccessibilityEnabled(mContext, true);
+
+ // enable the mock accessibility service
+ ensureOnlyMockServicesEnabled(mContext, true, false);
+
+ // configure the mock service
+ MockAccessibilityService service = MyFirstMockAccessibilityService.sInstance;
+ service.setServiceInfo(MockAccessibilityService.createDefaultInfo());
+
+ // wait for the binder call to #setService to complete
+ Thread.sleep(TIMEOUT_BINDER_CALL);
+
+ // create and populate an event to be sent
+ AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
+ fullyPopulateDefaultAccessibilityEvent(sentEvent);
+ sentEvent.setEventType(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
+
+ // set expectations
+ service.replay();
+
+ // send the event
+ mManagerService.sendAccessibilityEvent(sentEvent);
+
+ // verify if all expected methods have been called
+ assertMockServiceVerifiedWithinTimeout(service);
+ }
+
+ @LargeTest
+ public void testSendAccessibilityEvent_OneService_NotifivationAfterTimeout() throws Exception {
+ // set the accessibility setting value
+ ensureAccessibilityEnabled(mContext, true);
+
+ // enable the mock accessibility service
+ ensureOnlyMockServicesEnabled(mContext, true, false);
+
+ // configure the mock service
+ MockAccessibilityService service = MyFirstMockAccessibilityService.sInstance;
+ AccessibilityServiceInfo info = MockAccessibilityService.createDefaultInfo();
+ info.notificationTimeout = TIMEOUT_TEST_NOTIFICATION_TIMEOUT;
+ service.setServiceInfo(info);
+
+ // wait for the binder call to #setService to complete
+ Thread.sleep(TIMEOUT_BINDER_CALL);
+
+ // create and populate the first event to be sent
+ AccessibilityEvent firstEvent = AccessibilityEvent.obtain();
+ fullyPopulateDefaultAccessibilityEvent(firstEvent);
+
+ // create and populate the second event to be sent
+ AccessibilityEvent secondEvent = AccessibilityEvent.obtain();
+ fullyPopulateDefaultAccessibilityEvent(secondEvent);
+
+ // set expectations
+ service.expectEvent(secondEvent);
+ service.replay();
+
+ // send the events
+ mManagerService.sendAccessibilityEvent(firstEvent);
+ mManagerService.sendAccessibilityEvent(secondEvent);
+
+ // wait for #sendAccessibilityEvent to reach the backing service
+ Thread.sleep(TIMEOUT_BINDER_CALL);
+
+ try {
+ service.verify();
+ fail("No events must be dispatched before the expiration of the notification timeout.");
+ } catch (IllegalStateException ise) {
+ /* expected */
+ }
+
+ // wait for the configured notification timeout to expire
+ Thread.sleep(TIMEOUT_TEST_NOTIFICATION_TIMEOUT);
+
+ // verify if all expected methods have been called
+ assertMockServiceVerifiedWithinTimeout(service);
+ }
+
+ @LargeTest
+ public void testSendAccessibilityEvent_TwoServices_MatchingPackageAndEventType_DiffFeedback()
+ throws Exception {
+ // set the accessibility setting value
+ ensureAccessibilityEnabled(mContext, true);
+
+ // enable the mock accessibility services
+ ensureOnlyMockServicesEnabled(mContext, true, true);
+
+ // configure the first mock service
+ MockAccessibilityService firstService = MyFirstMockAccessibilityService.sInstance;
+ AccessibilityServiceInfo firstInfo = MockAccessibilityService.createDefaultInfo();
+ firstInfo.feedbackType = AccessibilityServiceInfo.FEEDBACK_AUDIBLE;
+ firstService.setServiceInfo(firstInfo);
+
+ // configure the second mock service
+ MockAccessibilityService secondService = MySecondMockAccessibilityService.sInstance;
+ AccessibilityServiceInfo secondInfo = MockAccessibilityService.createDefaultInfo();
+ secondInfo.feedbackType = AccessibilityServiceInfo.FEEDBACK_HAPTIC;
+ secondService.setServiceInfo(secondInfo);
+
+ // wait for the binder calls to #setService to complete
+ Thread.sleep(TIMEOUT_BINDER_CALL);
+
+ // create and populate an event to be sent
+ AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
+ fullyPopulateDefaultAccessibilityEvent(sentEvent);
+
+ // set expectations for the first mock service
+ firstService.expectEvent(sentEvent);
+ firstService.replay();
+
+ // set expectations for the second mock service
+ secondService.expectEvent(sentEvent);
+ secondService.replay();
+
+ // send the event
+ mManagerService.sendAccessibilityEvent(sentEvent);
+
+ // verify if all expected methods have been called
+ assertMockServiceVerifiedWithinTimeout(firstService);
+ assertMockServiceVerifiedWithinTimeout(secondService);
+ }
+
+ @LargeTest
+ public void testSendAccessibilityEvent_TwoServices_MatchingPackageAndEventType()
+ throws Exception {
+ // set the accessibility setting value
+ ensureAccessibilityEnabled(mContext, true);
+
+ // enable the mock accessibility services
+ ensureOnlyMockServicesEnabled(mContext, true, true);
+
+ // configure the first mock service
+ MockAccessibilityService firstService = MyFirstMockAccessibilityService.sInstance;
+ firstService.setServiceInfo(MockAccessibilityService.createDefaultInfo());
+
+ // configure the second mock service
+ MockAccessibilityService secondService = MySecondMockAccessibilityService.sInstance;
+ secondService.setServiceInfo(MockAccessibilityService.createDefaultInfo());
+
+ // wait for the binder calls to #setService to complete
+ Thread.sleep(TIMEOUT_BINDER_CALL);
+
+ // create and populate an event to be sent
+ AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
+ fullyPopulateDefaultAccessibilityEvent(sentEvent);
+
+ // set expectations for the first mock service
+ firstService.expectEvent(sentEvent);
+ firstService.replay();
+
+ // set expectations for the second mock service
+ secondService.replay();
+
+ // send the event
+ mManagerService.sendAccessibilityEvent(sentEvent);
+
+ // verify if all expected methods have been called
+ assertMockServiceVerifiedWithinTimeout(firstService);
+ assertMockServiceVerifiedWithinTimeout(secondService);
+ }
+
+ @LargeTest
+ public void testSendAccessibilityEvent_TwoServices_MatchingPackageAndEventType_OneDefault()
+ throws Exception {
+ // set the accessibility setting value
+ ensureAccessibilityEnabled(mContext, true);
+
+ // enable the mock accessibility services
+ ensureOnlyMockServicesEnabled(mContext, true, true);
+
+ // configure the first mock service
+ MockAccessibilityService firstService = MyFirstMockAccessibilityService.sInstance;
+ AccessibilityServiceInfo firstInfo = MyFirstMockAccessibilityService.createDefaultInfo();
+ firstInfo.flags = AccessibilityServiceInfo.DEFAULT;
+ firstService.setServiceInfo(firstInfo);
+
+ // configure the second mock service
+ MockAccessibilityService secondService = MySecondMockAccessibilityService.sInstance;
+ secondService.setServiceInfo(MySecondMockAccessibilityService.createDefaultInfo());
+
+ // wait for the binder calls to #setService to complete
+ Thread.sleep(TIMEOUT_BINDER_CALL);
+
+ // create and populate an event to be sent
+ AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
+ fullyPopulateDefaultAccessibilityEvent(sentEvent);
+
+ // set expectations for the first mock service
+ firstService.replay();
+
+ // set expectations for the second mock service
+ secondService.expectEvent(sentEvent);
+ secondService.replay();
+
+ // send the event
+ mManagerService.sendAccessibilityEvent(sentEvent);
+
+ // verify if all expected methods have been called
+ assertMockServiceVerifiedWithinTimeout(firstService);
+ assertMockServiceVerifiedWithinTimeout(secondService);
+ }
+
+ @LargeTest
+ public void testSendAccessibilityEvent_TwoServices_MatchingPackageAndEventType_TwoDefault()
+ throws Exception {
+ // set the accessibility setting value
+ ensureAccessibilityEnabled(mContext, true);
+
+ // enable the mock accessibility services
+ ensureOnlyMockServicesEnabled(mContext, true, true);
+
+ // configure the first mock service
+ MockAccessibilityService firstService = MyFirstMockAccessibilityService.sInstance;
+ AccessibilityServiceInfo firstInfo = MyFirstMockAccessibilityService.createDefaultInfo();
+ firstInfo.flags = AccessibilityServiceInfo.DEFAULT;
+ firstService.setServiceInfo(firstInfo);
+
+ // configure the second mock service
+ MockAccessibilityService secondService = MySecondMockAccessibilityService.sInstance;
+ AccessibilityServiceInfo secondInfo = MyFirstMockAccessibilityService.createDefaultInfo();
+ secondInfo.flags = AccessibilityServiceInfo.DEFAULT;
+ secondService.setServiceInfo(firstInfo);
+
+ // wait for the binder calls to #setService to complete
+ Thread.sleep(TIMEOUT_BINDER_CALL);
+
+ // create and populate an event to be sent
+ AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
+ fullyPopulateDefaultAccessibilityEvent(sentEvent);
+
+ // set expectations for the first mock service
+ firstService.expectEvent(sentEvent);
+ firstService.replay();
+
+ // set expectations for the second mock service
+ secondService.replay();
+
+ // send the event
+ mManagerService.sendAccessibilityEvent(sentEvent);
+
+ // verify if all expected methods have been called
+ assertMockServiceVerifiedWithinTimeout(firstService);
+ assertMockServiceVerifiedWithinTimeout(secondService);
+ }
+
+ @LargeTest
+ public void testInterrupt() throws Exception {
+ // set the accessibility setting value
+ ensureAccessibilityEnabled(mContext, true);
+
+ // enable the mock accessibility services
+ ensureOnlyMockServicesEnabled(mContext, true, true);
+
+ // configure the first mock service
+ MockAccessibilityService firstService = MyFirstMockAccessibilityService.sInstance;
+ firstService.setServiceInfo(MockAccessibilityService.createDefaultInfo());
+
+ // configure the second mock service
+ MockAccessibilityService secondService = MySecondMockAccessibilityService.sInstance;
+ secondService.setServiceInfo(MockAccessibilityService.createDefaultInfo());
+
+ // wait for the binder calls to #setService to complete
+ Thread.sleep(TIMEOUT_BINDER_CALL);
+
+ // set expectations for the first mock service
+ firstService.expectInterrupt();
+ firstService.replay();
+
+ // set expectations for the second mock service
+ secondService.expectInterrupt();
+ secondService.replay();
+
+ // call the method under test
+ mManagerService.interrupt();
+
+ // verify if all expected methods have been called
+ assertMockServiceVerifiedWithinTimeout(firstService);
+ assertMockServiceVerifiedWithinTimeout(secondService);
+ }
+
+ /**
+ * Fully populates the {@link AccessibilityEvent} to marshal.
+ *
+ * @param sentEvent The event to populate.
+ */
+ private void fullyPopulateDefaultAccessibilityEvent(AccessibilityEvent sentEvent) {
+ sentEvent.setAddedCount(1);
+ sentEvent.setBeforeText("BeforeText");
+ sentEvent.setChecked(true);
+ sentEvent.setClassName("foo.bar.baz.Class");
+ sentEvent.setContentDescription("ContentDescription");
+ sentEvent.setCurrentItemIndex(1);
+ sentEvent.setEnabled(true);
+ sentEvent.setEventType(AccessibilityEvent.TYPE_VIEW_CLICKED);
+ sentEvent.setEventTime(1000);
+ sentEvent.setFromIndex(1);
+ sentEvent.setFullScreen(true);
+ sentEvent.setItemCount(1);
+ sentEvent.setPackageName("foo.bar.baz");
+ sentEvent.setParcelableData(Message.obtain(null, 1, null));
+ sentEvent.setPassword(true);
+ sentEvent.setRemovedCount(1);
+ }
+
+ /**
+ * This class is a mock {@link IAccessibilityManagerClient}.
+ */
+ public class MyMockAccessibilityManagerClient extends IAccessibilityManagerClient.Stub {
+ boolean mIsEnabled;
+
+ public void setEnabled(boolean enabled) {
+ mIsEnabled = enabled;
+ }
+ }
+
+ /**
+ * Ensures accessibility is in a given state by writing the state to the
+ * settings and waiting until the accessibility manager service pick it up.
+ *
+ * @param context A context handle to access the settings.
+ * @param enabled The accessibility state to write to the settings.
+ * @throws Exception If any error occurs.
+ */
+ private void ensureAccessibilityEnabled(Context context, boolean enabled) throws Exception {
+ boolean isEnabled = (Settings.Secure.getInt(context.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1 ? true : false);
+
+ if (isEnabled == enabled) {
+ return;
+ }
+
+ Settings.Secure.putInt(context.getContentResolver(), Settings.Secure.ACCESSIBILITY_ENABLED,
+ enabled ? 1 : 0);
+
+ // wait the accessibility manager service to pick the change up
+ Thread.sleep(TIMEOUT_BINDER_CALL);
+ }
+
+ /**
+ * Ensures the only {@link MockAccessibilityService}s with given component
+ * names are enabled by writing to the system settings and waiting until the
+ * accessibility manager service picks that up or the
+ * {@link #TIMEOUT_START_MOCK_ACCESSIBILITY_SERVICES} is exceeded.
+ *
+ * @param context A context handle to access the settings.
+ * @param firstMockServiceEnabled If the first mock accessibility service is enabled.
+ * @param secondMockServiceEnabled If the second mock accessibility service is enabled.
+ * @throws IllegalStateException If some of the requested for enabling mock services
+ * is not properly started.
+ * @throws Exception Exception If any error occurs.
+ */
+ private void ensureOnlyMockServicesEnabled(Context context, boolean firstMockServiceEnabled,
+ boolean secondMockServiceEnabled) throws Exception {
+ String enabledServices = Settings.Secure.getString(context.getContentResolver(),
+ Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
+
+ StringBuilder servicesToEnable = new StringBuilder();
+ if (firstMockServiceEnabled) {
+ servicesToEnable.append(MyFirstMockAccessibilityService.sComponentName).append(":");
+ }
+ if (secondMockServiceEnabled) {
+ servicesToEnable.append(MySecondMockAccessibilityService.sComponentName).append(":");
+ }
+
+ if (servicesToEnable.equals(enabledServices)) {
+ return;
+ }
+
+ Settings.Secure.putString(context.getContentResolver(),
+ Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, servicesToEnable.toString());
+
+ // we have enabled the services of interest and need to wait until they
+ // are instantiated and started (if needed) and the system binds to them
+ boolean firstMockServiceOK = false;
+ boolean secondMockServiceOK = false;
+ long start = SystemClock.uptimeMillis();
+ long pollingInterval = TIMEOUT_START_MOCK_ACCESSIBILITY_SERVICES / 6;
+
+ while (SystemClock.uptimeMillis() - start < TIMEOUT_START_MOCK_ACCESSIBILITY_SERVICES) {
+ firstMockServiceOK = !firstMockServiceEnabled
+ || (MyFirstMockAccessibilityService.sInstance != null
+ && MyFirstMockAccessibilityService.sInstance.isSystemBoundAsClient());
+
+ secondMockServiceOK = !secondMockServiceEnabled
+ || (MySecondMockAccessibilityService.sInstance != null
+ && MySecondMockAccessibilityService.sInstance.isSystemBoundAsClient());
+
+ if (firstMockServiceOK && secondMockServiceOK) {
+ return;
+ }
+
+ Thread.sleep(pollingInterval);
+ }
+
+ StringBuilder message = new StringBuilder();
+ message.append("Mock accessibility services not started or system not bound as a client: ");
+ if (!firstMockServiceOK) {
+ message.append(MyFirstMockAccessibilityService.sComponentName);
+ message.append(" ");
+ }
+ if (!secondMockServiceOK) {
+ message.append(MySecondMockAccessibilityService.sComponentName);
+ }
+ throw new IllegalStateException(message.toString());
+ }
+
+ /**
+ * Asserts the the mock accessibility service has been successfully verified
+ * (which is it has received the expected method calls with expected
+ * arguments) within the {@link #TIMEOUT_BINDER_CALL}. The verified state is
+ * checked by polling upon small intervals.
+ *
+ * @param service The service to verify.
+ * @throws Exception If the verification has failed with exception after the
+ * {@link #TIMEOUT_BINDER_CALL}.
+ */
+ private void assertMockServiceVerifiedWithinTimeout(MockAccessibilityService service)
+ throws Exception {
+ Exception lastVerifyException = null;
+ long beginTime = SystemClock.uptimeMillis();
+ long pollTmeout = TIMEOUT_BINDER_CALL / 5;
+
+ // poll until the timeout has elapsed
+ while (SystemClock.uptimeMillis() - beginTime < TIMEOUT_BINDER_CALL) {
+ // sleep first since immediate call will always fail
+ try {
+ Thread.sleep(pollTmeout);
+ } catch (InterruptedException ie) {
+ /* ignore */
+ }
+ // poll for verification and if this fails save the exception and
+ // keep polling
+ try {
+ service.verify();
+ // reset so it does not accept more events
+ service.reset();
+ return;
+ } catch (Exception e) {
+ lastVerifyException = e;
+ }
+ }
+
+ // reset, we have already failed
+ service.reset();
+
+ // always not null
+ throw lastVerifyException;
+ }
+
+ /**
+ * This class is the first mock {@link AccessibilityService}.
+ */
+ public static class MyFirstMockAccessibilityService extends MockAccessibilityService {
+
+ /**
+ * The service {@link ComponentName} flattened as a string.
+ */
+ static final String sComponentName = new ComponentName(
+ sPackageName,
+ MyFirstMockAccessibilityService.class.getName()
+ ).flattenToShortString();
+
+ /**
+ * Handle to the service instance.
+ */
+ static MyFirstMockAccessibilityService sInstance;
+
+ /**
+ * Creates a new instance.
+ */
+ public MyFirstMockAccessibilityService() {
+ sInstance = this;
+ }
+ }
+
+ /**
+ * This class is the first mock {@link AccessibilityService}.
+ */
+ public static class MySecondMockAccessibilityService extends MockAccessibilityService {
+
+ /**
+ * The service {@link ComponentName} flattened as a string.
+ */
+ static final String sComponentName = new ComponentName(
+ sPackageName,
+ MySecondMockAccessibilityService.class.getName()
+ ).flattenToShortString();
+
+ /**
+ * Handle to the service instance.
+ */
+ static MySecondMockAccessibilityService sInstance;
+
+ /**
+ * Creates a new instance.
+ */
+ public MySecondMockAccessibilityService() {
+ sInstance = this;
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/AccessibilityManagerTest.java b/services/tests/servicestests/src/com/android/server/AccessibilityManagerTest.java
new file mode 100644
index 0000000..38fed22
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/AccessibilityManagerTest.java
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import static org.easymock.EasyMock.createStrictMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.reportMatcher;
+import static org.easymock.EasyMock.reset;
+import static org.easymock.EasyMock.verify;
+
+import org.easymock.IArgumentMatcher;
+
+import android.content.pm.ServiceInfo;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.IAccessibilityManager;
+import android.view.accessibility.IAccessibilityManagerClient;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tests for the AccessibilityManager which mocking the backing service.
+ */
+public class AccessibilityManagerTest extends AndroidTestCase {
+
+ /**
+ * Timeout required for pending Binder calls or event processing to
+ * complete.
+ */
+ public static final long TIMEOUT_BINDER_CALL = 50;
+
+ /**
+ * The reusable mock {@link IAccessibilityManager}.
+ */
+ private final IAccessibilityManager mMockServiceInterface =
+ createStrictMock(IAccessibilityManager.class);
+
+ @Override
+ public void setUp() throws Exception {
+ reset(mMockServiceInterface);
+ }
+
+ @MediumTest
+ public void testGetAccessibilityServiceList() throws Exception {
+ // create a list of installed accessibility services the mock service returns
+ List<ServiceInfo> expectedServices = new ArrayList<ServiceInfo>();
+ ServiceInfo serviceInfo = new ServiceInfo();
+ serviceInfo.name = "TestServiceInfoName";
+ expectedServices.add(serviceInfo);
+
+ // configure the mock service behavior
+ IAccessibilityManager mockServiceInterface = mMockServiceInterface;
+ expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient())).andReturn(true);
+ expect(mockServiceInterface.getAccessibilityServiceList()).andReturn(expectedServices);
+ replay(mockServiceInterface);
+
+ // invoke the method under test
+ AccessibilityManager manager = new AccessibilityManager(mContext, mockServiceInterface);
+ List<ServiceInfo> receivedServices = manager.getAccessibilityServiceList();
+
+ // check expected result (list equals() compares it contents as well)
+ assertEquals("All expected services must be returned", receivedServices, expectedServices);
+
+ // verify the mock service was properly called
+ verify(mockServiceInterface);
+ }
+
+ @MediumTest
+ public void testInterrupt() throws Exception {
+ // configure the mock service behavior
+ IAccessibilityManager mockServiceInterface = mMockServiceInterface;
+ expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient())).andReturn(true);
+ mockServiceInterface.interrupt();
+ replay(mockServiceInterface);
+
+ // invoke the method under test
+ AccessibilityManager manager = new AccessibilityManager(mContext, mockServiceInterface);
+ manager.interrupt();
+
+ // verify the mock service was properly called
+ verify(mockServiceInterface);
+ }
+
+ @LargeTest
+ public void testIsEnabled() throws Exception {
+ // configure the mock service behavior
+ IAccessibilityManager mockServiceInterface = mMockServiceInterface;
+ expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient())).andReturn(true);
+ replay(mockServiceInterface);
+
+ // invoke the method under test
+ AccessibilityManager manager = new AccessibilityManager(mContext, mockServiceInterface);
+ boolean isEnabledServiceEnabled = manager.isEnabled();
+
+ // check expected result
+ assertTrue("Must be enabled since the mock service is enabled", isEnabledServiceEnabled);
+
+ // disable accessibility
+ manager.getClient().setEnabled(false);
+
+ // wait for the asynchronous IBinder call to complete
+ Thread.sleep(TIMEOUT_BINDER_CALL);
+
+ // invoke the method under test
+ boolean isEnabledServcieDisabled = manager.isEnabled();
+
+ // check expected result
+ assertFalse("Must be disabled since the mock service is disabled",
+ isEnabledServcieDisabled);
+
+ // verify the mock service was properly called
+ verify(mockServiceInterface);
+ }
+
+ @MediumTest
+ public void testSendAccessibilityEvent_AccessibilityEnabled() throws Exception {
+ // create an event to be dispatched
+ AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
+
+ // configure the mock service behavior
+ IAccessibilityManager mockServiceInterface = mMockServiceInterface;
+ expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient())).andReturn(true);
+ expect(mockServiceInterface.sendAccessibilityEvent(eqAccessibilityEvent(sentEvent)))
+ .andReturn(true);
+ expect(mockServiceInterface.sendAccessibilityEvent(eqAccessibilityEvent(sentEvent)))
+ .andReturn(false);
+ replay(mockServiceInterface);
+
+ // invoke the method under test (manager and service in different processes)
+ AccessibilityManager manager = new AccessibilityManager(mContext, mockServiceInterface);
+ manager.sendAccessibilityEvent(sentEvent);
+
+ // check expected result
+ AccessibilityEvent nextEventDifferentProcesses = AccessibilityEvent.obtain();
+ assertSame("The manager and the service are in different processes, so the event must be " +
+ "recycled", sentEvent, nextEventDifferentProcesses);
+
+ // invoke the method under test (manager and service in the same process)
+ manager.sendAccessibilityEvent(sentEvent);
+
+ // check expected result
+ AccessibilityEvent nextEventSameProcess = AccessibilityEvent.obtain();
+ assertNotSame("The manager and the service are in the same process, so the event must not" +
+ "be recycled", sentEvent, nextEventSameProcess);
+
+ // verify the mock service was properly called
+ verify(mockServiceInterface);
+ }
+
+ @MediumTest
+ public void testSendAccessibilityEvent_AccessibilityDisabled() throws Exception {
+ // create an event to be dispatched
+ AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
+
+ // configure the mock service behavior
+ IAccessibilityManager mockServiceInterface = mMockServiceInterface;
+ expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient())).andReturn(false);
+ replay(mockServiceInterface);
+
+ // invoke the method under test (accessibility disabled)
+ AccessibilityManager manager = new AccessibilityManager(mContext, mockServiceInterface);
+ try {
+ manager.sendAccessibilityEvent(sentEvent);
+ fail("No accessibility events are sent if accessibility is disabled");
+ } catch (IllegalStateException ise) {
+ // check expected result
+ assertEquals("Accessibility off. Did you forget to check that?", ise.getMessage());
+ }
+
+ // verify the mock service was properly called
+ verify(mockServiceInterface);
+ }
+
+ /**
+ * Determines if an {@link AccessibilityEvent} passed as a method argument
+ * matches expectations.
+ *
+ * @param matched The event to check.
+ * @return True if expectations are matched.
+ */
+ private static AccessibilityEvent eqAccessibilityEvent(AccessibilityEvent matched) {
+ reportMatcher(new AccessibilityEventMather(matched));
+ return null;
+ }
+
+ /**
+ * Determines if an {@link IAccessibilityManagerClient} passed as a method argument
+ * matches expectations which in this case are that any instance is accepted.
+ *
+ * @return <code>null</code>.
+ */
+ private static IAccessibilityManagerClient anyIAccessibilityManagerClient() {
+ reportMatcher(new AnyIAccessibilityManagerClientMather());
+ return null;
+ }
+
+ /**
+ * Matcher for {@link AccessibilityEvent}s.
+ */
+ private static class AccessibilityEventMather implements IArgumentMatcher {
+ private AccessibilityEvent mExpectedEvent;
+
+ public AccessibilityEventMather(AccessibilityEvent expectedEvent) {
+ mExpectedEvent = expectedEvent;
+ }
+
+ public boolean matches(Object matched) {
+ if (!(matched instanceof AccessibilityEvent)) {
+ return false;
+ }
+ AccessibilityEvent receivedEvent = (AccessibilityEvent) matched;
+ return mExpectedEvent.getEventType() == receivedEvent.getEventType();
+ }
+
+ public void appendTo(StringBuffer buffer) {
+ buffer.append("sendAccessibilityEvent()");
+ buffer.append(" with event type \"");
+ buffer.append(mExpectedEvent.getEventType());
+ buffer.append("\"");
+ }
+ }
+
+ /**
+ * Matcher for {@link IAccessibilityManagerClient}s.
+ */
+ private static class AnyIAccessibilityManagerClientMather implements IArgumentMatcher {
+ public boolean matches(Object matched) {
+ if (!(matched instanceof IAccessibilityManagerClient)) {
+ return false;
+ }
+ return true;
+ }
+
+ public void appendTo(StringBuffer buffer) {
+ buffer.append("addClient() with any IAccessibilityManagerClient");
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/MockAccessibilityService.java b/services/tests/servicestests/src/com/android/server/MockAccessibilityService.java
new file mode 100644
index 0000000..1bc9b86
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/MockAccessibilityService.java
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.accessibilityservice.AccessibilityService;
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.content.Intent;
+import android.os.Message;
+import android.view.accessibility.AccessibilityEvent;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Queue;
+
+import junit.framework.TestCase;
+
+/**
+ * This is the base class for mock {@link AccessibilityService}s.
+ */
+public abstract class MockAccessibilityService extends AccessibilityService {
+
+ /**
+ * The event this service expects to receive.
+ */
+ private final Queue<AccessibilityEvent> mExpectedEvents = new LinkedList<AccessibilityEvent>();
+
+ /**
+ * Interruption call this service expects to receive.
+ */
+ private boolean mExpectedInterrupt;
+
+ /**
+ * Flag if the mock is currently replaying.
+ */
+ private boolean mReplaying;
+
+ /**
+ * Flag if the system is bound as a client to this service.
+ */
+ private boolean mIsSystemBoundAsClient;
+
+ /**
+ * Creates an {@link AccessibilityServiceInfo} populated with default
+ * values.
+ *
+ * @return The default info.
+ */
+ public static AccessibilityServiceInfo createDefaultInfo() {
+ AccessibilityServiceInfo defaultInfo = new AccessibilityServiceInfo();
+ defaultInfo.eventTypes = AccessibilityEvent.TYPE_VIEW_CLICKED;
+ defaultInfo.feedbackType = AccessibilityServiceInfo.FEEDBACK_AUDIBLE;
+ defaultInfo.flags = 0;
+ defaultInfo.notificationTimeout = 0;
+ defaultInfo.packageNames = new String[] {
+ "foo.bar.baz"
+ };
+
+ return defaultInfo;
+ }
+
+ /**
+ * Starts replaying the mock.
+ */
+ public void replay() {
+ mReplaying = true;
+ }
+
+ /**
+ * Verifies if all expected service methods have been called.
+ */
+ public void verify() {
+ if (!mReplaying) {
+ throw new IllegalStateException("Did you forget to call replay()");
+ }
+
+ if (mExpectedInterrupt) {
+ throw new IllegalStateException("Expected call to #interrupt() not received");
+ }
+ if (!mExpectedEvents.isEmpty()) {
+ throw new IllegalStateException("Expected a call to onAccessibilityEvent() for "
+ + "events \"" + mExpectedEvents + "\" not received");
+ }
+ }
+
+ /**
+ * Resets this instance so it can be reused.
+ */
+ public void reset() {
+ mExpectedEvents.clear();
+ mExpectedInterrupt = false;
+ mReplaying = false;
+ }
+
+ /**
+ * Sets an expected call to
+ * {@link #onAccessibilityEvent(AccessibilityEvent)} with given event as
+ * argument.
+ *
+ * @param expectedEvent The expected event argument.
+ */
+ public void expectEvent(AccessibilityEvent expectedEvent) {
+ mExpectedEvents.add(expectedEvent);
+ }
+
+ /**
+ * Sets an expected call of {@link #onInterrupt()}.
+ */
+ public void expectInterrupt() {
+ mExpectedInterrupt = true;
+ }
+
+ @Override
+ public void onAccessibilityEvent(AccessibilityEvent receivedEvent) {
+ if (!mReplaying) {
+ return;
+ }
+
+ if (mExpectedEvents.isEmpty()) {
+ throw new IllegalStateException("Unexpected event: " + receivedEvent);
+ }
+
+ AccessibilityEvent expectedEvent = mExpectedEvents.poll();
+ assertEqualsAccessiblityEvent(expectedEvent, receivedEvent);
+ }
+
+ @Override
+ public void onInterrupt() {
+ if (!mReplaying) {
+ return;
+ }
+
+ if (!mExpectedInterrupt) {
+ throw new IllegalStateException("Unexpected call to onInterrupt()");
+ }
+
+ mExpectedInterrupt = false;
+ }
+
+ @Override
+ protected void onServiceConnected() {
+ mIsSystemBoundAsClient = true;
+ }
+
+ @Override
+ public boolean onUnbind(Intent intent) {
+ mIsSystemBoundAsClient = false;
+ return false;
+ }
+
+ /**
+ * Returns if the system is bound as client to this service.
+ *
+ * @return True if the system is bound, false otherwise.
+ */
+ public boolean isSystemBoundAsClient() {
+ return mIsSystemBoundAsClient;
+ }
+
+ /**
+ * Compares all properties of the <code>expectedEvent</code> and the
+ * <code>receviedEvent</code> to verify that the received event is the one
+ * that is expected.
+ */
+ private void assertEqualsAccessiblityEvent(AccessibilityEvent expectedEvent,
+ AccessibilityEvent receivedEvent) {
+ TestCase.assertEquals("addedCount has incorrect value", expectedEvent.getAddedCount(),
+ receivedEvent.getAddedCount());
+ TestCase.assertEquals("beforeText has incorrect value", expectedEvent.getBeforeText(),
+ receivedEvent.getBeforeText());
+ TestCase.assertEquals("checked has incorrect value", expectedEvent.isChecked(),
+ receivedEvent.isChecked());
+ TestCase.assertEquals("className has incorrect value", expectedEvent.getClassName(),
+ receivedEvent.getClassName());
+ TestCase.assertEquals("contentDescription has incorrect value", expectedEvent
+ .getContentDescription(), receivedEvent.getContentDescription());
+ TestCase.assertEquals("currentItemIndex has incorrect value", expectedEvent
+ .getCurrentItemIndex(), receivedEvent.getCurrentItemIndex());
+ TestCase.assertEquals("enabled has incorrect value", expectedEvent.isEnabled(),
+ receivedEvent.isEnabled());
+ TestCase.assertEquals("eventType has incorrect value", expectedEvent.getEventType(),
+ receivedEvent.getEventType());
+ TestCase.assertEquals("fromIndex has incorrect value", expectedEvent.getFromIndex(),
+ receivedEvent.getFromIndex());
+ TestCase.assertEquals("fullScreen has incorrect value", expectedEvent.isFullScreen(),
+ receivedEvent.isFullScreen());
+ TestCase.assertEquals("itemCount has incorrect value", expectedEvent.getItemCount(),
+ receivedEvent.getItemCount());
+ assertEqualsNotificationAsParcelableData(expectedEvent, receivedEvent);
+ TestCase.assertEquals("password has incorrect value", expectedEvent.isPassword(),
+ receivedEvent.isPassword());
+ TestCase.assertEquals("removedCount has incorrect value", expectedEvent.getRemovedCount(),
+ receivedEvent.getRemovedCount());
+ assertEqualsText(expectedEvent, receivedEvent);
+ }
+
+ /**
+ * Compares the {@link android.os.Parcelable} data of the
+ * <code>expectedEvent</code> and <code>receivedEvent</code> to verify that
+ * the received event is the one that is expected.
+ */
+ private void assertEqualsNotificationAsParcelableData(AccessibilityEvent expectedEvent,
+ AccessibilityEvent receivedEvent) {
+ String message = "parcelableData has incorrect value";
+ Message expectedMessage = (Message) expectedEvent.getParcelableData();
+ Message receivedMessage = (Message) receivedEvent.getParcelableData();
+
+ if (expectedMessage == null) {
+ if (receivedMessage == null) {
+ return;
+ }
+ }
+
+ TestCase.assertNotNull(message, receivedMessage);
+
+ // we do a very simple sanity check since we do not test Message
+ TestCase.assertEquals(message, expectedMessage.what, receivedMessage.what);
+ }
+
+ /**
+ * Compares the text of the <code>expectedEvent</code> and
+ * <code>receivedEvent</code> by comparing the string representation of the
+ * corresponding {@link CharSequence}s.
+ */
+ private void assertEqualsText(AccessibilityEvent expectedEvent,
+ AccessibilityEvent receivedEvent) {
+ String message = "text has incorrect value";
+ List<CharSequence> expectedText = expectedEvent.getText();
+ List<CharSequence> receivedText = receivedEvent.getText();
+
+ TestCase.assertEquals(message, expectedText.size(), receivedText.size());
+
+ Iterator<CharSequence> expectedTextIterator = expectedText.iterator();
+ Iterator<CharSequence> receivedTextIterator = receivedText.iterator();
+
+ for (int i = 0; i < expectedText.size(); i++) {
+ // compare the string representation
+ TestCase.assertEquals(message, expectedTextIterator.next().toString(),
+ receivedTextIterator.next().toString());
+ }
+ }
+}
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index f2212fb..e1b9b60 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -586,7 +586,7 @@
}
} else {
// In the US, 1-650-555-1234 must be equal to 650-555-1234,
- // while 090-1234-1234 must not be equalt to 90-1234-1234 in Japan.
+ // while 090-1234-1234 must not be equal to 90-1234-1234 in Japan.
// This request exists just in US (with 1 trunk (NDD) prefix).
// In addition, "011 11 7005554141" must not equal to "+17005554141",
// while "011 1 7005554141" must equal to "+17005554141"
@@ -748,10 +748,10 @@
if (prependPlus) {
// This is an "international number" and should have
// a plus prepended to the dialing number. But there
- // can also be Gsm MMI codes as defined in TS 22.030 6.5.2
+ // can also be GSM MMI codes as defined in TS 22.030 6.5.2
// so we need to handle those also.
//
- // http://web.telia.com/~u47904776/gsmkode.htm is a
+ // http://web.telia.com/~u47904776/gsmkode.htm
// has a nice list of some of these GSM codes.
//
// Examples are:
@@ -839,10 +839,10 @@
// FIXME(mkf) TS 23.040 9.1.2.3 says
// "if a mobile receives 1111 in a position prior to
- // the last semi-octet then processing shall commense with
+ // the last semi-octet then processing shall commence with
// the next semi-octet and the intervening
// semi-octet shall be ignored"
- // How does this jive with 24,008 10.5.4.7
+ // How does this jive with 24.008 10.5.4.7
b = (byte)((bytes[i] >> 4) & 0xf);
@@ -973,7 +973,7 @@
* Convert a dialing number to BCD byte array
*
* @param number dialing number string
- * if the dialing number starts with '+', set to internationl TOA
+ * if the dialing number starts with '+', set to international TOA
* @return BCD byte array
*/
public static byte[]
@@ -1077,10 +1077,10 @@
*
* @param source the phone number to format
* @param defaultFormattingType The default formatting rules to apply if the number does
- * not begin with +<country_code>
+ * not begin with +[country_code]
* @return The phone number formatted with the given formatting type.
*
- * @hide TODO:Shuold be unhidden.
+ * @hide TODO: Should be unhidden.
*/
public static String formatNumber(String source, int defaultFormattingType) {
SpannableStringBuilder text = new SpannableStringBuilder(source);
@@ -1107,7 +1107,7 @@
*
* @param text The number to be formatted, will be modified with the formatting
* @param defaultFormattingType The default formatting rules to apply if the number does
- * not begin with +<country_code>
+ * not begin with +[country_code]
*/
public static void formatNumber(Editable text, int defaultFormattingType) {
int formatType = defaultFormattingType;
@@ -1515,7 +1515,7 @@
* @hide
*/
public static String
- cdmaCheckAndProcessPlusCodeByNumberFormat(String dialStr,int currFormat,int defaultFormt) {
+ cdmaCheckAndProcessPlusCodeByNumberFormat(String dialStr,int currFormat,int defaultFormat) {
String retStr = dialStr;
// Checks if the plus sign character is in the passed-in dial string
@@ -1523,7 +1523,7 @@
dialStr.lastIndexOf(PLUS_SIGN_STRING) != -1) {
// Format the string based on the rules for the country the number is from,
// and the current country the phone is camped on.
- if ((currFormat == defaultFormt) && (currFormat == FORMAT_NANP)) {
+ if ((currFormat == defaultFormat) && (currFormat == FORMAT_NANP)) {
// Handle case where default and current telephone numbering plans are NANP.
String postDialStr = null;
String tempDialStr = dialStr;
@@ -1701,7 +1701,7 @@
return -1;
}
- // This function appends the non-diablable P/W character to the original
+ // This function appends the non-dialable P/W character to the original
// dial string based on the dialable index passed in
private static String
appendPwCharBackToOrigDialStr(int dialableIndex,String origStr, String dialStr) {
@@ -1721,7 +1721,7 @@
return retStr;
}
- //===== Begining of utility methods used in compareLoosely() =====
+ //===== Beginning of utility methods used in compareLoosely() =====
/**
* Phone numbers are stored in "lookup" form in the database
@@ -1843,12 +1843,12 @@
//===== End of utility methods used only in compareLoosely() =====
- //===== Beggining of utility methods used only in compareStrictly() ====
+ //===== Beginning of utility methods used only in compareStrictly() ====
/*
* If true, the number is country calling code.
*/
- private static final boolean COUNTLY_CALLING_CALL[] = {
+ private static final boolean COUNTRY_CALLING_CALL[] = {
true, true, false, false, false, false, false, true, false, false,
false, false, false, false, false, false, false, false, false, false,
true, false, false, false, false, false, false, true, true, false,
@@ -1860,18 +1860,18 @@
false, true, true, true, true, false, true, false, false, true,
true, true, true, true, true, true, false, false, true, false,
};
- private static final int CCC_LENGTH = COUNTLY_CALLING_CALL.length;
+ private static final int CCC_LENGTH = COUNTRY_CALLING_CALL.length;
/**
* @return true when input is valid Country Calling Code.
*/
private static boolean isCountryCallingCode(int countryCallingCodeCandidate) {
return countryCallingCodeCandidate > 0 && countryCallingCodeCandidate < CCC_LENGTH &&
- COUNTLY_CALLING_CALL[countryCallingCodeCandidate];
+ COUNTRY_CALLING_CALL[countryCallingCodeCandidate];
}
/**
- * Returns interger corresponding to the input if input "ch" is
+ * Returns integer corresponding to the input if input "ch" is
* ISO-LATIN characters 0-9.
* Returns -1 otherwise
*/
@@ -2006,7 +2006,7 @@
/**
* Return true if the prefix of "str" is "ignorable". Here, "ignorable" means
- * that "str" has only one digit and separater characters. The one digit is
+ * that "str" has only one digit and separator characters. The one digit is
* assumed to be trunk prefix.
*/
private static boolean checkPrefixIsIgnorable(final String str,
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index f5e9751..953696b 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -21,7 +21,6 @@
import android.os.ServiceManager;
import android.text.TextUtils;
-import com.android.internal.telephony.EncodeException;
import com.android.internal.telephony.ISms;
import com.android.internal.telephony.IccConstants;
import com.android.internal.telephony.SmsRawData;
@@ -33,7 +32,7 @@
/*
* TODO(code review): Curious question... Why are a lot of these
* methods not declared as static, since they do not seem to require
- * any local object state? Assumedly this cannot be changed without
+ * any local object state? Presumably this cannot be changed without
* interfering with the API...
*/
@@ -42,7 +41,8 @@
* Get this object by calling the static method SmsManager.getDefault().
*/
public final class SmsManager {
- private static SmsManager sInstance;
+ /** Singleton object constructed during class initialization. */
+ private static final SmsManager sInstance = new SmsManager();
/**
* Send a text based SMS.
@@ -52,8 +52,8 @@
* the current default SMSC
* @param text the body of the message to send
* @param sentIntent if not NULL this <code>PendingIntent</code> is
- * broadcast when the message is sucessfully sent, or failed.
- * The result code will be <code>Activity.RESULT_OK<code> for success,
+ * broadcast when the message is successfully sent, or failed.
+ * The result code will be <code>Activity.RESULT_OK</code> for success,
* or one of these errors:<br>
* <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
* <code>RESULT_ERROR_RADIO_OFF</code><br>
@@ -116,7 +116,7 @@
* @param sentIntents if not null, an <code>ArrayList</code> of
* <code>PendingIntent</code>s (one for each message part) that is
* broadcast when the corresponding message part has been sent.
- * The result code will be <code>Activity.RESULT_OK<code> for success,
+ * The result code will be <code>Activity.RESULT_OK</code> for success,
* or one of these errors:<br>
* <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
* <code>RESULT_ERROR_RADIO_OFF</code><br>
@@ -125,7 +125,7 @@
* the extra "errorCode" containing a radio technology specific value,
* generally only useful for troubleshooting.<br>
* The per-application based SMS control checks sentIntent. If sentIntent
- * is NULL the caller will be checked against all unknown applicaitons,
+ * is NULL the caller will be checked against all unknown applications,
* which cause smaller number of SMS to be sent in checking period.
* @param deliveryIntents if not null, an <code>ArrayList</code> of
* <code>PendingIntent</code>s (one for each message part) that is
@@ -178,8 +178,8 @@
* @param destinationPort the port to deliver the message to
* @param data the body of the message to send
* @param sentIntent if not NULL this <code>PendingIntent</code> is
- * broadcast when the message is sucessfully sent, or failed.
- * The result code will be <code>Activity.RESULT_OK<code> for success,
+ * broadcast when the message is successfully sent, or failed.
+ * The result code will be <code>Activity.RESULT_OK</code> for success,
* or one of these errors:<br>
* <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
* <code>RESULT_ERROR_RADIO_OFF</code><br>
@@ -188,7 +188,7 @@
* the extra "errorCode" containing a radio technology specific value,
* generally only useful for troubleshooting.<br>
* The per-application based SMS control checks sentIntent. If sentIntent
- * is NULL the caller will be checked against all unknown applicaitons,
+ * is NULL the caller will be checked against all unknown applications,
* which cause smaller number of SMS to be sent in checking period.
* @param deliveryIntent if not NULL this <code>PendingIntent</code> is
* broadcast when the message is delivered to the recipient. The
@@ -224,9 +224,6 @@
* @return the default instance of the SmsManager
*/
public static SmsManager getDefault() {
- if (sInstance == null) {
- sInstance = new SmsManager();
- }
return sInstance;
}
diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java
index a284ea5..d899430 100644
--- a/telephony/java/android/telephony/SmsMessage.java
+++ b/telephony/java/android/telephony/SmsMessage.java
@@ -20,7 +20,6 @@
import android.util.Log;
import com.android.internal.telephony.GsmAlphabet;
-import com.android.internal.telephony.EncodeException;
import com.android.internal.telephony.SmsHeader;
import com.android.internal.telephony.SmsMessageBase;
import com.android.internal.telephony.SmsMessageBase.SubmitPduBase;
diff --git a/telephony/java/com/android/internal/telephony/CommandsInterface.java b/telephony/java/com/android/internal/telephony/CommandsInterface.java
index 8e03c5a..5f27e3f 100644
--- a/telephony/java/com/android/internal/telephony/CommandsInterface.java
+++ b/telephony/java/com/android/internal/telephony/CommandsInterface.java
@@ -27,8 +27,8 @@
*/
public interface CommandsInterface {
enum RadioState {
- RADIO_OFF, /* Radio explictly powered off (eg CFUN=0) */
- RADIO_UNAVAILABLE, /* Radio unavailable (eg, resetting or not booted) */
+ RADIO_OFF, /* Radio explicitly powered off (e.g. CFUN=0) */
+ RADIO_UNAVAILABLE, /* Radio unavailable (e.g. resetting or not booted) */
SIM_NOT_READY, /* Radio is on, but the SIM interface is not ready */
SIM_LOCKED_OR_ABSENT, /* SIM PIN locked, PUK required, network
personalization, or SIM absent */
@@ -121,7 +121,7 @@
// See 27.007 +CCFC or +CLCK
static final int SERVICE_CLASS_NONE = 0; // no user input
static final int SERVICE_CLASS_VOICE = (1 << 0);
- static final int SERVICE_CLASS_DATA = (1 << 1); //synoym for 16+32+64+128
+ static final int SERVICE_CLASS_DATA = (1 << 1); //synonym for 16+32+64+128
static final int SERVICE_CLASS_FAX = (1 << 2);
static final int SERVICE_CLASS_SMS = (1 << 3);
static final int SERVICE_CLASS_DATA_SYNC = (1 << 4);
@@ -952,19 +952,19 @@
void writeSmsToRuim(int status, String pdu, Message response);
/**
- * @deprecated
* @param apn
* @param user
* @param password
* @param response
*/
+ @Deprecated
void setupDefaultPDP(String apn, String user, String password, Message response);
/**
- * @deprecated
* @param cid
* @param response
*/
+ @Deprecated
void deactivateDefaultPDP(int cid, Message response);
void setRadioPower(boolean on, Message response);
@@ -974,7 +974,7 @@
void acknowledgeLastIncomingCdmaSms(boolean success, int cause, Message response);
/**
- * parameters equivilient to 27.007 AT+CRSM command
+ * parameters equivalent to 27.007 AT+CRSM command
* response.obj will be an AsyncResult
* response.obj.userObj will be a IccIoResult on success
*/
@@ -1079,7 +1079,7 @@
/**
* (AsyncResult)response.obj).result will be an Integer representing
- * the sum of enabled serivice classes (sum of SERVICE_CLASS_*)
+ * the sum of enabled service classes (sum of SERVICE_CLASS_*)
*
* @param facility one of CB_FACILTY_*
* @param password password or "" if not required
@@ -1152,7 +1152,7 @@
/**
* Request to enable/disable network state change notifications when
- * location informateion (lac and/or cid) has changed.
+ * location information (lac and/or cid) has changed.
*
* @param enable true to enable, false to disable
* @param response callback message
@@ -1183,7 +1183,7 @@
/**
* Indicates to the vendor ril that StkService is running
- * rand is eady to receive RIL_UNSOL_STK_XXXX commands.
+ * and is ready to receive RIL_UNSOL_STK_XXXX commands.
*
* @param result callback message
*/
diff --git a/telephony/java/com/android/internal/telephony/GsmAlphabet.java b/telephony/java/com/android/internal/telephony/GsmAlphabet.java
index ebdd220..75ea116 100644
--- a/telephony/java/com/android/internal/telephony/GsmAlphabet.java
+++ b/telephony/java/com/android/internal/telephony/GsmAlphabet.java
@@ -16,14 +16,13 @@
package com.android.internal.telephony;
-import android.telephony.SmsMessage;
import android.util.SparseIntArray;
import android.util.Log;
/**
* This class implements the character set mapping between
- * the GSM SMS 7-bit alphabet specifed in TS 23.038 6.2.1
+ * the GSM SMS 7-bit alphabet specified in TS 23.038 6.2.1
* and UTF-16
*
* {@hide}
@@ -171,7 +170,7 @@
* array cannot contain more than 255 septets.
*
* @param data The text string to encode.
- * @param header Optional header (includeing length byte) that precedes
+ * @param header Optional header (including length byte) that precedes
* the encoded data, padded to septet boundary.
* @return Byte array containing header and encoded data.
*/
@@ -204,7 +203,7 @@
* the packed septets. The returned array cannot contain more than 255
* septets.
*
- * @param data the data string to endcode
+ * @param data the data string to encode
* @throws EncodeException if String is too large to encode
*/
public static byte[] stringToGsm7BitPacked(String data)
@@ -223,7 +222,7 @@
*
* @param data the text to convert to septets
* @param startingSeptetOffset the number of padding septets to put before
- * the character data at the begining of the array
+ * the character data at the beginning of the array
* @param throwException If true, throws EncodeException on invalid char.
* If false, replaces unencodable char with GSM alphabet space char.
*
@@ -257,7 +256,7 @@
}
/**
- * Pack a 7-bit char into its appropirate place in a byte array
+ * Pack a 7-bit char into its appropriate place in a byte array
*
* @param bitOffset the bit offset that the septet should be packed at
* (septet index * 7)
@@ -320,7 +319,7 @@
gsmVal = (0x7f & (pdu[offset + byteOffset] >> shift));
- // if it crosses a byte boundry
+ // if it crosses a byte boundary
if (shift > 1) {
// set msb bits to 0
gsmVal &= 0x7f >> (shift - 1);
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 2328717..7a1587b 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -239,9 +239,11 @@
String getCdmaEriText();
/**
- * Returns true if CDMA provisioning needs to run.
+ * Returns true if OTA service provisioning needs to run.
+ * Only relevant on some technologies, others will always
+ * return false.
*/
- boolean getCdmaNeedsProvisioning();
+ boolean needsOtaServiceProvisioning();
/**
* Returns the unread count of voicemails
diff --git a/telephony/java/com/android/internal/telephony/IccSmsInterfaceManager.java b/telephony/java/com/android/internal/telephony/IccSmsInterfaceManager.java
index 8a5a6ae..5fef6de 100644
--- a/telephony/java/com/android/internal/telephony/IccSmsInterfaceManager.java
+++ b/telephony/java/com/android/internal/telephony/IccSmsInterfaceManager.java
@@ -57,7 +57,7 @@
* @param destPort the port to deliver the message to
* @param data the body of the message to send
* @param sentIntent if not NULL this <code>PendingIntent</code> is
- * broadcast when the message is sucessfully sent, or failed.
+ * broadcast when the message is successfully sent, or failed.
* The result code will be <code>Activity.RESULT_OK<code> for success,
* or one of these errors:<br>
* <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
@@ -67,7 +67,7 @@
* the extra "errorCode" containing a radio technology specific value,
* generally only useful for troubleshooting.<br>
* The per-application based SMS control checks sentIntent. If sentIntent
- * is NULL the caller will be checked against all unknown applicaitons,
+ * is NULL the caller will be checked against all unknown applications,
* which cause smaller number of SMS to be sent in checking period.
* @param deliveryIntent if not NULL this <code>PendingIntent</code> is
* broadcast when the message is delivered to the recipient. The
@@ -94,7 +94,7 @@
* the current default SMSC
* @param text the body of the message to send
* @param sentIntent if not NULL this <code>PendingIntent</code> is
- * broadcast when the message is sucessfully sent, or failed.
+ * broadcast when the message is successfully sent, or failed.
* The result code will be <code>Activity.RESULT_OK<code> for success,
* or one of these errors:<br>
* <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
@@ -140,7 +140,7 @@
* <code>RESULT_ERROR_RADIO_OFF</code>
* <code>RESULT_ERROR_NULL_PDU</code>.
* The per-application based SMS control checks sentIntent. If sentIntent
- * is NULL the caller will be checked against all unknown applicaitons,
+ * is NULL the caller will be checked against all unknown applications,
* which cause smaller number of SMS to be sent in checking period.
* @param deliveryIntents if not null, an <code>ArrayList</code> of
* <code>PendingIntent</code>s (one for each message part) that is
diff --git a/telephony/java/com/android/internal/telephony/IccUtils.java b/telephony/java/com/android/internal/telephony/IccUtils.java
index 71936f1..95bce13 100644
--- a/telephony/java/com/android/internal/telephony/IccUtils.java
+++ b/telephony/java/com/android/internal/telephony/IccUtils.java
@@ -265,9 +265,11 @@
/**
- * Converts a byte array into a String hexidecimal characters
+ * Converts a byte array into a String of hexadecimal characters.
*
- * null returns null
+ * @param bytes an array of bytes
+ *
+ * @return hex string representation of bytes array
*/
public static String
bytesToHexString(byte[] bytes) {
diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java
index 23325f6..8ff38d9 100644
--- a/telephony/java/com/android/internal/telephony/Phone.java
+++ b/telephony/java/com/android/internal/telephony/Phone.java
@@ -1533,6 +1533,11 @@
boolean isOtaSpNumber(String dialStr);
/**
+ * Returns true if OTA Service Provisioning needs to be performed.
+ */
+ boolean needsOtaServiceProvisioning();
+
+ /**
* Register for notifications when CDMA call waiting comes
*
* @param h Handler that receives the notification message.
diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java
index 74601e6..fbb658a 100644
--- a/telephony/java/com/android/internal/telephony/PhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/PhoneBase.java
@@ -824,9 +824,19 @@
logUnexpectedCdmaMethodCall("unregisterForSubscriptionInfoReady");
}
+ /**
+ * Returns true if OTA Service Provisioning needs to be performed.
+ * If not overridden return false.
+ */
+ public boolean needsOtaServiceProvisioning() {
+ return false;
+ }
+
+ /**
+ * Return true if number is an OTASP number.
+ * If not overridden return false.
+ */
public boolean isOtaSpNumber(String dialStr) {
- // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
- logUnexpectedCdmaMethodCall("isOtaSpNumber");
return false;
}
diff --git a/telephony/java/com/android/internal/telephony/PhoneProxy.java b/telephony/java/com/android/internal/telephony/PhoneProxy.java
index e1511e6..8c2a661 100644
--- a/telephony/java/com/android/internal/telephony/PhoneProxy.java
+++ b/telephony/java/com/android/internal/telephony/PhoneProxy.java
@@ -764,6 +764,10 @@
mActivePhone.exitEmergencyCallbackMode();
}
+ public boolean needsOtaServiceProvisioning(){
+ return mActivePhone.needsOtaServiceProvisioning();
+ }
+
public boolean isOtaSpNumber(String dialStr){
return mActivePhone.isOtaSpNumber(dialStr);
}
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index 3d410fd..5bd9e39 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -285,9 +285,8 @@
}
- //***** Handler implemementation
-
- public void
+ //***** Handler implementation
+ @Override public void
handleMessage(Message msg) {
RILRequest rr = (RILRequest)(msg.obj);
RILRequest req = null;
@@ -780,7 +779,7 @@
send(rr);
}
- public void
+ @Deprecated public void
getPDPContextList(Message result) {
getDataCallList(result);
}
diff --git a/telephony/java/com/android/internal/telephony/SMSDispatcher.java b/telephony/java/com/android/internal/telephony/SMSDispatcher.java
index ca526a5..9e17eb1 100644
--- a/telephony/java/com/android/internal/telephony/SMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/SMSDispatcher.java
@@ -143,7 +143,7 @@
private SmsCounter mCounter;
- private ArrayList mSTrackers = new ArrayList(MO_MSG_QUEUE_LIMIT);
+ private ArrayList<SmsTracker> mSTrackers = new ArrayList<SmsTracker>(MO_MSG_QUEUE_LIMIT);
/** Wake lock to ensure device stays awake while dispatching the SMS intent. */
private PowerManager.WakeLock mWakeLock;
@@ -265,6 +265,7 @@
mCm.unregisterForOn(this);
}
+ @Override
protected void finalize() {
Log.d(TAG, "SMSDispatcher finalized");
}
@@ -345,7 +346,7 @@
msg.obj = null;
if (mSTrackers.isEmpty() == false) {
try {
- SmsTracker sTracker = (SmsTracker)mSTrackers.remove(0);
+ SmsTracker sTracker = mSTrackers.remove(0);
sTracker.mSentIntent.send(RESULT_ERROR_LIMIT_EXCEEDED);
} catch (CanceledException ex) {
Log.e(TAG, "failed to send back RESULT_ERROR_LIMIT_EXCEEDED");
@@ -358,7 +359,7 @@
case EVENT_SEND_CONFIRMED_SMS:
if (mSTrackers.isEmpty() == false) {
- SmsTracker sTracker = (SmsTracker)mSTrackers.remove(mSTrackers.size() - 1);
+ SmsTracker sTracker = mSTrackers.remove(mSTrackers.size() - 1);
if (isMultipartTracker(sTracker)) {
sendMultipartSms(sTracker);
} else {
@@ -372,7 +373,7 @@
if (mSTrackers.isEmpty() == false) {
// Remove the latest one.
try {
- SmsTracker sTracker = (SmsTracker)mSTrackers.remove(mSTrackers.size() - 1);
+ SmsTracker sTracker = mSTrackers.remove(mSTrackers.size() - 1);
sTracker.mSentIntent.send(RESULT_ERROR_LIMIT_EXCEEDED);
} catch (CanceledException ex) {
Log.e(TAG, "failed to send back RESULT_ERROR_LIMIT_EXCEEDED");
@@ -679,7 +680,7 @@
* @param destPort the port to deliver the message to
* @param data the body of the message to send
* @param sentIntent if not NULL this <code>PendingIntent</code> is
- * broadcast when the message is sucessfully sent, or failed.
+ * broadcast when the message is successfully sent, or failed.
* The result code will be <code>Activity.RESULT_OK<code> for success,
* or one of these errors:<br>
* <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
@@ -689,7 +690,7 @@
* the extra "errorCode" containing a radio technology specific value,
* generally only useful for troubleshooting.<br>
* The per-application based SMS control checks sentIntent. If sentIntent
- * is NULL the caller will be checked against all unknown applicaitons,
+ * is NULL the caller will be checked against all unknown applications,
* which cause smaller number of SMS to be sent in checking period.
* @param deliveryIntent if not NULL this <code>PendingIntent</code> is
* broadcast when the message is delivered to the recipient. The
@@ -706,7 +707,7 @@
* the current default SMSC
* @param text the body of the message to send
* @param sentIntent if not NULL this <code>PendingIntent</code> is
- * broadcast when the message is sucessfully sent, or failed.
+ * broadcast when the message is successfully sent, or failed.
* The result code will be <code>Activity.RESULT_OK<code> for success,
* or one of these errors:<br>
* <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
@@ -742,7 +743,7 @@
* <code>RESULT_ERROR_RADIO_OFF</code>
* <code>RESULT_ERROR_NULL_PDU</code>.
* The per-application based SMS control checks sentIntent. If sentIntent
- * is NULL the caller will be checked against all unknown applicaitons,
+ * is NULL the caller will be checked against all unknown applications,
* which cause smaller number of SMS to be sent in checking period.
* @param deliveryIntents if not null, an <code>ArrayList</code> of
* <code>PendingIntent</code>s (one for each message part) that is
@@ -758,17 +759,17 @@
* Send a SMS
*
* @param smsc the SMSC to send the message through, or NULL for the
- * defatult SMSC
+ * default SMSC
* @param pdu the raw PDU to send
* @param sentIntent if not NULL this <code>Intent</code> is
- * broadcast when the message is sucessfully sent, or failed.
+ * broadcast when the message is successfully sent, or failed.
* The result code will be <code>Activity.RESULT_OK<code> for success,
* or one of these errors:
* <code>RESULT_ERROR_GENERIC_FAILURE</code>
* <code>RESULT_ERROR_RADIO_OFF</code>
* <code>RESULT_ERROR_NULL_PDU</code>.
* The per-application based SMS control checks sentIntent. If sentIntent
- * is NULL the caller will be checked against all unknown applicaitons,
+ * is NULL the caller will be checked against all unknown applications,
* which cause smaller number of SMS to be sent in checking period.
* @param deliveryIntent if not NULL this <code>Intent</code> is
* broadcast when the message is delivered to the recipient. The
@@ -937,14 +938,14 @@
*/
static protected class SmsTracker {
// fields need to be public for derived SmsDispatchers
- public HashMap mData;
+ public HashMap<String, Object> mData;
public int mRetryCount;
public int mMessageRef;
public PendingIntent mSentIntent;
public PendingIntent mDeliveryIntent;
- SmsTracker(HashMap data, PendingIntent sentIntent,
+ SmsTracker(HashMap<String, Object> data, PendingIntent sentIntent,
PendingIntent deliveryIntent) {
mData = data;
mSentIntent = sentIntent;
@@ -953,7 +954,7 @@
}
}
- protected SmsTracker SmsTrackerFactory(HashMap data, PendingIntent sentIntent,
+ protected SmsTracker SmsTrackerFactory(HashMap<String, Object> data, PendingIntent sentIntent,
PendingIntent deliveryIntent) {
return new SmsTracker(data, sentIntent, deliveryIntent);
}
diff --git a/telephony/java/com/android/internal/telephony/SmsHeader.java b/telephony/java/com/android/internal/telephony/SmsHeader.java
index 7872eec..7a65162 100644
--- a/telephony/java/com/android/internal/telephony/SmsHeader.java
+++ b/telephony/java/com/android/internal/telephony/SmsHeader.java
@@ -30,7 +30,7 @@
*/
public class SmsHeader {
- // TODO(cleanup): this datastructure is generally referred to as
+ // TODO(cleanup): this data structure is generally referred to as
// the 'user data header' or UDH, and so the class name should
// change to reflect this...
diff --git a/telephony/java/com/android/internal/telephony/SmsMessageBase.java b/telephony/java/com/android/internal/telephony/SmsMessageBase.java
index af6c5f8..cbd8606 100644
--- a/telephony/java/com/android/internal/telephony/SmsMessageBase.java
+++ b/telephony/java/com/android/internal/telephony/SmsMessageBase.java
@@ -16,7 +16,6 @@
package com.android.internal.telephony;
-import android.util.Log;
import com.android.internal.telephony.SmsHeader;
import java.util.Arrays;
@@ -366,13 +365,13 @@
/**
* Try to parse this message as an email gateway message
* There are two ways specified in TS 23.040 Section 3.8 :
- * - SMS message "may have its TP-PID set for internet electronic mail - MT
+ * - SMS message "may have its TP-PID set for Internet electronic mail - MT
* SMS format: [<from-address><space>]<message> - "Depending on the
* nature of the gateway, the destination/origination address is either
* derived from the content of the SMS TP-OA or TP-DA field, or the
* TP-OA/TP-DA field contains a generic gateway address and the to/from
* address is added at the beginning as shown above." (which is supported here)
- * - Multiple addreses separated by commas, no spaces, Subject field delimited
+ * - Multiple addresses separated by commas, no spaces, Subject field delimited
* by '()' or '##' and '#' Section 9.2.3.24.11 (which are NOT supported here)
*/
protected void extractEmailAddressFromMessageBody() {
diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
index a113787..136d5b1 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
@@ -45,7 +45,7 @@
* CDMA networks.
*/
static final String PROPERTY_OPERATOR_ALPHA = "gsm.operator.alpha";
- //TODO: most of these proprieties are generic, substitute gsm. with phone. bug 1856959
+ //TODO: most of these properties are generic, substitute gsm. with phone. bug 1856959
/** Numeric name (MCC+MNC) of current registered operator.<p>
* Availability: when registered to a network. Result may be unreliable on
@@ -83,12 +83,12 @@
/** The MCC+MNC (mobile country code+mobile network code) of the
* provider of the SIM. 5 or 6 decimal digits.
- * Availablity: SIM state must be "READY"
+ * Availability: SIM state must be "READY"
*/
static String PROPERTY_ICC_OPERATOR_NUMERIC = "gsm.sim.operator.numeric";
/** PROPERTY_ICC_OPERATOR_ALPHA is also known as the SPN, or Service Provider Name.
- * Availablity: SIM state must be "READY"
+ * Availability: SIM state must be "READY"
*/
static String PROPERTY_ICC_OPERATOR_ALPHA = "gsm.sim.operator.alpha";
@@ -127,7 +127,7 @@
"ro.telephony.call_ring.multiple";
/**
- * The number of milli-seconds between CALL_RING notifications.
+ * The number of milliseconds between CALL_RING notifications.
*/
static final String PROPERTY_CALL_RING_DELAY = "ro.telephony.call_ring.delay";
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
index 0c591e4..8934037 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -867,26 +867,6 @@
mRuimRecords.setVoiceMessageWaiting(1, mwi);
}
- /**
- * Returns true if CDMA OTA Service Provisioning needs to be performed.
- */
- /* package */ boolean
- needsOtaServiceProvisioning() {
- String cdmaMin = getCdmaMin();
- boolean needsProvisioning;
- if (cdmaMin == null || (cdmaMin.length() < 6)) {
- if (DBG) Log.d(LOG_TAG, "needsOtaServiceProvisioning: illegal cdmaMin='"
- + cdmaMin + "' assume provisioning needed.");
- needsProvisioning = true;
- } else {
- needsProvisioning = (cdmaMin.equals(UNACTIVATED_MIN_VALUE)
- || cdmaMin.substring(0,6).equals(UNACTIVATED_MIN2_VALUE))
- || SystemProperties.getBoolean("test_cdma_setup", false);
- }
- if (DBG) Log.d(LOG_TAG, "needsOtaServiceProvisioning: ret=" + needsProvisioning);
- return needsProvisioning;
- }
-
@Override
public void exitEmergencyCallbackMode() {
if (mWakeLock.isHeld()) {
@@ -1180,6 +1160,26 @@
mSMS.setCellBroadcastConfig(configValuesArray, response);
}
+ /**
+ * Returns true if OTA Service Provisioning needs to be performed.
+ */
+ @Override
+ public boolean needsOtaServiceProvisioning() {
+ String cdmaMin = getCdmaMin();
+ boolean needsProvisioning;
+ if (cdmaMin == null || (cdmaMin.length() < 6)) {
+ if (DBG) Log.d(LOG_TAG, "needsOtaServiceProvisioning: illegal cdmaMin='"
+ + cdmaMin + "' assume provisioning needed.");
+ needsProvisioning = true;
+ } else {
+ needsProvisioning = (cdmaMin.equals(UNACTIVATED_MIN_VALUE)
+ || cdmaMin.substring(0,6).equals(UNACTIVATED_MIN2_VALUE))
+ || SystemProperties.getBoolean("test_cdma_setup", false);
+ }
+ if (DBG) Log.d(LOG_TAG, "needsOtaServiceProvisioning: ret=" + needsProvisioning);
+ return needsProvisioning;
+ }
+
private static final String IS683A_FEATURE_CODE = "*228";
private static final int IS683A_FEATURE_CODE_NUM_DIGITS = 4;
private static final int IS683A_SYS_SEL_CODE_NUM_DIGITS = 2;
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
index ed93aea..1b08aed 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
@@ -51,7 +51,6 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
-import java.lang.Boolean;
final class CdmaSMSDispatcher extends SMSDispatcher {
@@ -75,6 +74,7 @@
* @param ar AsyncResult passed into the message handler. ar.result should
* be a String representing the status report PDU, as ASCII hex.
*/
+ @Override
protected void handleStatusReport(AsyncResult ar) {
Log.d(TAG, "handleStatusReport is a special GSM function, should never be called in CDMA!");
}
@@ -97,6 +97,7 @@
}
/** {@inheritDoc} */
+ @Override
protected int dispatchMessage(SmsMessageBase smsb) {
// If sms is null, means there was a parsing error.
@@ -176,7 +177,7 @@
* TODO(cleanup): Why are we using a getter method for this
* (and for so many other sms fields)? Trivial getters and
* setters like this are direct violations of the style guide.
- * If the purpose is to protect agaist writes (by not
+ * If the purpose is to protect against writes (by not
* providing a setter) then any protection is illusory (and
* hence bad) for cases where the values are not primitives,
* such as this call for the header. Since this is an issue
@@ -340,6 +341,7 @@
}
/** {@inheritDoc} */
+ @Override
protected void sendData(String destAddr, String scAddr, int destPort,
byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) {
SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu(
@@ -348,6 +350,7 @@
}
/** {@inheritDoc} */
+ @Override
protected void sendText(String destAddr, String scAddr, String text,
PendingIntent sentIntent, PendingIntent deliveryIntent) {
SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu(
@@ -356,6 +359,7 @@
}
/** {@inheritDoc} */
+ @Override
protected void sendMultipartText(String destAddr, String scAddr,
ArrayList<String> parts, ArrayList<PendingIntent> sentIntents,
ArrayList<PendingIntent> deliveryIntents) {
@@ -364,7 +368,7 @@
* TODO(cleanup): There is no real code difference between
* this and the GSM version, and hence it should be moved to
* the base class or consolidated somehow, provided calling
- * the proper submitpdu stuff can be arranged.
+ * the proper submit pdu stuff can be arranged.
*/
int refNumber = getNextConcatenatedRef() & 0x00FF;
@@ -437,8 +441,9 @@
}
/** {@inheritDoc} */
+ @Override
protected void sendSms(SmsTracker tracker) {
- HashMap map = tracker.mData;
+ HashMap<String, Object> map = tracker.mData;
byte smsc[] = (byte[]) map.get("smsc");
byte pdu[] = (byte[]) map.get("pdu");
@@ -449,11 +454,13 @@
}
/** {@inheritDoc} */
+ @Override
protected void sendMultipartSms (SmsTracker tracker) {
Log.d(TAG, "TODO: CdmaSMSDispatcher.sendMultipartSms not implemented");
}
/** {@inheritDoc} */
+ @Override
protected void acknowledgeLastIncomingSms(boolean success, int result, Message response){
// FIXME unit test leaves cm == null. this should change
@@ -474,16 +481,19 @@
}
/** {@inheritDoc} */
+ @Override
protected void activateCellBroadcastSms(int activate, Message response) {
mCm.setCdmaBroadcastActivation((activate == 0), response);
}
/** {@inheritDoc} */
+ @Override
protected void getCellBroadcastSmsConfig(Message response) {
mCm.getCdmaBroadcastConfig(response);
}
/** {@inheritDoc} */
+ @Override
protected void setCellBroadcastConfig(int[] configValuesArray, Message response) {
mCm.setCdmaBroadcastConfig(configValuesArray, response);
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimSmsInterfaceManager.java b/telephony/java/com/android/internal/telephony/cdma/RuimSmsInterfaceManager.java
index cfcfd98..a9df375 100644
--- a/telephony/java/com/android/internal/telephony/cdma/RuimSmsInterfaceManager.java
+++ b/telephony/java/com/android/internal/telephony/cdma/RuimSmsInterfaceManager.java
@@ -67,8 +67,7 @@
ar = (AsyncResult)msg.obj;
synchronized (mLock) {
if (ar.exception == null) {
- mSms = (List<SmsRawData>)
- buildValidRawData((ArrayList<byte[]>) ar.result);
+ mSms = buildValidRawData((ArrayList<byte[]>) ar.result);
} else {
if(DBG) log("Cannot load Sms records");
if (mSms != null)
diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
index b50502c..65d87f5 100755
--- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
@@ -18,11 +18,8 @@
import android.os.Parcel;
import android.os.SystemProperties;
-import android.text.format.Time;
import android.util.Config;
import android.util.Log;
-import com.android.internal.telephony.EncodeException;
-import com.android.internal.telephony.GsmAlphabet;
import com.android.internal.telephony.IccUtils;
import com.android.internal.telephony.SmsHeader;
import com.android.internal.telephony.SmsMessageBase;
@@ -33,7 +30,6 @@
import com.android.internal.telephony.cdma.sms.UserData;
import com.android.internal.util.HexDump;
-import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@@ -58,7 +54,7 @@
/**
* TODO(cleanup): internally returning null in many places makes
* debugging very hard (among many other reasons) and should be made
- * more meaningful (replaced with execptions for example). Null
+ * more meaningful (replaced with exceptions for example). Null
* returns should only occur at the very outside of the module/class
* scope.
*/
@@ -287,7 +283,7 @@
* @param destAddr Address of the recipient.
* @param message String representation of the message payload.
* @param statusReportRequested Indicates whether a report is requested for this message.
- * @param headerData Array containing the data for the User Data Header, preceded
+ * @param smsHeader Array containing the data for the User Data Header, preceded
* by the Element Identifiers.
* @return a <code>SubmitPdu</code> containing the encoded SC
* address, if applicable, and the encoded message.
@@ -355,7 +351,7 @@
* Get an SMS-SUBMIT PDU for a data message to a destination address & port
*
* @param destAddr the address of the destination for the message
- * @param userDara the data for the message
+ * @param userData the data for the message
* @param statusReportRequested Indicates whether a report is requested for this message.
* @return a <code>SubmitPdu</code> containing the encoded SC
* address, if applicable, and the encoded message.
@@ -614,7 +610,7 @@
* incrementing within the range 1..65535 remembering the state
* via a persistent system property. (See C.S0015-B, v2.0,
* 4.3.1.5) Since this routine is expected to be accessed via via
- * binder-call, and hence should be threadsafe, it has been
+ * binder-call, and hence should be thread-safe, it has been
* synchronized.
*/
private synchronized static int getNextMessageId() {
diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
index c7032ac..e9fea55 100644
--- a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
@@ -21,7 +21,6 @@
import static android.telephony.SmsMessage.MAX_USER_DATA_BYTES_WITH_HEADER;
import android.util.Log;
-import android.util.SparseIntArray;
import android.telephony.SmsMessage;
@@ -30,10 +29,8 @@
import com.android.internal.telephony.IccUtils;
import com.android.internal.telephony.GsmAlphabet;
import com.android.internal.telephony.SmsHeader;
-import com.android.internal.telephony.cdma.sms.UserData;
import com.android.internal.telephony.SmsMessageBase.TextEncodingDetails;
-import com.android.internal.util.HexDump;
import com.android.internal.util.BitwiseInputStream;
import com.android.internal.util.BitwiseOutputStream;
@@ -45,13 +42,13 @@
private final static String LOG_TAG = "SMS";
/**
- * Bearer Data Subparameter Indentifiers
+ * Bearer Data Subparameter Identifiers
* (See 3GPP2 C.S0015-B, v2.0, table 4.5-1)
* NOTE: Commented subparameter types are not implemented.
*/
private final static byte SUBPARAM_MESSAGE_IDENTIFIER = 0x00;
private final static byte SUBPARAM_USER_DATA = 0x01;
- private final static byte SUBPARAM_USER_REPONSE_CODE = 0x02;
+ private final static byte SUBPARAM_USER_RESPONSE_CODE = 0x02;
private final static byte SUBPARAM_MESSAGE_CENTER_TIME_STAMP = 0x03;
private final static byte SUBPARAM_VALIDITY_PERIOD_ABSOLUTE = 0x04;
private final static byte SUBPARAM_VALIDITY_PERIOD_RELATIVE = 0x05;
@@ -405,7 +402,7 @@
/**
* Calculate the message text encoding length, fragmentation, and other details.
*
- * @param force ignore (but still count) illegal characters if true
+ * @param force7BitEncoding ignore (but still count) illegal characters if true
* @return septet count, or -1 on failure
*/
public static TextEncodingDetails calcTextEncodingDetails(CharSequence msg,
@@ -695,7 +692,7 @@
/*
* TODO(cleanup): CdmaSmsAddress encoding should make use of
* CdmaSmsAddress.parse provided that DTMF encoding is unified,
- * and the difference in 4bit vs 8bit is resolved.
+ * and the difference in 4-bit vs. 8-bit is resolved.
*/
private static void encodeCdmaSmsAddress(CdmaSmsAddress addr) throws CodingException {
@@ -802,9 +799,9 @@
* Create serialized representation for BearerData object.
* (See 3GPP2 C.R1001-F, v1.0, section 4.5 for layout details)
*
- * @param bearerData an instance of BearerData.
+ * @param bData an instance of BearerData.
*
- * @return data byta array of raw encoded SMS bearer data.
+ * @return data byte array of raw encoded SMS bearer data.
*/
public static byte[] encode(BearerData bData) {
bData.hasUserDataHeader = ((bData.userData != null) &&
@@ -914,7 +911,7 @@
private static String decodeUtf16(byte[] data, int offset, int numFields)
throws CodingException
{
- // Start reading from the next 16-bit aligned boundry after offset.
+ // Start reading from the next 16-bit aligned boundary after offset.
int padding = offset % 2;
numFields -= (offset + padding) / 2;
try {
@@ -960,7 +957,7 @@
private static String decode7bitGsm(byte[] data, int offset, int numFields)
throws CodingException
{
- // Start reading from the next 7-bit aligned boundry after offset.
+ // Start reading from the next 7-bit aligned boundary after offset.
int offsetBits = offset * 8;
int offsetSeptets = (offsetBits + 6) / 7;
numFields -= offsetSeptets;
@@ -1553,7 +1550,7 @@
case SUBPARAM_USER_DATA:
decodeSuccess = decodeUserData(bData, inStream);
break;
- case SUBPARAM_USER_REPONSE_CODE:
+ case SUBPARAM_USER_RESPONSE_CODE:
decodeSuccess = decodeUserResponseCode(bData, inStream);
break;
case SUBPARAM_REPLY_OPTION:
diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java b/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java
index 0dcacc1..a67327a 100644
--- a/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java
@@ -17,7 +17,7 @@
package com.android.internal.telephony.cdma.sms;
-public final class SmsEnvelope{
+public final class SmsEnvelope {
/**
* Message Types
* (See 3GPP2 C.S0015-B 3.4.1)
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
index d720516..f09ff06 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
@@ -57,6 +57,7 @@
* @param ar AsyncResult passed into the message handler. ar.result should
* be a String representing the status report PDU, as ASCII hex.
*/
+ @Override
protected void handleStatusReport(AsyncResult ar) {
String pduString = (String) ar.result;
SmsMessage sms = SmsMessage.newFromCDS(pduString);
@@ -85,6 +86,7 @@
/** {@inheritDoc} */
+ @Override
protected int dispatchMessage(SmsMessageBase smsb) {
// If sms is null, means there was a parsing error.
@@ -152,6 +154,7 @@
}
/** {@inheritDoc} */
+ @Override
protected void sendData(String destAddr, String scAddr, int destPort,
byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) {
SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu(
@@ -160,6 +163,7 @@
}
/** {@inheritDoc} */
+ @Override
protected void sendText(String destAddr, String scAddr, String text,
PendingIntent sentIntent, PendingIntent deliveryIntent) {
SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu(
@@ -168,6 +172,7 @@
}
/** {@inheritDoc} */
+ @Override
protected void sendMultipartText(String destinationAddress, String scAddress,
ArrayList<String> parts, ArrayList<PendingIntent> sentIntents,
ArrayList<PendingIntent> deliveryIntents) {
@@ -307,8 +312,9 @@
}
/** {@inheritDoc} */
+ @Override
protected void sendSms(SmsTracker tracker) {
- HashMap map = tracker.mData;
+ HashMap<String, Object> map = tracker.mData;
byte smsc[] = (byte[]) map.get("smsc");
byte pdu[] = (byte[]) map.get("pdu");
@@ -323,12 +329,13 @@
*
* @param tracker holds the multipart Sms tracker ready to be sent
*/
+ @Override
protected void sendMultipartSms (SmsTracker tracker) {
ArrayList<String> parts;
ArrayList<PendingIntent> sentIntents;
ArrayList<PendingIntent> deliveryIntents;
- HashMap map = tracker.mData;
+ HashMap<String, Object> map = tracker.mData;
String destinationAddress = (String) map.get("destination");
String scAddress = (String) map.get("scaddress");
@@ -343,6 +350,7 @@
}
/** {@inheritDoc} */
+ @Override
protected void acknowledgeLastIncomingSms(boolean success, int result, Message response){
// FIXME unit test leaves cm == null. this should change
if (mCm != null) {
@@ -351,6 +359,7 @@
}
/** {@inheritDoc} */
+ @Override
protected void activateCellBroadcastSms(int activate, Message response) {
// Unless CBS is implemented for GSM, this point should be unreachable.
Log.e(TAG, "Error! The functionality cell broadcast sms is not implemented for GSM.");
@@ -358,6 +367,7 @@
}
/** {@inheritDoc} */
+ @Override
protected void getCellBroadcastSmsConfig(Message response){
// Unless CBS is implemented for GSM, this point should be unreachable.
Log.e(TAG, "Error! The functionality cell broadcast sms is not implemented for GSM.");
@@ -365,6 +375,7 @@
}
/** {@inheritDoc} */
+ @Override
protected void setCellBroadcastConfig(int[] configValuesArray, Message response) {
// Unless CBS is implemented for GSM, this point should be unreachable.
Log.e(TAG, "Error! The functionality cell broadcast sms is not implemented for GSM.");
diff --git a/telephony/java/com/android/internal/telephony/gsm/SimSmsInterfaceManager.java b/telephony/java/com/android/internal/telephony/gsm/SimSmsInterfaceManager.java
index 2028ca4..f000d79 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SimSmsInterfaceManager.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SimSmsInterfaceManager.java
@@ -86,6 +86,7 @@
public void dispose() {
}
+ @Override
protected void finalize() {
try {
super.finalize();
@@ -191,6 +192,7 @@
return mSms;
}
+ @Override
protected void log(String msg) {
Log.d(LOG_TAG, "[SimSmsInterfaceManager] " + msg);
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
index 12c6b88..487372e 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
@@ -26,7 +26,6 @@
import com.android.internal.telephony.GsmAlphabet;
import com.android.internal.telephony.SmsHeader;
import com.android.internal.telephony.SmsMessageBase;
-import com.android.internal.telephony.SmsMessageBase.TextEncodingDetails;
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
@@ -45,7 +44,7 @@
* A Short Message Service message.
*
*/
-public class SmsMessage extends SmsMessageBase{
+public class SmsMessage extends SmsMessageBase {
static final String LOG_TAG = "GSM";
private MessageClass messageClass;
@@ -311,7 +310,7 @@
// the receiver's SIM card. You can then send messages to yourself
// (on a phone with this change) and they'll end up on the SIM card.
bo.write(0x00);
- } else { //assume UCS-2
+ } else { // assume UCS-2
if ((0xff & userData[0]) > MAX_USER_DATA_BYTES) {
// Message too long
return null;
@@ -377,7 +376,7 @@
* @param destinationAddress the address of the destination for the message
* @param destinationPort the port to deliver the message to at the
* destination
- * @param data the dat for the message
+ * @param data the data for the message
* @return a <code>SubmitPdu</code> containing the encoded SC
* address, if applicable, and the encoded message.
* Returns null on encode error.
@@ -482,7 +481,7 @@
return bo;
}
- static class PduParser {
+ private static class PduParser {
byte pdu[];
int cur;
SmsHeader userDataHeader;
@@ -490,10 +489,6 @@
int mUserDataSeptetPadding;
int mUserDataSize;
- PduParser(String s) {
- this(IccUtils.hexStringToBytes(s));
- }
-
PduParser(byte[] pdu) {
this.pdu = pdu;
cur = 0;
@@ -545,7 +540,7 @@
GsmSmsAddress ret;
// "The Address-Length field is an integer representation of
- // the number field, i.e. excludes any semi octet containing only
+ // the number field, i.e. excludes any semi-octet containing only
// fill bits."
// The TOA field is not included as part of this
int addressLength = pdu[cur] & 0xff;
@@ -573,7 +568,7 @@
int second = IccUtils.gsmBcdByteToInt(pdu[cur++]);
// For the timezone, the most significant bit of the
- // least signficant nibble is the sign byte
+ // least significant nibble is the sign byte
// (meaning the max range of this field is 79 quarter-hours,
// which is more than enough)
@@ -632,7 +627,7 @@
/*
* Here we just create the user data length to be the remainder of
* the pdu minus the user data header, since userDataLength means
- * the number of uncompressed sepets.
+ * the number of uncompressed septets.
*/
bufferLen = pdu.length - offset;
} else {
@@ -671,10 +666,10 @@
}
/**
- * Returns the number of padding bits at the begining of the user data
+ * Returns the number of padding bits at the beginning of the user data
* array before the start of the septets.
*
- * @return the number of padding bits at the begining of the user data
+ * @return the number of padding bits at the beginning of the user data
* array before the start of the septets
*/
int getUserDataSeptetPadding() {
@@ -694,7 +689,7 @@
XXX Not sure what this one is supposed to be doing, and no one is using
it.
String getUserDataGSM8bit() {
- // System.out.println("remainder of pud:" +
+ // System.out.println("remainder of pdu:" +
// HexDump.dumpHexString(pdu, cur, pdu.length - cur));
int count = pdu[cur++] & 0xff;
int size = pdu[cur++];
@@ -825,11 +820,13 @@
}
/** {@inheritDoc} */
+ @Override
public int getProtocolIdentifier() {
return protocolIdentifier;
}
/** {@inheritDoc} */
+ @Override
public boolean isReplace() {
return (protocolIdentifier & 0xc0) == 0x40
&& (protocolIdentifier & 0x3f) > 0
@@ -837,12 +834,14 @@
}
/** {@inheritDoc} */
+ @Override
public boolean isCphsMwiMessage() {
return ((GsmSmsAddress) originatingAddress).isCphsVoiceMessageClear()
|| ((GsmSmsAddress) originatingAddress).isCphsVoiceMessageSet();
}
/** {@inheritDoc} */
+ @Override
public boolean isMWIClearMessage() {
if (isMwi && (mwiSense == false)) {
return true;
@@ -853,6 +852,7 @@
}
/** {@inheritDoc} */
+ @Override
public boolean isMWISetMessage() {
if (isMwi && (mwiSense == true)) {
return true;
@@ -863,6 +863,7 @@
}
/** {@inheritDoc} */
+ @Override
public boolean isMwiDontStore() {
if (isMwi && mwiDontStore) {
return true;
@@ -882,31 +883,34 @@
}
/** {@inheritDoc} */
+ @Override
public int getStatus() {
return status;
}
/** {@inheritDoc} */
+ @Override
public boolean isStatusReportMessage() {
return isStatusReportMessage;
}
/** {@inheritDoc} */
+ @Override
public boolean isReplyPathPresent() {
return replyPathPresent;
}
/**
- * TS 27.005 3.1, <pdu> definition "In the case of SMS: 3GPP TS 24.011 [6]
+ * TS 27.005 3.1, <pdu> definition "In the case of SMS: 3GPP TS 24.011 [6]
* SC address followed by 3GPP TS 23.040 [3] TPDU in hexadecimal format:
* ME/TA converts each octet of TP data unit into two IRA character long
- * hexad number (e.g. octet with integer value 42 is presented to TE as two
+ * hex number (e.g. octet with integer value 42 is presented to TE as two
* characters 2A (IRA 50 and 65))" ...in the case of cell broadcast,
* something else...
*/
private void parsePdu(byte[] pdu) {
mPdu = pdu;
- // Log.d(LOG_TAG, "raw sms mesage:");
+ // Log.d(LOG_TAG, "raw sms message:");
// Log.d(LOG_TAG, s);
PduParser p = new PduParser(pdu);
@@ -1158,6 +1162,7 @@
/**
* {@inheritDoc}
*/
+ @Override
public MessageClass getMessageClass() {
return messageClass;
}
diff --git a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
index a120f52..fdcf78d 100644
--- a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
+++ b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
@@ -16,7 +16,6 @@
package com.android.internal.telephony.test;
-
import android.os.AsyncResult;
import android.os.HandlerThread;
import android.os.Looper;
@@ -27,7 +26,6 @@
import com.android.internal.telephony.CommandException;
import com.android.internal.telephony.CommandsInterface;
import com.android.internal.telephony.DataCallState;
-import com.android.internal.telephony.IccCard;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.UUSInfo;
import com.android.internal.telephony.gsm.CallFailCause;
@@ -335,7 +333,7 @@
/**
* (AsyncResult)response.obj).result will be an Integer representing
- * the sum of enabled serivice classes (sum of SERVICE_CLASS_*)
+ * the sum of enabled service classes (sum of SERVICE_CLASS_*)
*
* @param facility one of CB_FACILTY_*
* @param pin password or "" if not required
@@ -441,7 +439,7 @@
* returned message
* retMsg.obj = AsyncResult ar
* ar.exception carries exception on failure
- * ar.userObject contains the orignal value of result.obj
+ * ar.userObject contains the original value of result.obj
* ar.result contains a List of DriverCall
* The ar.result List is sorted by DriverCall.index
*/
@@ -468,7 +466,7 @@
* returned message
* retMsg.obj = AsyncResult ar
* ar.exception carries exception on failure
- * ar.userObject contains the orignal value of result.obj
+ * ar.userObject contains the original value of result.obj
* ar.result contains a List of DataCallState
*/
public void getDataCallList(Message result) {
@@ -479,7 +477,7 @@
* returned message
* retMsg.obj = AsyncResult ar
* ar.exception carries exception on failure
- * ar.userObject contains the orignal value of result.obj
+ * ar.userObject contains the original value of result.obj
* ar.result is null on success and failure
*
* CLIR_DEFAULT == on "use subscription default value"
@@ -496,7 +494,7 @@
* returned message
* retMsg.obj = AsyncResult ar
* ar.exception carries exception on failure
- * ar.userObject contains the orignal value of result.obj
+ * ar.userObject contains the original value of result.obj
* ar.result is null on success and failure
*
* CLIR_DEFAULT == on "use subscription default value"
@@ -513,7 +511,7 @@
* returned message
* retMsg.obj = AsyncResult ar
* ar.exception carries exception on failure
- * ar.userObject contains the orignal value of result.obj
+ * ar.userObject contains the original value of result.obj
* ar.result is String containing IMSI on success
*/
public void getIMSI(Message result) {
@@ -524,7 +522,7 @@
* returned message
* retMsg.obj = AsyncResult ar
* ar.exception carries exception on failure
- * ar.userObject contains the orignal value of result.obj
+ * ar.userObject contains the original value of result.obj
* ar.result is String containing IMEI on success
*/
public void getIMEI(Message result) {
@@ -535,7 +533,7 @@
* returned message
* retMsg.obj = AsyncResult ar
* ar.exception carries exception on failure
- * ar.userObject contains the orignal value of result.obj
+ * ar.userObject contains the original value of result.obj
* ar.result is String containing IMEISV on success
*/
public void getIMEISV(Message result) {
@@ -547,7 +545,7 @@
* returned message
* retMsg.obj = AsyncResult ar
* ar.exception carries exception on failure
- * ar.userObject contains the orignal value of result.obj
+ * ar.userObject contains the original value of result.obj
* ar.result is null on success and failure
*
* 3GPP 22.030 6.5.5
@@ -572,7 +570,7 @@
* "Releases all held calls or sets User Determined User Busy (UDUB)
* for a waiting call."
* ar.exception carries exception on failure
- * ar.userObject contains the orignal value of result.obj
+ * ar.userObject contains the original value of result.obj
* ar.result is null on success and failure
*/
public void hangupWaitingOrBackground (Message result) {
@@ -593,7 +591,7 @@
* the other (held or waiting) call."
*
* ar.exception carries exception on failure
- * ar.userObject contains the orignal value of result.obj
+ * ar.userObject contains the original value of result.obj
* ar.result is null on success and failure
*/
public void hangupForegroundResumeBackground (Message result) {
@@ -614,7 +612,7 @@
* the other (held or waiting) call."
*
* ar.exception carries exception on failure
- * ar.userObject contains the orignal value of result.obj
+ * ar.userObject contains the original value of result.obj
* ar.result is null on success and failure
*/
public void switchWaitingOrHoldingAndActive (Message result) {
@@ -634,7 +632,7 @@
* "Adds a held call to the conversation"
*
* ar.exception carries exception on failure
- * ar.userObject contains the orignal value of result.obj
+ * ar.userObject contains the original value of result.obj
* ar.result is null on success and failure
*/
public void conference (Message result) {
@@ -654,7 +652,7 @@
* "Connects the two calls and disconnects the subscriber from both calls"
*
* ar.exception carries exception on failure
- * ar.userObject contains the orignal value of result.obj
+ * ar.userObject contains the original value of result.obj
* ar.result is null on success and failure
*/
public void explicitCallTransfer (Message result) {
@@ -690,7 +688,7 @@
/**
*
* ar.exception carries exception on failure
- * ar.userObject contains the orignal value of result.obj
+ * ar.userObject contains the original value of result.obj
* ar.result is null on success and failure
*/
public void acceptCall (Message result) {
@@ -708,7 +706,7 @@
/**
* also known as UDUB
* ar.exception carries exception on failure
- * ar.userObject contains the orignal value of result.obj
+ * ar.userObject contains the original value of result.obj
* ar.result is null on success and failure
*/
public void rejectCall (Message result) {
@@ -785,7 +783,7 @@
*
* @param result is callback message
* ((AsyncResult)response.obj).result is an int[] with every
- * element representing one avialable BM_*_BAND
+ * element representing one available BM_*_BAND
*/
public void queryAvailableBandMode (Message result) {
int ret[] = new int [4];
@@ -844,7 +842,6 @@
ret[11] = null;
ret[12] = null;
ret[13] = null;
- ret[14] = null;
resultSuccess(result, ret);
}
@@ -895,7 +892,7 @@
/**
* ar.exception carries exception on failure
- * ar.userObject contains the orignal value of result.obj
+ * ar.userObject contains the original value of result.obj
* ar.result is null on success and failure
*/
public void sendDtmf(char c, Message result) {
@@ -904,7 +901,7 @@
/**
* ar.exception carries exception on failure
- * ar.userObject contains the orignal value of result.obj
+ * ar.userObject contains the original value of result.obj
* ar.result is null on success and failure
*/
public void startDtmf(char c, Message result) {
@@ -913,7 +910,7 @@
/**
* ar.exception carries exception on failure
- * ar.userObject contains the orignal value of result.obj
+ * ar.userObject contains the original value of result.obj
* ar.result is null on success and failure
*/
public void stopDtmf(Message result) {
@@ -922,7 +919,7 @@
/**
* ar.exception carries exception on failure
- * ar.userObject contains the orignal value of result.obj
+ * ar.userObject contains the original value of result.obj
* ar.result is null on success and failure
*/
public void sendBurstDtmf(String dtmfString, int on, int off, Message result) {
@@ -957,6 +954,7 @@
unimplemented(response);
}
+ @Deprecated
public void setupDefaultPDP(String apn, String user, String password, Message result) {
unimplemented(result);
}
@@ -968,9 +966,7 @@
public void deactivateDataCall(int cid, Message result) {unimplemented(result);}
- /**
- * @deprecated
- */
+ @Deprecated
public void deactivateDefaultPDP(int cid, Message result) {unimplemented(result);}
public void setPreferredNetworkType(int networkType , Message result) {
@@ -1047,7 +1043,7 @@
}
/**
- * parameters equivilient to 27.007 AT+CRSM command
+ * parameters equivalent to 27.007 AT+CRSM command
* response.obj will be an AsyncResult
* response.obj.userObj will be a SimIoResult on success
*/
diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/GsmAlphabetTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/GsmAlphabetTest.java
index 3a9c511..a6b9a2a 100644
--- a/telephony/tests/telephonytests/src/com/android/internal/telephony/GsmAlphabetTest.java
+++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/GsmAlphabetTest.java
@@ -51,7 +51,7 @@
// '@' maps to char 0
assertEquals(0, GsmAlphabet.charToGsm('@'));
- // `a (a with grave accent) maps to last GSM charater
+ // `a (a with grave accent) maps to last GSM character
assertEquals(0x7f, GsmAlphabet.charToGsm('\u00e0'));
//
diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/GsmSmsTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/GsmSmsTest.java
index 3103fc1..215c6ce 100644
--- a/telephony/tests/telephonytests/src/com/android/internal/telephony/GsmSmsTest.java
+++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/GsmSmsTest.java
@@ -24,8 +24,6 @@
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Log;
-
public class GsmSmsTest extends AndroidTestCase {
@SmallTest
diff --git a/telephony/tests/telephonytests/src/android/telephony/PhoneNumberUtilsTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
similarity index 100%
rename from telephony/tests/telephonytests/src/android/telephony/PhoneNumberUtilsTest.java
rename to telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
diff --git a/telephony/tests/telephonytests/src/android/telephony/PhoneNumberWatcherTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberWatcherTest.java
similarity index 100%
rename from telephony/tests/telephonytests/src/android/telephony/PhoneNumberWatcherTest.java
rename to telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberWatcherTest.java
diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/gsm/GSMPhoneTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/gsm/GSMPhoneTest.java
index b96743a..485542b 100644
--- a/telephony/tests/telephonytests/src/com/android/internal/telephony/gsm/GSMPhoneTest.java
+++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/gsm/GSMPhoneTest.java
@@ -18,27 +18,21 @@
import android.os.AsyncResult;
import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
import android.os.Message;
-import android.os.Process;
import android.telephony.ServiceState;
import android.test.AndroidTestCase;
import android.test.PerformanceTestCase;
-import android.util.Log;
import com.android.internal.telephony.Call;
import com.android.internal.telephony.CallStateException;
import com.android.internal.telephony.Connection;
import com.android.internal.telephony.MmiCode;
import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.TestPhoneNotifier;
import com.android.internal.telephony.gsm.CallFailCause;
import com.android.internal.telephony.gsm.GSMPhone;
import com.android.internal.telephony.gsm.GSMTestHandler;
import com.android.internal.telephony.gsm.GsmMmiCode;
import com.android.internal.telephony.gsm.SuppServiceNotification;
-import com.android.internal.telephony.test.SimulatedCommands;
import com.android.internal.telephony.test.SimulatedRadioControl;
import java.util.List;
diff --git a/test-runner/Android.mk b/test-runner/Android.mk
index 962e96c..6d81b71 100644
--- a/test-runner/Android.mk
+++ b/test-runner/Android.mk
@@ -20,7 +20,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_JAVA_LIBRARIES := core framework
+LOCAL_JAVA_LIBRARIES := core core-junit framework
LOCAL_MODULE:= android.test.runner
diff --git a/test-runner/src/android/test/RenamingDelegatingContext.java b/test-runner/src/android/test/RenamingDelegatingContext.java
index 973b9f2..eee3ad7 100644
--- a/test-runner/src/android/test/RenamingDelegatingContext.java
+++ b/test-runner/src/android/test/RenamingDelegatingContext.java
@@ -21,6 +21,7 @@
import android.content.Context;
import android.content.ContextWrapper;
import android.content.ContentProvider;
+import android.database.DatabaseErrorHandler;
import android.database.sqlite.SQLiteDatabase;
import android.os.FileUtils;
import android.util.Log;
@@ -148,6 +149,17 @@
}
@Override
+ public SQLiteDatabase openOrCreateDatabase(String name,
+ int mode, SQLiteDatabase.CursorFactory factory, DatabaseErrorHandler errorHandler) {
+ final String internalName = renamedFileName(name);
+ if (!mDatabaseNames.contains(name)) {
+ mDatabaseNames.add(name);
+ mFileContext.deleteDatabase(internalName);
+ }
+ return mFileContext.openOrCreateDatabase(internalName, mode, factory, errorHandler);
+ }
+
+ @Override
public boolean deleteDatabase(String name) {
if (mDatabaseNames.contains(name)) {
mDatabaseNames.remove(name);
diff --git a/test-runner/src/android/test/ServiceTestCase.java b/test-runner/src/android/test/ServiceTestCase.java
index fcb9d55..d9262f6 100644
--- a/test-runner/src/android/test/ServiceTestCase.java
+++ b/test-runner/src/android/test/ServiceTestCase.java
@@ -147,9 +147,6 @@
* @param intent The Intent as if supplied to {@link android.content.Context#startService}.
*/
protected void startService(Intent intent) {
- assertFalse(mServiceStarted);
- assertFalse(mServiceBound);
-
if (!mServiceAttached) {
setupService();
}
@@ -159,7 +156,7 @@
mService.onCreate();
mServiceCreated = true;
}
- mService.onStart(intent, mServiceId);
+ mService.onStartCommand(intent, 0, mServiceId);
mServiceStarted = true;
}
@@ -183,9 +180,6 @@
* @return Return an IBinder for making further calls into the Service.
*/
protected IBinder bindService(Intent intent) {
- assertFalse(mServiceStarted);
- assertFalse(mServiceBound);
-
if (!mServiceAttached) {
setupService();
}
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index ffd757c..c31c9cc 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -29,6 +29,7 @@
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.content.res.Resources;
+import android.database.DatabaseErrorHandler;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
@@ -184,6 +185,12 @@
}
@Override
+ public SQLiteDatabase openOrCreateDatabase(String file, int mode,
+ SQLiteDatabase.CursorFactory factory, DatabaseErrorHandler errorHandler) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public File getDatabasePath(String name) {
throw new UnsupportedOperationException();
}
diff --git a/test-runner/src/android/test/mock/MockCursor.java b/test-runner/src/android/test/mock/MockCursor.java
index 9b1c0ef..baa150a 100644
--- a/test-runner/src/android/test/mock/MockCursor.java
+++ b/test-runner/src/android/test/mock/MockCursor.java
@@ -178,36 +178,11 @@
}
@SuppressWarnings("deprecation")
- public boolean commitUpdates() {
- throw new UnsupportedOperationException("unimplemented mock method");
- }
-
- @SuppressWarnings("deprecation")
- public boolean commitUpdates(Map<? extends Long, ? extends Map<String, Object>> values) {
- throw new UnsupportedOperationException("unimplemented mock method");
- }
-
- @SuppressWarnings("deprecation")
- public boolean hasUpdates() {
- throw new UnsupportedOperationException("unimplemented mock method");
- }
-
- @SuppressWarnings("deprecation")
public void setNotificationUri(ContentResolver cr, Uri uri) {
throw new UnsupportedOperationException("unimplemented mock method");
}
@SuppressWarnings("deprecation")
- public boolean supportsUpdates() {
- throw new UnsupportedOperationException("unimplemented mock method");
- }
-
- @SuppressWarnings("deprecation")
- public boolean deleteRow() {
- throw new UnsupportedOperationException("unimplemented mock method");
- }
-
- @SuppressWarnings("deprecation")
public void unregisterContentObserver(ContentObserver observer) {
throw new UnsupportedOperationException("unimplemented mock method");
}
@@ -217,48 +192,7 @@
throw new UnsupportedOperationException("unimplemented mock method");
}
- @SuppressWarnings("deprecation")
- public boolean updateBlob(int columnIndex, byte[] value) {
- throw new UnsupportedOperationException("unimplemented mock method");
- }
-
- @SuppressWarnings("deprecation")
- public boolean updateDouble(int columnIndex, double value) {
- throw new UnsupportedOperationException("unimplemented mock method");
- }
-
- @SuppressWarnings("deprecation")
- public boolean updateFloat(int columnIndex, float value) {
- throw new UnsupportedOperationException("unimplemented mock method");
- }
-
- @SuppressWarnings("deprecation")
- public boolean updateInt(int columnIndex, int value) {
- throw new UnsupportedOperationException("unimplemented mock method");
- }
-
- @SuppressWarnings("deprecation")
- public boolean updateLong(int columnIndex, long value) {
- throw new UnsupportedOperationException("unimplemented mock method");
- }
-
- @SuppressWarnings("deprecation")
- public boolean updateShort(int columnIndex, short value) {
- throw new UnsupportedOperationException("unimplemented mock method");
- }
-
- @SuppressWarnings("deprecation")
- public boolean updateString(int columnIndex, String value) {
- throw new UnsupportedOperationException("unimplemented mock method");
- }
-
- @SuppressWarnings("deprecation")
- public boolean updateToNull(int columnIndex) {
- throw new UnsupportedOperationException("unimplemented mock method");
- }
-
- @SuppressWarnings("deprecation")
- public void abortUpdates() {
+ public int getType(int columnIndex) {
throw new UnsupportedOperationException("unimplemented mock method");
}
}
\ No newline at end of file
diff --git a/test-runner/src/android/test/suitebuilder/TestGrouping.java b/test-runner/src/android/test/suitebuilder/TestGrouping.java
index df6da70..a2b94ff 100644
--- a/test-runner/src/android/test/suitebuilder/TestGrouping.java
+++ b/test-runner/src/android/test/suitebuilder/TestGrouping.java
@@ -46,6 +46,8 @@
*/
public class TestGrouping {
+ private static final String LOG_TAG = "TestGrouping";
+
SortedSet<Class<? extends TestCase>> testCaseClasses;
public static final Comparator<Class<? extends TestCase>> SORT_BY_SIMPLE_NAME
@@ -114,7 +116,7 @@
for (String packageName : packageNames) {
List<Class<? extends TestCase>> addedClasses = testCaseClassesInPackage(packageName);
if (addedClasses.isEmpty()) {
- Log.w("TestGrouping", "Invalid Package: '" + packageName
+ Log.w(LOG_TAG, "Invalid Package: '" + packageName
+ "' could not be found or has no tests");
}
testCaseClasses.addAll(addedClasses);
@@ -234,6 +236,10 @@
}
}
}
+ Log.i(LOG_TAG, String.format(
+ "TestCase class %s is missing a public constructor with no parameters " +
+ "or a single String parameter - skipping",
+ aClass.getName()));
return false;
}
}
diff --git a/test-runner/tests/src/android/test/suitebuilder/TestGroupingTest.java b/test-runner/tests/src/android/test/suitebuilder/TestGroupingTest.java
new file mode 100644
index 0000000..f4477d1
--- /dev/null
+++ b/test-runner/tests/src/android/test/suitebuilder/TestGroupingTest.java
@@ -0,0 +1,47 @@
+/*
+ * 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.test.suitebuilder;
+
+import java.util.List;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit tests for {@link TestGrouping}
+ */
+public class TestGroupingTest extends TestCase {
+
+ private TestGrouping mGrouping;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mGrouping = new TestGrouping(TestGrouping.SORT_BY_SIMPLE_NAME);
+ }
+
+ /**
+ * Verifies that TestCases with no public constructor are not loaded.
+ * Relies on fixture classes in android.test.suitebuilder.examples.constructor
+ */
+ public void testGetTests_noPublicConstructor() {
+ mGrouping.addPackagesRecursive("android.test.suitebuilder.examples.constructor");
+ List<TestMethod> tests = mGrouping.getTests();
+ // only the PublicConstructorTest's test method should be present
+ assertEquals(1, tests.size());
+ assertEquals("testPublicConstructor", tests.get(0).getName());
+ }
+}
diff --git a/test-runner/tests/src/android/test/suitebuilder/examples/constructor/NoPublicConstructorTest.java b/test-runner/tests/src/android/test/suitebuilder/examples/constructor/NoPublicConstructorTest.java
new file mode 100644
index 0000000..d7909a1
--- /dev/null
+++ b/test-runner/tests/src/android/test/suitebuilder/examples/constructor/NoPublicConstructorTest.java
@@ -0,0 +1,35 @@
+/*
+ * 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.test.suitebuilder.examples.constructor;
+
+import junit.framework.TestCase;
+
+/**
+ * A {@link TestCase} which should not be loaded since it has non-public constructors with no args.
+ */
+public class NoPublicConstructorTest extends TestCase {
+
+ NoPublicConstructorTest() {
+ }
+
+ public NoPublicConstructorTest(String foo, String foo2) {
+ }
+
+ public void testNotRun() {
+ fail("method in NoPublicConstructorTest run unexpectedly");
+ }
+}
diff --git a/test-runner/tests/src/android/test/suitebuilder/examples/constructor/ProtectedConstructorTest.java b/test-runner/tests/src/android/test/suitebuilder/examples/constructor/ProtectedConstructorTest.java
new file mode 100644
index 0000000..d2862fd
--- /dev/null
+++ b/test-runner/tests/src/android/test/suitebuilder/examples/constructor/ProtectedConstructorTest.java
@@ -0,0 +1,33 @@
+/*
+ * 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.test.suitebuilder.examples.constructor;
+
+import junit.framework.TestCase;
+
+/**
+ * A protected constructor test case that should not be loaded.
+ */
+public class ProtectedConstructorTest extends TestCase {
+
+ protected ProtectedConstructorTest() {
+ }
+
+ public void testNotRun() {
+ fail("method in ProtectedConstructorTest run unexpectedly");
+ }
+
+}
diff --git a/graphics/java/android/renderscript/Vector2f.java b/test-runner/tests/src/android/test/suitebuilder/examples/constructor/PublicConstructorTest.java
similarity index 65%
copy from graphics/java/android/renderscript/Vector2f.java
copy to test-runner/tests/src/android/test/suitebuilder/examples/constructor/PublicConstructorTest.java
index 567d57fa..a11e25d 100644
--- a/graphics/java/android/renderscript/Vector2f.java
+++ b/test-runner/tests/src/android/test/suitebuilder/examples/constructor/PublicConstructorTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,24 +14,15 @@
* limitations under the License.
*/
-package android.renderscript;
+package android.test.suitebuilder.examples.constructor;
-import java.lang.Math;
-import android.util.Log;
-
+import junit.framework.TestCase;
/**
- * @hide
- *
- **/
-public class Vector2f {
- public Vector2f() {
+ * A public constructor test case that should be loaded.
+ */
+public class PublicConstructorTest extends TestCase {
+
+ public void testPublicConstructor() {
}
-
- public float x;
- public float y;
}
-
-
-
-
diff --git a/tests/BrowserTestPlugin/jni/PluginObject.h b/tests/BrowserTestPlugin/jni/PluginObject.h
index a058d4a..037367e 100644
--- a/tests/BrowserTestPlugin/jni/PluginObject.h
+++ b/tests/BrowserTestPlugin/jni/PluginObject.h
@@ -65,7 +65,7 @@
public:
SubPlugin(NPP inst) : m_inst(inst) {}
virtual ~SubPlugin() {}
- virtual int16 handleEvent(const ANPEvent* evt) = 0;
+ virtual int16_t handleEvent(const ANPEvent* evt) = 0;
NPP inst() const { return m_inst; }
diff --git a/tests/BrowserTestPlugin/jni/event/EventPlugin.cpp b/tests/BrowserTestPlugin/jni/event/EventPlugin.cpp
index 2eff394..91f1b3d 100644
--- a/tests/BrowserTestPlugin/jni/event/EventPlugin.cpp
+++ b/tests/BrowserTestPlugin/jni/event/EventPlugin.cpp
@@ -138,7 +138,7 @@
browser->memfree(beginMem);
}
-int16 EventPlugin::handleEvent(const ANPEvent* evt) {
+int16_t EventPlugin::handleEvent(const ANPEvent* evt) {
switch (evt->eventType) {
case kDraw_ANPEventType: {
diff --git a/tests/BrowserTestPlugin/jni/event/EventPlugin.h b/tests/BrowserTestPlugin/jni/event/EventPlugin.h
index 88b7c9d..043be85 100644
--- a/tests/BrowserTestPlugin/jni/event/EventPlugin.h
+++ b/tests/BrowserTestPlugin/jni/event/EventPlugin.h
@@ -32,7 +32,7 @@
public:
EventPlugin(NPP inst);
virtual ~EventPlugin();
- virtual int16 handleEvent(const ANPEvent* evt);
+ virtual int16_t handleEvent(const ANPEvent* evt);
private:
void drawPlugin(const ANPBitmap& bitmap, const ANPRectI& clip);
diff --git a/tests/BrowserTestPlugin/jni/main.cpp b/tests/BrowserTestPlugin/jni/main.cpp
index 402a7e2..511180c 100644
--- a/tests/BrowserTestPlugin/jni/main.cpp
+++ b/tests/BrowserTestPlugin/jni/main.cpp
@@ -34,19 +34,19 @@
NPNetscapeFuncs* browser;
#define EXPORT __attribute__((visibility("default")))
-NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc,
+NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc,
char* argn[], char* argv[], NPSavedData* saved);
NPError NPP_Destroy(NPP instance, NPSavedData** save);
NPError NPP_SetWindow(NPP instance, NPWindow* window);
NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream,
- NPBool seekable, uint16* stype);
+ NPBool seekable, uint16_t* stype);
NPError NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason);
-int32 NPP_WriteReady(NPP instance, NPStream* stream);
-int32 NPP_Write(NPP instance, NPStream* stream, int32 offset, int32 len,
+int32_t NPP_WriteReady(NPP instance, NPStream* stream);
+int32_t NPP_Write(NPP instance, NPStream* stream, int32_t offset, int32_t len,
void* buffer);
void NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname);
void NPP_Print(NPP instance, NPPrint* platformPrint);
-int16 NPP_HandleEvent(NPP instance, void* event);
+int16_t NPP_HandleEvent(NPP instance, void* event);
void NPP_URLNotify(NPP instance, const char* URL, NPReason reason,
void* notifyData);
NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value);
@@ -129,7 +129,7 @@
return "application/x-browsertestplugin:btp:Android Browser Test Plugin";
}
-NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc,
+NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc,
char* argn[], char* argv[], NPSavedData* saved)
{
@@ -188,7 +188,7 @@
return NPERR_NO_ERROR;
}
-NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16* stype)
+NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16_t* stype)
{
*stype = NP_ASFILEONLY;
return NPERR_NO_ERROR;
@@ -199,12 +199,12 @@
return NPERR_NO_ERROR;
}
-int32 NPP_WriteReady(NPP instance, NPStream* stream)
+int32_t NPP_WriteReady(NPP instance, NPStream* stream)
{
return 0;
}
-int32 NPP_Write(NPP instance, NPStream* stream, int32 offset, int32 len, void* buffer)
+int32_t NPP_Write(NPP instance, NPStream* stream, int32_t offset, int32_t len, void* buffer)
{
return 0;
}
@@ -217,7 +217,7 @@
{
}
-int16 NPP_HandleEvent(NPP instance, void* event)
+int16_t NPP_HandleEvent(NPP instance, void* event)
{
PluginObject *obj = reinterpret_cast<PluginObject*>(instance->pdata);
const ANPEvent* evt = reinterpret_cast<const ANPEvent*>(event);
diff --git a/tests/DumpRenderTree/assets/run_layout_tests.py b/tests/DumpRenderTree/assets/run_layout_tests.py
index b6e7bf3..ceac5d2 100755
--- a/tests/DumpRenderTree/assets/run_layout_tests.py
+++ b/tests/DumpRenderTree/assets/run_layout_tests.py
@@ -176,7 +176,7 @@
# Count crashed tests.
crashed_tests = []
- timeout_ms = '30000'
+ timeout_ms = '15000'
if options.time_out_ms:
timeout_ms = options.time_out_ms
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
index 77fd3ed..8bdf77c 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
@@ -73,30 +73,40 @@
static final String[] ignoreTestList = {
"editing/selection/move-left-right.html", // Causes DumpRenderTree to hang
+ "fast/js/excessive-comma-usage.html", // Tests huge initializer list, causes OOM.
"fast/js/regexp-charclass-crash.html", // RegExp is too large, causing OOM
"fast/regex/test1.html", // Causes DumpRenderTree to hang with V8
"fast/regex/slow.html" // Causes DumpRenderTree to hang with V8
};
static void fillIgnoreResultList() {
- // This first block of tests are for HTML5 features, for which Android
+ // This first block of tests are for features for which Android
// should pass all tests. They are skipped only temporarily.
// TODO: Fix these failing tests and remove them from this list.
+ ignoreResultList.add("fast/events/touch/basic-multi-touch-events.html"); // Requires multi-touch
+ ignoreResultList.add("fast/events/touch/touch-target.html"); // Requires multi-touch
ignoreResultList.add("http/tests/appcache/empty-manifest.html"); // flaky
+ ignoreResultList.add("http/tests/appcache/fallback.html"); // http://b/issue?id=2713004
ignoreResultList.add("http/tests/appcache/foreign-iframe-main.html"); // flaky - skips states
ignoreResultList.add("http/tests/appcache/manifest-with-empty-file.html"); // flaky
ignoreResultList.add("storage/database-lock-after-reload.html"); // Succeeds but DumpRenderTree does not read result correctly
ignoreResultList.add("storage/hash-change-with-xhr.html"); // Succeeds but DumpRenderTree does not read result correctly
+ ignoreResultList.add("storage/open-database-creation-callback-isolated-world.html"); // Requires layoutTestController.evaluateScriptInIsolatedWorld()
+ ignoreResultList.add("storage/statement-error-callback-isolated-world.html"); // Requires layoutTestController.evaluateScriptInIsolatedWorld()
+ ignoreResultList.add("storage/statement-success-callback-isolated-world.html"); // Requires layoutTestController.evaluateScriptInIsolatedWorld()
+ ignoreResultList.add("storage/transaction-callback-isolated-world.html"); // Requires layoutTestController.evaluateScriptInIsolatedWorld()
+ ignoreResultList.add("storage/transaction-error-callback-isolated-world.html"); // Requires layoutTestController.evaluateScriptInIsolatedWorld()
+ ignoreResultList.add("storage/transaction-success-callback-isolated-world.html"); // Requires layoutTestController.evaluateScriptInIsolatedWorld()
- // Will always fail
- ignoreResultList.add("dom/svg/level3/xpath"); // XPath not supported
+ // Expected failures due to unsupported features.
+ ignoreResultList.add("fast/events/touch/touch-coords-in-zoom-and-scroll.html"); // Requires eventSender.zoomPageIn(),zoomPageOut()
ignoreResultList.add("fast/workers"); // workers not supported
- ignoreResultList.add("fast/xpath"); // XPath not supported
ignoreResultList.add("http/tests/eventsource/workers"); // workers not supported
ignoreResultList.add("http/tests/workers"); // workers not supported
ignoreResultList.add("http/tests/xmlhttprequest/workers"); // workers not supported
ignoreResultList.add("storage/domstorage/localstorage/private-browsing-affects-storage.html"); // private browsing not supported
ignoreResultList.add("storage/domstorage/sessionstorage/private-browsing-affects-storage.html"); // private browsing not supported
+ ignoreResultList.add("storage/indexeddb"); // indexeddb not supported
ignoreResultList.add("storage/private-browsing-readonly.html"); // private browsing not supported
ignoreResultList.add("websocket/tests/workers"); // workers not supported
@@ -104,12 +114,9 @@
ignoreResultList.add("fast/css/case-transform.html"); // will not fix #619707
ignoreResultList.add("fast/dom/Element/offsetLeft-offsetTop-body-quirk.html"); // different screen size result in extra spaces in Apple compared to us
ignoreResultList.add("fast/dom/Window/Plug-ins.html"); // need test plugin
- ignoreResultList.add("fast/dom/Window/window-properties.html"); // xslt and xpath elements missing from property list
ignoreResultList.add("fast/dom/Window/window-screen-properties.html"); // pixel depth
ignoreResultList.add("fast/dom/Window/window-xy-properties.html"); // requires eventSender.mouseDown(),mouseUp()
ignoreResultList.add("fast/dom/attribute-namespaces-get-set.html"); // http://b/733229
- ignoreResultList.add("fast/dom/gc-9.html"); // requires xpath support
- ignoreResultList.add("fast/dom/global-constructors.html"); // requires xslt and xpath support
ignoreResultList.add("fast/dom/object-embed-plugin-scripting.html"); // dynamic plugins not supported
ignoreResultList.add("fast/dom/tabindex-clamp.html"); // there is extra spacing in the file due to multiple input boxes fitting on one line on Apple, ours are wrapped. Space at line ends are stripped.
ignoreResultList.add("fast/events/anchor-image-scrolled-x-y.html"); // requires eventSender.mouseDown(),mouseUp()
@@ -172,8 +179,6 @@
ignoreResultList.add("fast/replaced/image-map.html"); // requires eventSender.mouseDown(),mouseUp()
ignoreResultList.add("fast/text/plain-text-line-breaks.html"); // extra spacing because iFrames rendered next to each other on Apple
ignoreResultList.add("profiler"); // profiler is not supported
- ignoreResultList.add("svg"); // svg is not supported
-
}
}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java
index 322b0d2..0883387 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java
@@ -42,8 +42,13 @@
//no creation of instances
}
- public static void findLayoutTestsRecursively(BufferedOutputStream bos,
+ /**
+ * @return the number of tests in the list.
+ */
+ public static int writeLayoutTestListRecursively(BufferedOutputStream bos,
String dir, boolean ignoreResultsInDir) throws IOException {
+
+ int testCount = 0;
Log.v(LOGTAG, "Searching tests under " + dir);
File d = new File(dir);
@@ -61,7 +66,7 @@
// If this is not a test directory, we don't recurse into it.
if (!FileFilter.isNonTestDir(s)) {
Log.v(LOGTAG, "Recursing on " + s);
- findLayoutTestsRecursively(bos, s, ignoreResultsInDir);
+ testCount += writeLayoutTestListRecursively(bos, s, ignoreResultsInDir);
}
continue;
}
@@ -81,8 +86,10 @@
bos.write((" IGNORE_RESULT").getBytes());
}
bos.write('\n');
+ testCount++;
}
}
+ return testCount;
}
public static void updateTestStatus(String statusFile, String s) {
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
index 042158a..fabbf89 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
@@ -18,12 +18,9 @@
import com.android.dumprendertree.TestShellActivity.DumpDataType;
import com.android.dumprendertree.forwarder.AdbUtils;
-import com.android.dumprendertree.forwarder.ForwardServer;
import com.android.dumprendertree.forwarder.ForwardService;
-import android.app.Instrumentation;
import android.content.Intent;
-import android.os.Bundle;
import android.test.ActivityInstrumentationTestCase2;
import android.util.Log;
@@ -156,18 +153,11 @@
private String mJsEngine;
private String mTestPathPrefix;
private boolean mFinished;
+ private int mTestCount;
+ private int mResumeIndex;
public LayoutTestsAutoTest() {
- super("com.android.dumprendertree", TestShellActivity.class);
- }
-
- // This function writes the result of the layout test to
- // Am status so that it can be picked up from a script.
- private void passOrFailCallback(String file, boolean result) {
- Instrumentation inst = getInstrumentation();
- Bundle bundle = new Bundle();
- bundle.putBoolean(file, result);
- inst.sendStatus(0, bundle);
+ super(TestShellActivity.class);
}
private void getTestList() {
@@ -188,6 +178,7 @@
} catch (Exception e) {
Log.e(LOGTAG, "Error while reading test list : " + e.getMessage());
}
+ mTestCount = mTestList.size();
}
private void resumeTestList() {
@@ -198,6 +189,7 @@
if (mTestList.elementAt(i).equals(line)) {
mTestList = new Vector<String>(mTestList.subList(i+1, mTestList.size()));
mTestListIgnoreResult = new Vector<Boolean>(mTestListIgnoreResult.subList(i+1, mTestListIgnoreResult.size()));
+ mResumeIndex = i + 1;
break;
}
}
@@ -298,7 +290,7 @@
}
}
- private void runTestAndWaitUntilDone(TestShellActivity activity, String test, int timeout, boolean ignoreResult) {
+ private void runTestAndWaitUntilDone(TestShellActivity activity, String test, int timeout, boolean ignoreResult, int testNumber) {
activity.setCallback(new TestShellCallback() {
public void finished() {
synchronized (LayoutTestsAutoTest.this) {
@@ -334,6 +326,8 @@
intent.putExtra(TestShellActivity.TEST_URL, FsUtils.getTestUrl(test));
intent.putExtra(TestShellActivity.RESULT_FILE, resultFile);
intent.putExtra(TestShellActivity.TIMEOUT_IN_MILLIS, timeout);
+ intent.putExtra(TestShellActivity.TOTAL_TEST_COUNT, mTestCount);
+ intent.putExtra(TestShellActivity.CURRENT_TEST_NUMBER, testNumber);
activity.startActivity(intent);
// Wait until done.
@@ -373,8 +367,8 @@
// Read settings
mTestPathPrefix = (new File(LAYOUT_TESTS_ROOT + runner.mTestPath)).getAbsolutePath();
mRebaselineResults = runner.mRebaseline;
- // JSC is the default JavaScript engine.
- mJsEngine = runner.mJsEngine == null ? "jsc" : runner.mJsEngine;
+ // V8 is the default JavaScript engine.
+ mJsEngine = runner.mJsEngine == null ? "v8" : runner.mJsEngine;
int timeout = runner.mTimeoutInMillis;
if (timeout <= 0) {
@@ -391,7 +385,7 @@
resumeTestList();
TestShellActivity activity = getActivity();
- activity.setDefaultDumpDataType(DumpDataType.DUMP_AS_TEXT);
+ activity.setDefaultDumpDataType(DumpDataType.EXT_REPR);
// Run tests.
int addr = -1;
@@ -408,7 +402,9 @@
boolean ignoreResult = mTestListIgnoreResult.elementAt(i);
FsUtils.updateTestStatus(TEST_STATUS_FILE, s);
// Run tests
- runTestAndWaitUntilDone(activity, s, runner.mTimeoutInMillis, ignoreResult);
+ // i is 0 based, but test count is 1 based so add 1 to i here.
+ runTestAndWaitUntilDone(activity, s, runner.mTimeoutInMillis, ignoreResult,
+ i + 1 + mResumeIndex);
}
FsUtils.updateTestStatus(TEST_STATUS_FILE, "#DONE");
@@ -433,7 +429,7 @@
try {
File tests_list = new File(LAYOUT_TESTS_LIST_FILE);
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(tests_list, false));
- FsUtils.findLayoutTestsRecursively(bos, getTestPath(), false); // Don't ignore results
+ FsUtils.writeLayoutTestListRecursively(bos, getTestPath(), false); // Don't ignore results
bos.flush();
bos.close();
} catch (Exception e) {
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/Menu.java b/tests/DumpRenderTree/src/com/android/dumprendertree/Menu.java
index 82671eb..5ffe6b0 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/Menu.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/Menu.java
@@ -51,29 +51,38 @@
intent.setClass(this, TestShellActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.putExtra(TestShellActivity.TEST_URL, "file://" + filename);
+ intent.putExtra(TestShellActivity.TOTAL_TEST_COUNT, 1);
+ intent.putExtra(TestShellActivity.CURRENT_TEST_NUMBER, 1);
startActivity(intent);
}
@Override
void processDirectory(String path, boolean selection) {
- generateTestList(path);
+ int testCount = generateTestList(path);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setClass(this, TestShellActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.putExtra(TestShellActivity.UI_AUTO_TEST, LAYOUT_TESTS_LIST_FILE);
+ intent.putExtra(TestShellActivity.TOTAL_TEST_COUNT, testCount);
+ // TestShellActivity will process this intent once and increment the test index
+ // before running the first test, so pass 0 here to allow for that.
+ intent.putExtra(TestShellActivity.CURRENT_TEST_NUMBER, 0);
startActivity(intent);
}
- private void generateTestList(String path) {
+ private int generateTestList(String path) {
+ int testCount = 0;
try {
File tests_list = new File(LAYOUT_TESTS_LIST_FILE);
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(tests_list, false));
- FsUtils.findLayoutTestsRecursively(bos, path, false); // Don't ignore results
+ testCount = FsUtils.writeLayoutTestListRecursively(
+ bos, path, false); // Don't ignore results
bos.flush();
bos.close();
} catch (Exception e) {
Log.e(LOGTAG, "Error when creating test list: " + e.getMessage());
}
+ return testCount;
}
}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
index 81d5b08..e6f7a27 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
@@ -34,6 +34,8 @@
import android.os.Message;
import android.util.Log;
import android.view.ViewGroup;
+import android.view.Window;
+import android.webkit.ConsoleMessage;
import android.webkit.GeolocationPermissions;
import android.webkit.HttpAuthHandler;
import android.webkit.JsPromptResult;
@@ -116,6 +118,7 @@
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
+ requestWindowFeature(Window.FEATURE_PROGRESS);
LinearLayout contentView = new LinearLayout(this);
contentView.setOrientation(LinearLayout.VERTICAL);
@@ -158,6 +161,9 @@
return;
}
+ mTotalTestCount = intent.getIntExtra(TOTAL_TEST_COUNT, mTotalTestCount);
+ mCurrentTestNumber = intent.getIntExtra(CURRENT_TEST_NUMBER, mCurrentTestNumber);
+
mTestUrl = intent.getStringExtra(TEST_URL);
if (mTestUrl == null) {
mUiAutoTestPath = intent.getStringExtra(UI_AUTO_TEST);
@@ -171,6 +177,10 @@
mTimeoutInMillis = intent.getIntExtra(TIMEOUT_IN_MILLIS, 0);
mGetDrawtime = intent.getBooleanExtra(GET_DRAW_TIME, false);
mSaveImagePath = intent.getStringExtra(SAVE_IMAGE);
+ setTitle("Test " + mCurrentTestNumber + " of " + mTotalTestCount);
+ float ratio = (float)mCurrentTestNumber / mTotalTestCount;
+ int progress = (int)(ratio * Window.PROGRESS_END);
+ getWindow().setFeatureInt(Window.FEATURE_PROGRESS, progress);
Log.v(LOGTAG, " Loading " + mTestUrl);
mWebView.loadUrl(mTestUrl);
@@ -236,6 +246,7 @@
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.putExtra(TestShellActivity.TEST_URL, FsUtils.getTestUrl(url));
+ intent.putExtra(TestShellActivity.CURRENT_TEST_NUMBER, ++mCurrentTestNumber);
intent.putExtra(TIMEOUT_IN_MILLIS, 10000);
executeIntent(intent);
}
@@ -347,7 +358,9 @@
Log.v(LOGTAG, "notifyDone called: " + url);
if (mWaitUntilDone) {
mWaitUntilDone = false;
- mChromeClient.onProgressChanged(mWebView, 101);
+ if (!mRequestedWebKitData && !mTimedOut && !finished()) {
+ requestWebKitData();
+ }
}
}
@@ -489,11 +502,30 @@
drawPageToFile(mSaveImagePath + "/" + name + ".png", mWebView);
}
}
+
// Calling finished() will check if we've met all the conditions for completing
- // this test and move to the next one if we are ready.
+ // this test and move to the next one if we are ready. Otherwise we ask WebCore to
+ // dump the page.
if (finished()) {
return;
}
+
+ if (!mWaitUntilDone && !mRequestedWebKitData && !mTimedOut) {
+ requestWebKitData();
+ } else {
+ if (mWaitUntilDone) {
+ Log.v(LOGTAG, "page finished loading but waiting for notifyDone to be called: " + url);
+ }
+
+ if (mRequestedWebKitData) {
+ Log.v(LOGTAG, "page finished loading but webkit data has already been requested: " + url);
+ }
+
+ if (mTimedOut) {
+ Log.v(LOGTAG, "page finished loading but already timed out: " + url);
+ }
+ }
+
super.onPageFinished(view, url);
}
@@ -535,44 +567,8 @@
private final WebChromeClient mChromeClient = new WebChromeClient() {
@Override
- public void onProgressChanged(WebView view, int newProgress) {
-
- // notifyDone calls this with 101%. We only want to update this flag if this
- // is the real call from WebCore.
- if (newProgress == 100) {
- mOneHundredPercentComplete = true;
- }
-
- // With the flag updated, we can now proceed as normal whether the progress update came from
- // WebCore or notifyDone.
- if (newProgress >= 100) {
- // finished() will check if we are ready to move to the next test and do so if we are.
- if (finished()) {
- return;
- }
-
- if (!mTimedOut && !mWaitUntilDone && !mRequestedWebKitData) {
- String url = mWebView.getUrl();
- Log.v(LOGTAG, "Finished: "+ url);
- requestWebKitData();
- } else {
- String url = mWebView.getUrl();
- if (mTimedOut) {
- Log.v(LOGTAG, "Timed out before finishing: " + url);
- } else if (mWaitUntilDone) {
- Log.v(LOGTAG, "Waiting for notifyDone: " + url);
- } else if (mRequestedWebKitData) {
- Log.v(LOGTAG, "Requested webkit data ready: " + url);
- }
- }
- }
- }
-
- @Override
public void onReceivedTitle(WebView view, String title) {
- if (title.length() > 30)
- title = "..."+title.substring(title.length()-30);
- setTitle(title);
+ setTitle("Test " + mCurrentTestNumber + " of " + mTotalTestCount + ": "+ title);
if (mDumpTitleChanges) {
mTitleChanges.append("TITLE CHANGED: ");
mTitleChanges.append(title);
@@ -675,15 +671,28 @@
}
@Override
- public void onConsoleMessage(String message, int lineNumber,
- String sourceID) {
+ public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
+ String msg = "CONSOLE MESSAGE: line " + consoleMessage.lineNumber() + ": "
+ + consoleMessage.message() + "\n";
if (mConsoleMessages == null) {
mConsoleMessages = new StringBuffer();
}
- String consoleMessage = "CONSOLE MESSAGE: line "
- + lineNumber +": "+ message +"\n";
- mConsoleMessages.append(consoleMessage);
- Log.v(LOGTAG, "LOG: "+consoleMessage);
+ mConsoleMessages.append(msg);
+ Log.v(LOGTAG, "LOG: " + msg);
+ // the rationale here is that if there's an error of either type, and the test was
+ // waiting for "notifyDone" signal to finish, then there's no point in waiting
+ // anymore because the JS execution is already terminated at this point and a
+ // "notifyDone" will never come out so it's just wasting time till timeout kicks in
+ if (msg.contains("Uncaught ReferenceError:") || msg.contains("Uncaught TypeError:")
+ && mWaitUntilDone) {
+ Log.w(LOGTAG, "Terminating test case on uncaught ReferenceError or TypeError.");
+ mHandler.postDelayed(new Runnable() {
+ public void run() {
+ notifyDone();
+ }
+ }, 500);
+ }
+ return true;
}
@Override
@@ -738,10 +747,10 @@
mEventSender.clearTouchPoints();
mEventSender.clearTouchMetaState();
mPageFinished = false;
- mOneHundredPercentComplete = false;
mDumpWebKitData = false;
mGetDrawtime = false;
mSaveImagePath = null;
+ setDefaultWebSettings(mWebView);
}
private long[] getDrawWebViewTime(WebView view, int count) {
@@ -778,7 +787,7 @@
}
private boolean canMoveToNextTest() {
- return (mDumpWebKitData && mOneHundredPercentComplete && mPageFinished && !mWaitUntilDone) || mTimedOut;
+ return (mDumpWebKitData && mPageFinished && !mWaitUntilDone) || mTimedOut;
}
private void setupWebViewForLayoutTests(WebView webview, CallbackProxy callbackProxy) {
@@ -786,6 +795,19 @@
return;
}
+ setDefaultWebSettings(webview);
+
+ webview.setWebChromeClient(mChromeClient);
+ webview.setWebViewClient(mViewClient);
+ // Setting a touch interval of -1 effectively disables the optimisation in WebView
+ // that stops repeated touch events flooding WebCore. The Event Sender only sends a
+ // single event rather than a stream of events (like what would generally happen in
+ // a real use of touch events in a WebView) and so if the WebView drops the event,
+ // the test will fail as the test expects one callback for every touch it synthesizes.
+ webview.setTouchInterval(-1);
+ }
+
+ public void setDefaultWebSettings(WebView webview) {
WebSettings settings = webview.getSettings();
settings.setAppCacheEnabled(true);
settings.setAppCachePath(getApplicationContext().getCacheDir().getPath());
@@ -798,15 +820,6 @@
settings.setDatabasePath(getDir("databases",0).getAbsolutePath());
settings.setDomStorageEnabled(true);
settings.setWorkersEnabled(false);
-
- webview.setWebChromeClient(mChromeClient);
- webview.setWebViewClient(mViewClient);
- // Setting a touch interval of -1 effectively disables the optimisation in WebView
- // that stops repeated touch events flooding WebCore. The Event Sender only sends a
- // single event rather than a stream of events (like what would generally happen in
- // a real use of touch events in a WebView) and so if the WebView drops the event,
- // the test will fail as the test expects one callback for every touch it synthesizes.
- webview.setTouchInterval(-1);
}
private WebView mWebView;
@@ -823,6 +836,8 @@
private String mSaveImagePath;
private BufferedReader mTestListReader;
private boolean mGetDrawtime;
+ private int mTotalTestCount;
+ private int mCurrentTestNumber;
// States
private boolean mTimedOut;
@@ -845,7 +860,6 @@
private boolean mPageFinished = false;
private boolean mDumpWebKitData = false;
- private boolean mOneHundredPercentComplete = false;
static final String TIMEOUT_STR = "**Test timeout";
@@ -860,6 +874,8 @@
static final String UI_AUTO_TEST = "UiAutoTest";
static final String GET_DRAW_TIME = "GetDrawTime";
static final String SAVE_IMAGE = "SaveImage";
+ static final String TOTAL_TEST_COUNT = "TestCount";
+ static final String CURRENT_TEST_NUMBER = "TestNumber";
static final int DRAW_RUNS = 5;
static final String DRAW_TIME_LOG = "/sdcard/android/page_draw_time.txt";
diff --git a/tools/layoutlib/README b/tools/layoutlib/README
new file mode 100644
index 0000000..0fea9bd
--- /dev/null
+++ b/tools/layoutlib/README
@@ -0,0 +1,4 @@
+Layoutlib is a custom version of the android View framework designed to run inside Eclipse.
+The goal of the library is to provide layout rendering in Eclipse that are very very close to their rendering on devices.
+
+None of the com.android.* or android.* classes in layoutlib run on devices.
\ No newline at end of file
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
index 744bfbe..58b1b6c 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
@@ -37,6 +37,7 @@
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.Resources.Theme;
+import android.database.DatabaseErrorHandler;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.graphics.Bitmap;
@@ -1059,6 +1060,13 @@
}
@Override
+ public SQLiteDatabase openOrCreateDatabase(String arg0, int arg1,
+ CursorFactory arg2, DatabaseErrorHandler arg3) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
public Drawable peekWallpaper() {
// TODO Auto-generated method stub
return null;