diff options
271 files changed, 7976 insertions, 2890 deletions
@@ -337,7 +337,7 @@ framework_docs_LOCAL_DROIDDOC_OPTIONS := \ -since ./frameworks/base/api/1.xml 1 \ -since ./frameworks/base/api/2.xml 2 \ -since ./frameworks/base/api/3.xml 3 \ - -since ./frameworks/base/api/current.xml Donut \ + -since ./frameworks/base/api/4.xml 4 \ -error 1 -error 2 -warning 3 -error 4 -error 6 -error 8 \ -overview $(LOCAL_PATH)/core/java/overview.html @@ -349,10 +349,18 @@ web_docs_sample_code_flags := \ -hdf android.hasSamples 1 \ -samplecode $(sample_dir)/ApiDemos \ guide/samples/ApiDemos "API Demos" \ + -samplecode $(sample_dir)/Home \ + guide/samples/Home "Home" \ + -samplecode $(sample_dir)/JetBoy \ + guide/samples/JetBoy "JetBoy" \ -samplecode $(sample_dir)/LunarLander \ guide/samples/LunarLander "Lunar Lander" \ -samplecode $(sample_dir)/NotePad \ - guide/samples/NotePad "Note Pad" + guide/samples/NotePad "Note Pad" \ + -samplecode $(sample_dir)/Snake \ + guide/samples/Snake "Snake" \ + -samplecode $(sample_dir)/SoftKeyboard \ + guide/samples/SoftKeyboard "Soft Keyboard" ## SDK version identifiers used in the published docs # major[.minor] version for current SDK. (full releases only) diff --git a/api/current.xml b/api/current.xml index 7fad505..ea70922 100644 --- a/api/current.xml +++ b/api/current.xml @@ -14932,7 +14932,7 @@ synchronized="false" static="false" final="false" - deprecated="deprecated" + deprecated="not deprecated" visibility="public" > <parameter name="response" type="android.accounts.IAccountAuthenticatorResponse"> @@ -21568,6 +21568,19 @@ <parameter name="intent" type="android.content.Intent"> </parameter> </method> +<method name="setIntentRedelivery" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="enabled" type="boolean"> +</parameter> +</method> </class> <class name="KeyguardManager" extends="java.lang.Object" @@ -23767,11 +23780,28 @@ synchronized="false" static="false" final="false" + deprecated="deprecated" + visibility="public" +> +<parameter name="intent" type="android.content.Intent"> +</parameter> +<parameter name="startId" type="int"> +</parameter> +</method> +<method name="onStartCommand" + return="int" + 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="flags" type="int"> +</parameter> <parameter name="startId" type="int"> </parameter> </method> @@ -23866,6 +23896,83 @@ <parameter name="startId" type="int"> </parameter> </method> +<field name="START_CONTINUATION_MASK" + type="int" + transient="false" + volatile="false" + value="15" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="START_FLAG_REDELIVERY" + type="int" + transient="false" + volatile="false" + value="1" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="START_FLAG_RETRY" + type="int" + transient="false" + volatile="false" + value="2" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="START_NOT_STICKY" + type="int" + transient="false" + volatile="false" + value="2" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="START_REDELIVER_INTENT" + type="int" + transient="false" + volatile="false" + value="3" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="START_STICKY" + type="int" + transient="false" + volatile="false" + value="1" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="START_STICKY_COMPATIBILITY" + type="int" + transient="false" + volatile="false" + value="0" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> </class> <class name="TabActivity" extends="android.app.ActivityGroup" @@ -60400,6 +60507,21 @@ visibility="public" > </method> +<method name="setGammaForText" + return="void" + abstract="false" + native="true" + synchronized="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="blackGamma" type="float"> +</parameter> +<parameter name="whiteGamma" type="float"> +</parameter> +</method> <field name="BOLD" type="int" transient="false" @@ -95009,6 +95131,17 @@ visibility="public" > </field> +<field name="ECLAIR" + type="int" + transient="false" + volatile="false" + value="10000" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> </class> <class name="Bundle" extends="java.lang.Object" @@ -105436,7 +105569,7 @@ abstract="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <field name="AUTHORITY" @@ -105446,7 +105579,7 @@ value=""contacts"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -105456,7 +105589,7 @@ volatile="false" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -105467,7 +105600,7 @@ value="1" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -105478,7 +105611,7 @@ value="3" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -105489,7 +105622,7 @@ value="4" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -105500,7 +105633,7 @@ value="5" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -105511,7 +105644,7 @@ value="2" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -105521,7 +105654,7 @@ abstract="false" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <implements name="android.provider.BaseColumns"> @@ -105537,7 +105670,7 @@ synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <parameter name="context" type="android.content.Context"> @@ -105556,7 +105689,7 @@ synchronized="false" static="true" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <parameter name="encodedString" type="java.lang.String"> @@ -105569,7 +105702,7 @@ synchronized="false" static="true" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <parameter name="protocolString" type="java.lang.String"> @@ -105582,7 +105715,7 @@ synchronized="false" static="true" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <parameter name="protocol" type="int"> @@ -105595,7 +105728,7 @@ synchronized="false" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <parameter name="context" type="android.content.Context"> @@ -105614,7 +105747,7 @@ value=""vnd.android.cursor.item/email"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -105625,7 +105758,7 @@ value=""vnd.android.cursor.dir/email"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -105635,7 +105768,7 @@ volatile="false" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -105646,7 +105779,7 @@ value=""vnd.android.cursor.item/jabber-im"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -105657,7 +105790,7 @@ value=""vnd.android.cursor.item/postal-address"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -105668,7 +105801,7 @@ value=""vnd.android.cursor.dir/postal-address"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -105679,7 +105812,7 @@ value=""vnd.android.cursor.dir/contact-methods"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -105689,7 +105822,7 @@ volatile="false" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -105700,7 +105833,7 @@ value=""name ASC"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -105711,7 +105844,7 @@ value=""person"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -105722,7 +105855,7 @@ value=""data"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -105733,7 +105866,7 @@ value=""aux_data"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -105744,7 +105877,7 @@ value="0" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -105755,7 +105888,7 @@ value="5" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -105766,7 +105899,7 @@ value="6" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -105777,7 +105910,7 @@ value="7" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -105788,7 +105921,7 @@ value="1" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -105799,7 +105932,7 @@ value="4" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -105810,7 +105943,7 @@ value="3" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -105821,7 +105954,7 @@ value="2" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -105830,7 +105963,7 @@ abstract="true" static="true" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <field name="AUX_DATA" @@ -105840,7 +105973,7 @@ value=""aux_data"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -105851,7 +105984,7 @@ value=""data"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -105862,7 +105995,7 @@ value=""isprimary"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -105873,7 +106006,7 @@ value=""kind"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -105884,7 +106017,7 @@ value=""label"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -105895,7 +106028,7 @@ value=""type"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -105906,7 +106039,7 @@ value="0" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -105917,7 +106050,7 @@ value="1" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -105928,7 +106061,7 @@ value="3" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -105939,7 +106072,7 @@ value="2" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -105949,7 +106082,7 @@ abstract="false" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <implements name="android.provider.BaseColumns"> @@ -105963,7 +106096,7 @@ value=""vnd.android.cursor.item/contact_extensions"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -105974,7 +106107,7 @@ value=""vnd.android.cursor.dir/contact_extensions"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -105984,7 +106117,7 @@ volatile="false" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -105995,7 +106128,7 @@ value=""person, name ASC"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106006,7 +106139,7 @@ value=""person"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106015,7 +106148,7 @@ abstract="true" static="true" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <field name="NAME" @@ -106025,7 +106158,7 @@ value=""name"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106036,7 +106169,7 @@ value=""value"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106046,7 +106179,7 @@ abstract="false" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <implements name="android.provider.BaseColumns"> @@ -106060,7 +106193,7 @@ value=""groupmembership"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106071,7 +106204,7 @@ value=""vnd.android.cursor.item/contactsgroupmembership"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106082,7 +106215,7 @@ value=""vnd.android.cursor.dir/contactsgroupmembership"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106092,7 +106225,7 @@ volatile="false" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106103,7 +106236,7 @@ value=""group_id ASC"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106114,7 +106247,7 @@ value=""group_id"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106125,7 +106258,7 @@ value=""group_sync_account"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106136,7 +106269,7 @@ value=""group_sync_account_type"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106147,7 +106280,7 @@ value=""group_sync_id"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106158,7 +106291,7 @@ value=""person"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106168,7 +106301,7 @@ volatile="false" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106178,7 +106311,7 @@ abstract="false" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <implements name="android.provider.BaseColumns"> @@ -106192,7 +106325,7 @@ value=""vnd.android.cursor.item/contactsgroup"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106203,7 +106336,7 @@ value=""vnd.android.cursor.dir/contactsgroup"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106213,7 +106346,7 @@ volatile="false" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106224,7 +106357,7 @@ value=""name ASC"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106234,7 +106367,7 @@ volatile="false" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106245,7 +106378,7 @@ value=""Starred in Android"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106256,7 +106389,7 @@ value=""Contacts"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106265,7 +106398,7 @@ abstract="true" static="true" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <field name="NAME" @@ -106275,7 +106408,7 @@ value=""name"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106286,7 +106419,7 @@ value=""notes"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106297,7 +106430,7 @@ value=""should_sync"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106308,7 +106441,7 @@ value=""system_id"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106318,14 +106451,14 @@ abstract="false" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <constructor name="Contacts.Intents" type="android.provider.Contacts.Intents" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </constructor> @@ -106336,7 +106469,7 @@ value=""com.android.contacts.action.ATTACH_IMAGE"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106347,7 +106480,7 @@ value=""com.android.contacts.action.CREATE_DESCRIPTION"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106358,7 +106491,7 @@ value=""com.android.contacts.action.FORCE_CREATE"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106369,7 +106502,7 @@ value=""android.provider.Contacts.SEARCH_SUGGESTION_CLICKED"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106380,7 +106513,7 @@ value=""android.provider.Contacts.SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106391,7 +106524,7 @@ value=""android.provider.Contacts.SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106402,7 +106535,7 @@ value=""com.android.contacts.action.SHOW_OR_CREATE_CONTACT"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106412,14 +106545,14 @@ abstract="false" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <constructor name="Contacts.Intents.Insert" type="android.provider.Contacts.Intents.Insert" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </constructor> @@ -106430,7 +106563,7 @@ value=""android.intent.action.INSERT"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106441,7 +106574,7 @@ value=""company"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106452,7 +106585,7 @@ value=""email"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106463,7 +106596,7 @@ value=""email_isprimary"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106474,7 +106607,7 @@ value=""email_type"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106485,7 +106618,7 @@ value=""full_mode"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106496,7 +106629,7 @@ value=""im_handle"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106507,7 +106640,7 @@ value=""im_isprimary"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106518,7 +106651,7 @@ value=""im_protocol"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106529,7 +106662,7 @@ value=""job_title"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106540,7 +106673,7 @@ value=""name"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106551,7 +106684,7 @@ value=""notes"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106562,7 +106695,7 @@ value=""phone"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106573,7 +106706,7 @@ value=""phonetic_name"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106584,7 +106717,7 @@ value=""phone_isprimary"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106595,7 +106728,7 @@ value=""phone_type"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106606,7 +106739,7 @@ value=""postal"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106617,7 +106750,7 @@ value=""postal_isprimary"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106628,7 +106761,7 @@ value=""postal_type"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106639,7 +106772,7 @@ value=""secondary_email"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106650,7 +106783,7 @@ value=""secondary_email_type"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106661,7 +106794,7 @@ value=""secondary_phone"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106672,7 +106805,7 @@ value=""secondary_phone_type"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106683,7 +106816,7 @@ value=""tertiary_email"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106694,7 +106827,7 @@ value=""tertiary_email_type"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106705,7 +106838,7 @@ value=""tertiary_phone"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106716,7 +106849,7 @@ value=""tertiary_phone_type"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106726,14 +106859,14 @@ abstract="false" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <constructor name="Contacts.Intents.UI" type="android.provider.Contacts.Intents.UI" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </constructor> @@ -106744,7 +106877,7 @@ value=""com.android.contacts.action.FILTER_CONTACTS"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106755,7 +106888,7 @@ value=""com.android.contacts.extra.FILTER_TEXT"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106766,7 +106899,7 @@ value=""com.android.contacts.extra.GROUP"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106777,7 +106910,7 @@ value=""com.android.contacts.action.LIST_ALL_CONTACTS"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106788,7 +106921,7 @@ value=""com.android.contacts.action.LIST_CONTACTS_WITH_PHONES"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106799,7 +106932,7 @@ value=""com.android.contacts.action.LIST_DEFAULT"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106810,7 +106943,7 @@ value=""com.android.contacts.action.LIST_FREQUENT"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106821,7 +106954,7 @@ value=""com.android.contacts.action.LIST_GROUP"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106832,7 +106965,7 @@ value=""com.android.contacts.action.LIST_STARRED"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106843,7 +106976,7 @@ value=""com.android.contacts.action.LIST_STREQUENT"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106854,7 +106987,7 @@ value=""com.android.contacts.extra.TITLE_EXTRA"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106863,7 +106996,7 @@ abstract="true" static="true" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <field name="COMPANY" @@ -106873,7 +107006,7 @@ value=""company"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106884,7 +107017,7 @@ value=""isprimary"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106895,7 +107028,7 @@ value=""label"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106906,7 +107039,7 @@ value=""person"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106917,7 +107050,7 @@ value=""title"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106928,7 +107061,7 @@ value=""type"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106939,7 +107072,7 @@ value="0" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106950,7 +107083,7 @@ value="2" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106961,7 +107094,7 @@ value="1" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -106971,7 +107104,7 @@ abstract="false" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <implements name="android.provider.BaseColumns"> @@ -106985,7 +107118,7 @@ synchronized="false" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <parameter name="context" type="android.content.Context"> @@ -107002,7 +107135,7 @@ value=""organizations"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107012,7 +107145,7 @@ volatile="false" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107023,7 +107156,7 @@ value=""company, title, isprimary ASC"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107033,7 +107166,7 @@ abstract="false" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <implements name="android.provider.BaseColumns"> @@ -107051,7 +107184,7 @@ synchronized="false" static="true" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <parameter name="resolver" type="android.content.ContentResolver"> @@ -107068,7 +107201,7 @@ synchronized="false" static="true" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <parameter name="resolver" type="android.content.ContentResolver"> @@ -107085,7 +107218,7 @@ synchronized="false" static="true" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <parameter name="resolver" type="android.content.ContentResolver"> @@ -107100,7 +107233,7 @@ synchronized="false" static="true" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <parameter name="resolver" type="android.content.ContentResolver"> @@ -107115,7 +107248,7 @@ synchronized="false" static="true" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <parameter name="context" type="android.content.Context"> @@ -107134,7 +107267,7 @@ synchronized="false" static="true" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <parameter name="resolver" type="android.content.ContentResolver"> @@ -107149,7 +107282,7 @@ synchronized="false" static="true" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <parameter name="cr" type="android.content.ContentResolver"> @@ -107164,7 +107297,7 @@ synchronized="false" static="true" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <parameter name="resolver" type="android.content.ContentResolver"> @@ -107179,7 +107312,7 @@ synchronized="false" static="true" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <parameter name="cr" type="android.content.ContentResolver"> @@ -107195,7 +107328,7 @@ volatile="false" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107206,7 +107339,7 @@ value=""vnd.android.cursor.item/person"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107217,7 +107350,7 @@ value=""vnd.android.cursor.dir/person"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107227,7 +107360,7 @@ volatile="false" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107238,7 +107371,7 @@ value=""name ASC"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107248,7 +107381,7 @@ volatile="false" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107259,7 +107392,7 @@ value=""primary_email"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107270,7 +107403,7 @@ value=""primary_organization"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107281,7 +107414,7 @@ value=""primary_phone"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107291,7 +107424,7 @@ abstract="false" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <implements name="android.provider.BaseColumns"> @@ -107307,7 +107440,7 @@ value=""contact_methods"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107318,7 +107451,7 @@ value=""data ASC"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107328,7 +107461,7 @@ abstract="false" static="true" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <implements name="android.provider.BaseColumns"> @@ -107342,7 +107475,7 @@ value=""extensions"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107353,7 +107486,7 @@ value=""name ASC"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107364,7 +107497,7 @@ value=""person"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107374,7 +107507,7 @@ abstract="false" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <implements name="android.provider.BaseColumns"> @@ -107390,7 +107523,7 @@ value=""phones"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107401,7 +107534,7 @@ value=""number ASC"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107410,7 +107543,7 @@ abstract="true" static="true" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <field name="CUSTOM_RINGTONE" @@ -107420,7 +107553,7 @@ value=""custom_ringtone"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107431,7 +107564,7 @@ value=""display_name"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107442,7 +107575,7 @@ value=""last_time_contacted"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107453,7 +107586,7 @@ value=""name"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107464,7 +107597,7 @@ value=""notes"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107475,7 +107608,7 @@ value=""phonetic_name"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107486,7 +107619,7 @@ value=""photo_version"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107497,7 +107630,7 @@ value=""send_to_voicemail"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107508,7 +107641,7 @@ value=""starred"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107519,7 +107652,7 @@ value=""times_contacted"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107529,7 +107662,7 @@ abstract="false" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <implements name="android.provider.BaseColumns"> @@ -107545,7 +107678,7 @@ synchronized="false" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <parameter name="context" type="android.content.Context"> @@ -107564,7 +107697,7 @@ synchronized="false" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <parameter name="context" type="android.content.Context"> @@ -107580,7 +107713,7 @@ volatile="false" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107591,7 +107724,7 @@ value=""vnd.android.cursor.item/phone"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107602,7 +107735,7 @@ value=""vnd.android.cursor.dir/phone"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107612,7 +107745,7 @@ volatile="false" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107623,7 +107756,7 @@ value=""name ASC"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107634,7 +107767,7 @@ value=""person"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107643,7 +107776,7 @@ abstract="true" static="true" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <field name="ISPRIMARY" @@ -107653,7 +107786,7 @@ value=""isprimary"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107664,7 +107797,7 @@ value=""label"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107675,7 +107808,7 @@ value=""number"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107686,7 +107819,7 @@ value=""number_key"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107697,7 +107830,7 @@ value=""type"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107708,7 +107841,7 @@ value="0" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107719,7 +107852,7 @@ value="5" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107730,7 +107863,7 @@ value="4" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107741,7 +107874,7 @@ value="1" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107752,7 +107885,7 @@ value="2" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107763,7 +107896,7 @@ value="7" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107774,7 +107907,7 @@ value="6" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107785,7 +107918,7 @@ value="3" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107795,7 +107928,7 @@ abstract="false" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <implements name="android.provider.BaseColumns"> @@ -107809,7 +107942,7 @@ value=""photo"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107819,7 +107952,7 @@ volatile="false" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107830,7 +107963,7 @@ value=""person ASC"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107839,7 +107972,7 @@ abstract="true" static="true" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <field name="DATA" @@ -107849,7 +107982,7 @@ value=""data"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107860,7 +107993,7 @@ value=""download_required"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107871,7 +108004,7 @@ value=""exists_on_server"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107882,7 +108015,7 @@ value=""local_version"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107893,7 +108026,7 @@ value=""person"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107904,7 +108037,7 @@ value=""sync_error"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107913,7 +108046,7 @@ abstract="true" static="true" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <field name="IM_ACCOUNT" @@ -107923,7 +108056,7 @@ value=""im_account"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107934,7 +108067,7 @@ value=""im_handle"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107945,7 +108078,7 @@ value=""im_protocol"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -107955,7 +108088,7 @@ abstract="false" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <implements name="android.provider.BaseColumns"> @@ -107969,7 +108102,7 @@ synchronized="false" static="true" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <parameter name="cr" type="android.content.ContentResolver"> @@ -107986,7 +108119,7 @@ synchronized="false" static="true" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <parameter name="cr" type="android.content.ContentResolver"> @@ -108005,7 +108138,7 @@ value=""settings"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -108015,7 +108148,7 @@ volatile="false" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -108026,7 +108159,7 @@ value=""key ASC"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -108037,7 +108170,7 @@ value=""syncEverything"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -108046,7 +108179,7 @@ abstract="true" static="true" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <field name="KEY" @@ -108056,7 +108189,7 @@ value=""key"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -108067,7 +108200,7 @@ value=""value"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -108078,7 +108211,7 @@ value=""_sync_account"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -108089,7 +108222,7 @@ value=""_sync_account_type"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -115444,7 +115577,7 @@ synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <parameter name="asu" type="int"> @@ -118531,6 +118664,19 @@ synchronized="false" static="false" final="false" + deprecated="deprecated" + visibility="public" +> +<parameter name="instrumentation" type="android.app.Instrumentation"> +</parameter> +</method> +<method name="setInstrumentation" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" deprecated="not deprecated" visibility="public" > @@ -118780,6 +118926,19 @@ synchronized="false" static="false" final="false" + deprecated="deprecated" + visibility="public" +> +<parameter name="instrumentation" type="android.app.Instrumentation"> +</parameter> +</method> +<method name="injectInstrumentation" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" deprecated="not deprecated" visibility="public" > @@ -162288,6 +162447,8 @@ </parameter> <parameter name="currentQuota" type="long"> </parameter> +<parameter name="estimatedSize" type="long"> +</parameter> <parameter name="totalUsedQuota" type="long"> </parameter> <parameter name="quotaUpdater" type="android.webkit.WebStorage.QuotaUpdater"> @@ -163950,6 +164111,8 @@ </parameter> <parameter name="currentQuota" type="long"> </parameter> +<parameter name="estimatedSize" type="long"> +</parameter> <parameter name="totalUsedQuota" type="long"> </parameter> <parameter name="quotaUpdater" type="android.webkit.WebStorage.QuotaUpdater"> @@ -263939,7 +264102,7 @@ </parameter> <parameter name="buffer" type="java.lang.StringBuffer"> </parameter> -<parameter name="field" type="java.text.FieldPosition"> +<parameter name="fieldPos" type="java.text.FieldPosition"> </parameter> </method> <method name="get2DigitYearStart" diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c index cc951c1..18713e9 100644 --- a/cmds/dumpstate/dumpstate.c +++ b/cmds/dumpstate/dumpstate.c @@ -102,7 +102,7 @@ static void dumpstate(int full) { PRINT("------ PACKAGE UID ERRORS ------"); DUMP("/data/system/uiderrors.txt"); PRINT("------ LAST KERNEL LOG ------"); - DUMP("/proc/last_kmsg"); + DUMP("/data/last_kmsg"); } PRINT("========================================================"); PRINT("== build.prop"); diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp index 6b2d8ad..ac6fb36 100644 --- a/cmds/stagefright/stagefright.cpp +++ b/cmds/stagefright/stagefright.cpp @@ -40,6 +40,7 @@ using namespace android; static long gNumRepetitions; +static long gMaxNumFrames; // 0 means decode all available. static int64_t getNowUs() { struct timeval tv; @@ -74,6 +75,8 @@ static void playSource(OMXClient *client, const sp<MediaSource> &source) { MediaSource::ReadOptions options; while (numIterationsLeft-- > 0) { + long numFrames = 0; + MediaBuffer *buffer; for (;;) { @@ -92,6 +95,11 @@ static void playSource(OMXClient *client, const sp<MediaSource> &source) { buffer->release(); buffer = NULL; + + ++numFrames; + if (gMaxNumFrames > 0 && numFrames == gMaxNumFrames) { + break; + } } printf("$"); @@ -115,6 +123,7 @@ static void usage(const char *me) { fprintf(stderr, " -a(udio)\n"); fprintf(stderr, " -n repetitions\n"); fprintf(stderr, " -l(ist) components\n"); + fprintf(stderr, " -m max-number-of-frames-to-decode in each pass\n"); } int main(int argc, char **argv) { @@ -123,9 +132,10 @@ int main(int argc, char **argv) { bool audioOnly = false; bool listComponents = false; gNumRepetitions = 1; + gMaxNumFrames = 0; int res; - while ((res = getopt(argc, argv, "han:l")) >= 0) { + while ((res = getopt(argc, argv, "han:lm:")) >= 0) { switch (res) { case 'a': { @@ -139,6 +149,7 @@ int main(int argc, char **argv) { break; } + case 'm': case 'n': { char *end; @@ -148,7 +159,11 @@ int main(int argc, char **argv) { x = 1; } - gNumRepetitions = x; + if (res == 'n') { + gNumRepetitions = x; + } else { + gMaxNumFrames = x; + } break; } diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java index 9f70534..d04abe5 100644 --- a/core/java/android/accounts/AccountManager.java +++ b/core/java/android/accounts/AccountManager.java @@ -261,6 +261,7 @@ public class AccountManager { } /** @deprecated use {@link #confirmCredentials} instead */ + @Deprecated public AccountManagerFuture<Boolean> confirmPassword(final Account account, final String password, AccountManagerCallback<Boolean> callback, Handler handler) { return new Future2Task<Boolean>(handler, callback) { diff --git a/core/java/android/accounts/AccountManagerFuture.java b/core/java/android/accounts/AccountManagerFuture.java index 9939398..74d83eb 100644 --- a/core/java/android/accounts/AccountManagerFuture.java +++ b/core/java/android/accounts/AccountManagerFuture.java @@ -56,9 +56,11 @@ public interface AccountManagerFuture<V> extends Future<V> { V getResult(long timeout, TimeUnit unit) throws OperationCanceledException, IOException, AuthenticatorException; + /** @deprecated Use {@link #getResult} */ @Deprecated V get() throws InterruptedException, ExecutionException; + /** @deprecated Use {@link #getResult} */ @Deprecated V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java index 140c814..5ed8941 100644 --- a/core/java/android/accounts/AccountManagerService.java +++ b/core/java/android/accounts/AccountManagerService.java @@ -23,6 +23,8 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.pm.RegisteredServicesCache; +import android.content.pm.PackageInfo; +import android.content.pm.ApplicationInfo; import android.database.Cursor; import android.database.DatabaseUtils; import android.database.sqlite.SQLiteDatabase; @@ -44,6 +46,7 @@ import android.util.Pair; import android.app.PendingIntent; import android.app.NotificationManager; import android.app.Notification; +import android.app.Activity; import android.Manifest; import java.io.FileDescriptor; @@ -118,8 +121,7 @@ public class AccountManagerService extends IAccountManager.Stub { private static final String[] ACCOUNT_NAME_TYPE_PROJECTION = new String[]{ACCOUNTS_ID, ACCOUNTS_NAME, ACCOUNTS_TYPE}; - private static final Intent ACCOUNTS_CHANGED_INTENT = - new Intent(Constants.LOGIN_ACCOUNTS_CHANGED_ACTION); + private static final Intent ACCOUNTS_CHANGED_INTENT; private static final String COUNT_OF_MATCHING_GRANTS = "" + "SELECT COUNT(*) FROM " + TABLE_GRANTS + ", " + TABLE_ACCOUNTS @@ -143,6 +145,12 @@ public class AccountManagerService extends IAccountManager.Stub { private static final boolean isDebuggableMonkeyBuild = SystemProperties.getBoolean("ro.monkey", false) && SystemProperties.getBoolean("ro.debuggable", false); + + static { + ACCOUNTS_CHANGED_INTENT = new Intent(Constants.LOGIN_ACCOUNTS_CHANGED_ACTION); + ACCOUNTS_CHANGED_INTENT.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); + } + /** * This should only be called by system code. One should only call this after the service * has started. @@ -1474,6 +1482,22 @@ public class AccountManagerService extends IAccountManager.Stub { } } + private boolean inSystemImage(int callerUid) { + String[] packages = mContext.getPackageManager().getPackagesForUid(callerUid); + for (String name : packages) { + try { + PackageInfo packageInfo = + mContext.getPackageManager().getPackageInfo(name, 0 /* flags */); + if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { + return true; + } + } catch (PackageManager.NameNotFoundException e) { + return false; + } + } + return false; + } + private boolean permissionIsGranted(Account account, String authTokenType, int callerUid) { final boolean fromAuthenticator = hasAuthenticatorUid(account.type, callerUid); final boolean hasExplicitGrants = hasExplicitlyGrantedPermission(account, authTokenType); @@ -1483,7 +1507,7 @@ public class AccountManagerService extends IAccountManager.Stub { + ": is authenticator? " + fromAuthenticator + ", has explicit permission? " + hasExplicitGrants); } - return fromAuthenticator || hasExplicitGrants; + return fromAuthenticator || hasExplicitGrants || inSystemImage(callerUid); } private boolean hasAuthenticatorUid(String accountType, int callingUid) { diff --git a/core/java/android/accounts/IAccountAuthenticator.aidl b/core/java/android/accounts/IAccountAuthenticator.aidl index 48f053c..1592eea 100644 --- a/core/java/android/accounts/IAccountAuthenticator.aidl +++ b/core/java/android/accounts/IAccountAuthenticator.aidl @@ -32,7 +32,7 @@ oneway interface IAccountAuthenticator { /** * Checks that the account/password combination is valid. - * @deprecated + * note -- deprecated */ void confirmPassword(in IAccountAuthenticatorResponse response, in Account account, String password); diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 4dc23c0..d14ec15 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -608,7 +608,10 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM case SERVICE_DONE_EXECUTING_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); IBinder token = data.readStrongBinder(); - serviceDoneExecuting(token); + int type = data.readInt(); + int startId = data.readInt(); + int res = data.readInt(); + serviceDoneExecuting(token, type, startId, res); reply.writeNoException(); return true; } @@ -1746,11 +1749,15 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); } - public void serviceDoneExecuting(IBinder token) throws RemoteException { + public void serviceDoneExecuting(IBinder token, int type, int startId, + int res) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeStrongBinder(token); + data.writeInt(type); + data.writeInt(startId); + data.writeInt(res); mRemote.transact(SERVICE_DONE_EXECUTING_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY); reply.readException(); data.recycle(); diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index e045105..1e915b4 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -1215,6 +1215,7 @@ public final class ActivityThread { private static final class ServiceArgsData { IBinder token; int startId; + int flags; Intent args; public String toString() { return "ServiceArgsData{token=" + token + " startId=" + startId @@ -1417,10 +1418,11 @@ public final class ActivityThread { } public final void scheduleServiceArgs(IBinder token, int startId, - Intent args) { + int flags ,Intent args) { ServiceArgsData s = new ServiceArgsData(); s.token = token; s.startId = startId; + s.flags = flags; s.args = args; queueOrSendMessage(H.SERVICE_ARGS, s); @@ -2684,7 +2686,8 @@ public final class ActivityThread { service.onCreate(); mServices.put(data.token, service); try { - ActivityManagerNative.getDefault().serviceDoneExecuting(data.token); + ActivityManagerNative.getDefault().serviceDoneExecuting( + data.token, 0, 0, 0); } catch (RemoteException e) { // nothing to do. } @@ -2710,7 +2713,7 @@ public final class ActivityThread { } else { s.onRebind(data.intent); ActivityManagerNative.getDefault().serviceDoneExecuting( - data.token); + data.token, 0, 0, 0); } } catch (RemoteException ex) { } @@ -2736,7 +2739,7 @@ public final class ActivityThread { data.token, data.intent, doRebind); } else { ActivityManagerNative.getDefault().serviceDoneExecuting( - data.token); + data.token, 0, 0, 0); } } catch (RemoteException ex) { } @@ -2773,9 +2776,10 @@ public final class ActivityThread { if (data.args != null) { data.args.setExtrasClassLoader(s.getClassLoader()); } - s.onStart(data.args, data.startId); + int res = s.onStartCommand(data.args, data.flags, data.startId); try { - ActivityManagerNative.getDefault().serviceDoneExecuting(data.token); + ActivityManagerNative.getDefault().serviceDoneExecuting( + data.token, 1, data.startId, res); } catch (RemoteException e) { // nothing to do. } @@ -2801,7 +2805,8 @@ public final class ActivityThread { ((ApplicationContext) context).scheduleFinalCleanup(who, "Service"); } try { - ActivityManagerNative.getDefault().serviceDoneExecuting(token); + ActivityManagerNative.getDefault().serviceDoneExecuting( + token, 0, 0, 0); } catch (RemoteException e) { // nothing to do. } diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java index 5335239..ad64465 100644 --- a/core/java/android/app/ApplicationThreadNative.java +++ b/core/java/android/app/ApplicationThreadNative.java @@ -206,8 +206,14 @@ public abstract class ApplicationThreadNative extends Binder data.enforceInterface(IApplicationThread.descriptor); IBinder token = data.readStrongBinder(); int startId = data.readInt(); - Intent args = Intent.CREATOR.createFromParcel(data); - scheduleServiceArgs(token, startId, args); + int fl = data.readInt(); + Intent args; + if (data.readInt() != 0) { + args = Intent.CREATOR.createFromParcel(data); + } else { + args = null; + } + scheduleServiceArgs(token, startId, fl, args); return true; } @@ -573,12 +579,18 @@ class ApplicationThreadProxy implements IApplicationThread { } public final void scheduleServiceArgs(IBinder token, int startId, - Intent args) throws RemoteException { + int flags, Intent args) throws RemoteException { Parcel data = Parcel.obtain(); data.writeInterfaceToken(IApplicationThread.descriptor); data.writeStrongBinder(token); data.writeInt(startId); - args.writeToParcel(data, 0); + data.writeInt(flags); + if (args != null) { + data.writeInt(1); + args.writeToParcel(data, 0); + } else { + data.writeInt(0); + } mRemote.transact(SCHEDULE_SERVICE_ARGS_TRANSACTION, data, null, IBinder.FLAG_ONEWAY); data.recycle(); diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 45c202d..c3e7224 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -149,7 +149,8 @@ public interface IActivityManager extends IInterface { public void unbindFinished(IBinder token, Intent service, boolean doRebind) throws RemoteException; /* oneway */ - public void serviceDoneExecuting(IBinder token) throws RemoteException; + public void serviceDoneExecuting(IBinder token, int type, int startId, + int res) throws RemoteException; public IBinder peekService(Intent service, String resolvedType) throws RemoteException; public boolean bindBackupAgent(ApplicationInfo appInfo, int backupRestoreMode) diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java index c915770..6faaa34 100644 --- a/core/java/android/app/IApplicationThread.java +++ b/core/java/android/app/IApplicationThread.java @@ -71,7 +71,8 @@ public interface IApplicationThread extends IInterface { Intent intent, boolean rebind) throws RemoteException; void scheduleUnbindService(IBinder token, Intent intent) throws RemoteException; - void scheduleServiceArgs(IBinder token, int startId, Intent args) throws RemoteException; + void scheduleServiceArgs(IBinder token, int startId, int flags, Intent args) + throws RemoteException; void scheduleStopService(IBinder token) throws RemoteException; static final int DEBUG_OFF = 0; static final int DEBUG_ON = 1; diff --git a/core/java/android/app/IntentService.java b/core/java/android/app/IntentService.java index 2b12a2a..804c8eb 100644 --- a/core/java/android/app/IntentService.java +++ b/core/java/android/app/IntentService.java @@ -18,6 +18,7 @@ public abstract class IntentService extends Service { private volatile Looper mServiceLooper; private volatile ServiceHandler mServiceHandler; private String mName; + private boolean mRedelivery; private final class ServiceHandler extends Handler { public ServiceHandler(Looper looper) { @@ -36,6 +37,19 @@ public abstract class IntentService extends Service { mName = name; } + /** + * Control redelivery of intents. If called with true, + * {@link #onStartCommand(Intent, int, int)} will return + * {@link Service#START_REDELIVER_INTENT} instead of + * {@link Service#START_NOT_STICKY}, so that if this service's process + * is called while it is executing the Intent in + * {@link #onHandleIntent(Intent)}, then when later restarted the same Intent + * will be re-delivered to it, to retry its execution. + */ + public void setIntentRedelivery(boolean enabled) { + mRedelivery = enabled; + } + @Override public void onCreate() { super.onCreate(); @@ -48,7 +62,6 @@ public abstract class IntentService extends Service { @Override public void onStart(Intent intent, int startId) { - super.onStart(intent, startId); Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; msg.obj = intent; @@ -56,6 +69,12 @@ public abstract class IntentService extends Service { } @Override + public int onStartCommand(Intent intent, int flags, int startId) { + onStart(intent, startId); + return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY; + } + + @Override public void onDestroy() { mServiceLooper.quit(); } diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java index 8a9cca7..f776452 100644 --- a/core/java/android/app/SearchDialog.java +++ b/core/java/android/app/SearchDialog.java @@ -428,7 +428,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS mSearchAutoComplete.setAdapter((SuggestionsAdapter)null); // close any leftover cursor if (mSuggestionsAdapter != null) { - mSuggestionsAdapter.changeCursor(null); + mSuggestionsAdapter.close(); } mSuggestionsAdapter = null; } diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java index 4854952..e43834a 100644 --- a/core/java/android/app/SearchManager.java +++ b/core/java/android/app/SearchManager.java @@ -1769,6 +1769,7 @@ public class SearchManager /** * @deprecated This method is an obsolete internal implementation detail. Do not use. */ + @Deprecated public void onCancel(DialogInterface dialog) { throw new UnsupportedOperationException(); } @@ -1776,6 +1777,7 @@ public class SearchManager /** * @deprecated This method is an obsolete internal implementation detail. Do not use. */ + @Deprecated public void onDismiss(DialogInterface dialog) { throw new UnsupportedOperationException(); } diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java index 2dedaa7..60c756b 100644 --- a/core/java/android/app/Service.java +++ b/core/java/android/app/Service.java @@ -22,6 +22,7 @@ import android.content.Intent; import android.content.ContextWrapper; import android.content.Context; import android.content.res.Configuration; +import android.os.Build; import android.os.RemoteException; import android.os.IBinder; import android.util.Log; @@ -169,20 +170,119 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac } /** + * @deprecated Implement {@link #onStartCommand(Intent, int, int)} instead. + */ + @Deprecated + public void onStart(Intent intent, int startId) { + } + + /** + * Bits returned by {@link #onStartCommand} describing how to continue + * the service if it is killed. May be {@link #START_STICKY}, + * {@link #START_NOT_STICKY}, {@link #START_REDELIVER_INTENT}, + * or {@link #START_STICKY_COMPATIBILITY}. + */ + public static final int START_CONTINUATION_MASK = 0xf; + + /** + * Constant to return from {@link #onStartCommand}: compatibility + * version of {@link #START_STICKY} that does not guarantee that + * {@link #onStartCommand} will be called again after being killed. + */ + public static final int START_STICKY_COMPATIBILITY = 0; + + /** + * Constant to return from {@link #onStartCommand}: if this service's + * process is killed while it is started (after returning from + * {@link #onStartCommand}), then leave it in the started state but + * don't retain this delivered intent. Later the system will try to + * re-create the service, but it will <em>not</em> call + * {@link #onStartCommand} unless there has been a new call to + * {@link Context#startService Context.startService(Intent)} with a new + * Intent to deliver. + * + * <p>This mode makes sense for things that will be explicitly started + * and stopped to run for arbitrary periods of time, such as a service + * performing background music playback. + */ + public static final int START_STICKY = 1; + + /** + * Constant to return from {@link #onStartCommand}: if this service's + * process is killed while it is started (after returning from + * {@link #onStartCommand}), and there are no new start intents to + * deliver to it, then take the service out of the started state and + * don't recreate until a future explicit call to + * {@link Context#startService Context.startService(Intent)}. + * + * <p>This mode makes sense for things that want to do some work as a + * result of being started, but can be stopped when under memory pressure + * and will explicit start themselves again later to do more work. An + * example of such a service would be one that polls for data from + * a server: it could schedule an alarm to poll every N minutes by having + * the alarm start its service. When its {@link #onStartCommand} is + * called from the alarm, it schedules a new alarm for N minutes later, + * and spawns a thread to do its networking. If its process is killed + * while doing that check, the service will not be restarted until the + * alarm goes off. + */ + public static final int START_NOT_STICKY = 2; + + /** + * Constant to return from {@link #onStartCommand}: if this service's + * process is killed while it is started (after returning from + * {@link #onStartCommand}), then it will be scheduled for a restart + * and the last delivered Intent re-delivered to it again via + * {@link #onStartCommand}. This Intent will remain scheduled for + * redelivery until the service calls {@link #stopSelf(int)} with the + * start ID provided to {@link #onStartCommand}. + */ + public static final int START_REDELIVER_INTENT = 3; + + /** + * This flag is set in {@link #onStartCommand} if the Intent is a + * re-delivery of a previously delivered intent, because the service + * had previously returned {@link #START_REDELIVER_INTENT} but had been + * killed before calling {@link #stopSelf(int)} for that Intent. + */ + public static final int START_FLAG_REDELIVERY = 0x0001; + + /** + * This flag is set in {@link #onStartCommand} if the Intent is a + * a retry because the original attempt never got to or returned from + * {@link #onStartCommand(Intent, int, int)}. + */ + public static final int START_FLAG_RETRY = 0x0002; + + /** * Called by the system every time a client explicitly starts the service by calling * {@link android.content.Context#startService}, providing the arguments it supplied and a * unique integer token representing the start request. Do not call this method directly. - * + * + * <p>For backwards compatibility, the default implementation calls + * {@link #onStart} and returns either {@link #START_STICKY} + * or {@link #START_STICKY_COMPATIBILITY}. + * * @param intent The Intent supplied to {@link android.content.Context#startService}, - * as given. + * as given. This may be null if the service is being restarted after + * its process has gone away, and it had previously returned anything + * except {@link #START_STICKY_COMPATIBILITY}. + * @param flags Additional data about this start request. Currently either + * 0, {@link #START_FLAG_REDELIVERY}, or {@link #START_FLAG_RETRY}. * @param startId A unique integer representing this specific request to - * start. Use with {@link #stopSelfResult(int)}. + * start. Use with {@link #stopSelfResult(int)}. + * + * @return The return value indicates what semantics the system should + * use for the service's current started state. It may be one of the + * constants associated with the {@link #START_CONTINUATION_MASK} bits. * * @see #stopSelfResult(int) */ - public void onStart(Intent intent, int startId) { + public int onStartCommand(Intent intent, int flags, int startId) { + onStart(intent, startId); + return mStartCompatibility ? START_STICKY_COMPATIBILITY : START_STICKY; } - + /** * Called by the system to notify a Service that it is no longer used and is being removed. The * service should clean up an resources it holds (threads, registered @@ -393,6 +493,8 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac mToken = token; mApplication = application; mActivityManager = (IActivityManager)activityManager; + mStartCompatibility = getApplicationInfo().targetSdkVersion + < Build.VERSION_CODES.ECLAIR; } final String getClassName() { @@ -405,4 +507,5 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac private IBinder mToken = null; private Application mApplication = null; private IActivityManager mActivityManager = null; + private boolean mStartCompatibility = false; } diff --git a/core/java/android/app/SuggestionsAdapter.java b/core/java/android/app/SuggestionsAdapter.java index 52e4a1f..90f8c50 100644 --- a/core/java/android/app/SuggestionsAdapter.java +++ b/core/java/android/app/SuggestionsAdapter.java @@ -65,6 +65,7 @@ class SuggestionsAdapter extends ResourceCursorAdapter { private WeakHashMap<String, Drawable.ConstantState> mOutsideDrawablesCache; private SparseArray<Drawable.ConstantState> mBackgroundsCache; private boolean mGlobalSearchMode; + private boolean mClosed = false; // Cached column indexes, updated when the cursor changes. private int mFormatCol; @@ -199,6 +200,12 @@ class SuggestionsAdapter extends ResourceCursorAdapter { } } + public void close() { + if (DBG) Log.d(LOG_TAG, "close()"); + changeCursor(null); + mClosed = true; + } + /** * Cache columns. */ @@ -206,6 +213,12 @@ class SuggestionsAdapter extends ResourceCursorAdapter { public void changeCursor(Cursor c) { if (DBG) Log.d(LOG_TAG, "changeCursor(" + c + ")"); + if (mClosed) { + Log.w(LOG_TAG, "Tried to change cursor after adapter was closed."); + if (c != null) c.close(); + return; + } + try { Cursor oldCursor = getCursor(); super.changeCursor(c); diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java index 1ec7fb3..c15bc20 100644 --- a/core/java/android/bluetooth/BluetoothUuid.java +++ b/core/java/android/bluetooth/BluetoothUuid.java @@ -37,6 +37,7 @@ public final class BluetoothUuid { public static final UUID Handsfree = UUID.fromString("0000111E-0000-1000-8000-00805F9B34FB"); public static final UUID AvrcpController = UUID.fromString("0000110E-0000-1000-8000-00805F9B34FB"); + public static final UUID AvrcpTarget = UUID.fromString("0000110C-0000-1000-8000-00805F9B34FB"); public static boolean isAudioSource(UUID uuid) { return uuid.equals(AudioSource); @@ -61,4 +62,8 @@ public final class BluetoothUuid { public static boolean isAvrcpController(UUID uuid) { return uuid.equals(AvrcpController); } + + public static boolean isAvrcpTarget(UUID uuid) { + return uuid.equals(AvrcpTarget); + } } diff --git a/core/java/android/content/AbstractThreadedSyncAdapter.java b/core/java/android/content/AbstractThreadedSyncAdapter.java index 538225a..424cb19 100644 --- a/core/java/android/content/AbstractThreadedSyncAdapter.java +++ b/core/java/android/content/AbstractThreadedSyncAdapter.java @@ -85,7 +85,6 @@ public abstract class AbstractThreadedSyncAdapter { mSyncThread = new SyncThread( "SyncAdapterThread-" + mNumSyncStarts.incrementAndGet(), syncContextClient, authority, account, extras); - Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); mSyncThread.start(); alreadyInProgress = false; } else { @@ -133,6 +132,8 @@ public abstract class AbstractThreadedSyncAdapter { } public void run() { + Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); + if (isCanceled()) { return; } diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java index b915803..88a4d02 100644 --- a/core/java/android/content/ContentResolver.java +++ b/core/java/android/content/ContentResolver.java @@ -887,6 +887,7 @@ public abstract class ContentResolver { * @deprecated instead use * {@link #requestSync(android.accounts.Account, String, android.os.Bundle)} */ + @Deprecated public void startSync(Uri uri, Bundle extras) { Account account = null; if (extras != null) { @@ -967,6 +968,7 @@ public abstract class ContentResolver { * @param uri the uri of the provider to sync or null to sync all providers. * @deprecated instead use {@link #cancelSync(android.accounts.Account, String)} */ + @Deprecated public void cancelSync(Uri uri) { cancelSync(null /* all accounts */, uri != null ? uri.getAuthority() : null); } diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index d86ab79..60551b8 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -491,42 +491,49 @@ public abstract class Context { * @deprecated Use {@link android.app.WallpaperManager#getDrawable * WallpaperManager.get()} instead. */ + @Deprecated public abstract Drawable getWallpaper(); /** * @deprecated Use {@link android.app.WallpaperManager#peekDrawable * WallpaperManager.peek()} instead. */ + @Deprecated public abstract Drawable peekWallpaper(); /** * @deprecated Use {@link android.app.WallpaperManager#getDesiredMinimumWidth() * WallpaperManager.getDesiredMinimumWidth()} instead. */ + @Deprecated public abstract int getWallpaperDesiredMinimumWidth(); /** * @deprecated Use {@link android.app.WallpaperManager#getDesiredMinimumHeight() * WallpaperManager.getDesiredMinimumHeight()} instead. */ + @Deprecated public abstract int getWallpaperDesiredMinimumHeight(); /** * @deprecated Use {@link android.app.WallpaperManager#setBitmap(Bitmap) * WallpaperManager.set()} instead. */ + @Deprecated public abstract void setWallpaper(Bitmap bitmap) throws IOException; /** * @deprecated Use {@link android.app.WallpaperManager#setStream(InputStream) * WallpaperManager.set()} instead. */ + @Deprecated public abstract void setWallpaper(InputStream data) throws IOException; /** * @deprecated Use {@link android.app.WallpaperManager#clear * WallpaperManager.clear()} instead. */ + @Deprecated public abstract void clearWallpaper() throws IOException; /** diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index a3517f8..9dedca6 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -1696,7 +1696,6 @@ public class Intent implements Parcelable { public static final String ACTION_REBOOT = "android.intent.action.REBOOT"; - /** * Broadcast Action: a remote intent is to be broadcasted. * @@ -1711,6 +1710,18 @@ public class Intent implements Parcelable { public static final String ACTION_REMOTE_INTENT = "android.intent.action.REMOTE_INTENT"; + /** + * Broadcast Action: hook for permforming cleanup after a system update. + * + * The broadcast is sent when the system is booting, before the + * BOOT_COMPLETED broadcast. It is only sent to receivers in the system + * image. A receiver for this should do its work and then disable itself + * so that it does not get run again at the next boot. + * @hide + */ + public static final String ACTION_PRE_BOOT_COMPLETED = + "android.intent.action.PRE_BOOT_COMPLETED"; + // --------------------------------------------------------------------- // --------------------------------------------------------------------- // Standard intent categories (see addCategory()). @@ -1970,9 +1981,9 @@ public class Intent implements Parcelable { /** * Used as an int extra field in {@link android.content.Intent#ACTION_DOCK_EVENT} * intents to request the dock state. Possible values are - * {@link android.content.Intent#ACTION_DOCK_STATE_UNDOCKED}, - * {@link android.content.Intent#ACTION_DOCK_STATE_DESK}, or - * {@link android.content.Intent#ACTION_DOCK_STATE_CAR}. + * {@link android.content.Intent#EXTRA_DOCK_STATE_UNDOCKED}, + * {@link android.content.Intent#EXTRA_DOCK_STATE_DESK}, or + * {@link android.content.Intent#EXTRA_DOCK_STATE_CAR}. * @hide */ public static final String EXTRA_DOCK_STATE = "android.intent.extra.DOCK_STATE"; @@ -2251,6 +2262,13 @@ public class Intent implements Parcelable { * @hide */ public static final int FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT = 0x20000000; + /** + * Set when this broadcast is for a boot upgrade, a special mode that + * allows the broadcast to be sent before the system is ready and launches + * the app process with no providers running in it. + * @hide + */ + public static final int FLAG_RECEIVER_BOOT_UPGRADE = 0x10000000; // --------------------------------------------------------------------- // --------------------------------------------------------------------- diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java index 82cf23f..15144a2 100644 --- a/core/java/android/content/SyncManager.java +++ b/core/java/android/content/SyncManager.java @@ -33,6 +33,7 @@ import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.RegisteredServicesCache; +import android.content.pm.ProviderInfo; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.os.Bundle; @@ -1996,11 +1997,19 @@ class SyncManager implements OnAccountsUpdatedListener { private void installHandleTooManyDeletesNotification(Account account, String authority, long numDeletes) { if (mNotificationMgr == null) return; + + final ProviderInfo providerInfo = mContext.getPackageManager().resolveContentProvider( + authority, 0 /* flags */); + if (providerInfo == null) { + return; + } + CharSequence authorityName = providerInfo.loadLabel(mContext.getPackageManager()); + Intent clickIntent = new Intent(); clickIntent.setClassName("com.android.providers.subscribedfeeds", "com.android.settings.SyncActivityTooManyDeletes"); clickIntent.putExtra("account", account); - clickIntent.putExtra("provider", authority); + clickIntent.putExtra("provider", authorityName.toString()); clickIntent.putExtra("numDeletes", numDeletes); if (!isActivityAvailable(clickIntent)) { @@ -2014,14 +2023,13 @@ class SyncManager implements OnAccountsUpdatedListener { CharSequence tooManyDeletesDescFormat = mContext.getResources().getText( R.string.contentServiceTooManyDeletesNotificationDesc); - String[] authorities = authority.split(";"); Notification notification = new Notification(R.drawable.stat_notify_sync_error, mContext.getString(R.string.contentServiceSync), System.currentTimeMillis()); notification.setLatestEventInfo(mContext, mContext.getString(R.string.contentServiceSyncNotificationTitle), - String.format(tooManyDeletesDescFormat.toString(), authorities[0]), + String.format(tooManyDeletesDescFormat.toString(), authorityName), pendingIntent); notification.flags |= Notification.FLAG_ONGOING_EVENT; mNotificationMgr.notify(account.hashCode() ^ authority.hashCode(), notification); diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index 7760612..4fc4fb9 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -123,7 +123,6 @@ interface IPackageManager { * providers that can sync. * @param outInfo Filled in with a list of the ProviderInfo for each * name in 'outNames'. - * @deprecated */ void querySyncProviders(inout List<String> outNames, inout List<ProviderInfo> outInfo); diff --git a/core/java/android/content/pm/ProviderInfo.java b/core/java/android/content/pm/ProviderInfo.java index d61e95b..ec01775 100644 --- a/core/java/android/content/pm/ProviderInfo.java +++ b/core/java/android/content/pm/ProviderInfo.java @@ -79,6 +79,7 @@ public final class ProviderInfo extends ComponentInfo * @deprecated This flag is now being ignored. The current way to make a provider * syncable is to provide a SyncAdapter service for a given provider/account type. */ + @Deprecated public boolean isSyncable = false; public ProviderInfo() { diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java index 184d6dc..6143b6c 100644 --- a/core/java/android/database/sqlite/SQLiteDatabase.java +++ b/core/java/android/database/sqlite/SQLiteDatabase.java @@ -517,6 +517,7 @@ public class SQLiteDatabase extends SQLiteClosable { * @deprecated if the db is locked more than once (becuase of nested transactions) then the lock * will not be yielded. Use yieldIfContendedSafely instead. */ + @Deprecated public boolean yieldIfContended() { return yieldIfContendedHelper(false /* do not check yielding */); } diff --git a/core/java/android/hardware/SensorListener.java b/core/java/android/hardware/SensorListener.java index cfa184b..c71e968 100644 --- a/core/java/android/hardware/SensorListener.java +++ b/core/java/android/hardware/SensorListener.java @@ -20,9 +20,8 @@ package android.hardware; * Used for receiving notifications from the SensorManager when * sensor values have changed. * - * This interface is deprecated, use + * @deprecated Use * {@link android.hardware.SensorEventListener SensorEventListener} instead. - * */ @Deprecated public interface SensorListener { diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java index bf945ec..271f973 100644 --- a/core/java/android/hardware/SensorManager.java +++ b/core/java/android/hardware/SensorManager.java @@ -116,47 +116,67 @@ public class SensorManager @Deprecated public static final int SENSOR_ORIENTATION_RAW = 1 << 7; - /** A constant that includes all sensors */ + /** A constant that includes all sensors + * @deprecated use {@link android.hardware.Sensor Sensor} instead. + */ @Deprecated public static final int SENSOR_ALL = 0x7F; - /** Smallest sensor ID */ + /** Smallest sensor ID + * @deprecated use {@link android.hardware.Sensor Sensor} instead. + */ @Deprecated public static final int SENSOR_MIN = SENSOR_ORIENTATION; - /** Largest sensor ID */ + /** Largest sensor ID + * @deprecated use {@link android.hardware.Sensor Sensor} instead. + */ @Deprecated public static final int SENSOR_MAX = ((SENSOR_ALL + 1)>>1); /** Index of the X value in the array returned by - * {@link android.hardware.SensorListener#onSensorChanged} */ + * {@link android.hardware.SensorListener#onSensorChanged} + * @deprecated use {@link android.hardware.Sensor Sensor} instead. + */ @Deprecated public static final int DATA_X = 0; /** Index of the Y value in the array returned by - * {@link android.hardware.SensorListener#onSensorChanged} */ + * {@link android.hardware.SensorListener#onSensorChanged} + * @deprecated use {@link android.hardware.Sensor Sensor} instead. + */ @Deprecated public static final int DATA_Y = 1; /** Index of the Z value in the array returned by - * {@link android.hardware.SensorListener#onSensorChanged} */ + * {@link android.hardware.SensorListener#onSensorChanged} + * @deprecated use {@link android.hardware.Sensor Sensor} instead. + */ @Deprecated public static final int DATA_Z = 2; /** Offset to the untransformed values in the array returned by - * {@link android.hardware.SensorListener#onSensorChanged} */ + * {@link android.hardware.SensorListener#onSensorChanged} + * @deprecated use {@link android.hardware.Sensor Sensor} instead. + */ @Deprecated public static final int RAW_DATA_INDEX = 3; /** Index of the untransformed X value in the array returned by - * {@link android.hardware.SensorListener#onSensorChanged} */ + * {@link android.hardware.SensorListener#onSensorChanged} + * @deprecated use {@link android.hardware.Sensor Sensor} instead. + */ @Deprecated public static final int RAW_DATA_X = 3; /** Index of the untransformed Y value in the array returned by - * {@link android.hardware.SensorListener#onSensorChanged} */ + * {@link android.hardware.SensorListener#onSensorChanged} + * @deprecated use {@link android.hardware.Sensor Sensor} instead. + */ @Deprecated public static final int RAW_DATA_Y = 4; /** Index of the untransformed Z value in the array returned by - * {@link android.hardware.SensorListener#onSensorChanged} */ + * {@link android.hardware.SensorListener#onSensorChanged} + * @deprecated use {@link android.hardware.Sensor Sensor} instead. + */ @Deprecated public static final int RAW_DATA_Z = 5; diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java index 3e4bbd5..f88fcdc 100644 --- a/core/java/android/net/MobileDataStateTracker.java +++ b/core/java/android/net/MobileDataStateTracker.java @@ -147,7 +147,10 @@ public class MobileDataStateTracker extends NetworkStateTracker { ", unavailable = " + unavailable + ", reason = " + (reason == null ? "(unspecified)" : reason)); + if (isApnTypeIncluded(apnTypeList)) { + // set this even if the apn isn't Enabled + mNetworkInfo.setIsAvailable(!unavailable); if (mEnabled == false) { // if we're not enabled but the APN Type is supported by this connection // we should record the interface name if one's provided. If the user @@ -168,7 +171,6 @@ public class MobileDataStateTracker extends NetworkStateTracker { return; } - mNetworkInfo.setIsAvailable(!unavailable); if (mMobileDataState != state) { mMobileDataState = state; switch (state) { @@ -320,6 +322,7 @@ public class MobileDataStateTracker extends NetworkStateTracker { mEnabled = true; // need to set self to CONNECTING so the below message is handled. mMobileDataState = Phone.DataState.CONNECTING; + setDetailedState(DetailedState.CONNECTING, Phone.REASON_APN_CHANGED, null); //send out a connected message Intent intent = new Intent(TelephonyIntents. ACTION_ANY_DATA_CONNECTION_STATE_CHANGED); diff --git a/core/java/android/net/NetworkStateTracker.java b/core/java/android/net/NetworkStateTracker.java index 418f511..54529ae 100644 --- a/core/java/android/net/NetworkStateTracker.java +++ b/core/java/android/net/NetworkStateTracker.java @@ -48,7 +48,7 @@ public abstract class NetworkStateTracker extends Handler { private boolean mDefaultRouteSet; private boolean mTeardownRequested; - private static boolean DBG = Config.LOGV; + private static boolean DBG = true; private static final String TAG = "NetworkStateTracker"; public static final int EVENT_STATE_CHANGED = 1; diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index 1775a4b..6c2a27a 100644 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -70,6 +70,7 @@ public class Build { * * @deprecated Use {@link #SDK_INT} to easily get this as an integer. */ + @Deprecated public static final String SDK = getString("ro.build.version.sdk"); /** @@ -132,6 +133,19 @@ public class Build { * </ul> */ public static final int DONUT = 4; + /** + * Current work on "Eclair" development branch. + * + * <p>Applications targeting this or a later release will get these + * new changes in behavior:</p> + * <ul> + * <li> The {@link android.app.Service#onStartCommand + * Service.onStartCommand} function will return the new + * {@link android.app.Service#START_STICKY} behavior instead of the + * old compatibility {@link android.app.Service#START_STICKY_COMPATIBILITY}. + * </ul> + */ + public static final int ECLAIR = CUR_DEVELOPMENT; } /** The type of build, like "user" or "eng". */ diff --git a/core/java/android/os/HandlerStateMachine.java b/core/java/android/os/HandlerStateMachine.java index d004a25..9e7902b 100644 --- a/core/java/android/os/HandlerStateMachine.java +++ b/core/java/android/os/HandlerStateMachine.java @@ -56,22 +56,22 @@ import android.util.LogPrinter; } class S1 extends HandlerState { - @Override public void enter(Message message) { + &#064;Override public void enter(Message message) { } - @Override public void processMessage(Message message) { + &#064;Override public void processMessage(Message message) { deferMessage(message); if (message.what == TEST_WHAT_2) { transitionTo(mS2); } } - @Override public void exit(Message message) { + &#064;Override public void exit(Message message) { } } class S2 extends HandlerState { - @Override public void processMessage(Message message) { + &#064;Override public void processMessage(Message message) { // Do some processing if (message.what == TEST_WHAT_2) { transtionTo(mS1); diff --git a/core/java/android/pim/vcard/Constants.java b/core/java/android/pim/vcard/Constants.java new file mode 100644 index 0000000..ca41ce5 --- /dev/null +++ b/core/java/android/pim/vcard/Constants.java @@ -0,0 +1,94 @@ +/* + * 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 composer and parser. + */ +/* package */ class Constants { + + public static final String ATTR_TYPE = "TYPE"; + + public static final String VERSION_V21 = "2.1"; + public static final String VERSION_V30 = "3.0"; + + // Properties both the current (as of 2009-08-17) ContactsStruct 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"; + // Phone number for Skype, available as usual phone. + public static final String PROPERTY_X_SKYPE_PSTNNUMBER = "X-SKYPE-PSTNNUMBER"; + // Some device emits this "X-" attribute, 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"; + + // How more than one TYPE fields are expressed is different between vCard 2.1 and vCard 3.0 + // + // e.g. + // 1) Probably valid in both vCard 2.1 and vCard 3.0: "ADR;TYPE=DOM;TYPE=HOME:..." + // 2) Valid in vCard 2.1 but not in vCard 3.0: "ADR;DOM;HOME:..." + // 3) Valid in vCard 3.0 but not in vCard 2.1: "ADR;TYPE=DOM,HOME:..." + // + // 2) has been the default of VCard exporter/importer in Android, but we can see the other + // formats in vCard data emitted by the other softwares/devices. + // + // So we are currently not sure which type is the best; probably we will have to change which + // type should be emitted depending on the device. + public static final String ATTR_TYPE_HOME = "HOME"; + public static final String ATTR_TYPE_WORK = "WORK"; + public static final String ATTR_TYPE_FAX = "FAX"; + public static final String ATTR_TYPE_CELL = "CELL"; + public static final String ATTR_TYPE_VOICE = "VOICE"; + public static final String ATTR_TYPE_INTERNET = "INTERNET"; + + public static final String ATTR_TYPE_PREF = "PREF"; + + // Phone types valid in vCard and known to ContactsContract, but not so common. + public static final String ATTR_TYPE_CAR = "CAR"; + public static final String ATTR_TYPE_ISDN = "ISDN"; + public static final String ATTR_TYPE_PAGER = "PAGER"; + + // Phone types existing in vCard 2.1 but not known to ContactsContract. + // TODO: should make parser make these TYPE_CUSTOM. + public static final String ATTR_TYPE_MODEM = "MODEM"; + public static final String ATTR_TYPE_MSG = "MSG"; + public static final String ATTR_TYPE_BBS = "BBS"; + public static final String ATTR_TYPE_VIDEO = "VIDEO"; + + // Phone types existing in the current Contacts structure but not valid in vCard (at least 2.1) + // These types are encoded to "X-" attributes when composing vCard for now. + // Parser passes these even if "X-" is added to the attribute. + public static final String ATTR_TYPE_PHONE_EXTRA_OTHER = "OTHER"; + public static final String ATTR_TYPE_PHONE_EXTRA_CALLBACK = "CALLBACK"; + // TODO: may be "TYPE=COMPANY,PREF", not "COMPANY-MAIN". + public static final String ATTR_TYPE_PHONE_EXTRA_COMPANY_MAIN = "COMPANY-MAIN"; + public static final String ATTR_TYPE_PHONE_EXTRA_RADIO = "RADIO"; + public static final String ATTR_TYPE_PHONE_EXTRA_TELEX = "TELEX"; + public static final String ATTR_TYPE_PHONE_EXTRA_TTY_TDD = "TTY-TDD"; + public static final String ATTR_TYPE_PHONE_EXTRA_ASSISTANT = "ASSISTANT"; + + // DoCoMo specific attribute. Used with "SOUND" property, which is alternate of SORT-STRING in + // vCard 3.0. + public static final String ATTR_TYPE_X_IRMC_N = "X-IRMC-N"; + + private Constants() { + } +}
\ No newline at end of file diff --git a/core/java/android/pim/vcard/ContactStruct.java b/core/java/android/pim/vcard/ContactStruct.java index 46725d3..8e8d46a 100644 --- a/core/java/android/pim/vcard/ContactStruct.java +++ b/core/java/android/pim/vcard/ContactStruct.java @@ -15,38 +15,58 @@ */ package android.pim.vcard; -import android.content.AbstractSyncableContentProvider; +import android.content.ContentProviderOperation; import android.content.ContentResolver; -import android.content.ContentUris; import android.content.ContentValues; -import android.net.Uri; -import android.provider.Contacts; -import android.provider.Contacts.ContactMethods; -import android.provider.Contacts.Extensions; -import android.provider.Contacts.GroupMembership; -import android.provider.Contacts.Organizations; -import android.provider.Contacts.People; -import android.provider.Contacts.Phones; -import android.provider.Contacts.Photos; +import android.content.OperationApplicationException; +import android.os.RemoteException; +import android.provider.ContactsContract; +import android.provider.ContactsContract.Data; +import android.provider.ContactsContract.RawContacts; +import android.provider.ContactsContract.CommonDataKinds.Email; +import android.provider.ContactsContract.CommonDataKinds.Im; +import android.provider.ContactsContract.CommonDataKinds.Miscellaneous; +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.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; -import java.util.Locale; import java.util.Map; -import java.util.Map.Entry; /** * This class bridges between data structure of Contact app and VCard data. */ public class ContactStruct { - private static final String LOG_TAG = "ContactStruct"; + private static final String LOG_TAG = "vcard.ContactStruct"; + + // Key: the name shown in VCard. e.g. "X-AIM", "X-ICQ" + // Value: the result of {@link Contacts.ContactMethods#encodePredefinedImProtocol} + private static final Map<String, Integer> sImMap = new HashMap<String, Integer>(); + + static { + sImMap.put(Constants.PROPERTY_X_AIM, Im.PROTOCOL_AIM); + sImMap.put(Constants.PROPERTY_X_MSN, Im.PROTOCOL_MSN); + sImMap.put(Constants.PROPERTY_X_YAHOO, Im.PROTOCOL_YAHOO); + sImMap.put(Constants.PROPERTY_X_ICQ, Im.PROTOCOL_ICQ); + sImMap.put(Constants.PROPERTY_X_JABBER, Im.PROTOCOL_JABBER); + sImMap.put(Constants.PROPERTY_X_SKYPE_USERNAME, Im.PROTOCOL_SKYPE); + sImMap.put(Constants.PROPERTY_X_GOOGLE_TALK, Im.PROTOCOL_GOOGLE_TALK); + sImMap.put(Constants.PROPERTY_X_GOOGLE_TALK_WITH_SPACE, Im.PROTOCOL_GOOGLE_TALK); + } /** * @hide only for testing @@ -85,11 +105,7 @@ public class ContactStruct { /** * @hide only for testing */ - static public class ContactMethod { - // Contacts.KIND_EMAIL, Contacts.KIND_POSTAL - public final int kind; - // e.g. Contacts.ContactMethods.TYPE_HOME, Contacts.PhoneColumns.TYPE_HOME - // If type == Contacts.PhoneColumns.TYPE_CUSTOM, label is used. + static public class EmailData { public final int type; public final String data; // Used only when TYPE is TYPE_CUSTOM. @@ -97,35 +113,143 @@ public class ContactStruct { // isPrimary is changable only when there's no appropriate one existing in // the original VCard. public boolean isPrimary; - public ContactMethod(int kind, int type, String data, String label, - boolean isPrimary) { - this.kind = kind; + public EmailData(int type, String data, String label, boolean isPrimary) { this.type = type; this.data = data; - this.label = 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; + + // Used only when type variable 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 PostalData(int type, List<String> propValueList, + 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 ContactMethod) { + if (obj instanceof PostalData) { return false; } - ContactMethod contactMethod = (ContactMethod)obj; - return (kind == contactMethod.kind && type == contactMethod.type && - data.equals(contactMethod.data) && label.equals(contactMethod.label) && - isPrimary == contactMethod.isPrimary); + 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(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(' '); + } + builder.append(addressPart); + empty = false; + } + } + } else { + for (int i = 0; i < ADDR_MAX_DATA_SIZE; i++) { + String addressPart = dataArray[i]; + if (!TextUtils.isEmpty(addressPart)) { + if (!empty) { + builder.append(' '); + } + builder.append(addressPart); + empty = false; + } + } + } + + return builder.toString().trim(); } @Override public String toString() { - return String.format("kind: %d, type: %d, data: %s, label: %s, isPrimary: %s", - kind, type, data, label, isPrimary); + return String.format("type: %d, label: %s, isPrimary: %s", + type, label, isPrimary); } } /** - * @hide only for testing + * @hide only for testing. */ static public class OrganizationData { public final int type; @@ -161,7 +285,54 @@ public class ContactStruct { } } - static class Property { + static public class ImData { + public final int type; + public final String data; + public final String label; + public final boolean isPrimary; + + // TODO: ContactsConstant#PROTOCOL, ContactsConstant#CUSTOM_PROTOCOL should be used? + public ImData(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 ImData) { + return false; + } + ImData imData = (ImData)obj; + return (type == imData.type && data.equals(imData.data) && + label.equals(imData.label) && isPrimary == imData.isPrimary); + } + + @Override + public String toString() { + return String.format("type: %d, data: %s, label: %s, isPrimary: %s", + type, data, label, isPrimary); + } + } + + /** + * @hide only for testing. + */ + static public 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 PhotoData(int type, String formatName, byte[] photoBytes) { + this.type = type; + this.formatName = formatName; + this.photoBytes = photoBytes; + } + } + + static /* package */ class Property { private String mPropertyName; private Map<String, Collection<String>> mParameterMap = new HashMap<String, Collection<String>>(); @@ -178,7 +349,7 @@ public class ContactStruct { public void addParameter(final String paramName, final String paramValue) { Collection<String> values; - if (mParameterMap.containsKey(paramName)) { + if (!mParameterMap.containsKey(paramName)) { if (paramName.equals("TYPE")) { values = new HashSet<String>(); } else { @@ -188,6 +359,7 @@ public class ContactStruct { } else { values = mParameterMap.get(paramName); } + values.add(paramValue); } public void addToPropertyValueList(final String propertyValue) { @@ -213,123 +385,129 @@ public class ContactStruct { } } - private String mName; - private String mPhoneticName; - // private String mPhotoType; - private byte[] mPhotoBytes; - private List<String> mNotes; - private List<PhoneData> mPhoneList; - private List<ContactMethod> mContactMethodList; - private List<OrganizationData> mOrganizationList; - private Map<String, List<String>> mExtensionMap; + private String mFamilyName; + private String mGivenName; + private String mMiddleName; + private String mPrefix; + private String mSuffix; - private int mNameOrderType; + // Used only when no family nor given name is found. + private String mFullName; - /* private variables bellow is for temporary use. */ + private String mPhoneticFamilyName; + private String mPhoneticGivenName; + private String mPhoneticMiddleName; - // For name, there are three fields in vCard: FN, N, NAME. - // We prefer FN, which is a required field in vCard 3.0 , but not in vCard 2.1. - // Next, we prefer NAME, which is defined only in vCard 3.0. - // Finally, we use N, which is a little difficult to parse. - private String mTmpFullName; - private String mTmpNameFromNProperty; + private String mPhoneticFullName; + + private List<String> mNickNameList; - // Some vCard has "X-PHONETIC-FIRST-NAME", "X-PHONETIC-MIDDLE-NAME", and - // "X-PHONETIC-LAST-NAME" - private String mTmpXPhoneticFirstName; - private String mTmpXPhoneticMiddleName; - private String mTmpXPhoneticLastName; + 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 final int mVCardType; // Each Column of four properties has ISPRIMARY field // (See android.provider.Contacts) - // If false even after the following loop, we choose the first - // entry as a "primary" entry. + // If false even after the parsing loop, we choose the first entry as a "primary" + // entry. private boolean mPrefIsSet_Address; private boolean mPrefIsSet_Phone; private boolean mPrefIsSet_Email; private boolean mPrefIsSet_Organization; public ContactStruct() { - mNameOrderType = VCardConfig.NAME_ORDER_TYPE_DEFAULT; + this(VCardConfig.VCARD_TYPE_V21_GENERIC); } - public ContactStruct(int nameOrderType) { - mNameOrderType = nameOrderType; + public ContactStruct(int vcardType) { + mVCardType = vcardType; } - + /** - * @hide only for test + * @hide only for testing. */ - public ContactStruct(String name, - String phoneticName, - byte[] photoBytes, + public ContactStruct(String givenName, + String familyName, + String middleName, + String prefix, + String suffix, + String phoneticGivenName, + String pheneticFamilyName, + String phoneticMiddleName, + List<byte[]> photoBytesList, List<String> notes, List<PhoneData> phoneList, - List<ContactMethod> contactMethodList, + List<EmailData> emailList, + List<PostalData> postalList, List<OrganizationData> organizationList, - Map<String, List<String>> extensionMap) { - mName = name; - mPhoneticName = phoneticName; - mPhotoBytes = photoBytes; - mContactMethodList = contactMethodList; + List<PhotoData> photoList, + List<String> websiteList) { + this(VCardConfig.VCARD_TYPE_DEFAULT); + mGivenName = givenName; + mFamilyName = familyName; + mPrefix = prefix; + mSuffix = suffix; + mPhoneticGivenName = givenName; + mPhoneticFamilyName = familyName; + mPhoneticMiddleName = middleName; + mEmailList = emailList; + mPostalList = postalList; mOrganizationList = organizationList; - mExtensionMap = extensionMap; + mPhotoList = photoList; + mWebsiteList = websiteList; } /** - * @hide only for test + * @hide only for testing. */ - public String getName() { - return mName; + public final List<PhotoData> getPhotoList() { + return mPhotoList; } /** - * @hide only for test - */ - public String getPhoneticName() { - return mPhoneticName; - } - - /** - * @hide only for test - */ - public final byte[] getPhotoBytes() { - return mPhotoBytes; - } - - /** - * @hide only for test + * @hide only for testing. */ public final List<String> getNotes() { - return mNotes; + return mNoteList; } /** - * @hide only for test + * @hide only for testing. */ public final List<PhoneData> getPhoneList() { return mPhoneList; } /** - * @hide only for test + * @hide only for testing. */ - public final List<ContactMethod> getContactMethodList() { - return mContactMethodList; + public final List<EmailData> getEmailList() { + return mEmailList; } /** - * @hide only for test + * @hide only for testing. */ - public final List<OrganizationData> getOrganizationList() { - return mOrganizationList; + public final List<PostalData> getPostalList() { + return mPostalList; } - + /** - * @hide only for test + * @hide only for testing. */ - public final Map<String, List<String>> getExtensionMap() { - return mExtensionMap; + public final List<OrganizationData> getOrganizationList() { + return mOrganizationList; } /** @@ -359,32 +537,55 @@ public class ContactStruct { mPhoneList.add(phoneData); } - /** - * Add a contactmethod info to contactmethodList. - * @param kind integer value defined in Contacts.java - * (e.g. Contacts.KIND_EMAIL) - * @param type type col of content://contacts/contact_methods - * @param data contact data - * @param label extra string used only when kind is Contacts.KIND_CUSTOM. - */ - private void addContactmethod(int kind, int type, String data, - String label, boolean isPrimary){ - if (mContactMethodList == null) { - mContactMethodList = new ArrayList<ContactMethod>(); + private void addNickName(final String nickName) { + if (mNickNameList == null) { + mNickNameList = new ArrayList<String>(); } - mContactMethodList.add(new ContactMethod(kind, type, data, label, isPrimary)); + mNickNameList.add(nickName); } - /** - * Add a Organization info to organizationList. - */ - private void addOrganization(int type, String companyName, String positionName, - boolean isPrimary) { + 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>(); + } + mPostalList.add(new PostalData(type, propValueList, label, isPrimary)); + } + + private void addOrganization(int type, final String companyName, + final String positionName, boolean isPrimary) { if (mOrganizationList == null) { mOrganizationList = new ArrayList<OrganizationData>(); } mOrganizationList.add(new OrganizationData(type, companyName, positionName, isPrimary)); } + + private void addIm(int type, String data, String label, boolean isPrimary) { + if (mImList == null) { + mImList = new ArrayList<ImData>(); + } + mImList.add(new ImData(type, data, label, 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) { + if (mPhotoList == null) { + mPhotoList = new ArrayList<PhotoData>(1); + } + final PhotoData photoData = new PhotoData(0, null, photoBytes); + } /** * Set "position" value to the appropriate data. If there's more than one @@ -407,148 +608,66 @@ public class ContactStruct { } int size = mOrganizationList.size(); if (size == 0) { - addOrganization(Contacts.OrganizationColumns.TYPE_OTHER, "", null, false); + addOrganization(ContactsContract.CommonDataKinds.Organization.TYPE_OTHER, + "", null, false); size = 1; } OrganizationData lastData = mOrganizationList.get(size - 1); lastData.positionName = positionValue; } - private void addExtension(String propName, Map<String, Collection<String>> paramMap, - List<String> propValueList) { - if (propValueList.size() == 0) { + @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; } - // Now store the string into extensionMap. - List<String> list; - if (mExtensionMap == null) { - mExtensionMap = new HashMap<String, List<String>>(); + if (size > 5) { + size = 5; } - if (!mExtensionMap.containsKey(propName)){ - list = new ArrayList<String>(); - mExtensionMap.put(propName, list); - } else { - list = mExtensionMap.get(propName); - } - - list.add(encodeProperty(propName, paramMap, propValueList)); - } - private String encodeProperty(String propName, Map<String, Collection<String>> paramMap, - List<String> propValueList) { - // PropertyNode#toString() is for reading, not for parsing in the future. - // We construct appropriate String here. - StringBuilder builder = new StringBuilder(); - if (propName.length() > 0) { - builder.append("propName:["); - builder.append(propName); - builder.append("],"); + 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); } - - if (paramMap.size() > 0) { - builder.append("paramMap:["); - int size = paramMap.size(); - int i = 0; - for (Map.Entry<String, Collection<String>> entry : paramMap.entrySet()) { - String key = entry.getKey(); - for (String value : entry.getValue()) { - // Assuming param-key does not contain NON-ASCII nor symbols. - // TODO: check it. - // - // According to vCard 3.0: - // param-name = iana-token / x-name - builder.append(key); - - // param-value may contain any value including NON-ASCIIs. - // We use the following replacing rule. - // \ -> \\ - // , -> \, - // In String#replaceAll(), "\\\\" means a single backslash. - builder.append("="); - - // TODO: fix this. - builder.append(value.replaceAll("\\\\", "\\\\\\\\").replaceAll(",", "\\\\,")); - if (i < size -1) { - builder.append(","); - } - i++; - } - } - - builder.append("],"); + } + + /** + * 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) { + // Family, Given, Middle. (1-3) + // This is not from specification but mere assumption. Some Japanese phones use this order. + int size; + if (elems == null || (size = elems.size()) < 1) { + return; } - - int size = propValueList.size(); - if (size > 0) { - builder.append("propValue:["); - List<String> list = propValueList; - for (int i = 0; i < size; i++) { - // TODO: fix this. - builder.append(list.get(i).replaceAll("\\\\", "\\\\\\\\").replaceAll(",", "\\\\,")); - if (i < size -1) { - builder.append(","); - } - } - builder.append("],"); + if (size > 3) { + size = 3; } - return builder.toString(); - } - - private static String getNameFromNProperty(List<String> elems, int nameOrderType) { - // Family, Given, Middle, Prefix, Suffix. (1 - 5) - int size = elems.size(); - if (size > 1) { - StringBuilder builder = new StringBuilder(); - boolean builderIsEmpty = true; - // Prefix - if (size > 3 && elems.get(3).length() > 0) { - builder.append(elems.get(3)); - builderIsEmpty = false; - } - String first, second; - if (nameOrderType == VCardConfig.NAME_ORDER_TYPE_JAPANESE) { - first = elems.get(0); - second = elems.get(1); - } else { - first = elems.get(1); - second = elems.get(0); - } - if (first.length() > 0) { - if (!builderIsEmpty) { - builder.append(' '); - } - builder.append(first); - builderIsEmpty = false; - } - // Middle name - if (size > 2 && elems.get(2).length() > 0) { - if (!builderIsEmpty) { - builder.append(' '); - } - builder.append(elems.get(2)); - builderIsEmpty = false; - } - if (second.length() > 0) { - if (!builderIsEmpty) { - builder.append(' '); - } - builder.append(second); - builderIsEmpty = false; - } - // Suffix - if (size > 4 && elems.get(4).length() > 0) { - if (!builderIsEmpty) { - builder.append(' '); - } - builder.append(elems.get(4)); - builderIsEmpty = false; - } - return builder.toString(); - } else if (size == 1) { - return elems.get(0); - } else { - return ""; + switch (size) { + // fallthrough + case 3: + mPhoneticMiddleName = elems.get(2); + case 2: + mPhoneticGivenName = elems.get(1); + default: + mPhoneticFamilyName = elems.get(0); } } @@ -561,41 +680,27 @@ public class ContactStruct { if (propValueList.size() == 0) { return; } - - String propValue = listToString(propValueList); - + final String propValue = listToString(propValueList).trim(); + if (propName.equals("VERSION")) { // vCard version. Ignore this. } else if (propName.equals("FN")) { - mTmpFullName = propValue; - } else if (propName.equals("NAME") && mTmpFullName == null) { - // Only in vCard 3.0. Use this if FN does not exist. - // Though, note that vCard 3.0 requires FN. - mTmpFullName = propValue; + mFullName = propValue; + } else if (propName.equals("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("N")) { - mTmpNameFromNProperty = getNameFromNProperty(propValueList, mNameOrderType); + handleNProperty(propValueList); } else if (propName.equals("SORT-STRING")) { - mPhoneticName = propValue; + mPhoneticFullName = propValue; + } else if (propName.equals("NICKNAME") || propName.equals("X-NICKNAME")) { + addNickName(propValue); } else if (propName.equals("SOUND")) { - if ("X-IRMC-N".equals(paramMap.get("TYPE")) && mPhoneticName == null) { - // 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. - // We remove them. - StringBuilder builder = new StringBuilder(); - String value = propValue; - int length = value.length(); - for (int i = 0; i < length; i++) { - char ch = value.charAt(i); - if (ch != ';') { - builder.append(ch); - } - } - if (builder.length() > 0) { - mPhoneticName = builder.toString(); - } + if (Constants.ATTR_TYPE_X_IRMC_N.equals(paramMap.get(Constants.ATTR_TYPE))) { + handlePhoneticNameFromSound(propValueList); } else { - addExtension(propName, paramMap, propValueList); + // Ignore this field since Android cannot understand what it is. } } else if (propName.equals("ADR")) { boolean valuesAreAllEmpty = true; @@ -609,108 +714,103 @@ public class ContactStruct { return; } - int kind = Contacts.KIND_POSTAL; int type = -1; String label = ""; boolean isPrimary = false; - Collection<String> typeCollection = paramMap.get("TYPE"); + Collection<String> typeCollection = paramMap.get(Constants.ATTR_TYPE); if (typeCollection != null) { for (String typeString : typeCollection) { - if (typeString.equals("PREF") && !mPrefIsSet_Address) { + typeString = typeString.toUpperCase(); + if (typeString.equals(Constants.ATTR_TYPE_PREF) && !mPrefIsSet_Address) { // Only first "PREF" is considered. mPrefIsSet_Address = true; isPrimary = true; - } else if (typeString.equalsIgnoreCase("HOME")) { - type = Contacts.ContactMethodsColumns.TYPE_HOME; + } else if (typeString.equals(Constants.ATTR_TYPE_HOME)) { + type = StructuredPostal.TYPE_HOME; label = ""; - } else if (typeString.equalsIgnoreCase("WORK") || + } else if (typeString.equals(Constants.ATTR_TYPE_WORK) || typeString.equalsIgnoreCase("COMPANY")) { // "COMPANY" seems emitted by Windows Mobile, which is not // specifically supported by vCard 2.1. We assume this is same // as "WORK". - type = Contacts.ContactMethodsColumns.TYPE_WORK; + type = StructuredPostal.TYPE_WORK; label = ""; - } else if (typeString.equalsIgnoreCase("POSTAL")) { - kind = Contacts.KIND_POSTAL; - } else if (typeString.equalsIgnoreCase("PARCEL") || - typeString.equalsIgnoreCase("DOM") || - typeString.equalsIgnoreCase("INTL")) { - // We do not have a kind or type matching these. - // TODO: fix this. We may need to split entries into two. - // (e.g. entries for KIND_POSTAL and KIND_PERCEL) - } else if (typeString.toUpperCase().startsWith("X-") && - type < 0) { - type = Contacts.ContactMethodsColumns.TYPE_CUSTOM; - label = typeString.substring(2); - } else if (type < 0) { + } else if (typeString.equals("PARCEL") || + typeString.equals("DOM") || + typeString.equals("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 = Contacts.ContactMethodsColumns.TYPE_CUSTOM; + type = StructuredPostal.TYPE_CUSTOM; label = typeString; } } } // We use "HOME" as default if (type < 0) { - type = Contacts.ContactMethodsColumns.TYPE_HOME; + type = StructuredPostal.TYPE_HOME; } - - // adr-value = 0*6(text-value ";") text-value - // ; PO Box, Extended Address, Street, Locality, Region, Postal - // ; Code, Country Name - String address; - int size = propValueList.size(); - if (size > 1) { - StringBuilder builder = new StringBuilder(); - boolean builderIsEmpty = true; - if (Locale.getDefault().getCountry().equals(Locale.JAPAN.getCountry())) { - // In Japan, the order is reversed. - for (int i = size - 1; i >= 0; i--) { - String addressPart = propValueList.get(i); - if (addressPart.length() > 0) { - if (!builderIsEmpty) { - builder.append(' '); - } - builder.append(addressPart); - builderIsEmpty = false; - } - } - } else { - for (int i = 0; i < size; i++) { - String addressPart = propValueList.get(i); - if (addressPart.length() > 0) { - if (!builderIsEmpty) { - builder.append(' '); - } - builder.append(addressPart); - builderIsEmpty = false; + + addPostal(type, propValueList, label, isPrimary); + } else if (propName.equals("EMAIL")) { + int type = -1; + String label = null; + boolean isPrimary = false; + Collection<String> typeCollection = paramMap.get(Constants.ATTR_TYPE); + if (typeCollection != null) { + for (String typeString : typeCollection) { + typeString = typeString.toUpperCase(); + if (typeString.equals(Constants.ATTR_TYPE_PREF) && !mPrefIsSet_Email) { + // Only first "PREF" is considered. + mPrefIsSet_Email = true; + isPrimary = true; + } else if (typeString.equals(Constants.ATTR_TYPE_HOME)) { + type = Email.TYPE_HOME; + } else if (typeString.equals(Constants.ATTR_TYPE_WORK)) { + type = Email.TYPE_WORK; + } else if (typeString.equals(Constants.ATTR_TYPE_CELL)) { + // We do not have TYPE_MOBILE yet. + // TODO: modify this code when TYPE_MOBILE is supported. + type = Email.TYPE_CUSTOM; + label = + android.provider.Contacts.ContactMethodsColumns.MOBILE_EMAIL_TYPE_NAME; + } 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; } } - address = builder.toString().trim(); - } else { - address = propValue; } - addContactmethod(kind, type, address, label, isPrimary); + if (type < 0) { + type = Email.TYPE_OTHER; + } + addEmail(type, propValue, label, isPrimary); } else if (propName.equals("ORG")) { // vCard specification does not specify other types. - int type = Contacts.OrganizationColumns.TYPE_WORK; + int type = Organization.TYPE_WORK; boolean isPrimary = false; - Collection<String> typeCollection = paramMap.get("TYPE"); + Collection<String> typeCollection = paramMap.get(Constants.ATTR_TYPE); if (typeCollection != null) { for (String typeString : typeCollection) { - if (typeString.equals("PREF") && !mPrefIsSet_Organization) { + if (typeString.equals(Constants.ATTR_TYPE_PREF) && !mPrefIsSet_Organization) { // vCard specification officially does not have PREF in ORG. // This is just for safety. mPrefIsSet_Organization = true; isPrimary = true; } - // XXX: Should we cope with X- words? } } - int size = propValueList.size(); StringBuilder builder = new StringBuilder(); for (Iterator<String> iter = propValueList.iterator(); iter.hasNext();) { builder.append(iter.next()); @@ -718,250 +818,190 @@ public class ContactStruct { builder.append(' '); } } - addOrganization(type, builder.toString(), "", isPrimary); } else if (propName.equals("TITLE")) { setPosition(propValue); } else if (propName.equals("ROLE")) { setPosition(propValue); - } else if ((propName.equals("PHOTO") || (propName.equals("LOGO")) && mPhotoBytes == null)) { - // We prefer PHOTO to LOGO. + } else if (propName.equals("PHOTO") || propName.equals("LOGO")) { + String formatName = null; + Collection<String> typeCollection = paramMap.get("TYPE"); + if (typeCollection != null) { + formatName = typeCollection.iterator().next(); + } Collection<String> paramMapValue = paramMap.get("VALUE"); if (paramMapValue != null && paramMapValue.contains("URL")) { - // TODO: do something. + // Currently we do not have appropriate example for testing this case. } else { - // Assume PHOTO is stored in BASE64. In that case, - // data is already stored in propValue_bytes in binary form. - // It should be automatically done by VBuilder (VDataBuilder/VCardDatabuilder) - mPhotoBytes = propBytes; - /* - Collection<String> typeCollection = paramMap.get("TYPE"); - if (typeCollection != null) { - if (typeCollection.size() > 1) { - StringBuilder builder = new StringBuilder(); - int size = typeCollection.size(); - int i = 0; - for (String type : typeCollection) { - builder.append(type); - if (i < size - 1) { - builder.append(','); - } - i++; - } - Log.w(LOG_TAG, "There is more than TYPE: " + builder.toString()); - } - mPhotoType = typeCollection.iterator().next(); - }*/ + addPhotoBytes(formatName, propBytes); } - } else if (propName.equals("EMAIL")) { - int type = -1; - String label = null; - boolean isPrimary = false; - Collection<String> typeCollection = paramMap.get("TYPE"); - if (typeCollection != null) { - for (String typeString : typeCollection) { - if (typeString.equals("PREF") && !mPrefIsSet_Email) { - // Only first "PREF" is considered. - mPrefIsSet_Email = true; - isPrimary = true; - } else if (typeString.equalsIgnoreCase("HOME")) { - type = Contacts.ContactMethodsColumns.TYPE_HOME; - } else if (typeString.equalsIgnoreCase("WORK")) { - type = Contacts.ContactMethodsColumns.TYPE_WORK; - } else if (typeString.equalsIgnoreCase("CELL")) { - // We do not have Contacts.ContactMethodsColumns.TYPE_MOBILE yet. - type = Contacts.ContactMethodsColumns.TYPE_CUSTOM; - label = Contacts.ContactMethodsColumns.MOBILE_EMAIL_TYPE_NAME; - } else if (typeString.toUpperCase().startsWith("X-") && - type < 0) { - type = Contacts.ContactMethodsColumns.TYPE_CUSTOM; - label = typeString.substring(2); - } else if (type < 0) { - // vCard 3.0 allows iana-token. - // We may have INTERNET (specified in vCard spec), - // SCHOOL, etc. - type = Contacts.ContactMethodsColumns.TYPE_CUSTOM; - label = typeString; - } - } + } else if (propName.equals("TEL")) { + Collection<String> typeCollection = paramMap.get(Constants.ATTR_TYPE); + Object typeObject = VCardUtils.getPhoneTypeFromStrings(typeCollection); + final int type; + final String label; + if (typeObject instanceof Integer) { + type = (Integer)typeObject; + label = null; + } else { + type = Phone.TYPE_CUSTOM; + label = typeObject.toString(); } - if (type < 0) { - type = Contacts.ContactMethodsColumns.TYPE_OTHER; + + final boolean isPrimary; + if (!mPrefIsSet_Phone && typeCollection != null && + typeCollection.contains(Constants.ATTR_TYPE_PREF)) { + mPrefIsSet_Phone = true; + isPrimary = true; + } else { + isPrimary = false; } - addContactmethod(Contacts.KIND_EMAIL, type, propValue,label, isPrimary); - } else if (propName.equals("TEL")) { - int type = -1; - String label = null; + addPhone(type, propValue, label, isPrimary); + } else if (propName.equals(Constants.PROPERTY_X_SKYPE_PSTNNUMBER)) { + // The phone number available via Skype. + Collection<String> typeCollection = paramMap.get(Constants.ATTR_TYPE); + // XXX: should use TYPE_CUSTOM + the label "Skype"? (which may need localization) + int type = Phone.TYPE_OTHER; + final String label = null; + final boolean isPrimary; + if (!mPrefIsSet_Phone && typeCollection != null && + typeCollection.contains(Constants.ATTR_TYPE_PREF)) { + mPrefIsSet_Phone = true; + isPrimary = true; + } else { + isPrimary = false; + } + addPhone(type, propValue, label, isPrimary); + } else if (sImMap.containsKey(propName)){ + int type = sImMap.get(propName); boolean isPrimary = false; - boolean isFax = false; - Collection<String> typeCollection = paramMap.get("TYPE"); + final Collection<String> typeCollection = paramMap.get(Constants.ATTR_TYPE); if (typeCollection != null) { for (String typeString : typeCollection) { - if (typeString.equals("PREF") && !mPrefIsSet_Phone) { - // Only first "PREF" is considered. - mPrefIsSet_Phone = true; + if (typeString.equals(Constants.ATTR_TYPE_PREF)) { isPrimary = true; - } else if (typeString.equalsIgnoreCase("HOME")) { - type = Contacts.PhonesColumns.TYPE_HOME; - } else if (typeString.equalsIgnoreCase("WORK")) { - type = Contacts.PhonesColumns.TYPE_WORK; - } else if (typeString.equalsIgnoreCase("CELL")) { - type = Contacts.PhonesColumns.TYPE_MOBILE; - } else if (typeString.equalsIgnoreCase("PAGER")) { - type = Contacts.PhonesColumns.TYPE_PAGER; - } else if (typeString.equalsIgnoreCase("FAX")) { - isFax = true; - } else if (typeString.equalsIgnoreCase("VOICE") || - typeString.equalsIgnoreCase("MSG")) { - // Defined in vCard 3.0. Ignore these because they - // conflict with "HOME", "WORK", etc. - // XXX: do something? - } else if (typeString.toUpperCase().startsWith("X-") && - type < 0) { - type = Contacts.PhonesColumns.TYPE_CUSTOM; - label = typeString.substring(2); - } else if (type < 0){ - // We may have MODEM, CAR, ISDN, etc... - type = Contacts.PhonesColumns.TYPE_CUSTOM; - label = typeString; + } else if (typeString.equalsIgnoreCase(Constants.ATTR_TYPE_HOME)) { + type = Phone.TYPE_HOME; + } else if (typeString.equalsIgnoreCase(Constants.ATTR_TYPE_WORK)) { + type = Phone.TYPE_WORK; } } } if (type < 0) { - type = Contacts.PhonesColumns.TYPE_HOME; + type = Phone.TYPE_HOME; } - if (isFax) { - if (type == Contacts.PhonesColumns.TYPE_HOME) { - type = Contacts.PhonesColumns.TYPE_FAX_HOME; - } else if (type == Contacts.PhonesColumns.TYPE_WORK) { - type = Contacts.PhonesColumns.TYPE_FAX_WORK; - } - } - - addPhone(type, propValue, label, isPrimary); + addIm(type, propValue, null, isPrimary); } else if (propName.equals("NOTE")) { - if (mNotes == null) { - mNotes = new ArrayList<String>(1); + addNote(propValue); + } else if (propName.equals("URL")) { + if (mWebsiteList == null) { + mWebsiteList = new ArrayList<String>(1); } - mNotes.add(propValue); + mWebsiteList.add(propValue); + } else if (propName.equals("X-PHONETIC-FIRST-NAME")) { + mPhoneticGivenName = propValue; + } else if (propName.equals("X-PHONETIC-MIDDLE-NAME")) { + mPhoneticMiddleName = propValue; + } else if (propName.equals("X-PHONETIC-LAST-NAME")) { + mPhoneticFamilyName = propValue; } else if (propName.equals("BDAY")) { - addExtension(propName, paramMap, propValueList); - } else if (propName.equals("URL")) { - addExtension(propName, paramMap, propValueList); - } else if (propName.equals("REV")) { + mBirthday = propValue; + /*} else if (propName.equals("REV")) { // Revision of this VCard entry. I think we can ignore this. - addExtension(propName, paramMap, propValueList); } else if (propName.equals("UID")) { - addExtension(propName, paramMap, propValueList); } else if (propName.equals("KEY")) { // Type is X509 or PGP? I don't know how to handle this... - addExtension(propName, paramMap, propValueList); } else if (propName.equals("MAILER")) { - addExtension(propName, paramMap, propValueList); } else if (propName.equals("TZ")) { - addExtension(propName, paramMap, propValueList); } else if (propName.equals("GEO")) { - addExtension(propName, paramMap, propValueList); - } else if (propName.equals("NICKNAME")) { - // vCard 3.0 only. - addExtension(propName, paramMap, propValueList); } else if (propName.equals("CLASS")) { // vCard 3.0 only. // e.g. CLASS:CONFIDENTIAL - addExtension(propName, paramMap, propValueList); } else if (propName.equals("PROFILE")) { // VCard 3.0 only. Must be "VCARD". I think we can ignore this. - addExtension(propName, paramMap, propValueList); } else if (propName.equals("CATEGORIES")) { // VCard 3.0 only. // e.g. CATEGORIES:INTERNET,IETF,INDUSTRY,INFORMATION TECHNOLOGY - addExtension(propName, paramMap, propValueList); } else if (propName.equals("SOURCE")) { // VCard 3.0 only. - addExtension(propName, paramMap, propValueList); } else if (propName.equals("PRODID")) { // VCard 3.0 only. // To specify the identifier for the product that created - // the vCard object. - addExtension(propName, paramMap, propValueList); - } else if (propName.equals("X-PHONETIC-FIRST-NAME")) { - mTmpXPhoneticFirstName = propValue; - } else if (propName.equals("X-PHONETIC-MIDDLE-NAME")) { - mTmpXPhoneticMiddleName = propValue; - } else if (propName.equals("X-PHONETIC-LAST-NAME")) { - mTmpXPhoneticLastName = propValue; + // the vCard object.*/ } else { // Unknown X- words and IANA token. - addExtension(propName, paramMap, propValueList); } } - public String displayString() { - if (mName.length() > 0) { - return mName; - } - if (mContactMethodList != null && mContactMethodList.size() > 0) { - for (ContactMethod contactMethod : mContactMethodList) { - if (contactMethod.kind == Contacts.KIND_EMAIL && contactMethod.isPrimary) { - return contactMethod.data; + public String getDisplayName() { + if (mDisplayName == null) { + constructDisplayName(); + } + return mDisplayName; + } + + /** + * Construct the display name. The constructed data must not be null. + */ + private void constructDisplayName() { + if (!(TextUtils.isEmpty(mFamilyName) && TextUtils.isEmpty(mGivenName))) { + StringBuilder builder = new StringBuilder(); + List<String> nameList; + switch (VCardConfig.getNameOrderType(mVCardType)) { + case VCardConfig.NAME_ORDER_JAPANESE: + if (VCardUtils.containsOnlyAscii(mFamilyName) && + VCardUtils.containsOnlyAscii(mGivenName)) { + nameList = Arrays.asList(mPrefix, mGivenName, mMiddleName, mFamilyName, mSuffix); + } else { + nameList = Arrays.asList(mPrefix, mFamilyName, mMiddleName, mGivenName, mSuffix); } + break; + case VCardConfig.NAME_ORDER_EUROPE: + nameList = Arrays.asList(mPrefix, mMiddleName, mGivenName, mFamilyName, mSuffix); + break; + default: + nameList = Arrays.asList(mPrefix, mGivenName, mMiddleName, mFamilyName, mSuffix); + break; } - } - if (mPhoneList != null && mPhoneList.size() > 0) { - for (PhoneData phoneData : mPhoneList) { - if (phoneData.isPrimary) { - return phoneData.data; + boolean first = true; + for (String namePart : nameList) { + if (!TextUtils.isEmpty(namePart)) { + if (first) { + first = false; + } else { + builder.append(' '); + } + builder.append(namePart); } } + mDisplayName = builder.toString(); + } else if (!TextUtils.isEmpty(mFullName)) { + mDisplayName = mFullName; + } 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); } - return ""; - } + if (mDisplayName == null) { + mDisplayName = ""; + } + } + /** * Consolidate several fielsds (like mName) using name candidates, */ public void consolidateFields() { - if (mTmpFullName != null) { - mName = mTmpFullName; - } else if(mTmpNameFromNProperty != null) { - mName = mTmpNameFromNProperty; - } else { - mName = ""; - } - - if (mPhoneticName == null && - (mTmpXPhoneticFirstName != null || mTmpXPhoneticMiddleName != null || - mTmpXPhoneticLastName != null)) { - // Note: In Europe, this order should be "LAST FIRST MIDDLE". See the comment around - // NAME_ORDER_TYPE_* for more detail. - String first; - String second; - if (mNameOrderType == VCardConfig.NAME_ORDER_TYPE_JAPANESE) { - first = mTmpXPhoneticLastName; - second = mTmpXPhoneticFirstName; - } else { - first = mTmpXPhoneticFirstName; - second = mTmpXPhoneticLastName; - } - StringBuilder builder = new StringBuilder(); - if (first != null) { - builder.append(first); - } - if (mTmpXPhoneticMiddleName != null) { - builder.append(mTmpXPhoneticMiddleName); - } - if (second != null) { - builder.append(second); - } - mPhoneticName = builder.toString(); - } + constructDisplayName(); - // Remove unnecessary white spaces. - // It is found that some mobile phone emits phonetic name with just one white space - // when a user does not specify one. - // This logic is effective toward such kind of weird data. - if (mPhoneticName != null) { - mPhoneticName = mPhoneticName.trim(); + if (mPhoneticFullName != null) { + mPhoneticFullName = mPhoneticFullName.trim(); } // If there is no "PREF", we choose the first entries as primary. @@ -969,258 +1009,196 @@ public class ContactStruct { mPhoneList.get(0).isPrimary = true; } - if (!mPrefIsSet_Address && mContactMethodList != null) { - for (ContactMethod contactMethod : mContactMethodList) { - if (contactMethod.kind == Contacts.KIND_POSTAL) { - contactMethod.isPrimary = true; - break; - } - } + if (!mPrefIsSet_Address && mPostalList != null && mPostalList.size() > 0) { + mPostalList.get(0).isPrimary = true; } - if (!mPrefIsSet_Email && mContactMethodList != null) { - for (ContactMethod contactMethod : mContactMethodList) { - if (contactMethod.kind == Contacts.KIND_EMAIL) { - contactMethod.isPrimary = true; - break; - } - } + if (!mPrefIsSet_Email && mEmailList != null && mEmailList.size() > 0) { + mEmailList.get(0).isPrimary = true; } if (!mPrefIsSet_Organization && mOrganizationList != null && mOrganizationList.size() > 0) { mOrganizationList.get(0).isPrimary = true; } - } - private void pushIntoContentProviderOrResolver(Object contentSomething, - long myContactsGroupId) { - ContentResolver resolver = null; - AbstractSyncableContentProvider provider = null; - if (contentSomething instanceof ContentResolver) { - resolver = (ContentResolver)contentSomething; - } else if (contentSomething instanceof AbstractSyncableContentProvider) { - provider = (AbstractSyncableContentProvider)contentSomething; - } else { - Log.e(LOG_TAG, "Unsupported object came."); - return; - } - - ContentValues contentValues = new ContentValues(); - contentValues.put(People.NAME, mName); - contentValues.put(People.PHONETIC_NAME, mPhoneticName); - - if (mNotes != null && mNotes.size() > 0) { - if (mNotes.size() > 1) { - StringBuilder builder = new StringBuilder(); - for (String note : mNotes) { - builder.append(note); - builder.append("\n"); - } - contentValues.put(People.NOTES, builder.toString()); - } else { - contentValues.put(People.NOTES, mNotes.get(0)); - } - } + public void pushIntoContentResolver(ContentResolver resolver) { + ArrayList<ContentProviderOperation> operationList = + new ArrayList<ContentProviderOperation>(); + ContentProviderOperation.Builder builder = + ContentProviderOperation.newInsert(RawContacts.CONTENT_URI); + builder.withValues(new ContentValues()); + operationList.add(builder.build()); - Uri personUri; - long personId = 0; - if (resolver != null) { - personUri = Contacts.People.createPersonInMyContactsGroup(resolver, contentValues); - if (personUri != null) { - personId = ContentUris.parseId(personUri); - } - } else { - personUri = provider.insert(People.CONTENT_URI, contentValues); - if (personUri != null) { - personId = ContentUris.parseId(personUri); - ContentValues values = new ContentValues(); - values.put(GroupMembership.PERSON_ID, personId); - values.put(GroupMembership.GROUP_ID, myContactsGroupId); - Uri resultUri = provider.insert(GroupMembership.CONTENT_URI, values); - if (resultUri == null) { - Log.e(LOG_TAG, "Faild to insert the person to MyContact."); - provider.delete(personUri, null, null); - personUri = null; - } - } - } + { + builder = ContentProviderOperation.newInsert(Data.CONTENT_URI); + builder.withValueBackReference(StructuredName.RAW_CONTACT_ID, 0); + builder.withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE); - if (personUri == null) { - Log.e(LOG_TAG, "Failed to create the contact."); - return; + 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); + + builder.withValue(StructuredName.PHONETIC_GIVEN_NAME, mPhoneticGivenName); + builder.withValue(StructuredName.PHONETIC_FAMILY_NAME, mPhoneticFamilyName); + builder.withValue(StructuredName.PHONETIC_MIDDLE_NAME, mPhoneticMiddleName); + + builder.withValue(StructuredName.DISPLAY_NAME, getDisplayName()); + operationList.add(builder.build()); } - - if (mPhotoBytes != null) { - if (resolver != null) { - People.setPhotoData(resolver, personUri, mPhotoBytes); - } else { - Uri photoUri = Uri.withAppendedPath(personUri, Contacts.Photos.CONTENT_DIRECTORY); - ContentValues values = new ContentValues(); - values.put(Photos.DATA, mPhotoBytes); - provider.update(photoUri, values, null, null); + + if (mNickNameList != null && mNickNameList.size() > 0) { + boolean first = true; + 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); + if (first) { + builder.withValue(Data.IS_PRIMARY, 1); + first = false; + } + operationList.add(builder.build()); } } - long primaryPhoneId = -1; - if (mPhoneList != null && mPhoneList.size() > 0) { + if (mPhoneList != null) { for (PhoneData phoneData : mPhoneList) { - ContentValues values = new ContentValues(); - values.put(Contacts.PhonesColumns.TYPE, phoneData.type); - if (phoneData.type == Contacts.PhonesColumns.TYPE_CUSTOM) { - values.put(Contacts.PhonesColumns.LABEL, phoneData.label); - } - // Already formatted. - values.put(Contacts.PhonesColumns.NUMBER, phoneData.data); - - // Not sure about Contacts.PhonesColumns.NUMBER_KEY ... - values.put(Contacts.PhonesColumns.ISPRIMARY, 1); - values.put(Contacts.Phones.PERSON_ID, personId); - Uri phoneUri; - if (resolver != null) { - phoneUri = resolver.insert(Phones.CONTENT_URI, values); - } else { - phoneUri = provider.insert(Phones.CONTENT_URI, values); + 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) { - primaryPhoneId = Long.parseLong(phoneUri.getLastPathSegment()); + builder.withValue(Data.IS_PRIMARY, 1); } + operationList.add(builder.build()); } } - long primaryOrganizationId = -1; - if (mOrganizationList != null && mOrganizationList.size() > 0) { + if (mOrganizationList != null) { + boolean first = true; for (OrganizationData organizationData : mOrganizationList) { - ContentValues values = new ContentValues(); + builder = ContentProviderOperation.newInsert(Data.CONTENT_URI); + builder.withValueBackReference(Organization.RAW_CONTACT_ID, 0); + builder.withValue(Data.MIMETYPE, Organization.CONTENT_ITEM_TYPE); + // Currently, we do not use TYPE_CUSTOM. - values.put(Contacts.OrganizationColumns.TYPE, - organizationData.type); - values.put(Contacts.OrganizationColumns.COMPANY, - organizationData.companyName); - values.put(Contacts.OrganizationColumns.TITLE, - organizationData.positionName); - values.put(Contacts.OrganizationColumns.ISPRIMARY, 1); - values.put(Contacts.OrganizationColumns.PERSON_ID, personId); - - Uri organizationUri; - if (resolver != null) { - organizationUri = resolver.insert(Organizations.CONTENT_URI, values); - } else { - organizationUri = provider.insert(Organizations.CONTENT_URI, values); - } - if (organizationData.isPrimary) { - primaryOrganizationId = Long.parseLong(organizationUri.getLastPathSegment()); + builder.withValue(Organization.TYPE, organizationData.type); + builder.withValue(Organization.COMPANY, organizationData.companyName); + builder.withValue(Organization.TITLE, organizationData.positionName); + if (first) { + builder.withValue(Data.IS_PRIMARY, 1); } + operationList.add(builder.build()); } } - long primaryEmailId = -1; - if (mContactMethodList != null && mContactMethodList.size() > 0) { - for (ContactMethod contactMethod : mContactMethodList) { - ContentValues values = new ContentValues(); - values.put(Contacts.ContactMethodsColumns.KIND, contactMethod.kind); - values.put(Contacts.ContactMethodsColumns.TYPE, contactMethod.type); - if (contactMethod.type == Contacts.ContactMethodsColumns.TYPE_CUSTOM) { - values.put(Contacts.ContactMethodsColumns.LABEL, contactMethod.label); + 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); } - values.put(Contacts.ContactMethodsColumns.DATA, contactMethod.data); - values.put(Contacts.ContactMethodsColumns.ISPRIMARY, 1); - values.put(Contacts.ContactMethods.PERSON_ID, personId); - - if (contactMethod.kind == Contacts.KIND_EMAIL) { - Uri emailUri; - if (resolver != null) { - emailUri = resolver.insert(ContactMethods.CONTENT_URI, values); - } else { - emailUri = provider.insert(ContactMethods.CONTENT_URI, values); - } - if (contactMethod.isPrimary) { - primaryEmailId = Long.parseLong(emailUri.getLastPathSegment()); - } - } else { // probably KIND_POSTAL - if (resolver != null) { - resolver.insert(ContactMethods.CONTENT_URI, values); - } else { - provider.insert(ContactMethods.CONTENT_URI, values); - } + builder.withValue(Email.DATA, emailData.data); + if (emailData.isPrimary) { + builder.withValue(Data.IS_PRIMARY, 1); } + operationList.add(builder.build()); } } - if (mExtensionMap != null && mExtensionMap.size() > 0) { - ArrayList<ContentValues> contentValuesArray; - if (resolver != null) { - contentValuesArray = new ArrayList<ContentValues>(); - } else { - contentValuesArray = null; + if (mPostalList != null) { + for (PostalData postalData : mPostalList) { + builder = ContentProviderOperation.newInsert(Data.CONTENT_URI); + VCardUtils.insertStructuredPostalDataUsingContactsStruct( + mVCardType, builder, postalData); + operationList.add(builder.build()); } - for (Entry<String, List<String>> entry : mExtensionMap.entrySet()) { - String key = entry.getKey(); - List<String> list = entry.getValue(); - for (String value : list) { - ContentValues values = new ContentValues(); - values.put(Extensions.NAME, key); - values.put(Extensions.VALUE, value); - values.put(Extensions.PERSON_ID, personId); - if (resolver != null) { - contentValuesArray.add(values); - } else { - provider.insert(Extensions.CONTENT_URI, values); - } + } + + 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); + if (imData.type == Im.TYPE_CUSTOM) { + builder.withValue(Im.LABEL, imData.label); + } + builder.withValue(Im.DATA, imData.data); + if (imData.isPrimary) { + builder.withValue(Data.IS_PRIMARY, 1); } - } - if (resolver != null) { - resolver.bulkInsert(Extensions.CONTENT_URI, - contentValuesArray.toArray(new ContentValues[0])); } } - if (primaryPhoneId >= 0 || primaryOrganizationId >= 0 || primaryEmailId >= 0) { - ContentValues values = new ContentValues(); - if (primaryPhoneId >= 0) { - values.put(People.PRIMARY_PHONE_ID, primaryPhoneId); - } - if (primaryOrganizationId >= 0) { - values.put(People.PRIMARY_ORGANIZATION_ID, primaryOrganizationId); + 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 (primaryEmailId >= 0) { - values.put(People.PRIMARY_EMAIL_ID, primaryEmailId); + } + + if (mPhotoList != null) { + boolean first = true; + 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 (first) { + builder.withValue(Data.IS_PRIMARY, 1); + first = false; + } + operationList.add(builder.build()); } - if (resolver != null) { - resolver.update(personUri, values, null, null); - } else { - provider.update(personUri, values, null, null); + } + + 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); + operationList.add(builder.build()); } } - } - - /** - * Push this object into database in the resolver. - */ - public void pushIntoContentResolver(ContentResolver resolver) { - pushIntoContentProviderOrResolver(resolver, 0); - } - - /** - * Push this object into AbstractSyncableContentProvider object. - * {@link #consolidateFields() must be called before this method is called} - * @hide - */ - public void pushIntoAbstractSyncableContentProvider( - AbstractSyncableContentProvider provider, long myContactsGroupId) { - boolean successful = false; - provider.beginBatch(); + + if (!TextUtils.isEmpty(mBirthday)) { + builder = ContentProviderOperation.newInsert(Data.CONTENT_URI); + builder.withValueBackReference(Miscellaneous.RAW_CONTACT_ID, 0); + builder.withValue(Data.MIMETYPE, Miscellaneous.CONTENT_ITEM_TYPE); + builder.withValue(Miscellaneous.BIRTHDAY, mBirthday); + operationList.add(builder.build()); + } + try { - pushIntoContentProviderOrResolver(provider, myContactsGroupId); - successful = true; - } finally { - provider.endBatch(successful); + resolver.applyBatch(ContactsContract.AUTHORITY, operationList); + } catch (RemoteException e) { + Log.e(LOG_TAG, String.format("%s: %s", e.toString(), e.getMessage())); + } catch (OperationApplicationException e) { + Log.e(LOG_TAG, String.format("%s: %s", e.toString(), e.getMessage())); } } - + public boolean isIgnorable() { - return TextUtils.isEmpty(mName) && - TextUtils.isEmpty(mPhoneticName) && - (mPhoneList == null || mPhoneList.size() == 0) && - (mContactMethodList == null || mContactMethodList.size() == 0); + return getDisplayName().length() == 0; } private String listToString(List<String> list){ diff --git a/core/java/android/pim/vcard/EntryCommitter.java b/core/java/android/pim/vcard/EntryCommitter.java index e26fac5..3f1655d 100644 --- a/core/java/android/pim/vcard/EntryCommitter.java +++ b/core/java/android/pim/vcard/EntryCommitter.java @@ -15,11 +15,7 @@ */ package android.pim.vcard; -import android.content.AbstractSyncableContentProvider; -import android.content.ContentProvider; import android.content.ContentResolver; -import android.content.IContentProvider; -import android.provider.Contacts; import android.util.Log; /** @@ -27,62 +23,26 @@ import android.util.Log; */ public class EntryCommitter implements EntryHandler { public static String LOG_TAG = "vcard.EntryComitter"; - + private ContentResolver mContentResolver; - - // Ideally, this should be ContactsProvider but it seems Class loader cannot find it, - // even when it is subclass of ContactsProvider... - private AbstractSyncableContentProvider mProvider; - private long mMyContactsGroupId; - private long mTimeToCommit; public EntryCommitter(ContentResolver resolver) { mContentResolver = resolver; - - tryGetOriginalProvider(); + } + + public void onParsingStart() { } - public void onFinal() { + public void onParsingEnd() { if (VCardConfig.showPerformanceLog()) { - Log.d(LOG_TAG, - String.format("time to commit entries: %ld ms", mTimeToCommit)); + Log.d(LOG_TAG, String.format("time to commit entries: %d ms", mTimeToCommit)); } } - - private void tryGetOriginalProvider() { - final ContentResolver resolver = mContentResolver; - - if ((mMyContactsGroupId = Contacts.People.tryGetMyContactsGroupId(resolver)) == 0) { - Log.e(LOG_TAG, "Could not get group id of MyContact"); - return; - } - IContentProvider iProviderForName = resolver.acquireProvider(Contacts.CONTENT_URI); - ContentProvider contentProvider = - ContentProvider.coerceToLocalContentProvider(iProviderForName); - if (contentProvider == null) { - Log.e(LOG_TAG, "Fail to get ContentProvider object."); - return; - } - - if (!(contentProvider instanceof AbstractSyncableContentProvider)) { - Log.e(LOG_TAG, - "Acquired ContentProvider object is not AbstractSyncableContentProvider."); - return; - } - - mProvider = (AbstractSyncableContentProvider)contentProvider; - } - public void onEntryCreated(final ContactStruct contactStruct) { long start = System.currentTimeMillis(); - if (mProvider != null) { - contactStruct.pushIntoAbstractSyncableContentProvider( - mProvider, mMyContactsGroupId); - } else { - contactStruct.pushIntoContentResolver(mContentResolver); - } + contactStruct.pushIntoContentResolver(mContentResolver); mTimeToCommit += System.currentTimeMillis() - start; } }
\ No newline at end of file diff --git a/core/java/android/pim/vcard/EntryHandler.java b/core/java/android/pim/vcard/EntryHandler.java index 4015cb5..7fb8114 100644 --- a/core/java/android/pim/vcard/EntryHandler.java +++ b/core/java/android/pim/vcard/EntryHandler.java @@ -16,18 +16,23 @@ package android.pim.vcard; /** - * Unlike VCardBuilderBase, this (and VCardDataBuilder) assumes + * Unlike {@link VCardBuilder}, this (and {@link VCardDataBuilder}) assumes * "each VCard entry should be correctly parsed and passed to each EntryHandler object", */ public interface EntryHandler { /** - * Able to be use this method for showing performance log, etc. - * TODO: better name? + * Called when the parsing started. */ - public void onFinal(); + public void onParsingStart(); /** * The method called when one VCard entry is successfully created */ public void onEntryCreated(final ContactStruct entry); + + /** + * Called when the parsing ended. + * Able to be use this method for showing performance log, etc. + */ + public void onParsingEnd(); } diff --git a/core/java/android/pim/vcard/VCardComposer.java b/core/java/android/pim/vcard/VCardComposer.java new file mode 100644 index 0000000..283d00b --- /dev/null +++ b/core/java/android/pim/vcard/VCardComposer.java @@ -0,0 +1,1433 @@ +/* + * 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.os.RemoteException; +import android.provider.ContactsContract.Contacts; +import android.provider.ContactsContract.Data; +import android.provider.ContactsContract.RawContacts; +import android.provider.ContactsContract.CommonDataKinds.Email; +import android.provider.ContactsContract.CommonDataKinds.Im; +import android.provider.ContactsContract.CommonDataKinds.Miscellaneous; +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.text.TextUtils; +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.util.ArrayList; +import java.util.Arrays; +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 = "vcard.VCardComposer"; + + 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"; + + private OutputStream mOutputStream; // mWriter will close this. + private Writer mWriter; + + private boolean mFinishIsCalled = 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")); + } 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() { + 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 (!mFinishIsCalled) { + onTerminate(); + } + } + } + + public static final String VCARD_TYPE_STRING_DOCOMO = "docomo"; + + private static final String VCARD_PROPERTY_ADR = "ADR"; + private static final String VCARD_PROPERTY_BEGIN = "BEGIN"; + private static final String VCARD_PROPERTY_EMAIL = "EMAIL"; + private static final String VCARD_PROPERTY_END = "END"; + private static final String VCARD_PROPERTY_NAME = "N"; + private static final String VCARD_PROPERTY_FULL_NAME = "FN"; + private static final String VCARD_PROPERTY_NOTE = "NOTE"; + private static final String VCARD_PROPERTY_ORG = "ORG"; + private static final String VCARD_PROPERTY_SOUND = "SOUND"; + private static final String VCARD_PROPERTY_SORT_STRING = "SORT-STRING"; + private static final String VCARD_PROPERTY_NICKNAME = "NICKNAME"; + private static final String VCARD_PROPERTY_TEL = "TEL"; + private static final String VCARD_PROPERTY_TITLE = "TITLE"; + private static final String VCARD_PROPERTY_PHOTO = "PHOTO"; + private static final String VCARD_PROPERTY_VERSION = "VERSION"; + private static final String VCARD_PROPERTY_URL = "URL"; + private static final String VCARD_PROPERTY_BIRTHDAY = "BDAY"; + + private static final String VCARD_PROPERTY_X_PHONETIC_FIRST_NAME = "X-PHONETIC-FIRST-NAME"; + private static final String VCARD_PROPERTY_X_PHONETIC_MIDDLE_NAME = "X-PHONETIC-MIDDLE-NAME"; + private static final String VCARD_PROPERTY_X_PHONETIC_LAST_NAME = "X-PHONETIC-LAST-NAME"; + + // Android specific properties + private static final String VCARD_PROPERTY_X_PHONETIC_NAME = "X-PHONETIC-NAME"; + private static final String VCARD_PROPERTY_X_NICKNAME = "X-NICKNAME"; + // TODO: add properties like X-LATITUDE + + // Properties for DoCoMo vCard. + private static final String VCARD_PROPERTY_X_CLASS = "X-CLASS"; + private static final String VCARD_PROPERTY_X_REDUCTION = "X-REDUCTION"; + private static final String VCARD_PROPERTY_X_NO = "X-NO"; + private static final String VCARD_PROPERTY_X_DCM_HMN_MODE = "X-DCM-HMN-MODE"; + + private static final String VCARD_DATA_VCARD = "VCARD"; + private static final String VCARD_DATA_PUBLIC = "PUBLIC"; + + private static final String VCARD_ATTR_SEPARATOR = ";"; + private static final String VCARD_COL_SEPARATOR = "\r\n"; + private static final String VCARD_DATA_SEPARATOR = ":"; + private static final String VCARD_ITEM_SEPARATOR = ";"; + private static final String VCARD_WS = " "; + + // Type strings are now in VCardConstants.java. + + private static final String VCARD_ATTR_ENCODING_QP = "ENCODING=QUOTED-PRINTABLE"; + + private static final String VCARD_ATTR_ENCODING_BASE64_V21 = "ENCODING=BASE64"; + private static final String VCARD_ATTR_ENCODING_BASE64_V30 = "ENCODING=b"; + + private static final String SHIFT_JIS = "SHIFT_JIS"; + + private final Context mContext; + private final int mVCardType; + private final boolean mCareHandlerErrors; + private final ContentResolver mContentResolver; + + // Convenient member variables about the restriction of the vCard format. + // Used for not calling the same methods returning same results. + private final boolean mIsV30; + private final boolean mIsJapaneseMobilePhone; + private final boolean mOnlyOneNoteFieldIsAvailable; + private final boolean mIsDoCoMo; + private final boolean mUsesQuotedPrintable; + private final boolean mUsesAndroidProperty; + private final boolean mUsesDefactProperty; + private final boolean mUsesShiftJis; + + private Cursor mCursor; + private int mIdColumn; + + private String mCharsetString; + private static String mVCardAttributeCharset; + private boolean mTerminateIsCalled; + private List<OneEntryHandler> mHandlerList; + + private String mErrorReason = "No error"; + + private static final Map<Integer, String> sImMap; + + static { + sImMap = new HashMap<Integer, String>(); + sImMap.put(Im.PROTOCOL_AIM, Constants.PROPERTY_X_AIM); + sImMap.put(Im.PROTOCOL_MSN, Constants.PROPERTY_X_MSN); + sImMap.put(Im.PROTOCOL_YAHOO, Constants.PROPERTY_X_YAHOO); + sImMap.put(Im.PROTOCOL_ICQ, Constants.PROPERTY_X_ICQ); + sImMap.put(Im.PROTOCOL_JABBER, Constants.PROPERTY_X_JABBER); + sImMap.put(Im.PROTOCOL_SKYPE, Constants.PROPERTY_X_SKYPE_USERNAME); + // Google talk is a special case. + } + + + public VCardComposer(Context context) { + this(context, VCardConfig.VCARD_TYPE_DEFAULT, true); + } + + public VCardComposer(Context context, String vcardTypeStr, + boolean careHandlerErrors) { + this(context, VCardConfig.getVCardTypeFromString(vcardTypeStr), + careHandlerErrors); + } + + public VCardComposer(Context context, int vcardType, boolean careHandlerErrors) { + mContext = context; + mVCardType = vcardType; + mCareHandlerErrors = careHandlerErrors; + mContentResolver = context.getContentResolver(); + + mIsV30 = VCardConfig.isV30(vcardType); + mUsesQuotedPrintable = VCardConfig.usesQuotedPrintable(vcardType); + mIsDoCoMo = VCardConfig.isDoCoMo(vcardType); + mIsJapaneseMobilePhone = VCardConfig + .needsToConvertPhoneticString(vcardType); + mOnlyOneNoteFieldIsAvailable = VCardConfig + .onlyOneNoteFieldIsAvailable(vcardType); + mUsesAndroidProperty = VCardConfig + .usesAndroidSpecificProperty(vcardType); + mUsesDefactProperty = VCardConfig.usesDefactProperty(vcardType); + mUsesShiftJis = VCardConfig.usesShiftJis(vcardType); + + if (mIsDoCoMo) { + mCharsetString = CharsetUtils.charsetForVendor(SHIFT_JIS, "docomo").name(); + // 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). + mVCardAttributeCharset = "CHARSET=" + SHIFT_JIS; + } else if (mUsesShiftJis) { + mCharsetString = CharsetUtils.charsetForVendor(SHIFT_JIS).name(); + mVCardAttributeCharset = "CHARSET=" + SHIFT_JIS; + } else { + mCharsetString = "UTF-8"; + mVCardAttributeCharset = "CHARSET=UTF-8"; + } + } + + /** + * Must call before {{@link #init()}. + */ + public void addHandler(OneEntryHandler handler) { + if (mHandlerList == null) { + mHandlerList = new ArrayList<OneEntryHandler>(); + } + mHandlerList.add(handler); + } + + public boolean init() { + return init(null, null); + } + + /** + * @return Returns true when initialization is successful and all the other + * methods are available. Returns false otherwise. + */ + public boolean init(final String selection, final String[] selectionArgs) { + 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 = new String[] {Contacts._ID,}; + + // TODO: thorow an appropriate exception! + mCursor = mContentResolver.query(RawContacts.CONTENT_URI, projection, + selection, selectionArgs, null); + if (mCursor == null || !mCursor.moveToFirst()) { + if (mCursor != null) { + try { + mCursor.close(); + } catch (SQLiteException e) { + Log.e(LOG_TAG, "SQLiteException on Cursor#close(): " + + e.getMessage()); + } + mCursor = null; + } + mErrorReason = "Getting database information failed."; + return false; + } + + mIdColumn = mCursor.getColumnIndex(Contacts._ID); + + return true; + } + + public boolean createOneEntry() { + if (mCursor == null || mCursor.isAfterLast()) { + // TODO: ditto + mErrorReason = "Not initialized or database has some problem."; + return false; + } + String name = null; + String vcard; + try { + vcard = createOneEntryInternal(mCursor.getString(mIdColumn)); + } 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: " + + name); + 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) { + final StringBuilder builder = new StringBuilder(); + appendVCardLine(builder, VCARD_PROPERTY_BEGIN, VCARD_DATA_VCARD); + if (mIsV30) { + appendVCardLine(builder, VCARD_PROPERTY_VERSION, Constants.VERSION_V30); + } else { + appendVCardLine(builder, VCARD_PROPERTY_VERSION, Constants.VERSION_V21); + } + + final Map<String, List<ContentValues>> contentValuesListMap = + new HashMap<String, List<ContentValues>>(); + + final String selection = Data.RAW_CONTACT_ID + "=?"; + final String[] selectionArgs = new String[] {contactId}; + EntityIterator entityIterator = null; + try { + entityIterator = mContentResolver.queryEntities( + RawContacts.CONTENT_URI, selection, selectionArgs, null); + 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); + } + } + } + } catch (RemoteException e) { + Log.e(LOG_TAG, String.format("RemoteException at id %s (%s)", + contactId, e.getMessage())); + return ""; + } finally { + if (entityIterator != null) { + entityIterator.close(); + } + } + + // TODO: consolidate order? (low priority) + appendStructuredNames(builder, contentValuesListMap); + appendNickNames(builder, contentValuesListMap); + appendPhones(builder, contentValuesListMap); + appendEmails(builder, contentValuesListMap); + appendPostals(builder, contentValuesListMap); + appendIms(builder, contentValuesListMap); + appendWebsites(builder, contentValuesListMap); + appendBirthday(builder, contentValuesListMap); + appendOrganizations(builder, contentValuesListMap); + appendPhotos(builder, contentValuesListMap); + appendNotes(builder, contentValuesListMap); + // TODO: GroupMembership... What? + + if (mIsDoCoMo) { + appendVCardLine(builder, VCARD_PROPERTY_X_CLASS, VCARD_DATA_PUBLIC); + appendVCardLine(builder, VCARD_PROPERTY_X_REDUCTION, ""); + appendVCardLine(builder, VCARD_PROPERTY_X_NO, ""); + appendVCardLine(builder, VCARD_PROPERTY_X_DCM_HMN_MODE, ""); + } + + appendVCardLine(builder, VCARD_PROPERTY_END, VCARD_DATA_VCARD); + + 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; + } + + private void appendStructuredNames(StringBuilder builder, + final Map<String, List<ContentValues>> contentValuesListMap) { + List<ContentValues> contentValuesList = contentValuesListMap + .get(StructuredName.CONTENT_ITEM_TYPE); + if (contentValuesList != null) { + appendStructuredNamesInternal(builder, contentValuesList); + } else if (mIsDoCoMo) { + appendVCardLine(builder, VCARD_PROPERTY_NAME, ""); + } + } + + private void appendStructuredNamesInternal(final StringBuilder builder, + final List<ContentValues> contentValuesList) { + for (ContentValues contentValues : 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); + + // For now, some primary element is not encoded into Quoted-Printable, which is not + // valid in vCard spec strictly. In the future, we may have to have some flag to + // enable composer to encode these primary field into Quoted-Printable. + if (!TextUtils.isEmpty(familyName) || !TextUtils.isEmpty(givenName)) { + final String encodedFamily = escapeCharacters(familyName); + final String encodedGiven = escapeCharacters(givenName); + final String encodedMiddle = escapeCharacters(middleName); + final String encodedPrefix = escapeCharacters(prefix); + final String encodedSuffix = escapeCharacters(suffix); + + // N property. This order is specified by vCard spec and does not depend on countries. + builder.append(VCARD_PROPERTY_NAME); + if (!(VCardUtils.containsOnlyAscii(familyName) && + VCardUtils.containsOnlyAscii(givenName) && + VCardUtils.containsOnlyAscii(middleName) && + VCardUtils.containsOnlyAscii(prefix) && + VCardUtils.containsOnlyAscii(suffix))) { + builder.append(VCARD_ATTR_SEPARATOR); + builder.append(mVCardAttributeCharset); + } + + builder.append(VCARD_DATA_SEPARATOR); + builder.append(encodedFamily); + builder.append(VCARD_ITEM_SEPARATOR); + builder.append(encodedGiven); + builder.append(VCARD_ITEM_SEPARATOR); + builder.append(encodedMiddle); + builder.append(VCARD_ITEM_SEPARATOR); + builder.append(encodedPrefix); + builder.append(VCARD_ITEM_SEPARATOR); + builder.append(encodedSuffix); + builder.append(VCARD_COL_SEPARATOR); + + final String encodedFullname = VCardUtils.constructNameFromElements( + VCardConfig.getNameOrderType(mVCardType), + encodedFamily, encodedMiddle, encodedGiven, encodedPrefix, encodedSuffix); + + // FN property + builder.append(VCARD_PROPERTY_FULL_NAME); + builder.append(VCARD_ATTR_SEPARATOR); + if (!VCardUtils.containsOnlyAscii(encodedFullname)) { + builder.append(mVCardAttributeCharset); + builder.append(VCARD_DATA_SEPARATOR); + } + builder.append(encodedFullname); + builder.append(VCARD_COL_SEPARATOR); + } else if (!TextUtils.isEmpty(displayName)) { + builder.append(VCARD_PROPERTY_NAME); + builder.append(VCARD_ATTR_SEPARATOR); + builder.append(mVCardAttributeCharset); + builder.append(VCARD_DATA_SEPARATOR); + builder.append(escapeCharacters(displayName)); + builder.append(VCARD_ITEM_SEPARATOR); + builder.append(VCARD_ITEM_SEPARATOR); + builder.append(VCARD_ITEM_SEPARATOR); + builder.append(VCARD_ITEM_SEPARATOR); + builder.append(VCARD_COL_SEPARATOR); + } else if (mIsDoCoMo) { + appendVCardLine(builder, VCARD_PROPERTY_NAME, ""); + } + + String phoneticFamilyName = contentValues + .getAsString(StructuredName.PHONETIC_FAMILY_NAME); + String phoneticMiddleName = contentValues + .getAsString(StructuredName.PHONETIC_MIDDLE_NAME); + String phoneticGivenName = contentValues + .getAsString(StructuredName.PHONETIC_GIVEN_NAME); + if (!(TextUtils.isEmpty(phoneticFamilyName) + && TextUtils.isEmpty(phoneticMiddleName) && TextUtils + .isEmpty(phoneticGivenName))) { // if not empty + if (mIsJapaneseMobilePhone) { + phoneticFamilyName = VCardUtils + .toHalfWidthString(phoneticFamilyName); + phoneticMiddleName = VCardUtils + .toHalfWidthString(phoneticMiddleName); + phoneticGivenName = VCardUtils + .toHalfWidthString(phoneticGivenName); + } + + if (mIsV30) { + final String sortString = VCardUtils + .constructNameFromElements(mVCardType, + phoneticFamilyName, phoneticMiddleName, + phoneticGivenName); + builder.append(VCARD_PROPERTY_SORT_STRING); + + if (!VCardUtils.containsOnlyAscii(sortString)) { + // Strictly, adding charset information is NOT valid in + // VCard 3.0, + // but we'll add this info since parser side may be able to + // use the charset via + // this attribute field. + // + // 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. + builder.append(VCARD_ATTR_SEPARATOR); + builder.append(mVCardAttributeCharset); + } + + builder.append(VCARD_DATA_SEPARATOR); + builder.append(sortString); + builder.append(VCARD_COL_SEPARATOR); + } else { + // 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 since it is supported by a + // lot of + // Japanese mobile phones. + // + // TODO: should use Quoted-Pritable? + builder.append(VCARD_PROPERTY_SOUND); + builder.append(VCARD_ATTR_SEPARATOR); + builder.append(Constants.ATTR_TYPE_X_IRMC_N); + builder.append(VCARD_ATTR_SEPARATOR); + + if (!(VCardUtils.containsOnlyAscii(phoneticFamilyName) && + VCardUtils.containsOnlyAscii(phoneticMiddleName) && + VCardUtils.containsOnlyAscii(phoneticGivenName))) { + builder.append(mVCardAttributeCharset); + builder.append(VCARD_DATA_SEPARATOR); + } + + builder.append(escapeCharacters(phoneticFamilyName)); + builder.append(VCARD_ITEM_SEPARATOR); + builder.append(escapeCharacters(phoneticMiddleName)); + builder.append(VCARD_ITEM_SEPARATOR); + builder.append(escapeCharacters(phoneticGivenName)); + builder.append(VCARD_ITEM_SEPARATOR); + builder.append(VCARD_ITEM_SEPARATOR); + builder.append(VCARD_COL_SEPARATOR); + + if (mUsesAndroidProperty) { + final String phoneticName = VCardUtils + .constructNameFromElements(mVCardType, + phoneticFamilyName, phoneticMiddleName, + phoneticGivenName); + builder.append(VCARD_PROPERTY_X_PHONETIC_NAME); + + if (!VCardUtils.containsOnlyAscii(phoneticName)) { + builder.append(VCARD_ATTR_SEPARATOR); + builder.append(mVCardAttributeCharset); + } + + builder.append(VCARD_DATA_SEPARATOR); + // TODO: may need to make the text quoted-printable. + builder.append(phoneticName); + builder.append(VCARD_COL_SEPARATOR); + } + } + } else if (mIsDoCoMo) { + builder.append(VCARD_PROPERTY_SOUND); + builder.append(VCARD_ATTR_SEPARATOR); + builder.append(Constants.ATTR_TYPE_X_IRMC_N); + builder.append(VCARD_DATA_SEPARATOR); + builder.append(VCARD_ITEM_SEPARATOR); + builder.append(VCARD_ITEM_SEPARATOR); + builder.append(VCARD_ITEM_SEPARATOR); + builder.append(VCARD_ITEM_SEPARATOR); + builder.append(VCARD_COL_SEPARATOR); + } + + if (mUsesDefactProperty) { + if (!TextUtils.isEmpty(phoneticGivenName)) { + builder.append(VCARD_PROPERTY_X_PHONETIC_FIRST_NAME); + builder.append(VCARD_DATA_SEPARATOR); + builder.append(phoneticGivenName); + builder.append(VCARD_COL_SEPARATOR); + } + if (!TextUtils.isEmpty(phoneticMiddleName)) { + builder.append(VCARD_PROPERTY_X_PHONETIC_MIDDLE_NAME); + builder.append(VCARD_DATA_SEPARATOR); + builder.append(phoneticMiddleName); + builder.append(VCARD_COL_SEPARATOR); + } + if (!TextUtils.isEmpty(phoneticFamilyName)) { + builder.append(VCARD_PROPERTY_X_PHONETIC_LAST_NAME); + builder.append(VCARD_DATA_SEPARATOR); + builder.append(phoneticFamilyName); + builder.append(VCARD_COL_SEPARATOR); + } + } + } + } + + private void appendNickNames(final StringBuilder builder, + final Map<String, List<ContentValues>> contentValuesListMap) { + List<ContentValues> contentValuesList = contentValuesListMap + .get(Nickname.CONTENT_ITEM_TYPE); + if (contentValuesList != null) { + final String propertyNickname; + if (mIsV30) { + propertyNickname = VCARD_PROPERTY_NICKNAME; + } else if (mUsesAndroidProperty) { + propertyNickname = VCARD_PROPERTY_X_NICKNAME; + } else { + // There's no way to add this field. + return; + } + + for (ContentValues contentValues : contentValuesList) { + final String nickname = contentValues + .getAsString(Nickname.NAME); + if (TextUtils.isEmpty(nickname)) { + continue; + } + builder.append(propertyNickname); + + if (!VCardUtils.containsOnlyAscii(propertyNickname)) { + // Strictly, this is not valid in vCard 3.0. See above. + builder.append(VCARD_ATTR_SEPARATOR); + builder.append(mVCardAttributeCharset); + } + + builder.append(VCARD_DATA_SEPARATOR); + builder.append(escapeCharacters(nickname)); + builder.append(VCARD_COL_SEPARATOR); + } + } + } + + private void appendPhones(final StringBuilder builder, + final Map<String, List<ContentValues>> contentValuesListMap) { + List<ContentValues> contentValuesList = contentValuesListMap + .get(Phone.CONTENT_ITEM_TYPE); + if (contentValuesList != null) { + for (ContentValues contentValues : contentValuesList) { + appendVCardTelephoneLine(builder, contentValues + .getAsInteger(Phone.TYPE), contentValues + .getAsString(Phone.LABEL), contentValues + .getAsString(Phone.NUMBER)); + } + } else if (mIsDoCoMo) { + appendVCardTelephoneLine(builder, Phone.TYPE_HOME, "", ""); + } + } + + private void appendEmails(final StringBuilder builder, + final Map<String, List<ContentValues>> contentValuesListMap) { + List<ContentValues> contentValuesList = contentValuesListMap + .get(Email.CONTENT_ITEM_TYPE); + if (contentValuesList != null) { + for (ContentValues contentValues : contentValuesList) { + appendVCardEmailLine(builder, contentValues + .getAsInteger(Email.TYPE), contentValues + .getAsString(Email.LABEL), contentValues + .getAsString(Email.DATA)); + } + } else if (mIsDoCoMo) { + appendVCardEmailLine(builder, Email.TYPE_HOME, "", ""); + } + } + + private void appendPostals(final StringBuilder builder, + final Map<String, List<ContentValues>> contentValuesListMap) { + List<ContentValues> contentValuesList = contentValuesListMap + .get(StructuredPostal.CONTENT_ITEM_TYPE); + + if (contentValuesList != null) { + if (mIsDoCoMo) { + appendPostalsForDoCoMo(builder, contentValuesList); + } else { + appendPostalsForGeneric(builder, contentValuesList); + } + } else if (mIsDoCoMo) { + builder.append(VCARD_PROPERTY_ADR); + builder.append(VCARD_ATTR_SEPARATOR); + builder.append(Constants.ATTR_TYPE_HOME); + builder.append(VCARD_DATA_SEPARATOR); + builder.append(VCARD_COL_SEPARATOR); + } + } + + /** + * Try to append just one line. If there's no appropriate address + * information, append an empty line. + */ + private void appendPostalsForDoCoMo(final StringBuilder builder, + final List<ContentValues> contentValuesList) { + // TODO: from old, inefficient code. fix this. + if (appendPostalsForDoCoMoInternal(builder, contentValuesList, + StructuredPostal.TYPE_HOME)) { + return; + } + if (appendPostalsForDoCoMoInternal(builder, contentValuesList, + StructuredPostal.TYPE_WORK)) { + return; + } + if (appendPostalsForDoCoMoInternal(builder, contentValuesList, + StructuredPostal.TYPE_OTHER)) { + return; + } + if (appendPostalsForDoCoMoInternal(builder, contentValuesList, + StructuredPostal.TYPE_CUSTOM)) { + return; + } + + Log.w(LOG_TAG, + "Should not come here. Must have at least one postal data."); + } + + private boolean appendPostalsForDoCoMoInternal(final StringBuilder builder, + final List<ContentValues> contentValuesList, int preferedType) { + for (ContentValues contentValues : contentValuesList) { + final int type = contentValues.getAsInteger(StructuredPostal.TYPE); + final String label = contentValues + .getAsString(StructuredPostal.LABEL); + if (type == preferedType) { + appendVCardPostalLine(builder, type, label, contentValues); + return true; + } + } + return false; + } + + private void appendPostalsForGeneric(final StringBuilder builder, + final List<ContentValues> contentValuesList) { + for (ContentValues contentValues : contentValuesList) { + final int type = contentValues.getAsInteger(StructuredPostal.TYPE); + final String label = contentValues + .getAsString(StructuredPostal.LABEL); + appendVCardPostalLine(builder, type, label, contentValues); + } + } + + private void appendIms(final StringBuilder builder, + final Map<String, List<ContentValues>> contentValuesListMap) { + List<ContentValues> contentValuesList = contentValuesListMap + .get(Im.CONTENT_ITEM_TYPE); + if (contentValuesList != null) { + for (ContentValues contentValues : contentValuesList) { + int type = contentValues.getAsInteger(Im.PROTOCOL); + String data = contentValues.getAsString(Im.DATA); + + Log.d("@@@", "Im information. protocol=\"" + type + + "\", data=\"" + data + "\", protocol=\"" + + contentValues.getAsString(Im.PROTOCOL) + "\", custom_protocol=\"" + + contentValues.getAsString(Im.CUSTOM_PROTOCOL) + "\""); + + if (type == Im.PROTOCOL_GOOGLE_TALK) { + if (VCardConfig.usesAndroidSpecificProperty(mVCardType)) { + appendVCardLine(builder, Constants.PROPERTY_X_GOOGLE_TALK, data); + } + // TODO: add "X-GOOGLE TALK" case... + } + } + } + } + + private void appendWebsites(final StringBuilder builder, + final Map<String, List<ContentValues>> contentValuesListMap) { + List<ContentValues> contentValuesList = contentValuesListMap + .get(Website.CONTENT_ITEM_TYPE); + if (contentValuesList != null) { + for (ContentValues contentValues : contentValuesList) { + final String website = contentValues.getAsString(Website.URL); + appendVCardLine(builder, VCARD_PROPERTY_URL, website); + } + } + } + + private void appendBirthday(final StringBuilder builder, + final Map<String, List<ContentValues>> contentValuesListMap) { + List<ContentValues> contentValuesList = contentValuesListMap + .get(Website.CONTENT_ITEM_TYPE); + if (contentValuesList != null && contentValuesList.size() > 0) { + // Theoretically, there must be only one birthday for each vCard data and + // we are afraid of some parse error occuring in some devices, so + // we emit only one birthday entry for now. + final String birthday = contentValuesList.get(0).getAsString(Miscellaneous.BIRTHDAY); + appendVCardLine(builder, VCARD_PROPERTY_BIRTHDAY, birthday); + } + } + + private void appendOrganizations(final StringBuilder builder, + final Map<String, List<ContentValues>> contentValuesListMap) { + List<ContentValues> contentValuesList = contentValuesListMap + .get(Organization.CONTENT_ITEM_TYPE); + if (contentValuesList != null) { + for (ContentValues contentValues : contentValuesList) { + final String company = contentValues + .getAsString(Organization.COMPANY); + final String title = contentValues + .getAsString(Organization.TITLE); + appendVCardLine(builder, VCARD_PROPERTY_ORG, company, true, + mUsesQuotedPrintable); + appendVCardLine(builder, VCARD_PROPERTY_TITLE, title, true, + mUsesQuotedPrintable); + } + } + } + + private void appendPhotos(final StringBuilder builder, + final Map<String, List<ContentValues>> contentValuesListMap) { + List<ContentValues> contentValuesList = contentValuesListMap + .get(Photo.CONTENT_ITEM_TYPE); + if (contentValuesList != null) { + for (ContentValues contentValues : contentValuesList) { + byte[] data = contentValues.getAsByteArray(Photo.PHOTO); + final String photoType; + // Use some heuristics for guessing the format of the image. + // TODO: there should be some general API for detecting the file format. + if (data.length >= 3 && data[0] == 'G' && data[1] == 'I' + && data[2] == 'F') { + photoType = "GIF"; + } else if (data.length >= 4 && data[0] == (byte) 0x89 + && data[1] == 'P' && data[2] == 'N' && data[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... + photoType = "PNG"; + } else if (data.length >= 2 && data[0] == (byte) 0xff + && data[1] == (byte) 0xd8) { + photoType = "JPEG"; + } else { + Log.d(LOG_TAG, "Unknown photo type. Ignore."); + continue; + } + String photoString = VCardUtils.encodeBase64(data); + if (photoString.length() > 0) { + appendVCardPhotoLine(builder, photoString, photoType); + } + } + } + } + + private void appendNotes(final StringBuilder builder, + final Map<String, List<ContentValues>> contentValuesListMap) { + final List<ContentValues> contentValuesList = + contentValuesListMap.get(Note.CONTENT_ITEM_TYPE); + if (contentValuesList != null) { + if (mOnlyOneNoteFieldIsAvailable) { + StringBuilder noteBuilder = new StringBuilder(); + boolean first = true; + for (ContentValues contentValues : contentValuesList) { + final String note = contentValues.getAsString(Note.NOTE); + if (note.length() > 0) { + if (first) { + first = false; + } else { + noteBuilder.append('\n'); + } + noteBuilder.append(note); + } + } + appendVCardLine(builder, VCARD_PROPERTY_NOTE, noteBuilder.toString(), + true, mUsesQuotedPrintable); + } else { + for (ContentValues contentValues : contentValuesList) { + final String note = contentValues.getAsString(Note.NOTE); + if (!TextUtils.isEmpty(note)) { + appendVCardLine(builder, VCARD_PROPERTY_NOTE, note, true, + mUsesQuotedPrintable); + } + } + } + } + } + + /** + * 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(String unescaped) { + if (TextUtils.isEmpty(unescaped)) { + return ""; + } + + StringBuilder builder = new StringBuilder(); + final int length = unescaped.length(); + for (int i = 0; i < length; i++) { + char ch = unescaped.charAt(i); + switch (ch) { + case ';': + builder.append('\\'); + builder.append(';'); + break; + case '\r': + if (i + 1 < length) { + char nextChar = unescaped.charAt(i); + if (nextChar == '\n') { + continue; + } 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". + builder.append("\\n"); + break; + case '\\': + if (mIsV30) { + builder.append("\\\\"); + break; + } + case '<': + case '>': + if (mIsDoCoMo) { + builder.append('\\'); + builder.append(ch); + } + break; + case ',': + if (mIsV30) { + builder.append("\\,"); + break; + } + default: + builder.append(ch); + break; + } + } + return builder.toString(); + } + + private void appendVCardPhotoLine(StringBuilder builder, + String encodedData, String type) { + StringBuilder tmpBuilder = new StringBuilder(); + tmpBuilder.append(VCARD_PROPERTY_PHOTO); + tmpBuilder.append(VCARD_ATTR_SEPARATOR); + if (mIsV30) { + tmpBuilder.append(VCARD_ATTR_ENCODING_BASE64_V30); + } else { + tmpBuilder.append(VCARD_ATTR_ENCODING_BASE64_V21); + } + tmpBuilder.append(VCARD_ATTR_SEPARATOR); + tmpBuilder.append("TYPE="); + tmpBuilder.append(type); + tmpBuilder.append(VCARD_DATA_SEPARATOR); + tmpBuilder.append(encodedData); + + String tmpStr = tmpBuilder.toString(); + tmpBuilder = new StringBuilder(); + int lineCount = 0; + for (int i = 0; i < tmpStr.length(); i++) { + tmpBuilder.append(tmpStr.charAt(i)); + lineCount++; + if (lineCount > 72) { + tmpBuilder.append(VCARD_COL_SEPARATOR); + tmpBuilder.append(VCARD_WS); + lineCount = 0; + } + } + builder.append(tmpBuilder.toString()); + builder.append(VCARD_COL_SEPARATOR); + builder.append(VCARD_COL_SEPARATOR); + } + + private void appendVCardPostalLine(StringBuilder builder, int type, + String label, final ContentValues contentValues) { + builder.append(VCARD_PROPERTY_ADR); + builder.append(VCARD_ATTR_SEPARATOR); + + boolean dataExists = false; + String[] dataArray = VCardUtils.getVCardPostalElements(contentValues); + int length = dataArray.length; + final boolean useQuotedPrintable = mUsesQuotedPrintable; + for (int i = 0; i < length; i++) { + String data = dataArray[i]; + if (!TextUtils.isEmpty(data)) { + dataExists = true; + if (useQuotedPrintable) { + dataArray[i] = encodeQuotedPrintable(data); + } else { + dataArray[i] = escapeCharacters(data); + } + } + } + + boolean typeIsAppended = false; + switch (type) { + case StructuredPostal.TYPE_HOME: + builder.append(Constants.ATTR_TYPE_HOME); + typeIsAppended = true; + break; + case StructuredPostal.TYPE_WORK: + builder.append(Constants.ATTR_TYPE_WORK); + typeIsAppended = true; + break; + case StructuredPostal.TYPE_CUSTOM: + if (mUsesAndroidProperty && VCardUtils.containsOnlyAlphaDigitHyphen(label)){ + // We're not sure whether the label is valid in the spec ("IANA-token" in the vCard 3.1 + // is unclear...) + // Just for safety, we add "X-" at the beggining of each label. + // Also checks the label obeys with vCard 3.0 spec. + builder.append("X-"); + builder.append(label); + builder.append(VCARD_DATA_SEPARATOR); + } + break; + case StructuredPostal.TYPE_OTHER: + break; + default: + Log.e(LOG_TAG, "Unknown StructuredPostal type: " + type); + break; + } + + if (dataExists) { + if (typeIsAppended) { + builder.append(VCARD_ATTR_SEPARATOR); + } + // Strictly, vCard 3.0 does not allow this, but we add this since + // this information + // should be useful, Assume no parser does not emit error with this + // attribute. + builder.append(mVCardAttributeCharset); + if (useQuotedPrintable) { + builder.append(VCARD_ATTR_SEPARATOR); + builder.append(VCARD_ATTR_ENCODING_QP); + } + } + builder.append(VCARD_DATA_SEPARATOR); + if (dataExists) { + // The elements in dataArray are already encoded to quoted printable + // if needed. + // See above. + // + // TODO: in vCard 3.0, one line may become too huge. Fix this. + builder.append(dataArray[0]); + builder.append(VCARD_ITEM_SEPARATOR); + builder.append(dataArray[1]); + builder.append(VCARD_ITEM_SEPARATOR); + builder.append(dataArray[2]); + builder.append(VCARD_ITEM_SEPARATOR); + builder.append(dataArray[3]); + builder.append(VCARD_ITEM_SEPARATOR); + builder.append(dataArray[4]); + builder.append(VCARD_ITEM_SEPARATOR); + builder.append(dataArray[5]); + builder.append(VCARD_ITEM_SEPARATOR); + builder.append(dataArray[6]); + } + builder.append(VCARD_COL_SEPARATOR); + } + + private void appendVCardEmailLine(StringBuilder builder, int type, + String label, String data) { + builder.append(VCARD_PROPERTY_EMAIL); + builder.append(VCARD_ATTR_SEPARATOR); + + switch (type) { + case Email.TYPE_CUSTOM: + if (label.equals( + android.provider.Contacts.ContactMethodsColumns.MOBILE_EMAIL_TYPE_NAME)) { + builder.append(Constants.ATTR_TYPE_CELL); + } else if (mUsesAndroidProperty && VCardUtils.containsOnlyAlphaDigitHyphen(label)){ + builder.append("X-"); + builder.append(label); + } else { + // Default to INTERNET. + builder.append(Constants.ATTR_TYPE_INTERNET); + } + break; + case Email.TYPE_HOME: + builder.append(Constants.ATTR_TYPE_HOME); + break; + case Email.TYPE_WORK: + builder.append(Constants.ATTR_TYPE_WORK); + break; + case Email.TYPE_OTHER: + builder.append(Constants.ATTR_TYPE_INTERNET); + break; + default: + Log.e(LOG_TAG, "Unknown Email type: " + type); + builder.append(Constants.ATTR_TYPE_INTERNET); + break; + } + + builder.append(VCARD_DATA_SEPARATOR); + builder.append(data); + builder.append(VCARD_COL_SEPARATOR); + } + + private void appendVCardTelephoneLine(StringBuilder builder, int type, + String label, String encodedData) { + builder.append(VCARD_PROPERTY_TEL); + builder.append(VCARD_ATTR_SEPARATOR); + + switch (type) { + case Phone.TYPE_HOME: + appendTypeAttributes(builder, Arrays.asList( + Constants.ATTR_TYPE_HOME, Constants.ATTR_TYPE_VOICE)); + break; + case Phone.TYPE_WORK: + appendTypeAttributes(builder, Arrays.asList( + Constants.ATTR_TYPE_WORK, Constants.ATTR_TYPE_VOICE)); + break; + case Phone.TYPE_FAX_HOME: + appendTypeAttributes(builder, Arrays.asList( + Constants.ATTR_TYPE_HOME, Constants.ATTR_TYPE_FAX)); + break; + case Phone.TYPE_FAX_WORK: + appendTypeAttributes(builder, Arrays.asList( + Constants.ATTR_TYPE_WORK, Constants.ATTR_TYPE_FAX)); + break; + case Phone.TYPE_MOBILE: + builder.append(Constants.ATTR_TYPE_CELL); + break; + case Phone.TYPE_PAGER: + if (mIsDoCoMo) { + // Not sure about the reason, but previous implementation had + // used "VOICE" instead of "PAGER" + builder.append(Constants.ATTR_TYPE_VOICE); + } else { + builder.append(Constants.ATTR_TYPE_PAGER); + } + break; + case Phone.TYPE_OTHER: + builder.append(Constants.ATTR_TYPE_VOICE); + break; + case Phone.TYPE_CUSTOM: + if (mUsesAndroidProperty) { + VCardUtils.containsOnlyAlphaDigitHyphen(label); + builder.append("X-" + label); + } else { + // Just ignore the custom type. + builder.append(Constants.ATTR_TYPE_VOICE); + } + break; + default: + appendUncommonPhoneType(builder, type); + break; + } + + builder.append(VCARD_DATA_SEPARATOR); + builder.append(encodedData); + builder.append(VCARD_COL_SEPARATOR); + } + + /** + * Appends phone type string which may not be available in some devices. + */ + private void appendUncommonPhoneType(StringBuilder builder, int type) { + if (mIsDoCoMo) { + // The previous implementation for DoCoMo had been conservative + // about + // miscellaneous types. + builder.append(Constants.ATTR_TYPE_VOICE); + } else { + String phoneAttribute = VCardUtils.getPhoneAttributeString(type); + if (phoneAttribute != null) { + builder.append(phoneAttribute); + } else { + Log.e(LOG_TAG, "Unknown or unsupported (by vCard) Phone type: " + type); + } + } + } + + private void appendVCardLine(final StringBuilder builder, + final String propertyName, final String rawData) { + appendVCardLine(builder, propertyName, rawData, false, false); + } + + private void appendVCardLine(final StringBuilder builder, + final String field, final String rawData, boolean needCharset, + boolean needQuotedPrintable) { + builder.append(field); + if (needCharset) { + builder.append(VCARD_ATTR_SEPARATOR); + builder.append(mVCardAttributeCharset); + } + + final String encodedData; + if (needQuotedPrintable) { + builder.append(VCARD_ATTR_SEPARATOR); + builder.append(VCARD_ATTR_ENCODING_QP); + encodedData = encodeQuotedPrintable(rawData); + } 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. + encodedData = escapeCharacters(rawData); + } + + builder.append(VCARD_DATA_SEPARATOR); + builder.append(encodedData); + builder.append(VCARD_COL_SEPARATOR); + } + + private void appendTypeAttributes(final StringBuilder builder, + 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 (String type : types) { + if (first) { + first = false; + } else { + builder.append(VCARD_ATTR_SEPARATOR); + } + if (mIsV30) { + builder.append(Constants.ATTR_TYPE); + builder.append('='); + } + builder.append(type); + } + } + + private String encodeQuotedPrintable(String str) { + if (TextUtils.isEmpty(str)) { + return ""; + } + { + // Replace "\n" and "\r" with "\r\n". + StringBuilder tmpBuilder = new StringBuilder(); + int length = str.length(); + for (int i = 0; i < length; i++) { + char ch = str.charAt(i); + if (ch == '\r') { + if (i + 1 < length && str.charAt(i + 1) == '\n') { + i++; + } + tmpBuilder.append("\r\n"); + } else if (ch == '\n') { + tmpBuilder.append("\r\n"); + } else { + tmpBuilder.append(ch); + } + } + str = tmpBuilder.toString(); + } + + 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(); + } +} diff --git a/core/java/android/pim/vcard/VCardConfig.java b/core/java/android/pim/vcard/VCardConfig.java index fef9dba..d87b002 100644 --- a/core/java/android/pim/vcard/VCardConfig.java +++ b/core/java/android/pim/vcard/VCardConfig.java @@ -15,43 +15,267 @@ */ package android.pim.vcard; +import java.util.HashMap; +import java.util.Map; + /** - * The class representing VCard related configurations + * The class representing VCard related configurations. Useful static methods are not in this class + * but in VCardUtils. */ public class VCardConfig { - static final int LOG_LEVEL_NONE = 0; - static final int LOG_LEVEL_PERFORMANCE_MEASUREMENT = 0x1; - static final int LOG_LEVEL_SHOW_WARNING = 0x2; - static final int LOG_LEVEL_VERBOSE = + // TODO: may be better to make the instance of this available and stop using static methods and + // one integer. + + /* 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_PERFORMANCE_MEASUREMENT; + // 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"; - // TODO: use this flag - public static boolean IGNORE_CASE_EXCEPT_VALUE = true; + // TODO: make the other codes use this flag + public static final boolean IGNORE_CASE_EXCEPT_VALUE = true; + + private static final int FLAG_V21 = 0; + private 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 = 0x20; + + /** + * 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; + + + // VCard types + + + /** + * General vCard format with the version 2.1. Uses UTF-8 for the charset. + * When composing a vCard entry, the US convension will be used. + * + * e.g. The order of the display name would be "Prefix Given Middle Family Suffix", + * while in Japan, it should be "Prefix Family Middle Given Suffix". + */ + public static final int VCARD_TYPE_V21_GENERIC = + (FLAG_V21 | NAME_ORDER_DEFAULT | FLAG_CHARSET_UTF8 | + FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY); + + /* package */ static String VCARD_TYPE_V21_GENERIC_STR = "v21_generic"; + + /** + * General vCard format with the version 3.0. Uses UTF-8 for the charset. + * + * Note that this type is not fully implemented, so probably some bugs remain especially + * in parsing part. + * + * TODO: implement this type. + */ + public static final int VCARD_TYPE_V30_GENERIC = + (FLAG_V30 | NAME_ORDER_DEFAULT | FLAG_CHARSET_UTF8 | + FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY); + + /* package */ static final String VCARD_TYPE_V30_GENERIC_STR = "v30_generic"; + + /** + * General vCard format with the version 2.1 with some Europe convension. Uses Utf-8. + * Currently, only name order is considered ("Prefix Middle Given Family Suffix") + */ + public static final int VCARD_TYPE_V21_EUROPE = + (FLAG_V21 | NAME_ORDER_EUROPE | FLAG_CHARSET_UTF8 | + FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY); + + /* package */ static final String VCARD_TYPE_V21_EUROPE_STR = "v21_europe"; + + /** + * General vCard format with the version 3.0 with some Europe convension. Uses UTF-8 + */ + public static final int VCARD_TYPE_V30_EUROPE = + (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"; + + /** + * vCard 2.1 format for miscellaneous Japanese devices. Shift_Jis is used for + * parsing/composing the vCard data. + */ + public static final int VCARD_TYPE_V21_JAPANESE = + (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_STR = "v21_japanese"; + + /** + * vCard 2.1 format for miscellaneous Japanese devices, using UTF-8 as default charset. + */ + 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"; - protected static final int LOG_LEVEL = LOG_LEVEL_PERFORMANCE_MEASUREMENT; + /** + * vCard format for miscellaneous Japanese devices, using Shift_Jis for + * parsing/composing the vCard data. + */ + public static final int VCARD_TYPE_V30_JAPANESE = + (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_STR = "v30_japanese"; - // Note: phonetic name probably should be "LAST FIRST MIDDLE" for European languages, and - // space should be added between each element while it should not be in Japanese. - // But unfortunately, we currently do not have the data and are not sure whether we should - // support European version of name ordering. - // - // TODO: Implement the logic described above if we really need European version of - // phonetic name handling. Also, adding the appropriate test case of vCard would be - // highly appreciated. - public static final int NAME_ORDER_TYPE_ENGLISH = 0; - public static final int NAME_ORDER_TYPE_JAPANESE = 1; + /** + * vCard 3.0 format for miscellaneous Japanese devices, using UTF-8 as default charset. + */ + 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"; + + /** + * VCard format used in DoCoMo, which is one of Japanese mobile phone careers. + * Base version is vCard 2.1, but the data has several DoCoMo-specific convensions. + * No Android-specific property nor defact property is included. + */ + public static final int VCARD_TYPE_DOCOMO = + (FLAG_V21 | NAME_ORDER_JAPANESE | FLAG_CHARSET_SHIFT_JIS | FLAG_DOCOMO); + + private static final String VCARD_TYPE_DOCOMO_STR = "docomo"; - public static final int NAME_ORDER_TYPE_DEFAULT = NAME_ORDER_TYPE_ENGLISH; + public static int VCARD_TYPE_DEFAULT = VCARD_TYPE_V21_GENERIC; + + private static final Map<String, Integer> VCARD_TYPES_MAP; + + static { + VCARD_TYPES_MAP = new HashMap<String, Integer>(); + VCARD_TYPES_MAP.put(VCARD_TYPE_V21_GENERIC_STR, VCARD_TYPE_V21_GENERIC); + VCARD_TYPES_MAP.put(VCARD_TYPE_V30_GENERIC_STR, VCARD_TYPE_V30_GENERIC); + VCARD_TYPES_MAP.put(VCARD_TYPE_V21_EUROPE_STR, VCARD_TYPE_V21_EUROPE); + VCARD_TYPES_MAP.put(VCARD_TYPE_V30_EUROPE_STR, VCARD_TYPE_V30_EUROPE); + VCARD_TYPES_MAP.put(VCARD_TYPE_V21_JAPANESE_STR, VCARD_TYPE_V21_JAPANESE); + VCARD_TYPES_MAP.put(VCARD_TYPE_V21_JAPANESE_UTF8_STR, VCARD_TYPE_V21_JAPANESE_UTF8); + VCARD_TYPES_MAP.put(VCARD_TYPE_V30_JAPANESE_STR, VCARD_TYPE_V30_JAPANESE); + VCARD_TYPES_MAP.put(VCARD_TYPE_V30_JAPANESE_UTF8_STR, VCARD_TYPE_V30_JAPANESE_UTF8); + VCARD_TYPES_MAP.put(VCARD_TYPE_DOCOMO_STR, VCARD_TYPE_DOCOMO); + } + + public static int getVCardTypeFromString(String vcardTypeString) { + String loweredKey = vcardTypeString.toLowerCase(); + if (VCARD_TYPES_MAP.containsKey(loweredKey)) { + return VCARD_TYPES_MAP.get(loweredKey); + } else { + // XXX: should return the value indicating the input is invalid? + return VCARD_TYPE_DEFAULT; + } + } + + public static boolean isV30(int vcardType) { + return ((vcardType & FLAG_V30) != 0); + } + + public static boolean usesQuotedPrintable(int vcardType) { + return !isV30(vcardType); + } + + public static boolean isDoCoMo(int vcardType) { + return ((vcardType & FLAG_DOCOMO) != 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(int vcardType) { + return ((vcardType == VCARD_TYPE_V21_JAPANESE) || + (vcardType == VCARD_TYPE_V21_JAPANESE_UTF8) || + (vcardType == VCARD_TYPE_V30_JAPANESE) || + (vcardType == VCARD_TYPE_V30_JAPANESE_UTF8) || + (vcardType == VCARD_TYPE_DOCOMO)); + } + + public static boolean usesShiftJis(int vcardType) { + return ((vcardType & FLAG_CHARSET_SHIFT_JIS) != 0); + } /** - * @hide temporal. may be deleted + * @return true when Japanese phonetic string must be converted to a string + * containing only half-width katakana. This method exists since Japanese mobile + * phones usually use only half-width katakana for expressing phonetic names and + * some devices are not ready for parsing other phonetic strings like hiragana and + * full-width katakana. */ + public static boolean needsToConvertPhoneticString(int vcardType) { + return (vcardType == VCARD_TYPE_DOCOMO); + } + + public static int getNameOrderType(int vcardType) { + return vcardType & NAME_ORDER_MASK; + } + + public static boolean usesAndroidSpecificProperty(int vcardType) { + return ((vcardType & FLAG_USE_ANDROID_PROPERTY) != 0); + } + + public static boolean usesDefactProperty(int vcardType) { + return ((vcardType & FLAG_USE_DEFACT_PROPERTY) != 0); + } + + public static boolean onlyOneNoteFieldIsAvailable(int vcardType) { + return vcardType == VCARD_TYPE_DOCOMO; + } + public static boolean showPerformanceLog() { - return (LOG_LEVEL & LOG_LEVEL_PERFORMANCE_MEASUREMENT) != 0; + return (VCardConfig.LOG_LEVEL & VCardConfig.LOG_LEVEL_PERFORMANCE_MEASUREMENT) != 0; } private VCardConfig() { diff --git a/core/java/android/pim/vcard/VCardDataBuilder.java b/core/java/android/pim/vcard/VCardDataBuilder.java index 4025f6c..fd165e9 100644 --- a/core/java/android/pim/vcard/VCardDataBuilder.java +++ b/core/java/android/pim/vcard/VCardDataBuilder.java @@ -59,7 +59,7 @@ public class VCardDataBuilder implements VCardBuilder { private String mTargetCharset; private boolean mStrictLineBreakParsing; - private int mNameOrderType; + private int mVCardType; // Just for testing. private long mTimePushIntoContentResolver; @@ -67,23 +67,21 @@ public class VCardDataBuilder implements VCardBuilder { private List<EntryHandler> mEntryHandlers = new ArrayList<EntryHandler>(); public VCardDataBuilder() { - this(null, null, false, VCardConfig.NAME_ORDER_TYPE_DEFAULT); + this(null, null, false, VCardConfig.VCARD_TYPE_V21_GENERIC); } /** * @hide */ - public VCardDataBuilder(int nameOrderType) { - this(null, null, false, nameOrderType); + public VCardDataBuilder(int vcardType) { + this(null, null, false, vcardType); } - + /** * @hide */ - public VCardDataBuilder(String charset, - boolean strictLineBreakParsing, - int nameOrderType) { - this(null, charset, strictLineBreakParsing, nameOrderType); + public VCardDataBuilder(String charset, boolean strictLineBreakParsing, int vcardType) { + this(null, charset, strictLineBreakParsing, vcardType); } /** @@ -92,7 +90,7 @@ public class VCardDataBuilder implements VCardBuilder { public VCardDataBuilder(String sourceCharset, String targetCharset, boolean strictLineBreakParsing, - int nameOrderType) { + int vcardType) { if (sourceCharset != null) { mSourceCharset = sourceCharset; } else { @@ -104,7 +102,7 @@ public class VCardDataBuilder implements VCardBuilder { mTargetCharset = TARGET_CHARSET; } mStrictLineBreakParsing = strictLineBreakParsing; - mNameOrderType = nameOrderType; + mVCardType = vcardType; } public void addEntryHandler(EntryHandler entryHandler) { @@ -112,11 +110,14 @@ public class VCardDataBuilder implements VCardBuilder { } public void start() { + for (EntryHandler entryHandler : mEntryHandlers) { + entryHandler.onParsingStart(); + } } public void end() { for (EntryHandler entryHandler : mEntryHandlers) { - entryHandler.onFinal(); + entryHandler.onParsingEnd(); } } @@ -135,7 +136,7 @@ public class VCardDataBuilder implements VCardBuilder { Log.e(LOG_TAG, "This is not VCARD!"); } - mCurrentContactStruct = new ContactStruct(mNameOrderType); + mCurrentContactStruct = new ContactStruct(mVCardType); } public void endRecord() { @@ -164,8 +165,7 @@ public class VCardDataBuilder implements VCardBuilder { public void propertyParamType(String type) { if (mParamType != null) { - Log.e(LOG_TAG, - "propertyParamType() is called more than once " + + Log.e(LOG_TAG, "propertyParamType() is called more than once " + "before propertyParamValue() is called"); } mParamType = type; @@ -173,6 +173,7 @@ public class VCardDataBuilder implements VCardBuilder { 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); @@ -297,7 +298,7 @@ public class VCardDataBuilder implements VCardBuilder { String charset = ((charsetCollection != null) ? charsetCollection.iterator().next() : null); String targetCharset = CharsetUtils.nameForDefaultVendor(charset); - + final Collection<String> encodingCollection = mCurrentProperty.getParameters("ENCODING"); String encoding = ((encodingCollection != null) ? encodingCollection.iterator().next() : null); diff --git a/core/java/android/pim/vcard/VCardParser_V21.java b/core/java/android/pim/vcard/VCardParser_V21.java index 17a138f..974fca8 100644 --- a/core/java/android/pim/vcard/VCardParser_V21.java +++ b/core/java/android/pim/vcard/VCardParser_V21.java @@ -34,7 +34,7 @@ import java.util.HashSet; * This class is used to parse vcard. Please refer to vCard Specification 2.1. */ public class VCardParser_V21 extends VCardParser { - private static final String LOG_TAG = "VCardParser_V21"; + private static final String LOG_TAG = "vcard.VCardParser_V21"; /** Store the known-type */ private static final HashSet<String> sKnownTypeSet = new HashSet<String>( @@ -58,8 +58,10 @@ public class VCardParser_V21 extends VCardParser { "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... + /** + * 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")); @@ -70,7 +72,10 @@ public class VCardParser_V21 extends VCardParser { /** The builder to build parsed data */ protected VCardBuilder mBuilder = null; - /** The encoding type */ + /** + * 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"; @@ -88,17 +93,17 @@ public class VCardParser_V21 extends VCardParser { // Just for debugging private long mTimeTotal; - private long mTimeStartRecord; - private long mTimeEndRecord; + private long mTimeReadStartRecord; + private long mTimeReadEndRecord; private long mTimeStartProperty; private long mTimeEndProperty; private long mTimeParseItems; - private long mTimeParseItem1; - private long mTimeParseItem2; - private long mTimeParseItem3; - private long mTimeHandlePropertyValue1; - private long mTimeHandlePropertyValue2; - private long mTimeHandlePropertyValue3; + private long mTimeParseLineAndHandleGroup; + private long mTimeParsePropertyValues; + private long mTimeParseAdrOrgN; + private long mTimeHandleMiscPropertyValue; + private long mTimeHandleQuotedPrintable; + private long mTimeHandleBase64; /** * Create a new VCard parser. @@ -213,7 +218,7 @@ public class VCardParser_V21 extends VCardParser { if (mBuilder != null) { start = System.currentTimeMillis(); mBuilder.startRecord("VCARD"); - mTimeStartRecord += System.currentTimeMillis() - start; + mTimeReadStartRecord += System.currentTimeMillis() - start; } start = System.currentTimeMillis(); parseItems(); @@ -222,7 +227,7 @@ public class VCardParser_V21 extends VCardParser { if (mBuilder != null) { start = System.currentTimeMillis(); mBuilder.endRecord(); - mTimeEndRecord += System.currentTimeMillis() - start; + mTimeReadEndRecord += System.currentTimeMillis() - start; } return true; } @@ -250,26 +255,6 @@ public class VCardParser_V21 extends VCardParser { // Though vCard 2.1/3.0 specification does not allow lower cases, // some data may have them, so we allow it (Actually, previous code // had explicitly allowed "BEGIN:vCard" though there's no example). - // - // TODO: ignore non vCard entry (e.g. vcalendar). - // XXX: Not sure, but according to VDataBuilder.java, vcalendar - // entry - // may be nested. Just seeking "END:SOMETHING" may not be enough. - // e.g. - // BEGIN:VCARD - // ... (Valid. Must parse this) - // END:VCARD - // BEGIN:VSOMETHING - // ... (Must ignore this) - // BEGIN:VSOMETHING2 - // ... (Must ignore this) - // END:VSOMETHING2 - // ... (Must ignore this!) - // END:VSOMETHING - // BEGIN:VCARD - // ... (Valid. Must parse this) - // END:VCARD - // INVALID_STRING (VCardException should be thrown) if (length == 2 && strArray[0].trim().equalsIgnoreCase("BEGIN") && strArray[1].trim().equalsIgnoreCase("VCARD")) { @@ -367,11 +352,11 @@ public class VCardParser_V21 extends VCardParser { } /** - * 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 + * 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; @@ -389,14 +374,13 @@ public class VCardParser_V21 extends VCardParser { String propertyName = propertyNameAndValue[0].toUpperCase(); String propertyValue = propertyNameAndValue[1]; - mTimeParseItem1 += System.currentTimeMillis() - start; + mTimeParseLineAndHandleGroup += System.currentTimeMillis() - start; - if (propertyName.equals("ADR") || - propertyName.equals("ORG") || + if (propertyName.equals("ADR") || propertyName.equals("ORG") || propertyName.equals("N")) { start = System.currentTimeMillis(); handleMultiplePropertyValue(propertyName, propertyValue); - mTimeParseItem3 += System.currentTimeMillis() - start; + mTimeParseAdrOrgN += System.currentTimeMillis() - start; return false; } else if (propertyName.equals("AGENT")) { handleAgent(propertyValue); @@ -408,14 +392,13 @@ public class VCardParser_V21 extends VCardParser { } else { throw new VCardException("Unknown BEGIN type: " + propertyValue); } - } else if (propertyName.equals("VERSION") && - !propertyValue.equals(getVersion())) { + } else if (propertyName.equals("VERSION") && !propertyValue.equals(getVersion())) { throw new VCardVersionException("Incompatible version: " + propertyValue + " != " + getVersion()); } start = System.currentTimeMillis(); handlePropertyValue(propertyName, propertyValue); - mTimeParseItem2 += System.currentTimeMillis() - start; + mTimeParsePropertyValues += System.currentTimeMillis() - start; return false; } @@ -542,7 +525,7 @@ public class VCardParser_V21 extends VCardParser { } /** - * ptypeval = knowntype / "X-" word + * ptypeval = knowntype / "X-" word */ protected void handleType(String ptypeval) { String upperTypeValue = ptypeval; @@ -637,8 +620,7 @@ public class VCardParser_V21 extends VCardParser { } } - protected void handlePropertyValue( - String propertyName, String propertyValue) throws + protected void handlePropertyValue(String propertyName, String propertyValue) throws IOException, VCardException { if (mEncoding.equalsIgnoreCase("QUOTED-PRINTABLE")) { long start = System.currentTimeMillis(); @@ -648,7 +630,7 @@ public class VCardParser_V21 extends VCardParser { v.add(result); mBuilder.propertyValues(v); } - mTimeHandlePropertyValue2 += System.currentTimeMillis() - start; + mTimeHandleQuotedPrintable += System.currentTimeMillis() - start; } else if (mEncoding.equalsIgnoreCase("BASE64") || mEncoding.equalsIgnoreCase("B")) { long start = System.currentTimeMillis(); @@ -667,7 +649,7 @@ public class VCardParser_V21 extends VCardParser { mBuilder.propertyValues(null); } } - mTimeHandlePropertyValue3 += System.currentTimeMillis() - start; + mTimeHandleBase64 += System.currentTimeMillis() - start; } else { if (!(mEncoding == null || mEncoding.equalsIgnoreCase("7BIT") || mEncoding.equalsIgnoreCase("8BIT") @@ -681,7 +663,7 @@ public class VCardParser_V21 extends VCardParser { v.add(maybeUnescapeText(propertyValue)); mBuilder.propertyValues(v); } - mTimeHandlePropertyValue1 += System.currentTimeMillis() - start; + mTimeHandleMiscPropertyValue += System.currentTimeMillis() - start; } } @@ -770,15 +752,15 @@ public class VCardParser_V21 extends VCardParser { * 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 data have it. + 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) { - // TODO: limit should be set in accordance with propertyName? StringBuilder builder = new StringBuilder(); ArrayList<String> list = new ArrayList<String>(); int length = propertyValue.length(); @@ -786,7 +768,7 @@ public class VCardParser_V21 extends VCardParser { char ch = propertyValue.charAt(i); if (ch == '\\' && i < length - 1) { char nextCh = propertyValue.charAt(i + 1); - String unescapedString = maybeUnescape(nextCh); + String unescapedString = maybeUnescapeCharacter(nextCh); if (unescapedString != null) { builder.append(unescapedString); i++; @@ -819,7 +801,6 @@ public class VCardParser_V21 extends VCardParser { throw new VCardNotSupportedException("AGENT Property is not supported now."); /* This is insufficient support. Also, AGENT Property is very rare. Ignore it for now. - TODO: fix this. String[] strArray = propertyValue.split(":", 2); if (!(strArray.length == 2 || @@ -843,7 +824,7 @@ public class VCardParser_V21 extends VCardParser { * 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 maybeUnescape(char ch) { + protected String maybeUnescapeCharacter(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. @@ -863,17 +844,11 @@ public class VCardParser_V21 extends VCardParser { @Override public boolean parse(InputStream is, String charset, VCardBuilder builder) throws IOException, VCardException { - // TODO: make this count error entries instead of just throwing VCardException. - - { - // TODO: If we really need to allow only CRLF as line break, - // we will have to develop our own BufferedReader(). - final InputStreamReader tmpReader = new InputStreamReader(is, charset); - if (VCardConfig.showPerformanceLog()) { - mReader = new CustomBufferedReader(tmpReader); - } else { - mReader = new BufferedReader(tmpReader); - } + final InputStreamReader tmpReader = new InputStreamReader(is, charset); + if (VCardConfig.showPerformanceLog()) { + mReader = new CustomBufferedReader(tmpReader); + } else { + mReader = new BufferedReader(tmpReader); } mBuilder = builder; @@ -903,21 +878,26 @@ public class VCardParser_V21 extends VCardParser { } private void showPerformanceInfo() { - Log.d(LOG_TAG, "total parsing time: " + mTimeTotal + " ms"); + Log.d(LOG_TAG, "Total parsing time: " + mTimeTotal + " ms"); if (mReader instanceof CustomBufferedReader) { - Log.d(LOG_TAG, "total readLine time: " + + Log.d(LOG_TAG, "Total readLine time: " + ((CustomBufferedReader)mReader).getTotalmillisecond() + " ms"); } - Log.d(LOG_TAG, "mTimeStartRecord: " + mTimeStartRecord + " ms"); - Log.d(LOG_TAG, "mTimeEndRecord: " + mTimeEndRecord + " ms"); - Log.d(LOG_TAG, "mTimeParseItem1: " + mTimeParseItem1 + " ms"); - Log.d(LOG_TAG, "mTimeParseItem2: " + mTimeParseItem2 + " ms"); - Log.d(LOG_TAG, "mTimeParseItem3: " + mTimeParseItem3 + " ms"); - Log.d(LOG_TAG, "mTimeHandlePropertyValue1: " + mTimeHandlePropertyValue1 + " ms"); - Log.d(LOG_TAG, "mTimeHandlePropertyValue2: " + mTimeHandlePropertyValue2 + " ms"); - Log.d(LOG_TAG, "mTimeHandlePropertyValue3: " + mTimeHandlePropertyValue3 + " 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; diff --git a/core/java/android/pim/vcard/VCardParser_V30.java b/core/java/android/pim/vcard/VCardParser_V30.java index 634d9f5..475be4e 100644 --- a/core/java/android/pim/vcard/VCardParser_V30.java +++ b/core/java/android/pim/vcard/VCardParser_V30.java @@ -27,7 +27,7 @@ import java.util.HashSet; * 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 String LOG_TAG = "vcard.VCardParser_V30"; private static final HashSet<String> sAcceptablePropsWithParam = new HashSet<String>( Arrays.asList( @@ -49,7 +49,7 @@ public class VCardParser_V30 extends VCardParser_V21 { @Override protected String getVersion() { - return "3.0"; + return Constants.VERSION_V30; } @Override @@ -284,7 +284,7 @@ public class VCardParser_V30 extends VCardParser_V21 { if (ch == '\\' && i < length - 1) { char next_ch = text.charAt(++i); if (next_ch == 'n' || next_ch == 'N') { - builder.append("\r\n"); + builder.append("\n"); } else { builder.append(next_ch); } @@ -296,9 +296,9 @@ public class VCardParser_V30 extends VCardParser_V21 { } @Override - protected String maybeUnescape(char ch) { + protected String maybeUnescapeCharacter(char ch) { if (ch == 'n' || ch == 'N') { - return "\r\n"; + return "\n"; } else { return String.valueOf(ch); } diff --git a/core/java/android/pim/vcard/VCardUtils.java b/core/java/android/pim/vcard/VCardUtils.java new file mode 100644 index 0000000..b7b706f --- /dev/null +++ b/core/java/android/pim/vcard/VCardUtils.java @@ -0,0 +1,764 @@ +/* + * 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.ContentValues; +import android.provider.ContactsContract.Data; +import android.provider.ContactsContract.CommonDataKinds.Phone; +import android.provider.ContactsContract.CommonDataKinds.StructuredPostal; +import android.text.TextUtils; + +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * Utilities for VCard handling codes. + */ +public class VCardUtils { + /* + * TODO: some of methods in this class should be placed to the more appropriate place... + */ + + // Note that not all types are included in this map/set, since, for example, TYPE_HOME_FAX is + // converted to two attribute 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> sPhoneTypesSetUnknownToContacts; + + private static final Map<String, Integer> sKnownPhoneTypesMap_StoI; + + static { + sKnownPhoneTypesMap_ItoS = new HashMap<Integer, String>(); + sKnownPhoneTypesMap_StoI = new HashMap<String, Integer>(); + + sKnownPhoneTypesMap_ItoS.put(Phone.TYPE_CAR, Constants.ATTR_TYPE_CAR); + sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_CAR, Phone.TYPE_CAR); + sKnownPhoneTypesMap_ItoS.put(Phone.TYPE_PAGER, Constants.ATTR_TYPE_PAGER); + sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_PAGER, Phone.TYPE_PAGER); + sKnownPhoneTypesMap_ItoS.put(Phone.TYPE_ISDN, Constants.ATTR_TYPE_ISDN); + sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_ISDN, Phone.TYPE_ISDN); + + sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_HOME, Phone.TYPE_HOME); + sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_WORK, Phone.TYPE_WORK); + sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_CELL, Phone.TYPE_MOBILE); + + sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_PHONE_EXTRA_OTHER, Phone.TYPE_OTHER); + sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_PHONE_EXTRA_CALLBACK, Phone.TYPE_CALLBACK); + sKnownPhoneTypesMap_StoI.put( + Constants.ATTR_TYPE_PHONE_EXTRA_COMPANY_MAIN, Phone.TYPE_COMPANY_MAIN); + sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_PHONE_EXTRA_RADIO, Phone.TYPE_RADIO); + sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_PHONE_EXTRA_TELEX, Phone.TYPE_TELEX); + sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_PHONE_EXTRA_TTY_TDD, Phone.TYPE_TTY_TDD); + sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_PHONE_EXTRA_ASSISTANT, Phone.TYPE_ASSISTANT); + + sPhoneTypesSetUnknownToContacts = new HashSet<String>(); + sPhoneTypesSetUnknownToContacts.add(Constants.ATTR_TYPE_MODEM); + sPhoneTypesSetUnknownToContacts.add(Constants.ATTR_TYPE_MSG); + sPhoneTypesSetUnknownToContacts.add(Constants.ATTR_TYPE_BBS); + sPhoneTypesSetUnknownToContacts.add(Constants.ATTR_TYPE_VIDEO); + } + + public static String getPhoneAttributeString(int 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) { + int type = -1; + String label = null; + boolean isFax = false; + boolean hasPref = false; + + if (types != null) { + for (String typeString : types) { + typeString = typeString.toUpperCase(); + if (typeString.equals(Constants.ATTR_TYPE_PREF)) { + hasPref = true; + } else if (typeString.equals(Constants.ATTR_TYPE_FAX)) { + isFax = true; + } else { + if (typeString.startsWith("X-") && type < 0) { + typeString = typeString.substring(2); + } + Integer tmp = sKnownPhoneTypesMap_StoI.get(typeString); + if (tmp != null) { + 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; + } + } + + public static boolean isValidPhoneAttribute(String phoneAttribute, int vcardType) { + // TODO: check the following. + // - it may violate vCard spec + // - it may contain non-ASCII characters + // + // TODO: use vcardType + return (phoneAttribute.startsWith("X-") || phoneAttribute.startsWith("x-") || + sPhoneTypesSetUnknownToContacts.contains(phoneAttribute)); + } + + public static String[] sortNameElements(int vcardType, + String familyName, String middleName, String givenName) { + String[] list = new String[3]; + switch (VCardConfig.getNameOrderType(vcardType)) { + case VCardConfig.NAME_ORDER_JAPANESE: + // TODO: Should handle Ascii case? + 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; + } + + /** + * 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. See also + * {{@link #getVCardPostalElements(ContentValues)} + */ + public static void insertStructuredPostalDataUsingContactsStruct(int vcardType, + final ContentProviderOperation.Builder builder, + final ContactStruct.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); + } + + builder.withValue(StructuredPostal.POBOX, postalData.pobox); + // Extended address is dropped since there's no relevant entry in ContactsContract. + builder.withValue(StructuredPostal.STREET, postalData.street); + 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); + } + } + + /** + * Returns String[] containing address information based on vCard spec + * (PO Box, Extended Address, Street, Locality, Region, Postal Code, Country Name). + * All String objects are non-null ("" is used when the relevant data is empty). + * + * Note that the data structure of ContactsContract is different from that defined in vCard. + * So some conversion may be performed in this method. See also + * {{@link #insertStructuredPostalDataUsingContactsStruct(int, + * android.content.ContentProviderOperation.Builder, + * android.pim.vcard.ContactStruct.PostalData)} + */ + public static String[] getVCardPostalElements(ContentValues contentValues) { + String[] dataArray = new String[7]; + dataArray[0] = contentValues.getAsString(StructuredPostal.POBOX); + if (dataArray[0] == null) { + dataArray[0] = ""; + } + // Extended addr. There's no relevant data in ContactsContract. + dataArray[1] = ""; + dataArray[2] = contentValues.getAsString(StructuredPostal.STREET); + if (dataArray[2] == null) { + dataArray[2] = ""; + } + // Assume that localty == city + dataArray[3] = contentValues.getAsString(StructuredPostal.CITY); + if (dataArray[3] == null) { + dataArray[3] = ""; + } + String region = contentValues.getAsString(StructuredPostal.REGION); + if (!TextUtils.isEmpty(region)) { + dataArray[4] = region; + } else { + dataArray[4] = ""; + } + dataArray[5] = contentValues.getAsString(StructuredPostal.POSTCODE); + if (dataArray[5] == null) { + dataArray[5] = ""; + } + dataArray[6] = contentValues.getAsString(StructuredPostal.COUNTRY); + if (dataArray[6] == null) { + dataArray[6] = ""; + } + + return dataArray; + } + + public static String constructNameFromElements(int nameOrderType, + String familyName, String middleName, String givenName) { + return constructNameFromElements(nameOrderType, familyName, middleName, givenName, + null, null); + } + + public static String constructNameFromElements(int nameOrderType, + String familyName, String middleName, String givenName, + String prefix, String suffix) { + StringBuilder builder = new StringBuilder(); + String[] nameList = sortNameElements(nameOrderType, + familyName, middleName, givenName); + boolean first = true; + if (!TextUtils.isEmpty(prefix)) { + first = false; + builder.append(prefix); + } + for (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 boolean containsOnlyAscii(String str) { + if (TextUtils.isEmpty(str)) { + return true; + } + + final int length = str.length(); + final int asciiFirst = 0x20; + final int asciiLast = 0x126; + for (int i = 0; i < length; i = str.offsetByCodePoints(i, 1)) { + int c = str.codePointAt(i); + if (c < asciiFirst || asciiLast < c) { + return false; + } + } + return true; + } + + /** + * 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 appreciate + * 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(String str) { + if (TextUtils.isEmpty(str)) { + return true; + } + + final int lowerAlphabetFirst = 0x41; // included ('A') + final int lowerAlphabetLast = 0x5b; // not included ('[') + final int upperAlphabetFirst = 0x61; // included ('a') + final int upperAlphabetLast = 0x7b; // included ('{') + final int digitFirst = 0x30; // included ('0') + final int digitLast = 0x39; // included ('9') + final int hyphen = '-'; + 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 < lowerAlphabetLast) || + (upperAlphabetFirst <= codepoint && codepoint < upperAlphabetLast) || + (digitFirst <= codepoint && codepoint < digitLast) || + (codepoint == hyphen))) { + return false; + } + } + return true; + } + + // TODO: Replace wth the method in Base64 class. + private static char PAD = '='; + private static final char[] ENCODE64 = { + 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', + 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f', + 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v', + 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/' + }; + + static public String encodeBase64(byte[] data) { + if (data == null) { + return ""; + } + + char[] charBuffer = new char[(data.length + 2) / 3 * 4]; + int position = 0; + int _3byte = 0; + for (int i=0; i<data.length-2; i+=3) { + _3byte = ((data[i] & 0xFF) << 16) + ((data[i+1] & 0xFF) << 8) + (data[i+2] & 0xFF); + charBuffer[position++] = ENCODE64[_3byte >> 18]; + charBuffer[position++] = ENCODE64[(_3byte >> 12) & 0x3F]; + charBuffer[position++] = ENCODE64[(_3byte >> 6) & 0x3F]; + charBuffer[position++] = ENCODE64[_3byte & 0x3F]; + } + switch(data.length % 3) { + case 1: // [111111][11 0000][0000 00][000000] + _3byte = ((data[data.length-1] & 0xFF) << 16); + charBuffer[position++] = ENCODE64[_3byte >> 18]; + charBuffer[position++] = ENCODE64[(_3byte >> 12) & 0x3F]; + charBuffer[position++] = PAD; + charBuffer[position++] = PAD; + break; + case 2: // [111111][11 1111][1111 00][000000] + _3byte = ((data[data.length-2] & 0xFF) << 16) + ((data[data.length-1] & 0xFF) << 8); + charBuffer[position++] = ENCODE64[_3byte >> 18]; + charBuffer[position++] = ENCODE64[(_3byte >> 12) & 0x3F]; + charBuffer[position++] = ENCODE64[(_3byte >> 6) & 0x3F]; + charBuffer[position++] = PAD; + break; + } + + return new String(charBuffer); + } + + static public String toHalfWidthString(String orgString) { + if (TextUtils.isEmpty(orgString)) { + return null; + } + StringBuilder builder = new StringBuilder(); + int length = orgString.length(); + for (int i = 0; i < length; i++) { + // All Japanese character is able to be expressed by char. + // Do not need to use String#codepPointAt(). + char ch = orgString.charAt(i); + CharSequence halfWidthText = JapaneseUtils.tryGetHalfWidthText(ch); + if (halfWidthText != null) { + builder.append(halfWidthText); + } else { + builder.append(ch); + } + } + return builder.toString(); + } + + private VCardUtils() { + } +} + +/** + * TextUtils especially for Japanese. + * TODO: make this in android.text in the future + */ +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 CharSequence tryGetHalfWidthText(char ch) { + if (sHalfWidthMap.containsKey(ch)) { + return sHalfWidthMap.get(ch); + } else { + return null; + } + } +}
\ No newline at end of file diff --git a/core/java/android/preference/VolumePreference.java b/core/java/android/preference/VolumePreference.java index db25cfa..46cce52 100644 --- a/core/java/android/preference/VolumePreference.java +++ b/core/java/android/preference/VolumePreference.java @@ -16,15 +16,17 @@ package android.preference; +import android.app.Dialog; import android.content.Context; import android.content.res.TypedArray; import android.database.ContentObserver; +import android.media.AudioManager; import android.media.Ringtone; import android.media.RingtoneManager; -import android.media.AudioManager; import android.net.Uri; import android.os.Handler; -import android.preference.PreferenceManager; +import android.os.Parcel; +import android.os.Parcelable; import android.provider.Settings; import android.provider.Settings.System; import android.util.AttributeSet; @@ -42,7 +44,7 @@ public class VolumePreference extends SeekBarPreference implements private static final String TAG = "VolumePreference"; private int mStreamType; - + /** May be null if the dialog isn't visible. */ private SeekBarVolumizer mSeekBarVolumizer; @@ -54,7 +56,7 @@ public class VolumePreference extends SeekBarPreference implements mStreamType = a.getInt(android.R.styleable.VolumePreference_streamType, 0); a.recycle(); } - + public void setStreamType(int streamType) { mStreamType = streamType; } @@ -65,7 +67,7 @@ public class VolumePreference extends SeekBarPreference implements final SeekBar seekBar = (SeekBar) view.findViewById(com.android.internal.R.id.seekbar); mSeekBarVolumizer = new SeekBarVolumizer(getContext(), seekBar, mStreamType); - + getPreferenceManager().registerOnActivityStopListener(this); // grab focus and key events so that pressing the volume buttons in the @@ -100,7 +102,7 @@ public class VolumePreference extends SeekBarPreference implements if (!positiveResult && mSeekBarVolumizer != null) { mSeekBarVolumizer.revertVolume(); } - + cleanup(); } @@ -113,19 +115,96 @@ public class VolumePreference extends SeekBarPreference implements */ private void cleanup() { getPreferenceManager().unregisterOnActivityStopListener(this); - + if (mSeekBarVolumizer != null) { + Dialog dialog = getDialog(); + if (dialog != null && dialog.isShowing()) { + // Stopped while dialog was showing, revert changes + mSeekBarVolumizer.revertVolume(); + } mSeekBarVolumizer.stop(); mSeekBarVolumizer = null; } + } - + protected void onSampleStarting(SeekBarVolumizer volumizer) { if (mSeekBarVolumizer != null && volumizer != mSeekBarVolumizer) { mSeekBarVolumizer.stopSample(); } } - + + @Override + protected Parcelable onSaveInstanceState() { + final Parcelable superState = super.onSaveInstanceState(); + if (isPersistent()) { + // No need to save instance state since it's persistent + return superState; + } + + final SavedState myState = new SavedState(superState); + if (mSeekBarVolumizer != null) { + mSeekBarVolumizer.onSaveInstanceState(myState.getVolumeStore()); + } + return myState; + } + + @Override + protected void onRestoreInstanceState(Parcelable state) { + if (state == null || !state.getClass().equals(SavedState.class)) { + // Didn't save state for us in onSaveInstanceState + super.onRestoreInstanceState(state); + return; + } + + SavedState myState = (SavedState) state; + super.onRestoreInstanceState(myState.getSuperState()); + if (mSeekBarVolumizer != null) { + mSeekBarVolumizer.onRestoreInstanceState(myState.getVolumeStore()); + } + } + + public static class VolumeStore { + public int volume = -1; + public int originalVolume = -1; + } + + private static class SavedState extends BaseSavedState { + VolumeStore mVolumeStore = new VolumeStore(); + + public SavedState(Parcel source) { + super(source); + mVolumeStore.volume = source.readInt(); + mVolumeStore.originalVolume = source.readInt(); + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeInt(mVolumeStore.volume); + dest.writeInt(mVolumeStore.originalVolume); + } + + VolumeStore getVolumeStore() { + return mVolumeStore; + } + + public SavedState(Parcelable superState) { + super(superState); + } + + 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]; + } + }; + } + /** * Turns a {@link SeekBar} into a volume control. */ @@ -139,7 +218,7 @@ public class VolumePreference extends SeekBarPreference implements private int mOriginalStreamVolume; private Ringtone mRingtone; - private int mLastProgress; + private int mLastProgress = -1; private SeekBar mSeekBar; private ContentObserver mVolumeObserver = new ContentObserver(mHandler) { @@ -153,7 +232,7 @@ public class VolumePreference extends SeekBarPreference implements } } }; - + public SeekBarVolumizer(Context context, SeekBar seekBar, int streamType) { mContext = context; mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); @@ -207,7 +286,7 @@ public class VolumePreference extends SeekBarPreference implements postSetVolume(progress); } - private void postSetVolume(int progress) { + void postSetVolume(int progress) { // Do the volume changing separately to give responsive UI mLastProgress = progress; mHandler.removeCallbacks(this); @@ -249,5 +328,20 @@ public class VolumePreference extends SeekBarPreference implements } postSetVolume(mSeekBar.getProgress()); } + + public void onSaveInstanceState(VolumeStore volumeStore) { + if (mLastProgress >= 0) { + volumeStore.volume = mLastProgress; + volumeStore.originalVolume = mOriginalStreamVolume; + } + } + + public void onRestoreInstanceState(VolumeStore volumeStore) { + if (volumeStore.volume != -1) { + mOriginalStreamVolume = volumeStore.originalVolume; + mLastProgress = volumeStore.volume; + postSetVolume(mLastProgress); + } + } } } diff --git a/core/java/android/provider/Contacts.java b/core/java/android/provider/Contacts.java index c0dbf4d..181a529 100644 --- a/core/java/android/provider/Contacts.java +++ b/core/java/android/provider/Contacts.java @@ -22,15 +22,14 @@ import android.content.ContentResolver; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; -import android.content.Intent; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; +import android.os.Build; import android.text.TextUtils; import android.util.Log; import android.widget.ImageView; -import android.accounts.Account; import java.io.ByteArrayInputStream; import java.io.InputStream; @@ -38,26 +37,34 @@ import java.io.InputStream; /** * The Contacts provider stores all information about contacts. */ +@Deprecated public class Contacts { private static final String TAG = "Contacts"; + @Deprecated public static final String AUTHORITY = "contacts"; /** * The content:// style URL for this provider */ + @Deprecated public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY); /** Signifies an email address row that is stored in the ContactMethods table */ + @Deprecated public static final int KIND_EMAIL = 1; /** Signifies a postal address row that is stored in the ContactMethods table */ + @Deprecated public static final int KIND_POSTAL = 2; /** Signifies an IM address row that is stored in the ContactMethods table */ + @Deprecated public static final int KIND_IM = 3; /** Signifies an Organization row that is stored in the Organizations table */ + @Deprecated public static final int KIND_ORGANIZATION = 4; /** Signifies an Phone row that is stored in the Phones table */ + @Deprecated public static final int KIND_PHONE = 5; /** @@ -68,35 +75,41 @@ public class Contacts { /** * Columns from the Settings table that other columns join into themselves. */ + @Deprecated public interface SettingsColumns { /** * The _SYNC_ACCOUNT to which this setting corresponds. This may be null. * <P>Type: TEXT</P> */ + @Deprecated public static final String _SYNC_ACCOUNT = "_sync_account"; /** * The _SYNC_ACCOUNT_TYPE to which this setting corresponds. This may be null. * <P>Type: TEXT</P> */ + @Deprecated public static final String _SYNC_ACCOUNT_TYPE = "_sync_account_type"; /** * The key of this setting. * <P>Type: TEXT</P> */ + @Deprecated public static final String KEY = "key"; /** * The value of this setting. * <P>Type: TEXT</P> */ + @Deprecated public static final String VALUE = "value"; } /** * The settings over all of the people */ + @Deprecated public static final class Settings implements BaseColumns, SettingsColumns { /** * no public constructor since this is a utility class @@ -106,17 +119,20 @@ public class Contacts { /** * The content:// style URL for this table */ + @Deprecated public static final Uri CONTENT_URI = Uri.parse("content://contacts/settings"); /** * The directory twig for this sub-table */ + @Deprecated public static final String CONTENT_DIRECTORY = "settings"; /** * The default sort order for this table */ + @Deprecated public static final String DEFAULT_SORT_ORDER = "key ASC"; /** @@ -128,8 +144,10 @@ public class Contacts { * This is a boolean setting. It is true if it is set and it is anything other than the * emptry string or "0". */ + @Deprecated public static final String SYNC_EVERYTHING = "syncEverything"; + @Deprecated public static String getSetting(ContentResolver cr, String account, String key) { // For now we only support a single account and the UI doesn't know what // the account name is, so we're using a global setting for SYNC_EVERYTHING. @@ -159,6 +177,7 @@ public class Contacts { } } + @Deprecated public static void setSetting(ContentResolver cr, String account, String key, String value) { ContentValues values = new ContentValues(); @@ -177,11 +196,13 @@ public class Contacts { /** * Columns from the People table that other tables join into themselves. */ + @Deprecated public interface PeopleColumns { /** * The person's name. * <P>Type: TEXT</P> */ + @Deprecated public static final String NAME = "name"; /** @@ -190,6 +211,7 @@ public class Contacts { * Used for pronunciation and/or collation in some languages. * <p>Type: TEXT</P> */ + @Deprecated public static final String PHONETIC_NAME = "phonetic_name"; /** @@ -197,6 +219,7 @@ public class Contacts { * else if email is not null email. * <P>Type: TEXT</P> */ + @Deprecated public static final String DISPLAY_NAME = "display_name"; /** @@ -205,30 +228,35 @@ public class Contacts { * <P>Type: TEXT</p> * @hide Used only in Contacts application for now. */ + @Deprecated public static final String SORT_STRING = "sort_string"; /** * Notes about the person. * <P>Type: TEXT</P> */ + @Deprecated public static final String NOTES = "notes"; /** * The number of times a person has been contacted * <P>Type: INTEGER</P> */ + @Deprecated public static final String TIMES_CONTACTED = "times_contacted"; /** * The last time a person was contacted. * <P>Type: INTEGER</P> */ + @Deprecated public static final String LAST_TIME_CONTACTED = "last_time_contacted"; /** * A custom ringtone associated with a person. Not always present. * <P>Type: TEXT (URI to the ringtone)</P> */ + @Deprecated public static final String CUSTOM_RINGTONE = "custom_ringtone"; /** @@ -236,24 +264,28 @@ public class Contacts { * present. * <P>Type: INTEGER (0 for false, 1 for true)</P> */ + @Deprecated public static final String SEND_TO_VOICEMAIL = "send_to_voicemail"; /** * Is the contact starred? * <P>Type: INTEGER (boolean)</P> */ + @Deprecated public static final String STARRED = "starred"; /** * The server version of the photo * <P>Type: TEXT (the version number portion of the photo URI)</P> */ + @Deprecated public static final String PHOTO_VERSION = "photo_version"; } /** * This table contains people. */ + @Deprecated public static final class People implements BaseColumns, SyncConstValue, PeopleColumns, PhonesColumns, PresenceColumns { /** @@ -264,6 +296,7 @@ public class Contacts { /** * The content:// style URL for this table */ + @Deprecated public static final Uri CONTENT_URI = Uri.parse("content://contacts/people"); @@ -271,6 +304,7 @@ public class Contacts { * The content:// style URL for filtering people by name. The filter * argument should be passed as an additional path segment after this URI. */ + @Deprecated public static final Uri CONTENT_FILTER_URI = Uri.parse("content://contacts/people/filter"); @@ -278,6 +312,7 @@ public class Contacts { * The content:// style URL for the table that holds the deleted * contacts. */ + @Deprecated public static final Uri DELETED_CONTENT_URI = Uri.parse("content://contacts/deleted_people"); @@ -292,6 +327,7 @@ public class Contacts { * schema and do not want to have to support this. * @hide */ + @Deprecated public static final Uri WITH_EMAIL_OR_IM_FILTER_URI = Uri.parse("content://contacts/people/with_email_or_im_filter"); @@ -299,23 +335,27 @@ public class Contacts { * The MIME type of {@link #CONTENT_URI} providing a directory of * people. */ + @Deprecated public static final String CONTENT_TYPE = "vnd.android.cursor.dir/person"; /** * The MIME type of a {@link #CONTENT_URI} subdirectory of a single * person. */ + @Deprecated public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/person"; /** * The default sort order for this table */ + @Deprecated public static final String DEFAULT_SORT_ORDER = People.NAME + " ASC"; /** * The ID of the persons preferred phone number. * <P>Type: INTEGER (foreign key to phones table on the _ID field)</P> */ + @Deprecated public static final String PRIMARY_PHONE_ID = "primary_phone"; /** @@ -323,6 +363,7 @@ public class Contacts { * <P>Type: INTEGER (foreign key to contact_methods table on the * _ID field)</P> */ + @Deprecated public static final String PRIMARY_EMAIL_ID = "primary_email"; /** @@ -330,6 +371,7 @@ public class Contacts { * <P>Type: INTEGER (foreign key to organizations table on the * _ID field)</P> */ + @Deprecated public static final String PRIMARY_ORGANIZATION_ID = "primary_organization"; /** @@ -338,6 +380,7 @@ public class Contacts { * @param resolver the ContentResolver to use * @param personId the person who was contacted */ + @Deprecated public static void markAsContacted(ContentResolver resolver, long personId) { Uri uri = ContentUris.withAppendedId(CONTENT_URI, personId); uri = Uri.withAppendedPath(uri, "update_contact_time"); @@ -351,6 +394,7 @@ public class Contacts { /** * @hide Used in vCard parser code. */ + @Deprecated public static long tryGetMyContactsGroupId(ContentResolver resolver) { Cursor groupsCursor = resolver.query(Groups.CONTENT_URI, GROUPS_PROJECTION, Groups.SYSTEM_ID + "='" + Groups.GROUP_MY_CONTACTS + "'", null, null); @@ -374,6 +418,7 @@ public class Contacts { * @return the URI of the group membership row * @throws IllegalStateException if the My Contacts group can't be found */ + @Deprecated public static Uri addToMyContactsGroup(ContentResolver resolver, long personId) { long groupId = tryGetMyContactsGroupId(resolver); if (groupId == 0) { @@ -392,6 +437,7 @@ public class Contacts { * @return the URI of the group membership row * @throws IllegalStateException if the group can't be found */ + @Deprecated public static Uri addToGroup(ContentResolver resolver, long personId, String groupName) { long groupId = 0; Cursor groupsCursor = resolver.query(Groups.CONTENT_URI, GROUPS_PROJECTION, @@ -421,6 +467,7 @@ public class Contacts { * @param groupId the group to add the person to * @return the URI of the group membership row */ + @Deprecated public static Uri addToGroup(ContentResolver resolver, long personId, long groupId) { ContentValues values = new ContentValues(); values.put(GroupMembership.PERSON_ID, personId); @@ -439,6 +486,7 @@ public class Contacts { * @param values the values to use when creating the contact * @return the URI of the contact, or null if the operation fails */ + @Deprecated public static Uri createPersonInMyContactsGroup(ContentResolver resolver, ContentValues values) { @@ -455,6 +503,7 @@ public class Contacts { return contactUri; } + @Deprecated public static Cursor queryGroups(ContentResolver resolver, long person) { return resolver.query(GroupMembership.CONTENT_URI, null, "person=?", new String[]{String.valueOf(person)}, Groups.DEFAULT_SORT_ORDER); @@ -466,6 +515,7 @@ public class Contacts { * @param person the Uri of the person whose photo is to be updated * @param data the byte[] that represents the photo */ + @Deprecated public static void setPhotoData(ContentResolver cr, Uri person, byte[] data) { Uri photoUri = Uri.withAppendedPath(person, Contacts.Photos.CONTENT_DIRECTORY); ContentValues values = new ContentValues(); @@ -478,6 +528,7 @@ public class Contacts { * If the person's photo isn't present returns the placeholderImageResource instead. * @param person the person whose photo should be used */ + @Deprecated public static InputStream openContactPhotoInputStream(ContentResolver cr, Uri person) { Uri photoUri = Uri.withAppendedPath(person, Contacts.Photos.CONTENT_DIRECTORY); Cursor cursor = cr.query(photoUri, new String[]{Photos.DATA}, null, null, null); @@ -504,6 +555,7 @@ public class Contacts { * have a photo * @param options the decoding options, can be set to null */ + @Deprecated public static Bitmap loadContactPhoto(Context context, Uri person, int placeholderImageResource, BitmapFactory.Options options) { if (person == null) { @@ -530,6 +582,7 @@ public class Contacts { /** * A sub directory of a single person that contains all of their Phones. */ + @Deprecated public static final class Phones implements BaseColumns, PhonesColumns, PeopleColumns { /** @@ -540,11 +593,13 @@ public class Contacts { /** * The directory twig for this sub-table */ + @Deprecated public static final String CONTENT_DIRECTORY = "phones"; /** * The default sort order for this table */ + @Deprecated public static final String DEFAULT_SORT_ORDER = "number ASC"; } @@ -552,6 +607,7 @@ public class Contacts { * A subdirectory of a single person that contains all of their * ContactMethods. */ + @Deprecated public static final class ContactMethods implements BaseColumns, ContactMethodsColumns, PeopleColumns { /** @@ -562,17 +618,20 @@ public class Contacts { /** * The directory twig for this sub-table */ + @Deprecated public static final String CONTENT_DIRECTORY = "contact_methods"; /** * The default sort order for this table */ + @Deprecated public static final String DEFAULT_SORT_ORDER = "data ASC"; } /** * The extensions for a person */ + @Deprecated public static class Extensions implements BaseColumns, ExtensionsColumns { /** * no public constructor since this is a utility class @@ -582,17 +641,20 @@ public class Contacts { /** * The directory twig for this sub-table */ + @Deprecated public static final String CONTENT_DIRECTORY = "extensions"; /** * The default sort order for this table */ + @Deprecated public static final String DEFAULT_SORT_ORDER = "name ASC"; /** * The ID of the person this phone number is assigned to. * <P>Type: INTEGER (long)</P> */ + @Deprecated public static final String PERSON_ID = "person"; } } @@ -600,17 +662,20 @@ public class Contacts { /** * Columns from the groups table. */ + @Deprecated public interface GroupsColumns { /** * The group name. * <P>Type: TEXT</P> */ + @Deprecated public static final String NAME = "name"; /** * Notes about the group. * <P>Type: TEXT</P> */ + @Deprecated public static final String NOTES = "notes"; /** @@ -618,18 +683,21 @@ public class Contacts { * for this group's account. * <P>Type: INTEGER (boolean)</P> */ + @Deprecated public static final String SHOULD_SYNC = "should_sync"; /** * The ID of this group if it is a System Group, null otherwise. * <P>Type: TEXT</P> */ + @Deprecated public static final String SYSTEM_ID = "system_id"; } /** * This table contains the groups for an account. */ + @Deprecated public static final class Groups implements BaseColumns, SyncConstValue, GroupsColumns { /** @@ -640,6 +708,7 @@ public class Contacts { /** * The content:// style URL for this table */ + @Deprecated public static final Uri CONTENT_URI = Uri.parse("content://contacts/groups"); @@ -647,6 +716,7 @@ public class Contacts { * The content:// style URL for the table that holds the deleted * groups. */ + @Deprecated public static final Uri DELETED_CONTENT_URI = Uri.parse("content://contacts/deleted_groups"); @@ -654,71 +724,90 @@ public class Contacts { * The MIME type of {@link #CONTENT_URI} providing a directory of * groups. */ + @Deprecated public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contactsgroup"; /** * The MIME type of a {@link #CONTENT_URI} subdirectory of a single * group. */ + @Deprecated public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contactsgroup"; /** * The default sort order for this table */ + @Deprecated public static final String DEFAULT_SORT_ORDER = NAME + " ASC"; /** * */ + @Deprecated public static final String GROUP_ANDROID_STARRED = "Starred in Android"; /** * The "My Contacts" system group. */ + @Deprecated public static final String GROUP_MY_CONTACTS = "Contacts"; } /** * Columns from the Phones table that other columns join into themselves. */ + @Deprecated public interface PhonesColumns { /** * The type of the the phone number. * <P>Type: INTEGER (one of the constants below)</P> */ + @Deprecated public static final String TYPE = "type"; + @Deprecated public static final int TYPE_CUSTOM = 0; + @Deprecated public static final int TYPE_HOME = 1; + @Deprecated public static final int TYPE_MOBILE = 2; + @Deprecated public static final int TYPE_WORK = 3; + @Deprecated public static final int TYPE_FAX_WORK = 4; + @Deprecated public static final int TYPE_FAX_HOME = 5; + @Deprecated public static final int TYPE_PAGER = 6; + @Deprecated public static final int TYPE_OTHER = 7; /** * The user provided label for the phone number, only used if TYPE is TYPE_CUSTOM. * <P>Type: TEXT</P> */ + @Deprecated public static final String LABEL = "label"; /** * The phone number as the user entered it. * <P>Type: TEXT</P> */ + @Deprecated public static final String NUMBER = "number"; /** * The normalized phone number * <P>Type: TEXT</P> */ + @Deprecated public static final String NUMBER_KEY = "number_key"; /** * Whether this is the primary phone number * <P>Type: INTEGER (if set, non-0 means true)</P> */ + @Deprecated public static final String ISPRIMARY = "isprimary"; } @@ -727,6 +816,7 @@ public class Contacts { * contact method belongs to. Phone numbers are stored separately from * other contact methods to make caller ID lookup more efficient. */ + @Deprecated public static final class Phones implements BaseColumns, PhonesColumns, PeopleColumns { /** @@ -734,6 +824,7 @@ public class Contacts { */ private Phones() {} + @Deprecated public static final CharSequence getDisplayLabel(Context context, int type, CharSequence label, CharSequence[] labelArray) { CharSequence display = ""; @@ -755,6 +846,7 @@ public class Contacts { return display; } + @Deprecated public static final CharSequence getDisplayLabel(Context context, int type, CharSequence label) { return getDisplayLabel(context, type, label, null); @@ -763,12 +855,14 @@ public class Contacts { /** * The content:// style URL for this table */ + @Deprecated public static final Uri CONTENT_URI = Uri.parse("content://contacts/phones"); /** * The content:// style URL for filtering phone numbers */ + @Deprecated public static final Uri CONTENT_FILTER_URL = Uri.parse("content://contacts/phones/filter"); @@ -776,26 +870,31 @@ public class Contacts { * The MIME type of {@link #CONTENT_URI} providing a directory of * phones. */ + @Deprecated public static final String CONTENT_TYPE = "vnd.android.cursor.dir/phone"; /** * The MIME type of a {@link #CONTENT_URI} subdirectory of a single * phone. */ + @Deprecated public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/phone"; /** * The default sort order for this table */ + @Deprecated public static final String DEFAULT_SORT_ORDER = "name ASC"; /** * The ID of the person this phone number is assigned to. * <P>Type: INTEGER (long)</P> */ + @Deprecated public static final String PERSON_ID = "person"; } + @Deprecated public static final class GroupMembership implements BaseColumns, GroupsColumns { /** * no public constructor since this is a utility class @@ -805,65 +904,77 @@ public class Contacts { /** * The content:// style URL for this table */ + @Deprecated public static final Uri CONTENT_URI = Uri.parse("content://contacts/groupmembership"); /** * The content:// style URL for this table */ + @Deprecated public static final Uri RAW_CONTENT_URI = Uri.parse("content://contacts/groupmembershipraw"); /** * The directory twig for this sub-table */ + @Deprecated public static final String CONTENT_DIRECTORY = "groupmembership"; + /** * The MIME type of {@link #CONTENT_URI} providing a directory of all * person groups. */ + @Deprecated public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contactsgroupmembership"; /** * The MIME type of a {@link #CONTENT_URI} subdirectory of a single * person group. */ + @Deprecated public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contactsgroupmembership"; /** * The default sort order for this table */ + @Deprecated public static final String DEFAULT_SORT_ORDER = "group_id ASC"; /** * The row id of the accounts group. * <P>Type: TEXT</P> */ + @Deprecated public static final String GROUP_ID = "group_id"; /** * The sync id of the group. * <P>Type: TEXT</P> */ + @Deprecated public static final String GROUP_SYNC_ID = "group_sync_id"; /** * The account of the group. * <P>Type: TEXT</P> */ + @Deprecated public static final String GROUP_SYNC_ACCOUNT = "group_sync_account"; /** * The account type of the group. * <P>Type: TEXT</P> */ + @Deprecated public static final String GROUP_SYNC_ACCOUNT_TYPE = "group_sync_account_type"; /** * The row id of the person. * <P>Type: TEXT</P> */ + @Deprecated public static final String PERSON_ID = "person"; } @@ -871,57 +982,70 @@ public class Contacts { * Columns from the ContactMethods table that other tables join into * themseleves. */ + @Deprecated public interface ContactMethodsColumns { /** * The kind of the the contact method. For example, email address, * postal address, etc. * <P>Type: INTEGER (one of the values below)</P> */ + @Deprecated public static final String KIND = "kind"; /** * The type of the contact method, must be one of the types below. * <P>Type: INTEGER (one of the values below)</P> */ + @Deprecated public static final String TYPE = "type"; + @Deprecated public static final int TYPE_CUSTOM = 0; + @Deprecated public static final int TYPE_HOME = 1; + @Deprecated public static final int TYPE_WORK = 2; + @Deprecated public static final int TYPE_OTHER = 3; /** * @hide This is temporal. TYPE_MOBILE should be added to TYPE in the future. */ + @Deprecated public static final int MOBILE_EMAIL_TYPE_INDEX = 2; /** * @hide This is temporal. TYPE_MOBILE should be added to TYPE in the future. * This is not "mobile" but "CELL" since vCard uses it for identifying mobile phone. */ + @Deprecated public static final String MOBILE_EMAIL_TYPE_NAME = "_AUTO_CELL"; /** * The user defined label for the the contact method. * <P>Type: TEXT</P> */ + @Deprecated public static final String LABEL = "label"; /** * The data for the contact method. * <P>Type: TEXT</P> */ + @Deprecated public static final String DATA = "data"; /** * Auxiliary data for the contact method. * <P>Type: TEXT</P> */ + @Deprecated public static final String AUX_DATA = "aux_data"; /** * Whether this is the primary organization * <P>Type: INTEGER (if set, non-0 means true)</P> */ + @Deprecated public static final String ISPRIMARY = "isprimary"; } @@ -929,18 +1053,21 @@ public class Contacts { * This table stores all non-phone contact methods and a reference to the * person that the contact method belongs to. */ + @Deprecated public static final class ContactMethods implements BaseColumns, ContactMethodsColumns, PeopleColumns { /** * The column with latitude data for postal locations * <P>Type: REAL</P> */ + @Deprecated public static final String POSTAL_LOCATION_LATITUDE = DATA; /** * The column with longitude data for postal locations * <P>Type: REAL</P> */ + @Deprecated public static final String POSTAL_LOCATION_LONGITUDE = AUX_DATA; /** @@ -951,23 +1078,34 @@ public class Contacts { * - pre:<an integer, one of the protocols below> * - custom:<a string> */ + @Deprecated public static final int PROTOCOL_AIM = 0; + @Deprecated public static final int PROTOCOL_MSN = 1; + @Deprecated public static final int PROTOCOL_YAHOO = 2; + @Deprecated public static final int PROTOCOL_SKYPE = 3; + @Deprecated public static final int PROTOCOL_QQ = 4; + @Deprecated public static final int PROTOCOL_GOOGLE_TALK = 5; + @Deprecated public static final int PROTOCOL_ICQ = 6; + @Deprecated public static final int PROTOCOL_JABBER = 7; + @Deprecated public static String encodePredefinedImProtocol(int protocol) { return "pre:" + protocol; } + @Deprecated public static String encodeCustomImProtocol(String protocolString) { return "custom:" + protocolString; } + @Deprecated public static Object decodeImProtocol(String encodedString) { if (encodedString == null) { return null; @@ -995,6 +1133,7 @@ public class Contacts { * provider is defined for the given protocol * @hide */ + @Deprecated public static String lookupProviderNameFromId(int protocol) { switch (protocol) { case PROTOCOL_GOOGLE_TALK: @@ -1022,6 +1161,7 @@ public class Contacts { */ private ContactMethods() {} + @Deprecated public static final CharSequence getDisplayLabel(Context context, int kind, int type, CharSequence label) { CharSequence display = ""; @@ -1074,6 +1214,7 @@ public class Contacts { * @param latitude the latitude for the address * @param longitude the longitude for the address */ + @Deprecated public void addPostalLocation(Context context, long postalId, double latitude, double longitude) { final ContentResolver resolver = context.getContentResolver(); @@ -1093,12 +1234,14 @@ public class Contacts { /** * The content:// style URL for this table */ + @Deprecated public static final Uri CONTENT_URI = Uri.parse("content://contacts/contact_methods"); /** * The content:// style URL for sub-directory of e-mail addresses. */ + @Deprecated public static final Uri CONTENT_EMAIL_URI = Uri.parse("content://contacts/contact_methods/email"); @@ -1106,30 +1249,35 @@ public class Contacts { * The MIME type of {@link #CONTENT_URI} providing a directory of * phones. */ + @Deprecated public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contact-methods"; /** * The MIME type of a {@link #CONTENT_EMAIL_URI} sub-directory of\ * multiple {@link Contacts#KIND_EMAIL} entries. */ + @Deprecated public static final String CONTENT_EMAIL_TYPE = "vnd.android.cursor.dir/email"; /** * The MIME type of a {@link #CONTENT_EMAIL_URI} sub-directory of\ * multiple {@link Contacts#KIND_POSTAL} entries. */ + @Deprecated public static final String CONTENT_POSTAL_TYPE = "vnd.android.cursor.dir/postal-address"; /** * The MIME type of a {@link #CONTENT_URI} sub-directory of a single * {@link Contacts#KIND_EMAIL} entry. */ + @Deprecated public static final String CONTENT_EMAIL_ITEM_TYPE = "vnd.android.cursor.item/email"; /** * The MIME type of a {@link #CONTENT_URI} sub-directory of a single * {@link Contacts#KIND_POSTAL} entry. */ + @Deprecated public static final String CONTENT_POSTAL_ITEM_TYPE = "vnd.android.cursor.item/postal-address"; @@ -1137,23 +1285,27 @@ public class Contacts { * The MIME type of a {@link #CONTENT_URI} sub-directory of a single * {@link Contacts#KIND_IM} entry. */ + @Deprecated public static final String CONTENT_IM_ITEM_TYPE = "vnd.android.cursor.item/jabber-im"; /** * The default sort order for this table */ + @Deprecated public static final String DEFAULT_SORT_ORDER = "name ASC"; /** * The ID of the person this contact method is assigned to. * <P>Type: INTEGER (long)</P> */ + @Deprecated public static final String PERSON_ID = "person"; } /** * The IM presence columns with some contacts specific columns mixed in. */ + @Deprecated public interface PresenceColumns extends Im.CommonPresenceColumns { /** * The IM service the presence is coming from. Formatted using either @@ -1161,6 +1313,7 @@ public class Contacts { * {@link Contacts.ContactMethods#encodeCustomImProtocol}. * <P>Type: STRING</P> */ + @Deprecated public static final String IM_PROTOCOL = "im_protocol"; /** @@ -1168,12 +1321,14 @@ public class Contacts { * the {@link #IM_PROTOCOL}. * <P>Type: STRING</P> */ + @Deprecated public static final String IM_HANDLE = "im_handle"; /** * The IM account for the local user that the presence data came from. * <P>Type: STRING</P> */ + @Deprecated public static final String IM_ACCOUNT = "im_account"; } @@ -1181,11 +1336,13 @@ public class Contacts { * Contains presence information about contacts. * @hide */ + @Deprecated public static final class Presence implements BaseColumns, PresenceColumns, PeopleColumns { /** * The content:// style URL for this table */ + @Deprecated public static final Uri CONTENT_URI = Uri.parse("content://contacts/presence"); @@ -1193,6 +1350,7 @@ public class Contacts { * The ID of the person this presence item is assigned to. * <P>Type: INTEGER (long)</P> */ + @Deprecated public static final String PERSON_ID = "person"; /** @@ -1201,6 +1359,7 @@ public class Contacts { * @param status the status to get the icon for * @return the resource ID for the proper presence icon */ + @Deprecated public static final int getPresenceIconResourceId(int status) { switch (status) { case Contacts.People.AVAILABLE: @@ -1228,6 +1387,7 @@ public class Contacts { * @param icon the icon to to set * @param serverStatus that status */ + @Deprecated public static final void setPresenceIcon(ImageView icon, int serverStatus) { icon.setImageResource(getPresenceIconResourceId(serverStatus)); } @@ -1236,57 +1396,69 @@ public class Contacts { /** * Columns from the Organizations table that other columns join into themselves. */ + @Deprecated public interface OrganizationColumns { /** * The type of the organizations. * <P>Type: INTEGER (one of the constants below)</P> */ + @Deprecated public static final String TYPE = "type"; + @Deprecated public static final int TYPE_CUSTOM = 0; + @Deprecated public static final int TYPE_WORK = 1; + @Deprecated public static final int TYPE_OTHER = 2; /** * The user provided label, only used if TYPE is TYPE_CUSTOM. * <P>Type: TEXT</P> */ + @Deprecated public static final String LABEL = "label"; /** * The name of the company for this organization. * <P>Type: TEXT</P> */ + @Deprecated public static final String COMPANY = "company"; /** * The title within this organization. * <P>Type: TEXT</P> */ + @Deprecated public static final String TITLE = "title"; /** * The person this organization is tied to. * <P>Type: TEXT</P> */ + @Deprecated public static final String PERSON_ID = "person"; /** * Whether this is the primary organization * <P>Type: INTEGER (if set, non-0 means true)</P> */ + @Deprecated public static final String ISPRIMARY = "isprimary"; } /** * A sub directory of a single person that contains all of their Phones. */ + @Deprecated public static final class Organizations implements BaseColumns, OrganizationColumns { /** * no public constructor since this is a utility class */ private Organizations() {} + @Deprecated public static final CharSequence getDisplayLabel(Context context, int type, CharSequence label) { CharSequence display = ""; @@ -1310,34 +1482,40 @@ public class Contacts { /** * The content:// style URL for this table */ + @Deprecated public static final Uri CONTENT_URI = Uri.parse("content://contacts/organizations"); /** * The directory twig for this sub-table */ + @Deprecated public static final String CONTENT_DIRECTORY = "organizations"; /** * The default sort order for this table */ + @Deprecated public static final String DEFAULT_SORT_ORDER = "company, title, isprimary ASC"; } /** * Columns from the Photos table that other columns join into themselves. */ + @Deprecated public interface PhotosColumns { /** * The _SYNC_VERSION of the photo that was last downloaded * <P>Type: TEXT</P> */ + @Deprecated public static final String LOCAL_VERSION = "local_version"; /** * The person this photo is associated with. * <P>Type: TEXT</P> */ + @Deprecated public static final String PERSON_ID = "person"; /** @@ -1345,12 +1523,14 @@ public class Contacts { * You must specify this in the columns in order to use it in the where clause. * <P>Type: INTEGER(boolean)</P> */ + @Deprecated public static final String DOWNLOAD_REQUIRED = "download_required"; /** * non-zero if this photo is known to exist on the server * <P>Type: INTEGER(boolean)</P> */ + @Deprecated public static final String EXISTS_ON_SERVER = "exists_on_server"; /** @@ -1358,12 +1538,14 @@ public class Contacts { * the previous attempt. If null then the previous attempt succeeded. * <P>Type: TEXT</P> */ + @Deprecated public static final String SYNC_ERROR = "sync_error"; /** * The image data, or null if there is no image. * <P>Type: BLOB</P> */ + @Deprecated public static final String DATA = "data"; } @@ -1371,6 +1553,7 @@ public class Contacts { /** * The photos over all of the people */ + @Deprecated public static final class Photos implements BaseColumns, PhotosColumns, SyncConstValue { /** * no public constructor since this is a utility class @@ -1380,37 +1563,44 @@ public class Contacts { /** * The content:// style URL for this table */ + @Deprecated public static final Uri CONTENT_URI = Uri.parse("content://contacts/photos"); /** * The directory twig for this sub-table */ + @Deprecated public static final String CONTENT_DIRECTORY = "photo"; /** * The default sort order for this table */ + @Deprecated public static final String DEFAULT_SORT_ORDER = "person ASC"; } + @Deprecated public interface ExtensionsColumns { /** * The name of this extension. May not be null. There may be at most one row for each name. * <P>Type: TEXT</P> */ + @Deprecated public static final String NAME = "name"; /** * The value of this extension. May not be null. * <P>Type: TEXT</P> */ + @Deprecated public static final String VALUE = "value"; } /** * The extensions for a person */ + @Deprecated public static final class Extensions implements BaseColumns, ExtensionsColumns { /** * no public constructor since this is a utility class @@ -1420,6 +1610,7 @@ public class Contacts { /** * The content:// style URL for this table */ + @Deprecated public static final Uri CONTENT_URI = Uri.parse("content://contacts/extensions"); @@ -1427,22 +1618,27 @@ public class Contacts { * The MIME type of {@link #CONTENT_URI} providing a directory of * phones. */ + @Deprecated public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contact_extensions"; /** * The MIME type of a {@link #CONTENT_URI} subdirectory of a single * phone. */ + @Deprecated public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_extensions"; + /** * The default sort order for this table */ + @Deprecated public static final String DEFAULT_SORT_ORDER = "person, name ASC"; /** * The ID of the person this phone number is assigned to. * <P>Type: INTEGER (long)</P> */ + @Deprecated public static final String PERSON_ID = "person"; } @@ -1450,10 +1646,16 @@ public class Contacts { * Contains helper classes used to create or manage {@link android.content.Intent Intents} * that involve contacts. */ + @Deprecated public static final class Intents { + @Deprecated + public Intents() { + } + /** * This is the intent that is fired when a search suggestion is clicked on. */ + @Deprecated public static final String SEARCH_SUGGESTION_CLICKED = ContactsContract.Intents.SEARCH_SUGGESTION_CLICKED; @@ -1461,6 +1663,7 @@ public class Contacts { * This is the intent that is fired when a search suggestion for dialing a number * is clicked on. */ + @Deprecated public static final String SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED = ContactsContract.Intents.SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED; @@ -1468,6 +1671,7 @@ public class Contacts { * This is the intent that is fired when a search suggestion for creating a contact * is clicked on. */ + @Deprecated public static final String SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED = ContactsContract.Intents.SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED; @@ -1475,6 +1679,7 @@ public class Contacts { * Starts an Activity that lets the user pick a contact to attach an image to. * After picking the contact it launches the image cropper in face detection mode. */ + @Deprecated public static final String ATTACH_IMAGE = ContactsContract.Intents.ATTACH_IMAGE; /** @@ -1500,6 +1705,7 @@ public class Contacts { * Passing true for the {@link #EXTRA_FORCE_CREATE} extra will skip * prompting the user when the contact doesn't exist. */ + @Deprecated public static final String SHOW_OR_CREATE_CONTACT = ContactsContract.Intents.SHOW_OR_CREATE_CONTACT; @@ -1510,6 +1716,7 @@ public class Contacts { * <p> * Type: BOOLEAN */ + @Deprecated public static final String EXTRA_FORCE_CREATE = ContactsContract.Intents.EXTRA_FORCE_CREATE; /** @@ -1519,6 +1726,7 @@ public class Contacts { * <p> * Type: STRING */ + @Deprecated public static final String EXTRA_CREATE_DESCRIPTION = ContactsContract.Intents.EXTRA_CREATE_DESCRIPTION; @@ -1529,49 +1737,62 @@ public class Contacts { * * @hide pending API council review */ + @Deprecated public static final String EXTRA_TARGET_RECT = ContactsContract.Intents.EXTRA_TARGET_RECT; /** * Intents related to the Contacts app UI. */ + @Deprecated public static final class UI { + @Deprecated + public UI() { + } + /** * The action for the default contacts list tab. */ + @Deprecated public static final String LIST_DEFAULT = ContactsContract.Intents.UI.LIST_DEFAULT; /** * The action for the contacts list tab. */ + @Deprecated public static final String LIST_GROUP_ACTION = ContactsContract.Intents.UI.LIST_GROUP_ACTION; /** * When in LIST_GROUP_ACTION mode, this is the group to display. */ + @Deprecated public static final String GROUP_NAME_EXTRA_KEY = ContactsContract.Intents.UI.GROUP_NAME_EXTRA_KEY; /** * The action for the all contacts list tab. */ + @Deprecated public static final String LIST_ALL_CONTACTS_ACTION = ContactsContract.Intents.UI.LIST_ALL_CONTACTS_ACTION; /** * The action for the contacts with phone numbers list tab. */ + @Deprecated public static final String LIST_CONTACTS_WITH_PHONES_ACTION = ContactsContract.Intents.UI.LIST_CONTACTS_WITH_PHONES_ACTION; /** * The action for the starred contacts list tab. */ + @Deprecated public static final String LIST_STARRED_ACTION = ContactsContract.Intents.UI.LIST_STARRED_ACTION; /** * The action for the frequent contacts list tab. */ + @Deprecated public static final String LIST_FREQUENT_ACTION = ContactsContract.Intents.UI.LIST_FREQUENT_ACTION; @@ -1580,6 +1801,7 @@ public class Contacts { * contacts in alphabetical order and then the frequent contacts in descending * order of the number of times they have been contacted. */ + @Deprecated public static final String LIST_STREQUENT_ACTION = ContactsContract.Intents.UI.LIST_STREQUENT_ACTION; @@ -1587,6 +1809,7 @@ public class Contacts { * A key for to be used as an intent extra to set the activity * title to a custom String value. */ + @Deprecated public static final String TITLE_EXTRA_KEY = ContactsContract.Intents.UI.TITLE_EXTRA_KEY; @@ -1598,6 +1821,7 @@ public class Contacts { * <p> * Output: Nothing. */ + @Deprecated public static final String FILTER_CONTACTS_ACTION = ContactsContract.Intents.UI.FILTER_CONTACTS_ACTION; @@ -1605,6 +1829,7 @@ public class Contacts { * Used as an int extra field in {@link #FILTER_CONTACTS_ACTION} * intents to supply the text on which to filter. */ + @Deprecated public static final String FILTER_TEXT_EXTRA_KEY = ContactsContract.Intents.UI.FILTER_TEXT_EXTRA_KEY; } @@ -1613,23 +1838,34 @@ public class Contacts { * Convenience class that contains string constants used * to create contact {@link android.content.Intent Intents}. */ + @Deprecated public static final class Insert { + @Deprecated + public Insert() { + } + /** The action code to use when adding a contact */ + @Deprecated public static final String ACTION = ContactsContract.Intents.Insert.ACTION; + /** * If present, forces a bypass of quick insert mode. */ + @Deprecated public static final String FULL_MODE = ContactsContract.Intents.Insert.FULL_MODE; + /** * The extra field for the contact name. * <P>Type: String</P> */ + @Deprecated public static final String NAME = ContactsContract.Intents.Insert.NAME; /** * The extra field for the contact phonetic name. * <P>Type: String</P> */ + @Deprecated public static final String PHONETIC_NAME = ContactsContract.Intents.Insert.PHONETIC_NAME; @@ -1637,24 +1873,28 @@ public class Contacts { * The extra field for the contact company. * <P>Type: String</P> */ + @Deprecated public static final String COMPANY = ContactsContract.Intents.Insert.COMPANY; /** * The extra field for the contact job title. * <P>Type: String</P> */ + @Deprecated public static final String JOB_TITLE = ContactsContract.Intents.Insert.JOB_TITLE; /** * The extra field for the contact notes. * <P>Type: String</P> */ + @Deprecated public static final String NOTES = ContactsContract.Intents.Insert.NOTES; /** * The extra field for the contact phone number. * <P>Type: String</P> */ + @Deprecated public static final String PHONE = ContactsContract.Intents.Insert.PHONE; /** @@ -1662,12 +1902,14 @@ public class Contacts { * <P>Type: Either an integer value from {@link android.provider.Contacts.PhonesColumns PhonesColumns}, * or a string specifying a custom label.</P> */ + @Deprecated public static final String PHONE_TYPE = ContactsContract.Intents.Insert.PHONE_TYPE; /** * The extra field for the phone isprimary flag. * <P>Type: boolean</P> */ + @Deprecated public static final String PHONE_ISPRIMARY = ContactsContract.Intents.Insert.PHONE_ISPRIMARY; @@ -1675,6 +1917,7 @@ public class Contacts { * The extra field for an optional second contact phone number. * <P>Type: String</P> */ + @Deprecated public static final String SECONDARY_PHONE = ContactsContract.Intents.Insert.SECONDARY_PHONE; @@ -1683,6 +1926,7 @@ public class Contacts { * <P>Type: Either an integer value from {@link android.provider.Contacts.PhonesColumns PhonesColumns}, * or a string specifying a custom label.</P> */ + @Deprecated public static final String SECONDARY_PHONE_TYPE = ContactsContract.Intents.Insert.SECONDARY_PHONE_TYPE; @@ -1690,6 +1934,7 @@ public class Contacts { * The extra field for an optional third contact phone number. * <P>Type: String</P> */ + @Deprecated public static final String TERTIARY_PHONE = ContactsContract.Intents.Insert.TERTIARY_PHONE; @@ -1698,6 +1943,7 @@ public class Contacts { * <P>Type: Either an integer value from {@link android.provider.Contacts.PhonesColumns PhonesColumns}, * or a string specifying a custom label.</P> */ + @Deprecated public static final String TERTIARY_PHONE_TYPE = ContactsContract.Intents.Insert.TERTIARY_PHONE_TYPE; @@ -1705,6 +1951,7 @@ public class Contacts { * The extra field for the contact email address. * <P>Type: String</P> */ + @Deprecated public static final String EMAIL = ContactsContract.Intents.Insert.EMAIL; /** @@ -1712,12 +1959,14 @@ public class Contacts { * <P>Type: Either an integer value from {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns} * or a string specifying a custom label.</P> */ + @Deprecated public static final String EMAIL_TYPE = ContactsContract.Intents.Insert.EMAIL_TYPE; /** * The extra field for the email isprimary flag. * <P>Type: boolean</P> */ + @Deprecated public static final String EMAIL_ISPRIMARY = ContactsContract.Intents.Insert.EMAIL_ISPRIMARY; @@ -1725,6 +1974,7 @@ public class Contacts { * The extra field for an optional second contact email address. * <P>Type: String</P> */ + @Deprecated public static final String SECONDARY_EMAIL = ContactsContract.Intents.Insert.SECONDARY_EMAIL; @@ -1733,6 +1983,7 @@ public class Contacts { * <P>Type: Either an integer value from {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns} * or a string specifying a custom label.</P> */ + @Deprecated public static final String SECONDARY_EMAIL_TYPE = ContactsContract.Intents.Insert.SECONDARY_EMAIL_TYPE; @@ -1740,6 +1991,7 @@ public class Contacts { * The extra field for an optional third contact email address. * <P>Type: String</P> */ + @Deprecated public static final String TERTIARY_EMAIL = ContactsContract.Intents.Insert.TERTIARY_EMAIL; @@ -1748,6 +2000,7 @@ public class Contacts { * <P>Type: Either an integer value from {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns} * or a string specifying a custom label.</P> */ + @Deprecated public static final String TERTIARY_EMAIL_TYPE = ContactsContract.Intents.Insert.TERTIARY_EMAIL_TYPE; @@ -1755,6 +2008,7 @@ public class Contacts { * The extra field for the contact postal address. * <P>Type: String</P> */ + @Deprecated public static final String POSTAL = ContactsContract.Intents.Insert.POSTAL; /** @@ -1762,18 +2016,21 @@ public class Contacts { * <P>Type: Either an integer value from {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns} * or a string specifying a custom label.</P> */ + @Deprecated public static final String POSTAL_TYPE = ContactsContract.Intents.Insert.POSTAL_TYPE; /** * The extra field for the postal isprimary flag. * <P>Type: boolean</P> */ + @Deprecated public static final String POSTAL_ISPRIMARY = ContactsContract.Intents.Insert.POSTAL_ISPRIMARY; /** * The extra field for an IM handle. * <P>Type: String</P> */ + @Deprecated public static final String IM_HANDLE = ContactsContract.Intents.Insert.IM_HANDLE; /** @@ -1781,12 +2038,14 @@ public class Contacts { * <P>Type: the result of {@link Contacts.ContactMethods#encodePredefinedImProtocol} * or {@link Contacts.ContactMethods#encodeCustomImProtocol}.</P> */ + @Deprecated public static final String IM_PROTOCOL = ContactsContract.Intents.Insert.IM_PROTOCOL; /** * The extra field for the IM isprimary flag. * <P>Type: boolean</P> */ + @Deprecated public static final String IM_ISPRIMARY = ContactsContract.Intents.Insert.IM_ISPRIMARY; } } diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java index 3a4449e..53b2aa8 100644 --- a/core/java/android/provider/ContactsContract.java +++ b/core/java/android/provider/ContactsContract.java @@ -343,7 +343,7 @@ public final class ContactsContract { Cursor cursor = cr.query(photoUri, new String[]{ContactsContract.CommonDataKinds.Photo.PHOTO}, null, null, null); try { - if (!cursor.moveToNext()) { + if (cursor == null || !cursor.moveToNext()) { return null; } byte[] data = cursor.getBlob(0); @@ -352,7 +352,9 @@ public final class ContactsContract { } return new ByteArrayInputStream(data); } finally { - cursor.close(); + if (cursor != null) { + cursor.close(); + } } } } @@ -452,15 +454,24 @@ public final class ContactsContract { public static final int AGGREGATION_MODE_IMMEDITATE = 1; /** + * If {@link #AGGREGATION_MODE} is {@link #AGGREGATION_MODE_SUSPENDED}, changes + * to the raw contact do not cause its aggregation to be revisited. Note that changing + * {@link #AGGREGATION_MODE} from {@link #AGGREGATION_MODE_SUSPENDED} to + * {@link #AGGREGATION_MODE_DEFAULT} does not trigger an aggregation pass. Any subsequent + * change to the raw contact's data will. + */ + public static final int AGGREGATION_MODE_SUSPENDED = 2; + + /** * Aggregation mode: never aggregate this raw contact (note that the raw contact will not * have a corresponding Aggregate and therefore will not be included in Aggregates * query results.) */ - public static final int AGGREGATION_MODE_DISABLED = 2; + public static final int AGGREGATION_MODE_DISABLED = 3; /** * A sub-directory of a single raw contact that contains all of their {@link Data} rows. - * To access this directory append + * To access this directory append {@link Data#CONTENT_DIRECTORY} to the contact URI. */ public static final class Data implements BaseColumns, DataColumns { /** diff --git a/core/java/android/provider/Gmail.java b/core/java/android/provider/Gmail.java index 5702e7c..4425e51 100644 --- a/core/java/android/provider/Gmail.java +++ b/core/java/android/provider/Gmail.java @@ -1521,8 +1521,9 @@ public final class Gmail { /** * Returns the number of conversation with a given label. - * @deprecated + * @deprecated Use {@link #getLabelId} instead. */ + @Deprecated public int getNumConversations(String label) { return getNumConversations(getLabelId(label)); } @@ -1534,8 +1535,9 @@ public final class Gmail { /** * Returns the number of unread conversation with a given label. - * @deprecated + * @deprecated Use {@link #getLabelId} instead. */ + @Deprecated public int getNumUnreadConversations(String label) { return getNumUnreadConversations(getLabelId(label)); } @@ -2040,8 +2042,9 @@ public final class Gmail { } /** - * @deprecated + * @deprecated Always returns true. */ + @Deprecated public boolean getExpanded() { return true; } diff --git a/core/java/android/provider/LiveFolders.java b/core/java/android/provider/LiveFolders.java index 6e95fb7..19f361b 100644 --- a/core/java/android/provider/LiveFolders.java +++ b/core/java/android/provider/LiveFolders.java @@ -45,7 +45,7 @@ import android.annotation.SdkConstant; * public static class MyLiveFolder extends Activity { * public static final Uri CONTENT_URI = Uri.parse("content://my.app/live"); * - * @Override + * &#064;Override * protected void onCreate(Bundle savedInstanceState) { * super.onCreate(savedInstanceState); * diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java index 21e5865..49b5bb1 100644 --- a/core/java/android/provider/MediaStore.java +++ b/core/java/android/provider/MediaStore.java @@ -164,6 +164,12 @@ public final class MediaStore public final static String EXTRA_SIZE_LIMIT = "android.intent.extra.sizeLimit"; /** + * Specify the maximum allowed recording duration in seconds. + * @hide + */ + public final static String EXTRA_DURATION_LIMIT = "android.intent.extra.durationLimit"; + + /** * The name of the Intent-extra used to indicate a content resolver Uri to be used to * store the requested image or video. */ diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 588068e..9e3008b 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -1522,18 +1522,17 @@ public final class Settings { @Deprecated public static final String USE_GOOGLE_MAIL = Secure.USE_GOOGLE_MAIL; -// /** -// * @deprecated Use {@link android.provider.Settings.Secure#WIFI_MAX_DHCP_RETRY_COUNT} -// * instead -// */ + /** + * @deprecated Use + * {@link android.provider.Settings.Secure#WIFI_MAX_DHCP_RETRY_COUNT} instead + */ @Deprecated public static final String WIFI_MAX_DHCP_RETRY_COUNT = Secure.WIFI_MAX_DHCP_RETRY_COUNT; -// /** -// * @deprecated Use -// * {@link android.provider.Settings.Secure#WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS} -// * instead -// */ + /** + * @deprecated Use + * {@link android.provider.Settings.Secure#WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS} instead + */ @Deprecated public static final String WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS = Secure.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS; @@ -2935,8 +2934,8 @@ public final class Settings { * it so the UI can give it some special treatment when displaying the "time sent" for * it. This setting is to control what x is. */ - public static final String GTALK_OLD_CHAT_MESSAGE_THREADHOLD_IN_SEC = - "gtalk_old_chat_msg_threadhold_in_sec"; + public static final String GTALK_OLD_CHAT_MESSAGE_THRESHOLD_IN_SEC = + "gtalk_old_chat_msg_threshold_in_sec"; /** * a setting to control the max connection history record GTalkService stores. @@ -3122,6 +3121,13 @@ public final class Settings { "vending_promo_refresh_freq_ms"; /** + * Frequency in milliseconds when we should refresh the provisioning information from + * the carrier backend. + */ + public static final String VENDING_CARRIER_PROVISIONING_REFRESH_FREQUENCY_MS = + "vending_carrier_ref_freq_ms"; + + /** * URL that points to the legal terms of service to display in Settings. * <p> * This should be a https URL. For a pretty user-friendly URL, use diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java index 7a6f6bb..0207330 100644 --- a/core/java/android/provider/Telephony.java +++ b/core/java/android/provider/Telephony.java @@ -1264,6 +1264,21 @@ public final class Telephony { } /** + * Returns true if the number is a Phone number + * + * @param number the input number to be tested + * @return true if number is a Phone number + */ + public static boolean isPhoneNumber(String number) { + if (TextUtils.isEmpty(number)) { + return false; + } + + Matcher match = Regex.PHONE_PATTERN.matcher(number); + return match.matches(); + } + + /** * Contains all MMS messages in the MMS app's inbox. */ public static final class Inbox implements BaseMmsColumns { diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java index 6610d0e..975c2ff 100644 --- a/core/java/android/server/BluetoothEventLoop.java +++ b/core/java/android/server/BluetoothEventLoop.java @@ -430,8 +430,10 @@ class BluetoothEventLoop { boolean authorized = false; UUID uuid = UUID.fromString(deviceUuid); + // Bluez sends the UUID of the local service being accessed, _not_ the + // remote service if (mBluetoothService.isEnabled() && - (BluetoothUuid.isAudioSink(uuid) || BluetoothUuid.isAvrcpController(uuid) + (BluetoothUuid.isAudioSource(uuid) || BluetoothUuid.isAvrcpTarget(uuid) || BluetoothUuid.isAdvAudioDist(uuid))) { BluetoothA2dp a2dp = new BluetoothA2dp(mContext); BluetoothDevice device = mAdapter.getRemoteDevice(address); @@ -444,6 +446,7 @@ class BluetoothEventLoop { } else { Log.i(TAG, "Rejecting incoming " + deviceUuid + " connection from " + address); } + log("onAgentAuthorize(" + objectPath + ", " + deviceUuid + ") = " + authorized); return authorized; } diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java index a7c0425..413f6a8 100644 --- a/core/java/android/server/BluetoothService.java +++ b/core/java/android/server/BluetoothService.java @@ -1083,14 +1083,25 @@ public class BluetoothService extends IBluetooth.Stub { pw.println("\n--Known devices--"); for (String address : mDeviceProperties.keySet()) { + int bondState = mBondState.getBondState(address); pw.printf("%s %10s (%d) %s\n", address, - toBondStateString(mBondState.getBondState(address)), + toBondStateString(bondState), mBondState.getAttempt(address), getRemoteName(address)); + if (bondState == BluetoothDevice.BOND_BONDED) { + String[] uuids = getRemoteUuids(address); + if (uuids == null) { + pw.printf("\tuuids = null\n"); + } else { + for (String uuid : uuids) { + pw.printf("\t" + uuid + "\n"); + } + } + } } String value = getProperty("Devices"); - String []devicesObjectPath = null; + String[] devicesObjectPath = null; if (value != null) { devicesObjectPath = value.split(","); } diff --git a/core/java/android/syncml/pim/vcard/VCardDataBuilder.java b/core/java/android/syncml/pim/vcard/VCardDataBuilder.java index a0513f1..f2a2733 100644 --- a/core/java/android/syncml/pim/vcard/VCardDataBuilder.java +++ b/core/java/android/syncml/pim/vcard/VCardDataBuilder.java @@ -28,6 +28,7 @@ import android.syncml.pim.PropertyNode; import android.syncml.pim.VBuilder; import android.syncml.pim.VNode; import android.syncml.pim.VParser; +import android.text.TextUtils; import android.util.CharsetUtils; import android.util.Log; @@ -403,7 +404,10 @@ public class VCardDataBuilder implements VBuilder { String targetCharset = CharsetUtils.nameForDefaultVendor(paramMap.getAsString("CHARSET")); String encoding = paramMap.getAsString("ENCODING"); - if (targetCharset == null || targetCharset.length() == 0) { + Log.d("@@@", String.format("targetCharset: \"%s\", encoding: \"%s\"", + targetCharset, encoding)); + + if (TextUtils.isEmpty(targetCharset)) { targetCharset = mTargetCharset; } diff --git a/core/java/android/syncml/pim/vcard/VCardParser.java b/core/java/android/syncml/pim/vcard/VCardParser.java index 6dad852d..9a590dd 100644 --- a/core/java/android/syncml/pim/vcard/VCardParser.java +++ b/core/java/android/syncml/pim/vcard/VCardParser.java @@ -17,7 +17,6 @@ package android.syncml.pim.vcard; import android.syncml.pim.VDataBuilder; -import android.syncml.pim.VParser; import android.util.Config; import android.util.Log; diff --git a/core/java/android/test/InstrumentationTestCase.java b/core/java/android/test/InstrumentationTestCase.java index 2145d7c..22d95d1 100644 --- a/core/java/android/test/InstrumentationTestCase.java +++ b/core/java/android/test/InstrumentationTestCase.java @@ -43,11 +43,25 @@ public class InstrumentationTestCase extends TestCase { * * @param instrumentation the instrumentation to use with this instance */ - public void injectInsrumentation(Instrumentation instrumentation) { + public void injectInstrumentation(Instrumentation instrumentation) { mInstrumentation = instrumentation; } /** + * Injects instrumentation into this test case. This method is + * called by the test runner during test setup. + * + * @param instrumentation the instrumentation to use with this instance + * + * @deprecated Incorrect spelling, + * use {@link #injectInstrumentation(android.app.Instrumentation) instead. + */ + @Deprecated + public void injectInsrumentation(Instrumentation instrumentation) { + injectInstrumentation(instrumentation); + } + + /** * Inheritors can access the instrumentation using this. * @return instrumentation */ diff --git a/core/java/android/test/InstrumentationTestSuite.java b/core/java/android/test/InstrumentationTestSuite.java index 2ab949e..7a78ffb 100644 --- a/core/java/android/test/InstrumentationTestSuite.java +++ b/core/java/android/test/InstrumentationTestSuite.java @@ -65,7 +65,7 @@ public class InstrumentationTestSuite extends TestSuite { public void runTest(Test test, TestResult result) { if (test instanceof InstrumentationTestCase) { - ((InstrumentationTestCase) test).injectInsrumentation(mInstrumentation); + ((InstrumentationTestCase) test).injectInstrumentation(mInstrumentation); } // run the test as usual diff --git a/core/java/android/text/style/ImageSpan.java b/core/java/android/text/style/ImageSpan.java index 86ef5f6..74b9463 100644 --- a/core/java/android/text/style/ImageSpan.java +++ b/core/java/android/text/style/ImageSpan.java @@ -36,6 +36,7 @@ public class ImageSpan extends DynamicDrawableSpan { /** * @deprecated Use {@link #ImageSpan(Context, Bitmap)} instead. */ + @Deprecated public ImageSpan(Bitmap b) { this(null, b, ALIGN_BOTTOM); } @@ -43,6 +44,7 @@ public class ImageSpan extends DynamicDrawableSpan { /** * @deprecated Use {@link #ImageSpan(Context, Bitmap, int) instead. */ + @Deprecated public ImageSpan(Bitmap b, int verticalAlignment) { this(null, b, verticalAlignment); } diff --git a/core/java/android/util/Config.java b/core/java/android/util/Config.java index 9571041..924b49d 100644 --- a/core/java/android/util/Config.java +++ b/core/java/android/util/Config.java @@ -34,25 +34,25 @@ public final class Config */ /** - * Always the inverse of DEBUG. + * @deprecated Use {@link #DEBUG} instead. */ @Deprecated public static final boolean RELEASE = !DEBUG; /** - * Always false. + * @deprecated Always false. */ @Deprecated public static final boolean PROFILE = false; /** - * Always false. + * @deprecated Always false. */ @Deprecated public static final boolean LOGV = false; /** - * Always true. + * @deprecated Always true. */ @Deprecated public static final boolean LOGD = true; diff --git a/core/java/android/view/RawInputEvent.java b/core/java/android/view/RawInputEvent.java index db024b4..8b3cdd4 100644 --- a/core/java/android/view/RawInputEvent.java +++ b/core/java/android/view/RawInputEvent.java @@ -171,6 +171,9 @@ public class RawInputEvent { public static final int ABS_MT_BLOB_ID = 0x38; public static final int ABS_MAX = 0x3f; + // Switch events + public static final int SW_LID = 0x00; + public static final int SYN_REPORT = 0; public static final int SYN_CONFIG = 1; public static final int SYN_MT_REPORT = 2; diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java index a662760..2f5e601 100644 --- a/core/java/android/view/animation/Animation.java +++ b/core/java/android/view/animation/Animation.java @@ -319,7 +319,7 @@ public abstract class Animation implements Cloneable { * * @param durationMillis Duration in milliseconds * - * @throw java.lang.IllegalArgumentException if the duration is < 0 + * @throws java.lang.IllegalArgumentException if the duration is < 0 * * @attr ref android.R.styleable#Animation_duration */ diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java index afa2c35..ce27fd7 100644 --- a/core/java/android/webkit/BrowserFrame.java +++ b/core/java/android/webkit/BrowserFrame.java @@ -343,17 +343,16 @@ class BrowserFrame extends Handler { switch (msg.what) { case FRAME_COMPLETED: { if (mSettings.getSavePassword() && hasPasswordField()) { - if (DebugFlags.BROWSER_FRAME) { - Assert.assertNotNull(mCallbackProxy.getBackForwardList() - .getCurrentItem()); - } - WebAddress uri = new WebAddress( - mCallbackProxy.getBackForwardList().getCurrentItem() - .getUrl()); - String schemePlusHost = uri.mScheme + uri.mHost; - String[] up = mDatabase.getUsernamePassword(schemePlusHost); - if (up != null && up[0] != null) { - setUsernamePassword(up[0], up[1]); + WebHistoryItem item = mCallbackProxy.getBackForwardList() + .getCurrentItem(); + if (item != null) { + WebAddress uri = new WebAddress(item.getUrl()); + String schemePlusHost = uri.mScheme + uri.mHost; + String[] up = + mDatabase.getUsernamePassword(schemePlusHost); + if (up != null && up[0] != null) { + setUsernamePassword(up[0], up[1]); + } } } CacheManager.trimCacheIfNeeded(); diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java index e77d29b..41e604d 100644 --- a/core/java/android/webkit/CallbackProxy.java +++ b/core/java/android/webkit/CallbackProxy.java @@ -70,9 +70,6 @@ class CallbackProxy extends Handler { private final WebBackForwardList mBackForwardList; // Used to call startActivity during url override. private final Context mContext; - // Stores the URL being loaded and the viewing mode to switch into when - // the URL finishes loading. - private ChangeViewModeOnFinishedLoad mChange; // Message Ids private static final int PAGE_STARTED = 100; @@ -181,35 +178,15 @@ class CallbackProxy extends Handler { /** * Tell the host application that the WebView has changed viewing modes. - * @param toZoomedOut If true, the WebView has zoomed out so that the page - * fits the screen. If false, it is zoomed to the setting - * specified by the user. + * @param newViewingMode One of the values described in WebView as possible + * values for the viewing mode */ - /* package */ void uiOnChangeViewingMode(boolean toZoomOverview) { + /* package */ void uiOnChangeViewingMode(int newViewingMode) { if (mWebChromeClient != null) { - mWebChromeClient.onChangeViewingMode(toZoomOverview); + mWebChromeClient.onChangeViewingMode(mWebView, newViewingMode); } } - private static class ChangeViewModeOnFinishedLoad { - boolean mToZoomOverView; - String mOriginalUrl; - ChangeViewModeOnFinishedLoad(boolean toZoomOverview, - String originalUrl) { - mToZoomOverView = toZoomOverview; - mOriginalUrl = originalUrl; - } - } - - /** - * Keep track of the url and the viewing mode to change into. If/when that - * url finishes loading, this will change the viewing mode. - */ - /* package */ void uiChangeViewingModeOnFinishedLoad( - boolean toZoomOverview, String originalUrl) { - if (mWebChromeClient == null) return; - mChange = new ChangeViewModeOnFinishedLoad(toZoomOverview, originalUrl); - } /** * Called by the UI side. Calling overrideUrlLoading from the WebCore * side will post a message to call this method. @@ -271,15 +248,6 @@ class CallbackProxy extends Handler { if (mWebViewClient != null) { mWebViewClient.onPageFinished(mWebView, (String) msg.obj); } - if (mChange != null) { - if (mWebView.getOriginalUrl().equals(mChange.mOriginalUrl)) { - uiOnChangeViewingMode(mChange.mToZoomOverView); - } else { - // The user has gone to a different page, so there is - // no need to hang on to the old object. - mChange = null; - } - } break; case RECEIVED_ICON: @@ -466,12 +434,14 @@ class CallbackProxy extends Handler { ((Long) map.get("currentQuota")).longValue(); long totalUsedQuota = ((Long) map.get("totalUsedQuota")).longValue(); + long estimatedSize = + ((Long) map.get("estimatedSize")).longValue(); WebStorage.QuotaUpdater quotaUpdater = (WebStorage.QuotaUpdater) map.get("quotaUpdater"); mWebChromeClient.onExceededDatabaseQuota(url, - databaseIdentifier, currentQuota, totalUsedQuota, - quotaUpdater); + databaseIdentifier, currentQuota, estimatedSize, + totalUsedQuota, quotaUpdater); } break; @@ -1227,6 +1197,7 @@ class CallbackProxy extends Handler { * @param databaseIdentifier The identifier of the database that the * transaction that caused the overflow was running on. * @param currentQuota The current quota the origin is allowed. + * @param estimatedSize The estimated size of the database. * @param totalUsedQuota is the sum of all origins' quota. * @param quotaUpdater An instance of a class encapsulating a callback * to WebViewCore to run when the decision to allow or deny more @@ -1234,7 +1205,8 @@ class CallbackProxy extends Handler { */ public void onExceededDatabaseQuota( String url, String databaseIdentifier, long currentQuota, - long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater) { + long estimatedSize, long totalUsedQuota, + WebStorage.QuotaUpdater quotaUpdater) { if (mWebChromeClient == null) { quotaUpdater.updateQuota(currentQuota); return; @@ -1245,6 +1217,7 @@ class CallbackProxy extends Handler { map.put("databaseIdentifier", databaseIdentifier); map.put("url", url); map.put("currentQuota", currentQuota); + map.put("estimatedSize", estimatedSize); map.put("totalUsedQuota", totalUsedQuota); map.put("quotaUpdater", quotaUpdater); exceededQuota.obj = map; diff --git a/core/java/android/webkit/Plugin.java b/core/java/android/webkit/Plugin.java index 302bea2..34a30a9 100644 --- a/core/java/android/webkit/Plugin.java +++ b/core/java/android/webkit/Plugin.java @@ -27,7 +27,7 @@ import android.webkit.WebView; * Represents a plugin (Java equivalent of the PluginPackageAndroid * C++ class in libs/WebKitLib/WebKit/WebCore/plugins/android/) * - * @deprecated This interface was inteded to be used by Gears. Since Gears was + * @deprecated This interface was intended to be used by Gears. Since Gears was * deprecated, so is this class. */ @Deprecated @@ -43,7 +43,8 @@ public class Plugin { private PreferencesClickHandler mHandler; /** - * @deprecated + * @deprecated This interface was intended to be used by Gears. Since Gears was + * deprecated, so is this class. */ @Deprecated public Plugin(String name, @@ -58,7 +59,8 @@ public class Plugin { } /** - * @deprecated + * @deprecated This interface was intended to be used by Gears. Since Gears was + * deprecated, so is this class. */ @Deprecated public String toString() { @@ -66,7 +68,8 @@ public class Plugin { } /** - * @deprecated + * @deprecated This interface was intended to be used by Gears. Since Gears was + * deprecated, so is this class. */ @Deprecated public String getName() { @@ -74,7 +77,8 @@ public class Plugin { } /** - * @deprecated + * @deprecated This interface was intended to be used by Gears. Since Gears was + * deprecated, so is this class. */ @Deprecated public String getPath() { @@ -82,7 +86,8 @@ public class Plugin { } /** - * @deprecated + * @deprecated This interface was intended to be used by Gears. Since Gears was + * deprecated, so is this class. */ @Deprecated public String getFileName() { @@ -90,7 +95,8 @@ public class Plugin { } /** - * @deprecated + * @deprecated This interface was intended to be used by Gears. Since Gears was + * deprecated, so is this class. */ @Deprecated public String getDescription() { @@ -98,7 +104,8 @@ public class Plugin { } /** - * @deprecated + * @deprecated This interface was intended to be used by Gears. Since Gears was + * deprecated, so is this class. */ @Deprecated public void setName(String name) { @@ -106,7 +113,8 @@ public class Plugin { } /** - * @deprecated + * @deprecated This interface was intended to be used by Gears. Since Gears was + * deprecated, so is this class. */ @Deprecated public void setPath(String path) { @@ -114,7 +122,8 @@ public class Plugin { } /** - * @deprecated + * @deprecated This interface was intended to be used by Gears. Since Gears was + * deprecated, so is this class. */ @Deprecated public void setFileName(String fileName) { @@ -122,7 +131,8 @@ public class Plugin { } /** - * @deprecated + * @deprecated This interface was intended to be used by Gears. Since Gears was + * deprecated, so is this class. */ @Deprecated public void setDescription(String description) { @@ -130,7 +140,8 @@ public class Plugin { } /** - * @deprecated + * @deprecated This interface was intended to be used by Gears. Since Gears was + * deprecated, so is this class. */ @Deprecated public void setClickHandler(PreferencesClickHandler handler) { @@ -140,7 +151,8 @@ public class Plugin { /** * Invokes the click handler for this plugin. * - * @deprecated + * @deprecated This interface was intended to be used by Gears. Since Gears was + * deprecated, so is this class. */ @Deprecated public void dispatchClickEvent(Context context) { @@ -152,7 +164,8 @@ public class Plugin { /** * Default click handler. The plugins should implement their own. * - * @deprecated + * @deprecated This interface was intended to be used by Gears. Since Gears was + * deprecated, so is this class. */ @Deprecated private class DefaultClickHandler implements PreferencesClickHandler, @@ -172,7 +185,8 @@ public class Plugin { } } /** - * @deprecated + * @deprecated This interface was intended to be used by Gears. Since Gears was + * deprecated, so is this class. */ @Deprecated public void onClick(DialogInterface dialog, int which) { diff --git a/core/java/android/webkit/PluginData.java b/core/java/android/webkit/PluginData.java index d9b196a..2dd445e 100644 --- a/core/java/android/webkit/PluginData.java +++ b/core/java/android/webkit/PluginData.java @@ -28,7 +28,7 @@ import java.util.Map; * status code. The PluginData class is the container for all these * parts. * - * @deprecated This class was inteded to be used by Gears. Since Gears was + * @deprecated This class was intended to be used by Gears. Since Gears was * deprecated, so is this class. */ @Deprecated @@ -63,7 +63,8 @@ public final class PluginData { * lowercase header name to [ unmodified header name, header value] * @param length The HTTP response status code. * - * @deprecated + * @deprecated This class was intended to be used by Gears. Since Gears was + * deprecated, so is this class. */ @Deprecated public PluginData( @@ -82,7 +83,8 @@ public final class PluginData { * * @return An InputStream instance with the plugin content. * - * @deprecated + * @deprecated This class was intended to be used by Gears. Since Gears was + * deprecated, so is this class. */ @Deprecated public InputStream getInputStream() { @@ -94,7 +96,8 @@ public final class PluginData { * * @return the length of the plugin content. * - * @deprecated + * @deprecated This class was intended to be used by Gears. Since Gears was + * deprecated, so is this class. */ @Deprecated public long getContentLength() { @@ -109,7 +112,8 @@ public final class PluginData { * mapping is 'lowercase header name' to ['unmodified header * name', header value]. * - * @deprecated + * @deprecated This class was intended to be used by Gears. Since Gears was + * deprecated, so is this class. */ @Deprecated public Map<String, String[]> getHeaders() { @@ -121,7 +125,8 @@ public final class PluginData { * * @return The HTTP statue code, e.g 200. * - * @deprecated + * @deprecated This class was intended to be used by Gears. Since Gears was + * deprecated, so is this class. */ @Deprecated public int getStatusCode() { diff --git a/core/java/android/webkit/PluginList.java b/core/java/android/webkit/PluginList.java index 5b65b9a..a61b07b 100644 --- a/core/java/android/webkit/PluginList.java +++ b/core/java/android/webkit/PluginList.java @@ -25,7 +25,7 @@ import java.util.List; * populated when the plugins are initialized (at * browser startup, at the moment). * - * @deprecated This interface was inteded to be used by Gears. Since Gears was + * @deprecated This interface was intended to be used by Gears. Since Gears was * deprecated, so is this class. */ @Deprecated @@ -35,7 +35,8 @@ public class PluginList { /** * Public constructor. Initializes the list of plugins. * - * @deprecated + * @deprecated This interface was intended to be used by Gears. Since Gears was + * deprecated, so is this class. */ @Deprecated public PluginList() { @@ -45,7 +46,8 @@ public class PluginList { /** * Returns the list of plugins as a java.util.List. * - * @deprecated + * @deprecated This interface was intended to be used by Gears. Since Gears was + * deprecated, so is this class. */ @Deprecated public synchronized List getList() { @@ -55,7 +57,8 @@ public class PluginList { /** * Adds a plugin to the list. * - * @deprecated + * @deprecated This interface was intended to be used by Gears. Since Gears was + * deprecated, so is this class. */ @Deprecated public synchronized void addPlugin(Plugin plugin) { @@ -67,7 +70,8 @@ public class PluginList { /** * Removes a plugin from the list. * - * @deprecated + * @deprecated This interface was intended to be used by Gears. Since Gears was + * deprecated, so is this class. */ @Deprecated public synchronized void removePlugin(Plugin plugin) { @@ -80,7 +84,8 @@ public class PluginList { /** * Clears the plugin list. * - * @deprecated + * @deprecated This interface was intended to be used by Gears. Since Gears was + * deprecated, so is this class. */ @Deprecated public synchronized void clear() { @@ -90,7 +95,8 @@ public class PluginList { /** * Dispatches the click event to the appropriate plugin. * - * @deprecated + * @deprecated This interface was intended to be used by Gears. Since Gears was + * deprecated, so is this class. */ @Deprecated public synchronized void pluginClicked(Context context, int position) { diff --git a/core/java/android/webkit/URLUtil.java b/core/java/android/webkit/URLUtil.java index 5ed42e9..232ed36 100644 --- a/core/java/android/webkit/URLUtil.java +++ b/core/java/android/webkit/URLUtil.java @@ -172,6 +172,7 @@ public final class URLUtil { * requests from a file url. * @deprecated Cookieless proxy is no longer supported. */ + @Deprecated public static boolean isCookielessProxyUrl(String url) { return (null != url) && url.startsWith(PROXY_BASE); } diff --git a/core/java/android/webkit/UrlInterceptRegistry.java b/core/java/android/webkit/UrlInterceptRegistry.java index 6e2a482..eca5acd 100644 --- a/core/java/android/webkit/UrlInterceptRegistry.java +++ b/core/java/android/webkit/UrlInterceptRegistry.java @@ -25,7 +25,7 @@ import java.util.LinkedList; import java.util.Map; /** - * @deprecated This class was inteded to be used by Gears. Since Gears was + * @deprecated This class was intended to be used by Gears. Since Gears was * deprecated, so is this class. */ @Deprecated @@ -48,7 +48,8 @@ public final class UrlInterceptRegistry { * * @param disabled true to disable the cache * - * @deprecated + * @deprecated This class was intended to be used by Gears. Since Gears was + * deprecated, so is this class. */ @Deprecated public static synchronized void setUrlInterceptDisabled(boolean disabled) { @@ -60,7 +61,8 @@ public final class UrlInterceptRegistry { * * @return return if it is disabled * - * @deprecated + * @deprecated This class was intended to be used by Gears. Since Gears was + * deprecated, so is this class. */ @Deprecated public static synchronized boolean urlInterceptDisabled() { @@ -74,7 +76,8 @@ public final class UrlInterceptRegistry { * @param handler The new UrlInterceptHandler object * @return true if the handler was not previously registered. * - * @deprecated + * @deprecated This class was intended to be used by Gears. Since Gears was + * deprecated, so is this class. */ @Deprecated public static synchronized boolean registerHandler( @@ -93,7 +96,8 @@ public final class UrlInterceptRegistry { * @param handler A previously registered UrlInterceptHandler. * @return true if the handler was found and removed from the list. * - * @deprecated + * @deprecated This class was intended to be used by Gears. Since Gears was + * deprecated, so is this class. */ @Deprecated public static synchronized boolean unregisterHandler( @@ -107,7 +111,8 @@ public final class UrlInterceptRegistry { * * @return A CacheResult containing surrogate content. * - * @deprecated + * @deprecated This class was intended to be used by Gears. Since Gears was + * deprecated, so is this class. */ @Deprecated public static synchronized CacheResult getSurrogate( @@ -133,7 +138,8 @@ public final class UrlInterceptRegistry { * * @return A PluginData instance containing surrogate content. * - * @deprecated + * @deprecated This class was intended to be used by Gears. Since Gears was + * deprecated, so is this class. */ @Deprecated public static synchronized PluginData getPluginData( diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java index e1c8d4d..ad4ba05 100644 --- a/core/java/android/webkit/WebChromeClient.java +++ b/core/java/android/webkit/WebChromeClient.java @@ -24,12 +24,12 @@ public class WebChromeClient { /** * Tell the host application that the WebView has changed viewing modes. - * @param toZoomedOut If true, the WebView has zoomed out so that the page - * fits the screen. If false, it is zoomed to the setting - * specified by the user. + * @param view The WebView that initiated the callback. + * @param newViewingMode One of the values described in WebView as possible + * values for the viewing mode * @hide */ - public void onChangeViewingMode(boolean toZoomedOut) {} + public void onChangeViewingMode(WebView view, int newViewingMode) {} /** * Tell the host application the current progress of loading a page. @@ -215,13 +215,14 @@ public class WebChromeClient { * @param databaseIdentifier The identifier of the database that caused the * quota overflow. * @param currentQuota The current quota for the origin. + * @param estimatedSize The estimated size of the database. * @param totalUsedQuota is the sum of all origins' quota. * @param quotaUpdater A callback to inform the WebCore thread that a new * quota is available. This callback must always be executed at some * point to ensure that the sleeping WebCore thread is woken up. */ public void onExceededDatabaseQuota(String url, String databaseIdentifier, - long currentQuota, long totalUsedQuota, + long currentQuota, long estimatedSize, long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater) { // This default implementation passes the current quota back to WebCore. // WebCore will interpret this that new quota was declined. diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java index 4bdd488..e8b2702 100644 --- a/core/java/android/webkit/WebSettings.java +++ b/core/java/android/webkit/WebSettings.java @@ -172,6 +172,7 @@ public class WebSettings { private long mAppCacheMaxSize = Long.MAX_VALUE; private String mAppCachePath = ""; private String mDatabasePath = ""; + private String mGeolocationDatabasePath = ""; // Don't need to synchronize the get/set methods as they // are basic types, also none of these values are used in // native WebCore code. @@ -978,6 +979,21 @@ public class WebSettings { } /** + * Set the path where the Geolocation permissions database should be saved. + * This will update WebCore when the Sync runs in the C++ side. + * @param databasePath String path to the directory where the Geolocation + * permissions database should be saved. May be the empty string but + * should never be null. + * @hide pending api council approval + */ + public synchronized void setGeolocationDatabasePath(String databasePath) { + if (databasePath != null && !databasePath.equals(mDatabasePath)) { + mGeolocationDatabasePath = databasePath; + postSync(); + } + } + + /** * Tell the WebView to enable Application Caches API. * @param flag True if the WebView should enable Application Caches. * @hide pending api council approval diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index f49aab1..196c66b 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -522,6 +522,48 @@ public class WebView extends AbsoluteLayout // the last zoom scale. boolean mInZoomOverview = false; + // The viewing mode of this webview. Reported back to the WebChromeClient + // so we can hide and display the title bar as appropriate. + private int mViewingMode; + /** + * Not supporting overview vs reading mode + * @hide + */ + public final static int NO_VIEWING_MODE = 0; + /** + * Zoom overview mode. The page is zoomed all the way out, mInZoomOverview + * is true, and the title bar is showing. Double tapping will change to + * reading mode. + * @hide + */ + public final static int OVERVIEW_MODE = 1; + /** + * Reading mode. The page is at the level specified by the user, + * mInZoomOverview is false, and the title bar is not showing. Double + * tapping will change to zoom overview mode. + * @hide + */ + public final static int READING_MODE = 2; + /** + * Modified reading mode, which shows the title bar. mInZoomOverview is + * false, and double tapping will change to zoom overview mode. However, + * if the scrolling will change to reading mode. Used when swiping a + * tab into view which was in reading mode, unless it was a mobile site + * with zero scroll. + * @hide + */ + public final static int READING_MODE_WITH_TITLE_BAR = 3; + /** + * Another modified reading mode. For loading a mobile site, or swiping a + * tab into view which was displaying a mobile site in reading mode + * with zero scroll + * @hide + */ + public final static int TITLE_BAR_DISMISS_MODE = 4; + // Whether the current site is a mobile site. Determined when we receive + // NEW_PICTURE_MSG_ID to help determine how to handle double taps + private boolean mMobileSite; + // ideally mZoomOverviewWidth should be mContentWidth. But sites like espn, // engadget always have wider mContentWidth no matter what viewport size is. int mZoomOverviewWidth = WebViewCore.DEFAULT_VIEWPORT_WIDTH; @@ -1135,6 +1177,7 @@ public class WebView extends AbsoluteLayout if (mInZoomOverview) { b.putFloat("lastScale", mLastScale); } + b.putBoolean("mobile", mMobileSite); return true; } return false; @@ -1180,12 +1223,20 @@ public class WebView extends AbsoluteLayout // correctly mActualScale = scale; float lastScale = b.getFloat("lastScale", -1.0f); + mMobileSite = b.getBoolean("mobile", false); if (lastScale > 0) { mInZoomOverview = true; + mViewingMode = OVERVIEW_MODE; mLastScale = lastScale; } else { mInZoomOverview = false; + if (mMobileSite && (mScrollX | mScrollY) == 0) { + mViewingMode = TITLE_BAR_DISMISS_MODE; + } else { + mViewingMode = READING_MODE_WITH_TITLE_BAR; + } } + mCallbackProxy.uiOnChangeViewingMode(mViewingMode); invalidate(); return true; } @@ -3674,8 +3725,10 @@ public class WebView extends AbsoluteLayout 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. - mZoomCenterX = getViewWidth() * .5f; - mZoomCenterY = getViewHeight() * .5f; + if (mZoomScale == 0) { // unless we're already zooming + mZoomCenterX = getViewWidth() * .5f; + mZoomCenterY = getViewHeight() * .5f; + } // update mMinZoomScale if the minimum zoom scale is not fixed if (!mMinZoomScaleFixed) { @@ -3693,6 +3746,12 @@ public class WebView extends AbsoluteLayout protected void onScrollChanged(int l, int t, int oldl, int oldt) { super.onScrollChanged(l, t, oldl, oldt); + if (mViewingMode == READING_MODE_WITH_TITLE_BAR + || mViewingMode == TITLE_BAR_DISMISS_MODE) { + mViewingMode = READING_MODE; + mCallbackProxy.uiOnChangeViewingMode(mViewingMode); + } + sendOurVisibleRect(); } @@ -3907,6 +3966,13 @@ public class WebView extends AbsoluteLayout deltaY = newScrollY - mScrollY; boolean done = false; if (deltaX == 0 && deltaY == 0) { + // The user attempted to pan the page, so dismiss the title + // bar + if (mViewingMode == READING_MODE_WITH_TITLE_BAR + || mViewingMode == TITLE_BAR_DISMISS_MODE) { + mViewingMode = READING_MODE; + mCallbackProxy.uiOnChangeViewingMode(mViewingMode); + } done = true; } else { if (mSnapScrollMode == SNAP_X || mSnapScrollMode == SNAP_Y) { @@ -4681,14 +4747,42 @@ public class WebView extends AbsoluteLayout } } + /** + * Called when the Tabs are used to slide this WebView's tab into view. + * @hide + */ + public void slideIntoFocus() { + if (mViewingMode == READING_MODE) { + if (!mMobileSite || (mScrollX | mScrollY) != 0) { + mViewingMode = READING_MODE_WITH_TITLE_BAR; + } else { + mViewingMode = TITLE_BAR_DISMISS_MODE; + } + mCallbackProxy.uiOnChangeViewingMode(mViewingMode); + } + } + private void doDoubleTap() { - if (mWebViewCore.getSettings().getUseWideViewPort() == false) { + if (mWebViewCore.getSettings().getUseWideViewPort() == false || + mViewingMode == NO_VIEWING_MODE) { return; } + if (mViewingMode == TITLE_BAR_DISMISS_MODE) { + mViewingMode = READING_MODE; + // mInZoomOverview will not change, so change the viewing mode + // and return + mCallbackProxy.uiOnChangeViewingMode(mViewingMode); + return; + } + if (mViewingMode == READING_MODE_WITH_TITLE_BAR && mMobileSite) { + scrollTo(0,0); + } + // READING_MODE_WITH_TITLE_BAR will go to OVERVIEW_MODE here. mZoomCenterX = mLastTouchX; mZoomCenterY = mLastTouchY; mInZoomOverview = !mInZoomOverview; - mCallbackProxy.uiOnChangeViewingMode(mInZoomOverview); + mViewingMode = mInZoomOverview ? OVERVIEW_MODE : READING_MODE; + mCallbackProxy.uiOnChangeViewingMode(mViewingMode); // remove the zoom control after double tap if (getSettings().getBuiltInZoomControls()) { if (mZoomButtonsController.isVisible()) { @@ -5033,21 +5127,27 @@ public class WebView extends AbsoluteLayout } else { mMaxZoomScale = restoreState.mMaxScale; } - if (useWideViewport && restoreState.mViewScale == 0) { - mInZoomOverview = ENABLE_DOUBLETAP_ZOOM - && settings.getLoadWithOverviewMode(); - } - mCallbackProxy.uiOnChangeViewingMode(true); - if (!mInZoomOverview) { - // We are going to start zoomed in. However, we - // truly want to show the title bar, and then hide - // it once the page has loaded - mCallbackProxy.uiChangeViewingModeOnFinishedLoad( - false, getOriginalUrl()); - } setNewZoomScale(mLastScale, false); setContentScrollTo(restoreState.mScrollX, restoreState.mScrollY); + if (!ENABLE_DOUBLETAP_ZOOM + || !settings.getLoadWithOverviewMode()) { + mMobileSite = false; + mViewingMode = NO_VIEWING_MODE; + } else { + mMobileSite = restoreState.mMobileSite; + if (useWideViewport + && restoreState.mViewScale == 0) { + mViewingMode = OVERVIEW_MODE; + mInZoomOverview = true; + } else if (mMobileSite + && (mScrollX | mScrollY) == 0) { + mViewingMode = TITLE_BAR_DISMISS_MODE; + } else { + mViewingMode = READING_MODE_WITH_TITLE_BAR; + } + } + mCallbackProxy.uiOnChangeViewingMode(mViewingMode); // 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 diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java index dee62b4..25cb249 100644 --- a/core/java/android/webkit/WebViewCore.java +++ b/core/java/android/webkit/WebViewCore.java @@ -258,20 +258,23 @@ final class WebViewCore { * @param url The URL that caused the overflow. * @param databaseIdentifier The identifier of the database. * @param currentQuota The current quota for the origin. + * @param estimatedSize The estimated size of the database. */ protected void exceededDatabaseQuota(String url, String databaseIdentifier, - long currentQuota) { + long currentQuota, + long estimatedSize) { // Inform the callback proxy of the quota overflow. Send an object // that encapsulates a call to the nativeSetDatabaseQuota method to // awaken the sleeping webcore thread when a decision from the // client to allow or deny quota is available. mCallbackProxy.onExceededDatabaseQuota(url, databaseIdentifier, - currentQuota, getUsedQuota(), new WebStorage.QuotaUpdater() { - public void updateQuota(long quota) { - nativeSetNewStorageLimit(quota); - } - }); + currentQuota, estimatedSize, getUsedQuota(), + new WebStorage.QuotaUpdater() { + public void updateQuota(long quota) { + nativeSetNewStorageLimit(quota); + } + }); } /** @@ -1505,6 +1508,7 @@ final class WebViewCore { float mTextWrapScale; int mScrollX; int mScrollY; + boolean mMobileSite; } static class DrawData { @@ -1859,6 +1863,7 @@ final class WebViewCore { mRestoreState.mMaxScale = mViewportMaximumScale / 100.0f; mRestoreState.mScrollX = mRestoredX; mRestoreState.mScrollY = mRestoredY; + mRestoreState.mMobileSite = (0 == mViewportWidth); if (mRestoredScale > 0) { if (mRestoredScreenWidthScale > 0) { mRestoreState.mTextWrapScale = diff --git a/core/java/android/widget/TabHost.java b/core/java/android/widget/TabHost.java index 1bee9db..ee3b91e 100644 --- a/core/java/android/widget/TabHost.java +++ b/core/java/android/widget/TabHost.java @@ -101,8 +101,8 @@ mTabHost.addTab(TAB_TAG_1, "Hello, world!", "Tab 1"); throw new RuntimeException( "Your TabHost must have a TabWidget whose id attribute is 'android.R.id.tabs'"); } - - // KeyListener to attach to all tabs. Detects non-navigation keys + + // KeyListener to attach to all tabs. Detects non-navigation keys // and relays them to the tab content. mTabKeyListener = new OnKeyListener() { public boolean onKey(View v, int keyCode, KeyEvent event) { @@ -114,14 +114,14 @@ mTabHost.addTab(TAB_TAG_1, "Hello, world!", "Tab 1"); case KeyEvent.KEYCODE_DPAD_DOWN: case KeyEvent.KEYCODE_ENTER: return false; - + } mTabContent.requestFocus(View.FOCUS_FORWARD); return mTabContent.dispatchKeyEvent(event); } - + }; - + mTabWidget.setTabSelectionListener(new TabWidget.OnTabSelectionChanged() { public void onTabSelectionChanged(int tabIndex, boolean clicked) { setCurrentTab(tabIndex); @@ -134,7 +134,7 @@ mTabHost.addTab(TAB_TAG_1, "Hello, world!", "Tab 1"); mTabContent = (FrameLayout) findViewById(com.android.internal.R.id.tabcontent); if (mTabContent == null) { throw new RuntimeException( - "Your TabHost must have a FrameLayout whose id attribute is " + "Your TabHost must have a FrameLayout whose id attribute is " + "'android.R.id.tabcontent'"); } } @@ -284,7 +284,7 @@ mTabHost.addTab(TAB_TAG_1, "Hello, world!", "Tab 1"); playSoundEffect(SoundEffectConstants.NAVIGATION_UP); return true; } - return handled; + return handled; } @@ -313,7 +313,7 @@ mTabHost.addTab(TAB_TAG_1, "Hello, world!", "Tab 1"); // Call the tab widget's focusCurrentTab(), instead of just // selecting the tab. mTabWidget.focusCurrentTab(mCurrentTab); - + // tab content mCurrentView = spec.mContentStrategy.getContentView(); @@ -368,7 +368,7 @@ mTabHost.addTab(TAB_TAG_1, "Hello, world!", "Tab 1"); public interface TabContentFactory { /** * Callback to make the tab contents - * + * * @param tag * Which tab was selected. * @return The view to display the contents of the selected tab. @@ -502,6 +502,8 @@ mTabHost.addTab(TAB_TAG_1, "Hello, world!", "Tab 1"); View tabIndicator = inflater.inflate(R.layout.tab_indicator, mTabWidget, // tab widget is the parent false); // no inflate params + // TODO: Move this to xml when bug 2068024 is resolved. + tabIndicator.getBackground().setDither(true); final TextView tv = (TextView) tabIndicator.findViewById(R.id.title); tv.setText(mLabel); @@ -529,6 +531,8 @@ mTabHost.addTab(TAB_TAG_1, "Hello, world!", "Tab 1"); View tabIndicator = inflater.inflate(R.layout.tab_indicator, mTabWidget, // tab widget is the parent false); // no inflate params + // TODO: Move this to xml when bug 2068024 is resolved. + tabIndicator.getBackground().setDither(true); final TextView tv = (TextView) tabIndicator.findViewById(R.id.title); tv.setText(mLabel); @@ -638,7 +642,7 @@ mTabHost.addTab(TAB_TAG_1, "Hello, world!", "Tab 1"); } } mLaunchedView = wd; - + // XXX Set FOCUS_AFTER_DESCENDANTS on embedded activities for now so they can get // focus if none of their children have it. They need focus to be able to // display menu items. diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java index 47f5c6c..889f37f 100644 --- a/core/java/android/widget/TabWidget.java +++ b/core/java/android/widget/TabWidget.java @@ -30,7 +30,7 @@ import android.view.View.OnFocusChangeListener; /** - * + * * Displays a list of tab labels representing each page in the parent's tab * collection. The container object for this widget is * {@link android.widget.TabHost TabHost}. When the user selects a tab, this @@ -64,21 +64,36 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener { super(context, attrs); initTabWidget(); - TypedArray a = + TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.TabWidget, defStyle, 0); a.recycle(); } - + @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { mStripMoved = true; super.onSizeChanged(w, h, oldw, oldh); } + @Override + protected int getChildDrawingOrder(int childCount, int i) { + // Always draw the selected tab last, so that drop shadows are drawn + // in the correct z-order. + if (i == childCount - 1) { + return mSelectedTab; + } else if (i >= mSelectedTab) { + return i + 1; + } else { + return i; + } + } + private void initTabWidget() { setOrientation(LinearLayout.HORIZONTAL); + mGroupFlags |= FLAG_USE_CHILD_DRAWING_ORDER; + mBottomLeftStrip = mContext.getResources().getDrawable( com.android.internal.R.drawable.tab_bottom_left); mBottomRightStrip = mContext.getResources().getDrawable( @@ -156,7 +171,7 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener { } super.childDrawableStateChanged(child); } - + @Override public void dispatchDraw(Canvas canvas) { super.dispatchDraw(canvas); @@ -169,17 +184,17 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener { } View selectedChild = getChildTabViewAt(mSelectedTab); - + mBottomLeftStrip.setState(selectedChild.getDrawableState()); mBottomRightStrip.setState(selectedChild.getDrawableState()); - + if (mStripMoved) { Rect selBounds = new Rect(); // Bounds of the selected tab indicator selBounds.left = selectedChild.getLeft(); selBounds.right = selectedChild.getRight(); final int myHeight = getHeight(); mBottomLeftStrip.setBounds( - Math.min(0, selBounds.left + Math.min(0, selBounds.left - mBottomLeftStrip.getIntrinsicWidth()), myHeight - mBottomLeftStrip.getIntrinsicHeight(), selBounds.left, @@ -187,12 +202,12 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener { mBottomRightStrip.setBounds( selBounds.right, myHeight - mBottomRightStrip.getIntrinsicHeight(), - Math.max(getWidth(), + Math.max(getWidth(), selBounds.right + mBottomRightStrip.getIntrinsicWidth()), myHeight); mStripMoved = false; } - + mBottomLeftStrip.draw(canvas); mBottomRightStrip.draw(canvas); } @@ -202,26 +217,26 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener { * This method is used to bring a tab to the front of the Widget, * and is used to post to the rest of the UI that a different tab * has been brought to the foreground. - * - * Note, this is separate from the traditional "focus" that is - * employed from the view logic. - * - * For instance, if we have a list in a tabbed view, a user may be - * navigating up and down the list, moving the UI focus (orange - * highlighting) through the list items. The cursor movement does - * not effect the "selected" tab though, because what is being - * scrolled through is all on the same tab. The selected tab only - * changes when we navigate between tabs (moving from the list view + * + * Note, this is separate from the traditional "focus" that is + * employed from the view logic. + * + * For instance, if we have a list in a tabbed view, a user may be + * navigating up and down the list, moving the UI focus (orange + * highlighting) through the list items. The cursor movement does + * not effect the "selected" tab though, because what is being + * scrolled through is all on the same tab. The selected tab only + * changes when we navigate between tabs (moving from the list view * to the next tabbed view, in this example). - * + * * To move both the focus AND the selected tab at once, please use - * {@link #setCurrentTab}. Normally, the view logic takes care of - * adjusting the focus, so unless you're circumventing the UI, + * {@link #setCurrentTab}. Normally, the view logic takes care of + * adjusting the focus, so unless you're circumventing the UI, * you'll probably just focus your interest here. - * + * * @param index The tab that you want to indicate as the selected * tab (tab brought to the front of the widget) - * + * * @see #focusCurrentTab */ public void setCurrentTab(int index) { @@ -234,19 +249,19 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener { getChildTabViewAt(mSelectedTab).setSelected(true); mStripMoved = true; } - + /** * Sets the current tab and focuses the UI on it. - * This method makes sure that the focused tab matches the selected - * tab, normally at {@link #setCurrentTab}. Normally this would not - * be an issue if we go through the UI, since the UI is responsible - * for calling TabWidget.onFocusChanged(), but in the case where we - * are selecting the tab programmatically, we'll need to make sure + * This method makes sure that the focused tab matches the selected + * tab, normally at {@link #setCurrentTab}. Normally this would not + * be an issue if we go through the UI, since the UI is responsible + * for calling TabWidget.onFocusChanged(), but in the case where we + * are selecting the tab programmatically, we'll need to make sure * focus keeps up. - * - * @param index The tab that you want focused (highlighted in orange) + * + * @param index The tab that you want focused (highlighted in orange) * and selected (tab brought to the front of the widget) - * + * * @see #setCurrentTab */ public void focusCurrentTab(int index) { @@ -254,18 +269,18 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener { // set the tab setCurrentTab(index); - + // change the focus if applicable. if (oldTab != index) { getChildTabViewAt(index).requestFocus(); } } - + @Override public void setEnabled(boolean enabled) { super.setEnabled(enabled); int count = getTabCount(); - + for (int i = 0; i < count; i++) { View child = getChildTabViewAt(i); child.setEnabled(enabled); @@ -318,7 +333,7 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener { getChildTabViewAt(mSelectedTab).requestFocus(); return; } - + if (hasFocus) { int i = 0; int numTabs = getTabCount(); @@ -354,7 +369,7 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener { /** * Informs the TabHost which tab was selected. It also indicates * if the tab was clicked/pressed or just focused into. - * + * * @param tabIndex index of the tab that was selected * @param clicked whether the selection changed due to a touch/click * or due to focus entering the tab through navigation. Pass true diff --git a/core/java/com/android/internal/widget/ContactHeaderWidget.java b/core/java/com/android/internal/widget/ContactHeaderWidget.java index 9e48777..8bae3e4 100644 --- a/core/java/com/android/internal/widget/ContactHeaderWidget.java +++ b/core/java/com/android/internal/widget/ContactHeaderWidget.java @@ -39,6 +39,7 @@ import android.provider.ContactsContract.Intents; import android.provider.ContactsContract.PhoneLookup; import android.provider.ContactsContract.Presence; import android.provider.ContactsContract.RawContacts; +import android.provider.ContactsContract.CommonDataKinds.Email; import android.provider.ContactsContract.CommonDataKinds.Photo; import android.provider.SocialContract.Activities; import android.util.AttributeSet; @@ -347,9 +348,8 @@ public class ContactHeaderWidget extends FrameLayout implements View.OnClickList public void bindFromEmail(String emailAddress) { Cursor c = null; try { - c = mContentResolver.query(Uri.withAppendedPath( - RawContacts.CONTENT_FILTER_EMAIL_URI, Uri.encode(emailAddress)), - EMAIL_LOOKUP_PROJECTION, null, null, null); + c = mContentResolver.query(Uri.withAppendedPath(Email.CONTENT_FILTER_EMAIL_URI, Uri + .encode(emailAddress)), EMAIL_LOOKUP_PROJECTION, null, null, null); if (c != null && c.moveToFirst()) { long contactId = c.getLong(EMAIL_LOOKUP_CONTACT_ID_COLUMN_INDEX); bindFromContactId(contactId); diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index f0b311c..58056bd 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -316,20 +316,14 @@ public class LockPatternUtils { /** * Set the state of whether the device is permanently locked, meaning the user - * must authenticate via other means. If false, that means the user has gone - * out of permanent lock, so the existing (forgotten) lock pattern needs to - * be cleared. + * must authenticate via other means. + * * @param locked Whether the user is permanently locked out until they verify their * credentials. Occurs after {@link #FAILED_ATTEMPTS_BEFORE_RESET} failed * attempts. */ public void setPermanentlyLocked(boolean locked) { setBoolean(LOCKOUT_PERMANENT_KEY, locked); - - if (!locked) { - setLockPatternEnabled(false); - saveLockPattern(null); - } } /** diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp index 21dde63..238ece1 100644 --- a/core/jni/android/graphics/Typeface.cpp +++ b/core/jni/android/graphics/Typeface.cpp @@ -141,6 +141,25 @@ static SkTypeface* Typeface_createFromFile(JNIEnv* env, jobject, jstring jpath) return SkTypeface::CreateFromFile(str.c_str()); } +#define MIN_GAMMA (0.1f) +#define MAX_GAMMA (10.0f) +static float pinGamma(float gamma) { + if (gamma < MIN_GAMMA) { + gamma = MIN_GAMMA; + } else if (gamma > MAX_GAMMA) { + gamma = MAX_GAMMA; + } + return gamma; +} + +extern void skia_set_text_gamma(float, float); + +static void Typeface_setGammaForText(JNIEnv* env, jobject, jfloat blackGamma, + jfloat whiteGamma) { + // Comment this out for release builds. This is only used during development + skia_set_text_gamma(pinGamma(blackGamma), pinGamma(whiteGamma)); +} + /////////////////////////////////////////////////////////////////////////////// static JNINativeMethod gTypefaceMethods[] = { @@ -151,7 +170,8 @@ static JNINativeMethod gTypefaceMethods[] = { { "nativeCreateFromAsset", "(Landroid/content/res/AssetManager;Ljava/lang/String;)I", (void*)Typeface_createFromAsset }, { "nativeCreateFromFile", "(Ljava/lang/String;)I", - (void*)Typeface_createFromFile } + (void*)Typeface_createFromFile }, + { "setGammaForText", "(FF)V", (void*)Typeface_setGammaForText }, }; int register_android_graphics_Typeface(JNIEnv* env); diff --git a/core/jni/android_server_BluetoothA2dpService.cpp b/core/jni/android_server_BluetoothA2dpService.cpp index 14da1fd..a185d8d 100644 --- a/core/jni/android_server_BluetoothA2dpService.cpp +++ b/core/jni/android_server_BluetoothA2dpService.cpp @@ -211,10 +211,6 @@ DBusHandlerResult a2dp_event_filter(DBusMessage *msg, JNIEnv *env) { method_onSinkPropertyChanged, env->NewStringUTF(c_path), str_array); - for (int i = 0; i < env->GetArrayLength(str_array); i++) { - env->DeleteLocalRef(env->GetObjectArrayElement(str_array, i)); - } - env->DeleteLocalRef(str_array); result = DBUS_HANDLER_RESULT_HANDLED; return result; } else { diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp index 527bf07..1bfabd7 100644 --- a/core/jni/android_server_BluetoothEventLoop.cpp +++ b/core/jni/android_server_BluetoothEventLoop.cpp @@ -57,6 +57,8 @@ static jmethodID method_onAgentCancel; typedef event_loop_native_data_t native_data_t; +#define EVENT_LOOP_REFS 10 + static inline native_data_t * get_native_data(JNIEnv *env, jobject object) { return (native_data_t *)(env->GetIntField(object, field_mNativeData)); @@ -679,6 +681,7 @@ static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg, native_data_t *nat; JNIEnv *env; DBusError err; + DBusHandlerResult ret; dbus_error_init(&err); @@ -694,6 +697,7 @@ static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg, dbus_message_get_interface(msg), dbus_message_get_member(msg), dbus_message_get_path(msg)); + env->PushLocalFrame(EVENT_LOOP_REFS); if (dbus_message_is_signal(msg, "org.bluez.Adapter", "DeviceFound")) { @@ -711,10 +715,9 @@ static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg, method_onDeviceFound, env->NewStringUTF(c_address), str_array); - env->DeleteLocalRef(str_array); } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg); - return DBUS_HANDLER_RESULT_HANDLED; + goto success; } else if (dbus_message_is_signal(msg, "org.bluez.Adapter", "DeviceDisappeared")) { @@ -726,7 +729,7 @@ static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg, env->CallVoidMethod(nat->me, method_onDeviceDisappeared, env->NewStringUTF(c_address)); } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg); - return DBUS_HANDLER_RESULT_HANDLED; + goto success; } else if (dbus_message_is_signal(msg, "org.bluez.Adapter", "DeviceCreated")) { @@ -739,7 +742,7 @@ static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg, method_onDeviceCreated, env->NewStringUTF(c_object_path)); } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg); - return DBUS_HANDLER_RESULT_HANDLED; + goto success; } else if (dbus_message_is_signal(msg, "org.bluez.Adapter", "DeviceRemoved")) { @@ -752,8 +755,7 @@ static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg, method_onDeviceRemoved, env->NewStringUTF(c_object_path)); } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg); - - return DBUS_HANDLER_RESULT_HANDLED; + goto success; } else if (dbus_message_is_signal(msg, "org.bluez.Adapter", "PropertyChanged")) { @@ -775,9 +777,8 @@ static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg, env->CallVoidMethod(nat->me, method_onPropertyChanged, str_array); - env->DeleteLocalRef(str_array); } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg); - return DBUS_HANDLER_RESULT_HANDLED; + goto success; } else if (dbus_message_is_signal(msg, "org.bluez.Device", "PropertyChanged")) { @@ -788,12 +789,17 @@ static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg, method_onDevicePropertyChanged, env->NewStringUTF(remote_device_path), str_array); - env->DeleteLocalRef(str_array); } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg); - return DBUS_HANDLER_RESULT_HANDLED; - + goto success; } - return a2dp_event_filter(msg, env); + + ret = a2dp_event_filter(msg, env); + env->PopLocalFrame(NULL); + return ret; + +success: + env->PopLocalFrame(NULL); + return DBUS_HANDLER_RESULT_HANDLED; } // Called by dbus during WaitForAndDispatchEventNative() @@ -811,6 +817,8 @@ DBusHandlerResult agent_event_filter(DBusConnection *conn, if (nat == NULL) return DBUS_HANDLER_RESULT_HANDLED; nat->vm->GetEnv((void**)&env, nat->envVer); + env->PushLocalFrame(EVENT_LOOP_REFS); + if (dbus_message_is_method_call(msg, "org.bluez.Agent", "Cancel")) { @@ -820,11 +828,11 @@ DBusHandlerResult agent_event_filter(DBusConnection *conn, DBusMessage *reply = dbus_message_new_method_return(msg); if (!reply) { LOGE("%s: Cannot create message reply\n", __FUNCTION__); - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + goto failure; } dbus_connection_send(nat->conn, reply, NULL); dbus_message_unref(reply); - return DBUS_HANDLER_RESULT_HANDLED; + goto success; } else if (dbus_message_is_method_call(msg, "org.bluez.Agent", "Authorize")) { @@ -835,7 +843,7 @@ DBusHandlerResult agent_event_filter(DBusConnection *conn, DBUS_TYPE_STRING, &uuid, DBUS_TYPE_INVALID)) { LOGE("%s: Invalid arguments for Authorize() method", __FUNCTION__); - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + goto failure; } LOGV("... object_path = %s", object_path); @@ -850,7 +858,7 @@ DBusHandlerResult agent_event_filter(DBusConnection *conn, DBusMessage *reply = dbus_message_new_method_return(msg); if (!reply) { LOGE("%s: Cannot create message reply\n", __FUNCTION__); - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + goto failure; } dbus_connection_send(nat->conn, reply, NULL); dbus_message_unref(reply); @@ -859,12 +867,12 @@ DBusHandlerResult agent_event_filter(DBusConnection *conn, "org.bluez.Error.Rejected", "Authorization rejected"); if (!reply) { LOGE("%s: Cannot create message reply\n", __FUNCTION__); - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + goto failure; } dbus_connection_send(nat->conn, reply, NULL); dbus_message_unref(reply); } - return DBUS_HANDLER_RESULT_HANDLED; + goto success; } else if (dbus_message_is_method_call(msg, "org.bluez.Agent", "RequestPinCode")) { char *object_path; @@ -872,14 +880,14 @@ DBusHandlerResult agent_event_filter(DBusConnection *conn, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)) { LOGE("%s: Invalid arguments for RequestPinCode() method", __FUNCTION__); - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + goto failure; } dbus_message_ref(msg); // increment refcount because we pass to java env->CallVoidMethod(nat->me, method_onRequestPinCode, env->NewStringUTF(object_path), int(msg)); - return DBUS_HANDLER_RESULT_HANDLED; + goto success; } else if (dbus_message_is_method_call(msg, "org.bluez.Agent", "RequestPasskey")) { char *object_path; @@ -887,13 +895,14 @@ DBusHandlerResult agent_event_filter(DBusConnection *conn, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)) { LOGE("%s: Invalid arguments for RequestPasskey() method", __FUNCTION__); - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + goto failure; } dbus_message_ref(msg); // increment refcount because we pass to java env->CallVoidMethod(nat->me, method_onRequestPasskey, env->NewStringUTF(object_path), int(msg)); + goto success; } else if (dbus_message_is_method_call(msg, "org.bluez.Agent", "RequestConfirmation")) { char *object_path; @@ -903,7 +912,7 @@ DBusHandlerResult agent_event_filter(DBusConnection *conn, DBUS_TYPE_UINT32, &passkey, DBUS_TYPE_INVALID)) { LOGE("%s: Invalid arguments for RequestConfirmation() method", __FUNCTION__); - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + goto failure; } dbus_message_ref(msg); // increment refcount because we pass to java @@ -911,23 +920,30 @@ DBusHandlerResult agent_event_filter(DBusConnection *conn, env->NewStringUTF(object_path), passkey, int(msg)); - return DBUS_HANDLER_RESULT_HANDLED; + goto success; } else if (dbus_message_is_method_call(msg, "org.bluez.Agent", "Release")) { // reply DBusMessage *reply = dbus_message_new_method_return(msg); if (!reply) { LOGE("%s: Cannot create message reply\n", __FUNCTION__); - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + goto failure; } dbus_connection_send(nat->conn, reply, NULL); dbus_message_unref(reply); - return DBUS_HANDLER_RESULT_HANDLED; + goto success; } else { LOGV("%s:%s is ignored", dbus_message_get_interface(msg), dbus_message_get_member(msg)); } +failure: + env->PopLocalFrame(NULL); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + +success: + env->PopLocalFrame(NULL); + return DBUS_HANDLER_RESULT_HANDLED; + } #endif diff --git a/core/jni/android_server_BluetoothService.cpp b/core/jni/android_server_BluetoothService.cpp index 326052b..d1901b4 100644 --- a/core/jni/android_server_BluetoothService.cpp +++ b/core/jni/android_server_BluetoothService.cpp @@ -46,6 +46,7 @@ namespace android { #define BLUETOOTH_CLASS_ERROR 0xFF000000 +#define PROPERTIES_NREFS 10 #ifdef HAVE_BLUETOOTH // We initialize these variables when we load class @@ -576,11 +577,16 @@ static jobjectArray getDevicePropertiesNative(JNIEnv *env, jobject object, LOGE("DBus reply is NULL in function %s", __FUNCTION__); return NULL; } + env->PushLocalFrame(PROPERTIES_NREFS); + DBusMessageIter iter; jobjectArray str_array = NULL; if (dbus_message_iter_init(reply, &iter)) str_array = parse_remote_device_properties(env, &iter); dbus_message_unref(reply); + + env->PopLocalFrame(NULL); + return str_array; } #endif @@ -607,11 +613,15 @@ static jobjectArray getAdapterPropertiesNative(JNIEnv *env, jobject object) { LOGE("DBus reply is NULL in function %s", __FUNCTION__); return NULL; } + env->PushLocalFrame(PROPERTIES_NREFS); + DBusMessageIter iter; jobjectArray str_array = NULL; if (dbus_message_iter_init(reply, &iter)) str_array = parse_adapter_properties(env, &iter); dbus_message_unref(reply); + + env->PopLocalFrame(NULL); return str_array; } #endif diff --git a/core/res/res/color/tab_indicator_text.xml b/core/res/res/color/tab_indicator_text.xml index ce321db..5f5c2a4 100644 --- a/core/res/res/color/tab_indicator_text.xml +++ b/core/res/res/color/tab_indicator_text.xml @@ -15,6 +15,6 @@ --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_selected="true" android:color="#323232"/> - <item android:color="#FFF"/> <!-- not selected --> + <item android:state_selected="true" android:color="#ffffff"/> + <item android:color="#808080"/> <!-- not selected --> </selector> diff --git a/core/res/res/drawable/dark_header.9.png b/core/res/res/drawable/dark_header.9.png Binary files differindex 8fa5f09..7242b61 100644 --- a/core/res/res/drawable/dark_header.9.png +++ b/core/res/res/drawable/dark_header.9.png diff --git a/core/res/res/drawable/dark_header_dither.xml b/core/res/res/drawable/dark_header_dither.xml new file mode 100644 index 0000000..0741fa4 --- /dev/null +++ b/core/res/res/drawable/dark_header_dither.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<nine-patch xmlns:android="http://schemas.android.com/apk/res/android" + android:src="@drawable/dark_header" + android:dither="true" +/> diff --git a/core/res/res/drawable/divider_horizontal_bright.9.png b/core/res/res/drawable/divider_horizontal_bright.9.png Binary files differindex 144fc22..395227a 100644 --- a/core/res/res/drawable/divider_horizontal_bright.9.png +++ b/core/res/res/drawable/divider_horizontal_bright.9.png diff --git a/core/res/res/drawable/divider_horizontal_bright_opaque.9.png b/core/res/res/drawable/divider_horizontal_bright_opaque.9.png Binary files differindex 30c9b2b..5c537ee 100644 --- a/core/res/res/drawable/divider_horizontal_bright_opaque.9.png +++ b/core/res/res/drawable/divider_horizontal_bright_opaque.9.png diff --git a/core/res/res/drawable/divider_horizontal_dark.9.png b/core/res/res/drawable/divider_horizontal_dark.9.png Binary files differindex 08838ca..548d0bd 100644 --- a/core/res/res/drawable/divider_horizontal_dark.9.png +++ b/core/res/res/drawable/divider_horizontal_dark.9.png diff --git a/core/res/res/drawable/divider_horizontal_dark_opaque.9.png b/core/res/res/drawable/divider_horizontal_dark_opaque.9.png Binary files differindex ce21acd..8f35315 100644 --- a/core/res/res/drawable/divider_horizontal_dark_opaque.9.png +++ b/core/res/res/drawable/divider_horizontal_dark_opaque.9.png diff --git a/core/res/res/drawable/divider_vertical_bright.9.png b/core/res/res/drawable/divider_vertical_bright.9.png Binary files differindex da6e4ec..395227a 100644 --- a/core/res/res/drawable/divider_vertical_bright.9.png +++ b/core/res/res/drawable/divider_vertical_bright.9.png diff --git a/core/res/res/drawable/divider_vertical_bright_opaque.9.png b/core/res/res/drawable/divider_vertical_bright_opaque.9.png Binary files differnew file mode 100644 index 0000000..5c537ee --- /dev/null +++ b/core/res/res/drawable/divider_vertical_bright_opaque.9.png diff --git a/core/res/res/drawable/divider_vertical_dark.9.png b/core/res/res/drawable/divider_vertical_dark.9.png Binary files differnew file mode 100644 index 0000000..548d0bd --- /dev/null +++ b/core/res/res/drawable/divider_vertical_dark.9.png diff --git a/core/res/res/drawable/divider_vertical_dark_opaque.9.png b/core/res/res/drawable/divider_vertical_dark_opaque.9.png Binary files differnew file mode 100644 index 0000000..8f35315 --- /dev/null +++ b/core/res/res/drawable/divider_vertical_dark_opaque.9.png diff --git a/core/res/res/drawable/fasttrack_badge_dark.xml b/core/res/res/drawable/fasttrack_badge_dark.xml new file mode 100644 index 0000000..c60d403 --- /dev/null +++ b/core/res/res/drawable/fasttrack_badge_dark.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item + android:state_focused="false" + android:state_selected="false" + android:state_pressed="false" + android:drawable="@drawable/fasttrack_badge_dark_normal" /> + + <item + android:state_pressed="true" + android:drawable="@drawable/fasttrack_badge_dark_pressed" /> + +</selector> diff --git a/core/res/res/drawable/fasttrack_badge_dark_normal.9.png b/core/res/res/drawable/fasttrack_badge_dark_normal.9.png Binary files differnew file mode 100644 index 0000000..52bb08c --- /dev/null +++ b/core/res/res/drawable/fasttrack_badge_dark_normal.9.png diff --git a/core/res/res/drawable/fasttrack_badge_dark_pressed.9.png b/core/res/res/drawable/fasttrack_badge_dark_pressed.9.png Binary files differnew file mode 100644 index 0000000..84a6783 --- /dev/null +++ b/core/res/res/drawable/fasttrack_badge_dark_pressed.9.png diff --git a/core/res/res/drawable/fasttrack_badge_light.xml b/core/res/res/drawable/fasttrack_badge_light.xml new file mode 100644 index 0000000..fd81258 --- /dev/null +++ b/core/res/res/drawable/fasttrack_badge_light.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item + android:state_focused="false" + android:state_selected="false" + android:state_pressed="false" + android:drawable="@drawable/fasttrack_badge_light_normal" /> + + <item + android:state_pressed="true" + android:drawable="@drawable/fasttrack_badge_light_pressed" /> + +</selector> diff --git a/core/res/res/drawable/fasttrack_badge_light_normal.9.png b/core/res/res/drawable/fasttrack_badge_light_normal.9.png Binary files differnew file mode 100644 index 0000000..595b179 --- /dev/null +++ b/core/res/res/drawable/fasttrack_badge_light_normal.9.png diff --git a/core/res/res/drawable/fasttrack_badge_light_pressed.9.png b/core/res/res/drawable/fasttrack_badge_light_pressed.9.png Binary files differnew file mode 100644 index 0000000..8e3f557 --- /dev/null +++ b/core/res/res/drawable/fasttrack_badge_light_pressed.9.png diff --git a/core/res/res/drawable/fasttrack_badge_middle_normal.9.png b/core/res/res/drawable/fasttrack_badge_middle_normal.9.png Binary files differindex 1ac6ef9..07df063 100644 --- a/core/res/res/drawable/fasttrack_badge_middle_normal.9.png +++ b/core/res/res/drawable/fasttrack_badge_middle_normal.9.png diff --git a/core/res/res/drawable/fasttrack_badge_middle_pressed.9.png b/core/res/res/drawable/fasttrack_badge_middle_pressed.9.png Binary files differindex 33921ba..ded95f6 100644 --- a/core/res/res/drawable/fasttrack_badge_middle_pressed.9.png +++ b/core/res/res/drawable/fasttrack_badge_middle_pressed.9.png diff --git a/core/res/res/drawable/light_header.9.png b/core/res/res/drawable/light_header.9.png Binary files differindex ad5dce1..fcd9e2d 100644 --- a/core/res/res/drawable/light_header.9.png +++ b/core/res/res/drawable/light_header.9.png diff --git a/core/res/res/drawable/light_header_dither.xml b/core/res/res/drawable/light_header_dither.xml new file mode 100644 index 0000000..c54b6c2 --- /dev/null +++ b/core/res/res/drawable/light_header_dither.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<nine-patch xmlns:android="http://schemas.android.com/apk/res/android" + android:src="@drawable/light_header" + android:dither="true" +/> diff --git a/core/res/res/drawable/stat_sys_data_connected_1x.png b/core/res/res/drawable/stat_sys_data_connected_1x.png Binary files differnew file mode 100644 index 0000000..130724f --- /dev/null +++ b/core/res/res/drawable/stat_sys_data_connected_1x.png diff --git a/core/res/res/drawable/stat_sys_data_connected_1xrtt.png b/core/res/res/drawable/stat_sys_data_connected_1xrtt.png Binary files differdeleted file mode 100644 index c2fbbdf..0000000 --- a/core/res/res/drawable/stat_sys_data_connected_1xrtt.png +++ /dev/null diff --git a/core/res/res/drawable/stat_sys_data_connected_evdo.png b/core/res/res/drawable/stat_sys_data_connected_evdo.png Binary files differdeleted file mode 100644 index db9f282..0000000 --- a/core/res/res/drawable/stat_sys_data_connected_evdo.png +++ /dev/null diff --git a/core/res/res/drawable/stat_sys_data_dormant_1xrtt.png b/core/res/res/drawable/stat_sys_data_dormant_1xrtt.png Binary files differdeleted file mode 100755 index 11c2eae..0000000 --- a/core/res/res/drawable/stat_sys_data_dormant_1xrtt.png +++ /dev/null diff --git a/core/res/res/drawable/stat_sys_data_dormant_evdo.png b/core/res/res/drawable/stat_sys_data_dormant_evdo.png Binary files differdeleted file mode 100755 index 811fcb5..0000000 --- a/core/res/res/drawable/stat_sys_data_dormant_evdo.png +++ /dev/null diff --git a/core/res/res/drawable/stat_sys_data_in_1x.png b/core/res/res/drawable/stat_sys_data_in_1x.png Binary files differnew file mode 100644 index 0000000..3155e632 --- /dev/null +++ b/core/res/res/drawable/stat_sys_data_in_1x.png diff --git a/core/res/res/drawable/stat_sys_data_in_1xrtt.png b/core/res/res/drawable/stat_sys_data_in_1xrtt.png Binary files differdeleted file mode 100644 index a421a8a..0000000 --- a/core/res/res/drawable/stat_sys_data_in_1xrtt.png +++ /dev/null diff --git a/core/res/res/drawable/stat_sys_data_in_evdo.png b/core/res/res/drawable/stat_sys_data_in_evdo.png Binary files differdeleted file mode 100644 index 54f55ba..0000000 --- a/core/res/res/drawable/stat_sys_data_in_evdo.png +++ /dev/null diff --git a/core/res/res/drawable/stat_sys_data_inandout_1x.png b/core/res/res/drawable/stat_sys_data_inandout_1x.png Binary files differnew file mode 100644 index 0000000..1017e3b --- /dev/null +++ b/core/res/res/drawable/stat_sys_data_inandout_1x.png diff --git a/core/res/res/drawable/stat_sys_data_inandout_1xrtt.png b/core/res/res/drawable/stat_sys_data_inandout_1xrtt.png Binary files differdeleted file mode 100644 index 1a94cdf..0000000 --- a/core/res/res/drawable/stat_sys_data_inandout_1xrtt.png +++ /dev/null diff --git a/core/res/res/drawable/stat_sys_data_inandout_evdo.png b/core/res/res/drawable/stat_sys_data_inandout_evdo.png Binary files differdeleted file mode 100644 index 7aa6f00..0000000 --- a/core/res/res/drawable/stat_sys_data_inandout_evdo.png +++ /dev/null diff --git a/core/res/res/drawable/stat_sys_data_out_1x.png b/core/res/res/drawable/stat_sys_data_out_1x.png Binary files differnew file mode 100644 index 0000000..5418791 --- /dev/null +++ b/core/res/res/drawable/stat_sys_data_out_1x.png diff --git a/core/res/res/drawable/stat_sys_data_out_1xrtt.png b/core/res/res/drawable/stat_sys_data_out_1xrtt.png Binary files differdeleted file mode 100644 index 74fd351..0000000 --- a/core/res/res/drawable/stat_sys_data_out_1xrtt.png +++ /dev/null diff --git a/core/res/res/drawable/stat_sys_data_out_evdo.png b/core/res/res/drawable/stat_sys_data_out_evdo.png Binary files differdeleted file mode 100644 index 21e19a7..0000000 --- a/core/res/res/drawable/stat_sys_data_out_evdo.png +++ /dev/null diff --git a/core/res/res/drawable/stat_sys_signal_0_cdma.png b/core/res/res/drawable/stat_sys_signal_0_cdma.png Binary files differdeleted file mode 100644 index 0ef7d53..0000000 --- a/core/res/res/drawable/stat_sys_signal_0_cdma.png +++ /dev/null diff --git a/core/res/res/drawable/stat_sys_signal_1_cdma.png b/core/res/res/drawable/stat_sys_signal_1_cdma.png Binary files differdeleted file mode 100644 index f4839d4..0000000 --- a/core/res/res/drawable/stat_sys_signal_1_cdma.png +++ /dev/null diff --git a/core/res/res/drawable/stat_sys_signal_2_cdma.png b/core/res/res/drawable/stat_sys_signal_2_cdma.png Binary files differdeleted file mode 100644 index e25a99c..0000000 --- a/core/res/res/drawable/stat_sys_signal_2_cdma.png +++ /dev/null diff --git a/core/res/res/drawable/stat_sys_signal_3_cdma.png b/core/res/res/drawable/stat_sys_signal_3_cdma.png Binary files differdeleted file mode 100644 index d828d99..0000000 --- a/core/res/res/drawable/stat_sys_signal_3_cdma.png +++ /dev/null diff --git a/core/res/res/drawable/stat_sys_signal_4_cdma.png b/core/res/res/drawable/stat_sys_signal_4_cdma.png Binary files differdeleted file mode 100644 index 53a31ea..0000000 --- a/core/res/res/drawable/stat_sys_signal_4_cdma.png +++ /dev/null diff --git a/core/res/res/drawable/stat_sys_signal_cdma_0.png b/core/res/res/drawable/stat_sys_signal_cdma_0.png Binary files differdeleted file mode 100755 index 0ef7d53..0000000 --- a/core/res/res/drawable/stat_sys_signal_cdma_0.png +++ /dev/null diff --git a/core/res/res/drawable/stat_sys_signal_cdma_1.png b/core/res/res/drawable/stat_sys_signal_cdma_1.png Binary files differdeleted file mode 100755 index f4839d4..0000000 --- a/core/res/res/drawable/stat_sys_signal_cdma_1.png +++ /dev/null diff --git a/core/res/res/drawable/stat_sys_signal_cdma_2.png b/core/res/res/drawable/stat_sys_signal_cdma_2.png Binary files differdeleted file mode 100755 index e25a99c..0000000 --- a/core/res/res/drawable/stat_sys_signal_cdma_2.png +++ /dev/null diff --git a/core/res/res/drawable/stat_sys_signal_cdma_3.png b/core/res/res/drawable/stat_sys_signal_cdma_3.png Binary files differdeleted file mode 100755 index d828d99..0000000 --- a/core/res/res/drawable/stat_sys_signal_cdma_3.png +++ /dev/null diff --git a/core/res/res/drawable/stat_sys_signal_cdma_4.png b/core/res/res/drawable/stat_sys_signal_cdma_4.png Binary files differdeleted file mode 100755 index 53a31ea..0000000 --- a/core/res/res/drawable/stat_sys_signal_cdma_4.png +++ /dev/null diff --git a/core/res/res/drawable/stat_sys_signal_evdo_0.png b/core/res/res/drawable/stat_sys_signal_evdo_0.png Binary files differdeleted file mode 100755 index 1b8aec7..0000000 --- a/core/res/res/drawable/stat_sys_signal_evdo_0.png +++ /dev/null diff --git a/core/res/res/drawable/stat_sys_signal_evdo_1.png b/core/res/res/drawable/stat_sys_signal_evdo_1.png Binary files differdeleted file mode 100755 index 7ce01fd..0000000 --- a/core/res/res/drawable/stat_sys_signal_evdo_1.png +++ /dev/null diff --git a/core/res/res/drawable/stat_sys_signal_evdo_2.png b/core/res/res/drawable/stat_sys_signal_evdo_2.png Binary files differdeleted file mode 100755 index 890cd59..0000000 --- a/core/res/res/drawable/stat_sys_signal_evdo_2.png +++ /dev/null diff --git a/core/res/res/drawable/stat_sys_signal_evdo_3.png b/core/res/res/drawable/stat_sys_signal_evdo_3.png Binary files differdeleted file mode 100755 index 712c640..0000000 --- a/core/res/res/drawable/stat_sys_signal_evdo_3.png +++ /dev/null diff --git a/core/res/res/drawable/stat_sys_signal_evdo_4.png b/core/res/res/drawable/stat_sys_signal_evdo_4.png Binary files differdeleted file mode 100755 index f0537dd..0000000 --- a/core/res/res/drawable/stat_sys_signal_evdo_4.png +++ /dev/null diff --git a/core/res/res/drawable/tab_focus.9.png b/core/res/res/drawable/tab_focus.9.png Binary files differindex 2806da9..d9bcc57 100755 --- a/core/res/res/drawable/tab_focus.9.png +++ b/core/res/res/drawable/tab_focus.9.png diff --git a/core/res/res/drawable/tab_focus_bar_left.9.png b/core/res/res/drawable/tab_focus_bar_left.9.png Binary files differindex 21421cb..2536d94 100755 --- a/core/res/res/drawable/tab_focus_bar_left.9.png +++ b/core/res/res/drawable/tab_focus_bar_left.9.png diff --git a/core/res/res/drawable/tab_focus_bar_right.9.png b/core/res/res/drawable/tab_focus_bar_right.9.png Binary files differindex b6304d9..2536d94 100755 --- a/core/res/res/drawable/tab_focus_bar_right.9.png +++ b/core/res/res/drawable/tab_focus_bar_right.9.png diff --git a/core/res/res/drawable/tab_press.9.png b/core/res/res/drawable/tab_press.9.png Binary files differindex 3fb717c..3332660 100755 --- a/core/res/res/drawable/tab_press.9.png +++ b/core/res/res/drawable/tab_press.9.png diff --git a/core/res/res/drawable/tab_press_bar_left.9.png b/core/res/res/drawable/tab_press_bar_left.9.png Binary files differindex 95ef2d3..d2c75e3 100755 --- a/core/res/res/drawable/tab_press_bar_left.9.png +++ b/core/res/res/drawable/tab_press_bar_left.9.png diff --git a/core/res/res/drawable/tab_press_bar_right.9.png b/core/res/res/drawable/tab_press_bar_right.9.png Binary files differindex 7ae938b5..d2c75e3 100755 --- a/core/res/res/drawable/tab_press_bar_right.9.png +++ b/core/res/res/drawable/tab_press_bar_right.9.png diff --git a/core/res/res/drawable/tab_selected.9.png b/core/res/res/drawable/tab_selected.9.png Binary files differindex f929d99..54190ea 100644 --- a/core/res/res/drawable/tab_selected.9.png +++ b/core/res/res/drawable/tab_selected.9.png diff --git a/core/res/res/drawable/tab_selected_bar_left.9.png b/core/res/res/drawable/tab_selected_bar_left.9.png Binary files differindex 58e2d35..d20f3a2 100755 --- a/core/res/res/drawable/tab_selected_bar_left.9.png +++ b/core/res/res/drawable/tab_selected_bar_left.9.png diff --git a/core/res/res/drawable/tab_selected_bar_right.9.png b/core/res/res/drawable/tab_selected_bar_right.9.png Binary files differindex 0c9c8dd..d20f3a2 100755 --- a/core/res/res/drawable/tab_selected_bar_right.9.png +++ b/core/res/res/drawable/tab_selected_bar_right.9.png diff --git a/core/res/res/drawable/tab_unselected.9.png b/core/res/res/drawable/tab_unselected.9.png Binary files differindex 9036c1d..1b8a69c 100644 --- a/core/res/res/drawable/tab_unselected.9.png +++ b/core/res/res/drawable/tab_unselected.9.png diff --git a/core/res/res/layout/contact_header.xml b/core/res/res/layout/contact_header.xml index 8c1957d..ba91e00 100644 --- a/core/res/res/layout/contact_header.xml +++ b/core/res/res/layout/contact_header.xml @@ -24,8 +24,8 @@ android:gravity="center_vertical"> <ImageView android:id="@+id/photo" - android:layout_width="56dip" - android:layout_height="64dip" + android:layout_width="48dip" + android:layout_height="52dip" android:layout_marginRight="10dip" android:layout_marginLeft="10dip" android:scaleType="fitCenter" diff --git a/core/res/res/layout/keyguard_screen_glogin_unlock.xml b/core/res/res/layout/keyguard_screen_glogin_unlock.xml index 74ff3b0..6e00d11 100644 --- a/core/res/res/layout/keyguard_screen_glogin_unlock.xml +++ b/core/res/res/layout/keyguard_screen_glogin_unlock.xml @@ -42,7 +42,6 @@ android:gravity="center_vertical" android:drawableLeft="@drawable/ic_lock_idle_lock" android:drawablePadding="5dip" - android:text="@android:string/lockscreen_glogin_too_many_attempts" /> <!-- spacer below header --> diff --git a/core/res/res/layout/tab_indicator.xml b/core/res/res/layout/tab_indicator.xml index fcf0b5e..e3ea555 100644 --- a/core/res/res/layout/tab_indicator.xml +++ b/core/res/res/layout/tab_indicator.xml @@ -18,6 +18,8 @@ android:layout_width="0dip" android:layout_height="64dip" android:layout_weight="1" + android:layout_marginLeft="-4px" + android:layout_marginRight="-4px" android:orientation="vertical" android:background="@android:drawable/tab_indicator"> diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml index 0fd6861..1057c09 100644 --- a/core/res/res/values/colors.xml +++ b/core/res/res/values/colors.xml @@ -19,7 +19,7 @@ --> <resources> <drawable name="screen_background_light">#fff9f9f9</drawable> - <drawable name="screen_background_dark">#ff1a1a1a</drawable> + <drawable name="screen_background_dark">#ff202020</drawable> <drawable name="status_bar_closed_default_background">#ff000000</drawable> <drawable name="status_bar_opened_default_background">#ff000000</drawable> <drawable name="search_bar_default_color">#ff000000</drawable> @@ -28,7 +28,7 @@ <color name="white">#ffffffff</color> <color name="black">#ff000000</color> <color name="transparent">#00000000</color> - <color name="background_dark">#ff1a1a1a</color> + <color name="background_dark">#ff202020</color> <color name="bright_foreground_dark">#ffffffff</color> <color name="bright_foreground_dark_disabled">#80ffffff</color> <color name="bright_foreground_dark_inverse">#ff000000</color> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 92c776c..9966930 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -35,10 +35,6 @@ <!-- The duration (in milliseconds) of a long animation. --> <integer name="config_longAnimTime">300</integer> - <!-- Flag indicating whether Last Name comes before First Name. - This becomes true in Japan, for example.--> - <bool name="config_lastname_comes_before_firstname">false</bool> - <!-- This string array should be overridden by the device to present a list of network attributes. This is used by the connectivity manager to decide which networks can coexist based on the hardward --> <!-- An Array of "[type-name],[associated radio-name],[priority] --> <string-array translatable="false" name="networkAttributes"> @@ -57,4 +53,10 @@ <item>"wifi,1,1"</item> <item>"mobile,0,1"</item> </string-array> + + <!-- The number of degrees to rotate the display when the keyboard is open. --> + <integer name="config_lidOpenRotation">90</integer> + + <!-- The number of degrees to rotate the display when the device is in a dock. --> + <integer name="config_dockedRotation">90</integer> </resources> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index c14ecc0..7dc4ff9 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -1294,7 +1294,11 @@ their lock gesture --> <string name="lockscreen_forgot_pattern_button_text">Forgot pattern?</string> - <!-- Title of the unlock screen that uses your Google login and password --> + <!-- Title of the unlock screen that uses your Google login and password when the user hit + the 'forgot pattern' button.--> + <string name="lockscreen_glogin_forgot_pattern">Account unlock</string> + <!-- Title of the unlock screen that uses your Google login and password when the user attempted + too many patterns and we are forcing them to use their account instead. --> <string name="lockscreen_glogin_too_many_attempts">Too many pattern attempts!</string> <!-- In the unlock screen, message telling the user that they need to use their Google login and password to unlock the phone --> <string name="lockscreen_glogin_instructions">To unlock, sign in with your Google account</string> @@ -1307,6 +1311,9 @@ <!-- Displayed to the user when unlocking the phone with a username and password fails. --> <string name="lockscreen_glogin_invalid_input">Invalid username or password.</string> + <!-- Displayed in a progress dialog while a username and password are being checked. --> + <string name="lockscreen_glogin_checking_password">Checking...</string> + <!-- A format string for 12-hour time of day, just the hour, not the minute, with lower-case "am" or "pm" (example: "3pm"). --> <string name="hour_ampm">"<xliff:g id="hour" example="3">%-l</xliff:g><xliff:g id="ampm" example="pm">%P</xliff:g>"</string> @@ -1641,7 +1648,7 @@ <string name="copyUrl">Copy URL</string> <!-- EditText context menu --> - <string name="inputMethod">Input Method</string> + <string name="inputMethod">Input method</string> <!-- Item on EditText context menu, used to add a word to the input method dictionary. --> diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml index 10d2093..3950cb1 100644 --- a/core/res/res/values/styles.xml +++ b/core/res/res/values/styles.xml @@ -339,7 +339,7 @@ </style> <style name="Widget.TextView.ListSeparator"> - <item name="android:background">@android:drawable/dark_header</item> + <item name="android:background">@android:drawable/dark_header_dither</item> <item name="android:layout_width">fill_parent</item> <item name="android:layout_height">25dip</item> <item name="android:textStyle">bold</item> @@ -351,7 +351,7 @@ <style name="Widget.TextView.ListSeparator.White"> <item name="android:textColor">?textColorPrimaryInverse</item> - <item name="android:background">@android:drawable/light_header</item> + <item name="android:background">@android:drawable/light_header_dither</item> </style> <style name="Widget.EditText"> diff --git a/docs/html/guide/developing/device.jd b/docs/html/guide/developing/device.jd index 2c42e78..9dea053 100644 --- a/docs/html/guide/developing/device.jd +++ b/docs/html/guide/developing/device.jd @@ -7,11 +7,12 @@ page.title=Developing on a Device <ol> <li><a href="#devices">Available Devices</a> <ol> - <li><a href="#g1">T-Mobile G1</a></li> + <li><a href="#consumer">Consumer devices</a></li> <li><a href="#dev-phone-1">Android Dev Phone 1</a></li> </ol> </li> <li><a href="#setting-up">Setting up a Device for Development</a></li> + <li><a href="#WinUsbDriver">Installing the WinUsb Driver</a></li> </ol> </div> </div> @@ -23,20 +24,24 @@ developing and debugging.</p> <h2 id="devices">Available Devices</h2> -<p>While developers can use regular -consumer devices purchased at retail to test and use their apps, some developers -may choose not to use a retail device, preferring an unlocked or no-contract -device. Here are some options for obtaining devices capable of testing your applications.</p> +<p>Here are some options for obtaining devices capable of testing your applications.</p> -<h3 id="g1">T-Mobile G1</h3> +<h3 id="consumer">Consumer devices</h3> -<p>The T-Mobile G1 device makes an excellent development device. You can write -applications in the SDK and install them on the G1, then run them as users -would, using the same hardware, system, and network.</p> +<p>It's likely that one of your local mobile carriers offers an Android-powered device. +Any Android-powered device (even one bought from your mobile carrier) is a perfectly good +device for running and testing your own Android applications. +You can write applications using the Android SDK and then install them +directly onto the device for testing.</p> + +<p>Check with the service providers in your area to determine which Android-powered +devices are available.</p> + +<p>Be aware that consumer devices are not designed to allow system image updates by the +user. If you're interested in manually updating the device with custom system images, then +you'll need a developer device such as the <a href="#dev-phone-1">Android Dev Phone 1</a>.</p> -<p>For more information about obtaining a G1, visit the <a -href="http://www.t-mobileg1.com">T-Mobile G1 site</a>. </p> <h3 id="dev-phone-1">Android Dev Phone 1</h3> @@ -60,6 +65,7 @@ href="http://www.t-mobileg1.com">T-Mobile G1 site</a>. </p> </ul> </div> </div> + <p>The Android Dev Phone 1 is a SIM-unlocked and hardware-unlocked device that is designed for advanced developers. The device ships with a system image that is fully compatible with Android 1.0, so you can rely on it when developing your @@ -67,7 +73,7 @@ applications. You can use any SIM in the device and can flash custom Android builds that will work with the unlocked bootloader. Unlike the bootloader on retail devices, the bootloader on the Android Dev Phone 1 does not enforce signed system images. The Android Dev Phone 1 should also appeal to developers -who live outside of T-Mobile geographies. </p> +who live in geographies where local mobile carriers do not currently offer Android-powered devices. </p> <p>To purchase an Android Dev Phone 1 device, you must first register as an Android developer on the Android Market site, if you haven't done so already. @@ -82,25 +88,30 @@ Singapore, Switzerland, Netherlands, Austria, Sweden, Finland, Poland, and Hungary. We will continue to expand this program into new geographies over time. Check this page for updated information.</p> -<p>Note that Android Dev Phone 1 devices are <em>not</em> intended for +<p>Android Dev Phone 1 devices are <em>not</em> intended for non-developer end-users. Because the device can be configured with system software not provided by or supported by Google or any other company, end-users operate these devices at their own risk.</p> +<p>Note that your Android Dev Phone 1 will not receive automated +over-the-air (OTA) updates for the system image. System updates must be flashed manually. +See the HTC site for a guide to <a href="http://www.htc.com/www/support/android/adp.html">Flashing +your Android Dev Phone with a Factory System Image</a>.</p> + <p>For full device specs and more information about obtaining an Android Dev Phone 1 device, see the <a href="http://market.android.com/publish">Android Market</a> site.</p> + <h2 id="setting-up">Setting up a Device for Development</h2> -<p>With a T-mobile G1 or Android Dev Phone 1, you can develop and debug your Android applications just as you +<p>With an Android-powered device, you can develop and debug your Android applications just as you would on the emulator. There are just a few things to do before you can start.</p> <ol> <li>Declare your application as "debuggable" in your Android Manifest. <p>In Eclipse, you can do this from the <b>Application</b> tab when viewing the Manifest (on the right side, set <b>Debuggable</b> to <em>true</em>). Otherwise, in the <code>AndroidManifest.xml</code> - file, add <code>android:debuggable="true"</code> to the <code><application></code> element.</p> </li> <li>Turn on "USB Debugging" on your device. @@ -110,30 +121,8 @@ would on the emulator. There are just a few things to do before you can start.</ </li> <li>Setup your system to detect your device. <ul> - <li>If you're developing on 32-bit Windows, you need to install the 32-bit USB driver for adb. - The USB driver is included in the SDK package. To install it, follow these steps:</p> - <ol> - <li>Connect your Android device via USB. When the <em>Found New Hardware Wizard</em> appears, - you'll be asked if you'd like Windows Update to search for software. Select <em>No, not this - time</em> and click <b>Next</b>.</li> - - <li>Select <em>Install from a list or specified location</em> and click <b>Next</b>.</li> - <li>Select <em>Search for the best driver in these locations</em>. Browse to the <code>usb_driver/x86</code> in the SDK package (<code><sdk>\usb_driver\x86</code>).</li> - <li>Click <b>Finish</b>. The system should install the driver files as necessary. Your machine may require a reboot.</li> - </ol> - </li> - <li>If you're developing on 64-bit Windows Vista, you need to install the 64-bit USB driver for adb. - The USB driver is included in the SDK package. To install it, follow these steps:</p> - <ol> - <li>Connect your Android device via USB. When the <em>Found New Hardware Wizard</em> appears, - you'll be asked if you'd like Windows Update to search for software. Select <em>No, not this - time</em> and click <b>Next</b>.</li> - - <li>Select <em>Install from a list or specified location</em> and click <b>Next</b>.</li> - <li>Select <em>Search for the best driver in these locations</em>. Browse to the <code>usb_driver/amd64</code> in the SDK package (<code><sdk>\usb_driver\amd64</code>).</li> - <li>Click <b>Finish</b>. The system should install the driver files as necessary. Your machine may require a reboot.</li> - </ol> - </li> + <li>If you're developing on Windows, you need to install a USB driver for adb. + Follow the steps below for <a href="#WinUsbDriver">Installing the WinUsb Driver</a>.</li> <li>If you're developing on Mac OS X, it just works. Skip this step.</li> <li>If you're developing on Ubuntu Linux, you need to add a rules file: <ol> @@ -145,7 +134,7 @@ would on the emulator. There are just a few things to do before you can start.</ <code>SUBSYSTEM=="usb_device", SYSFS{idVendor}=="0bb4", MODE="0666"</code></p> </li> <li>Now execute:<br/> - <code>chmod a+r /etc/udev/rules.d/50-android.rules</code> + <code>chmod a+r /etc/udev/rules.d/51-android.rules</code> </li> </ol> @@ -161,3 +150,156 @@ Select the device to install and run the application there.</p> <p>If using the <a href="{@docRoot}guide/developing/tools/adb.html">Android Debug Bridge</a> (adb), you can issue commands with the <code>-d</code> flag to target your connected device.</p> + + + + +<h2 id="WinUsbDriver">Installing the WinUsb Driver</h2> + +<p>A WinUsb-based driver is needed in order to use your Android-powered device for development on a Windows machine. +The USB installation package can be found in the <code><em><sdk></em>\usb_driver\</code> +folder of your SDK package.</p> + +<p class="note"><strong>Note:</strong> If you are connecting an Android-powered device to your computer +for the first time, folllow the procedure to "Perform a fresh installation." +Android SDKs older than version 1.6 included a non-WinUsb-based driver +for connecting your device. If you installed the older USB driver and it is working properly, +you do not need to upgrade to the new driver. However, if you are having problems with the driver or +would simply like to upgrade to the latest version, follow the procedure to "Upgrade an existing +driver." </p> + +<p>Before you begin installing or upgrading the USB driver, you must +copy the USB installation package to a secure location on your computer. +For example, you might want to create a directory at <code>C:\Android\Windows\USB\install\</code> and +move it there. Once you've moved the installation package, select the appropriate procedure below, +based on your operating system and whether you're installing for the first time or upgrading.</p> + +<ol class="nolist"> + <li>Windows Vista: + <ol class="nolist"> + <li><a href="#VistaFreshInstall">Perform a fresh installation</a></li> + <li><a href="#VistaUprade">Upgrade an existing driver</a></li> + </ol> + </li> + <li>Windows XP: + <ol class="nolist"> + <li><a href="#XPFreshInstall">Perform a fresh installation</a></li> + <li><a href="#XPUpgrade">Upgrade an existing driver</a></li> + </ol> + </li> +</ol> + + +<p class="caution"><strong>Caution:</strong> +You may make changes to <code>android_winusb.inf</code> file found inside <code>usb_driver\</code> +(e.g., to add support for new devices), +however, this will lead to security warnings when you install or upgrade the +driver. Making any other changes to the driver files may break the installation process.</p> + +<h3 id="VistaFreshInstall">Windows Vista: Perform a fresh installation</h3> + +<p>To install the Android USB driver on Windows Vista for the first time:</p> + +<ol> + <li>Connect your Android-powered device to your computer's USB port. Windows will detect the device + and launch the Found New Hardware wizard.</li> + <li>Select "Locate and install driver software."</li> + <li>Select "Don't search online."</li> + <li>Select "I don't have the disk. Show me other options."</li> + <li>Select "Browse my computer for driver software."</li> + <li>Click "Browse..." and locate the folder where you copied the + installation package. As long as you specified the exact location of the + installation package, you may leave "Include subfolders" checked or unchecked—it doesn't matter.</li> + <li>Click "Next." Vista may prompt you to confirm the privilege elevation required for driver + installation. Confirm it.</li> + <li>When Vista asks if you'd like to install the Google ADB Interface device, click "Install" + to install the driver.</li> +</ol> + +<p>Return to <a href="#setting-up">Setting up a Device for Development</a>.</p> + + + +<h3 id="VistaUpgrade">Windows Vista: Upgrade an existing driver</h3> + +<p>To upgrade an existing Android USB driver on Windows Vista with the new one:</p> + +<ol> + <li>Connect your Android-powered device to your computer's USB port.</li> + <li>Right-click on "Computer" from your desktop or Windows Explorer, + and select "Manage."</li> + <li>Select "Device Manager" in the left pane of the Computer Management window.</li> + <li>Locate and expand "ADB Interface" in the right pane.</li> + <li>Right-click on "HTC Dream Composite ADB Interface", and select "Update Driver Software..."</li> + <li>When Vista starts updating the driver, a prompt will ask how you want to search for the driver + software. Select "Browse my computer for driver software."</li> + <li>Click "Browse..." and locate the folder where you copied the + installation package. As long as you specified the exact location of the + installation package, you may leave "Include subfolders" checked or unchecked—it doesn't matter.</li> + <li>Click "Next." Vista may prompt you to confirm the privilege elevation required for driver + installation. Confirm it.</li> + <li>When Vista asks if you'd like to install the Google ADB Interface device, click "Install" + to install the driver.</li> +</ol> + +<p>Return to <a href="#setting-up">Setting up a Device for Development</a>.</p> + + + +<h3 id="XPFreshInstall">Windows XP: Perform a fresh installation</h3> + +<p>To install the Android USB driver on Windows XP for the first time:</p> + +<ol> + <li>Connect your Android-powered device to your computer's USB port. Windows + will detect the device and launch the Hardware Update Wizard.</li> + <li>Select "Install from a list or specific location" and click + "Next."</li> + <li>Select "Search for the best driver in these locations"; uncheck "Search + removable media"; and check "Include this location in the search."</li> + <li>Click "Browse..." and locate the folder where you copied the installation + package.</li> + <li>Click "Next" to install the driver.</li> +</ol> + +<p>Return to <a href="#setting-up">Setting up a Device for Development</a>.</p> + + + +<h3 id="XPUpgrade">Windows XP: Upgrade an existing driver</h3> + +<p>To upgrade an existing Android USB driver on Windows XP with the new one:</p> + +<ol> + <li>Connect your Android-powered device to your computer's USB port.</li> + <li>Right-click on "My Computer" from your desktop or Windows Explorer, + and select "Manage."</li> + <li>Select "Device Manager" in the left pane of the Computer Management window.</li> + <li>Locate and expand "Android Phone" in the right pane.</li> + <li>Right-click "Android Composite ADB Interface" and select "Update Driver..." + This will launch the Hardware Update Wizard.</li> + <li>Select "Install from a list or specific location" and click + "Next."</li> + <li>Select "Search for the best driver in these locations"; uncheck "Search + removable media"; and check "Include this location in the search."</li> + <li>Click "Browse..." and locate the folder where you copied the installation + package.</li> + <li>Click "Next" to install the driver.</li> +</ol> + +<p>Return to <a href="#setting-up">Setting up a Device for Development</a>.</p> + + + + + + + + + + + + + + + diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs index 0b33739..459ad37 100644 --- a/docs/html/guide/guide_toc.cs +++ b/docs/html/guide/guide_toc.cs @@ -387,17 +387,30 @@ <li><a href="<?cs var:toroot ?>guide/samples/ApiDemos/index.html"> <span class="en">API Demos</span> </a></li> + <li><a href="<?cs var:toroot ?>guide/samples/Home/index.html"> + <span class="en">Home</span> + </a></li> + <li><a href="<?cs var:toroot ?>guide/samples/JetBoy/index.html"> + <span class="en">JetBoy</span> + </a></li> <li><a href="<?cs var:toroot ?>guide/samples/LunarLander/index.html"> <span class="en">Lunar Lander</span> </a></li> <li><a href="<?cs var:toroot ?>guide/samples/NotePad/index.html"> - <span class="en">NotePad</span> + <span class="en">Note Pad</span> + </a></li> + <li><a href="<?cs var:toroot ?>guide/samples/Snake/index.html"> + <span class="en">Snake</span> + </a></li> + <li><a href="<?cs var:toroot ?>guide/samples/SoftKeyboard/index.html"> + <span class="en">Soft Keyboard</span> </a></li> </ul> </li> <?cs /if ?> </ul> </li> + <li> <h2><span class="en">Appendix</span> diff --git a/docs/html/guide/samples/images/HomeSample.png b/docs/html/guide/samples/images/HomeSample.png Binary files differnew file mode 100644 index 0000000..990bebb --- /dev/null +++ b/docs/html/guide/samples/images/HomeSample.png diff --git a/docs/html/guide/samples/images/JetBoy.png b/docs/html/guide/samples/images/JetBoy.png Binary files differnew file mode 100644 index 0000000..3da0448 --- /dev/null +++ b/docs/html/guide/samples/images/JetBoy.png diff --git a/docs/html/guide/samples/images/Snake.png b/docs/html/guide/samples/images/Snake.png Binary files differnew file mode 100644 index 0000000..c5211d8 --- /dev/null +++ b/docs/html/guide/samples/images/Snake.png diff --git a/docs/html/guide/samples/images/SoftKeyboard.png b/docs/html/guide/samples/images/SoftKeyboard.png Binary files differnew file mode 100644 index 0000000..8a4ec63 --- /dev/null +++ b/docs/html/guide/samples/images/SoftKeyboard.png diff --git a/docs/html/guide/samples/images/sample_lunarlander.png b/docs/html/guide/samples/images/sample_lunarlander.png Binary files differnew file mode 100644 index 0000000..a2ff75a --- /dev/null +++ b/docs/html/guide/samples/images/sample_lunarlander.png diff --git a/docs/html/guide/samples/images/sample_note.png b/docs/html/guide/samples/images/sample_note.png Binary files differnew file mode 100644 index 0000000..8fc9dcc --- /dev/null +++ b/docs/html/guide/samples/images/sample_note.png diff --git a/docs/html/guide/samples/images/sample_notepad.png b/docs/html/guide/samples/images/sample_notepad.png Binary files differnew file mode 100644 index 0000000..46f2211 --- /dev/null +++ b/docs/html/guide/samples/images/sample_notepad.png diff --git a/docs/html/guide/samples/index.jd b/docs/html/guide/samples/index.jd index 365284d..d8bbc41 100644 --- a/docs/html/guide/samples/index.jd +++ b/docs/html/guide/samples/index.jd @@ -15,11 +15,28 @@ in the SDK. You can find the sample applications for each platform version in th <p>You can easily add these applications as projects in your development environment, so that you can modify them and watch them execute. </p> <dl> + <dt><a href="ApiDemos/index.html">API Demos</a></dt> - <dd>A variety of small applications that demonstrate simple views and widgets.</dd> + <dd>A variety of small applications that demonstrate an extensive collection of framework topics.</dd> + + <dt><a href="Home/index.html">Home</a></dt> + <dd>An application for saving notes. Similar (but not identical) to the + <a href="{@docRoot}guide/tutorials/notepad/index.html">Notepad tutorial</a>.</dd> + + <dt><a href="JetBoy/index.html">JetBoy</a></dt> + <dd>JetBoy is a game that demonstrates the SONiVOX JET interactive music technology, with {@link android.media.JetPlayer}.</dd> + <dt><a href="LunarLander/index.html">Lunar Lander</a></dt> <dd>A classic Lunar Lander game.</dd> + <dt><a href="NotePad/index.html">Note Pad</a></dt> <dd>An application for saving notes. Similar (but not identical) to the <a href="{@docRoot}guide/tutorials/notepad/index.html">Notepad tutorial</a>.</dd> + + <dt><a href="Snake/index.html">Snake</a></dt> + <dd>An implementation of the classic game "Snake."</dd> + + <dt><a href="SoftKeyboard/index.html">Soft Keyboard</a></dt> + <dd>An example of writing an input method for a software keyboard.</dd> + </dl> diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java index e40e84a..9bcab72 100644 --- a/graphics/java/android/graphics/Typeface.java +++ b/graphics/java/android/graphics/Typeface.java @@ -172,4 +172,14 @@ public class Typeface { private static native int nativeGetStyle(int native_instance); private static native int nativeCreateFromAsset(AssetManager mgr, String path); private static native int nativeCreateFromFile(String path); + + /** + * Set the global gamma coefficients for black and white text. This call is + * usually a no-op in shipping products, and only exists for testing during + * development. + * + * @param blackGamma gamma coefficient for black text + * @param whiteGamma gamma coefficient for white text + */ + public static native void setGammaForText(float blackGamma, float whiteGamma); } diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java index eade73a..1755d4f 100644 --- a/graphics/java/android/graphics/drawable/BitmapDrawable.java +++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java @@ -76,6 +76,7 @@ public class BitmapDrawable extends Drawable { * @deprecated Use {@link #BitmapDrawable(Resources)} to ensure * that the drawable has correctly set its target density. */ + @Deprecated public BitmapDrawable() { mBitmapState = new BitmapState((Bitmap) null); } @@ -97,6 +98,7 @@ public class BitmapDrawable extends Drawable { * @deprecated Use {@link #BitmapDrawable(Resources, Bitmap)} to ensure * that the drawable has correctly set its target density. */ + @Deprecated public BitmapDrawable(Bitmap bitmap) { this(new BitmapState(bitmap)); } diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java index d5c8a08..b175bb6 100644 --- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java +++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java @@ -56,6 +56,7 @@ public class NinePatchDrawable extends Drawable { * @deprecated Use {@link #NinePatchDrawable(Resources, Bitmap, byte[], Rect, String)} * to ensure that the drawable has correctly set its target density. */ + @Deprecated public NinePatchDrawable(Bitmap bitmap, byte[] chunk, Rect padding, String srcName) { this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding)); } @@ -78,6 +79,7 @@ public class NinePatchDrawable extends Drawable { * @deprecated Use {@link #NinePatchDrawable(Resources, NinePatch)} * to ensure that the drawable has correctly set its target density. */ + @Deprecated public NinePatchDrawable(NinePatch patch) { this(new NinePatchState(patch, null)); } diff --git a/graphics/java/android/renderscript/RSSurfaceView.java b/graphics/java/android/renderscript/RSSurfaceView.java index a4be171..a3f1ded 100644 --- a/graphics/java/android/renderscript/RSSurfaceView.java +++ b/graphics/java/android/renderscript/RSSurfaceView.java @@ -71,7 +71,6 @@ public class RSSurfaceView extends SurfaceView implements SurfaceHolder.Callback public void surfaceCreated(SurfaceHolder holder) { Log.v(RenderScript.LOG_TAG, "surfaceCreated"); mSurfaceHolder = holder; - //mGLThread.surfaceCreated(); } /** @@ -81,7 +80,6 @@ public class RSSurfaceView extends SurfaceView implements SurfaceHolder.Callback public void surfaceDestroyed(SurfaceHolder holder) { // Surface will be destroyed when we return Log.v(RenderScript.LOG_TAG, "surfaceDestroyed"); - //mGLThread.surfaceDestroyed(); } /** @@ -90,8 +88,6 @@ public class RSSurfaceView extends SurfaceView implements SurfaceHolder.Callback */ public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { Log.v(RenderScript.LOG_TAG, "surfaceChanged"); - - //mGLThread.onWindowResize(w, h); } /** @@ -102,7 +98,6 @@ public class RSSurfaceView extends SurfaceView implements SurfaceHolder.Callback */ public void onPause() { Log.v(RenderScript.LOG_TAG, "onPause"); - //mGLThread.onPause(); } /** @@ -114,7 +109,6 @@ public class RSSurfaceView extends SurfaceView implements SurfaceHolder.Callback */ public void onResume() { Log.v(RenderScript.LOG_TAG, "onResume"); - //mGLThread.onResume(); } /** @@ -125,7 +119,6 @@ public class RSSurfaceView extends SurfaceView implements SurfaceHolder.Callback */ public void queueEvent(Runnable r) { Log.v(RenderScript.LOG_TAG, "queueEvent"); - //mGLThread.queueEvent(r); } /** @@ -136,20 +129,16 @@ public class RSSurfaceView extends SurfaceView implements SurfaceHolder.Callback @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); - //mGLThread.requestExitAndWait(); } // ---------------------------------------------------------------------- - public RenderScript createRenderScript() { - Log.v(RenderScript.LOG_TAG, "createRenderScript 1"); + public RenderScript createRenderScript(boolean useDepth) { Surface sur = null; while ((sur == null) || (mSurfaceHolder == null)) { sur = getHolder().getSurface(); } - Log.v(RenderScript.LOG_TAG, "createRenderScript 2"); - RenderScript rs = new RenderScript(sur); - Log.v(RenderScript.LOG_TAG, "createRenderScript 3 rs"); + RenderScript rs = new RenderScript(sur, useDepth); return rs; } diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java index 1bdabe7..84890038 100644 --- a/graphics/java/android/renderscript/RenderScript.java +++ b/graphics/java/android/renderscript/RenderScript.java @@ -60,7 +60,7 @@ public class RenderScript { native int nDeviceCreate(); native void nDeviceDestroy(int dev); - native int nContextCreate(int dev, Surface sur, int ver); + native int nContextCreate(int dev, Surface sur, int ver, boolean useDepth); native void nContextDestroy(int con); //void rsContextBindSampler (uint32_t slot, RsSampler sampler); @@ -194,10 +194,10 @@ public class RenderScript { /////////////////////////////////////////////////////////////////////////////////// // - public RenderScript(Surface sur) { + public RenderScript(Surface sur, boolean useDepth) { mSurface = sur; mDev = nDeviceCreate(); - mContext = nContextCreate(mDev, mSurface, 0); + mContext = nContextCreate(mDev, mSurface, 0, useDepth); // TODO: This should be protected by a lock if(!mElementsInitialized) { @@ -206,6 +206,13 @@ public class RenderScript { } } + public void destroy() { + nContextDestroy(mContext); + mContext = 0; + + nDeviceDestroy(mDev); + mDev = 0; + } ////////////////////////////////////////////////////////////////////////////////// // Triangle Mesh diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp index fede0e5..2393f74 100644 --- a/graphics/jni/android_renderscript_RenderScript.cpp +++ b/graphics/jni/android_renderscript_RenderScript.cpp @@ -126,7 +126,7 @@ nDeviceDestroy(JNIEnv *_env, jobject _this, jint dev) } static jint -nContextCreate(JNIEnv *_env, jobject _this, jint dev, jobject wnd, jint ver) +nContextCreate(JNIEnv *_env, jobject _this, jint dev, jobject wnd, jint ver, jboolean useDepth) { LOG_API("nContextCreate"); @@ -142,7 +142,7 @@ nContextCreate(JNIEnv *_env, jobject _this, jint dev, jobject wnd, jint ver) if (window == NULL) goto not_valid_surface; - return (jint)rsContextCreate((RsDevice)dev, window, ver); + return (jint)rsContextCreate((RsDevice)dev, window, ver, useDepth); } static void @@ -1206,7 +1206,7 @@ static JNINativeMethod methods[] = { {"_nInit", "()V", (void*)_nInit }, {"nDeviceCreate", "()I", (void*)nDeviceCreate }, {"nDeviceDestroy", "(I)V", (void*)nDeviceDestroy }, -{"nContextCreate", "(ILandroid/view/Surface;I)I", (void*)nContextCreate }, +{"nContextCreate", "(ILandroid/view/Surface;IZ)I", (void*)nContextCreate }, {"nContextDestroy", "(I)V", (void*)nContextDestroy }, {"nAssignName", "(I[B)V", (void*)nAssignName }, {"nObjDestroy", "(I)V", (void*)nObjDestroy }, diff --git a/include/media/stagefright/MediaDebug.h b/include/media/stagefright/MediaDebug.h index 83acd77..c8a8f00 100644 --- a/include/media/stagefright/MediaDebug.h +++ b/include/media/stagefright/MediaDebug.h @@ -2,6 +2,8 @@ #define MEDIA_DEBUG_H_ +#include <cutils/log.h> + #define LITERAL_TO_STRING_INTERNAL(x) #x #define LITERAL_TO_STRING(x) LITERAL_TO_STRING_INTERNAL(x) diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h index 0b94118..ff94e10 100644 --- a/include/media/stagefright/OMXCodec.h +++ b/include/media/stagefright/OMXCodec.h @@ -82,6 +82,8 @@ private: kWantsNALFragments = 2, kRequiresLoadedToIdleAfterAllocation = 4, kRequiresAllocateBufferOnInputPorts = 8, + kRequiresFlushCompleteEmulation = 16, + kRequiresAllocateBufferOnOutputPorts = 32, }; struct BufferInfo { @@ -165,7 +167,13 @@ private: void drainInputBuffers(); void fillOutputBuffers(); - void flushPortAsync(OMX_U32 portIndex); + // Returns true iff a flush was initiated and a completion event is + // upcoming, false otherwise (A flush was not necessary as we own all + // the buffers on that port). + // This method will ONLY ever return false for a component with quirk + // "kRequiresFlushCompleteEmulation". + bool flushPortAsync(OMX_U32 portIndex); + void disablePortAsync(OMX_U32 portIndex); void enablePortAsync(OMX_U32 portIndex); diff --git a/include/media/stagefright/TIHardwareRenderer.h b/include/media/stagefright/TIHardwareRenderer.h index f7fa81b..ef42648 100644 --- a/include/media/stagefright/TIHardwareRenderer.h +++ b/include/media/stagefright/TIHardwareRenderer.h @@ -46,6 +46,7 @@ private: size_t mFrameSize; sp<Overlay> mOverlay; Vector<void *> mOverlayAddresses; + bool mIsFirstFrame; size_t mIndex; TIHardwareRenderer(const TIHardwareRenderer &); diff --git a/include/private/opengles/gl_context.h b/include/private/opengles/gl_context.h index 523aed0..67c2dd8 100644 --- a/include/private/opengles/gl_context.h +++ b/include/private/opengles/gl_context.h @@ -287,6 +287,7 @@ struct light_t { vec4_t normalizedObjPosition; vec4_t spotDir; vec4_t normalizedSpotDir; + vec4_t objViewer; GLfixed spotExp; GLfixed spotCutoff; GLfixed spotCutoffCosine; diff --git a/libs/rs/RenderScript.h b/libs/rs/RenderScript.h index 2f60c9f..1e24cd2 100644 --- a/libs/rs/RenderScript.h +++ b/libs/rs/RenderScript.h @@ -49,7 +49,7 @@ typedef void * RsProgramFragmentStore; RsDevice rsDeviceCreate(); void rsDeviceDestroy(RsDevice); -RsContext rsContextCreate(RsDevice, void *, uint32_t version); +RsContext rsContextCreate(RsDevice, void *, uint32_t version, bool useDepth); void rsContextDestroy(RsContext); void rsObjDestroyOOB(RsContext, void *); diff --git a/libs/rs/java/Fall/src/com/android/fall/rs/FallView.java b/libs/rs/java/Fall/src/com/android/fall/rs/FallView.java index fa2caa7..7468d2b 100644 --- a/libs/rs/java/Fall/src/com/android/fall/rs/FallView.java +++ b/libs/rs/java/Fall/src/com/android/fall/rs/FallView.java @@ -36,7 +36,7 @@ class FallView extends RSSurfaceView { public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { super.surfaceChanged(holder, format, w, h); - RenderScript RS = createRenderScript(); + RenderScript RS = createRenderScript(false); mRender = new FallRS(w, h); mRender.init(RS, getResources()); } diff --git a/libs/rs/java/Film/src/com/android/film/FilmView.java b/libs/rs/java/Film/src/com/android/film/FilmView.java index 73b7414..1c5b2bc 100644 --- a/libs/rs/java/Film/src/com/android/film/FilmView.java +++ b/libs/rs/java/Film/src/com/android/film/FilmView.java @@ -52,7 +52,7 @@ public class FilmView extends RSSurfaceView { public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { super.surfaceChanged(holder, format, w, h); - mRS = createRenderScript(); + mRS = createRenderScript(true); mRender = new FilmRS(); mRender.init(mRS, getResources(), w, h); } diff --git a/libs/rs/java/Fountain/res/raw/fountain.c b/libs/rs/java/Fountain/res/raw/fountain.c index e7804a5..8c1cad4 100644 --- a/libs/rs/java/Fountain/res/raw/fountain.c +++ b/libs/rs/java/Fountain/res/raw/fountain.c @@ -12,7 +12,6 @@ int main(int launchID) { float height = getHeight(); if (rate) { - debugI32("rate", rate); int *dataI = loadArrayI32(1, 0); float rMax = ((float)rate) * 0.005f; int x = Control_x; diff --git a/libs/rs/java/Fountain/src/com/android/fountain/FountainView.java b/libs/rs/java/Fountain/src/com/android/fountain/FountainView.java index 2768e2c..7826161 100644 --- a/libs/rs/java/Fountain/src/com/android/fountain/FountainView.java +++ b/libs/rs/java/Fountain/src/com/android/fountain/FountainView.java @@ -52,7 +52,7 @@ public class FountainView extends RSSurfaceView { public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { super.surfaceChanged(holder, format, w, h); - mRS = createRenderScript(); + mRS = createRenderScript(false); mRender = new FountainRS(); mRender.init(mRS, getResources(), w, h); } diff --git a/libs/rs/java/Galaxy/AndroidManifest.xml b/libs/rs/java/Galaxy/AndroidManifest.xml deleted file mode 100644 index 6da1e0f..0000000 --- a/libs/rs/java/Galaxy/AndroidManifest.xml +++ /dev/null @@ -1,21 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.galaxy.rs"> - - <application android:label="GalaxyRS"> - - <activity - android:screenOrientation="portrait" - android:name="Galaxy" - android:theme="@android:style/Theme.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/Galaxy/res/drawable-hdpi/flares.png b/libs/rs/java/Galaxy/res/drawable-hdpi/flares.png Binary files differdeleted file mode 100644 index 3a5c970..0000000 --- a/libs/rs/java/Galaxy/res/drawable-hdpi/flares.png +++ /dev/null diff --git a/libs/rs/java/Galaxy/res/drawable-hdpi/light1.png b/libs/rs/java/Galaxy/res/drawable-hdpi/light1.png Binary files differdeleted file mode 100644 index 4ffb1ee..0000000 --- a/libs/rs/java/Galaxy/res/drawable-hdpi/light1.png +++ /dev/null diff --git a/libs/rs/java/Galaxy/res/drawable-hdpi/space.jpg b/libs/rs/java/Galaxy/res/drawable-hdpi/space.jpg Binary files differdeleted file mode 100644 index b61f6a3..0000000 --- a/libs/rs/java/Galaxy/res/drawable-hdpi/space.jpg +++ /dev/null diff --git a/libs/rs/java/Galaxy/res/raw/galaxy.c b/libs/rs/java/Galaxy/res/raw/galaxy.c deleted file mode 100644 index 9ff449f..0000000 --- a/libs/rs/java/Galaxy/res/raw/galaxy.c +++ /dev/null @@ -1,126 +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. - -#pragma version(1) -#pragma stateVertex(PVBackground) -#pragma stateFragment(PFBackground) -#pragma stateFragmentStore(PFSBackground) - -#define RSID_PARTICLES 1 - -#define PARTICLE_STRUCT_FIELDS_COUNT 6 -#define PARTICLE_STRUCT_ANGLE 0 -#define PARTICLE_STRUCT_DISTANCE 1 -#define PARTICLE_STRUCT_SPEED 2 -#define PARTICLE_STRUCT_RADIUS 3 -#define PARTICLE_STRUCT_S 4 -#define PARTICLE_STRUCT_T 5 - -#define RSID_PARTICLES_BUFFER 2 -#define PARTICLE_BUFFER_COMPONENTS_COUNT 5 - -#define PARTICLES_TEXTURES_COUNT 2 - -#define ELLIPSE_RATIO 0.892f - -void drawSpace(int width, int height) { - bindTexture(NAMED_PFBackground, 0, NAMED_TSpace); - drawQuadTexCoords( - 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, - width, 0.0f, 0.0f, 2.0f, 1.0f, - width, height, 0.0f, 2.0f, 0.0f, - 0.0f, height, 0.0f, 0.0f, 0.0f); -} - -void drawLights(int width, int height) { - float x = (width - 512.0f) * 0.5f; - float y = (height - 512.0f) * 0.5f; - - // increase the size of the texture by 5% on each side - x -= 512.0f * 0.05f; - - bindProgramFragment(NAMED_PFBackground); - bindTexture(NAMED_PFBackground, 0, NAMED_TLight1); - drawQuad(x + 512.0f * 1.1f, y , 0.0f, - x , y , 0.0f, - x , y + 512.0f, 0.0f, - x + 512.0f * 1.1f, y + 512.0f, 0.0f); -} - -void drawParticle(float *particle, float *particleBuffer, float w, float h) { - float distance = particle[PARTICLE_STRUCT_DISTANCE]; - float angle = particle[PARTICLE_STRUCT_ANGLE]; - float speed = particle[PARTICLE_STRUCT_SPEED]; - float r = particle[PARTICLE_STRUCT_RADIUS]; - - float a = angle + speed; - float x = distance * sinf_fast(a); - float y = distance * cosf_fast(a) * ELLIPSE_RATIO; - float s = particle[PARTICLE_STRUCT_S]; - float t = particle[PARTICLE_STRUCT_T]; - - float sX = t * x + s * y + w; - float sY = s * x - t * y + h; - - // lower left vertex of the particle's triangle - particleBuffer[1] = sX - r; // X - particleBuffer[2] = sY + r; // Y - - // lower right vertex of the particle's triangle - particleBuffer[6] = sX + r; // X - particleBuffer[7] = sY + r; // Y - - // upper middle vertex of the particle's triangle - particleBuffer[11] = sX; // X - particleBuffer[12] = sY - r; // Y - - particle[PARTICLE_STRUCT_ANGLE] = a; -} - -void drawParticles(int width, int height) { - bindProgramFragment(NAMED_PFLighting); - bindProgramFragmentStore(NAMED_PFSLights); - bindTexture(NAMED_PFLighting, 0, NAMED_TFlares); - - int radius = State_galaxyRadius; - int particlesCount = State_particlesCount; - - float *particle = loadArrayF(RSID_PARTICLES, 0); - float *particleBuffer = loadArrayF(RSID_PARTICLES_BUFFER, 0); - - float w = width * 0.5f; - float h = height * 0.5f; - - int i = 0; - for ( ; i < particlesCount; i++) { - drawParticle(particle, particleBuffer, w, h); - particle += PARTICLE_STRUCT_FIELDS_COUNT; - // each particle is a triangle (3 vertices) of 5 properties (ABGR, X, Y, S, T) - particleBuffer += 3 * PARTICLE_BUFFER_COMPONENTS_COUNT; - } - - uploadToBufferObject(NAMED_ParticlesBuffer); - drawSimpleMeshRange(NAMED_ParticlesMesh, 0, particlesCount * 3); -} - -int main(int index) { - int width = State_width; - int height = State_height; - - drawSpace(width, height); - drawParticles(width, height); - drawLights(width, height); - - return 1; -} diff --git a/libs/rs/java/Galaxy/src/com/android/galaxy/rs/Galaxy.java b/libs/rs/java/Galaxy/src/com/android/galaxy/rs/Galaxy.java deleted file mode 100644 index 27d333c..0000000 --- a/libs/rs/java/Galaxy/src/com/android/galaxy/rs/Galaxy.java +++ /dev/null @@ -1,46 +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 com.android.galaxy.rs; - -import android.app.Activity; -import android.os.Bundle; - -public class Galaxy extends Activity { - private GalaxyView mView; - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - - mView = new GalaxyView(this); - setContentView(mView); - } - - @Override - protected void onResume() { - super.onResume(); - mView.onResume(); - } - - @Override - protected void onPause() { - super.onPause(); - mView.onPause(); - - Runtime.getRuntime().exit(0); - } -}
\ No newline at end of file diff --git a/libs/rs/java/Galaxy/src/com/android/galaxy/rs/GalaxyRS.java b/libs/rs/java/Galaxy/src/com/android/galaxy/rs/GalaxyRS.java deleted file mode 100644 index fae92f7..0000000 --- a/libs/rs/java/Galaxy/src/com/android/galaxy/rs/GalaxyRS.java +++ /dev/null @@ -1,338 +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 com.android.galaxy.rs; - -import android.content.res.Resources; -import android.renderscript.RenderScript; -import android.renderscript.ScriptC; -import android.renderscript.ProgramFragment; -import android.renderscript.ProgramStore; -import android.renderscript.ProgramVertex; -import android.renderscript.Allocation; -import android.renderscript.Sampler; -import android.renderscript.Element; -import android.renderscript.SimpleMesh; -import android.renderscript.Primitive; -import android.renderscript.Type; -import static android.renderscript.Sampler.Value.LINEAR; -import static android.renderscript.Sampler.Value.NEAREST; -import static android.renderscript.Sampler.Value.WRAP; -import static android.renderscript.ProgramStore.DepthFunc.*; -import static android.renderscript.ProgramStore.BlendDstFunc; -import static android.renderscript.ProgramStore.BlendSrcFunc; -import static android.renderscript.ProgramFragment.EnvMode.*; -import static android.renderscript.Element.*; -import android.graphics.BitmapFactory; -import android.graphics.Bitmap; -import static android.util.MathUtils.*; - -import java.util.TimeZone; - -@SuppressWarnings({"FieldCanBeLocal"}) -class GalaxyRS { - private static final int GALAXY_RADIUS = 300; - private static final int PARTICLES_COUNT = 12000; - private static final float ELLIPSE_TWIST = 0.023333333f; - - private static final int RSID_STATE = 0; - - private static final int TEXTURES_COUNT = 3; - private static final int RSID_TEXTURE_SPACE = 0; - private static final int RSID_TEXTURE_LIGHT1 = 1; - private static final int RSID_TEXTURE_FLARES = 2; - - private static final int RSID_PARTICLES = 1; - private static final int PARTICLE_STRUCT_FIELDS_COUNT = 6; - private static final int PARTICLE_STRUCT_ANGLE = 0; - private static final int PARTICLE_STRUCT_DISTANCE = 1; - private static final int PARTICLE_STRUCT_SPEED = 2; - private static final int PARTICLE_STRUCT_RADIUS = 3; - private static final int PARTICLE_STRUCT_S = 4; - private static final int PARTICLE_STRUCT_T = 5; - - private static final int RSID_PARTICLES_BUFFER = 2; - - private Resources mResources; - private RenderScript mRS; - - private final BitmapFactory.Options mOptionsARGB = new BitmapFactory.Options(); - - private final int mWidth; - private final int mHeight; - - private ScriptC mScript; - private Sampler mSampler; - private Sampler mLightSampler; - private ProgramFragment mPfBackground; - private ProgramFragment mPfLighting; - private ProgramStore mPfsBackground; - private ProgramStore mPfsLights; - private ProgramVertex mPvBackground; - private ProgramVertex.MatrixAllocation mPvOrthoAlloc; - - private Allocation[] mTextures; - - private Type mStateType; - private Allocation mState; - private Allocation mParticles; - private Allocation mParticlesBuffer; - private SimpleMesh mParticlesMesh; - - private final float[] mFloatData5 = new float[5]; - - public GalaxyRS(int width, int height) { - mWidth = width; - mHeight = height; - mOptionsARGB.inScaled = false; - mOptionsARGB.inPreferredConfig = Bitmap.Config.ARGB_8888; - } - - public void init(RenderScript rs, Resources res) { - mRS = rs; - mResources = res; - initRS(); - } - - private void initRS() { - createProgramVertex(); - createProgramFragmentStore(); - createProgramFragment(); - createScriptStructures(); - loadTextures(); - - ScriptC.Builder sb = new ScriptC.Builder(mRS); - sb.setType(mStateType, "State", RSID_STATE); - sb.setScript(mResources, R.raw.galaxy); - sb.setRoot(true); - - mScript = sb.create(); - mScript.setClearColor(0.0f, 0.0f, 0.0f, 1.0f); - mScript.setTimeZone(TimeZone.getDefault().getID()); - - mScript.bindAllocation(mState, RSID_STATE); - mScript.bindAllocation(mParticles, RSID_PARTICLES); - mScript.bindAllocation(mParticlesBuffer, RSID_PARTICLES_BUFFER); - - mRS.contextBindRootScript(mScript); - } - - private void createScriptStructures() { - createState(); - createParticlesMesh(); - createParticles(); - } - - private void createParticlesMesh() { - final Element.Builder elementBuilder = new Element.Builder(mRS); - elementBuilder.addUNorm8RGBA(); - elementBuilder.addFloatXY(); - elementBuilder.addFloatST(); - final Element vertexElement = elementBuilder.create(); - - final SimpleMesh.Builder meshBuilder = new SimpleMesh.Builder(mRS); - final int vertexSlot = meshBuilder.addVertexType(vertexElement, PARTICLES_COUNT * 3); - meshBuilder.setPrimitive(Primitive.TRIANGLE); - mParticlesMesh = meshBuilder.create(); - mParticlesMesh.setName("ParticlesMesh"); - - mParticlesBuffer = mParticlesMesh.createVertexAllocation(vertexSlot); - mParticlesBuffer.setName("ParticlesBuffer"); - mParticlesMesh.bindVertexAllocation(mParticlesBuffer, 0); - } - - static class GalaxyState { - public int frameCount; - public int width; - public int height; - public int particlesCount; - public int galaxyRadius; - } - - private void createState() { - GalaxyState state = new GalaxyState(); - state.width = mWidth; - state.height = mHeight; - state.particlesCount = PARTICLES_COUNT; - state.galaxyRadius = GALAXY_RADIUS; - - mStateType = Type.createFromClass(mRS, GalaxyState.class, 1, "GalaxyState"); - mState = Allocation.createTyped(mRS, mStateType); - mState.data(state); - } - - private void createParticles() { - final float[] particles = new float[PARTICLES_COUNT * PARTICLE_STRUCT_FIELDS_COUNT]; - - int bufferIndex = 0; - - for (int i = 0; i < particles.length; i += PARTICLE_STRUCT_FIELDS_COUNT) { - createParticle(particles, i, bufferIndex); - bufferIndex += 3; - } - - mParticles = Allocation.createSized(mRS, USER_FLOAT, particles.length); - mParticles.data(particles); - } - - @SuppressWarnings({"PointlessArithmeticExpression"}) - private void createParticle(float[] particles, int index, int bufferIndex) { - float d = abs(randomGauss()) * GALAXY_RADIUS / 2.0f + random(-4.0f, 4.0f); - float z = randomGauss() * 0.5f * 0.8f * ((GALAXY_RADIUS - d) / (float) GALAXY_RADIUS); - z += 1.0f; - float p = d * ELLIPSE_TWIST; - - particles[index + PARTICLE_STRUCT_ANGLE] = random(0.0f, (float) (Math.PI * 2.0)); - particles[index + PARTICLE_STRUCT_DISTANCE] = d; - particles[index + PARTICLE_STRUCT_SPEED] = random(0.0015f, 0.0025f) * - (0.5f + (0.5f * (float) GALAXY_RADIUS / d)) * 0.7f; - particles[index + PARTICLE_STRUCT_RADIUS] = z * random(1.2f, 2.1f); - particles[index + PARTICLE_STRUCT_S] = (float) Math.cos(p); - particles[index + PARTICLE_STRUCT_T] = (float) Math.sin(p); - - int red, green, blue; - if (d < GALAXY_RADIUS / 3.0f) { - red = (int) (220 + (d / (float) GALAXY_RADIUS) * 35); - green = 220; - blue = 220; - } else { - red = 180; - green = 180; - blue = (int) constrain(140 + (d / (float) GALAXY_RADIUS) * 115, 140, 255); - } - - final int color = red | green << 8 | blue << 16 | 0xff000000; - - final float[] floatData = mFloatData5; - final Allocation buffer = mParticlesBuffer; - - floatData[0] = Float.intBitsToFloat(color); - floatData[3] = 0.0f; - floatData[4] = 1.0f; - buffer.subData1D(bufferIndex, 1, floatData); - - bufferIndex++; - floatData[3] = 1.0f; - floatData[4] = 1.0f; - buffer.subData1D(bufferIndex, 1, floatData); - - bufferIndex++; - floatData[3] = 0.5f; - floatData[4] = 0.0f; - buffer.subData1D(bufferIndex, 1, floatData); - } - - private static float randomGauss() { - float x1; - float x2; - float w; - - do { - x1 = 2.0f * random(0.0f, 1.0f) - 1.0f; - x2 = 2.0f * random(0.0f, 1.0f) - 1.0f; - w = x1 * x1 + x2 * x2; - } while (w >= 1.0f); - - w = (float) Math.sqrt(-2.0 * log(w) / w); - return x1 * w; - } - - private void loadTextures() { - mTextures = new Allocation[TEXTURES_COUNT]; - - final Allocation[] textures = mTextures; - textures[RSID_TEXTURE_SPACE] = loadTexture(R.drawable.space, "TSpace"); - textures[RSID_TEXTURE_LIGHT1] = loadTextureARGB(R.drawable.light1, "TLight1"); - textures[RSID_TEXTURE_FLARES] = loadTextureARGB(R.drawable.flares, "TFlares"); - - final int count = textures.length; - for (int i = 0; i < count; i++) { - final Allocation texture = textures[i]; - texture.uploadToTexture(0); - } - } - - private Allocation loadTexture(int id, String name) { - final Allocation allocation = Allocation.createFromBitmapResource(mRS, mResources, - id, RGB_565, false); - allocation.setName(name); - return allocation; - } - - private Allocation loadTextureARGB(int id, String name) { - Bitmap b = BitmapFactory.decodeResource(mResources, id, mOptionsARGB); - final Allocation allocation = Allocation.createFromBitmap(mRS, b, RGBA_8888, false); - allocation.setName(name); - return allocation; - } - - private void createProgramFragment() { - Sampler.Builder sampleBuilder = new Sampler.Builder(mRS); - sampleBuilder.setMin(LINEAR); - sampleBuilder.setMag(LINEAR); - sampleBuilder.setWrapS(WRAP); - sampleBuilder.setWrapT(WRAP); - mSampler = sampleBuilder.create(); - - ProgramFragment.Builder builder = new ProgramFragment.Builder(mRS, null, null); - builder.setTexEnable(true, 0); - builder.setTexEnvMode(REPLACE, 0); - mPfBackground = builder.create(); - mPfBackground.setName("PFBackground"); - mPfBackground.bindSampler(mSampler, 0); - - sampleBuilder = new Sampler.Builder(mRS); - sampleBuilder.setMin(NEAREST); - sampleBuilder.setMag(NEAREST); - sampleBuilder.setWrapS(WRAP); - sampleBuilder.setWrapT(WRAP); - mLightSampler = sampleBuilder.create(); - - builder = new ProgramFragment.Builder(mRS, null, null); - builder.setTexEnable(true, 0); - builder.setTexEnvMode(MODULATE, 0); - mPfLighting = builder.create(); - mPfLighting.setName("PFLighting"); - mPfLighting.bindSampler(mLightSampler, 0); - } - - private void createProgramFragmentStore() { - ProgramStore.Builder builder = new ProgramStore.Builder(mRS, null, null); - builder.setDepthFunc(ALWAYS); - builder.setBlendFunc(BlendSrcFunc.ONE, BlendDstFunc.ZERO); - builder.setDitherEnable(false); - mPfsBackground = builder.create(); - mPfsBackground.setName("PFSBackground"); - - builder = new ProgramStore.Builder(mRS, null, null); - builder.setDepthFunc(ALWAYS); - builder.setBlendFunc(BlendSrcFunc.ONE, BlendDstFunc.ONE); - builder.setDitherEnable(false); - mPfsLights = builder.create(); - mPfsLights.setName("PFSLights"); - } - - private void createProgramVertex() { - mPvOrthoAlloc = new ProgramVertex.MatrixAllocation(mRS); - //mPvOrthoAlloc.setupProjectionNormalized(mWidth, mHeight); - mPvOrthoAlloc.setupOrthoWindow(mWidth, mHeight); - - ProgramVertex.Builder builder = new ProgramVertex.Builder(mRS, null, null); - mPvBackground = builder.create(); - mPvBackground.bindAllocation(mPvOrthoAlloc); - mPvBackground.setName("PVBackground"); - } -} diff --git a/libs/rs/java/Galaxy/src/com/android/galaxy/rs/GalaxyView.java b/libs/rs/java/Galaxy/src/com/android/galaxy/rs/GalaxyView.java deleted file mode 100644 index 4f6d3f0..0000000 --- a/libs/rs/java/Galaxy/src/com/android/galaxy/rs/GalaxyView.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 com.android.galaxy.rs; - -import android.content.Context; -import android.view.SurfaceHolder; -import android.renderscript.RenderScript; -import android.renderscript.RSSurfaceView; - -class GalaxyView extends RSSurfaceView { - public GalaxyView(Context context) { - super(context); - setFocusable(true); - setFocusableInTouchMode(true); - } - - public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { - super.surfaceChanged(holder, format, w, h); - - RenderScript RS = createRenderScript(); - GalaxyRS render = new GalaxyRS(w, h); - render.init(RS, getResources()); - } -} diff --git a/libs/rs/java/Rollo/src/com/android/rollo/RolloView.java b/libs/rs/java/Rollo/src/com/android/rollo/RolloView.java index 3e1c54d..7524a0e 100644 --- a/libs/rs/java/Rollo/src/com/android/rollo/RolloView.java +++ b/libs/rs/java/Rollo/src/com/android/rollo/RolloView.java @@ -54,7 +54,7 @@ public class RolloView extends RSSurfaceView { public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { super.surfaceChanged(holder, format, w, h); - mRS = createRenderScript(); + mRS = createRenderScript(false); mRender = new RolloRS(); mRender.init(mRS, getResources(), w, h); } diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp index 413caab..52c2b78 100644 --- a/libs/rs/rsContext.cpp +++ b/libs/rs/rsContext.cpp @@ -18,6 +18,7 @@ #include "rsContext.h" #include "rsThreadIO.h" #include <ui/FramebufferNativeWindow.h> +#include <ui/EGLUtils.h> #include <GLES/gl.h> #include <GLES/glext.h> @@ -29,41 +30,63 @@ pthread_key_t Context::gThreadTLSKey = 0; void Context::initEGL() { - mNumConfigs = -1; - - EGLint s_configAttribs[] = { - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, -#if 1 - EGL_RED_SIZE, 8, - EGL_GREEN_SIZE, 8, - EGL_BLUE_SIZE, 8, - EGL_ALPHA_SIZE, 8, -#else - EGL_RED_SIZE, 5, - EGL_GREEN_SIZE, 6, - EGL_BLUE_SIZE, 5, -#endif - EGL_DEPTH_SIZE, 16, - EGL_NONE - }; - - mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); - eglInitialize(mDisplay, &mMajorVersion, &mMinorVersion); - eglChooseConfig(mDisplay, s_configAttribs, &mConfig, 1, &mNumConfigs); - - if (mWndSurface) { - mSurface = eglCreateWindowSurface(mDisplay, mConfig, mWndSurface, - NULL); - } else { - mSurface = eglCreateWindowSurface(mDisplay, mConfig, - android_createDisplaySurface(), - NULL); - } + mEGL.mNumConfigs = -1; + EGLint configAttribs[128]; + EGLint *configAttribsPtr = configAttribs; + + memset(configAttribs, 0, sizeof(configAttribs)); + + configAttribsPtr[0] = EGL_SURFACE_TYPE; + configAttribsPtr[1] = EGL_WINDOW_BIT; + configAttribsPtr += 2; + + if (mUseDepth) { + configAttribsPtr[0] = EGL_DEPTH_SIZE; + configAttribsPtr[1] = 16; + configAttribsPtr += 2; + } + configAttribsPtr[0] = EGL_NONE; + rsAssert(configAttribsPtr < (configAttribs + (sizeof(configAttribs) / sizeof(EGLint)))); + + mEGL.mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + eglInitialize(mEGL.mDisplay, &mEGL.mMajorVersion, &mEGL.mMinorVersion); + + status_t err = EGLUtils::selectConfigForNativeWindow(mEGL.mDisplay, configAttribs, mWndSurface, &mEGL.mConfig); + if (err) { + LOGE("couldn't find an EGLConfig matching the screen format\n"); + } + //eglChooseConfig(mEGL.mDisplay, configAttribs, &mEGL.mConfig, 1, &mEGL.mNumConfigs); + + if (mWndSurface) { + mEGL.mSurface = eglCreateWindowSurface(mEGL.mDisplay, mEGL.mConfig, mWndSurface, NULL); + } else { + mEGL.mSurface = eglCreateWindowSurface(mEGL.mDisplay, mEGL.mConfig, + android_createDisplaySurface(), + NULL); + } + + mEGL.mContext = eglCreateContext(mEGL.mDisplay, mEGL.mConfig, NULL, NULL); + eglMakeCurrent(mEGL.mDisplay, mEGL.mSurface, mEGL.mSurface, mEGL.mContext); + eglQuerySurface(mEGL.mDisplay, mEGL.mSurface, EGL_WIDTH, &mEGL.mWidth); + eglQuerySurface(mEGL.mDisplay, mEGL.mSurface, EGL_HEIGHT, &mEGL.mHeight); + - mContext = eglCreateContext(mDisplay, mConfig, NULL, NULL); - eglMakeCurrent(mDisplay, mSurface, mSurface, mContext); - eglQuerySurface(mDisplay, mSurface, EGL_WIDTH, &mWidth); - eglQuerySurface(mDisplay, mSurface, EGL_HEIGHT, &mHeight); + mGL.mVersion = glGetString(GL_VERSION); + mGL.mVendor = glGetString(GL_VENDOR); + mGL.mRenderer = glGetString(GL_RENDERER); + mGL.mExtensions = glGetString(GL_EXTENSIONS); + + //LOGV("EGL Version %i %i", mEGL.mMajorVersion, mEGL.mMinorVersion); + //LOGV("GL Version %s", mGL.mVersion); + //LOGV("GL Vendor %s", mGL.mVendor); + //LOGV("GL Renderer %s", mGL.mRenderer); + //LOGV("GL Extensions %s", mGL.mExtensions); + + if ((strlen((const char *)mGL.mVersion) < 12) || memcmp(mGL.mVersion, "OpenGL ES-CM", 12)) { + LOGE("Error, OpenGL ES Lite not supported"); + } else { + sscanf((const char *)mGL.mVersion + 13, "%i.%i", &mGL.mMajorVersion, &mGL.mMinorVersion); + } } bool Context::runScript(Script *s, uint32_t launchID) @@ -90,18 +113,20 @@ bool Context::runRootScript() //glColor4f(1,1,1,1); //glEnable(GL_LIGHT0); - glViewport(0, 0, mWidth, mHeight); - - glDepthMask(GL_TRUE); + 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]); - glClearDepthf(mRootScript->mEnviroment.mClearDepth); - glClear(GL_COLOR_BUFFER_BIT); - glClear(GL_DEPTH_BUFFER_BIT); + if (mUseDepth) { + glDepthMask(GL_TRUE); + glClearDepthf(mRootScript->mEnviroment.mClearDepth); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } else { + glClear(GL_COLOR_BUFFER_BIT); + } #if RS_LOG_TIMES timerSet(RS_TIMER_SCRIPT); @@ -156,13 +181,13 @@ void Context::timerPrint() void Context::setupCheck() { if (mFragmentStore.get()) { - mFragmentStore->setupGL(&mStateFragmentStore); + mFragmentStore->setupGL(this, &mStateFragmentStore); } if (mFragment.get()) { - mFragment->setupGL(&mStateFragment); + mFragment->setupGL(this, &mStateFragment); } if (mVertex.get()) { - mVertex->setupGL(&mStateVertex); + mVertex->setupGL(this, &mStateVertex); } } @@ -186,11 +211,11 @@ void * Context::threadProc(void *vrsc) LOGE("pthread_setspecific %i", status); } - rsc->mStateVertex.init(rsc, rsc->mWidth, rsc->mHeight); + rsc->mStateVertex.init(rsc, rsc->mEGL.mWidth, rsc->mEGL.mHeight); rsc->setVertex(NULL); - rsc->mStateFragment.init(rsc, rsc->mWidth, rsc->mHeight); + rsc->mStateFragment.init(rsc, rsc->mEGL.mWidth, rsc->mEGL.mHeight); rsc->setFragment(NULL); - rsc->mStateFragmentStore.init(rsc, rsc->mWidth, rsc->mHeight); + rsc->mStateFragmentStore.init(rsc, rsc->mEGL.mWidth, rsc->mEGL.mHeight); rsc->setFragmentStore(NULL); rsc->mRunning = true; @@ -204,7 +229,7 @@ void * Context::threadProc(void *vrsc) #if RS_LOG_TIMES rsc->timerSet(RS_TIMER_CLEAR_SWAP); #endif - eglSwapBuffers(rsc->mDisplay, rsc->mSurface); + eglSwapBuffers(rsc->mEGL.mDisplay, rsc->mEGL.mSurface); #if RS_LOG_TIMES rsc->timerSet(RS_TIMER_INTERNAL); rsc->timerPrint(); @@ -216,20 +241,23 @@ void * Context::threadProc(void *vrsc) } } + LOGV("RS Thread exiting"); glClearColor(0,0,0,0); glClear(GL_COLOR_BUFFER_BIT); - eglSwapBuffers(rsc->mDisplay, rsc->mSurface); - eglTerminate(rsc->mDisplay); + eglSwapBuffers(rsc->mEGL.mDisplay, rsc->mEGL.mSurface); + eglTerminate(rsc->mEGL.mDisplay); rsc->objDestroyOOBRun(); + LOGV("RS Thread exited"); return NULL; } -Context::Context(Device *dev, Surface *sur) +Context::Context(Device *dev, Surface *sur, bool useDepth) { dev->addContext(this); mDev = dev; mRunning = false; mExit = false; + mUseDepth = useDepth; int status; pthread_attr_t threadAttr; @@ -270,9 +298,11 @@ Context::Context(Device *dev, Surface *sur) Context::~Context() { + LOGV("Context::~Context"); mExit = true; void *res; + mIO.shutdown(); int status = pthread_join(mThreadId, &res); objDestroyOOBRun(); @@ -284,17 +314,6 @@ Context::~Context() objDestroyOOBDestroy(); } -void Context::swapBuffers() -{ - eglSwapBuffers(mDisplay, mSurface); -} - -void rsContextSwap(RsContext vrsc) -{ - Context *rsc = static_cast<Context *>(vrsc); - rsc->swapBuffers(); -} - void Context::setRootScript(Script *s) { mRootScript.set(s); @@ -520,10 +539,10 @@ void rsi_ContextSetDefineI32(Context *rsc, const char* name, int32_t value) } -RsContext rsContextCreate(RsDevice vdev, void *sur, uint32_t version) +RsContext rsContextCreate(RsDevice vdev, void *sur, uint32_t version, bool useDepth) { Device * dev = static_cast<Device *>(vdev); - Context *rsc = new Context(dev, (Surface *)sur); + Context *rsc = new Context(dev, (Surface *)sur, useDepth); return rsc; } diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h index ca67e40..c58a88c 100644 --- a/libs/rs/rsContext.h +++ b/libs/rs/rsContext.h @@ -49,7 +49,7 @@ namespace renderscript { class Context { public: - Context(Device *, Surface *); + Context(Device *, Surface *, bool useDepth); ~Context(); static pthread_key_t gThreadTLSKey; @@ -111,8 +111,8 @@ public: mFloatDefines.add(String8(name), value); } - uint32_t getWidth() const {return mWidth;} - uint32_t getHeight() const {return mHeight;} + uint32_t getWidth() const {return mEGL.mWidth;} + uint32_t getHeight() const {return mEGL.mHeight;} ThreadIO mIO; @@ -132,21 +132,38 @@ public: void timerSet(Timers); void timerPrint(); + bool checkVersion1_1() const {return (mGL.mMajorVersion > 1) || (mGL.mMinorVersion >= 1); } + bool checkVersion2_0() const {return mGL.mMajorVersion >= 2; } + protected: Device *mDev; - EGLint mNumConfigs; - EGLint mMajorVersion; - EGLint mMinorVersion; - EGLConfig mConfig; - EGLContext mContext; - EGLSurface mSurface; - EGLint mWidth; - EGLint mHeight; - EGLDisplay mDisplay; + struct { + EGLint mNumConfigs; + EGLint mMajorVersion; + EGLint mMinorVersion; + EGLConfig mConfig; + EGLContext mContext; + EGLSurface mSurface; + EGLint mWidth; + EGLint mHeight; + EGLDisplay mDisplay; + } mEGL; + + struct { + const uint8_t * mVendor; + const uint8_t * mRenderer; + const uint8_t * mVersion; + const uint8_t * mExtensions; + + uint32_t mMajorVersion; + uint32_t mMinorVersion; + + } mGL; bool mRunning; bool mExit; + bool mUseDepth; pthread_t mThreadId; diff --git a/libs/rs/rsLocklessFifo.cpp b/libs/rs/rsLocklessFifo.cpp index c3fee54..0c40389 100644 --- a/libs/rs/rsLocklessFifo.cpp +++ b/libs/rs/rsLocklessFifo.cpp @@ -25,6 +25,16 @@ LocklessCommandFifo::LocklessCommandFifo() LocklessCommandFifo::~LocklessCommandFifo() { + if (!mInShutdown) { + shutdown(); + } + free(mBuffer); +} + +void LocklessCommandFifo::shutdown() +{ + mInShutdown = true; + mSignalToWorker.set(); } bool LocklessCommandFifo::init(uint32_t sizeInBytes) @@ -42,6 +52,7 @@ bool LocklessCommandFifo::init(uint32_t sizeInBytes) return false; } + mInShutdown = false; mSize = sizeInBytes; mPut = mBuffer; mGet = mBuffer; @@ -50,7 +61,7 @@ bool LocklessCommandFifo::init(uint32_t sizeInBytes) return true; } -uint32_t LocklessCommandFifo::getFreeSpace() const +uint32_t LocklessCommandFifo::getFreeSpace() const { int32_t freeSpace = 0; //dumpState("getFreeSpace"); @@ -115,7 +126,7 @@ const void * LocklessCommandFifo::get(uint32_t *command, uint32_t *bytesData) { while(1) { //dumpState("get"); - while(isEmpty()) { + while(isEmpty() && !mInShutdown) { mSignalToControl.set(); mSignalToWorker.wait(); } @@ -126,7 +137,7 @@ const void * LocklessCommandFifo::get(uint32_t *command, uint32_t *bytesData) // non-zero command is valid return mGet+4; } - + // zero command means reset to beginning. mGet = mBuffer; } @@ -161,7 +172,7 @@ void LocklessCommandFifo::makeSpace(uint32_t bytes) while(getFreeSpace() < bytes) { sleep(1); } - + } void LocklessCommandFifo::dumpState(const char *s) const diff --git a/libs/rs/rsLocklessFifo.h b/libs/rs/rsLocklessFifo.h index abeddf7..d0a4356 100644 --- a/libs/rs/rsLocklessFifo.h +++ b/libs/rs/rsLocklessFifo.h @@ -25,13 +25,14 @@ namespace android { // A simple FIFO to be used as a producer / consumer between two // threads. One is writer and one is reader. The common cases -// will not require locking. It is not threadsafe for multiple +// will not require locking. It is not threadsafe for multiple // readers or writers by design. -class LocklessCommandFifo +class LocklessCommandFifo { public: bool init(uint32_t size); + void shutdown(); LocklessCommandFifo(); ~LocklessCommandFifo(); @@ -59,6 +60,7 @@ protected: uint8_t * mBuffer; uint8_t * mEnd; uint8_t mSize; + bool mInShutdown; Signal mSignalToWorker; Signal mSignalToControl; diff --git a/libs/rs/rsObjectBase.cpp b/libs/rs/rsObjectBase.cpp index 6a5b7d8..07bbc1e 100644 --- a/libs/rs/rsObjectBase.cpp +++ b/libs/rs/rsObjectBase.cpp @@ -43,6 +43,11 @@ void ObjectBase::decRef() const mRefCount --; //LOGV("ObjectBase %p dec ref %i", this, mRefCount); if (!mRefCount) { + if (mName) { + LOGV("Deleting RS object %p, name %s", this, mName); + } else { + LOGV("Deleting RS object %p, no name", this); + } delete this; } } diff --git a/libs/rs/rsProgram.cpp b/libs/rs/rsProgram.cpp index 6606daa..18eacfb 100644 --- a/libs/rs/rsProgram.cpp +++ b/libs/rs/rsProgram.cpp @@ -47,9 +47,3 @@ void Program::checkUpdatedAllocation(const Allocation *alloc) } } -void Program::setupGL() -{ - -} - - diff --git a/libs/rs/rsProgram.h b/libs/rs/rsProgram.h index 251072f..bb3d9ac 100644 --- a/libs/rs/rsProgram.h +++ b/libs/rs/rsProgram.h @@ -32,11 +32,7 @@ public: Program(Element *in, Element *out); virtual ~Program(); - void bindAllocation(Allocation *); - - virtual void setupGL(); - void checkUpdatedAllocation(const Allocation *); protected: diff --git a/libs/rs/rsProgramFragment.cpp b/libs/rs/rsProgramFragment.cpp index 4ef6835..654974f 100644 --- a/libs/rs/rsProgramFragment.cpp +++ b/libs/rs/rsProgramFragment.cpp @@ -40,7 +40,7 @@ ProgramFragment::~ProgramFragment() { } -void ProgramFragment::setupGL(ProgramFragmentState *state) +void ProgramFragment::setupGL(const Context *rsc, ProgramFragmentState *state) { if ((state->mLast.get() == this) && !mDirty) { return; @@ -55,7 +55,9 @@ void ProgramFragment::setupGL(ProgramFragmentState *state) } glEnable(GL_TEXTURE_2D); - //glTexEnvi(GL_POINT_SPRITE_OES, GL_COORD_REPLACE_OES, mPointSpriteEnable); + if (rsc->checkVersion1_1()) { + glTexEnvi(GL_POINT_SPRITE_OES, GL_COORD_REPLACE_OES, mPointSpriteEnable); + } glBindTexture(GL_TEXTURE_2D, mTextures[ct]->getTextureID()); switch(mEnvModes[ct]) { diff --git a/libs/rs/rsProgramFragment.h b/libs/rs/rsProgramFragment.h index bd45342..51117eb 100644 --- a/libs/rs/rsProgramFragment.h +++ b/libs/rs/rsProgramFragment.h @@ -35,7 +35,7 @@ public: ProgramFragment(Element *in, Element *out, bool pointSpriteEnable); virtual ~ProgramFragment(); - virtual void setupGL(ProgramFragmentState *); + virtual void setupGL(const Context *, ProgramFragmentState *); diff --git a/libs/rs/rsProgramFragmentStore.cpp b/libs/rs/rsProgramFragmentStore.cpp index 99eed16..36ec615 100644 --- a/libs/rs/rsProgramFragmentStore.cpp +++ b/libs/rs/rsProgramFragmentStore.cpp @@ -48,7 +48,7 @@ ProgramFragmentStore::~ProgramFragmentStore() { } -void ProgramFragmentStore::setupGL(ProgramFragmentStoreState *state) +void ProgramFragmentStore::setupGL(const Context *rsc, ProgramFragmentStoreState *state) { if (state->mLast.get() == this) { return; diff --git a/libs/rs/rsProgramFragmentStore.h b/libs/rs/rsProgramFragmentStore.h index 0de5c3a..e646e03 100644 --- a/libs/rs/rsProgramFragmentStore.h +++ b/libs/rs/rsProgramFragmentStore.h @@ -31,7 +31,7 @@ public: ProgramFragmentStore(Element *in, Element *out); virtual ~ProgramFragmentStore(); - virtual void setupGL(ProgramFragmentStoreState *); + virtual void setupGL(const Context *, ProgramFragmentStoreState *); void setDepthFunc(RsDepthFunc); void setDepthMask(bool); diff --git a/libs/rs/rsProgramVertex.cpp b/libs/rs/rsProgramVertex.cpp index 6ef5456..dc57d34 100644 --- a/libs/rs/rsProgramVertex.cpp +++ b/libs/rs/rsProgramVertex.cpp @@ -44,7 +44,7 @@ static void logMatrix(const char *txt, const float *f) LOGV("%6.2f, %6.2f, %6.2f, %6.2f", f[3], f[7], f[11], f[15]); } -void ProgramVertex::setupGL(ProgramVertexState *state) +void ProgramVertex::setupGL(const Context *rsc, ProgramVertexState *state) { if ((state->mLast.get() == this) && !mDirty) { return; diff --git a/libs/rs/rsProgramVertex.h b/libs/rs/rsProgramVertex.h index c9ce7aa..523c3ed 100644 --- a/libs/rs/rsProgramVertex.h +++ b/libs/rs/rsProgramVertex.h @@ -33,7 +33,7 @@ public: ProgramVertex(Element *in, Element *out); virtual ~ProgramVertex(); - virtual void setupGL(ProgramVertexState *state); + virtual void setupGL(const Context *rsc, ProgramVertexState *state); void setTextureMatrixEnable(bool e) {mTextureMatrixEnable = e;} diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp index db4fd09..9419829 100644 --- a/libs/rs/rsScriptC.cpp +++ b/libs/rs/rsScriptC.cpp @@ -267,7 +267,7 @@ void ScriptCState::appendTypes(String8 *str) tmp.append(c->getComponentName()); sprintf(buf, " %i\n", ct2); tmp.append(buf); - LOGD(tmp); + //LOGD(tmp); str->append(tmp); } } @@ -295,7 +295,7 @@ void ScriptCState::appendTypes(String8 *str) sprintf(buf, "%i, %i)\n", ct, ct2); tmp.append(buf); - LOGD(tmp); + //LOGD(tmp); str->append(tmp); } } diff --git a/libs/rs/rsThreadIO.cpp b/libs/rs/rsThreadIO.cpp index 4a1dbbb..db4bb81 100644 --- a/libs/rs/rsThreadIO.cpp +++ b/libs/rs/rsThreadIO.cpp @@ -30,6 +30,11 @@ ThreadIO::~ThreadIO() { } +void ThreadIO::shutdown() +{ + mToCore.shutdown(); +} + bool ThreadIO::playCoreCommands(Context *con, bool waitForCommand) { bool ret = false; diff --git a/libs/rs/rsThreadIO.h b/libs/rs/rsThreadIO.h index 4aab1b4..1f6a0c2 100644 --- a/libs/rs/rsThreadIO.h +++ b/libs/rs/rsThreadIO.h @@ -31,6 +31,8 @@ public: ThreadIO(); ~ThreadIO(); + void shutdown(); + // Plays back commands from the client. // Returns true if any commands were processed. bool playCoreCommands(Context *con, bool waitForCommand); diff --git a/location/java/com/android/internal/location/GpsLocationProvider.java b/location/java/com/android/internal/location/GpsLocationProvider.java index bdef01f..0b4fb88 100755 --- a/location/java/com/android/internal/location/GpsLocationProvider.java +++ b/location/java/com/android/internal/location/GpsLocationProvider.java @@ -728,7 +728,7 @@ public class GpsLocationProvider extends ILocationProvider.Stub { mStarted = true; int positionMode; if (Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.ASSISTED_GPS_ENABLED, 0) != 0) { + Settings.Secure.ASSISTED_GPS_ENABLED, 1) != 0) { positionMode = GPS_POSITION_MODE_MS_BASED; } else { positionMode = GPS_POSITION_MODE_STANDALONE; diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 16bf8a2..de944ee 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -816,37 +816,44 @@ public class AudioManager { /* Routing bits for setRouting/getRouting API */ /** * Routing audio output to earpiece - * @deprecated + * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), + * setBluetoothScoOn() methods instead. */ @Deprecated public static final int ROUTE_EARPIECE = AudioSystem.ROUTE_EARPIECE; /** - * Routing audio output to spaker - * @deprecated + * Routing audio output to speaker + * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), + * setBluetoothScoOn() methods instead. */ @Deprecated public static final int ROUTE_SPEAKER = AudioSystem.ROUTE_SPEAKER; /** * @deprecated use {@link #ROUTE_BLUETOOTH_SCO} - * @deprecated + * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), + * setBluetoothScoOn() methods instead. */ @Deprecated public static final int ROUTE_BLUETOOTH = AudioSystem.ROUTE_BLUETOOTH_SCO; /** * Routing audio output to bluetooth SCO - * @deprecated + * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), + * setBluetoothScoOn() methods instead. */ @Deprecated public static final int ROUTE_BLUETOOTH_SCO = AudioSystem.ROUTE_BLUETOOTH_SCO; /** * Routing audio output to headset - * @deprecated + * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), + * setBluetoothScoOn() methods instead. */ @Deprecated public static final int ROUTE_HEADSET = AudioSystem.ROUTE_HEADSET; /** * Routing audio output to bluetooth A2DP - * @deprecated + * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), + * setBluetoothScoOn() methods instead. */ @Deprecated public static final int ROUTE_BLUETOOTH_A2DP = AudioSystem.ROUTE_BLUETOOTH_A2DP; /** * Used for mask parameter of {@link #setRouting(int,int,int)}. - * @deprecated + * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), + * setBluetoothScoOn() methods instead. */ @Deprecated public static final int ROUTE_ALL = AudioSystem.ROUTE_ALL; diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index 0a1b142..d1b9351 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -144,16 +144,16 @@ public class AudioService extends IAudioService.Stub { /** @hide Maximum volume index values for audio streams */ private int[] MAX_STREAM_VOLUME = new int[] { - 6, // STREAM_VOICE_CALL - 8, // STREAM_SYSTEM - 8, // STREAM_RING - 16, // STREAM_MUSIC - 8, // STREAM_ALARM - 8, // STREAM_NOTIFICATION - 16, // STREAM_BLUETOOTH_SCO - 8, // STREAM_SYSTEM_ENFORCED - 16, // STREAM_DTMF - 16 // STREAM_TTS + 5, // STREAM_VOICE_CALL + 7, // STREAM_SYSTEM + 7, // STREAM_RING + 15, // STREAM_MUSIC + 7, // STREAM_ALARM + 7, // STREAM_NOTIFICATION + 15, // STREAM_BLUETOOTH_SCO + 7, // STREAM_SYSTEM_ENFORCED + 15, // STREAM_DTMF + 15 // STREAM_TTS }; /* STREAM_VOLUME_ALIAS[] indicates for each stream if it uses the volume settings * of another stream: This avoids multiplying the volume settings for hidden diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index d587f65..dbf6d9d 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -93,8 +93,9 @@ public class AudioSystem * * return the current audio mode (NORMAL, RINGTONE, or IN_CALL). * Returns the current current audio state from the HAL. + * */ - /** @deprecated */ + /** @deprecated Do not use. */ public static int getMode() { return MODE_INVALID; } diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index a8689f2..6a9a9bd 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -539,7 +539,7 @@ public class MediaPlayer * @param request Parcel with the data for the extension. The * caller must use {@link #newRequest()} to get one. * - * @param[out] reply Parcel with the data returned by the + * @param reply Output parcel with the data returned by the * native player. * * @return The status code see utils/Errors.h diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java index 46ede7f..9bb00c6 100644 --- a/media/java/android/media/MediaRecorder.java +++ b/media/java/android/media/MediaRecorder.java @@ -168,7 +168,7 @@ public class MediaRecorder /** The following formats are audio only .aac or .amr formats **/ /** @deprecated Deprecated in favor of AMR_NB */ - /** @todo change link when AMR_NB is exposed. Deprecated in favor of {@link MediaRecorder.OutputFormat#AMR_NB} */ + /** TODO: change link when AMR_NB is exposed. Deprecated in favor of MediaRecorder.OutputFormat.AMR_NB */ public static final int RAW_AMR = 3; /** @hide AMR NB file format */ public static final int AMR_NB = 3; diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp index e8571b5..140bc68 100644 --- a/media/libstagefright/AudioPlayer.cpp +++ b/media/libstagefright/AudioPlayer.cpp @@ -14,14 +14,12 @@ * limitations under the License. */ -#undef NDEBUG -#include <assert.h> - #define LOG_TAG "AudioPlayer" #include <utils/Log.h> #include <media/AudioTrack.h> #include <media/stagefright/AudioPlayer.h> +#include <media/stagefright/MediaDebug.h> #include <media/stagefright/MediaSource.h> #include <media/stagefright/MetaData.h> @@ -48,36 +46,36 @@ AudioPlayer::~AudioPlayer() { } void AudioPlayer::setSource(const sp<MediaSource> &source) { - assert(mSource == NULL); + CHECK_EQ(mSource, NULL); mSource = source; } void AudioPlayer::start() { - assert(!mStarted); - assert(mSource != NULL); + CHECK(!mStarted); + CHECK(mSource != NULL); status_t err = mSource->start(); - assert(err == OK); + CHECK_EQ(err, OK); sp<MetaData> format = mSource->getFormat(); const char *mime; bool success = format->findCString(kKeyMIMEType, &mime); - assert(success); - assert(!strcasecmp(mime, "audio/raw")); + CHECK(success); + CHECK(!strcasecmp(mime, "audio/raw")); success = format->findInt32(kKeySampleRate, &mSampleRate); - assert(success); + CHECK(success); int32_t numChannels; success = format->findInt32(kKeyChannelCount, &numChannels); - assert(success); + CHECK(success); if (mAudioSink.get() != NULL) { status_t err = mAudioSink->open( mSampleRate, numChannels, AudioSystem::PCM_16_BIT, DEFAULT_AUDIOSINK_BUFFERCOUNT, &AudioPlayer::AudioSinkCallback, this); - assert(err == OK); + CHECK_EQ(err, OK); mLatencyUs = (int64_t)mAudioSink->latency() * 1000; mFrameSize = mAudioSink->frameSize(); @@ -91,7 +89,7 @@ void AudioPlayer::start() { : AudioSystem::CHANNEL_OUT_MONO, 8192, 0, &AudioCallback, this, 0); - assert(mAudioTrack->initCheck() == OK); + CHECK_EQ(mAudioTrack->initCheck(), OK); mLatencyUs = (int64_t)mAudioTrack->latency() * 1000; mFrameSize = mAudioTrack->frameSize(); @@ -103,7 +101,7 @@ void AudioPlayer::start() { } void AudioPlayer::pause() { - assert(mStarted); + CHECK(mStarted); if (mAudioSink.get() != NULL) { mAudioSink->pause(); @@ -113,7 +111,7 @@ void AudioPlayer::pause() { } void AudioPlayer::resume() { - assert(mStarted); + CHECK(mStarted); if (mAudioSink.get() != NULL) { mAudioSink->start(); @@ -123,7 +121,7 @@ void AudioPlayer::resume() { } void AudioPlayer::stop() { - assert(mStarted); + CHECK(mStarted); if (mAudioSink.get() != NULL) { mAudioSink->stop(); @@ -202,7 +200,7 @@ void AudioPlayer::fillBuffer(void *data, size_t size) { if (mInputBuffer == NULL) { status_t err = mSource->read(&mInputBuffer, &options); - assert((err == OK && mInputBuffer != NULL) + CHECK((err == OK && mInputBuffer != NULL) || (err != OK && mInputBuffer == NULL)); if (err != OK) { @@ -215,7 +213,7 @@ void AudioPlayer::fillBuffer(void *data, size_t size) { mInputBuffer->meta_data()->findInt32(kKeyTimeUnits, &units); success = success && mInputBuffer->meta_data()->findInt32(kKeyTimeScale, &scale); - assert(success); + CHECK(success); Mutex::Autolock autoLock(mLock); mPositionTimeMediaUs = (int64_t)units * 1000000 / scale; diff --git a/media/libstagefright/CachingDataSource.cpp b/media/libstagefright/CachingDataSource.cpp index d599cd5..fd00576 100644 --- a/media/libstagefright/CachingDataSource.cpp +++ b/media/libstagefright/CachingDataSource.cpp @@ -14,14 +14,12 @@ * limitations under the License. */ -#include <media/stagefright/CachingDataSource.h> - -#undef NDEBUG -#include <assert.h> - #include <stdlib.h> #include <string.h> +#include <media/stagefright/CachingDataSource.h> +#include <media/stagefright/MediaDebug.h> + namespace android { CachingDataSource::CachingDataSource( diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp index ee12873..f75b173 100644 --- a/media/libstagefright/CameraSource.cpp +++ b/media/libstagefright/CameraSource.cpp @@ -16,13 +16,11 @@ #include <sys/time.h> -#undef NDEBUG -#include <assert.h> - #include <OMX_Component.h> #include <binder/IServiceManager.h> #include <media/stagefright/CameraSource.h> +#include <media/stagefright/MediaDebug.h> #include <media/stagefright/MediaErrors.h> #include <media/stagefright/MetaData.h> #include <ui/ICameraClient.h> @@ -56,12 +54,12 @@ public: } virtual void notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) { - assert(mSource != NULL); + CHECK(mSource != NULL); mSource->notifyCallback(msgType, ext1, ext2); } virtual void dataCallback(int32_t msgType, const sp<IMemory> &data) { - assert(mSource != NULL); + CHECK(mSource != NULL); mSource->dataCallback(msgType, data); } @@ -128,16 +126,16 @@ CameraSource::~CameraSource() { } status_t CameraSource::start(MetaData *) { - assert(!mStarted); + CHECK(!mStarted); status_t err = mCamera->lock(); - assert(err == OK); + CHECK_EQ(err, OK); err = mCamera->setPreviewDisplay(new DummySurface); - assert(err == OK); + CHECK_EQ(err, OK); mCamera->setPreviewCallbackFlag(1); mCamera->startPreview(); - assert(err == OK); + CHECK_EQ(err, OK); mStarted = true; @@ -145,7 +143,7 @@ status_t CameraSource::start(MetaData *) { } status_t CameraSource::stop() { - assert(mStarted); + CHECK(mStarted); mCamera->stopPreview(); mCamera->unlock(); @@ -167,7 +165,7 @@ sp<MetaData> CameraSource::getFormat() { status_t CameraSource::read( MediaBuffer **buffer, const ReadOptions *options) { - assert(mStarted); + CHECK(mStarted); *buffer = NULL; diff --git a/media/libstagefright/FileSource.cpp b/media/libstagefright/FileSource.cpp index c26d0a0..f6b90b2 100644 --- a/media/libstagefright/FileSource.cpp +++ b/media/libstagefright/FileSource.cpp @@ -15,9 +15,7 @@ */ #include <media/stagefright/FileSource.h> - -#undef NDEBUG -#include <assert.h> +#include <media/stagefright/MediaDebug.h> namespace android { @@ -40,7 +38,7 @@ ssize_t FileSource::read_at(off_t offset, void *data, size_t size) { Mutex::Autolock autoLock(mLock); int err = fseeko(mFile, offset, SEEK_SET); - assert(err != -1); + CHECK(err != -1); ssize_t result = fread(data, 1, size, mFile); diff --git a/media/libstagefright/HTTPDataSource.cpp b/media/libstagefright/HTTPDataSource.cpp index d1f8cd4..698223b 100644 --- a/media/libstagefright/HTTPDataSource.cpp +++ b/media/libstagefright/HTTPDataSource.cpp @@ -14,13 +14,11 @@ * limitations under the License. */ -#undef NDEBUG -#include <assert.h> - #include <stdlib.h> #include <media/stagefright/HTTPDataSource.h> #include <media/stagefright/HTTPStream.h> +#include <media/stagefright/MediaDebug.h> #include <media/stagefright/string.h> namespace android { @@ -32,7 +30,7 @@ HTTPDataSource::HTTPDataSource(const char *uri) mBuffer(malloc(kBufferSize)), mBufferLength(0), mBufferOffset(0) { - assert(!strncasecmp("http://", uri, 7)); + CHECK(!strncasecmp("http://", uri, 7)); string host; string path; @@ -53,8 +51,8 @@ HTTPDataSource::HTTPDataSource(const char *uri) } else { char *end; long tmp = strtol(colon + 1, &end, 10); - assert(end > colon + 1); - assert(tmp > 0 && tmp < 65536); + CHECK(end > colon + 1); + CHECK(tmp > 0 && tmp < 65536); port = tmp; host = string(host, 0, colon - host.c_str()); @@ -68,7 +66,7 @@ HTTPDataSource::HTTPDataSource(const char *uri) mPath = strdup(path.c_str()); status_t err = mHttp.connect(mHost, mPort); - assert(err == OK); + CHECK_EQ(err, OK); } HTTPDataSource::HTTPDataSource(const char *host, int port, const char *path) @@ -79,7 +77,7 @@ HTTPDataSource::HTTPDataSource(const char *host, int port, const char *path) mBufferLength(0), mBufferOffset(0) { status_t err = mHttp.connect(mHost, mPort); - assert(err == OK); + CHECK_EQ(err, OK); } HTTPDataSource::~HTTPDataSource() { diff --git a/media/libstagefright/HTTPStream.cpp b/media/libstagefright/HTTPStream.cpp index 29e6f72..098ddbd 100644 --- a/media/libstagefright/HTTPStream.cpp +++ b/media/libstagefright/HTTPStream.cpp @@ -17,7 +17,6 @@ #include <sys/socket.h> #include <arpa/inet.h> -#include <assert.h> #include <ctype.h> #include <errno.h> #include <netdb.h> @@ -27,6 +26,7 @@ #include <unistd.h> #include <media/stagefright/HTTPStream.h> +#include <media/stagefright/MediaDebug.h> namespace android { @@ -49,7 +49,7 @@ status_t HTTPStream::connect(const char *server, int port) { return ERROR_ALREADY_CONNECTED; } - assert(mSocket == -1); + CHECK_EQ(mSocket, -1); mSocket = socket(AF_INET, SOCK_STREAM, 0); if (mSocket < 0) { @@ -89,7 +89,7 @@ status_t HTTPStream::disconnect() { return ERROR_NOT_CONNECTED; } - assert(mSocket >= 0); + CHECK(mSocket >= 0); close(mSocket); mSocket = -1; @@ -165,7 +165,7 @@ status_t HTTPStream::receive_line(char *line, size_t size) { saw_CR = (c == '\r'); - assert(length + 1 < size); + CHECK(length + 1 < size); line[length++] = c; } } diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp index 44258ba..14f3e0c 100644 --- a/media/libstagefright/MP3Extractor.cpp +++ b/media/libstagefright/MP3Extractor.cpp @@ -18,13 +18,11 @@ #define LOG_TAG "MP3Extractor" #include <utils/Log.h> -#undef NDEBUG -#include <assert.h> - #include <media/stagefright/DataSource.h> #include <media/stagefright/MP3Extractor.h> #include <media/stagefright/MediaBuffer.h> #include <media/stagefright/MediaBufferGroup.h> +#include <media/stagefright/MediaDebug.h> #include <media/stagefright/MediaErrors.h> #include <media/stagefright/MediaSource.h> #include <media/stagefright/MetaData.h> @@ -317,7 +315,7 @@ MP3Extractor::MP3Extractor(const sp<DataSource> &source) off_t pos = 0; uint32_t header; bool success = Resync(mDataSource, 0, &pos, &header); - assert(success); + CHECK(success); if (success) { mFirstFramePos = pos; @@ -393,7 +391,7 @@ MP3Source::~MP3Source() { } status_t MP3Source::start(MetaData *) { - assert(!mStarted); + CHECK(!mStarted); mGroup = new MediaBufferGroup; @@ -409,7 +407,7 @@ status_t MP3Source::start(MetaData *) { } status_t MP3Source::stop() { - assert(mStarted); + CHECK(mStarted); delete mGroup; mGroup = NULL; @@ -481,7 +479,7 @@ status_t MP3Source::read( // Try again with the new position. } - assert(frame_size <= buffer->size()); + CHECK(frame_size <= buffer->size()); ssize_t n = mDataSource->read_at(mCurrentPos, buffer->data(), frame_size); if (n < (ssize_t)frame_size) { diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp index 10c4629..90b1b9a 100644 --- a/media/libstagefright/MPEG4Writer.cpp +++ b/media/libstagefright/MPEG4Writer.cpp @@ -16,15 +16,13 @@ #include <arpa/inet.h> -#undef NDEBUG -#include <assert.h> - #include <ctype.h> #include <pthread.h> #include <media/stagefright/MPEG4Writer.h> #include <media/stagefright/MediaBuffer.h> #include <media/stagefright/MetaData.h> +#include <media/stagefright/MediaDebug.h> #include <media/stagefright/MediaSource.h> #include <media/stagefright/Utils.h> @@ -71,7 +69,7 @@ MPEG4Writer::MPEG4Writer(const char *filename) : mFile(fopen(filename, "wb")), mOffset(0), mMdatOffset(0) { - assert(mFile != NULL); + CHECK(mFile != NULL); } MPEG4Writer::~MPEG4Writer() { @@ -173,7 +171,7 @@ void MPEG4Writer::stop() { } endBox(); // moov - assert(mBoxes.empty()); + CHECK(mBoxes.empty()); fclose(mFile); mFile = NULL; @@ -193,7 +191,7 @@ off_t MPEG4Writer::addSample(MediaBuffer *buffer) { } void MPEG4Writer::beginBox(const char *fourcc) { - assert(strlen(fourcc) == 4); + CHECK_EQ(strlen(fourcc), 4); mBoxes.push_back(mOffset); @@ -202,7 +200,7 @@ void MPEG4Writer::beginBox(const char *fourcc) { } void MPEG4Writer::endBox() { - assert(!mBoxes.empty()); + CHECK(!mBoxes.empty()); off_t offset = *--mBoxes.end(); mBoxes.erase(--mBoxes.end()); @@ -244,7 +242,7 @@ void MPEG4Writer::writeCString(const char *s) { } void MPEG4Writer::writeFourcc(const char *s) { - assert(strlen(s) == 4); + CHECK_EQ(strlen(s), 4); fwrite(s, 1, 4, mFile); mOffset += 4; } @@ -286,7 +284,7 @@ void MPEG4Writer::Track::start() { mDone = false; int err = pthread_create(&mThread, &attr, ThreadWrapper, this); - assert(err == 0); + CHECK_EQ(err, 0); pthread_attr_destroy(&attr); } @@ -345,7 +343,7 @@ void MPEG4Writer::Track::threadEntry() { ++offset; } - // assert(offset + 3 < size); + // CHECK(offset + 3 < size); if (offset + 3 >= size) { // XXX assume the entire first chunk of data is the codec specific // data. @@ -368,10 +366,10 @@ void MPEG4Writer::Track::threadEntry() { int32_t units, scale; bool success = buffer->meta_data()->findInt32(kKeyTimeUnits, &units); - assert(success); + CHECK(success); success = buffer->meta_data()->findInt32(kKeyTimeScale, &scale); - assert(success); + CHECK(success); info.timestamp = (int64_t)units * 1000 / scale; @@ -389,7 +387,7 @@ int64_t MPEG4Writer::Track::getDuration() const { void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) { const char *mime; bool success = mMeta->findCString(kKeyMIMEType, &mime); - assert(success); + CHECK(success); bool is_audio = !strncasecmp(mime, "audio/", 6); @@ -428,7 +426,7 @@ void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) { int32_t width, height; bool success = mMeta->findInt32(kKeyWidth, &width); success = success && mMeta->findInt32(kKeyHeight, &height); - assert(success); + CHECK(success); mOwner->writeInt32(width); mOwner->writeInt32(height); @@ -505,7 +503,7 @@ void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) { int32_t samplerate; bool success = mMeta->findInt32(kKeySampleRate, &samplerate); - assert(success); + CHECK(success); mOwner->writeInt32(samplerate << 16); mOwner->endBox(); @@ -515,7 +513,7 @@ void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) { } else if (!strcasecmp("video/3gpp", mime)) { mOwner->beginBox("s263"); } else { - assert(!"should not be here, unknown mime type."); + CHECK(!"should not be here, unknown mime type."); } mOwner->writeInt32(0); // reserved @@ -530,7 +528,7 @@ void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) { int32_t width, height; bool success = mMeta->findInt32(kKeyWidth, &width); success = success && mMeta->findInt32(kKeyHeight, &height); - assert(success); + CHECK(success); mOwner->writeInt16(width); mOwner->writeInt16(height); @@ -542,7 +540,7 @@ void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) { mOwner->writeInt16(0x18); // depth mOwner->writeInt16(-1); // predefined - assert(23 + mCodecSpecificDataSize < 128); + CHECK(23 + mCodecSpecificDataSize < 128); if (!strcasecmp("video/mp4v-es", mime)) { mOwner->beginBox("esds"); diff --git a/media/libstagefright/MediaBuffer.cpp b/media/libstagefright/MediaBuffer.cpp index cd78dbd..f3c0e73 100644 --- a/media/libstagefright/MediaBuffer.cpp +++ b/media/libstagefright/MediaBuffer.cpp @@ -17,14 +17,12 @@ #define LOG_TAG "MediaBuffer" #include <utils/Log.h> -#undef NDEBUG -#include <assert.h> - #include <errno.h> #include <pthread.h> #include <stdlib.h> #include <media/stagefright/MediaBuffer.h> +#include <media/stagefright/MediaDebug.h> #include <media/stagefright/MetaData.h> namespace android { @@ -65,7 +63,7 @@ MediaBuffer::MediaBuffer(size_t size) void MediaBuffer::release() { if (mObserver == NULL) { - assert(mRefCount == 0); + CHECK_EQ(mRefCount, 0); delete this; return; } @@ -79,12 +77,12 @@ void MediaBuffer::release() { mObserver->signalBufferReturned(this); } - assert(prevCount > 0); + CHECK(prevCount > 0); } void MediaBuffer::claim() { - assert(mObserver != NULL); - assert(mRefCount == 1); + CHECK(mObserver != NULL); + CHECK_EQ(mRefCount, 1); mRefCount = 0; } @@ -113,7 +111,7 @@ void MediaBuffer::set_range(size_t offset, size_t length) { if (offset < 0 || offset + length > mSize) { LOGE("offset = %d, length = %d, mSize = %d", offset, length, mSize); } - assert(offset >= 0 && offset + length <= mSize); + CHECK(offset >= 0 && offset + length <= mSize); mRangeOffset = offset; mRangeLength = length; @@ -129,7 +127,7 @@ void MediaBuffer::reset() { } MediaBuffer::~MediaBuffer() { - assert(mObserver == NULL); + CHECK_EQ(mObserver, NULL); if (mOwnsData && mData != NULL) { free(mData); @@ -143,7 +141,7 @@ MediaBuffer::~MediaBuffer() { } void MediaBuffer::setObserver(MediaBufferObserver *observer) { - assert(observer == NULL || mObserver == NULL); + CHECK(observer == NULL || mObserver == NULL); mObserver = observer; } diff --git a/media/libstagefright/MediaBufferGroup.cpp b/media/libstagefright/MediaBufferGroup.cpp index aec7722..c8d05f4 100644 --- a/media/libstagefright/MediaBufferGroup.cpp +++ b/media/libstagefright/MediaBufferGroup.cpp @@ -17,11 +17,9 @@ #define LOG_TAG "MediaBufferGroup" #include <utils/Log.h> -#undef NDEBUG -#include <assert.h> - #include <media/stagefright/MediaBuffer.h> #include <media/stagefright/MediaBufferGroup.h> +#include <media/stagefright/MediaDebug.h> namespace android { @@ -36,7 +34,7 @@ MediaBufferGroup::~MediaBufferGroup() { buffer = next) { next = buffer->nextBuffer(); - assert(buffer->refcount() == 0); + CHECK_EQ(buffer->refcount(), 0); buffer->setObserver(NULL); buffer->release(); diff --git a/media/libstagefright/MediaPlayerImpl.cpp b/media/libstagefright/MediaPlayerImpl.cpp index 2d7b628..e5301bb 100644 --- a/media/libstagefright/MediaPlayerImpl.cpp +++ b/media/libstagefright/MediaPlayerImpl.cpp @@ -18,9 +18,6 @@ #define LOG_TAG "MediaPlayerImpl" #include "utils/Log.h" -#undef NDEBUG -#include <assert.h> - #include <OMX_Component.h> #include <unistd.h> @@ -30,6 +27,7 @@ // #include <media/stagefright/CameraSource.h> #include <media/stagefright/HTTPDataSource.h> #include <media/stagefright/HTTPStream.h> +#include <media/stagefright/MediaDebug.h> #include <media/stagefright/MediaExtractor.h> #include <media/stagefright/MediaPlayerImpl.h> #include <media/stagefright/MetaData.h> @@ -227,7 +225,7 @@ void MediaPlayerImpl::videoEntry() { bool eof = false; status_t err = mVideoDecoder->start(); - assert(err == OK); + CHECK_EQ(err, OK); while (mPlaying) { MediaBuffer *buffer; @@ -253,7 +251,7 @@ void MediaPlayerImpl::videoEntry() { } status_t err = mVideoDecoder->read(&buffer, &options); - assert((err == OK && buffer != NULL) || (err != OK && buffer == NULL)); + CHECK((err == OK && buffer != NULL) || (err != OK && buffer == NULL)); if (err == ERROR_END_OF_STREAM || err != OK) { eof = true; @@ -269,10 +267,10 @@ void MediaPlayerImpl::videoEntry() { int32_t units, scale; bool success = buffer->meta_data()->findInt32(kKeyTimeUnits, &units); - assert(success); + CHECK(success); success = buffer->meta_data()->findInt32(kKeyTimeScale, &scale); - assert(success); + CHECK(success); int64_t pts_us = (int64_t)units * 1000000 / scale; { @@ -362,7 +360,7 @@ void MediaPlayerImpl::init() { for (size_t i = 0; i < num_tracks; ++i) { const sp<MetaData> meta = mExtractor->getTrackMetaData(i); - assert(meta != NULL); + CHECK(meta != NULL); const char *mime; if (!meta->findCString(kKeyMIMEType, &mime)) { @@ -424,10 +422,10 @@ void MediaPlayerImpl::setVideoSource(const sp<MediaSource> &source) { sp<MetaData> meta = source->getFormat(); bool success = meta->findInt32(kKeyWidth, &mVideoWidth); - assert(success); + CHECK(success); success = meta->findInt32(kKeyHeight, &mVideoHeight); - assert(success); + CHECK(success); #if !USE_OMX_CODEC mVideoDecoder = OMXDecoder::Create( @@ -495,8 +493,8 @@ MediaSource *MediaPlayerImpl::makeShoutcastSource(const char *uri) { } else { char *end; long tmp = strtol(colon + 1, &end, 10); - assert(end > colon + 1); - assert(tmp > 0 && tmp < 65536); + CHECK(end > colon + 1); + CHECK(tmp > 0 && tmp < 65536); port = tmp; host = string(host, 0, colon - host.c_str()); @@ -510,7 +508,7 @@ MediaSource *MediaPlayerImpl::makeShoutcastSource(const char *uri) { for (;;) { status_t err = http->connect(host.c_str(), port); - assert(err == OK); + CHECK_EQ(err, OK); err = http->send("GET "); err = http->send(path.c_str()); @@ -520,13 +518,13 @@ MediaSource *MediaPlayerImpl::makeShoutcastSource(const char *uri) { err = http->send("\r\n"); err = http->send("Icy-MetaData: 1\r\n\r\n"); - assert(OK == http->receive_header(&http_status)); + CHECK_EQ(OK, http->receive_header(&http_status)); if (http_status == 301 || http_status == 302) { string location; - assert(http->find_header_value("Location", &location)); + CHECK(http->find_header_value("Location", &location)); - assert(string(location, 0, 7) == "http://"); + CHECK(string(location, 0, 7) == "http://"); location.erase(0, 7); string::size_type slashPos = location.find('/'); if (slashPos == string::npos) { @@ -545,7 +543,7 @@ MediaSource *MediaPlayerImpl::makeShoutcastSource(const char *uri) { const char *start = host.c_str() + colonPos + 1; char *end; long tmp = strtol(start, &end, 10); - assert(end > start && *end == '\0'); + CHECK(end > start && (*end == '\0')); port = (tmp >= 0 && tmp < 65536) ? (int)tmp : 80; } else { @@ -622,7 +620,7 @@ void MediaPlayerImpl::populateISurface() { success = success && meta->findCString(kKeyDecoderComponent, &component); success = success && meta->findInt32(kKeyWidth, &decodedWidth); success = success && meta->findInt32(kKeyHeight, &decodedHeight); - assert(success); + CHECK(success); if (mSurface.get() != NULL) { mVideoRenderer = diff --git a/media/libstagefright/MetaData.cpp b/media/libstagefright/MetaData.cpp index 5d23732b..6b067cb 100644 --- a/media/libstagefright/MetaData.cpp +++ b/media/libstagefright/MetaData.cpp @@ -14,10 +14,10 @@ * limitations under the License. */ -#include <assert.h> #include <stdlib.h> #include <string.h> +#include <media/stagefright/MediaDebug.h> #include <media/stagefright/MetaData.h> namespace android { @@ -87,7 +87,7 @@ bool MetaData::findInt32(uint32_t key, int32_t *value) { return false; } - assert(size == sizeof(*value)); + CHECK_EQ(size, sizeof(*value)); *value = *(int32_t *)data; @@ -102,7 +102,7 @@ bool MetaData::findFloat(uint32_t key, float *value) { return false; } - assert(size == sizeof(*value)); + CHECK_EQ(size, sizeof(*value)); *value = *(float *)data; @@ -117,7 +117,7 @@ bool MetaData::findPointer(uint32_t key, void **value) { return false; } - assert(size == sizeof(*value)); + CHECK_EQ(size, sizeof(*value)); *value = *(void **)data; diff --git a/media/libstagefright/MmapSource.cpp b/media/libstagefright/MmapSource.cpp index 7cb861c..47d95f9 100644 --- a/media/libstagefright/MmapSource.cpp +++ b/media/libstagefright/MmapSource.cpp @@ -20,13 +20,11 @@ #include <sys/mman.h> -#undef NDEBUG -#include <assert.h> - #include <fcntl.h> #include <string.h> #include <unistd.h> +#include <media/stagefright/MediaDebug.h> #include <media/stagefright/MmapSource.h> namespace android { @@ -36,7 +34,7 @@ MmapSource::MmapSource(const char *filename) mBase(NULL), mSize(0) { LOGV("MmapSource '%s'", filename); - assert(mFd >= 0); + CHECK(mFd >= 0); off_t size = lseek(mFd, 0, SEEK_END); mSize = (size_t)size; @@ -56,7 +54,7 @@ MmapSource::MmapSource(int fd, int64_t offset, int64_t length) mBase(NULL), mSize(length) { LOGV("MmapSource fd:%d offset:%lld length:%lld", fd, offset, length); - assert(fd >= 0); + CHECK(fd >= 0); mBase = mmap(0, mSize, PROT_READ, MAP_FILE | MAP_SHARED, mFd, offset); @@ -86,7 +84,7 @@ status_t MmapSource::InitCheck() const { ssize_t MmapSource::read_at(off_t offset, void *data, size_t size) { LOGV("read_at offset:%ld data:%p size:%d", offset, data, size); - assert(offset >= 0); + CHECK(offset >= 0); size_t avail = 0; if (offset >= 0 && offset < (off_t)mSize) { diff --git a/media/libstagefright/OMXClient.cpp b/media/libstagefright/OMXClient.cpp index 5423ffa..2a32b4c 100644 --- a/media/libstagefright/OMXClient.cpp +++ b/media/libstagefright/OMXClient.cpp @@ -20,12 +20,10 @@ #include <sys/socket.h> -#undef NDEBUG -#include <assert.h> - #include <binder/IServiceManager.h> #include <media/IMediaPlayerService.h> #include <media/IOMX.h> +#include <media/stagefright/MediaDebug.h> #include <media/stagefright/OMXClient.h> namespace android { @@ -44,10 +42,10 @@ status_t OMXClient::connect() { sp<IBinder> binder = sm->getService(String16("media.player")); sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder); - assert(service.get() != NULL); + CHECK(service.get() != NULL); mOMX = service->createOMX(); - assert(mOMX.get() != NULL); + CHECK(mOMX.get() != NULL); mReflector = new OMXClientReflector(this); @@ -61,7 +59,7 @@ void OMXClient::disconnect() { return; } - assert(mObservers.isEmpty()); + CHECK(mObservers.isEmpty()); mReflector->reset(); mReflector.clear(); @@ -88,7 +86,7 @@ void OMXClient::unregisterObserver(IOMX::node_id node) { Mutex::Autolock autoLock(mLock); ssize_t index = mObservers.indexOfKey(node); - assert(index >= 0); + CHECK(index >= 0); if (index < 0) { return; @@ -155,7 +153,7 @@ void OMXObserver::start() { pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); int err = pthread_create(&mThread, &attr, ThreadWrapper, this); - assert(err == 0); + CHECK_EQ(err, 0); pthread_attr_destroy(&attr); } diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index ec9f6d3..cdaba7c 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -193,6 +193,7 @@ sp<OMXCodec> OMXCodec::Create( } if (!strcmp(componentName, "OMX.TI.AAC.decode")) { quirks |= kNeedsFlushBeforeDisable; + quirks |= kRequiresFlushCompleteEmulation; } if (!strncmp(componentName, "OMX.qcom.video.encoder.", 23)) { quirks |= kRequiresLoadedToIdleAfterAllocation; @@ -493,6 +494,7 @@ void OMXCodec::setVideoOutputFormat( // Enabling this code appears to be the right thing(tm), but,... // the TI decoder then loses the ability to output YUV420 and only outputs // YCbYCr (16bit) +#if 1 if (!strcmp("OMX.TI.Video.Decoder", mComponentName) && !strcasecmp("video/avc", mime)) { OMX_PARAM_COMPONENTROLETYPE role; @@ -508,6 +510,7 @@ void OMXCodec::setVideoOutputFormat( &role, sizeof(role)); CHECK_EQ(err, OK); } +#endif OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused; if (!strcasecmp("video/avc", mime)) { @@ -734,6 +737,10 @@ status_t OMXCodec::allocateBuffersOnPort(OMX_U32 portIndex) { && (mQuirks & kRequiresAllocateBufferOnInputPorts)) { err = mOMX->allocate_buffer_with_backup( mNode, portIndex, mem, &buffer); + } else if (portIndex == kPortIndexOutput + && (mQuirks & kRequiresAllocateBufferOnOutputPorts)) { + err = mOMX->allocate_buffer( + mNode, portIndex, def.nBufferSize, &buffer); } else { err = mOMX->use_buffer(mNode, portIndex, mem, &buffer); } @@ -852,7 +859,8 @@ void OMXCodec::on_message(const omx_message &msg) { CHECK_EQ(err, OK); buffers->removeAt(i); - } else if (flags & OMX_BUFFERFLAG_EOS) { + } else if (mPortStatus[kPortIndexOutput] == ENABLED + && (flags & OMX_BUFFERFLAG_EOS)) { LOGV("No more output data."); mNoMoreOutputData = true; mBufferFilled.signal(); @@ -1163,21 +1171,38 @@ void OMXCodec::onPortSettingsChanged(OMX_U32 portIndex) { setState(RECONFIGURING); if (mQuirks & kNeedsFlushBeforeDisable) { - flushPortAsync(portIndex); + if (!flushPortAsync(portIndex)) { + onCmdComplete(OMX_CommandFlush, portIndex); + } } else { disablePortAsync(portIndex); } } -void OMXCodec::flushPortAsync(OMX_U32 portIndex) { +bool OMXCodec::flushPortAsync(OMX_U32 portIndex) { CHECK(mState == EXECUTING || mState == RECONFIGURING); + LOGV("flushPortAsync(%ld): we own %d out of %d buffers already.", + portIndex, countBuffersWeOwn(mPortBuffers[portIndex]), + mPortBuffers[portIndex].size()); + CHECK_EQ(mPortStatus[portIndex], ENABLED); mPortStatus[portIndex] = SHUTTING_DOWN; + if ((mQuirks & kRequiresFlushCompleteEmulation) + && countBuffersWeOwn(mPortBuffers[portIndex]) + == mPortBuffers[portIndex].size()) { + // No flush is necessary and this component fails to send a + // flush-complete event in this case. + + return false; + } + status_t err = mOMX->send_command(mNode, OMX_CommandFlush, portIndex); CHECK_EQ(err, OK); + + return true; } void OMXCodec::disablePortAsync(OMX_U32 portIndex) { @@ -1323,6 +1348,12 @@ void OMXCodec::drainInputBuffer(BufferInfo *info) { void OMXCodec::fillOutputBuffer(BufferInfo *info) { CHECK_EQ(info->mOwnedByComponent, false); + if (mNoMoreOutputData) { + LOGV("There is no more output data available, not " + "calling fillOutputBuffer"); + return; + } + LOGV("Calling fill_buffer on buffer %p", info->mBuffer); mOMX->fill_buffer(mNode, info->mBuffer); @@ -1648,8 +1679,16 @@ status_t OMXCodec::read( CHECK_EQ(mState, EXECUTING); - flushPortAsync(kPortIndexInput); - flushPortAsync(kPortIndexOutput); + bool emulateInputFlushCompletion = !flushPortAsync(kPortIndexInput); + bool emulateOutputFlushCompletion = !flushPortAsync(kPortIndexOutput); + + if (emulateInputFlushCompletion) { + onCmdComplete(OMX_CommandFlush, kPortIndexInput); + } + + if (emulateOutputFlushCompletion) { + onCmdComplete(OMX_CommandFlush, kPortIndexOutput); + } } while (mState != ERROR && !mNoMoreOutputData && mFilledBuffers.empty()) { diff --git a/media/libstagefright/OMXDecoder.cpp b/media/libstagefright/OMXDecoder.cpp index cf08fa5..a3172ed 100644 --- a/media/libstagefright/OMXDecoder.cpp +++ b/media/libstagefright/OMXDecoder.cpp @@ -18,13 +18,12 @@ #define LOG_TAG "OMXDecoder" #include <utils/Log.h> -#undef NDEBUG -#include <assert.h> #include <ctype.h> #include <OMX_Component.h> #include <media/stagefright/ESDS.h> +#include <media/stagefright/MediaDebug.h> #include <media/stagefright/MetaData.h> #include <media/stagefright/OMXDecoder.h> @@ -87,7 +86,7 @@ static const CodecInfo kEncoderInfo[] = { static const char *GetCodec(const CodecInfo *info, size_t numInfos, const char *mime, int index) { - assert(index >= 0); + CHECK(index >= 0); for(size_t i = 0; i < numInfos; ++i) { if (!strcasecmp(mime, info[i].mime)) { if (index == 0) { @@ -108,7 +107,7 @@ sp<OMXDecoder> OMXDecoder::Create( const sp<MediaSource> &source) { const char *mime; bool success = meta->findCString(kKeyMIMEType, &mime); - assert(success); + CHECK(success); sp<IOMX> omx = client->interface(); @@ -168,7 +167,7 @@ sp<OMXDecoder> OMXDecoder::Create( size_t size; if (meta->findData(kKeyESDS, &type, &data, &size)) { ESDS esds((const char *)data, size); - assert(esds.InitCheck() == OK); + CHECK_EQ(esds.InitCheck(), OK); const void *codec_specific_data; size_t codec_specific_data_size; @@ -193,7 +192,7 @@ sp<OMXDecoder> OMXDecoder::Create( // printf("length = %d, size = %d\n", length, size); - assert(size >= length); + CHECK(size >= length); decoder->addCodecSpecificData(ptr, length); @@ -258,7 +257,7 @@ OMXDecoder::~OMXDecoder() { mClient->unregisterObserver(mNode); status_t err = mOMX->free_node(mNode); - assert(err == OK); + CHECK_EQ(err, OK); mNode = 0; free(mMIME); @@ -269,7 +268,7 @@ OMXDecoder::~OMXDecoder() { } status_t OMXDecoder::start(MetaData *) { - assert(!mStarted); + CHECK(!mStarted); // mDealer->dump("Decoder Dealer"); @@ -292,7 +291,7 @@ status_t OMXDecoder::start(MetaData *) { } status_t OMXDecoder::stop() { - assert(mStarted); + CHECK(mStarted); LOGI("Initiating OMX Node shutdown, busy polling."); initiateShutdown(); @@ -340,7 +339,7 @@ sp<MetaData> OMXDecoder::getFormat() { status_t OMXDecoder::read( MediaBuffer **out, const ReadOptions *options) { - assert(mStarted); + CHECK(mStarted); *out = NULL; @@ -384,7 +383,7 @@ status_t OMXDecoder::read( // never sends the completion event... FIXME status_t err = mOMX->send_command(mNode, OMX_CommandFlush, OMX_ALL); - assert(err == OK); + CHECK_EQ(err, OK); // Once flushing is completed buffers will again be scheduled to be // filled/emptied. @@ -402,7 +401,7 @@ status_t OMXDecoder::read( return OK; } else { - assert(mErrorCondition != OK); + CHECK(mErrorCondition != OK); return mErrorCondition; } } @@ -463,13 +462,13 @@ void OMXDecoder::setAMRFormat() { status_t err = mOMX->get_parameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def)); - assert(err == NO_ERROR); + CHECK_EQ(err, NO_ERROR); def.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF; def.eAMRBandMode = OMX_AUDIO_AMRBandModeNB0; err = mOMX->set_parameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def)); - assert(err == NO_ERROR); + CHECK_EQ(err, NO_ERROR); } void OMXDecoder::setAACFormat() { @@ -481,12 +480,12 @@ void OMXDecoder::setAACFormat() { status_t err = mOMX->get_parameter(mNode, OMX_IndexParamAudioAac, &def, sizeof(def)); - assert(err == NO_ERROR); + CHECK_EQ(err, NO_ERROR); def.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4ADTS; err = mOMX->set_parameter(mNode, OMX_IndexParamAudioAac, &def, sizeof(def)); - assert(err == NO_ERROR); + CHECK_EQ(err, NO_ERROR); } status_t OMXDecoder::setVideoPortFormatType( @@ -512,8 +511,8 @@ status_t OMXDecoder::setVideoPortFormatType( return err; } - // The following assertion is violated by TI's video decoder. - // assert(format.nIndex == index); + // The following CHECKion is violated by TI's video decoder. + // CHECK_EQ(format.nIndex, index); #if 1 LOGI("portIndex: %ld, index: %ld, eCompressionFormat=%d eColorFormat=%d", @@ -570,7 +569,7 @@ void OMXDecoder::setVideoInputFormat( compressionFormat = OMX_VIDEO_CodingH263; } else { LOGE("Not a supported video mime type: %s", mime); - assert(!"Should not be here. Not a supported video mime type."); + CHECK(!"Should not be here. Not a supported video mime type."); } OMX_COLOR_FORMATTYPE colorFormat = @@ -598,9 +597,9 @@ void OMXDecoder::setVideoInputFormat( status_t err = mOMX->get_parameter( mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - assert(err == NO_ERROR); + CHECK_EQ(err, NO_ERROR); - assert(def.eDomain == OMX_PortDomainVideo); + CHECK_EQ(def.eDomain, OMX_PortDomainVideo); video_def->nFrameWidth = width; video_def->nFrameHeight = height; @@ -610,7 +609,7 @@ void OMXDecoder::setVideoInputFormat( err = mOMX->set_parameter( mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - assert(err == NO_ERROR); + CHECK_EQ(err, NO_ERROR); //////////////////////////////////////////////////////////////////////////// @@ -621,12 +620,12 @@ void OMXDecoder::setVideoInputFormat( err = mOMX->get_parameter( mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - assert(err == NO_ERROR); + CHECK_EQ(err, NO_ERROR); def.nBufferSize = (width * height * 2); // (width * height * 3) / 2; LOGI("setting nBufferSize = %ld", def.nBufferSize); - assert(def.eDomain == OMX_PortDomainVideo); + CHECK_EQ(def.eDomain, OMX_PortDomainVideo); video_def->nFrameWidth = width; video_def->nFrameHeight = height; @@ -635,7 +634,7 @@ void OMXDecoder::setVideoInputFormat( err = mOMX->set_parameter( mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - assert(err == NO_ERROR); + CHECK_EQ(err, NO_ERROR); } void OMXDecoder::setVideoOutputFormat( @@ -659,7 +658,7 @@ void OMXDecoder::setVideoOutputFormat( status_t err = mOMX->set_parameter( mNode, OMX_IndexParamStandardComponentRole, &role, sizeof(role)); - assert(err == OK); + CHECK_EQ(err, OK); } #endif @@ -672,7 +671,7 @@ void OMXDecoder::setVideoOutputFormat( compressionFormat = OMX_VIDEO_CodingH263; } else { LOGE("Not a supported video mime type: %s", mime); - assert(!"Should not be here. Not a supported video mime type."); + CHECK(!"Should not be here. Not a supported video mime type."); } setVideoPortFormatType( @@ -690,13 +689,13 @@ void OMXDecoder::setVideoOutputFormat( status_t err = mOMX->get_parameter( mNode, OMX_IndexParamVideoPortFormat, &format, sizeof(format)); - assert(err == OK); + CHECK_EQ(err, OK); - assert(format.eCompressionFormat == OMX_VIDEO_CodingUnused); + CHECK_EQ(format.eCompressionFormat, OMX_VIDEO_CodingUnused); static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00; - assert(format.eColorFormat == OMX_COLOR_FormatYUV420Planar + CHECK(format.eColorFormat == OMX_COLOR_FormatYUV420Planar || format.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar || format.eColorFormat == OMX_COLOR_FormatCbYCrY || format.eColorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar); @@ -704,7 +703,7 @@ void OMXDecoder::setVideoOutputFormat( err = mOMX->set_parameter( mNode, OMX_IndexParamVideoPortFormat, &format, sizeof(format)); - assert(err == OK); + CHECK_EQ(err, OK); } #endif @@ -719,7 +718,7 @@ void OMXDecoder::setVideoOutputFormat( status_t err = mOMX->get_parameter( mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - assert(err == NO_ERROR); + CHECK_EQ(err, NO_ERROR); #if 1 // XXX Need a (much) better heuristic to compute input buffer sizes. @@ -729,7 +728,7 @@ void OMXDecoder::setVideoOutputFormat( } #endif - assert(def.eDomain == OMX_PortDomainVideo); + CHECK_EQ(def.eDomain, OMX_PortDomainVideo); video_def->nFrameWidth = width; video_def->nFrameHeight = height; @@ -738,7 +737,7 @@ void OMXDecoder::setVideoOutputFormat( err = mOMX->set_parameter( mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - assert(err == NO_ERROR); + CHECK_EQ(err, NO_ERROR); //////////////////////////////////////////////////////////////////////////// @@ -749,9 +748,9 @@ void OMXDecoder::setVideoOutputFormat( err = mOMX->get_parameter( mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - assert(err == NO_ERROR); + CHECK_EQ(err, NO_ERROR); - assert(def.eDomain == OMX_PortDomainVideo); + CHECK_EQ(def.eDomain, OMX_PortDomainVideo); #if 0 def.nBufferSize = @@ -763,7 +762,7 @@ void OMXDecoder::setVideoOutputFormat( err = mOMX->set_parameter( mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - assert(err == NO_ERROR); + CHECK_EQ(err, NO_ERROR); } void OMXDecoder::setup() { @@ -771,7 +770,7 @@ void OMXDecoder::setup() { const char *mime; bool success = meta->findCString(kKeyMIMEType, &mime); - assert(success); + CHECK(success); if (!strcasecmp(mime, "audio/3gpp")) { setAMRFormat(); @@ -781,7 +780,7 @@ void OMXDecoder::setup() { int32_t width, height; bool success = meta->findInt32(kKeyWidth, &width); success = success && meta->findInt32(kKeyHeight, &height); - assert(success); + CHECK(success); if (mIsEncoder) { setVideoInputFormat(mime, width, height); @@ -804,14 +803,14 @@ void OMXDecoder::setup() { status_t err = mOMX->get_parameter( mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - assert(err == NO_ERROR); + CHECK_EQ(err, NO_ERROR); switch (def.eDomain) { case OMX_PortDomainAudio: { OMX_AUDIO_PORTDEFINITIONTYPE *audio_def = &def.format.audio; - assert(audio_def->eEncoding == OMX_AUDIO_CodingPCM); + CHECK_EQ(audio_def->eEncoding, OMX_AUDIO_CodingPCM); OMX_AUDIO_PARAM_PCMMODETYPE params; params.nSize = sizeof(params); @@ -821,11 +820,11 @@ void OMXDecoder::setup() { err = mOMX->get_parameter( mNode, OMX_IndexParamAudioPcm, ¶ms, sizeof(params)); - assert(err == OK); + CHECK_EQ(err, OK); - assert(params.eNumData == OMX_NumericalDataSigned); - assert(params.nBitPerSample == 16); - assert(params.ePCMMode == OMX_AUDIO_PCMModeLinear); + CHECK_EQ(params.eNumData, OMX_NumericalDataSigned); + CHECK_EQ(params.nBitPerSample, 16); + CHECK_EQ(params.ePCMMode, OMX_AUDIO_PCMModeLinear); int32_t numChannels, sampleRate; meta->findInt32(kKeyChannelCount, &numChannels); @@ -850,7 +849,7 @@ void OMXDecoder::setup() { } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingAVC) { mOutputFormat->setCString(kKeyMIMEType, "video/avc"); } else { - assert(!"Unknown compression format."); + CHECK(!"Unknown compression format."); } if (!strcmp(mComponentName, "OMX.PV.avcdec")) { @@ -870,7 +869,7 @@ void OMXDecoder::setup() { default: { - assert(!"should not be here, neither audio nor video."); + CHECK(!"should not be here, neither audio nor video."); break; } } @@ -880,7 +879,7 @@ void OMXDecoder::onStart() { if (!(mQuirks & kRequiresLoadedToIdleAfterAllocation)) { status_t err = mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle); - assert(err == NO_ERROR); + CHECK_EQ(err, NO_ERROR); } allocateBuffers(kPortIndexInput); @@ -891,12 +890,12 @@ void OMXDecoder::onStart() { // h264 vdec disagrees. status_t err = mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle); - assert(err == NO_ERROR); + CHECK_EQ(err, NO_ERROR); } } void OMXDecoder::allocateBuffers(OMX_U32 port_index) { - assert(mBuffers[port_index].empty()); + CHECK(mBuffers[port_index].empty()); OMX_U32 num_buffers; OMX_U32 buffer_size; @@ -911,7 +910,7 @@ void OMXDecoder::allocateBuffers(OMX_U32 port_index) { status_t err = mOMX->get_parameter( mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - assert(err == NO_ERROR); + CHECK_EQ(err, NO_ERROR); num_buffers = def.nBufferCountActual; buffer_size = def.nBufferSize; @@ -925,7 +924,7 @@ void OMXDecoder::allocateBuffers(OMX_U32 port_index) { LOGE("[%s] allocating IMemory of size %ld FAILED.", mComponentName, buffer_size); } - assert(mem.get() != NULL); + CHECK(mem.get() != NULL); IOMX::buffer_id buffer; status_t err; @@ -960,7 +959,7 @@ void OMXDecoder::allocateBuffers(OMX_U32 port_index) { mComponentName, err); } } - assert(err == OK); + CHECK_EQ(err, OK); LOGV("allocated %s buffer %p.", port_index == kPortIndexInput ? "INPUT" : "OUTPUT", @@ -1019,7 +1018,7 @@ void OMXDecoder::onEventCmdComplete(OMX_COMMANDTYPE type, OMX_U32 data) { case OMX_CommandPortDisable: { OMX_U32 port_index = data; - assert(getPortStatus(port_index) == kPortStatusDisabled); + CHECK_EQ(getPortStatus(port_index), kPortStatusDisabled); status_t err = mOMX->send_command(mNode, OMX_CommandPortEnable, port_index); @@ -1031,10 +1030,10 @@ void OMXDecoder::onEventCmdComplete(OMX_COMMANDTYPE type, OMX_U32 data) { case OMX_CommandPortEnable: { OMX_U32 port_index = data; - assert(getPortStatus(port_index) ==kPortStatusDisabled); + CHECK(getPortStatus(port_index) ==kPortStatusDisabled); setPortStatus(port_index, kPortStatusActive); - assert(port_index == kPortIndexOutput); + CHECK_EQ(port_index, kPortIndexOutput); BufferList *obuffers = &mBuffers.editItemAt(kPortIndexOutput); while (!obuffers->empty()) { @@ -1053,7 +1052,7 @@ void OMXDecoder::onEventCmdComplete(OMX_COMMANDTYPE type, OMX_U32 data) { PortStatus status = getPortStatus(port_index); - assert(status == kPortStatusFlushing + CHECK(status == kPortStatusFlushing || status == kPortStatusFlushingToDisabled || status == kPortStatusFlushingToShutdown); @@ -1085,7 +1084,7 @@ void OMXDecoder::onEventCmdComplete(OMX_COMMANDTYPE type, OMX_U32 data) { setPortStatus(port_index, kPortStatusDisabled); status_t err = mOMX->send_command( mNode, OMX_CommandPortDisable, port_index); - assert(err == OK); + CHECK_EQ(err, OK); freePortBuffers(port_index); break; @@ -1093,14 +1092,14 @@ void OMXDecoder::onEventCmdComplete(OMX_COMMANDTYPE type, OMX_U32 data) { default: { - assert(status == kPortStatusFlushingToShutdown); + CHECK_EQ(status, kPortStatusFlushingToShutdown); setPortStatus(port_index, kPortStatusShutdown); if (getPortStatus(kPortIndexInput) == kPortStatusShutdown && getPortStatus(kPortIndexOutput) == kPortStatusShutdown) { status_t err = mOMX->send_command( mNode, OMX_CommandStateSet, OMX_StateIdle); - assert(err == OK); + CHECK_EQ(err, OK); } break; } @@ -1114,7 +1113,7 @@ void OMXDecoder::onEventCmdComplete(OMX_COMMANDTYPE type, OMX_U32 data) { } void OMXDecoder::onEventPortSettingsChanged(OMX_U32 port_index) { - assert(getPortStatus(port_index) == kPortStatusActive); + CHECK_EQ(getPortStatus(port_index), kPortStatusActive); status_t err; @@ -1131,18 +1130,18 @@ void OMXDecoder::onEventPortSettingsChanged(OMX_U32 port_index) { err = mOMX->send_command(mNode, OMX_CommandPortDisable, port_index); } - assert(err == NO_ERROR); + CHECK_EQ(err, NO_ERROR); } void OMXDecoder::onStateChanged(OMX_STATETYPE to) { if (mState == OMX_StateLoaded) { - assert(to == OMX_StateIdle); + CHECK_EQ(to, OMX_StateIdle); mState = to; status_t err = mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateExecuting); - assert(err == NO_ERROR); + CHECK_EQ(err, NO_ERROR); } else if (mState == OMX_StateIdle) { if (to == OMX_StateExecuting) { mState = to; @@ -1163,7 +1162,7 @@ void OMXDecoder::onStateChanged(OMX_STATETYPE to) { postInitialFillBuffer(buffer); } } else { - assert(to == OMX_StateLoaded); + CHECK_EQ(to, OMX_StateLoaded); mState = to; @@ -1171,14 +1170,14 @@ void OMXDecoder::onStateChanged(OMX_STATETYPE to) { setPortStatus(kPortIndexOutput, kPortStatusActive); } } else if (mState == OMX_StateExecuting) { - assert(to == OMX_StateIdle); + CHECK_EQ(to, OMX_StateIdle); mState = to; LOGV("Executing->Idle complete, initiating Idle->Loaded"); status_t err = mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateLoaded); - assert(err == NO_ERROR); + CHECK_EQ(err, NO_ERROR); freePortBuffers(kPortIndexInput); freePortBuffers(kPortIndexOutput); @@ -1196,7 +1195,7 @@ void OMXDecoder::initiateShutdown() { return; } - assert(mState == OMX_StateExecuting); + CHECK_EQ(mState, OMX_StateExecuting); mShutdownInitiated = true; @@ -1204,7 +1203,7 @@ void OMXDecoder::initiateShutdown() { if (mQuirks & kDoesntFlushOnExecutingToIdle) { if (mQuirks & kDoesntProperlyFlushAllPortsAtOnce) { err = mOMX->send_command(mNode, OMX_CommandFlush, kPortIndexInput); - assert(err == OK); + CHECK_EQ(err, OK); err = mOMX->send_command(mNode, OMX_CommandFlush, kPortIndexOutput); } else { @@ -1220,7 +1219,7 @@ void OMXDecoder::initiateShutdown() { setPortStatus(kPortIndexInput, kPortStatusShutdown); setPortStatus(kPortIndexOutput, kPortStatusShutdown); } - assert(err == OK); + CHECK_EQ(err, OK); } void OMXDecoder::setPortStatus(OMX_U32 port_index, PortStatus status) { @@ -1266,7 +1265,7 @@ void OMXDecoder::onEmptyBufferDone(IOMX::buffer_id buffer) { err = NO_ERROR; break; } - assert(err == NO_ERROR); + CHECK_EQ(err, NO_ERROR); } void OMXDecoder::onFillBufferDone(const omx_message &msg) { @@ -1310,7 +1309,7 @@ void OMXDecoder::onFillBufferDone(const omx_message &msg) { break; } } - assert(err == NO_ERROR); + CHECK_EQ(err, NO_ERROR); } void OMXDecoder::onRealEmptyBufferDone(IOMX::buffer_id buffer) { @@ -1322,7 +1321,7 @@ void OMXDecoder::onRealEmptyBufferDone(IOMX::buffer_id buffer) { } const sp<IMemory> mem = mBufferMap.valueFor(buffer); - assert(mem.get() != NULL); + CHECK(mem.get() != NULL); static const uint8_t kNALStartCode[4] = { 0x00, 0x00, 0x00, 0x01 }; @@ -1332,14 +1331,14 @@ void OMXDecoder::onRealEmptyBufferDone(IOMX::buffer_id buffer) { size_t range_length = 0; if (mIsAVC && !(mQuirks & kWantsNALFragments)) { - assert((*mCodecSpecificDataIterator).size + 4 <= mem->size()); + CHECK((*mCodecSpecificDataIterator).size + 4 <= mem->size()); memcpy(mem->pointer(), kNALStartCode, 4); memcpy((uint8_t *)mem->pointer() + 4, (*it).data, (*it).size); range_length = (*it).size + 4; } else { - assert((*mCodecSpecificDataIterator).size <= mem->size()); + CHECK((*mCodecSpecificDataIterator).size <= mem->size()); memcpy((uint8_t *)mem->pointer(), (*it).data, (*it).size); range_length = (*it).size; @@ -1371,7 +1370,7 @@ void OMXDecoder::onRealEmptyBufferDone(IOMX::buffer_id buffer) { } else { err = mSource->read(&input_buffer); } - assert((err == OK && input_buffer != NULL) + CHECK((err == OK && input_buffer != NULL) || (err != OK && input_buffer == NULL)); if (err == ERROR_END_OF_STREAM) { @@ -1415,7 +1414,7 @@ void OMXDecoder::onRealEmptyBufferDone(IOMX::buffer_id buffer) { src_length, mem->size()); } - assert(src_length <= mem->size()); + CHECK(src_length <= mem->size()); memcpy(mem->pointer(), src_data, src_length); OMX_U32 flags = 0; @@ -1520,7 +1519,7 @@ void OMXDecoder::freeInputBuffer(IOMX::buffer_id buffer) { LOGV("freeInputBuffer %p", buffer); status_t err = mOMX->free_buffer(mNode, kPortIndexInput, buffer); - assert(err == NO_ERROR); + CHECK_EQ(err, NO_ERROR); mBufferMap.removeItem(buffer); LOGV("freeInputBuffer %p done", buffer); @@ -1530,11 +1529,11 @@ void OMXDecoder::freeOutputBuffer(IOMX::buffer_id buffer) { LOGV("freeOutputBuffer %p", buffer); status_t err = mOMX->free_buffer(mNode, kPortIndexOutput, buffer); - assert(err == NO_ERROR); + CHECK_EQ(err, NO_ERROR); mBufferMap.removeItem(buffer); ssize_t index = mMediaBufferMap.indexOfKey(buffer); - assert(index >= 0); + CHECK(index >= 0); MediaBuffer *mbuffer = mMediaBufferMap.editValueAt(index); mMediaBufferMap.removeItemsAt(index); mbuffer->setObserver(NULL); @@ -1553,7 +1552,7 @@ void OMXDecoder::dumpPortDefinition(OMX_U32 port_index) { status_t err = mOMX->get_parameter( mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - assert(err == NO_ERROR); + CHECK_EQ(err, NO_ERROR); LOGI("DumpPortDefinition on port %ld", port_index); LOGI("nBufferCountActual = %ld, nBufferCountMin = %ld, nBufferSize = %ld", @@ -1565,7 +1564,7 @@ void OMXDecoder::dumpPortDefinition(OMX_U32 port_index) { if (port_index == kPortIndexOutput) { OMX_AUDIO_PORTDEFINITIONTYPE *audio_def = &def.format.audio; - assert(audio_def->eEncoding == OMX_AUDIO_CodingPCM); + CHECK_EQ(audio_def->eEncoding, OMX_AUDIO_CodingPCM); OMX_AUDIO_PARAM_PCMMODETYPE params; params.nSize = sizeof(params); @@ -1575,12 +1574,12 @@ void OMXDecoder::dumpPortDefinition(OMX_U32 port_index) { err = mOMX->get_parameter( mNode, OMX_IndexParamAudioPcm, ¶ms, sizeof(params)); - assert(err == OK); + CHECK_EQ(err, OK); - assert(params.nChannels == 1 || params.bInterleaved); - assert(params.eNumData == OMX_NumericalDataSigned); - assert(params.nBitPerSample == 16); - assert(params.ePCMMode == OMX_AUDIO_PCMModeLinear); + CHECK(params.nChannels == 1 || params.bInterleaved); + CHECK_EQ(params.eNumData, OMX_NumericalDataSigned); + CHECK_EQ(params.nBitPerSample, 16); + CHECK_EQ(params.ePCMMode, OMX_AUDIO_PCMModeLinear); LOGI("nChannels = %ld, nSamplingRate = %ld", params.nChannels, params.nSamplingRate); diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp index 75bfde3..5e32559 100644 --- a/media/libstagefright/SampleTable.cpp +++ b/media/libstagefright/SampleTable.cpp @@ -18,9 +18,9 @@ #include <utils/Log.h> #include <arpa/inet.h> -#include <assert.h> #include <media/stagefright/DataSource.h> +#include <media/stagefright/MediaDebug.h> #include <media/stagefright/SampleTable.h> #include <media/stagefright/Utils.h> @@ -59,7 +59,7 @@ status_t SampleTable::setChunkOffsetParams( return ERROR_MALFORMED; } - assert(type == kChunkOffsetType32 || type == kChunkOffsetType64); + CHECK(type == kChunkOffsetType32 || type == kChunkOffsetType64); mChunkOffsetOffset = data_offset; mChunkOffsetType = type; @@ -132,7 +132,7 @@ status_t SampleTable::setSampleSizeParams( return ERROR_MALFORMED; } - assert(type == kSampleSizeType32 || type == kSampleSizeTypeCompact); + CHECK(type == kSampleSizeType32 || type == kSampleSizeTypeCompact); mSampleSizeOffset = data_offset; @@ -272,7 +272,7 @@ status_t SampleTable::getChunkOffset(uint32_t chunk_index, off_t *offset) { *offset = ntohl(offset32); } else { - assert(mChunkOffsetOffset == kChunkOffsetType64); + CHECK_EQ(mChunkOffsetOffset, kChunkOffsetType64); uint64_t offset64; if (mDataSource->read_at( @@ -399,7 +399,7 @@ status_t SampleTable::getSampleSize( default: { - assert(mSampleSizeFieldSize == 4); + CHECK_EQ(mSampleSizeFieldSize, 4); uint8_t x; if (mDataSource->read_at( @@ -569,26 +569,6 @@ status_t SampleTable::findClosestSyncSample( } } -#if 1 - // Make sure we return a sample at or _after_ the requested one. - // Seeking to a particular time in a media source containing audio and - // video will most likely be able to sync fairly close to the requested - // time in the audio track but may only be able to seek a fair distance - // from the requested time in the video track. - // If we seek the video track to a time earlier than the audio track, - // we'll cause the video track to be late for quite a while, the decoder - // trying to catch up. - // If we seek the video track to a time later than the audio track, - // audio will start playing fine while no video will be output for a - // while, the video decoder will not stress the system. - if (mDataSource->read_at( - mSyncSampleOffset + 8 + (left - 1) * 4, &x, 4) != 4) { - return ERROR_IO; - } - x = ntohl(x); - assert((x - 1) >= start_sample_index); -#endif - *sample_index = x - 1; return OK; diff --git a/media/libstagefright/ShoutcastSource.cpp b/media/libstagefright/ShoutcastSource.cpp index 17b626e..4375f38 100644 --- a/media/libstagefright/ShoutcastSource.cpp +++ b/media/libstagefright/ShoutcastSource.cpp @@ -19,6 +19,7 @@ #include <media/stagefright/HTTPStream.h> #include <media/stagefright/MediaBuffer.h> #include <media/stagefright/MediaBufferGroup.h> +#include <media/stagefright/MediaDebug.h> #include <media/stagefright/MetaData.h> #include <media/stagefright/ShoutcastSource.h> #include <media/stagefright/string.h> @@ -36,8 +37,8 @@ ShoutcastSource::ShoutcastSource(HTTPStream *http) char *end; const char *start = metaint.c_str(); mMetaDataOffset = strtol(start, &end, 10); - assert(end > start && *end == '\0'); - assert(mMetaDataOffset > 0); + CHECK(end > start && *end == '\0'); + CHECK(mMetaDataOffset > 0); mBytesUntilMetaData = mMetaDataOffset; } @@ -53,7 +54,7 @@ ShoutcastSource::~ShoutcastSource() { } status_t ShoutcastSource::start(MetaData *) { - assert(!mStarted); + CHECK(!mStarted); mGroup = new MediaBufferGroup; mGroup->add_buffer(new MediaBuffer(4096)); // XXX @@ -64,7 +65,7 @@ status_t ShoutcastSource::start(MetaData *) { } status_t ShoutcastSource::stop() { - assert(mStarted); + CHECK(mStarted); delete mGroup; mGroup = NULL; @@ -85,7 +86,7 @@ sp<MetaData> ShoutcastSource::getFormat() { status_t ShoutcastSource::read( MediaBuffer **out, const ReadOptions *options) { - assert(mStarted); + CHECK(mStarted); *out = NULL; @@ -120,7 +121,7 @@ status_t ShoutcastSource::read( if (mBytesUntilMetaData == 0) { unsigned char num_16_byte_blocks = 0; n = mHttp->receive((char *)&num_16_byte_blocks, 1); - assert(n == 1); + CHECK_EQ(n, 1); char meta[255 * 16]; size_t meta_size = num_16_byte_blocks * 16; diff --git a/media/libstagefright/TimedEventQueue.cpp b/media/libstagefright/TimedEventQueue.cpp index 2f8a19f..3d85f75 100644 --- a/media/libstagefright/TimedEventQueue.cpp +++ b/media/libstagefright/TimedEventQueue.cpp @@ -24,9 +24,7 @@ #include <sys/time.h> -#undef NDEBUG -#include <assert.h> - +#include <media/stagefright/MediaDebug.h> #include <media/stagefright/TimedEventQueue.h> namespace android { @@ -89,7 +87,7 @@ void TimedEventQueue::postEventToBack(const sp<Event> &event) { void TimedEventQueue::postEventWithDelay( const sp<Event> &event, int64_t delay_us) { - assert(delay_us >= 0); + CHECK(delay_us >= 0); postTimedEvent(event, getRealTimeUs() + delay_us); } diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk index 46affe7..77e42be 100644 --- a/media/libstagefright/omx/Android.mk +++ b/media/libstagefright/omx/Android.mk @@ -6,6 +6,8 @@ include external/opencore/Config.mk LOCAL_C_INCLUDES := $(PV_INCLUDES) LOCAL_CFLAGS := $(PV_CFLAGS_MINUS_VISIBILITY) +LOCAL_C_INCLUDES += $(TOP)/hardware/ti/omap3/liboverlay + LOCAL_SRC_FILES:= \ OMX.cpp \ QComHardwareRenderer.cpp \ diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp index 39fa27e..1e59b52 100644 --- a/media/libstagefright/omx/OMX.cpp +++ b/media/libstagefright/omx/OMX.cpp @@ -20,15 +20,13 @@ #include <sys/socket.h> -#undef NDEBUG -#include <assert.h> - #include "OMX.h" #include "OMXRenderer.h" #include "pv_omxcore.h" #include <binder/IMemory.h> +#include <media/stagefright/MediaDebug.h> #include <media/stagefright/QComHardwareRenderer.h> #include <media/stagefright/SoftwareRenderer.h> #include <media/stagefright/TIHardwareRenderer.h> @@ -50,7 +48,7 @@ public: } void setHandle(OMX_HANDLETYPE handle) { - assert(mHandle == NULL); + CHECK_EQ(mHandle, NULL); mHandle = handle; } @@ -541,7 +539,7 @@ void OMX::fill_buffer(node_id node, buffer_id buffer) { OMX_ERRORTYPE err = OMX_FillThisBuffer(node_meta->handle(), header); - assert(err == OMX_ErrorNone); + CHECK_EQ(err, OMX_ErrorNone); } void OMX::empty_buffer( @@ -563,7 +561,7 @@ void OMX::empty_buffer( OMX_ERRORTYPE err = OMX_EmptyThisBuffer(node_meta->handle(), header); - assert(err == OMX_ErrorNone); + CHECK_EQ(err, OMX_ErrorNone); } status_t OMX::get_extension_index( diff --git a/media/libstagefright/omx/QComHardwareRenderer.cpp b/media/libstagefright/omx/QComHardwareRenderer.cpp index 5a23792..e9930be 100644 --- a/media/libstagefright/omx/QComHardwareRenderer.cpp +++ b/media/libstagefright/omx/QComHardwareRenderer.cpp @@ -14,11 +14,9 @@ * limitations under the License. */ -#undef NDEBUG -#include <assert.h> - #include <binder/MemoryHeapBase.h> #include <binder/MemoryHeapPmem.h> +#include <media/stagefright/MediaDebug.h> #include <media/stagefright/QComHardwareRenderer.h> #include <ui/ISurface.h> @@ -68,9 +66,9 @@ QComHardwareRenderer::QComHardwareRenderer( mDecodedWidth(decodedWidth), mDecodedHeight(decodedHeight), mFrameSize((mDecodedWidth * mDecodedHeight * 3) / 2) { - assert(mISurface.get() != NULL); - assert(mDecodedWidth > 0); - assert(mDecodedHeight > 0); + CHECK(mISurface.get() != NULL); + CHECK(mDecodedWidth > 0); + CHECK(mDecodedHeight > 0); } QComHardwareRenderer::~QComHardwareRenderer() { @@ -133,7 +131,7 @@ void QComHardwareRenderer::publishBuffers(uint32_t pmem_fd) { mMemoryHeap); status_t err = mISurface->registerBuffers(bufferHeap); - assert(err == OK); + CHECK_EQ(err, OK); } } // namespace android diff --git a/media/libstagefright/omx/SoftwareRenderer.cpp b/media/libstagefright/omx/SoftwareRenderer.cpp index 5483238..da97d55 100644 --- a/media/libstagefright/omx/SoftwareRenderer.cpp +++ b/media/libstagefright/omx/SoftwareRenderer.cpp @@ -17,10 +17,8 @@ #define LOG_TAG "SoftwareRenderer" #include <utils/Log.h> -#undef NDEBUG -#include <assert.h> - #include <binder/MemoryHeapBase.h> +#include <media/stagefright/MediaDebug.h> #include <media/stagefright/SoftwareRenderer.h> #include <ui/ISurface.h> @@ -40,10 +38,10 @@ SoftwareRenderer::SoftwareRenderer( mFrameSize(mDecodedWidth * mDecodedHeight * 2), // RGB565 mMemoryHeap(new MemoryHeapBase(2 * mFrameSize)), mIndex(0) { - assert(mISurface.get() != NULL); - assert(mDecodedWidth > 0); - assert(mDecodedHeight > 0); - assert(mMemoryHeap->heapID() >= 0); + CHECK(mISurface.get() != NULL); + CHECK(mDecodedWidth > 0); + CHECK(mDecodedHeight > 0); + CHECK(mMemoryHeap->heapID() >= 0); ISurface::BufferHeap bufferHeap( mDisplayWidth, mDisplayHeight, @@ -52,7 +50,7 @@ SoftwareRenderer::SoftwareRenderer( mMemoryHeap); status_t err = mISurface->registerBuffers(bufferHeap); - assert(err == OK); + CHECK_EQ(err, OK); } SoftwareRenderer::~SoftwareRenderer() { @@ -65,7 +63,7 @@ void SoftwareRenderer::render( LOGE("size is %d, expected %d", size, (mDecodedHeight * mDecodedWidth * 3) / 2); } - assert(size >= (mDecodedWidth * mDecodedHeight * 3) / 2); + CHECK(size >= (mDecodedWidth * mDecodedHeight * 3) / 2); static const signed kClipMin = -278; static const signed kClipMax = 535; diff --git a/media/libstagefright/omx/TIHardwareRenderer.cpp b/media/libstagefright/omx/TIHardwareRenderer.cpp index ba42ef4..ebade4a 100644 --- a/media/libstagefright/omx/TIHardwareRenderer.cpp +++ b/media/libstagefright/omx/TIHardwareRenderer.cpp @@ -17,13 +17,15 @@ #define LOG_TAG "TIHardwareRenderer" #include <utils/Log.h> -#undef NDEBUG -#include <assert.h> - #include <media/stagefright/TIHardwareRenderer.h> +#include <media/stagefright/MediaDebug.h> #include <ui/ISurface.h> #include <ui/Overlay.h> +#include "v4l2_utils.h" + +#define CACHEABLE_BUFFERS 0x1 + namespace android { //////////////////////////////////////////////////////////////////////////////// @@ -37,10 +39,12 @@ TIHardwareRenderer::TIHardwareRenderer( mDisplayHeight(displayHeight), mDecodedWidth(decodedWidth), mDecodedHeight(decodedHeight), - mFrameSize((mDecodedWidth * mDecodedHeight * 3) / 2) { - assert(mISurface.get() != NULL); - assert(mDecodedWidth > 0); - assert(mDecodedHeight > 0); + mFrameSize(mDecodedWidth * mDecodedHeight * 2), + mIsFirstFrame(true), + mIndex(0) { + CHECK(mISurface.get() != NULL); + CHECK(mDecodedWidth > 0); + CHECK(mDecodedHeight > 0); sp<OverlayRef> ref = mISurface->createOverlay( mDisplayWidth, mDisplayHeight, OVERLAY_FORMAT_CbYCrY_422_I); @@ -51,11 +55,14 @@ TIHardwareRenderer::TIHardwareRenderer( } mOverlay = new Overlay(ref); + mOverlay->setParameter(CACHEABLE_BUFFERS, 0); - for (size_t i = 0; i < mOverlay->getBufferCount(); ++i) { - mOverlayAddresses.push(mOverlay->getBufferAddress((void *)i)); + for (size_t i = 0; i < (size_t)mOverlay->getBufferCount(); ++i) { + mapping_data_t *data = + (mapping_data_t *)mOverlay->getBufferAddress((void *)i); + + mOverlayAddresses.push(data->ptr); } - mIndex = mOverlayAddresses.size() - 1; } TIHardwareRenderer::~TIHardwareRenderer() { @@ -70,27 +77,51 @@ TIHardwareRenderer::~TIHardwareRenderer() { void TIHardwareRenderer::render( const void *data, size_t size, void *platformPrivate) { - // assert(size == mFrameSize); + // CHECK_EQ(size, mFrameSize); if (mOverlay.get() == NULL) { return; } #if 0 - overlay_buffer_t buffer; - if (mOverlay->dequeueBuffer(&buffer) == OK) { - void *addr = mOverlay->getBufferAddress(buffer); + size_t i = 0; + for (; i < mOverlayAddresses.size(); ++i) { + if (mOverlayAddresses[i] == data) { + break; + } + + if (mIsFirstFrame) { + LOGI("overlay buffer #%d: %p", i, mOverlayAddresses[i]); + } + } - memcpy(addr, data, size); + if (i == mOverlayAddresses.size()) { + LOGE("No suitable overlay buffer found."); + return; + } + + mOverlay->queueBuffer((void *)i); - mOverlay->queueBuffer(buffer); + overlay_buffer_t overlay_buffer; + if (!mIsFirstFrame) { + CHECK_EQ(mOverlay->dequeueBuffer(&overlay_buffer), OK); + } else { + mIsFirstFrame = false; } #else memcpy(mOverlayAddresses[mIndex], data, size); + mOverlay->queueBuffer((void *)mIndex); - if (mIndex-- == 0) { - mIndex = mOverlayAddresses.size() - 1; + if (++mIndex == mOverlayAddresses.size()) { + mIndex = 0; + } + + overlay_buffer_t overlay_buffer; + if (!mIsFirstFrame) { + CHECK_EQ(mOverlay->dequeueBuffer(&overlay_buffer), OK); + } else { + mIsFirstFrame = false; } #endif } diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java index dcb8c43..ea42f53 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java @@ -435,13 +435,6 @@ public class MediaPlayerApiTest extends ActivityInstrumentationTestCase<MediaFra @LargeTest public void testLocalMp3PrepareAsyncCallback() throws Exception { boolean onPrepareSuccess = - CodecTest.prepareAsyncCallback(MediaNames.MP3CBR, false); - assertTrue("LocalMp3prepareAsyncCallback", onPrepareSuccess); - } - - @LargeTest - public void testLocalH263AMRPrepareAsyncCallback() throws Exception { - boolean onPrepareSuccess = CodecTest.prepareAsyncCallback(MediaNames.VIDEO_H263_AMR, false); assertTrue("LocalMp3prepareAsyncCallback", onPrepareSuccess); } diff --git a/opengl/libagl/light.cpp b/opengl/libagl/light.cpp index 8ae32cc0f..f211bca 100644 --- a/opengl/libagl/light.cpp +++ b/opengl/libagl/light.cpp @@ -216,6 +216,8 @@ static inline void light_picker(ogles_context_t* c) static inline void validate_light_mvi(ogles_context_t* c) { uint32_t en = c->lighting.enabledLights; + // Vector from object to viewer, in eye coordinates + const vec4_t eyeViewer = { 0, 0, 0x1000, 0 }; while (en) { const int i = 31 - gglClz(en); en &= ~(1<<i); @@ -223,6 +225,9 @@ static inline void validate_light_mvi(ogles_context_t* c) c->transforms.mvui.point4(&c->transforms.mvui, &l.objPosition, &l.position); vnorm3(l.normalizedObjPosition.v, l.objPosition.v); + c->transforms.mvui.point4(&c->transforms.mvui, + &l.objViewer, &eyeViewer); + vnorm3(l.objViewer.v, l.objViewer.v); } } @@ -379,9 +384,9 @@ void lightVertex(ogles_context_t* c, vertex_t* v) // specular if (ggl_unlikely(s && l.implicitSpecular.v[3])) { vec4_t h; - h.x = d.x; - h.y = d.y; - h.z = d.z + 0x10000; + h.x = d.x + l.objViewer.x; + h.y = d.y + l.objViewer.y; + h.z = d.z + l.objViewer.z; vnorm3(h.v, h.v); s = dot3(n.v, h.v); s = (s<0) ? (twoSide?(-s):0) : s; diff --git a/opengl/libagl/matrix.cpp b/opengl/libagl/matrix.cpp index 0b68dc0..21ef50e 100644 --- a/opengl/libagl/matrix.cpp +++ b/opengl/libagl/matrix.cpp @@ -696,6 +696,8 @@ void ogles_viewport(ogles_context_t* c, f[2] = 0; f[6] = 0; f[10] = A; f[14] = B; f[3] = 0; f[7] = 0; f[11] = 0; f[15] = 1; c->transforms.dirty |= transform_state_t::VIEWPORT; + if (c->transforms.mvp4.flags & transform_t::FLAGS_2D_PROJECTION) + c->transforms.dirty |= transform_state_t::MVP; } // ---------------------------------------------------------------------------- diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk index e1fd48b..9578452 100644 --- a/opengl/libs/Android.mk +++ b/opengl/libs/Android.mk @@ -28,6 +28,10 @@ LOCAL_CFLAGS += -DLOG_TAG=\"libEGL\" LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES LOCAL_CFLAGS += -fvisibility=hidden +ifeq ($(TARGET_BOARD_PLATFORM),msm7k) +LOCAL_CFLAGS += -DADRENO130=1 +endif + include $(BUILD_SHARED_LIBRARY) installed_libEGL := $(LOCAL_INSTALLED_MODULE) diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp index 03e764c..d1ddcd3 100644 --- a/opengl/libs/EGL/egl.cpp +++ b/opengl/libs/EGL/egl.cpp @@ -36,6 +36,8 @@ #include <cutils/properties.h> #include <cutils/memory.h> +#include <utils/SortedVector.h> + #include "hooks.h" #include "egl_impl.h" #include "Loader.h" @@ -63,40 +65,122 @@ static char const * const gExtensionString = // ---------------------------------------------------------------------------- -template <int MAGIC> -struct egl_object_t -{ - egl_object_t() : magic(MAGIC) { } - ~egl_object_t() { magic = 0; } - bool isValid() const { return magic == MAGIC; } +class egl_object_t { + static SortedVector<egl_object_t*> sObjects; + static Mutex sLock; + + volatile int32_t terminated; + mutable volatile int32_t count; + +public: + egl_object_t() : terminated(0), count(1) { + Mutex::Autolock _l(sLock); + sObjects.add(this); + } + + inline bool isAlive() const { return !terminated; } + private: - uint32_t magic; + bool get() { + Mutex::Autolock _l(sLock); + if (egl_object_t::sObjects.indexOf(this) >= 0) { + android_atomic_inc(&count); + return true; + } + return false; + } + + bool put() { + Mutex::Autolock _l(sLock); + if (android_atomic_dec(&count) == 1) { + sObjects.remove(this); + return true; + } + return false; + } + +public: + template <typename N, typename T> + struct LocalRef { + N* ref; + LocalRef(T o) : ref(0) { + N* native = reinterpret_cast<N*>(o); + if (o && native->get()) { + ref = native; + } + } + ~LocalRef() { + if (ref && ref->put()) { + delete ref; + } + } + inline N* get() { + return ref; + } + void acquire() const { + if (ref) { + android_atomic_inc(&ref->count); + } + } + void release() const { + if (ref) { + int32_t c = android_atomic_dec(&ref->count); + // ref->count cannot be 1 prior atomic_dec because we have + // a reference, and if we have one, it means there was + // already one before us. + LOGE_IF(c==1, "refcount is now 0 in release()"); + } + } + void terminate() { + if (ref) { + ref->terminated = 1; + release(); + } + } + }; }; -struct egl_display_t : public egl_object_t<'_dpy'> -{ - EGLDisplay dpys[IMPL_NUM_DRIVERS_IMPLEMENTATIONS]; - EGLConfig* configs[IMPL_NUM_DRIVERS_IMPLEMENTATIONS]; - EGLint numConfigs[IMPL_NUM_DRIVERS_IMPLEMENTATIONS]; - EGLint numTotalConfigs; - char const* extensionsString; - volatile int32_t refs; +SortedVector<egl_object_t*> egl_object_t::sObjects; +Mutex egl_object_t::sLock; + +struct egl_display_t { + enum { NOT_INITIALIZED, INITIALIZED, TERMINATED }; + struct strings_t { char const * vendor; char const * version; char const * clientApi; char const * extensions; }; - strings_t queryString[IMPL_NUM_DRIVERS_IMPLEMENTATIONS]; + + struct DisplayImpl { + DisplayImpl() : dpy(EGL_NO_DISPLAY), config(0), + state(NOT_INITIALIZED), numConfigs(0) { } + EGLDisplay dpy; + EGLConfig* config; + EGLint state; + EGLint numConfigs; + strings_t queryString; + }; + + uint32_t magic; + DisplayImpl disp[IMPL_NUM_DRIVERS_IMPLEMENTATIONS]; + EGLint numTotalConfigs; + volatile int32_t refs; + + egl_display_t() : magic('_dpy'), numTotalConfigs(0) { } + ~egl_display_t() { magic = 0; } + inline bool isValid() const { return magic == '_dpy'; } + inline bool isAlive() const { return isValid(); } }; -struct egl_surface_t : public egl_object_t<'_srf'> +struct egl_surface_t : public egl_object_t { + typedef egl_object_t::LocalRef<egl_surface_t, EGLSurface> Ref; + egl_surface_t(EGLDisplay dpy, EGLSurface surface, int impl, egl_connection_t const* cnx) - : dpy(dpy), surface(surface), impl(impl), cnx(cnx) - { - // NOTE: window must be incRef'ed and connected already + : dpy(dpy), surface(surface), impl(impl), cnx(cnx) { } ~egl_surface_t() { } @@ -106,8 +190,10 @@ struct egl_surface_t : public egl_object_t<'_srf'> egl_connection_t const* cnx; }; -struct egl_context_t : public egl_object_t<'_ctx'> +struct egl_context_t : public egl_object_t { + typedef egl_object_t::LocalRef<egl_context_t, EGLContext> Ref; + egl_context_t(EGLDisplay dpy, EGLContext context, int impl, egl_connection_t const* cnx) : dpy(dpy), context(context), read(0), draw(0), impl(impl), cnx(cnx) @@ -121,8 +207,10 @@ struct egl_context_t : public egl_object_t<'_ctx'> egl_connection_t const* cnx; }; -struct egl_image_t : public egl_object_t<'_img'> +struct egl_image_t : public egl_object_t { + typedef egl_object_t::LocalRef<egl_image_t, EGLImageKHR> Ref; + egl_image_t(EGLDisplay dpy, EGLContext context) : dpy(dpy), context(context) { @@ -133,6 +221,10 @@ struct egl_image_t : public egl_object_t<'_img'> EGLImageKHR images[IMPL_NUM_DRIVERS_IMPLEMENTATIONS]; }; +typedef egl_surface_t::Ref SurfaceRef; +typedef egl_context_t::Ref ContextRef; +typedef egl_image_t::Ref ImageRef; + struct tls_t { tls_t() : error(EGL_SUCCESS), ctx(0), logCallWithNoContext(EGL_TRUE) { } @@ -272,14 +364,14 @@ int binarySearch( static EGLint configToUniqueId(egl_display_t const* dp, int i, int index) { // NOTE: this mapping works only if we have no more than two EGLimpl - return (i>0 ? dp->numConfigs[0] : 0) + index; + return (i>0 ? dp->disp[0].numConfigs : 0) + index; } static void uniqueIdToConfig(egl_display_t const* dp, EGLint configId, int& i, int& index) { // NOTE: this mapping works only if we have no more than two EGLimpl - size_t numConfigs = dp->numConfigs[0]; + size_t numConfigs = dp->disp[0].numConfigs; i = configId / numConfigs; index = configId % numConfigs; } @@ -391,7 +483,7 @@ static egl_connection_t* validate_display_config( return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL); } index = uintptr_t(config) & 0xFFFFFF; - if (index >= dp->numConfigs[impl]) { + if (index >= dp->disp[impl].numConfigs) { return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL); } egl_connection_t* const cnx = &gEGLImpl[impl]; @@ -405,11 +497,9 @@ static EGLBoolean validate_display_context(EGLDisplay dpy, EGLContext ctx) { if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS) return setError(EGL_BAD_DISPLAY, EGL_FALSE); - if (!get_display(dpy)->isValid()) + if (!get_display(dpy)->isAlive()) return setError(EGL_BAD_DISPLAY, EGL_FALSE); - if (!ctx) // TODO: make sure context is a valid object - return setError(EGL_BAD_CONTEXT, EGL_FALSE); - if (!get_context(ctx)->isValid()) + if (!get_context(ctx)->isAlive()) return setError(EGL_BAD_CONTEXT, EGL_FALSE); return EGL_TRUE; } @@ -418,37 +508,34 @@ static EGLBoolean validate_display_surface(EGLDisplay dpy, EGLSurface surface) { if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS) return setError(EGL_BAD_DISPLAY, EGL_FALSE); - if (!get_display(dpy)->isValid()) + if (!get_display(dpy)->isAlive()) return setError(EGL_BAD_DISPLAY, EGL_FALSE); - if (!surface) // TODO: make sure surface is a valid object - return setError(EGL_BAD_SURFACE, EGL_FALSE); - if (!get_surface(surface)->isValid()) + if (!get_surface(surface)->isAlive()) return setError(EGL_BAD_SURFACE, EGL_FALSE); return EGL_TRUE; } - EGLImageKHR egl_get_image_for_current_context(EGLImageKHR image) { + ImageRef _i(image); + if (!_i.get()) return EGL_NO_IMAGE_KHR; + EGLContext context = getContext(); if (context == EGL_NO_CONTEXT || image == EGL_NO_IMAGE_KHR) return EGL_NO_IMAGE_KHR; egl_context_t const * const c = get_context(context); - if (!c->isValid()) + if (!c->isAlive()) return EGL_NO_IMAGE_KHR; egl_image_t const * const i = get_image(image); - if (!i->isValid()) - return EGL_NO_IMAGE_KHR; - return i->images[c->impl]; } // ---------------------------------------------------------------------------- // this mutex protects: -// d->dpys[] +// d->disp[] // egl_init_drivers_locked() // static pthread_mutex_t gInitDriverMutex = PTHREAD_MUTEX_INITIALIZER; @@ -477,7 +564,7 @@ EGLBoolean egl_init_drivers_locked() if (cnx->dso) { EGLDisplay dpy = cnx->hooks->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY); LOGE_IF(dpy==EGL_NO_DISPLAY, "No EGLDisplay for software EGL!"); - d->dpys[IMPL_SOFTWARE] = dpy; + d->disp[IMPL_SOFTWARE].dpy = dpy; if (dpy == EGL_NO_DISPLAY) { loader.close(cnx->dso); cnx->dso = NULL; @@ -495,7 +582,7 @@ EGLBoolean egl_init_drivers_locked() if (cnx->dso) { EGLDisplay dpy = cnx->hooks->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY); LOGE_IF(dpy==EGL_NO_DISPLAY, "No EGLDisplay for hardware EGL!"); - d->dpys[IMPL_HARDWARE] = dpy; + d->disp[IMPL_HARDWARE].dpy = dpy; if (dpy == EGL_NO_DISPLAY) { loader.close(cnx->dso); cnx->dso = NULL; @@ -505,7 +592,7 @@ EGLBoolean egl_init_drivers_locked() LOGD("3D hardware acceleration is disabled"); } } - + if (!gEGLImpl[IMPL_SOFTWARE].dso && !gEGLImpl[IMPL_HARDWARE].dso) { return EGL_FALSE; } @@ -563,7 +650,6 @@ EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) // initialize each EGL and // build our own extension string first, based on the extension we know // and the extension supported by our client implementation - dp->extensionsString = strdup(gExtensionString); for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) { egl_connection_t* const cnx = &gEGLImpl[i]; cnx->major = -1; @@ -571,25 +657,43 @@ EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) if (!cnx->dso) continue; - if (cnx->hooks->egl.eglInitialize( - dp->dpys[i], &cnx->major, &cnx->minor)) { +#if defined(ADRENO130) +#warning "Adreno-130 eglInitialize() workaround" + /* + * The ADRENO 130 driver returns a different EGLDisplay each time + * eglGetDisplay() is called, but also makes the EGLDisplay invalid + * after eglTerminate() has been called, so that eglInitialize() + * cannot be called again. Therefore, we need to make sure to call + * eglGetDisplay() before calling eglInitialize(); + */ + if (i == IMPL_HARDWARE) { + dp->disp[i].dpy = + cnx->hooks->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY); + } +#endif + + EGLDisplay idpy = dp->disp[i].dpy; + if (cnx->hooks->egl.eglInitialize(idpy, &cnx->major, &cnx->minor)) { //LOGD("initialized %d dpy=%p, ver=%d.%d, cnx=%p", - // i, dp->dpys[i], cnx->major, cnx->minor, cnx); + // i, idpy, cnx->major, cnx->minor, cnx); + + // display is now initialized + dp->disp[i].state = egl_display_t::INITIALIZED; // get the query-strings for this display for each implementation - dp->queryString[i].vendor = - cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_VENDOR); - dp->queryString[i].version = - cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_VERSION); - dp->queryString[i].extensions = strdup( - cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_EXTENSIONS)); - dp->queryString[i].clientApi = - cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_CLIENT_APIS); + dp->disp[i].queryString.vendor = + cnx->hooks->egl.eglQueryString(idpy, EGL_VENDOR); + dp->disp[i].queryString.version = + cnx->hooks->egl.eglQueryString(idpy, EGL_VERSION); + dp->disp[i].queryString.extensions = + cnx->hooks->egl.eglQueryString(idpy, EGL_EXTENSIONS); + dp->disp[i].queryString.clientApi = + cnx->hooks->egl.eglQueryString(idpy, EGL_CLIENT_APIS); } else { - LOGD("%d: eglInitialize() failed (%s)", - i, egl_strerror(cnx->hooks->egl.eglGetError())); + LOGW("%d: eglInitialize(%p) failed (%s)", i, idpy, + egl_strerror(cnx->hooks->egl.eglGetError())); } } @@ -598,15 +702,16 @@ EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) egl_connection_t* const cnx = &gEGLImpl[i]; if (cnx->dso && cnx->major>=0 && cnx->minor>=0) { EGLint n; - if (cnx->hooks->egl.eglGetConfigs(dp->dpys[i], 0, 0, &n)) { - dp->configs[i] = (EGLConfig*)malloc(sizeof(EGLConfig)*n); - if (dp->configs[i]) { + if (cnx->hooks->egl.eglGetConfigs(dp->disp[i].dpy, 0, 0, &n)) { + dp->disp[i].config = (EGLConfig*)malloc(sizeof(EGLConfig)*n); + if (dp->disp[i].config) { if (cnx->hooks->egl.eglGetConfigs( - dp->dpys[i], dp->configs[i], n, &dp->numConfigs[i])) + dp->disp[i].dpy, dp->disp[i].config, n, + &dp->disp[i].numConfigs)) { // sort the configurations so we can do binary searches - qsort( dp->configs[i], - dp->numConfigs[i], + qsort( dp->disp[i].config, + dp->disp[i].numConfigs, sizeof(EGLConfig), cmp_configs); dp->numTotalConfigs += n; @@ -639,18 +744,24 @@ EGLBoolean eglTerminate(EGLDisplay dpy) EGLBoolean res = EGL_FALSE; for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) { egl_connection_t* const cnx = &gEGLImpl[i]; - if (cnx->dso) { - cnx->hooks->egl.eglTerminate(dp->dpys[i]); + if (cnx->dso && dp->disp[i].state == egl_display_t::INITIALIZED) { + if (cnx->hooks->egl.eglTerminate(dp->disp[i].dpy) == EGL_FALSE) { + LOGW("%d: eglTerminate(%p) failed (%s)", i, dp->disp[i].dpy, + egl_strerror(cnx->hooks->egl.eglGetError())); + } // REVISIT: it's unclear what to do if eglTerminate() fails - free(dp->configs[i]); - free((void*)dp->queryString[i].extensions); - dp->numConfigs[i] = 0; - dp->dpys[i] = EGL_NO_DISPLAY; + free(dp->disp[i].config); + + dp->disp[i].numConfigs = 0; + dp->disp[i].config = 0; + dp->disp[i].state = egl_display_t::TERMINATED; + res = EGL_TRUE; } } - free((void*)dp->extensionsString); - dp->extensionsString = 0; + + // TODO: all egl_object_t should be marked for termination + dp->numTotalConfigs = 0; clearTLS(); return res; @@ -674,7 +785,7 @@ EGLBoolean eglGetConfigs( EGLDisplay dpy, } GLint n = 0; for (int j=0 ; j<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; j++) { - for (int i=0 ; i<dp->numConfigs[j] && config_size ; i++) { + for (int i=0 ; i<dp->disp[j].numConfigs && config_size ; i++) { *configs++ = MAKE_CONFIG(j, i); config_size--; n++; @@ -731,7 +842,7 @@ EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list, egl_connection_t* const cnx = &gEGLImpl[i]; if (cnx->dso) { cnx->hooks->egl.eglGetConfigAttrib( - dp->dpys[i], dp->configs[i][index], + dp->disp[i].dpy, dp->disp[i].config[index], EGL_CONFIG_ID, &configId); // and switch to the new list @@ -746,7 +857,7 @@ EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list, // which one. res = cnx->hooks->egl.eglChooseConfig( - dp->dpys[i], attrib_list, configs, config_size, &n); + dp->disp[i].dpy, attrib_list, configs, config_size, &n); if (res && n>0) { // n has to be 0 or 1, by construction, and we already know // which config it will return (since there can be only one). @@ -765,13 +876,14 @@ EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list, egl_connection_t* const cnx = &gEGLImpl[i]; if (cnx->dso) { if (cnx->hooks->egl.eglChooseConfig( - dp->dpys[i], attrib_list, configs, config_size, &n)) { + dp->disp[i].dpy, attrib_list, configs, config_size, &n)) { if (configs) { // now we need to convert these client EGLConfig to our // internal EGLConfig format. This is done in O(n log n). for (int j=0 ; j<n ; j++) { int index = binarySearch<EGLConfig>( - dp->configs[i], 0, dp->numConfigs[i]-1, configs[j]); + dp->disp[i].config, 0, + dp->disp[i].numConfigs-1, configs[j]); if (index >= 0) { if (configs) { configs[j] = MAKE_CONFIG(i, index); @@ -806,7 +918,7 @@ EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, return EGL_TRUE; } return cnx->hooks->egl.eglGetConfigAttrib( - dp->dpys[i], dp->configs[i][index], attribute, value); + dp->disp[i].dpy, dp->disp[i].config[index], attribute, value); } // ---------------------------------------------------------------------------- @@ -822,7 +934,7 @@ EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index); if (cnx) { EGLSurface surface = cnx->hooks->egl.eglCreateWindowSurface( - dp->dpys[i], dp->configs[i][index], window, attrib_list); + dp->disp[i].dpy, dp->disp[i].config[index], window, attrib_list); if (surface != EGL_NO_SURFACE) { egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx); return s; @@ -840,7 +952,7 @@ EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config, egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index); if (cnx) { EGLSurface surface = cnx->hooks->egl.eglCreatePixmapSurface( - dp->dpys[i], dp->configs[i][index], pixmap, attrib_list); + dp->disp[i].dpy, dp->disp[i].config[index], pixmap, attrib_list); if (surface != EGL_NO_SURFACE) { egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx); return s; @@ -857,7 +969,7 @@ EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config, egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index); if (cnx) { EGLSurface surface = cnx->hooks->egl.eglCreatePbufferSurface( - dp->dpys[i], dp->configs[i][index], attrib_list); + dp->disp[i].dpy, dp->disp[i].config[index], attrib_list); if (surface != EGL_NO_SURFACE) { egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx); return s; @@ -868,28 +980,35 @@ EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config, EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface) { + SurfaceRef _s(surface); + if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE); + if (!validate_display_surface(dpy, surface)) return EGL_FALSE; egl_display_t const * const dp = get_display(dpy); - egl_surface_t const * const s = get_surface(surface); + egl_surface_t * const s = get_surface(surface); EGLBoolean result = s->cnx->hooks->egl.eglDestroySurface( - dp->dpys[s->impl], s->surface); - - delete s; + dp->disp[s->impl].dpy, s->surface); + if (result == EGL_TRUE) { + _s.terminate(); + } return result; } EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value) { + SurfaceRef _s(surface); + if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE); + if (!validate_display_surface(dpy, surface)) return EGL_FALSE; egl_display_t const * const dp = get_display(dpy); egl_surface_t const * const s = get_surface(surface); return s->cnx->hooks->egl.eglQuerySurface( - dp->dpys[s->impl], s->surface, attribute, value); + dp->disp[s->impl].dpy, s->surface, attribute, value); } // ---------------------------------------------------------------------------- @@ -904,7 +1023,8 @@ EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index); if (cnx) { EGLContext context = cnx->hooks->egl.eglCreateContext( - dp->dpys[i], dp->configs[i][index], share_list, attrib_list); + dp->disp[i].dpy, dp->disp[i].config[index], + share_list, attrib_list); if (context != EGL_NO_CONTEXT) { egl_context_t* c = new egl_context_t(dpy, context, i, cnx); return c; @@ -915,66 +1035,125 @@ EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx) { + ContextRef _c(ctx); + if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE); + if (!validate_display_context(dpy, ctx)) return EGL_FALSE; egl_display_t const * const dp = get_display(dpy); egl_context_t * const c = get_context(ctx); EGLBoolean result = c->cnx->hooks->egl.eglDestroyContext( - dp->dpys[c->impl], c->context); - delete c; + dp->disp[c->impl].dpy, c->context); + if (result == EGL_TRUE) { + _c.terminate(); + } return result; } EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) { + // get a reference to the object passed in + ContextRef _c(ctx); + SurfaceRef _d(draw); + SurfaceRef _r(read); + + // validate the display and the context (if not EGL_NO_CONTEXT) egl_display_t const * const dp = get_display(dpy); if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE); + if ((ctx != EGL_NO_CONTEXT) && (!validate_display_context(dpy, ctx))) { + // EGL_NO_CONTEXT is valid + return EGL_FALSE; + } - if (read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE && - ctx == EGL_NO_CONTEXT) - { - EGLBoolean result = EGL_TRUE; - ctx = getContext(); - if (ctx) { - egl_context_t * const c = get_context(ctx); - result = c->cnx->hooks->egl.eglMakeCurrent(dp->dpys[c->impl], 0, 0, 0); - if (result == EGL_TRUE) { - setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]); - setContext(EGL_NO_CONTEXT); + // these are the underlying implementation's object + EGLContext impl_ctx = EGL_NO_CONTEXT; + EGLSurface impl_draw = EGL_NO_SURFACE; + EGLSurface impl_read = EGL_NO_SURFACE; + + // these are our objects structs passed in + egl_context_t * c = NULL; + egl_surface_t const * d = NULL; + egl_surface_t const * r = NULL; + + // these are the current objects structs + egl_context_t * cur_c = get_context(getContext()); + egl_surface_t * cur_r = NULL; + egl_surface_t * cur_d = NULL; + + if (ctx != EGL_NO_CONTEXT) { + c = get_context(ctx); + cur_r = get_surface(c->read); + cur_d = get_surface(c->draw); + impl_ctx = c->context; + } else { + // no context given, use the implementation of the current context + if (cur_c == NULL) { + // no current context + if (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE) { + // calling eglMakeCurrent( ..., EGL_NO_CONTEXT, !=0, !=0); + return setError(EGL_BAD_PARAMETER, EGL_FALSE); } + // not an error, there is just not current context. + return EGL_TRUE; } - return result; } - if (!validate_display_context(dpy, ctx)) - return EGL_FALSE; - - EGLSurface impl_draw = EGL_NO_SURFACE; - EGLSurface impl_read = EGL_NO_SURFACE; - egl_context_t * const c = get_context(ctx); + // retrieve the underlying implementation's draw EGLSurface if (draw != EGL_NO_SURFACE) { - egl_surface_t const * d = get_surface(draw); - if (!d) return setError(EGL_BAD_SURFACE, EGL_FALSE); - if (d->impl != c->impl) + d = get_surface(draw); + // make sure the EGLContext and EGLSurface passed in are for + // the same driver + if (c && d->impl != c->impl) return setError(EGL_BAD_MATCH, EGL_FALSE); impl_draw = d->surface; } + + // retrieve the underlying implementation's read EGLSurface if (read != EGL_NO_SURFACE) { - egl_surface_t const * r = get_surface(read); - if (!r) return setError(EGL_BAD_SURFACE, EGL_FALSE); - if (r->impl != c->impl) + r = get_surface(read); + // make sure the EGLContext and EGLSurface passed in are for + // the same driver + if (c && r->impl != c->impl) return setError(EGL_BAD_MATCH, EGL_FALSE); impl_read = r->surface; } - EGLBoolean result = c->cnx->hooks->egl.eglMakeCurrent( - dp->dpys[c->impl], impl_draw, impl_read, c->context); + + EGLBoolean result; + + if (c) { + result = c->cnx->hooks->egl.eglMakeCurrent( + dp->disp[c->impl].dpy, impl_draw, impl_read, impl_ctx); + } else { + result = cur_c->cnx->hooks->egl.eglMakeCurrent( + dp->disp[cur_c->impl].dpy, impl_draw, impl_read, impl_ctx); + } if (result == EGL_TRUE) { - setGlThreadSpecific(c->cnx->hooks); - setContext(ctx); - c->read = read; - c->draw = draw; + // by construction, these are either 0 or valid (possibly terminated) + // it should be impossible for these to be invalid + ContextRef _cur_c(cur_c); + SurfaceRef _cur_r(cur_r); + SurfaceRef _cur_d(cur_d); + + // cur_c has to be valid here (but could be terminated) + if (ctx != EGL_NO_CONTEXT) { + setGlThreadSpecific(c->cnx->hooks); + setContext(ctx); + _c.acquire(); + } else { + setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]); + setContext(EGL_NO_CONTEXT); + } + _cur_c.release(); + + _r.acquire(); + _cur_r.release(); + if (c) c->read = read; + + _d.acquire(); + _cur_d.release(); + if (c) c->draw = draw; } return result; } @@ -983,6 +1162,9 @@ EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw, EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value) { + ContextRef _c(ctx); + if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE); + if (!validate_display_context(dpy, ctx)) return EGL_FALSE; @@ -990,7 +1172,7 @@ EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx, egl_context_t * const c = get_context(ctx); return c->cnx->hooks->egl.eglQueryContext( - dp->dpys[c->impl], c->context, attribute, value); + dp->disp[c->impl].dpy, c->context, attribute, value); } EGLContext eglGetCurrentContext(void) @@ -1158,22 +1340,28 @@ __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname) EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw) { + SurfaceRef _s(draw); + if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE); + if (!validate_display_surface(dpy, draw)) return EGL_FALSE; egl_display_t const * const dp = get_display(dpy); egl_surface_t const * const s = get_surface(draw); - return s->cnx->hooks->egl.eglSwapBuffers(dp->dpys[s->impl], s->surface); + return s->cnx->hooks->egl.eglSwapBuffers(dp->disp[s->impl].dpy, s->surface); } EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface, NativePixmapType target) { + SurfaceRef _s(surface); + if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE); + if (!validate_display_surface(dpy, surface)) return EGL_FALSE; egl_display_t const * const dp = get_display(dpy); egl_surface_t const * const s = get_surface(surface); return s->cnx->hooks->egl.eglCopyBuffers( - dp->dpys[s->impl], s->surface, target); + dp->disp[s->impl].dpy, s->surface, target); } const char* eglQueryString(EGLDisplay dpy, EGLint name) @@ -1200,13 +1388,16 @@ const char* eglQueryString(EGLDisplay dpy, EGLint name) EGLBoolean eglSurfaceAttrib( EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value) { + SurfaceRef _s(surface); + if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE); + if (!validate_display_surface(dpy, surface)) return EGL_FALSE; egl_display_t const * const dp = get_display(dpy); egl_surface_t const * const s = get_surface(surface); if (s->cnx->hooks->egl.eglSurfaceAttrib) { return s->cnx->hooks->egl.eglSurfaceAttrib( - dp->dpys[s->impl], s->surface, attribute, value); + dp->disp[s->impl].dpy, s->surface, attribute, value); } return setError(EGL_BAD_SURFACE, EGL_FALSE); } @@ -1214,13 +1405,16 @@ EGLBoolean eglSurfaceAttrib( EGLBoolean eglBindTexImage( EGLDisplay dpy, EGLSurface surface, EGLint buffer) { + SurfaceRef _s(surface); + if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE); + if (!validate_display_surface(dpy, surface)) return EGL_FALSE; egl_display_t const * const dp = get_display(dpy); egl_surface_t const * const s = get_surface(surface); if (s->cnx->hooks->egl.eglBindTexImage) { return s->cnx->hooks->egl.eglBindTexImage( - dp->dpys[s->impl], s->surface, buffer); + dp->disp[s->impl].dpy, s->surface, buffer); } return setError(EGL_BAD_SURFACE, EGL_FALSE); } @@ -1228,13 +1422,16 @@ EGLBoolean eglBindTexImage( EGLBoolean eglReleaseTexImage( EGLDisplay dpy, EGLSurface surface, EGLint buffer) { + SurfaceRef _s(surface); + if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE); + if (!validate_display_surface(dpy, surface)) return EGL_FALSE; egl_display_t const * const dp = get_display(dpy); egl_surface_t const * const s = get_surface(surface); if (s->cnx->hooks->egl.eglReleaseTexImage) { return s->cnx->hooks->egl.eglReleaseTexImage( - dp->dpys[s->impl], s->surface, buffer); + dp->disp[s->impl].dpy, s->surface, buffer); } return setError(EGL_BAD_SURFACE, EGL_FALSE); } @@ -1249,7 +1446,8 @@ EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval) egl_connection_t* const cnx = &gEGLImpl[i]; if (cnx->dso) { if (cnx->hooks->egl.eglSwapInterval) { - if (cnx->hooks->egl.eglSwapInterval(dp->dpys[i], interval) == EGL_FALSE) { + if (cnx->hooks->egl.eglSwapInterval( + dp->disp[i].dpy, interval) == EGL_FALSE) { res = EGL_FALSE; } } @@ -1351,7 +1549,8 @@ EGLSurface eglCreatePbufferFromClientBuffer( if (!cnx) return EGL_FALSE; if (cnx->hooks->egl.eglCreatePbufferFromClientBuffer) { return cnx->hooks->egl.eglCreatePbufferFromClientBuffer( - dp->dpys[i], buftype, buffer, dp->configs[i][index], attrib_list); + dp->disp[i].dpy, buftype, buffer, + dp->disp[i].config[index], attrib_list); } return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE); } @@ -1363,6 +1562,9 @@ EGLSurface eglCreatePbufferFromClientBuffer( EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface, const EGLint *attrib_list) { + SurfaceRef _s(surface); + if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE); + if (!validate_display_surface(dpy, surface)) return EGL_FALSE; @@ -1371,13 +1573,16 @@ EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface, if (s->cnx->hooks->egl.eglLockSurfaceKHR) { return s->cnx->hooks->egl.eglLockSurfaceKHR( - dp->dpys[s->impl], s->surface, attrib_list); + dp->disp[s->impl].dpy, s->surface, attrib_list); } return setError(EGL_BAD_DISPLAY, EGL_FALSE); } EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface) { + SurfaceRef _s(surface); + if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE); + if (!validate_display_surface(dpy, surface)) return EGL_FALSE; @@ -1386,7 +1591,7 @@ EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface) if (s->cnx->hooks->egl.eglUnlockSurfaceKHR) { return s->cnx->hooks->egl.eglUnlockSurfaceKHR( - dp->dpys[s->impl], s->surface); + dp->disp[s->impl].dpy, s->surface); } return setError(EGL_BAD_DISPLAY, EGL_FALSE); } @@ -1395,13 +1600,15 @@ EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list) { if (ctx != EGL_NO_CONTEXT) { + ContextRef _c(ctx); + if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR); if (!validate_display_context(dpy, ctx)) return EGL_NO_IMAGE_KHR; egl_display_t const * const dp = get_display(dpy); egl_context_t * const c = get_context(ctx); // since we have an EGLContext, we know which implementation to use EGLImageKHR image = c->cnx->hooks->egl.eglCreateImageKHR( - dp->dpys[c->impl], c->context, target, buffer, attrib_list); + dp->disp[c->impl].dpy, c->context, target, buffer, attrib_list); if (image == EGL_NO_IMAGE_KHR) return image; @@ -1425,7 +1632,7 @@ EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, if (cnx->dso) { if (cnx->hooks->egl.eglCreateImageKHR) { implImages[i] = cnx->hooks->egl.eglCreateImageKHR( - dp->dpys[i], ctx, target, buffer, attrib_list); + dp->disp[i].dpy, ctx, target, buffer, attrib_list); if (implImages[i] != EGL_NO_IMAGE_KHR) { success = true; } @@ -1443,16 +1650,15 @@ EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img) { - egl_display_t const * const dp = get_display(dpy); + egl_display_t const * const dp = get_display(dpy); if (dp == 0) { return setError(EGL_BAD_DISPLAY, EGL_FALSE); } - egl_image_t* image = get_image(img); - if (!image->isValid()) { - return setError(EGL_BAD_PARAMETER, EGL_FALSE); - } + ImageRef _i(img); + if (!_i.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE); + egl_image_t* image = get_image(img); bool success = false; for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) { egl_connection_t* const cnx = &gEGLImpl[i]; @@ -1460,7 +1666,7 @@ EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img) if (cnx->dso) { if (cnx->hooks->egl.eglCreateImageKHR) { if (cnx->hooks->egl.eglDestroyImageKHR( - dp->dpys[i], image->images[i])) { + dp->disp[i].dpy, image->images[i])) { success = true; } } @@ -1470,7 +1676,7 @@ EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img) if (!success) return EGL_FALSE; - delete image; + _i.terminate(); return EGL_TRUE; } @@ -1483,26 +1689,32 @@ EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img) EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw, EGLint left, EGLint top, EGLint width, EGLint height) { + SurfaceRef _s(draw); + if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE); + if (!validate_display_surface(dpy, draw)) return EGL_FALSE; egl_display_t const * const dp = get_display(dpy); egl_surface_t const * const s = get_surface(draw); if (s->cnx->hooks->egl.eglSetSwapRectangleANDROID) { - return s->cnx->hooks->egl.eglSetSwapRectangleANDROID(dp->dpys[s->impl], - s->surface, left, top, width, height); + return s->cnx->hooks->egl.eglSetSwapRectangleANDROID( + dp->disp[s->impl].dpy, s->surface, left, top, width, height); } return setError(EGL_BAD_DISPLAY, NULL); } EGLClientBuffer eglGetRenderBufferANDROID(EGLDisplay dpy, EGLSurface draw) { + SurfaceRef _s(draw); + if (!_s.get()) return setError(EGL_BAD_SURFACE, (EGLClientBuffer*)0); + if (!validate_display_surface(dpy, draw)) return 0; egl_display_t const * const dp = get_display(dpy); egl_surface_t const * const s = get_surface(draw); if (s->cnx->hooks->egl.eglGetRenderBufferANDROID) { - return s->cnx->hooks->egl.eglGetRenderBufferANDROID(dp->dpys[s->impl], - s->surface); + return s->cnx->hooks->egl.eglGetRenderBufferANDROID( + dp->disp[s->impl].dpy, s->surface); } return setError(EGL_BAD_DISPLAY, (EGLClientBuffer*)0); } diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java index 6a1f6f8..8f4061e 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java @@ -64,7 +64,7 @@ public class DatabaseHelper extends SQLiteOpenHelper { private static final String TAG = "SettingsProvider"; private static final String DATABASE_NAME = "settings.db"; - private static final int DATABASE_VERSION = 38; + private static final int DATABASE_VERSION = 39; private Context mContext; @@ -389,21 +389,6 @@ public class DatabaseHelper extends SQLiteOpenHelper { if (upgradeVersion == 34) { db.beginTransaction(); try { - String value = - mContext.getResources().getBoolean(R.bool.assisted_gps_enabled) ? "1" : "0"; - db.execSQL("INSERT OR IGNORE INTO secure(name,value) values('" + - Settings.Secure.ASSISTED_GPS_ENABLED + "','" + value + "');"); - db.setTransactionSuccessful(); - } finally { - db.endTransaction(); - } - - upgradeVersion = 35; - } - - if (upgradeVersion == 35) { - db.beginTransaction(); - try { SQLiteStatement stmt = db.compileStatement("INSERT OR IGNORE INTO secure(name,value)" + " VALUES(?,?);"); loadSecure35Settings(stmt); @@ -412,8 +397,15 @@ public class DatabaseHelper extends SQLiteOpenHelper { } finally { db.endTransaction(); } + } + // due to a botched merge from donut to eclair, the initialization of ASSISTED_GPS_ENABLED + // was accidentally done out of order here. + // to fix this, ASSISTED_GPS_ENABLED is now initialized while upgrading from 38 to 39, + // and we intentionally do nothing from 35 to 36 now. + if (upgradeVersion == 35) { upgradeVersion = 36; } + if (upgradeVersion == 36) { // This upgrade adds the STREAM_SYSTEM_ENFORCED type to the list of // types affected by ringer modes (silent, vibrate, etc.) @@ -450,6 +442,21 @@ public class DatabaseHelper extends SQLiteOpenHelper { upgradeVersion = 38; } + if (upgradeVersion == 38) { + db.beginTransaction(); + try { + String value = + mContext.getResources().getBoolean(R.bool.assisted_gps_enabled) ? "1" : "0"; + db.execSQL("INSERT OR IGNORE INTO secure(name,value) values('" + + Settings.Secure.ASSISTED_GPS_ENABLED + "','" + value + "');"); + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + } + + upgradeVersion = 39; + } + if (upgradeVersion != currentVersion) { Log.w(TAG, "Got stuck trying to upgrade from version " + upgradeVersion + ", must wipe the settings provider"); diff --git a/packages/SubscribedFeedsProvider/AndroidManifest.xml b/packages/SubscribedFeedsProvider/AndroidManifest.xml index d839c4e..a3938bd 100644 --- a/packages/SubscribedFeedsProvider/AndroidManifest.xml +++ b/packages/SubscribedFeedsProvider/AndroidManifest.xml @@ -13,7 +13,8 @@ android:label="@string/app_label"> <uses-library android:name="com.google.android.gtalkservice" /> <provider android:name="SubscribedFeedsProvider" - android:authorities="subscribedfeeds" android:syncable="false" + android:authorities="subscribedfeeds" + android:label="@string/provider_label" android:multiprocess="false" android:readPermission="android.permission.SUBSCRIBED_FEEDS_READ" android:writePermission="android.permission.SUBSCRIBED_FEEDS_WRITE" /> diff --git a/packages/SubscribedFeedsProvider/res/values/strings.xml b/packages/SubscribedFeedsProvider/res/values/strings.xml index 072571d..c4c2484 100644 --- a/packages/SubscribedFeedsProvider/res/values/strings.xml +++ b/packages/SubscribedFeedsProvider/res/values/strings.xml @@ -17,5 +17,9 @@ <resources> <!-- Title of the feed synchronization activity. --> <string name="app_label">Sync Feeds</string> + + <!-- What to show in messaging that refers to this provider, e.g. AccountSyncSettings --> + <string name="provider_label">Push Subscriptions</string> + </resources> diff --git a/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsProvider.java b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsProvider.java index d87f5e7..2647752 100644 --- a/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsProvider.java +++ b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsProvider.java @@ -16,6 +16,7 @@ package com.android.providers.subscribedfeeds; +import android.accounts.Account; import android.content.UriMatcher; import android.content.*; import android.database.Cursor; @@ -123,6 +124,16 @@ public class SubscribedFeedsProvider extends AbstractSyncableContentProvider { } @Override + protected void onAccountsChanged(Account[] accountsArray) { + super.onAccountsChanged(accountsArray); + for (Account account : accountsArray) { + if (account.type.equals("com.google.GAIA")) { + ContentResolver.setSyncAutomatically(account, "subscribedfeeds", true); + } + } + } + + @Override protected void onDatabaseOpened(SQLiteDatabase db) { db.markTableSyncable("feeds", "_deleted_feeds"); } diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index df37d35..e26dd13 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -357,6 +357,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { for (int t=0; t <= ConnectivityManager.MAX_RADIO_TYPE; t++) { if (t != mNetworkPreference && mNetTrackers[t].getNetworkInfo().isConnected()) { + if (DBG) { + Log.d(TAG, "tearing down " + + mNetTrackers[t].getNetworkInfo() + + " in enforcePreference"); + } teardown(mNetTrackers[t]); } } @@ -1106,11 +1111,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { int j = 1; for (String dns : dnsList) { if (dns != null && !TextUtils.equals(dns, "0.0.0.0")) { + if (DBG) Log.d(TAG, " adding "+dns); SystemProperties.set("net.dns" + j++, dns); } } for (int k=j ; k<mNumDnsEntries; k++) { - SystemProperties.set("net.dns" + j, ""); + if (DBG) Log.d(TAG, "erasing net.dns" + k); + SystemProperties.set("net.dns" + k, ""); } mNumDnsEntries = j; } else { @@ -1232,6 +1239,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { NetworkInfo i = net.getNetworkInfo(); if (i.isConnected() && !mNetAttributes[i.getType()].isDefault()) { + if (DBG) { + Log.d(TAG, "tearing down " + i + + " to restore the default network"); + } teardown(net); } } diff --git a/services/java/com/android/server/DockObserver.java b/services/java/com/android/server/DockObserver.java index 68ff416..2bd039f 100644 --- a/services/java/com/android/server/DockObserver.java +++ b/services/java/com/android/server/DockObserver.java @@ -16,7 +16,6 @@ package com.android.server; -import android.app.ActivityManagerNative; import android.content.Context; import android.content.Intent; import android.os.Handler; @@ -91,16 +90,12 @@ class DockObserver extends UEventObserver { } private synchronized final void sendIntent() { + Log.d(TAG, "Broadcasting dock state " + mDockState); + // Pack up the values and broadcast them to everyone Intent intent = new Intent(Intent.ACTION_DOCK_EVENT); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.putExtra(Intent.EXTRA_DOCK_STATE, mDockState); - - // TODO: Should we require a permission? - if (Log.isLoggable(TAG, Log.VERBOSE)) { - Log.v(TAG, "Broadcasting dock state " + mDockState); - } - ActivityManagerNative.broadcastStickyIntent(intent, null); + mContext.sendStickyBroadcast(intent); } private final Handler mHandler = new Handler() { diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java index f81c519..3d4bcc5 100644 --- a/services/java/com/android/server/MountService.java +++ b/services/java/com/android/server/MountService.java @@ -231,6 +231,7 @@ class MountService extends IMountService.Stub { if (getMassStorageConnected() && !suppressIfConnected) { Intent intent = new Intent(); intent.setClass(mContext, com.android.internal.app.UsbStorageActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0); setUsbStorageNotification( com.android.internal.R.string.usb_storage_notification_title, diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java index f8ba058..1384ede 100644 --- a/services/java/com/android/server/WindowManagerService.java +++ b/services/java/com/android/server/WindowManagerService.java @@ -8850,6 +8850,7 @@ public class WindowManagerService extends IWindowManager.Stub "Now opening app" + wtoken); wtoken.reportedVisible = false; wtoken.inPendingTransaction = false; + wtoken.animation = null; setTokenVisibilityLocked(wtoken, lp, true, transit, false); wtoken.updateReportedVisibilityLocked(); wtoken.showAllWindowsLocked(); @@ -8860,6 +8861,7 @@ public class WindowManagerService extends IWindowManager.Stub if (DEBUG_APP_TRANSITIONS) Log.v(TAG, "Now closing app" + wtoken); wtoken.inPendingTransaction = false; + wtoken.animation = null; setTokenVisibilityLocked(wtoken, lp, false, transit, false); wtoken.updateReportedVisibilityLocked(); // Force the allDrawn flag, because we want to start diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index ee9fa36..23eb7c1 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -42,6 +42,7 @@ import android.app.Instrumentation; import android.app.Notification; import android.app.PendingIntent; import android.app.ResultInfo; +import android.app.Service; import android.backup.IBackupManager; import android.content.ActivityNotFoundException; import android.content.ComponentName; @@ -754,6 +755,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen String mTopData; boolean mSystemReady = false; boolean mBooting = false; + boolean mWaitingUpdate = false; + boolean mDidUpdate = false; Context mContext; @@ -971,6 +974,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen res.set(0); } } + + ensureBootCompleted(); } break; case SHOW_NOT_RESPONDING_MSG: { synchronized (ActivityManagerService.this) { @@ -991,13 +996,13 @@ public final class ActivityManagerService extends ActivityManagerNative implemen proc.anrDialog = d; } - ensureScreenEnabled(); + ensureBootCompleted(); } break; case SHOW_FACTORY_ERROR_MSG: { Dialog d = new FactoryErrorDialog( mContext, msg.getData().getCharSequence("msg")); d.show(); - enableScreenAfterBoot(); + ensureBootCompleted(); } break; case UPDATE_CONFIGURATION_MSG: { final ContentResolver resolver = mContext.getContentResolver(); @@ -1842,12 +1847,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } startProcessLocked(r.processName, r.info.applicationInfo, true, 0, - "activity", r.intent.getComponent()); + "activity", r.intent.getComponent(), false); } private final ProcessRecord startProcessLocked(String processName, ApplicationInfo info, boolean knownToBeDead, int intentFlags, - String hostingType, ComponentName hostingName) { + String hostingType, ComponentName hostingName, boolean allowWhileBooting) { ProcessRecord app = getProcessRecordLocked(processName, info.uid); // We don't have to do anything more if: // (1) There is an existing application record; and @@ -1900,7 +1905,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // If the system is not ready yet, then hold off on starting this // process until it is. if (!mSystemReady - && (info.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) { + && !isAllowedWhileBooting(info) + && !allowWhileBooting) { if (!mProcessesOnHold.contains(app)) { mProcessesOnHold.add(app); } @@ -1911,6 +1917,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen return (app.pid != 0) ? app : null; } + boolean isAllowedWhileBooting(ApplicationInfo ai) { + return (ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0; + } + private final void startProcessLocked(ProcessRecord app, String hostingType, String hostingNameStr) { if (app.pid > 0 && app.pid != MY_PID) { @@ -5084,8 +5094,13 @@ public final class ActivityManagerService extends ActivityManagerNative implemen mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app); - List providers = generateApplicationProvidersLocked(app); + boolean normalMode = mSystemReady || isAllowedWhileBooting(app.info); + List providers = normalMode ? generateApplicationProvidersLocked(app) : null; + if (!normalMode) { + Log.i(TAG, "Launching preboot mode app: " + app); + } + if (localLOGV) Log.v( TAG, "New app record " + app + " thread=" + thread.asBinder() + " pid=" + pid); @@ -5101,12 +5116,14 @@ public final class ActivityManagerService extends ActivityManagerNative implemen mWaitForDebugger = mOrigWaitForDebugger; } } + // If the app is being launched for restore or full backup, set it up specially boolean isRestrictedBackupMode = false; if (mBackupTarget != null && mBackupAppName.equals(processName)) { isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE) || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL); } + ensurePackageDexOpt(app.instrumentationInfo != null ? app.instrumentationInfo.packageName : app.info.packageName); @@ -5117,7 +5134,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen ? app.instrumentationInfo : app.info, providers, app.instrumentationClass, app.instrumentationProfileFile, app.instrumentationArguments, app.instrumentationWatcher, testMode, - isRestrictedBackupMode, mConfiguration, getCommonServicesLocked()); + isRestrictedBackupMode || !normalMode, + mConfiguration, getCommonServicesLocked()); updateLRUListLocked(app, false); app.lastRequestedGc = SystemClock.uptimeMillis(); } catch (Exception e) { @@ -5283,6 +5301,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } void enableScreenAfterBoot() { + EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN, + SystemClock.uptimeMillis()); mWindowManager.enableScreenAfterBoot(); } @@ -5393,26 +5413,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } if (booting) { - // Ensure that any processes we had put on hold are now started - // up. - final int NP = mProcessesOnHold.size(); - if (NP > 0) { - ArrayList<ProcessRecord> procs = - new ArrayList<ProcessRecord>(mProcessesOnHold); - for (int ip=0; ip<NP; ip++) { - this.startProcessLocked(procs.get(ip), "on-hold", null); - } - } - if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) { - // Tell anyone interested that we are done booting! - synchronized (this) { - broadcastIntentLocked(null, null, - new Intent(Intent.ACTION_BOOT_COMPLETED, null), - null, null, 0, null, null, - android.Manifest.permission.RECEIVE_BOOT_COMPLETED, - false, false, MY_PID, Process.SYSTEM_UID); - } - } + finishBooting(); } trimApplications(); @@ -5420,22 +5421,48 @@ public final class ActivityManagerService extends ActivityManagerNative implemen //mWindowManager.dump(); if (enableScreen) { - EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN, - SystemClock.uptimeMillis()); enableScreenAfterBoot(); } } - final void ensureScreenEnabled() { + final void finishBooting() { + // Ensure that any processes we had put on hold are now started + // up. + final int NP = mProcessesOnHold.size(); + if (NP > 0) { + ArrayList<ProcessRecord> procs = + new ArrayList<ProcessRecord>(mProcessesOnHold); + for (int ip=0; ip<NP; ip++) { + this.startProcessLocked(procs.get(ip), "on-hold", null); + } + } + if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) { + // Tell anyone interested that we are done booting! + synchronized (this) { + broadcastIntentLocked(null, null, + new Intent(Intent.ACTION_BOOT_COMPLETED, null), + null, null, 0, null, null, + android.Manifest.permission.RECEIVE_BOOT_COMPLETED, + false, false, MY_PID, Process.SYSTEM_UID); + } + } + } + + final void ensureBootCompleted() { + boolean booting; boolean enableScreen; synchronized (this) { + booting = mBooting; + mBooting = false; enableScreen = !mBooted; mBooted = true; } + + if (booting) { + finishBooting(); + } if (enableScreen) { - EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN, - SystemClock.uptimeMillis()); enableScreenAfterBoot(); } } @@ -5587,6 +5614,13 @@ public final class ActivityManagerService extends ActivityManagerNative implemen throw new IllegalArgumentException("File descriptors passed in Intent"); } + if (type == INTENT_SENDER_BROADCAST) { + if ((intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) { + throw new IllegalArgumentException( + "Can't use FLAG_RECEIVER_BOOT_UPGRADE here"); + } + } + synchronized(this) { int callingUid = Binder.getCallingUid(); try { @@ -7397,7 +7431,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen ProcessRecord proc = startProcessLocked(cpi.processName, cpr.appInfo, false, 0, "content provider", new ComponentName(cpi.applicationInfo.packageName, - cpi.name)); + cpi.name), false); if (proc == null) { Log.w(TAG, "Unable to launch app " + cpi.applicationInfo.packageName + "/" @@ -8124,17 +8158,93 @@ public final class ActivityManagerService extends ActivityManagerNative implemen if (mSystemReady) { return; } + + // Check to see if there are any update receivers to run. + if (!mDidUpdate) { + if (mWaitingUpdate) { + return; + } + Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED); + List<ResolveInfo> ris = null; + try { + ris = ActivityThread.getPackageManager().queryIntentReceivers( + intent, null, 0); + } catch (RemoteException e) { + } + if (ris != null) { + for (int i=ris.size()-1; i>=0; i--) { + if ((ris.get(i).activityInfo.applicationInfo.flags + &ApplicationInfo.FLAG_SYSTEM) == 0) { + ris.remove(i); + } + } + intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE); + for (int i=0; i<ris.size(); i++) { + ActivityInfo ai = ris.get(i).activityInfo; + intent.setComponent(new ComponentName(ai.packageName, ai.name)); + IIntentReceiver finisher = null; + if (i == 0) { + finisher = new IIntentReceiver.Stub() { + public void performReceive(Intent intent, int resultCode, + String data, Bundle extras, boolean ordered) + throws RemoteException { + synchronized (ActivityManagerService.this) { + mDidUpdate = true; + } + systemReady(); + } + }; + } + Log.i(TAG, "Sending system update to: " + intent.getComponent()); + broadcastIntentLocked(null, null, intent, null, finisher, + 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID); + if (i == 0) { + mWaitingUpdate = true; + } + } + } + if (mWaitingUpdate) { + return; + } + mDidUpdate = true; + } + mSystemReady = true; if (!mStartRunning) { return; } } + ArrayList<ProcessRecord> procsToKill = null; + synchronized(mPidsSelfLocked) { + for (int i=mPidsSelfLocked.size()-1; i>=0; i--) { + ProcessRecord proc = mPidsSelfLocked.valueAt(i); + if (!isAllowedWhileBooting(proc.info)){ + if (procsToKill == null) { + procsToKill = new ArrayList<ProcessRecord>(); + } + procsToKill.add(proc); + } + } + } + + if (procsToKill != null) { + synchronized(this) { + for (int i=procsToKill.size()-1; i>=0; i--) { + ProcessRecord proc = procsToKill.get(i); + Log.i(TAG, "Removing system update proc: " + proc); + removeProcessLocked(proc, true); + } + } + } + if (Config.LOGD) Log.d(TAG, "Start running!"); EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY, SystemClock.uptimeMillis()); synchronized(this) { + // Make sure we have no pre-ready processes sitting around. + if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) { ResolveInfo ri = mContext.getPackageManager() .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST), @@ -8192,6 +8302,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } + // Start up initial activity. + mBooting = true; + try { if (ActivityThread.getPackageManager().hasSystemUidErrors()) { Message msg = Message.obtain(); @@ -8201,8 +8314,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } catch (RemoteException e) { } - // Start up initial activity. - mBooting = true; resumeTopActivityLocked(null); } } @@ -9385,7 +9496,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen sr.app = null; sr.executeNesting = 0; mStoppingServices.remove(sr); - if (sr.bindings.size() > 0) { + + boolean hasClients = sr.bindings.size() > 0; + if (hasClients) { Iterator<IntentBindRecord> bindings = sr.bindings.values().iterator(); while (bindings.hasNext()) { @@ -9406,7 +9519,20 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } else if (!allowRestart) { bringDownServiceLocked(sr, true); } else { - scheduleServiceRestartLocked(sr); + boolean canceled = scheduleServiceRestartLocked(sr, true); + + // Should the service remain running? Note that in the + // extreme case of so many attempts to deliver a command + // that it failed, that we also will stop it here. + if (sr.startRequested && (sr.stopIfKilled || canceled)) { + if (sr.pendingStarts.size() == 0) { + sr.startRequested = false; + if (!hasClients) { + // Whoops, no reason to restart! + bringDownServiceLocked(sr, true); + } + } + } } } @@ -9845,35 +9971,55 @@ public final class ActivityManagerService extends ActivityManagerNative implemen private final void sendServiceArgsLocked(ServiceRecord r, boolean oomAdjusted) { - final int N = r.startArgs.size(); + final int N = r.pendingStarts.size(); if (N == 0) { return; } - final int BASEID = r.lastStartId - N + 1; int i = 0; while (i < N) { try { - Intent args = r.startArgs.get(i); + ServiceRecord.StartItem si = r.pendingStarts.get(i); if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: " - + r.name + " " + r.intent + " args=" + args); + + r.name + " " + r.intent + " args=" + si.intent); + if (si.intent == null && N > 0) { + // If somehow we got a dummy start at the front, then + // just drop it here. + i++; + continue; + } bumpServiceExecutingLocked(r); if (!oomAdjusted) { oomAdjusted = true; updateOomAdjLocked(r.app); } - r.app.thread.scheduleServiceArgs(r, BASEID+i, args); + int flags = 0; + if (si.deliveryCount > 0) { + flags |= Service.START_FLAG_RETRY; + } + if (si.doneExecutingCount > 0) { + flags |= Service.START_FLAG_REDELIVERY; + } + r.app.thread.scheduleServiceArgs(r, si.id, flags, si.intent); + si.deliveredTime = SystemClock.uptimeMillis(); + r.deliveredStarts.add(si); + si.deliveryCount++; i++; + } catch (RemoteException e) { + // Remote process gone... we'll let the normal cleanup take + // care of this. + break; } catch (Exception e) { + Log.w(TAG, "Unexpected exception", e); break; } } if (i == N) { - r.startArgs.clear(); + r.pendingStarts.clear(); } else { while (i > 0) { - r.startArgs.remove(0); i--; + r.pendingStarts.remove(i); } } } @@ -9942,19 +10088,61 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } finally { if (!created) { app.services.remove(r); - scheduleServiceRestartLocked(r); + scheduleServiceRestartLocked(r, false); } } requestServiceBindingsLocked(r); + + // If the service is in the started state, and there are no + // pending arguments, then fake up one so its onStartCommand() will + // be called. + if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) { + r.lastStartId++; + if (r.lastStartId < 1) { + r.lastStartId = 1; + } + r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, null)); + } + sendServiceArgsLocked(r, true); } - private final void scheduleServiceRestartLocked(ServiceRecord r) { + private final boolean scheduleServiceRestartLocked(ServiceRecord r, + boolean allowCancel) { + boolean canceled = false; + + long minDuration = SERVICE_RESTART_DURATION; + long resetTime = minDuration*2*2*2; + + // Any delivered but not yet finished starts should be put back + // on the pending list. + final int N = r.deliveredStarts.size(); + if (N > 0) { + for (int i=N-1; i>=0; i--) { + ServiceRecord.StartItem si = r.deliveredStarts.get(i); + if (si.intent == null) { + // We'll generate this again if needed. + } else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT + && si.doneExecutingCount < ServiceRecord.MAX_DONE_EXECUTING_COUNT)) { + r.pendingStarts.add(0, si); + long dur = SystemClock.uptimeMillis() - si.deliveredTime; + dur *= 2; + if (minDuration < dur) minDuration = dur; + if (resetTime < dur) resetTime = dur; + } else { + Log.w(TAG, "Canceling start item " + si.intent + " in service " + + r.name); + canceled = true; + } + } + r.deliveredStarts.clear(); + } + r.totalRestartCount++; if (r.restartDelay == 0) { r.restartCount++; - r.restartDelay = SERVICE_RESTART_DURATION; + r.restartDelay = minDuration; } else { // If it has been a "reasonably long time" since the service // was started, then reset our restart duration back to @@ -9962,17 +10150,21 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // on a service that just occasionally gets killed (which is // a normal case, due to process being killed to reclaim memory). long now = SystemClock.uptimeMillis(); - if (now > (r.restartTime+(SERVICE_RESTART_DURATION*2*2*2))) { + if (now > (r.restartTime+resetTime)) { r.restartCount = 1; - r.restartDelay = SERVICE_RESTART_DURATION; + r.restartDelay = minDuration; } else { - r.restartDelay *= 2; + r.restartDelay *= 4; + if (r.restartDelay < minDuration) { + r.restartDelay = minDuration; + } } } if (!mRestartingServices.contains(r)) { mRestartingServices.add(r); } r.cancelNotification(); + mHandler.removeCallbacks(r.restarter); mHandler.postDelayed(r.restarter, r.restartDelay); r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay; @@ -9985,6 +10177,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen msg.what = SERVICE_ERROR_MSG; msg.obj = r; mHandler.sendMessage(msg); + + return canceled; } final void performServiceRestartLocked(ServiceRecord r) { @@ -10044,7 +10238,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // Not running -- get it started, and enqueue this service record // to be executed when the app comes up. if (startProcessLocked(appName, r.appInfo, true, intentFlags, - "service", r.name) == null) { + "service", r.name, false) == null) { Log.w(TAG, "Unable to launch app " + r.appInfo.packageName + "/" + r.appInfo.uid + " for service " @@ -10146,6 +10340,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen r.foregroundId = 0; r.foregroundNoti = null; + // Clear start entries. + r.deliveredStarts.clear(); + r.pendingStarts.clear(); + if (r.app != null) { synchronized (r.stats.getBatteryStats()) { r.stats.stopLaunchedLocked(); @@ -10207,11 +10405,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen + r.shortName); } r.startRequested = true; - r.startArgs.add(service); + r.callStart = false; r.lastStartId++; if (r.lastStartId < 1) { r.lastStartId = 1; } + r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, service)); r.lastActivity = SystemClock.uptimeMillis(); synchronized (r.stats.getBatteryStats()) { r.stats.startRunningLocked(); @@ -10279,6 +10478,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen r.record.stats.stopRunningLocked(); } r.record.startRequested = false; + r.record.callStart = false; final long origId = Binder.clearCallingIdentity(); bringDownServiceLocked(r.record, false); Binder.restoreCallingIdentity(origId); @@ -10327,10 +10527,35 @@ public final class ActivityManagerService extends ActivityManagerNative implemen if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className + " " + token + " startId=" + startId); ServiceRecord r = findServiceLocked(className, token); - if (r != null && (startId < 0 || r.lastStartId == startId)) { + if (r != null) { + if (startId >= 0) { + // Asked to only stop if done with all work. Note that + // to avoid leaks, we will take this as dropping all + // start items up to and including this one. + ServiceRecord.StartItem si = r.findDeliveredStart(startId, false); + if (si != null) { + while (r.deliveredStarts.size() > 0) { + if (r.deliveredStarts.remove(0) == si) { + break; + } + } + } + + if (r.lastStartId != startId) { + return false; + } + + if (r.deliveredStarts.size() > 0) { + Log.w(TAG, "stopServiceToken startId " + startId + + " is last, but have " + r.deliveredStarts.size() + + " remaining args"); + } + } + synchronized (r.stats.getBatteryStats()) { r.stats.stopRunningLocked(); r.startRequested = false; + r.callStart = false; } final long origId = Binder.clearCallingIdentity(); bringDownServiceLocked(r, false); @@ -10674,7 +10899,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } - public void serviceDoneExecuting(IBinder token) { + public void serviceDoneExecuting(IBinder token, int type, int startId, int res) { synchronized(this) { if (!(token instanceof ServiceRecord)) { throw new IllegalArgumentException("Invalid service token"); @@ -10692,6 +10917,51 @@ public final class ActivityManagerService extends ActivityManagerNative implemen return; } + if (type == 1) { + // This is a call from a service start... take care of + // book-keeping. + r.callStart = true; + switch (res) { + case Service.START_STICKY_COMPATIBILITY: + case Service.START_STICKY: { + // We are done with the associated start arguments. + r.findDeliveredStart(startId, true); + // Don't stop if killed. + r.stopIfKilled = false; + break; + } + case Service.START_NOT_STICKY: { + // We are done with the associated start arguments. + r.findDeliveredStart(startId, true); + if (r.lastStartId == startId) { + // There is no more work, and this service + // doesn't want to hang around if killed. + r.stopIfKilled = true; + } + break; + } + case Service.START_REDELIVER_INTENT: { + // We'll keep this item until they explicitly + // call stop for it, but keep track of the fact + // that it was delivered. + ServiceRecord.StartItem si = r.findDeliveredStart(startId, false); + if (si != null) { + si.deliveryCount = 0; + si.doneExecutingCount++; + // Don't stop if killed. + r.stopIfKilled = true; + } + break; + } + default: + throw new IllegalArgumentException( + "Unknown service start result: " + res); + } + if (res == Service.START_STICKY_COMPATIBILITY) { + r.callStart = false; + } + } + final long origId = Binder.clearCallingIdentity(); serviceDoneExecutingLocked(r, inStopping); Binder.restoreCallingIdentity(origId); @@ -10770,7 +11040,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName); // startProcessLocked() returns existing proc's record if it's already running ProcessRecord proc = startProcessLocked(app.processName, app, - false, 0, "backup", hostingName); + false, 0, "backup", hostingName, false); if (proc == null) { Log.e(TAG, "Unable to start backup agent process " + r); return false; @@ -11307,10 +11577,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } synchronized(this) { + int flags = intent.getFlags(); + if (!mSystemReady) { // if the caller really truly claims to know what they're doing, go // ahead and allow the broadcast without launching any receivers - int flags = intent.getFlags(); if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) { intent = new Intent(intent); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); @@ -11321,6 +11592,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } + if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) { + throw new IllegalArgumentException( + "Can't use FLAG_RECEIVER_BOOT_UPGRADE here"); + } + final ProcessRecord callerApp = getRecordForAppLocked(caller); final int callingPid = Binder.getCallingPid(); final int callingUid = Binder.getCallingUid(); @@ -11915,12 +12191,13 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // restart the application. } - // Not running -- get it started, and enqueue this history record - // to be executed when the app comes up. + // Not running -- get it started, to be executed when the app comes up. if ((r.curApp=startProcessLocked(targetProcess, info.activityInfo.applicationInfo, true, r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND, - "broadcast", r.curComponent)) == null) { + "broadcast", r.curComponent, + (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0)) + == null) { // Ah, this recipient is unavailable. Finish it if necessary, // and mark the broadcast record as ready for the next. Log.w(TAG, "Unable to launch app " diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java index 9318a72..afbf9c7 100644 --- a/services/java/com/android/server/am/ServiceRecord.java +++ b/services/java/com/android/server/am/ServiceRecord.java @@ -64,7 +64,28 @@ class ServiceRecord extends Binder { final HashMap<IBinder, ConnectionRecord> connections = new HashMap<IBinder, ConnectionRecord>(); // IBinder -> ConnectionRecord of all bound clients - final List<Intent> startArgs = new ArrayList<Intent>(); + + // Maximum number of delivery attempts before giving up. + static final int MAX_DELIVERY_COUNT = 3; + + // Maximum number of times it can fail during execution before giving up. + static final int MAX_DONE_EXECUTING_COUNT = 6; + + static class StartItem { + final int id; + final Intent intent; + long deliveredTime; + int deliveryCount; + int doneExecutingCount; + + StartItem(int _id, Intent _intent) { + id = _id; + intent = _intent; + } + } + final ArrayList<StartItem> deliveredStarts = new ArrayList<StartItem>(); + // start() arguments which been delivered. + final ArrayList<StartItem> pendingStarts = new ArrayList<StartItem>(); // start() arguments that haven't yet been delivered. ProcessRecord app; // where this service is running or null. @@ -73,6 +94,8 @@ class ServiceRecord extends Binder { Notification foregroundNoti; // Notification record of foreground state. long lastActivity; // last time there was some activity on the service. boolean startRequested; // someone explicitly called start? + boolean stopIfKilled; // last onStart() said to stop if service killed? + boolean callStart; // last onStart() has asked to alway be called on restart. int lastStartId; // identifier of most recent start request. int executeNesting; // number of outstanding operations keeping foreground. long executingStart; // start time of last execute request. @@ -85,6 +108,25 @@ class ServiceRecord extends Binder { String stringName; // caching of toString + void dumpStartList(PrintWriter pw, String prefix, List<StartItem> list, long now) { + final int N = list.size(); + for (int i=0; i<N; i++) { + StartItem si = list.get(i); + pw.print(prefix); pw.print("#"); pw.print(i); + pw.print(" id="); pw.print(si.id); + if (now != 0) pw.print(" dur="); pw.print(now-si.deliveredTime); + if (si.deliveryCount != 0) { + pw.print(" dc="); pw.print(si.deliveryCount); + } + if (si.doneExecutingCount != 0) { + pw.print(" dxc="); pw.print(si.doneExecutingCount); + } + pw.print(" "); + if (si.intent != null) pw.println(si.intent.toString()); + else pw.println("null"); + } + } + void dump(PrintWriter pw, String prefix) { pw.print(prefix); pw.print("intent={"); pw.print(intent.getIntent().toShortString(true, false)); @@ -108,6 +150,8 @@ class ServiceRecord extends Binder { pw.print(" restartTime="); pw.println(restartTime); if (startRequested || lastStartId != 0) { pw.print(prefix); pw.print("startRequested="); pw.print(startRequested); + pw.print(" stopIfKilled="); pw.print(stopIfKilled); + pw.print(" callStart="); pw.print(callStart); pw.print(" lastStartId="); pw.println(lastStartId); } if (executeNesting != 0 || crashCount != 0 || restartCount != 0 @@ -118,8 +162,17 @@ class ServiceRecord extends Binder { pw.print(" nextRestartTime="); pw.print(nextRestartTime); pw.print(" crashCount="); pw.println(crashCount); } + if (deliveredStarts.size() > 0) { + pw.print(prefix); pw.println("Delivered Starts:"); + dumpStartList(pw, prefix, deliveredStarts, SystemClock.uptimeMillis()); + } + if (pendingStarts.size() > 0) { + pw.print(prefix); pw.println("Pending Starts:"); + dumpStartList(pw, prefix, pendingStarts, 0); + } if (bindings.size() > 0) { Iterator<IntentBindRecord> it = bindings.values().iterator(); + pw.print(prefix); pw.println("Bindings:"); while (it.hasNext()) { IntentBindRecord b = it.next(); pw.print(prefix); pw.print("* IntentBindRecord{"); @@ -180,6 +233,19 @@ class ServiceRecord extends Binder { restartTime = 0; } + public StartItem findDeliveredStart(int id, boolean remove) { + final int N = deliveredStarts.size(); + for (int i=0; i<N; i++) { + StartItem si = deliveredStarts.get(i); + if (si.id == id) { + if (remove) deliveredStarts.remove(i); + return si; + } + } + + return null; + } + public void postNotification() { if (foregroundId != 0 && foregroundNoti != null) { INotificationManager inm = NotificationManager.getService(); diff --git a/services/java/com/android/server/status/StatusBarPolicy.java b/services/java/com/android/server/status/StatusBarPolicy.java index c6b085d..10680dd 100644 --- a/services/java/com/android/server/status/StatusBarPolicy.java +++ b/services/java/com/android/server/status/StatusBarPolicy.java @@ -105,11 +105,9 @@ public class StatusBarPolicy { // phone private TelephonyManager mPhone; private IBinder mPhoneIcon; - private IBinder mPhoneEvdoIcon; //***** Signal strength icons private IconData mPhoneData; - private IconData mPhoneEvdoData; //GSM/UMTS private static final int[] sSignalImages = new int[] { com.android.internal.R.drawable.stat_sys_signal_0, @@ -125,14 +123,6 @@ public class StatusBarPolicy { com.android.internal.R.drawable.stat_sys_r_signal_3, com.android.internal.R.drawable.stat_sys_r_signal_4 }; - //CDMA - private static final int[] sSignalImages_cdma = new int[] { - com.android.internal.R.drawable.stat_sys_signal_cdma_0, - com.android.internal.R.drawable.stat_sys_signal_cdma_1, - com.android.internal.R.drawable.stat_sys_signal_cdma_2, - com.android.internal.R.drawable.stat_sys_signal_cdma_3, - com.android.internal.R.drawable.stat_sys_signal_cdma_4 - }; private static final int[] sRoamingIndicatorImages_cdma = new int[] { com.android.internal.R.drawable.stat_sys_roaming_cdma_0, //Standard Roaming Indicator // 1 is Standard Roaming Indicator OFF @@ -232,14 +222,6 @@ public class StatusBarPolicy { // 128-255 Reserved }; - // EVDO - private static final int[] sSignalImages_evdo = new int[] { - com.android.internal.R.drawable.stat_sys_signal_evdo_0, - com.android.internal.R.drawable.stat_sys_signal_evdo_1, - com.android.internal.R.drawable.stat_sys_signal_evdo_2, - com.android.internal.R.drawable.stat_sys_signal_evdo_3, - com.android.internal.R.drawable.stat_sys_signal_evdo_4 - }; //***** Data connection icons private int[] mDataIconList = sDataNetType_g; @@ -271,19 +253,12 @@ public class StatusBarPolicy { }; //CDMA - private static final int[] sDataNetType_evdo = new int[] { - com.android.internal.R.drawable.stat_sys_data_connected_evdo, - com.android.internal.R.drawable.stat_sys_data_in_evdo, - com.android.internal.R.drawable.stat_sys_data_out_evdo, - com.android.internal.R.drawable.stat_sys_data_inandout_evdo, - com.android.internal.R.drawable.stat_sys_data_dormant_evdo, - }; - private static final int[] sDataNetType_1xrtt = new int[] { - com.android.internal.R.drawable.stat_sys_data_connected_1xrtt, - com.android.internal.R.drawable.stat_sys_data_in_1xrtt, - com.android.internal.R.drawable.stat_sys_data_out_1xrtt, - com.android.internal.R.drawable.stat_sys_data_inandout_1xrtt, - com.android.internal.R.drawable.stat_sys_data_dormant_1xrtt, + // Use 3G icons for EVDO data and 1x icons for 1XRTT data + private static final int[] sDataNetType_1x = new int[] { + com.android.internal.R.drawable.stat_sys_data_connected_1x, + com.android.internal.R.drawable.stat_sys_data_in_1x, + com.android.internal.R.drawable.stat_sys_data_out_1x, + com.android.internal.R.drawable.stat_sys_data_inandout_1x, }; // Assume it's all good unless we hear otherwise. We don't always seem @@ -438,12 +413,6 @@ public class StatusBarPolicy { null, com.android.internal.R.drawable.stat_sys_signal_null, 0, 0); mPhoneIcon = service.addIcon(mPhoneData, null); - // phone_evdo_signal - mPhoneEvdoData = IconData.makeIcon("phone_evdo_signal", - null, com.android.internal.R.drawable.stat_sys_signal_evdo_0, 0, 0); - mPhoneEvdoIcon = service.addIcon(mPhoneEvdoData, null); - service.setIconVisibility(mPhoneEvdoIcon, false); - // register for phone state notifications. ((TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE)) .listen(mPhoneStateListener, @@ -499,7 +468,7 @@ public class StatusBarPolicy { mGpsFixIconData = IconData.makeIcon("gps", null, com.android.internal.R.drawable.stat_sys_gps_on, 0, 0); mGpsIcon = service.addIcon(mGpsEnabledIconData, null); - service.setIconVisibility(mGpsIcon, false); + service.setIconVisibility(mGpsIcon, false); // Alarm clock mAlarmClockIconData = IconData.makeIcon( @@ -522,7 +491,7 @@ public class StatusBarPolicy { mVolumeIcon = service.addIcon(mVolumeData, null); service.setIconVisibility(mVolumeIcon, false); updateVolume(); - + IntentFilter filter = new IntentFilter(); // Register for Intent broadcasts for... @@ -642,7 +611,7 @@ public class StatusBarPolicy { } } - private void showBatteryView() { + private void showBatteryView() { closeLastBatteryView(); if (mLowBatteryDialog != null) { mLowBatteryDialog.dismiss(); @@ -723,7 +692,7 @@ public class StatusBarPolicy { b.setView(v); b.setIcon(android.R.drawable.ic_dialog_alert); b.setPositiveButton(android.R.string.ok, null); - + final Intent intent = new Intent(Intent.ACTION_POWER_USAGE_SUMMARY); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK @@ -811,6 +780,10 @@ public class StatusBarPolicy { @Override public void onCallStateChanged(int state, String incomingNumber) { updateCallState(state); + // In cdma, if a voice call is made, RSSI should switch to 1x. + if (isCdma()) { + updateSignalStrength(); + } } @Override @@ -839,7 +812,7 @@ public class StatusBarPolicy { final String lockedReason = intent.getStringExtra(IccCard.INTENT_KEY_LOCKED_REASON); if (IccCard.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) { mSimState = IccCard.State.PIN_REQUIRED; - } + } else if (IccCard.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) { mSimState = IccCard.State.PUK_REQUIRED; } @@ -856,6 +829,14 @@ public class StatusBarPolicy { return ((mPhone != null) && (mPhone.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA)); } + private boolean isEvdo() { + return ( (mServiceState != null) + && ((mServiceState.getRadioTechnology() + == ServiceState.RADIO_TECHNOLOGY_EVDO_0) + || (mServiceState.getRadioTechnology() + == ServiceState.RADIO_TECHNOLOGY_EVDO_A))); + } + private boolean hasService() { if (mServiceState != null) { switch (mServiceState.getState()) { @@ -872,9 +853,7 @@ public class StatusBarPolicy { private final void updateSignalStrength() { int iconLevel = -1; - int evdoIconLevel = -1; int[] iconList; - int[] evdoIconList; if (!hasService()) { //Log.d(TAG, "updateSignalStrength: no service"); @@ -885,7 +864,6 @@ public class StatusBarPolicy { mPhoneData.iconId = com.android.internal.R.drawable.stat_sys_signal_null; } mService.updateIcon(mPhoneIcon, mPhoneData, null); - mService.setIconVisibility(mPhoneEvdoIcon,false); return; } @@ -908,64 +886,67 @@ public class StatusBarPolicy { iconList = sSignalImages; } } else { - iconList = this.sSignalImages_cdma; - - int cdmaDbm = mSignalStrength.getCdmaDbm(); - int cdmaEcio = mSignalStrength.getCdmaEcio(); - int levelDbm = 0; - int levelEcio = 0; - - if (cdmaDbm >= -75) levelDbm = 4; - else if (cdmaDbm >= -85) levelDbm = 3; - else if (cdmaDbm >= -95) levelDbm = 2; - else if (cdmaDbm >= -100) levelDbm = 1; - else levelDbm = 0; - - // Ec/Io are in dB*10 - if (cdmaEcio >= -90) levelEcio = 4; - else if (cdmaEcio >= -110) levelEcio = 3; - else if (cdmaEcio >= -130) levelEcio = 2; - else if (cdmaEcio >= -150) levelEcio = 1; - else levelEcio = 0; - - iconLevel = (levelDbm < levelEcio) ? levelDbm : levelEcio; - } - - if ((mServiceState.getRadioTechnology() == ServiceState.RADIO_TECHNOLOGY_EVDO_0) - || (mServiceState.getRadioTechnology() == ServiceState.RADIO_TECHNOLOGY_EVDO_A)) { - // Use Evdo icon - evdoIconList = this.sSignalImages_evdo; - - int evdoDbm = mSignalStrength.getEvdoDbm(); - int evdoSnr = mSignalStrength.getEvdoSnr(); - int levelEvdoDbm = 0; - int levelEvdoSnr = 0; - - if (evdoDbm >= -65) levelEvdoDbm = 4; - else if (evdoDbm >= -75) levelEvdoDbm = 3; - else if (evdoDbm >= -90) levelEvdoDbm = 2; - else if (evdoDbm >= -105) levelEvdoDbm = 1; - else levelEvdoDbm = 0; - - if (evdoSnr > 7) levelEvdoSnr = 4; - else if (evdoSnr > 5) levelEvdoSnr = 3; - else if (evdoSnr > 3) levelEvdoSnr = 2; - else if (evdoSnr > 1) levelEvdoSnr = 1; - else levelEvdoSnr = 0; - - evdoIconLevel = (levelEvdoDbm < levelEvdoSnr) ? levelEvdoDbm : levelEvdoSnr; - - mPhoneEvdoData.iconId = evdoIconList[evdoIconLevel]; - mService.updateIcon(mPhoneEvdoIcon, mPhoneEvdoData, null); - mService.setIconVisibility(mPhoneEvdoIcon,true); - } else { - mService.setIconVisibility(mPhoneEvdoIcon,false); + iconList = this.sSignalImages; + + // If 3G(EV) and 1x network are available than 3G should be + // displayed, displayed RSSI should be from the EV side. + // If a voice call is made then RSSI should switch to 1x. + if ((mPhoneState == TelephonyManager.CALL_STATE_IDLE) && isEvdo()){ + iconLevel = getEvdoLevel(); + if (false) { + Log.d(TAG, "use Evdo level=" + iconLevel + " to replace Cdma Level=" + getCdmaLevel()); + } + } else { + iconLevel = getCdmaLevel(); + } } - mPhoneData.iconId = iconList[iconLevel]; mService.updateIcon(mPhoneIcon, mPhoneData, null); } + private int getCdmaLevel() { + final int cdmaDbm = mSignalStrength.getCdmaDbm(); + final int cdmaEcio = mSignalStrength.getCdmaEcio(); + int levelDbm = 0; + int levelEcio = 0; + + if (cdmaDbm >= -75) levelDbm = 4; + else if (cdmaDbm >= -85) levelDbm = 3; + else if (cdmaDbm >= -95) levelDbm = 2; + else if (cdmaDbm >= -100) levelDbm = 1; + else levelDbm = 0; + + // Ec/Io are in dB*10 + if (cdmaEcio >= -90) levelEcio = 4; + else if (cdmaEcio >= -110) levelEcio = 3; + else if (cdmaEcio >= -130) levelEcio = 2; + else if (cdmaEcio >= -150) levelEcio = 1; + else levelEcio = 0; + + return (levelDbm < levelEcio) ? levelDbm : levelEcio; + } + + private int getEvdoLevel() { + int evdoDbm = mSignalStrength.getEvdoDbm(); + int evdoSnr = mSignalStrength.getEvdoSnr(); + int levelEvdoDbm = 0; + int levelEvdoSnr = 0; + + if (evdoDbm >= -65) levelEvdoDbm = 4; + else if (evdoDbm >= -75) levelEvdoDbm = 3; + else if (evdoDbm >= -90) levelEvdoDbm = 2; + else if (evdoDbm >= -105) levelEvdoDbm = 1; + else levelEvdoDbm = 0; + + if (evdoSnr > 7) levelEvdoSnr = 4; + else if (evdoSnr > 5) levelEvdoSnr = 3; + else if (evdoSnr > 3) levelEvdoSnr = 2; + else if (evdoSnr > 1) levelEvdoSnr = 1; + else levelEvdoSnr = 0; + + return (levelEvdoDbm < levelEvdoSnr) ? levelEvdoDbm : levelEvdoSnr; + } + private final void updateDataNetType() { int net = mPhone.getNetworkType(); @@ -983,14 +964,14 @@ public class StatusBarPolicy { break; case TelephonyManager.NETWORK_TYPE_CDMA: // display 1xRTT for IS95A/B - mDataIconList = this.sDataNetType_1xrtt; + mDataIconList = this.sDataNetType_1x; break; case TelephonyManager.NETWORK_TYPE_1xRTT: - mDataIconList = this.sDataNetType_1xrtt; + mDataIconList = this.sDataNetType_1x; break; case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through case TelephonyManager.NETWORK_TYPE_EVDO_A: - mDataIconList = sDataNetType_evdo; + mDataIconList = sDataNetType_3g; break; default: mDataIconList = sDataNetType_g; @@ -1043,8 +1024,6 @@ public class StatusBarPolicy { iconId = mDataIconList[3]; break; case TelephonyManager.DATA_ACTIVITY_DORMANT: - iconId = mDataIconList[4]; - break; default: iconId = mDataIconList[0]; break; diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java index e113680..73e7baa5 100644 --- a/telephony/java/android/telephony/PhoneStateListener.java +++ b/telephony/java/android/telephony/PhoneStateListener.java @@ -154,8 +154,9 @@ public class PhoneStateListener { * @see ServiceState#STATE_IN_SERVICE * @see ServiceState#STATE_OUT_OF_SERVICE * @see ServiceState#STATE_POWER_OFF - * @deprecated, @see #onSignalStrengthsChanged + * @deprecated see #onSignalStrengthsChanged */ + @Deprecated public void onSignalStrengthChanged(int asu) { // default implementation empty } diff --git a/telephony/java/android/telephony/gsm/SmsMessage.java b/telephony/java/android/telephony/gsm/SmsMessage.java index 84dfca0..37ef912 100644 --- a/telephony/java/android/telephony/gsm/SmsMessage.java +++ b/telephony/java/android/telephony/gsm/SmsMessage.java @@ -345,6 +345,7 @@ public class SmsMessage { * the number of code units used, and int[2] is the number of code * units remaining until the next message. int[3] is the encoding * type that should be used for the message. + * @deprecated Use android.telephony.SmsMessage. */ @Deprecated public static int[] calculateLength(String messageBody, boolean use7bitOnly) { diff --git a/telephony/java/com/android/internal/telephony/CommandsInterface.java b/telephony/java/com/android/internal/telephony/CommandsInterface.java index 6ebd8d6..ed8bc1e 100644 --- a/telephony/java/com/android/internal/telephony/CommandsInterface.java +++ b/telephony/java/com/android/internal/telephony/CommandsInterface.java @@ -607,8 +607,9 @@ public interface CommandsInterface { * ar.exception carries exception on failure * ar.userObject contains the orignal value of result.obj * ar.result contains a List of DataCallState - * @deprecated + * @deprecated Do not use. */ + @Deprecated void getPDPContextList(Message result); /** @@ -779,8 +780,9 @@ public interface CommandsInterface { * cause code returned as int[0] in Message.obj.response * returns an integer cause code defined in TS 24.008 * section 6.1.3.1.3 or close approximation - * @deprecated + * @deprecated Do not use. */ + @Deprecated void getLastPdpFailCause (Message result); /** diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java index e187c37..cfb465e 100644 --- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java @@ -453,7 +453,8 @@ public abstract class DataConnectionTracker extends Handler { } protected synchronized void setEnabled(int id, boolean enable) { - if (DBG) Log.d(LOG_TAG, "setEnabled(" + id + ", " + enable + ')'); + if (DBG) Log.d(LOG_TAG, "setEnabled(" + id + ", " + enable + ") with old state = " + + dataEnabled[id] + " and enabledCount = " + enabledCount); if (dataEnabled[id] != enable) { dataEnabled[id] = enable; diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java index 04a3749..9edb4c2 100644 --- a/telephony/java/com/android/internal/telephony/PhoneBase.java +++ b/telephony/java/com/android/internal/telephony/PhoneBase.java @@ -618,7 +618,7 @@ public abstract class PhoneBase implements Phone { * This should only be called in GSM mode. * Only here for some backward compatibility * issues concerning the GSMPhone class. - * @deprecated + * @deprecated Always returns null. */ public List<PdpConnection> getCurrentPdpList() { return null; diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java index bb04a43..3c1308b 100755 --- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java +++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java @@ -1084,8 +1084,9 @@ public class GSMPhone extends PhoneBase { } /** - * @deprecated + * @deprecated Do not use. */ + @Deprecated public void getPdpContextList(Message response) { getDataCallList(response); } @@ -1095,8 +1096,9 @@ public class GSMPhone extends PhoneBase { } /** - * @deprecated + * @deprecated Do not use. */ + @Deprecated public List<PdpConnection> getCurrentPdpList() { ArrayList<DataConnection> connections = new ArrayList<DataConnection>(); ArrayList<PdpConnection> pdp_list = new ArrayList<PdpConnection>(); diff --git a/test-runner/android/test/AndroidTestRunner.java b/test-runner/android/test/AndroidTestRunner.java index 0d4e1e9..358b7e9 100644 --- a/test-runner/android/test/AndroidTestRunner.java +++ b/test-runner/android/test/AndroidTestRunner.java @@ -180,14 +180,23 @@ public class AndroidTestRunner extends BaseTestRunner { private void setInstrumentationIfInstrumentationTestCase( Test test, Instrumentation instrumentation) { if (InstrumentationTestCase.class.isAssignableFrom(test.getClass())) { - ((InstrumentationTestCase) test).injectInsrumentation(instrumentation); + ((InstrumentationTestCase) test).injectInstrumentation(instrumentation); } } - public void setInstrumentaiton(Instrumentation instrumentation) { + public void setInstrumentation(Instrumentation instrumentation) { mInstrumentation = instrumentation; } + /** + * @deprecated Incorrect spelling, + * use {@link #setInstrumentation(android.app.Instrumentation)} instead. + */ + @Deprecated + public void setInstrumentaiton(Instrumentation instrumentation) { + setInstrumentation(instrumentation); + } + @Override protected Class loadSuiteClass(String suiteClassName) throws ClassNotFoundException { return mContext.getClassLoader().loadClass(suiteClassName); diff --git a/test-runner/android/test/InstrumentationTestRunner.java b/test-runner/android/test/InstrumentationTestRunner.java index 6658fb0..23f0ed4 100644 --- a/test-runner/android/test/InstrumentationTestRunner.java +++ b/test-runner/android/test/InstrumentationTestRunner.java @@ -329,7 +329,7 @@ public class InstrumentationTestRunner extends Instrumentation implements TestSu mTestRunner = getAndroidTestRunner(); mTestRunner.setContext(getTargetContext()); - mTestRunner.setInstrumentaiton(this); + mTestRunner.setInstrumentation(this); mTestRunner.setSkipExecution(logOnly); mTestRunner.setTest(testSuiteBuilder.build()); mTestCount = mTestRunner.getTestCases().size(); diff --git a/test-runner/android/test/ProviderTestCase.java b/test-runner/android/test/ProviderTestCase.java index 445b4eb..668e9f7 100644 --- a/test-runner/android/test/ProviderTestCase.java +++ b/test-runner/android/test/ProviderTestCase.java @@ -15,6 +15,7 @@ import android.database.DatabaseUtils; * @deprecated this class extends InstrumentationTestCase but should extend AndroidTestCase. Use * ProviderTestCase2, which corrects this problem, instead. */ +@Deprecated public abstract class ProviderTestCase<T extends ContentProvider> extends InstrumentationTestCase { diff --git a/test-runner/android/test/TouchUtils.java b/test-runner/android/test/TouchUtils.java index 52d2ee8..962b2f9 100644 --- a/test-runner/android/test/TouchUtils.java +++ b/test-runner/android/test/TouchUtils.java @@ -565,6 +565,7 @@ public class TouchUtils { * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for * configuring the Activity under test */ + @Deprecated public static int dragViewBy(InstrumentationTestCase test, View v, int gravity, int deltaX, int deltaY) { int[] xy = new int[2]; diff --git a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardTests.java b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardTests.java index af5562a..7589ba8 100644 --- a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardTests.java +++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardTests.java @@ -19,11 +19,6 @@ package com.android.unit_tests.vcard; import android.content.ContentValues; import android.pim.vcard.ContactStruct; import android.pim.vcard.EntryHandler; -import android.pim.vcard.VCardBuilder; -import android.pim.vcard.VCardBuilderCollection; -import android.pim.vcard.VCardConfig; -import android.pim.vcard.VCardDataBuilder; -import android.pim.vcard.VCardParser; import android.pim.vcard.VCardParser_V21; import android.pim.vcard.VCardParser_V30; import android.pim.vcard.exception.VCardException; @@ -38,20 +33,21 @@ import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Map; public class VCardTests extends AndroidTestCase { // TODO: Use EntityIterator, which is added in Eclair. private static class EntryHolder implements EntryHandler { public List<ContactStruct> contacts = new ArrayList<ContactStruct>(); + public void onParsingStart() { + } public void onEntryCreated(ContactStruct contactStruct) { contacts.add(contactStruct); } - public void onFinal() { + public void onParsingEnd() { } } - + /* static void verify(ContactStruct expected, ContactStruct actual) { if (!equalsString(expected.getName(), actual.getName())) { fail(String.format("Names do not equal: \"%s\" != \"%s\"", @@ -128,7 +124,7 @@ public class VCardTests extends AndroidTestCase { } } } - } + }*/ private class PropertyNodesVerifier { private HashMap<String, ArrayList<PropertyNode>> mPropertyNodeMap; @@ -189,6 +185,7 @@ public class VCardTests extends AndroidTestCase { } } + /* public void testV21SimpleCase1_1() throws IOException, VCardException { VCardParser parser = new VCardParser_V21(); VCardDataBuilder builder = new VCardDataBuilder(VCardConfig.NAME_ORDER_TYPE_ENGLISH); @@ -260,7 +257,7 @@ public class VCardTests extends AndroidTestCase { verify(new ContactStruct("Ando Roid", null, null, null, null, null, null, null), actual); - } + }*/ public void testV21BackslashCase() throws IOException, VCardException { VCardParser_V21 parser = new VCardParser_V21(); diff --git a/libs/rs/java/Galaxy/Android.mk b/tests/BrowserTestPlugin/Android.mk index 0884e18..968d9e6 100644 --- a/libs/rs/java/Galaxy/Android.mk +++ b/tests/BrowserTestPlugin/Android.mk @@ -1,4 +1,3 @@ -# # Copyright (C) 2009 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,12 +13,24 @@ # limitations under the License. # -LOCAL_PATH := $(call my-dir) +TOP_LOCAL_PATH:= $(call my-dir) + +# Build application + +LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) -LOCAL_SRC_FILES := $(call all-java-files-under, src) -#LOCAL_STATIC_JAVA_LIBRARIES := android.renderscript +LOCAL_MODULE_TAGS := tests + +LOCAL_SRC_FILES := $(call all-subdir-java-files) -LOCAL_PACKAGE_NAME := GalaxyRS +LOCAL_PACKAGE_NAME := BrowserTestPlugin + +LOCAL_JNI_SHARED_LIBRARIES := libtestplugin include $(BUILD_PACKAGE) + +# ============================================================ + +# Also build all of the sub-targets under this one: the shared library. +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/tests/BrowserTestPlugin/AndroidManifest.xml b/tests/BrowserTestPlugin/AndroidManifest.xml new file mode 100644 index 0000000..f071ab6 --- /dev/null +++ b/tests/BrowserTestPlugin/AndroidManifest.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.testplugin" + android:versionCode="1" + android:versionName="1.0"> + + <uses-permission android:name="android.webkit.permission.PLUGIN"/> + + <uses-sdk android:minSdkVersion="3" /> + + <application android:icon="@drawable/browser_test_plugin" + android:label="Browser Test Plugin"> + <service android:name="TestPlugin"> + <intent-filter> + <action android:name="android.webkit.PLUGIN" /> + </intent-filter> + </service> + </application> + +</manifest> diff --git a/tests/BrowserTestPlugin/MODULE_LICENSE_APACHE2 b/tests/BrowserTestPlugin/MODULE_LICENSE_APACHE2 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/BrowserTestPlugin/MODULE_LICENSE_APACHE2 diff --git a/tests/BrowserTestPlugin/NOTICE b/tests/BrowserTestPlugin/NOTICE new file mode 100644 index 0000000..9df2554 --- /dev/null +++ b/tests/BrowserTestPlugin/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2005-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. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/tests/BrowserTestPlugin/jni/Android.mk b/tests/BrowserTestPlugin/jni/Android.mk new file mode 100644 index 0000000..95a21e9 --- /dev/null +++ b/tests/BrowserTestPlugin/jni/Android.mk @@ -0,0 +1,49 @@ +## +## +## Copyright 2009, The Android Open Source Project +## +## Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions +## are met: +## * Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## * Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in the +## documentation and/or other materials provided with the distribution. +## +## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY +## EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR +## CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +## EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +## PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +## PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +## OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +## + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + main.cpp \ + PluginObject.cpp \ + event/EventPlugin.cpp \ + +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH) \ + $(LOCAL_PATH)/event \ + external/webkit/WebCore/bridge \ + external/webkit/WebCore/plugins \ + external/webkit/WebCore/platform/android/JavaVM \ + external/webkit/WebKit/android/plugins + +LOCAL_CFLAGS += -fvisibility=hidden +LOCAL_PRELINK_MODULE := false + +LOCAL_MODULE := libtestplugin +LOCAL_MODULE_TAGS := tests + +include $(BUILD_SHARED_LIBRARY) diff --git a/tests/BrowserTestPlugin/jni/PluginObject.cpp b/tests/BrowserTestPlugin/jni/PluginObject.cpp new file mode 100644 index 0000000..68fca60 --- /dev/null +++ b/tests/BrowserTestPlugin/jni/PluginObject.cpp @@ -0,0 +1,202 @@ +/* + * Copyright 2009, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. ("Apple") in + consideration of your agreement to the following terms, and your use, installation, + modification or redistribution of this Apple software constitutes acceptance of these + terms. If you do not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject to these + terms, Apple grants you a personal, non-exclusive license, under AppleÕs copyrights in + this original Apple software (the "Apple Software"), to use, reproduce, modify and + redistribute the Apple Software, with or without modifications, in source and/or binary + forms; provided that if you redistribute the Apple Software in its entirety and without + modifications, you must retain this notice and the following text and disclaimers in all + such redistributions of the Apple Software. Neither the name, trademarks, service marks + or logos of Apple Computer, Inc. may be used to endorse or promote products derived from + the Apple Software without specific prior written permission from Apple. Except as expressly + stated in this notice, no other rights or licenses, express or implied, are granted by Apple + herein, including but not limited to any patent rights that may be infringed by your + derivative works or by other works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO WARRANTIES, + EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS + USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, + REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND + WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR + OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdlib.h> +#include "main.h" +#include "PluginObject.h" + +static void pluginInvalidate(NPObject *obj); +static bool pluginHasProperty(NPObject *obj, NPIdentifier name); +static bool pluginHasMethod(NPObject *obj, NPIdentifier name); +static bool pluginGetProperty(NPObject *obj, NPIdentifier name, NPVariant *variant); +static bool pluginSetProperty(NPObject *obj, NPIdentifier name, const NPVariant *variant); +static bool pluginInvoke(NPObject *obj, NPIdentifier name, const NPVariant *args, uint32_t argCount, NPVariant *result); +static bool pluginInvokeDefault(NPObject *obj, const NPVariant *args, uint32_t argCount, NPVariant *result); +static NPObject *pluginAllocate(NPP npp, NPClass *theClass); +static void pluginDeallocate(NPObject *obj); +static bool pluginRemoveProperty(NPObject *npobj, NPIdentifier name); +static bool pluginEnumerate(NPObject *npobj, NPIdentifier **value, uint32_t *count); + + + +static NPClass pluginClass = { + NP_CLASS_STRUCT_VERSION, + pluginAllocate, + pluginDeallocate, + pluginInvalidate, + pluginHasMethod, + pluginInvoke, + pluginInvokeDefault, + pluginHasProperty, + pluginGetProperty, + pluginSetProperty, + pluginRemoveProperty, + pluginEnumerate +}; + +NPClass *getPluginClass(void) +{ + return &pluginClass; +} + +static bool identifiersInitialized = false; + +#define ID_TESTFILE_PROPERTY 0 +#define NUM_PROPERTY_IDENTIFIERS 1 + +static NPIdentifier pluginPropertyIdentifiers[NUM_PROPERTY_IDENTIFIERS]; +static const NPUTF8 *pluginPropertyIdentifierNames[NUM_PROPERTY_IDENTIFIERS] = { + "testfile" +}; + +#define ID_GETTESTFILE_METHOD 0 +#define NUM_METHOD_IDENTIFIERS 1 + +static NPIdentifier pluginMethodIdentifiers[NUM_METHOD_IDENTIFIERS]; +static const NPUTF8 *pluginMethodIdentifierNames[NUM_METHOD_IDENTIFIERS] = { + "getTestFile" +}; + +static void initializeIdentifiers(void) +{ + browser->getstringidentifiers(pluginPropertyIdentifierNames, NUM_PROPERTY_IDENTIFIERS, pluginPropertyIdentifiers); + browser->getstringidentifiers(pluginMethodIdentifierNames, NUM_METHOD_IDENTIFIERS, pluginMethodIdentifiers); +} + +static bool pluginHasProperty(NPObject *obj, NPIdentifier name) +{ + int i; + for (i = 0; i < NUM_PROPERTY_IDENTIFIERS; i++) + if (name == pluginPropertyIdentifiers[i]) + return true; + return false; +} + +static bool pluginHasMethod(NPObject *obj, NPIdentifier name) +{ + int i; + for (i = 0; i < NUM_METHOD_IDENTIFIERS; i++) + if (name == pluginMethodIdentifiers[i]) + return true; + return false; +} + +static bool pluginGetProperty(NPObject *obj, NPIdentifier name, NPVariant *variant) +{ + PluginObject *plugin = (PluginObject *)obj; + if (name == pluginPropertyIdentifiers[ID_TESTFILE_PROPERTY]) { + BOOLEAN_TO_NPVARIANT(true, *variant); + return true; + } + return false; +} + +static bool pluginSetProperty(NPObject *obj, NPIdentifier name, const NPVariant *variant) +{ + return false; +} + +static bool pluginInvoke(NPObject *obj, NPIdentifier name, const NPVariant *args, uint32_t argCount, NPVariant *result) +{ + PluginObject *plugin = (PluginObject *)obj; + if (name == pluginMethodIdentifiers[ID_GETTESTFILE_METHOD]) { + return true; + } + return false; +} + +static bool pluginInvokeDefault(NPObject *obj, const NPVariant *args, uint32_t argCount, NPVariant *result) +{ + return false; +} + +static void pluginInvalidate(NPObject *obj) +{ + // Release any remaining references to JavaScript objects. +} + +static NPObject *pluginAllocate(NPP npp, NPClass *theClass) +{ + PluginObject *newInstance = (PluginObject*) malloc(sizeof(PluginObject)); + newInstance->header._class = theClass; + newInstance->header.referenceCount = 1; + + if (!identifiersInitialized) { + identifiersInitialized = true; + initializeIdentifiers(); + } + + newInstance->npp = npp; + + return &newInstance->header; +} + +static void pluginDeallocate(NPObject *obj) +{ + free(obj); +} + +static bool pluginRemoveProperty(NPObject *npobj, NPIdentifier name) +{ + return false; +} + +static bool pluginEnumerate(NPObject *npobj, NPIdentifier **value, uint32_t *count) +{ + return false; +} diff --git a/tests/BrowserTestPlugin/jni/PluginObject.h b/tests/BrowserTestPlugin/jni/PluginObject.h new file mode 100644 index 0000000..a058d4a --- /dev/null +++ b/tests/BrowserTestPlugin/jni/PluginObject.h @@ -0,0 +1,87 @@ +/* + * Copyright 2009, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. ("Apple") in + consideration of your agreement to the following terms, and your use, installation, + modification or redistribution of this Apple software constitutes acceptance of these + terms. If you do not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject to these + terms, Apple grants you a personal, non-exclusive license, under AppleÕs copyrights in + this original Apple software (the "Apple Software"), to use, reproduce, modify and + redistribute the Apple Software, with or without modifications, in source and/or binary + forms; provided that if you redistribute the Apple Software in its entirety and without + modifications, you must retain this notice and the following text and disclaimers in all + such redistributions of the Apple Software. Neither the name, trademarks, service marks + or logos of Apple Computer, Inc. may be used to endorse or promote products derived from + the Apple Software without specific prior written permission from Apple. Except as expressly + stated in this notice, no other rights or licenses, express or implied, are granted by Apple + herein, including but not limited to any patent rights that may be infringed by your + derivative works or by other works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO WARRANTIES, + EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS + USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, + REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND + WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR + OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef PluginObject__DEFINED +#define PluginObject__DEFINED + +#include "main.h" + +class SubPlugin { +public: + SubPlugin(NPP inst) : m_inst(inst) {} + virtual ~SubPlugin() {} + virtual int16 handleEvent(const ANPEvent* evt) = 0; + + NPP inst() const { return m_inst; } + +private: + NPP m_inst; +}; + +typedef struct PluginObject { + NPObject header; + NPP npp; + NPWindow* window; + + SubPlugin* subPlugin; + +} PluginObject; + +NPClass *getPluginClass(void); + +#endif // PluginObject__DEFINED diff --git a/tests/BrowserTestPlugin/jni/event/EventPlugin.cpp b/tests/BrowserTestPlugin/jni/event/EventPlugin.cpp new file mode 100644 index 0000000..1263204 --- /dev/null +++ b/tests/BrowserTestPlugin/jni/event/EventPlugin.cpp @@ -0,0 +1,198 @@ +/* + * Copyright 2009, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "EventPlugin.h" +#include "android_npapi.h" + +#include <stdio.h> +#include <sys/time.h> +#include <time.h> +#include <math.h> +#include <string.h> + +extern NPNetscapeFuncs* browser; +extern ANPCanvasInterfaceV0 gCanvasI; +extern ANPLogInterfaceV0 gLogI; +extern ANPPaintInterfaceV0 gPaintI; +extern ANPSurfaceInterfaceV0 gSurfaceI; +extern ANPTypefaceInterfaceV0 gTypefaceI; + +/////////////////////////////////////////////////////////////////////////////// + +EventPlugin::EventPlugin(NPP inst) : SubPlugin(inst) { + + // initialize the drawing surface + m_surfaceReady = false; + m_surface = gSurfaceI.newRasterSurface(inst, kRGB_565_ANPBitmapFormat, false); + if(!m_surface) + gLogI.log(inst, kError_ANPLogType, "----%p Unable to create Raster surface", inst); +} + +EventPlugin::~EventPlugin() { + gSurfaceI.deleteSurface(m_surface); +} + +void EventPlugin::drawPlugin(int surfaceWidth, int surfaceHeight) { + + gLogI.log(inst(), kDebug_ANPLogType, " ------ %p drawing the plugin (%d,%d)", inst(), surfaceWidth, surfaceHeight); + + // get the plugin's dimensions according to the DOM + PluginObject *obj = (PluginObject*) inst()->pdata; + const int W = obj->window->width; + const int H = obj->window->height; + + // compute the current zoom level + const float zoomFactorW = static_cast<float>(surfaceWidth) / W; + const float zoomFactorH = static_cast<float>(surfaceHeight) / H; + + // check to make sure the zoom level is uniform + if (zoomFactorW + .01 < zoomFactorH && zoomFactorW - .01 > zoomFactorH) + gLogI.log(inst(), kError_ANPLogType, " ------ %p zoom is out of sync (%f,%f)", + inst(), zoomFactorW, zoomFactorH); + + // scale the variables based on the zoom level + const int fontSize = (int)(zoomFactorW * 16); + const int leftMargin = (int)(zoomFactorW * 10); + + // lock the surface + ANPBitmap bitmap; + if (!m_surfaceReady || !gSurfaceI.lock(m_surface, &bitmap, NULL)) { + gLogI.log(inst(), kError_ANPLogType, " ------ %p unable to lock the plugin", inst()); + return; + } + + // create a canvas + ANPCanvas* canvas = gCanvasI.newCanvas(&bitmap); + gCanvasI.drawColor(canvas, 0xFFFFFFFF); + + // configure the paint + ANPPaint* paint = gPaintI.newPaint(); + gPaintI.setFlags(paint, gPaintI.getFlags(paint) | kAntiAlias_ANPPaintFlag); + gPaintI.setColor(paint, 0xFF0000FF); + gPaintI.setTextSize(paint, fontSize); + + // configure the font + ANPTypeface* tf = gTypefaceI.createFromName("serif", kItalic_ANPTypefaceStyle); + gPaintI.setTypeface(paint, tf); + gTypefaceI.unref(tf); + + // retrieve the font metrics + ANPFontMetrics fm; + gPaintI.getFontMetrics(paint, &fm); + + // write text on the canvas + const char c[] = "Browser Test Plugin"; + gCanvasI.drawText(canvas, c, sizeof(c)-1, leftMargin, -fm.fTop, paint); + + // clean up variables and unlock the surface + gPaintI.deletePaint(paint); + gCanvasI.deleteCanvas(canvas); + gSurfaceI.unlock(m_surface); +} + +void EventPlugin::printToDiv(const char* text, int length) { + // Get the plugin's DOM object + NPObject* windowObject = NULL; + browser->getvalue(inst(), NPNVWindowNPObject, &windowObject); + + if (!windowObject) + gLogI.log(inst(), kError_ANPLogType, " ------ %p Unable to retrieve DOM Window", inst()); + + // create a string (JS code) that is stored in memory allocated by the browser + const char* jsBegin = "var outputDiv = document.getElementById('eventOutput'); outputDiv.innerHTML += ' "; + const char* jsEnd = "';"; + + // allocate memory and configure pointers + int totalLength = strlen(jsBegin) + length + strlen(jsEnd); + char* beginMem = (char*)browser->memalloc(totalLength); + char* middleMem = beginMem + strlen(jsBegin); + char* endMem = middleMem + length; + + // copy into the allocated memory + memcpy(beginMem, jsBegin, strlen(jsBegin)); + memcpy(middleMem, text, length); + memcpy(endMem, jsEnd, strlen(jsEnd)); + + gLogI.log(inst(), kError_ANPLogType, "text: %.*s\n", totalLength, (char*)beginMem); + + // execute the javascript in the plugin's DOM object + NPString script = { (char*)beginMem, totalLength }; + NPVariant scriptVariant; + if (!browser->evaluate(inst(), windowObject, &script, &scriptVariant)) + gLogI.log(inst(), kError_ANPLogType, " ------ %p Unable to eval the JS.", inst()); + + // free the memory allocated within the browser + browser->memfree(beginMem); +} + +int16 EventPlugin::handleEvent(const ANPEvent* evt) { + switch (evt->eventType) { + case kDraw_ANPEventType: + gLogI.log(inst(), kError_ANPLogType, " ------ %p the plugin did not request draw events", inst()); + break; + case kSurface_ANPEventType: + switch (evt->data.surface.action) { + case kCreated_ANPSurfaceAction: + m_surfaceReady = true; + return 1; + case kDestroyed_ANPSurfaceAction: + m_surfaceReady = false; + return 1; + case kChanged_ANPSurfaceAction: + drawPlugin(evt->data.surface.data.changed.width, + evt->data.surface.data.changed.height); + return 1; + } + break; + case kLifecycle_ANPEventType: + switch (evt->data.lifecycle.action) { + case kOnLoad_ANPLifecycleAction: { + char msg[] = "lifecycle-onLoad"; + printToDiv(msg, strlen(msg)); + break; + } + case kGainFocus_ANPLifecycleAction: { + char msg[] = "lifecycle-gainFocus"; + printToDiv(msg, strlen(msg)); + break; + } + case kLoseFocus_ANPLifecycleAction: { + char msg[] = "lifecycle-loseFocus"; + printToDiv(msg, strlen(msg)); + break; + } + } + return 1; + case kTouch_ANPEventType: + gLogI.log(inst(), kError_ANPLogType, " ------ %p the plugin did not request touch events", inst()); + break; + case kKey_ANPEventType: + gLogI.log(inst(), kError_ANPLogType, " ------ %p the plugin did not request key events", inst()); + break; + default: + break; + } + return 0; // unknown or unhandled event +} diff --git a/tests/BrowserTestPlugin/jni/event/EventPlugin.h b/tests/BrowserTestPlugin/jni/event/EventPlugin.h new file mode 100644 index 0000000..73dd6ea --- /dev/null +++ b/tests/BrowserTestPlugin/jni/event/EventPlugin.h @@ -0,0 +1,45 @@ +/* + * Copyright 2009, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "PluginObject.h" + +#ifndef eventPlugin__DEFINED +#define eventPlugin__DEFINED + +class EventPlugin : public SubPlugin { +public: + EventPlugin(NPP inst); + virtual ~EventPlugin(); + virtual int16 handleEvent(const ANPEvent* evt); + +private: + void drawPlugin(int surfaceWidth, int surfaceHeight); + void printToDiv(const char* text, int length); + + bool m_surfaceReady; + ANPSurface* m_surface; +}; + +#endif // eventPlugin__DEFINED diff --git a/tests/BrowserTestPlugin/jni/main.cpp b/tests/BrowserTestPlugin/jni/main.cpp new file mode 100644 index 0000000..056ec4d --- /dev/null +++ b/tests/BrowserTestPlugin/jni/main.cpp @@ -0,0 +1,280 @@ +/* + * Copyright 2009, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include "android_npapi.h" +#include "main.h" +#include "PluginObject.h" +#include "EventPlugin.h" + +NPNetscapeFuncs* browser; +#define EXPORT __attribute__((visibility("default"))) + +NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 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); +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, + 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); +void NPP_URLNotify(NPP instance, const char* URL, NPReason reason, + void* notifyData); +NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value); +NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value); + +extern "C" { +EXPORT NPError NP_Initialize(NPNetscapeFuncs* browserFuncs, NPPluginFuncs* pluginFuncs, void *java_env, void *application_context); +EXPORT NPError NP_GetValue(NPP instance, NPPVariable variable, void *value); +EXPORT const char* NP_GetMIMEDescription(void); +EXPORT void NP_Shutdown(void); +}; + +ANPAudioTrackInterfaceV0 gSoundI; +ANPBitmapInterfaceV0 gBitmapI; +ANPCanvasInterfaceV0 gCanvasI; +ANPLogInterfaceV0 gLogI; +ANPPaintInterfaceV0 gPaintI; +ANPPathInterfaceV0 gPathI; +ANPSurfaceInterfaceV0 gSurfaceI; +ANPSystemInterfaceV0 gSystemI; +ANPTypefaceInterfaceV0 gTypefaceI; +ANPWindowInterfaceV0 gWindowI; + +#define ARRAY_COUNT(array) (sizeof(array) / sizeof(array[0])) + +NPError NP_Initialize(NPNetscapeFuncs* browserFuncs, NPPluginFuncs* pluginFuncs, void *java_env, void *application_context) +{ + // Make sure we have a function table equal or larger than we are built against. + if (browserFuncs->size < sizeof(NPNetscapeFuncs)) { + return NPERR_GENERIC_ERROR; + } + + // Copy the function table (structure) + browser = (NPNetscapeFuncs*) malloc(sizeof(NPNetscapeFuncs)); + memcpy(browser, browserFuncs, sizeof(NPNetscapeFuncs)); + + // Build the plugin function table + pluginFuncs->version = 11; + pluginFuncs->size = sizeof(pluginFuncs); + pluginFuncs->newp = NPP_New; + pluginFuncs->destroy = NPP_Destroy; + pluginFuncs->setwindow = NPP_SetWindow; + pluginFuncs->newstream = NPP_NewStream; + pluginFuncs->destroystream = NPP_DestroyStream; + pluginFuncs->asfile = NPP_StreamAsFile; + pluginFuncs->writeready = NPP_WriteReady; + pluginFuncs->write = (NPP_WriteProcPtr)NPP_Write; + pluginFuncs->print = NPP_Print; + pluginFuncs->event = NPP_HandleEvent; + pluginFuncs->urlnotify = NPP_URLNotify; + pluginFuncs->getvalue = NPP_GetValue; + pluginFuncs->setvalue = NPP_SetValue; + + static const struct { + NPNVariable v; + uint32_t size; + ANPInterface* i; + } gPairs[] = { + { kAudioTrackInterfaceV0_ANPGetValue, sizeof(gSoundI), &gSoundI }, + { kBitmapInterfaceV0_ANPGetValue, sizeof(gBitmapI), &gBitmapI }, + { kCanvasInterfaceV0_ANPGetValue, sizeof(gCanvasI), &gCanvasI }, + { kLogInterfaceV0_ANPGetValue, sizeof(gLogI), &gLogI }, + { kPaintInterfaceV0_ANPGetValue, sizeof(gPaintI), &gPaintI }, + { kPathInterfaceV0_ANPGetValue, sizeof(gPathI), &gPathI }, + { kSurfaceInterfaceV0_ANPGetValue, sizeof(gSurfaceI), &gSurfaceI }, + { kSystemInterfaceV0_ANPGetValue, sizeof(gSystemI), &gSystemI }, + { kTypefaceInterfaceV0_ANPGetValue, sizeof(gTypefaceI), &gTypefaceI }, + { kWindowInterfaceV0_ANPGetValue, sizeof(gWindowI), &gWindowI }, + }; + for (size_t i = 0; i < ARRAY_COUNT(gPairs); i++) { + gPairs[i].i->inSize = gPairs[i].size; + NPError err = browser->getvalue(NULL, gPairs[i].v, gPairs[i].i); + if (err) { + return err; + } + } + + return NPERR_NO_ERROR; +} + +void NP_Shutdown(void) +{ + +} + +const char *NP_GetMIMEDescription(void) +{ + return "application/x-browsertestplugin:btp:Android Browser Test Plugin"; +} + +NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, + char* argn[], char* argv[], NPSavedData* saved) +{ + + + gLogI.log(instance, kDebug_ANPLogType, "creating plugin"); + + PluginObject *obj = NULL; + + // Scripting functions appeared in NPAPI version 14 + if (browser->version >= 14) { + instance->pdata = browser->createobject (instance, getPluginClass()); + obj = static_cast<PluginObject*>(instance->pdata); + bzero(obj, sizeof(*obj)); + } else { + return NPERR_GENERIC_ERROR; + } + + // select the drawing model + ANPDrawingModel model = kSurface_ANPDrawingModel; + + // notify the plugin API of the drawing model we wish to use. This must be + // done prior to creating certain subPlugin objects (e.g. surfaceViews) + NPError err = browser->setvalue(instance, kRequestDrawingModel_ANPSetValue, + reinterpret_cast<void*>(model)); + if (err) { + gLogI.log(instance, kError_ANPLogType, "request model %d err %d", model, err); + return err; + } + + // create the sub-plugin + obj->subPlugin = new EventPlugin(instance); + + return NPERR_NO_ERROR; +} + +NPError NPP_Destroy(NPP instance, NPSavedData** save) +{ + PluginObject *obj = (PluginObject*) instance->pdata; + delete obj->subPlugin; + + return NPERR_NO_ERROR; +} + +NPError NPP_SetWindow(NPP instance, NPWindow* window) +{ + PluginObject *obj = (PluginObject*) instance->pdata; + + // Do nothing if browser didn't support NPN_CreateObject which would have created the PluginObject. + if (obj != NULL) { + obj->window = window; + } + + return NPERR_NO_ERROR; +} + +NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16* stype) +{ + *stype = NP_ASFILEONLY; + return NPERR_NO_ERROR; +} + +NPError NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason) +{ + return NPERR_NO_ERROR; +} + +int32 NPP_WriteReady(NPP instance, NPStream* stream) +{ + return 0; +} + +int32 NPP_Write(NPP instance, NPStream* stream, int32 offset, int32 len, void* buffer) +{ + return 0; +} + +void NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname) +{ +} + +void NPP_Print(NPP instance, NPPrint* platformPrint) +{ +} + +int16 NPP_HandleEvent(NPP instance, void* event) +{ + PluginObject *obj = reinterpret_cast<PluginObject*>(instance->pdata); + const ANPEvent* evt = reinterpret_cast<const ANPEvent*>(event); + + if(!obj->subPlugin) { + gLogI.log(instance, kError_ANPLogType, "the sub-plugin is null."); + return 0; // unknown or unhandled event + } + else { + return obj->subPlugin->handleEvent(evt); + } +} + +void NPP_URLNotify(NPP instance, const char* url, NPReason reason, void* notifyData) +{ +} + +EXPORT NPError NP_GetValue(NPP instance, NPPVariable variable, void *value) { + + if (variable == NPPVpluginNameString) { + const char **str = (const char **)value; + *str = "Browser Test Plugin"; + return NPERR_NO_ERROR; + } + + if (variable == NPPVpluginDescriptionString) { + const char **str = (const char **)value; + *str = "Description of Browser Test Plugin"; + return NPERR_NO_ERROR; + } + + return NPERR_GENERIC_ERROR; +} + +NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value) +{ + if (variable == NPPVpluginScriptableNPObject) { + void **v = (void **)value; + PluginObject *obj = (PluginObject*) instance->pdata; + + if (obj) + browser->retainobject((NPObject*)obj); + + *v = obj; + return NPERR_NO_ERROR; + } + + return NPERR_GENERIC_ERROR; +} + +NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value) +{ + return NPERR_GENERIC_ERROR; +} + diff --git a/tests/BrowserTestPlugin/jni/main.h b/tests/BrowserTestPlugin/jni/main.h new file mode 100644 index 0000000..e6e8c73 --- /dev/null +++ b/tests/BrowserTestPlugin/jni/main.h @@ -0,0 +1,31 @@ +/* + * Copyright 2009, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <npapi.h> +#include <npfunctions.h> +#include <npruntime.h> +#include "android_npapi.h" + +extern NPNetscapeFuncs* browser; diff --git a/tests/BrowserTestPlugin/res/drawable/browser_test_plugin.png b/tests/BrowserTestPlugin/res/drawable/browser_test_plugin.png Binary files differnew file mode 100755 index 0000000..47c79d1 --- /dev/null +++ b/tests/BrowserTestPlugin/res/drawable/browser_test_plugin.png diff --git a/tests/BrowserTestPlugin/src/com/android/testplugin/TestPlugin.java b/tests/BrowserTestPlugin/src/com/android/testplugin/TestPlugin.java new file mode 100644 index 0000000..94a18fd --- /dev/null +++ b/tests/BrowserTestPlugin/src/com/android/testplugin/TestPlugin.java @@ -0,0 +1,15 @@ +package com.android.testplugin; + +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; + +public class TestPlugin extends Service { + + @Override + public IBinder onBind(Intent intent) { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java index ede5197..8fea967 100644 --- a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java @@ -79,7 +79,8 @@ public class FileFilter { "profiler", // profiler is not supported "svg", // svg is not supported "platform", // platform specific - "http" // requires local http(s) server + "http", // requires local http(s) server + "fast/workers", }; static final String [] ignoreTestList = { diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java index 96b34b3..e342efb 100644 --- a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java @@ -552,7 +552,8 @@ public class TestShellActivity extends Activity implements LayoutTestController @Override public void onExceededDatabaseQuota(String url_str, - String databaseIdentifier, long currentQuota, long totalUsedQuota, + String databaseIdentifier, long currentQuota, + long estimatedSize, long totalUsedQuota, WebStorage.QuotaUpdater callback) { if (mDumpDatabaseCallbacks) { if (mDatabaseCallbackStrings == null) { diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp index 9a5127d..e8410cd 100644 --- a/tools/aapt/Resource.cpp +++ b/tools/aapt/Resource.cpp @@ -1238,10 +1238,16 @@ static status_t writeLayoutClasses( NA = idents.size(); + bool deprecated = false; + String16 comment = symbols->getComment(realClassName); fprintf(fp, "%s/** ", indentStr); if (comment.size() > 0) { - fprintf(fp, "%s\n", String8(comment).string()); + String8 cmt(comment); + fprintf(fp, "%s\n", cmt.string()); + if (strstr(cmt.string(), "@deprecated") != NULL) { + deprecated = true; + } } else { fprintf(fp, "Attributes that can be used with a %s.\n", nclassName.string()); } @@ -1317,6 +1323,10 @@ static status_t writeLayoutClasses( } fprintf(fp, "%s */\n", getIndentSpace(indent)); + if (deprecated) { + fprintf(fp, "%s@Deprecated\n", indentStr); + } + fprintf(fp, "%spublic static final int[] %s = {\n" "%s", @@ -1365,11 +1375,17 @@ static status_t writeLayoutClasses( //printf("%s:%s/%s: 0x%08x\n", String8(package16).string(), // String8(attr16).string(), String8(name16).string(), typeSpecFlags); const bool pub = (typeSpecFlags&ResTable_typeSpec::SPEC_PUBLIC) != 0; - + + bool deprecated = false; + fprintf(fp, "%s/**\n", indentStr); if (comment.size() > 0) { + String8 cmt(comment); fprintf(fp, "%s <p>\n%s @attr description\n", indentStr, indentStr); - fprintf(fp, "%s %s\n", indentStr, String8(comment).string()); + fprintf(fp, "%s %s\n", indentStr, cmt.string()); + if (strstr(cmt.string(), "@deprecated") != NULL) { + deprecated = true; + } } else { fprintf(fp, "%s <p>This symbol is the offset where the {@link %s.R.attr#%s}\n" @@ -1381,7 +1397,11 @@ static status_t writeLayoutClasses( indentStr, nclassName.string()); } if (typeComment.size() > 0) { - fprintf(fp, "\n\n%s %s\n", indentStr, String8(typeComment).string()); + String8 cmt(typeComment); + fprintf(fp, "\n\n%s %s\n", indentStr, cmt.string()); + if (strstr(cmt.string(), "@deprecated") != NULL) { + deprecated = true; + } } if (comment.size() > 0) { if (pub) { @@ -1399,6 +1419,9 @@ static status_t writeLayoutClasses( fprintf(fp, "%s @attr name %s:%s\n", indentStr, "android", String8(name).string()); fprintf(fp, "%s*/\n", indentStr); + if (deprecated) { + fprintf(fp, "%s@Deprecated\n", indentStr); + } fprintf(fp, "%spublic static final int %s_%s = %d;\n", indentStr, nclassName.string(), @@ -1440,11 +1463,16 @@ static status_t writeSymbolClass( } String16 comment(sym.comment); bool haveComment = false; + bool deprecated = false; if (comment.size() > 0) { haveComment = true; + String8 cmt(comment); fprintf(fp, "%s/** %s\n", - getIndentSpace(indent), String8(comment).string()); + getIndentSpace(indent), cmt.string()); + if (strstr(cmt.string(), "@deprecated") != NULL) { + deprecated = true; + } } else if (sym.isPublic && !includePrivate) { sym.sourcePos.warning("No comment for public symbol %s:%s/%s", assets->getPackage().string(), className.string(), @@ -1452,20 +1480,25 @@ static status_t writeSymbolClass( } String16 typeComment(sym.typeComment); if (typeComment.size() > 0) { + String8 cmt(typeComment); if (!haveComment) { haveComment = true; fprintf(fp, - "%s/** %s\n", - getIndentSpace(indent), String8(typeComment).string()); + "%s/** %s\n", getIndentSpace(indent), cmt.string()); } else { fprintf(fp, - "%s %s\n", - getIndentSpace(indent), String8(typeComment).string()); + "%s %s\n", getIndentSpace(indent), cmt.string()); + } + if (strstr(cmt.string(), "@deprecated") != NULL) { + deprecated = true; } } if (haveComment) { fprintf(fp,"%s */\n", getIndentSpace(indent)); } + if (deprecated) { + fprintf(fp, "%s@Deprecated\n", getIndentSpace(indent)); + } fprintf(fp, "%spublic static final int %s=0x%08x;\n", getIndentSpace(indent), String8(name).string(), (int)sym.int32Val); @@ -1484,17 +1517,25 @@ static status_t writeSymbolClass( return UNKNOWN_ERROR; } String16 comment(sym.comment); + bool deprecated = false; if (comment.size() > 0) { + String8 cmt(comment); fprintf(fp, "%s/** %s\n" "%s */\n", - getIndentSpace(indent), String8(comment).string(), + getIndentSpace(indent), cmt.string(), getIndentSpace(indent)); + if (strstr(cmt.string(), "@deprecated") != NULL) { + deprecated = true; + } } else if (sym.isPublic && !includePrivate) { sym.sourcePos.warning("No comment for public symbol %s:%s/%s", assets->getPackage().string(), className.string(), String8(sym.name).string()); } + if (deprecated) { + fprintf(fp, "%s@Deprecated\n", getIndentSpace(indent)); + } fprintf(fp, "%spublic static final String %s=\"%s\";\n", getIndentSpace(indent), String8(name).string(), sym.stringVal.string()); diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index d8a03a9..27755ed 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -960,7 +960,7 @@ public class WifiManager { * * If this MulticastLock is not reference-counted, the first call to * {@code release} (after the radio was multicast locked using - * {@linke #acquire}) will unlock the multicast, and subsequent calls + * {@link #acquire}) will unlock the multicast, and subsequent calls * will be ignored. * * Note that if any other Wifi Multicast Locks are still outstanding |
