CB-6521: Remove development branch
diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 7a4a3ea..0000000 --- a/LICENSE +++ /dev/null
@@ -1,202 +0,0 @@ - - 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 - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file
diff --git a/NOTICE b/NOTICE deleted file mode 100644 index 8ec56a5..0000000 --- a/NOTICE +++ /dev/null
@@ -1,5 +0,0 @@ -Apache Cordova -Copyright 2012 The Apache Software Foundation - -This product includes software developed at -The Apache Software Foundation (http://www.apache.org/).
diff --git a/README.md b/README.md index 5b74138..07daee6 100644 --- a/README.md +++ b/README.md
@@ -20,3 +20,5 @@ # org.apache.cordova.contacts Plugin documentation: [doc/index.md](doc/index.md) + +This is `dev` - the deprecated development branch of this plugin; development of this plugin has moved to the `master` branch
diff --git a/RELEASENOTES.md b/RELEASENOTES.md deleted file mode 100644 index 30f2c2f..0000000 --- a/RELEASENOTES.md +++ /dev/null
@@ -1,84 +0,0 @@ -<!-- -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# ---> -# Release Notes - -### 0.2.1 (Sept 5, 2013) -* [CB-4580] Fixed up duplicate definitions of module id -* [CB-4432] Copyright notice change - -### 0.2.3 (Sept 25, 2013) -* CB-4889 bumping&resetting version -* [BlackBerry10] removed uneeded permission tags in plugin.xml -* [BlackBerry10] removed uneeded permission tags in plugin.xml -* CB-4889 renaming blackberry10 reference in plugin.xml -* CB-4888 renaming org.apache.cordova.core.contacts to org.apache.cordova.contacts -* added contacts api for firefoxos -* Rename CHANGELOG.md -> RELEASENOTES.md -* [CB-4824] Fix XCode 5 contacts plugin warnings -* [CB-4752] Incremented plugin version on dev branch. - -### 0.2.4 (Oct 9, 2013) -* [CB-4950] Remove the dependence on concrete component android.webkit.WebView. -* [CB-4915] Incremented plugin version on dev branch. - - ### 0.2.5 (Oct 28, 2013) -* CB-5128: added repo + issue tags for contacts -* [CB-5010] Incremented plugin version on dev branch. - -### 0.2.6 (Dec 4, 2013) -* Fix bad commit/merge -* CB-3035 Fix issue with windows new line char \n\r -* wrong example given -* docs added -* FxOS name fields are arrays hackedSearch refactored search based on find commented out -* search hacked via getAll -* search added - no idea if this is working -* createMozillaFromCordova and vice versa are used to translate contact objects from one API to another. -* add/remove working -* save is working -* attempt to save is failing trying to limit the translated contact fields to name and familyName, but still failing -* save is linked with the proxy contact.name doesn't exist www/Contact.js#Contact.prototype.save check on which side is the error -* CB-5214 Make mobile spec tests on WP8 to run w/o user interaction + Sync with cordova-mobile-spec -* CB-5525 WP8. Contacts Api fails in case of there is special character in contact field -* fixed ubuntu policy error -* [ubuntu] specify policy_group -* add ubuntu platform -* CB-3035 Fix issue with windows new line char \n\r -* 1. Added amazon-fireos platform. 2. Change to use amazon-fireos as the platform if user agent string contains 'cordova-amazon-fireos'. -* CB-5198 [BlackBerry10] Update dependencies to point to registry -* handle null filter when fields are specified. ( long standing pull-req from @kevfromireland ) - -### 0.2.7 (Jan 02, 2014) -* B-5658 Add doc/index.md for Contacts plugin - -### 0.2.8 (Feb 05, 2014) -* [CB-3208] FFOS docs updated -* CB-4590 - chooseContact in CDVContacts crashes app - -### 0.2.9 (Feb 26, 2014) -* CB-6086 Fix typo in ffos part of plugin.xml: Camera -> Contacts -* CB-5994 Switch Contact ID lookup to use Raw contact id. - -### 0.2.10 (Apr 17, 2014) -* CB-6126: [BlackBerry10] Update docs quirks section for fields which are supported -* CB-6212: [iOS] fix warnings compiled under arm64 64-bit -* CB-6460: Update license headers -* Add NOTICE file
diff --git a/doc/index.md b/doc/index.md deleted file mode 100644 index 83f5a30..0000000 --- a/doc/index.md +++ /dev/null
@@ -1,687 +0,0 @@ -<!--- - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. ---> - -# org.apache.cordova.contacts - -Provides access to the device contacts database. - -__WARNING__: Collection and use of contact data raises -important privacy issues. Your app's privacy policy should discuss -how the app uses contact data and whether it is shared with any other -parties. Contact information is considered sensitive because it -reveals the people with whom a person communicates. Therefore, in -addition to the app's privacy policy, you should strongly consider -providing a just-in-time notice before the app accesses or uses -contact data, if the device operating system doesn't do so -already. That notice should provide the same information noted above, -as well as obtaining the user's permission (e.g., by presenting -choices for __OK__ and __No Thanks__). Note that some app -marketplaces may require the app to provide a just-in-time notice and -obtain the user's permission before accessing contact data. A -clear and easy-to-understand user experience surrounding the use of -contact data helps avoid user confusion and perceived misuse of -contact data. For more information, please see the Privacy Guide. - -## Installation - - cordova plugin add org.apache.cordova.contacts - -### Firefox OS Quirks - -Create __www/manifest.webapp__ as described in -[Manifest Docs](https://developer.mozilla.org/en-US/Apps/Developing/Manifest). -Add relevant permisions. -There is also a need to change the webapp type to "privileged" - [Manifest Docs](https://developer.mozilla.org/en-US/Apps/Developing/Manifest#type). -__WARNING__: All privileged apps enforce [Content Security Policy](https://developer.mozilla.org/en-US/Apps/CSP) which forbids inline script. Initialize your application in another way. - - "type": "privileged", - "permissions": { - "contacts": { - "access": "readwrite", - "description": "Describe why there is a need for such permission" - } - } - -## navigator.contacts - -### Methods - -- navigator.contacts.create -- navigator.contacts.find - -### Objects - -- Contact -- ContactName -- ContactField -- ContactAddress -- ContactOrganization -- ContactFindOptions -- ContactError - -## navigator.contacts.create - -The `navigator.contacts.create` method is synchronous, and returns a new `Contact` object. - -This method does not retain the Contact object in the device contacts -database, for which you need to invoke the `Contact.save` method. - -### Supported Platforms - -- Android -- BlackBerry 10 -- Firefox OS -- iOS -- Windows Phone 7 and 8 -- Windows 8 ( Note: Windows 8 Contacts are readonly via the Cordova API -Contacts are not queryable/searchable, you should inform the user to pick a contact as a call to contacts.find will open the 'People' app where the user must choose a contact. -Any contacts returned are readonly, so your application cannot modify them. ) - -### Example - - var myContact = navigator.contacts.create({"displayName": "Test User"}); - -## navigator.contacts.find - -The `navigator.contacts.find` method executes asynchronously, querying the -device contacts database and returning an array of `Contact` objects. -The resulting objects are passed to the `contactSuccess` callback -function specified by the __contactSuccess__ parameter. - -The __contactFields__ parameter specifies the fields to be used as a -search qualifier, and only those results are passed to the -__contactSuccess__ callback function. A zero-length __contactFields__ -parameter is invalid and results in -`ContactError.INVALID_ARGUMENT_ERROR`. A __contactFields__ value of -`"*"` returns all contact fields. - -The __contactFindOptions.filter__ string can be used as a search -filter when querying the contacts database. If provided, a -case-insensitive, partial value match is applied to each field -specified in the __contactFields__ parameter. If there's a match for -_any_ of the specified fields, the contact is returned. - -### Parameters - -- __contactFields__: Contact fields to use as a search qualifier. The resulting `Contact` object only features values for these fields. _(DOMString[])_ [Required] - -- __contactSuccess__: Success callback function invoked with the array of Contact objects returned from the database. [Required] - -- __contactError__: Error callback function, invoked when an error occurs. [Optional] - -- __contactFindOptions__: Search options to filter navigator.contacts. [Optional] Keys include: - -- __filter__: The search string used to find navigator.contacts. _(DOMString)_ (Default: `""`) - -- __multiple__: Determines if the find operation returns multiple navigator.contacts. _(Boolean)_ (Default: `false`) - -### Supported Platforms - -- Android -- BlackBerry 10 -- Firefox OS -- iOS -- Windows Phone 7 and 8 -- Windows 8 ( read-only support, search requires user interaction, contactFields are ignored, only contactFindOptions.multiple is used to enable the user to select 1 or many contacts. ) - -### Example - - function onSuccess(contacts) { - alert('Found ' + contacts.length + ' contacts.'); - }; - - function onError(contactError) { - alert('onError!'); - }; - - // find all contacts with 'Bob' in any name field - var options = new ContactFindOptions(); - options.filter = "Bob"; - options.multiple = true; - var fields = ["displayName", "name"]; - navigator.contacts.find(fields, onSuccess, onError, options); - - -## Contact - -The `Contact` object represents a user's contact. Contacts can be -created, stored, or removed from the device contacts database. -Contacts can also be retrieved (individually or in bulk) from the -database by invoking the `navigator.contacts.find` method. - -__NOTE__: Not all of the contact fields listed above are supported on -every device platform. Please check each platform's _Quirks_ section -for details. - - -### Properties - -- __id__: A globally unique identifier. _(DOMString)_ - -- __displayName__: The name of this Contact, suitable for display to end users. _(DOMString)_ - -- __name__: An object containing all components of a persons name. _(ContactName)_ - -- __nickname__: A casual name by which to address the contact. _(DOMString)_ - -- __phoneNumbers__: An array of all the contact's phone numbers. _(ContactField[])_ - -- __emails__: An array of all the contact's email addresses. _(ContactField[])_ - -- __addresses__: An array of all the contact's addresses. _(ContactAddress[])_ - -- __ims__: An array of all the contact's IM addresses. _(ContactField[])_ - -- __organizations__: An array of all the contact's organizations. _(ContactOrganization[])_ - -- __birthday__: The birthday of the contact. _(Date)_ - -- __note__: A note about the contact. _(DOMString)_ - -- __photos__: An array of the contact's photos. _(ContactField[])_ - -- __categories__: An array of all the user-defined categories associated with the contact. _(ContactField[])_ - -- __urls__: An array of web pages associated with the contact. _(ContactField[])_ - -### Methods - -- __clone__: Returns a new `Contact` object that is a deep copy of the calling object, with the `id` property set to `null`. - -- __remove__: Removes the contact from the device contacts database, otherwise executes an error callback with a `ContactError` object. - -- __save__: Saves a new contact to the device contacts database, or updates an existing contact if a contact with the same __id__ already exists. - -### Supported Platforms - -- Amazon Fire OS -- Android -- BlackBerry 10 -- Firefox OS -- iOS -- Windows Phone 7 and 8 - -### Save Example - - function onSuccess(contact) { - alert("Save Success"); - }; - - function onError(contactError) { - alert("Error = " + contactError.code); - }; - - // create a new contact object - var contact = navigator.contacts.create(); - contact.displayName = "Plumber"; - contact.nickname = "Plumber"; // specify both to support all devices - - // populate some fields - var name = new ContactName(); - name.givenName = "Jane"; - name.familyName = "Doe"; - contact.name = name; - - // save to device - contact.save(onSuccess,onError); - -### Clone Example - - // clone the contact object - var clone = contact.clone(); - clone.name.givenName = "John"; - console.log("Original contact name = " + contact.name.givenName); - console.log("Cloned contact name = " + clone.name.givenName); - -### Remove Example - - function onSuccess() { - alert("Removal Success"); - }; - - function onError(contactError) { - alert("Error = " + contactError.code); - }; - - // remove the contact from the device - contact.remove(onSuccess,onError); - - -### Android 2.X Quirks - -- __categories__: Not supported on Android 2.X devices, returning `null`. - -### BlackBerry 10 Quirks - -- __id__: Assigned by the device when saving the contact. - -### FirefoxOS Quirks - -- __categories__: Partially supported. Fields __pref__ and __type__ are returning `null` - -- __ims__: Not supported - -- __photos__: Not supported - - -### iOS Quirks - -- __displayName__: Not supported on iOS, returning `null` unless there is no `ContactName` specified, in which case it returns the composite name, __nickname__ or `""`, respectively. - -- __birthday__: Must be input as a JavaScript `Date` object, the same way it is returned. - -- __photos__: Returns a File URL to the image, which is stored in the application's temporary directory. Contents of the temporary directory are removed when the application exits. - -- __categories__: This property is currently not supported, returning `null`. - -### Windows Phone 7 and 8 Quirks - -- __displayName__: When creating a contact, the value provided for the display name parameter differs from the display name retrieved when finding the contact. - -- __urls__: When creating a contact, users can input and save more than one web address, but only one is available when searching the contact. - -- __phoneNumbers__: The _pref_ option is not supported. The _type_ is not supported in a _find_ operation. Only one `phoneNumber` is allowed for each _type_. - -- __emails__: The _pref_ option is not supported. Home and personal references same email entry. Only one entry is allowed for each _type_. - -- __addresses__: Supports only work, and home/personal _type_. The home and personal _type_ reference the same address entry. Only one entry is allowed for each _type_. - -- __organizations__: Only one is allowed, and does not support the _pref_, _type_, and _department_ attributes. - -- __note__: Not supported, returning `null`. - -- __ims__: Not supported, returning `null`. - -- __birthdays__: Not supported, returning `null`. - -- __categories__: Not supported, returning `null`. - - -## ContactAddress - -The `ContactAddress` object stores the properties of a single address -of a contact. A `Contact` object may include more than one address in -a `ContactAddress[]` array. - - -### Properties - -- __pref__: Set to `true` if this `ContactAddress` contains the user's preferred value. _(boolean)_ - -- __type__: A string indicating what type of field this is, _home_ for example. _(DOMString)_ - -- __formatted__: The full address formatted for display. _(DOMString)_ - -- __streetAddress__: The full street address. _(DOMString)_ - -- __locality__: The city or locality. _(DOMString)_ - -- __region__: The state or region. _(DOMString)_ - -- __postalCode__: The zip code or postal code. _(DOMString)_ - -- __country__: The country name. _(DOMString)_ - -### Supported Platforms - -- Amazon Fire OS -- Android -- BlackBerry 10 -- Firefox OS -- iOS -- Windows Phone 7 and 8 -- Windows 8 - -### Example - - // display the address information for all contacts - - function onSuccess(contacts) { - for (var i = 0; i < contacts.length; i++) { - for (var j = 0; j < contacts[i].addresses.length; j++) { - alert("Pref: " + contacts[i].addresses[j].pref + "\n" + - "Type: " + contacts[i].addresses[j].type + "\n" + - "Formatted: " + contacts[i].addresses[j].formatted + "\n" + - "Street Address: " + contacts[i].addresses[j].streetAddress + "\n" + - "Locality: " + contacts[i].addresses[j].locality + "\n" + - "Region: " + contacts[i].addresses[j].region + "\n" + - "Postal Code: " + contacts[i].addresses[j].postalCode + "\n" + - "Country: " + contacts[i].addresses[j].country); - } - } - }; - - function onError(contactError) { - alert('onError!'); - }; - - // find all contacts - var options = new ContactFindOptions(); - options.filter = ""; - var filter = ["displayName", "addresses"]; - navigator.contacts.find(filter, onSuccess, onError, options); - -### Android 2.X Quirks - -- __pref__: Not supported, returning `false` on Android 2.X devices. - -### BlackBerry 10 Quirks - -- __pref__: Not supported on BlackBerry devices, returning `false`. - -- __type__: Partially supported. Only one each of _Work_ and _Home_ type addresses can be stored per contact. - -- __formatted__: Partially supported. Returns a concatenation of all BlackBerry address fields. - -- __streetAddress__: Supported. Returns a concatenation of BlackBerry __address1__ and __address2__ address fields. - -- __locality__: Supported. Stored in BlackBerry __city__ address field. - -- __region__: Supported. Stored in BlackBerry __stateProvince__ address field. - -- __postalCode__: Supported. Stored in BlackBerry __zipPostal__ address field. - -- __country__: Supported. - -### FirefoxOS Quirks - -- __formatted__: Currently not supported - -### iOS Quirks - -- __pref__: Not supported on iOS devices, returning `false`. - -- __formatted__: Currently not supported. - -### Windows 8 Quirks - -- __pref__: Not supported - - -## ContactError - -The `ContactError` object is returned to the user through the -`contactError` callback function when an error occurs. - -### Properties - -- __code__: One of the predefined error codes listed below. - -### Constants - -- `ContactError.UNKNOWN_ERROR` -- `ContactError.INVALID_ARGUMENT_ERROR` -- `ContactError.TIMEOUT_ERROR` -- `ContactError.PENDING_OPERATION_ERROR` -- `ContactError.IO_ERROR` -- `ContactError.NOT_SUPPORTED_ERROR` -- `ContactError.PERMISSION_DENIED_ERROR` - - -## ContactField - -The `ContactField` object is a reusable component that represents -contact fields generically. Each `ContactField` object contains a -`value`, `type`, and `pref` property. A `Contact` object stores -several properties in `ContactField[]` arrays, such as phone numbers -and email addresses. - -In most instances, there are no pre-determined values for a -`ContactField` object's __type__ attribute. For example, a phone -number can specify __type__ values of _home_, _work_, _mobile_, -_iPhone_, or any other value that is supported by a particular device -platform's contact database. However, for the `Contact` __photos__ -field, the __type__ field indicates the format of the returned image: -__url__ when the __value__ attribute contains a URL to the photo -image, or _base64_ when the __value__ contains a base64-encoded image -string. - -### Properties - -- __type__: A string that indicates what type of field this is, _home_ for example. _(DOMString)_ - -- __value__: The value of the field, such as a phone number or email address. _(DOMString)_ - -- __pref__: Set to `true` if this `ContactField` contains the user's preferred value. _(boolean)_ - -### Supported Platforms - -- Amazon Fire OS -- Android -- BlackBerry 10 -- Firefox OS -- iOS -- Windows Phone 7 and 8 -- Windows 8 - -### Example - - // create a new contact - var contact = navigator.contacts.create(); - - // store contact phone numbers in ContactField[] - var phoneNumbers = []; - phoneNumbers[0] = new ContactField('work', '212-555-1234', false); - phoneNumbers[1] = new ContactField('mobile', '917-555-5432', true); // preferred number - phoneNumbers[2] = new ContactField('home', '203-555-7890', false); - contact.phoneNumbers = phoneNumbers; - - // save the contact - contact.save(); - -### Android Quirks - -- __pref__: Not supported, returning `false`. - -### BlackBerry 10 Quirks - -- __type__: Partially supported. Used for phone numbers. - -- __value__: Supported. - -- __pref__: Not supported, returning `false`. - -### iOS Quirks - -- __pref__: Not supported, returning `false`. - -### Windows8 Quirks - -- __pref__: Not supported, returning `false`. - - -## ContactName - -Contains different kinds of information about a `Contact` object's name. - -### Properties - -- __formatted__: The complete name of the contact. _(DOMString)_ - -- __familyName__: The contact's family name. _(DOMString)_ - -- __givenName__: The contact's given name. _(DOMString)_ - -- __middleName__: The contact's middle name. _(DOMString)_ - -- __honorificPrefix__: The contact's prefix (example _Mr._ or _Dr._) _(DOMString)_ - -- __honorificSuffix__: The contact's suffix (example _Esq._). _(DOMString)_ - -### Supported Platforms - -- Amazon Fire OS -- Android 2.X -- BlackBerry 10 -- Firefox OS -- iOS -- Windows Phone 7 and 8 -- Windows 8 - -### Example - - function onSuccess(contacts) { - for (var i = 0; i < contacts.length; i++) { - alert("Formatted: " + contacts[i].name.formatted + "\n" + - "Family Name: " + contacts[i].name.familyName + "\n" + - "Given Name: " + contacts[i].name.givenName + "\n" + - "Middle Name: " + contacts[i].name.middleName + "\n" + - "Suffix: " + contacts[i].name.honorificSuffix + "\n" + - "Prefix: " + contacts[i].name.honorificSuffix); - } - }; - - function onError(contactError) { - alert('onError!'); - }; - - var options = new ContactFindOptions(); - options.filter = ""; - filter = ["displayName", "name"]; - navigator.contacts.find(filter, onSuccess, onError, options); - -### Android Quirks - -- __formatted__: Partially supported, and read-only. Returns a concatenation of `honorificPrefix`, `givenName`, `middleName`, `familyName`, and `honorificSuffix`. - -### BlackBerry 10 Quirks - -- __formatted__: Partially supported. Returns a concatenation of BlackBerry __firstName__ and __lastName__ fields. - -- __familyName__: Supported. Stored in BlackBerry __lastName__ field. - -- __givenName__: Supported. Stored in BlackBerry __firstName__ field. - -- __middleName__: Not supported, returning `null`. - -- __honorificPrefix__: Not supported, returning `null`. - -- __honorificSuffix__: Not supported, returning `null`. - -### FirefoxOS Quirks - -- __formatted__: Partially supported, and read-only. Returns a concatenation of `honorificPrefix`, `givenName`, `middleName`, `familyName`, and `honorificSuffix`. - - -### iOS Quirks - -- __formatted__: Partially supported. Returns iOS Composite Name, but is read-only. - -### Windows 8 Quirks - -- __formatted__: This is the only name property, and is identical to `displayName`, and `nickname` - -- __familyName__: not supported - -- __givenName__: not supported - -- __middleName__: not supported - -- __honorificPrefix__: not supported - -- __honorificSuffix__: not supported - - -## ContactOrganization - -The `ContactOrganization` object stores a contact's organization -properties. A `Contact` object stores one or more -`ContactOrganization` objects in an array. - -### Properties - -- __pref__: Set to `true` if this `ContactOrganization` contains the user's preferred value. _(boolean)_ - -- __type__: A string that indicates what type of field this is, _home_ for example. _(DOMString) - -- __name__: The name of the organization. _(DOMString)_ - -- __department__: The department the contract works for. _(DOMString)_ - -- __title__: The contact's title at the organization. _(DOMString)_ - - -### Supported Platforms - -- Android -- BlackBerry 10 -- Firefox OS -- iOS -- Windows Phone 7 and 8 - -### Example - - function onSuccess(contacts) { - for (var i = 0; i < contacts.length; i++) { - for (var j = 0; j < contacts[i].organizations.length; j++) { - alert("Pref: " + contacts[i].organizations[j].pref + "\n" + - "Type: " + contacts[i].organizations[j].type + "\n" + - "Name: " + contacts[i].organizations[j].name + "\n" + - "Department: " + contacts[i].organizations[j].department + "\n" + - "Title: " + contacts[i].organizations[j].title); - } - } - }; - - function onError(contactError) { - alert('onError!'); - }; - - var options = new ContactFindOptions(); - options.filter = ""; - filter = ["displayName", "organizations"]; - navigator.contacts.find(filter, onSuccess, onError, options); - -### Android 2.X Quirks - -- __pref__: Not supported by Android 2.X devices, returning `false`. - -### BlackBerry 10 Quirks - -- __pref__: Not supported by BlackBerry devices, returning `false`. - -- __type__: Not supported by BlackBerry devices, returning `null`. - -- __name__: Partially supported. The first organization name is stored in the BlackBerry __company__ field. - -- __department__: Not supported, returning `null`. - -- __title__: Partially supported. The first organization title is stored in the BlackBerry __jobTitle__ field. - -### Firefox OS Quirks - -- __pref__: Not supported - -- __type__: Not supported - -- __department__: Not supported - -- Fields __name__ and __title__ stored in __org__ and __jobTitle__. - -### iOS Quirks - -- __pref__: Not supported on iOS devices, returning `false`. - -- __type__: Not supported on iOS devices, returning `null`. - -- __name__: Partially supported. The first organization name is stored in the iOS __kABPersonOrganizationProperty__ field. - -- __department__: Partially supported. The first department name is stored in the iOS __kABPersonDepartmentProperty__ field. - -- __title__: Partially supported. The first title is stored in the iOS __kABPersonJobTitleProperty__ field.
diff --git a/plugin.xml b/plugin.xml deleted file mode 100644 index 676ffd5..0000000 --- a/plugin.xml +++ /dev/null
@@ -1,215 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. ---> - -<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0" - xmlns:rim="http://www.blackberry.com/ns/widgets" - xmlns:android="http://schemas.android.com/apk/res/android" - id="org.apache.cordova.contacts" - version="0.2.11-dev"> - - <name>Contacts</name> - <description>Cordova Contacts Plugin</description> - <license>Apache 2.0</license> - <keywords>cordova,contacts</keywords> - <repo>https://git-wip-us.apache.org/repos/asf/cordova-plugin-contacts.git</repo> - <issue>https://issues.apache.org/jira/browse/CB/component/12320652</issue> - - <js-module src="www/contacts.js" name="contacts"> - <clobbers target="navigator.contacts" /> - </js-module> - - <js-module src="www/Contact.js" name="Contact"> - <clobbers target="Contact" /> - </js-module> - - <js-module src="www/ContactAddress.js" name="ContactAddress"> - <clobbers target="ContactAddress" /> - </js-module> - - <js-module src="www/ContactError.js" name="ContactError"> - <clobbers target="ContactError" /> - </js-module> - - <js-module src="www/ContactField.js" name="ContactField"> - <clobbers target="ContactField" /> - </js-module> - - <js-module src="www/ContactFindOptions.js" name="ContactFindOptions"> - <clobbers target="ContactFindOptions" /> - </js-module> - - <js-module src="www/ContactName.js" name="ContactName"> - <clobbers target="ContactName" /> - </js-module> - - <js-module src="www/ContactOrganization.js" name="ContactOrganization"> - <clobbers target="ContactOrganization" /> - </js-module> - - - - - <!-- android --> - <platform name="android"> - <config-file target="res/xml/config.xml" parent="/*"> - <feature name="Contacts"> - <param name="android-package" value="org.apache.cordova.contacts.ContactManager"/> - </feature> - </config-file> - - <config-file target="AndroidManifest.xml" parent="/*"> - <uses-permission android:name="android.permission.READ_CONTACTS" /> - <uses-permission android:name="android.permission.WRITE_CONTACTS" /> - <uses-permission android:name="android.permission.GET_ACCOUNTS" /> - </config-file> - - <source-file src="src/android/ContactAccessor.java" target-dir="src/org/apache/cordova/contacts" /> - <source-file src="src/android/ContactAccessorSdk5.java" target-dir="src/org/apache/cordova/contacts" /> - <source-file src="src/android/ContactManager.java" target-dir="src/org/apache/cordova/contacts" /> - </platform> - - <!-- amazon-fireos --> - <platform name="amazon-fireos"> - <config-file target="res/xml/config.xml" parent="/*"> - <feature name="Contacts"> - <param name="android-package" value="org.apache.cordova.contacts.ContactManager"/> - </feature> - </config-file> - - <config-file target="AndroidManifest.xml" parent="/*"> - <uses-permission android:name="android.permission.READ_CONTACTS" /> - <uses-permission android:name="android.permission.WRITE_CONTACTS" /> - <uses-permission android:name="android.permission.GET_ACCOUNTS" /> - </config-file> - - <source-file src="src/android/ContactAccessor.java" target-dir="src/org/apache/cordova/contacts" /> - <source-file src="src/android/ContactAccessorSdk5.java" target-dir="src/org/apache/cordova/contacts" /> - <source-file src="src/android/ContactManager.java" target-dir="src/org/apache/cordova/contacts" /> - </platform> - - <!-- ubuntu --> - <platform name="ubuntu"> - <config-file target="config.xml" parent="/*"> - <feature name="Contacts"> - <param policy_group="contacts" policy_version="1" /> - </feature> - </config-file> - <header-file src="src/ubuntu/contacts.h" /> - <source-file src="src/ubuntu/contacts.cpp" /> - </platform> - - <!-- ios --> - <platform name="ios"> - <config-file target="config.xml" parent="/*"> - <feature name="Contacts"> - <param name="ios-package" value="CDVContacts"/> - </feature> - </config-file> - - <js-module src="www/ios/contacts.js" name="contacts-ios"> - <merges target="navigator.contacts" /> - </js-module> - - <js-module src="www/ios/Contact.js" name="Contact-iOS"> - <merges target="Contact" /> - </js-module> - - <header-file src="src/ios/CDVContacts.h" /> - <source-file src="src/ios/CDVContacts.m" /> - <header-file src="src/ios/CDVContact.h" /> - <source-file src="src/ios/CDVContact.m" /> - - <framework src="AddressBook.framework" weak="true" /> - <framework src="AddressBookUI.framework" weak="true" /> - <framework src="CoreGraphics.framework" /> - </platform> - - <!-- blackberry10 --> - <platform name="blackberry10"> - <config-file target="www/config.xml" parent="/widget"> - <feature name="Contacts" value="Contacts"/> - </config-file> - <config-file target="www/config.xml" parent="/widget/rim:permissions"> - <rim:permit>access_pimdomain_contacts</rim:permit> - </config-file> - <source-file src="src/blackberry10/index.js" target-dir="Contacts"></source-file> - <source-file src="src/blackberry10/ContactActivity.js" target-dir="Contacts"></source-file> - <source-file src="src/blackberry10/ContactAddress.js" target-dir="Contacts"></source-file> - <source-file src="src/blackberry10/contactConsts.js" target-dir="Contacts"></source-file> - <source-file src="src/blackberry10/ContactError.js" target-dir="Contacts"></source-file> - <source-file src="src/blackberry10/ContactField.js" target-dir="Contacts"></source-file> - <source-file src="src/blackberry10/ContactFindOptions.js" target-dir="Contacts"></source-file> - <source-file src="src/blackberry10/ContactName.js" target-dir="Contacts"></source-file> - <source-file src="src/blackberry10/ContactNews.js" target-dir="Contacts"></source-file> - <source-file src="src/blackberry10/ContactOrganization.js" target-dir="Contacts"></source-file> - <source-file src="src/blackberry10/ContactPhoto.js" target-dir="Contacts"></source-file> - <source-file src="src/blackberry10/contactUtils.js" target-dir="Contacts"></source-file> - <dependency id="com.blackberry.utils" /> - <dependency id="com.blackberry.pim.lib" /> - </platform> - - <!-- wp7 --> - <platform name="wp7"> - <config-file target="config.xml" parent="/*"> - <feature name="Contacts"> - <param name="wp-package" value="Contacts"/> - </feature> - </config-file> - - <config-file target="Properties/WMAppManifest.xml" parent="/Deployment/App/Capabilities"> - <Capability Name="ID_CAP_CONTACTS" /> - </config-file> - - <source-file src="src/wp/Contacts.cs" /> - </platform> - - <!-- wp8 --> - <platform name="wp8"> - <config-file target="config.xml" parent="/*"> - <feature name="Contacts"> - <param name="wp-package" value="Contacts"/> - </feature> - </config-file> - - <config-file target="Properties/WMAppManifest.xml" parent="/Deployment/App/Capabilities"> - <Capability Name="ID_CAP_CONTACTS" /> - </config-file> - - <source-file src="src/wp/Contacts.cs" /> - </platform> - - <!-- firefoxos --> - <platform name="firefoxos"> - <config-file target="config.xml" parent="/*"> - <feature name="Contacts"> - <param name="firefoxos-package" value="Contacts" /> - </feature> - </config-file> - <js-module src="src/firefoxos/ContactsProxy.js" name="ContactsProxy"> - <runs /> - </js-module> - </platform> - - <!-- wp8 --> - <js-module src="src/windows8/ContactProxy.js" name="ContactProxy"> - <merges target="" /> - </js-module> - -</plugin>
diff --git a/src/android/ContactAccessor.java b/src/android/ContactAccessor.java deleted file mode 100644 index bac243e..0000000 --- a/src/android/ContactAccessor.java +++ /dev/null
@@ -1,196 +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 org.apache.cordova.contacts; - -import java.util.HashMap; - -import android.util.Log; - -import org.apache.cordova.CordovaInterface; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -/** - * This abstract class defines SDK-independent API for communication with - * Contacts Provider. The actual implementation used by the application depends - * on the level of API available on the device. If the API level is Cupcake or - * Donut, we want to use the {@link ContactAccessorSdk3_4} class. If it is - * Eclair or higher, we want to use {@link ContactAccessorSdk5}. - */ -public abstract class ContactAccessor { - - protected final String LOG_TAG = "ContactsAccessor"; - protected CordovaInterface mApp; - - /** - * Check to see if the data associated with the key is required to - * be populated in the Contact object. - * @param key - * @param map created by running buildPopulationSet. - * @return true if the key data is required - */ - protected boolean isRequired(String key, HashMap<String,Boolean> map) { - Boolean retVal = map.get(key); - return (retVal == null) ? false : retVal.booleanValue(); - } - - /** - * Create a hash map of what data needs to be populated in the Contact object - * @param fields the list of fields to populate - * @return the hash map of required data - */ - protected HashMap<String,Boolean> buildPopulationSet(JSONArray fields) { - HashMap<String,Boolean> map = new HashMap<String,Boolean>(); - - String key; - try { - if (fields.length() == 1 && fields.getString(0).equals("*")) { - map.put("displayName", true); - map.put("name", true); - map.put("nickname", true); - map.put("phoneNumbers", true); - map.put("emails", true); - map.put("addresses", true); - map.put("ims", true); - map.put("organizations", true); - map.put("birthday", true); - map.put("note", true); - map.put("urls", true); - map.put("photos", true); - map.put("categories", true); - } - else { - for (int i=0; i<fields.length(); i++) { - key = fields.getString(i); - if (key.startsWith("displayName")) { - map.put("displayName", true); - } - else if (key.startsWith("name")) { - map.put("displayName", true); - map.put("name", true); - } - else if (key.startsWith("nickname")) { - map.put("nickname", true); - } - else if (key.startsWith("phoneNumbers")) { - map.put("phoneNumbers", true); - } - else if (key.startsWith("emails")) { - map.put("emails", true); - } - else if (key.startsWith("addresses")) { - map.put("addresses", true); - } - else if (key.startsWith("ims")) { - map.put("ims", true); - } - else if (key.startsWith("organizations")) { - map.put("organizations", true); - } - else if (key.startsWith("birthday")) { - map.put("birthday", true); - } - else if (key.startsWith("note")) { - map.put("note", true); - } - else if (key.startsWith("urls")) { - map.put("urls", true); - } - else if (key.startsWith("photos")) { - map.put("photos", true); - } - else if (key.startsWith("categories")) { - map.put("categories", true); - } - } - } - } - catch (JSONException e) { - Log.e(LOG_TAG, e.getMessage(), e); - } - return map; - } - - /** - * Convenience method to get a string from a JSON object. Saves a - * lot of try/catch writing. - * If the property is not found in the object null will be returned. - * - * @param obj contact object to search - * @param property to be looked up - * @return The value of the property - */ - protected String getJsonString(JSONObject obj, String property) { - String value = null; - try { - if (obj != null) { - value = obj.getString(property); - if (value.equals("null")) { - Log.d(LOG_TAG, property + " is string called 'null'"); - value = null; - } - } - } - catch (JSONException e) { - Log.d(LOG_TAG, "Could not get = " + e.getMessage()); - } - return value; - } - - /** - * Handles adding a JSON Contact object into the database. - * @return TODO - */ - public abstract String save(JSONObject contact); - - /** - * Handles searching through SDK-specific contacts API. - */ - public abstract JSONArray search(JSONArray filter, JSONObject options); - - /** - * Handles searching through SDK-specific contacts API. - * @throws JSONException - */ - public abstract JSONObject getContactById(String id) throws JSONException; - - /** - * Handles removing a contact from the database. - */ - public abstract boolean remove(String id); - - /** - * A class that represents the where clause to be used in the database query - */ - class WhereOptions { - private String where; - private String[] whereArgs; - public void setWhere(String where) { - this.where = where; - } - public String getWhere() { - return where; - } - public void setWhereArgs(String[] whereArgs) { - this.whereArgs = whereArgs; - } - public String[] getWhereArgs() { - return whereArgs; - } - } -}
diff --git a/src/android/ContactAccessorSdk5.java b/src/android/ContactAccessorSdk5.java deleted file mode 100644 index d8b9592..0000000 --- a/src/android/ContactAccessorSdk5.java +++ /dev/null
@@ -1,2181 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT 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 org.apache.cordova.contacts; - -import android.accounts.Account; -import android.accounts.AccountManager; -import android.content.ContentProviderOperation; -import android.content.ContentProviderResult; -import android.content.ContentUris; -import android.content.ContentValues; -import android.content.OperationApplicationException; -import android.database.Cursor; -import android.net.Uri; -import android.os.RemoteException; -import android.provider.ContactsContract; -import android.util.Log; - -import org.apache.cordova.CordovaInterface; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.io.ByteArrayOutputStream; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; -//import android.app.Activity; -//import android.content.Context; - -/** - * An implementation of {@link ContactAccessor} that uses current Contacts API. - * This class should be used on Eclair or beyond, but would not work on any earlier - * release of Android. As a matter of fact, it could not even be loaded. - * <p> - * This implementation has several advantages: - * <ul> - * <li>It sees contacts from multiple accounts. - * <li>It works with aggregated contacts. So for example, if the contact is the result - * of aggregation of two raw contacts from different accounts, it may return the name from - * one and the phone number from the other. - * <li>It is efficient because it uses the more efficient current API. - * <li>Not obvious in this particular example, but it has access to new kinds - * of data available exclusively through the new APIs. Exercise for the reader: add support - * for nickname (see {@link android.provider.ContactsContract.CommonDataKinds.Nickname}) or - * social status updates (see {@link android.provider.ContactsContract.StatusUpdates}). - * </ul> - */ - -public class ContactAccessorSdk5 extends ContactAccessor { - - /** - * Keep the photo size under the 1 MB blog limit. - */ - private static final long MAX_PHOTO_SIZE = 1048576; - - private static final String EMAIL_REGEXP = ".+@.+\\.+.+"; /* <anything>@<anything>.<anything>*/ - - /** - * A static map that converts the JavaScript property name to Android database column name. - */ - private static final Map<String, String> dbMap = new HashMap<String, String>(); - static { - dbMap.put("id", ContactsContract.Data.CONTACT_ID); - dbMap.put("displayName", ContactsContract.Contacts.DISPLAY_NAME); - dbMap.put("name", ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME); - dbMap.put("name.formatted", ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME); - dbMap.put("name.familyName", ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME); - dbMap.put("name.givenName", ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME); - dbMap.put("name.middleName", ContactsContract.CommonDataKinds.StructuredName.MIDDLE_NAME); - dbMap.put("name.honorificPrefix", ContactsContract.CommonDataKinds.StructuredName.PREFIX); - dbMap.put("name.honorificSuffix", ContactsContract.CommonDataKinds.StructuredName.SUFFIX); - dbMap.put("nickname", ContactsContract.CommonDataKinds.Nickname.NAME); - dbMap.put("phoneNumbers", ContactsContract.CommonDataKinds.Phone.NUMBER); - dbMap.put("phoneNumbers.value", ContactsContract.CommonDataKinds.Phone.NUMBER); - dbMap.put("emails", ContactsContract.CommonDataKinds.Email.DATA); - dbMap.put("emails.value", ContactsContract.CommonDataKinds.Email.DATA); - dbMap.put("addresses", ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS); - dbMap.put("addresses.formatted", ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS); - dbMap.put("addresses.streetAddress", ContactsContract.CommonDataKinds.StructuredPostal.STREET); - dbMap.put("addresses.locality", ContactsContract.CommonDataKinds.StructuredPostal.CITY); - dbMap.put("addresses.region", ContactsContract.CommonDataKinds.StructuredPostal.REGION); - dbMap.put("addresses.postalCode", ContactsContract.CommonDataKinds.StructuredPostal.POSTCODE); - dbMap.put("addresses.country", ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY); - dbMap.put("ims", ContactsContract.CommonDataKinds.Im.DATA); - dbMap.put("ims.value", ContactsContract.CommonDataKinds.Im.DATA); - dbMap.put("organizations", ContactsContract.CommonDataKinds.Organization.COMPANY); - dbMap.put("organizations.name", ContactsContract.CommonDataKinds.Organization.COMPANY); - dbMap.put("organizations.department", ContactsContract.CommonDataKinds.Organization.DEPARTMENT); - dbMap.put("organizations.title", ContactsContract.CommonDataKinds.Organization.TITLE); - dbMap.put("birthday", ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE); - dbMap.put("note", ContactsContract.CommonDataKinds.Note.NOTE); - dbMap.put("photos.value", ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE); - //dbMap.put("categories.value", null); - dbMap.put("urls", ContactsContract.CommonDataKinds.Website.URL); - dbMap.put("urls.value", ContactsContract.CommonDataKinds.Website.URL); - } - - /** - * Create an contact accessor. - */ - public ContactAccessorSdk5(CordovaInterface context) { - mApp = context; - } - - /** - * This method takes the fields required and search options in order to produce an - * array of contacts that matches the criteria provided. - * @param fields an array of items to be used as search criteria - * @param options that can be applied to contact searching - * @return an array of contacts - */ - @Override - public JSONArray search(JSONArray fields, JSONObject options) { - // Get the find options - String searchTerm = ""; - int limit = Integer.MAX_VALUE; - boolean multiple = true; - - if (options != null) { - searchTerm = options.optString("filter"); - if (searchTerm.length() == 0) { - searchTerm = "%"; - } - else { - searchTerm = "%" + searchTerm + "%"; - } - - try { - multiple = options.getBoolean("multiple"); - if (!multiple) { - limit = 1; - } - } catch (JSONException e) { - // Multiple was not specified so we assume the default is true. - } - } - else { - searchTerm = "%"; - } - - - //Log.d(LOG_TAG, "Search Term = " + searchTerm); - //Log.d(LOG_TAG, "Field Length = " + fields.length()); - //Log.d(LOG_TAG, "Fields = " + fields.toString()); - - // Loop through the fields the user provided to see what data should be returned. - HashMap<String, Boolean> populate = buildPopulationSet(fields); - - // Build the ugly where clause and where arguments for one big query. - WhereOptions whereOptions = buildWhereClause(fields, searchTerm); - - // Get all the id's where the search term matches the fields passed in. - Cursor idCursor = mApp.getActivity().getContentResolver().query(ContactsContract.Data.CONTENT_URI, - new String[] { ContactsContract.Data.CONTACT_ID }, - whereOptions.getWhere(), - whereOptions.getWhereArgs(), - ContactsContract.Data.CONTACT_ID + " ASC"); - - // Create a set of unique ids - Set<String> contactIds = new HashSet<String>(); - int idColumn = -1; - while (idCursor.moveToNext()) { - if (idColumn < 0) { - idColumn = idCursor.getColumnIndex(ContactsContract.Data.CONTACT_ID); - } - contactIds.add(idCursor.getString(idColumn)); - } - idCursor.close(); - - // Build a query that only looks at ids - WhereOptions idOptions = buildIdClause(contactIds, searchTerm); - - // Determine which columns we should be fetching. - HashSet<String> columnsToFetch = new HashSet<String>(); - columnsToFetch.add(ContactsContract.Data.CONTACT_ID); - columnsToFetch.add(ContactsContract.Data.RAW_CONTACT_ID); - columnsToFetch.add(ContactsContract.Data.MIMETYPE); - - if (isRequired("displayName", populate)) { - columnsToFetch.add(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME); - } - if (isRequired("name", populate)) { - columnsToFetch.add(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME); - columnsToFetch.add(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME); - columnsToFetch.add(ContactsContract.CommonDataKinds.StructuredName.MIDDLE_NAME); - columnsToFetch.add(ContactsContract.CommonDataKinds.StructuredName.PREFIX); - columnsToFetch.add(ContactsContract.CommonDataKinds.StructuredName.SUFFIX); - } - if (isRequired("phoneNumbers", populate)) { - columnsToFetch.add(ContactsContract.CommonDataKinds.Phone._ID); - columnsToFetch.add(ContactsContract.CommonDataKinds.Phone.NUMBER); - columnsToFetch.add(ContactsContract.CommonDataKinds.Phone.TYPE); - } - if (isRequired("emails", populate)) { - columnsToFetch.add(ContactsContract.CommonDataKinds.Email._ID); - columnsToFetch.add(ContactsContract.CommonDataKinds.Email.DATA); - columnsToFetch.add(ContactsContract.CommonDataKinds.Email.TYPE); - } - if (isRequired("addresses", populate)) { - columnsToFetch.add(ContactsContract.CommonDataKinds.StructuredPostal._ID); - columnsToFetch.add(ContactsContract.CommonDataKinds.Organization.TYPE); - columnsToFetch.add(ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS); - columnsToFetch.add(ContactsContract.CommonDataKinds.StructuredPostal.STREET); - columnsToFetch.add(ContactsContract.CommonDataKinds.StructuredPostal.CITY); - columnsToFetch.add(ContactsContract.CommonDataKinds.StructuredPostal.REGION); - columnsToFetch.add(ContactsContract.CommonDataKinds.StructuredPostal.POSTCODE); - columnsToFetch.add(ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY); - } - if (isRequired("organizations", populate)) { - columnsToFetch.add(ContactsContract.CommonDataKinds.Organization._ID); - columnsToFetch.add(ContactsContract.CommonDataKinds.Organization.TYPE); - columnsToFetch.add(ContactsContract.CommonDataKinds.Organization.DEPARTMENT); - columnsToFetch.add(ContactsContract.CommonDataKinds.Organization.COMPANY); - columnsToFetch.add(ContactsContract.CommonDataKinds.Organization.TITLE); - } - if (isRequired("ims", populate)) { - columnsToFetch.add(ContactsContract.CommonDataKinds.Im._ID); - columnsToFetch.add(ContactsContract.CommonDataKinds.Im.DATA); - columnsToFetch.add(ContactsContract.CommonDataKinds.Im.TYPE); - } - if (isRequired("note", populate)) { - columnsToFetch.add(ContactsContract.CommonDataKinds.Note.NOTE); - } - if (isRequired("nickname", populate)) { - columnsToFetch.add(ContactsContract.CommonDataKinds.Nickname.NAME); - } - if (isRequired("urls", populate)) { - columnsToFetch.add(ContactsContract.CommonDataKinds.Website._ID); - columnsToFetch.add(ContactsContract.CommonDataKinds.Website.URL); - columnsToFetch.add(ContactsContract.CommonDataKinds.Website.TYPE); - } - if (isRequired("birthday", populate)) { - columnsToFetch.add(ContactsContract.CommonDataKinds.Event.START_DATE); - columnsToFetch.add(ContactsContract.CommonDataKinds.Event.TYPE); - } - if (isRequired("photos", populate)) { - columnsToFetch.add(ContactsContract.CommonDataKinds.Photo._ID); - } - - // Do the id query - Cursor c = mApp.getActivity().getContentResolver().query(ContactsContract.Data.CONTENT_URI, - columnsToFetch.toArray(new String[] {}), - idOptions.getWhere(), - idOptions.getWhereArgs(), - ContactsContract.Data.CONTACT_ID + " ASC"); - - JSONArray contacts = populateContactArray(limit, populate, c); - return contacts; - } - - /** - * A special search that finds one contact by id - * - * @param id contact to find by id - * @return a JSONObject representing the contact - * @throws JSONException - */ - public JSONObject getContactById(String id) throws JSONException { - // Do the id query - Cursor c = mApp.getActivity().getContentResolver().query(ContactsContract.Data.CONTENT_URI, - null, - ContactsContract.Data.RAW_CONTACT_ID + " = ? ", - new String[] { id }, - ContactsContract.Data.RAW_CONTACT_ID + " ASC"); - - JSONArray fields = new JSONArray(); - fields.put("*"); - - HashMap<String, Boolean> populate = buildPopulationSet(fields); - - JSONArray contacts = populateContactArray(1, populate, c); - - if (contacts.length() == 1) { - return contacts.getJSONObject(0); - } else { - return null; - } - } - - /** - * Creates an array of contacts from the cursor you pass in - * - * @param limit max number of contacts for the array - * @param populate whether or not you should populate a certain value - * @param c the cursor - * @return a JSONArray of contacts - */ - private JSONArray populateContactArray(int limit, - HashMap<String, Boolean> populate, Cursor c) { - - String contactId = ""; - String rawId = ""; - String oldContactId = ""; - boolean newContact = true; - String mimetype = ""; - - JSONArray contacts = new JSONArray(); - JSONObject contact = new JSONObject(); - JSONArray organizations = new JSONArray(); - JSONArray addresses = new JSONArray(); - JSONArray phones = new JSONArray(); - JSONArray emails = new JSONArray(); - JSONArray ims = new JSONArray(); - JSONArray websites = new JSONArray(); - JSONArray photos = new JSONArray(); - - // Column indices - int colContactId = c.getColumnIndex(ContactsContract.Data.CONTACT_ID); - int colRawContactId = c.getColumnIndex(ContactsContract.Data.RAW_CONTACT_ID); - int colMimetype = c.getColumnIndex(ContactsContract.Data.MIMETYPE); - int colDisplayName = c.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME); - int colNote = c.getColumnIndex(ContactsContract.CommonDataKinds.Note.NOTE); - int colNickname = c.getColumnIndex(ContactsContract.CommonDataKinds.Nickname.NAME); - int colBirthday = c.getColumnIndex(ContactsContract.CommonDataKinds.Event.START_DATE); - int colEventType = c.getColumnIndex(ContactsContract.CommonDataKinds.Event.TYPE); - - if (c.getCount() > 0) { - while (c.moveToNext() && (contacts.length() <= (limit - 1))) { - try { - contactId = c.getString(colContactId); - rawId = c.getString(colRawContactId); - - // If we are in the first row set the oldContactId - if (c.getPosition() == 0) { - oldContactId = contactId; - } - - // When the contact ID changes we need to push the Contact object - // to the array of contacts and create new objects. - if (!oldContactId.equals(contactId)) { - // Populate the Contact object with it's arrays - // and push the contact into the contacts array - contacts.put(populateContact(contact, organizations, addresses, phones, - emails, ims, websites, photos)); - - // Clean up the objects - contact = new JSONObject(); - organizations = new JSONArray(); - addresses = new JSONArray(); - phones = new JSONArray(); - emails = new JSONArray(); - ims = new JSONArray(); - websites = new JSONArray(); - photos = new JSONArray(); - - // Set newContact to true as we are starting to populate a new contact - newContact = true; - } - - // When we detect a new contact set the ID and display name. - // These fields are available in every row in the result set returned. - if (newContact) { - newContact = false; - contact.put("id", contactId); - contact.put("rawId", rawId); - } - - // Grab the mimetype of the current row as it will be used in a lot of comparisons - mimetype = c.getString(colMimetype); - - if (mimetype.equals(ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)) { - contact.put("displayName", c.getString(colDisplayName)); - } - - if (mimetype.equals(ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) - && isRequired("name", populate)) { - contact.put("name", nameQuery(c)); - } - else if (mimetype.equals(ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) - && isRequired("phoneNumbers", populate)) { - phones.put(phoneQuery(c)); - } - else if (mimetype.equals(ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE) - && isRequired("emails", populate)) { - emails.put(emailQuery(c)); - } - else if (mimetype.equals(ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE) - && isRequired("addresses", populate)) { - addresses.put(addressQuery(c)); - } - else if (mimetype.equals(ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE) - && isRequired("organizations", populate)) { - organizations.put(organizationQuery(c)); - } - else if (mimetype.equals(ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE) - && isRequired("ims", populate)) { - ims.put(imQuery(c)); - } - else if (mimetype.equals(ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE) - && isRequired("note", populate)) { - contact.put("note", c.getString(colNote)); - } - else if (mimetype.equals(ContactsContract.CommonDataKinds.Nickname.CONTENT_ITEM_TYPE) - && isRequired("nickname", populate)) { - contact.put("nickname", c.getString(colNickname)); - } - else if (mimetype.equals(ContactsContract.CommonDataKinds.Website.CONTENT_ITEM_TYPE) - && isRequired("urls", populate)) { - websites.put(websiteQuery(c)); - } - else if (mimetype.equals(ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE)) { - if (isRequired("birthday", populate) && - ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY == c.getInt(colEventType)) { - contact.put("birthday", c.getString(colBirthday)); - } - } - else if (mimetype.equals(ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE) - && isRequired("photos", populate)) { - photos.put(photoQuery(c, contactId)); - } - } catch (JSONException e) { - Log.e(LOG_TAG, e.getMessage(), e); - } - - // Set the old contact ID - oldContactId = contactId; - - } - - // Push the last contact into the contacts array - if (contacts.length() < limit) { - contacts.put(populateContact(contact, organizations, addresses, phones, - emails, ims, websites, photos)); - } - } - c.close(); - return contacts; - } - - /** - * Builds a where clause all all the ids passed into the method - * @param contactIds a set of unique contact ids - * @param searchTerm what to search for - * @return an object containing the selection and selection args - */ - private WhereOptions buildIdClause(Set<String> contactIds, String searchTerm) { - WhereOptions options = new WhereOptions(); - - // If the user is searching for every contact then short circuit the method - // and return a shorter where clause to be searched. - if (searchTerm.equals("%")) { - options.setWhere("(" + ContactsContract.Data.CONTACT_ID + " LIKE ? )"); - options.setWhereArgs(new String[] { searchTerm }); - return options; - } - - // This clause means that there are specific ID's to be populated - Iterator<String> it = contactIds.iterator(); - StringBuffer buffer = new StringBuffer("("); - - while (it.hasNext()) { - buffer.append("'" + it.next() + "'"); - if (it.hasNext()) { - buffer.append(","); - } - } - buffer.append(")"); - - options.setWhere(ContactsContract.Data.CONTACT_ID + " IN " + buffer.toString()); - options.setWhereArgs(null); - - return options; - } - - /** - * Create a new contact using a JSONObject to hold all the data. - * @param contact - * @param organizations array of organizations - * @param addresses array of addresses - * @param phones array of phones - * @param emails array of emails - * @param ims array of instant messenger addresses - * @param websites array of websites - * @param photos - * @return - */ - private JSONObject populateContact(JSONObject contact, JSONArray organizations, - JSONArray addresses, JSONArray phones, JSONArray emails, - JSONArray ims, JSONArray websites, JSONArray photos) { - try { - // Only return the array if it has at least one entry - if (organizations.length() > 0) { - contact.put("organizations", organizations); - } - if (addresses.length() > 0) { - contact.put("addresses", addresses); - } - if (phones.length() > 0) { - contact.put("phoneNumbers", phones); - } - if (emails.length() > 0) { - contact.put("emails", emails); - } - if (ims.length() > 0) { - contact.put("ims", ims); - } - if (websites.length() > 0) { - contact.put("urls", websites); - } - if (photos.length() > 0) { - contact.put("photos", photos); - } - } catch (JSONException e) { - Log.e(LOG_TAG, e.getMessage(), e); - } - return contact; - } - - /** - * Take the search criteria passed into the method and create a SQL WHERE clause. - * @param fields the properties to search against - * @param searchTerm the string to search for - * @return an object containing the selection and selection args - */ - private WhereOptions buildWhereClause(JSONArray fields, String searchTerm) { - - ArrayList<String> where = new ArrayList<String>(); - ArrayList<String> whereArgs = new ArrayList<String>(); - - WhereOptions options = new WhereOptions(); - - /* - * Special case where the user wants all fields returned - */ - if (isWildCardSearch(fields)) { - // Get all contacts with all properties - if ("%".equals(searchTerm)) { - options.setWhere("(" + ContactsContract.Contacts.DISPLAY_NAME + " LIKE ? )"); - options.setWhereArgs(new String[] { searchTerm }); - return options; - } else { - // Get all contacts that match the filter but return all properties - where.add("(" + dbMap.get("displayName") + " LIKE ? )"); - whereArgs.add(searchTerm); - where.add("(" + dbMap.get("name") + " LIKE ? AND " - + ContactsContract.Data.MIMETYPE + " = ? )"); - whereArgs.add(searchTerm); - whereArgs.add(ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE); - where.add("(" + dbMap.get("nickname") + " LIKE ? AND " - + ContactsContract.Data.MIMETYPE + " = ? )"); - whereArgs.add(searchTerm); - whereArgs.add(ContactsContract.CommonDataKinds.Nickname.CONTENT_ITEM_TYPE); - where.add("(" + dbMap.get("phoneNumbers") + " LIKE ? AND " - + ContactsContract.Data.MIMETYPE + " = ? )"); - whereArgs.add(searchTerm); - whereArgs.add(ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE); - where.add("(" + dbMap.get("emails") + " LIKE ? AND " - + ContactsContract.Data.MIMETYPE + " = ? )"); - whereArgs.add(searchTerm); - whereArgs.add(ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE); - where.add("(" + dbMap.get("addresses") + " LIKE ? AND " - + ContactsContract.Data.MIMETYPE + " = ? )"); - whereArgs.add(searchTerm); - whereArgs.add(ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE); - where.add("(" + dbMap.get("ims") + " LIKE ? AND " - + ContactsContract.Data.MIMETYPE + " = ? )"); - whereArgs.add(searchTerm); - whereArgs.add(ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE); - where.add("(" + dbMap.get("organizations") + " LIKE ? AND " - + ContactsContract.Data.MIMETYPE + " = ? )"); - whereArgs.add(searchTerm); - whereArgs.add(ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE); - where.add("(" + dbMap.get("note") + " LIKE ? AND " - + ContactsContract.Data.MIMETYPE + " = ? )"); - whereArgs.add(searchTerm); - whereArgs.add(ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE); - where.add("(" + dbMap.get("urls") + " LIKE ? AND " - + ContactsContract.Data.MIMETYPE + " = ? )"); - whereArgs.add(searchTerm); - whereArgs.add(ContactsContract.CommonDataKinds.Website.CONTENT_ITEM_TYPE); - } - } - - /* - * Special case for when the user wants all the contacts but - */ - if ("%".equals(searchTerm)) { - options.setWhere("(" + ContactsContract.Contacts.DISPLAY_NAME + " LIKE ? )"); - options.setWhereArgs(new String[] { searchTerm }); - return options; - } - - String key; - try { - //Log.d(LOG_TAG, "How many fields do we have = " + fields.length()); - for (int i = 0; i < fields.length(); i++) { - key = fields.getString(i); - - if (key.equals("id")) { - where.add("(" + dbMap.get(key) + " = ? )"); - whereArgs.add(searchTerm.substring(1, searchTerm.length() - 1)); - } - else if (key.startsWith("displayName")) { - where.add("(" + dbMap.get(key) + " LIKE ? )"); - whereArgs.add(searchTerm); - } - else if (key.startsWith("name")) { - where.add("(" + dbMap.get(key) + " LIKE ? AND " - + ContactsContract.Data.MIMETYPE + " = ? )"); - whereArgs.add(searchTerm); - whereArgs.add(ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE); - } - else if (key.startsWith("nickname")) { - where.add("(" + dbMap.get(key) + " LIKE ? AND " - + ContactsContract.Data.MIMETYPE + " = ? )"); - whereArgs.add(searchTerm); - whereArgs.add(ContactsContract.CommonDataKinds.Nickname.CONTENT_ITEM_TYPE); - } - else if (key.startsWith("phoneNumbers")) { - where.add("(" + dbMap.get(key) + " LIKE ? AND " - + ContactsContract.Data.MIMETYPE + " = ? )"); - whereArgs.add(searchTerm); - whereArgs.add(ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE); - } - else if (key.startsWith("emails")) { - where.add("(" + dbMap.get(key) + " LIKE ? AND " - + ContactsContract.Data.MIMETYPE + " = ? )"); - whereArgs.add(searchTerm); - whereArgs.add(ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE); - } - else if (key.startsWith("addresses")) { - where.add("(" + dbMap.get(key) + " LIKE ? AND " - + ContactsContract.Data.MIMETYPE + " = ? )"); - whereArgs.add(searchTerm); - whereArgs.add(ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE); - } - else if (key.startsWith("ims")) { - where.add("(" + dbMap.get(key) + " LIKE ? AND " - + ContactsContract.Data.MIMETYPE + " = ? )"); - whereArgs.add(searchTerm); - whereArgs.add(ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE); - } - else if (key.startsWith("organizations")) { - where.add("(" + dbMap.get(key) + " LIKE ? AND " - + ContactsContract.Data.MIMETYPE + " = ? )"); - whereArgs.add(searchTerm); - whereArgs.add(ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE); - } - // else if (key.startsWith("birthday")) { -// where.add("(" + dbMap.get(key) + " LIKE ? AND " -// + ContactsContract.Data.MIMETYPE + " = ? )"); -// } - else if (key.startsWith("note")) { - where.add("(" + dbMap.get(key) + " LIKE ? AND " - + ContactsContract.Data.MIMETYPE + " = ? )"); - whereArgs.add(searchTerm); - whereArgs.add(ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE); - } - else if (key.startsWith("urls")) { - where.add("(" + dbMap.get(key) + " LIKE ? AND " - + ContactsContract.Data.MIMETYPE + " = ? )"); - whereArgs.add(searchTerm); - whereArgs.add(ContactsContract.CommonDataKinds.Website.CONTENT_ITEM_TYPE); - } - } - } catch (JSONException e) { - Log.e(LOG_TAG, e.getMessage(), e); - } - - // Creating the where string - StringBuffer selection = new StringBuffer(); - for (int i = 0; i < where.size(); i++) { - selection.append(where.get(i)); - if (i != (where.size() - 1)) { - selection.append(" OR "); - } - } - options.setWhere(selection.toString()); - - // Creating the where args array - String[] selectionArgs = new String[whereArgs.size()]; - for (int i = 0; i < whereArgs.size(); i++) { - selectionArgs[i] = whereArgs.get(i); - } - options.setWhereArgs(selectionArgs); - - return options; - } - - /** - * If the user passes in the '*' wildcard character for search then they want all fields for each contact - * - * @param fields - * @return true if wildcard search requested, false otherwise - */ - private boolean isWildCardSearch(JSONArray fields) { - // Only do a wildcard search if we are passed ["*"] - if (fields.length() == 1) { - try { - if ("*".equals(fields.getString(0))) { - return true; - } - } catch (JSONException e) { - return false; - } - } - return false; - } - - /** - * Create a ContactOrganization JSONObject - * @param cursor the current database row - * @return a JSONObject representing a ContactOrganization - */ - private JSONObject organizationQuery(Cursor cursor) { - JSONObject organization = new JSONObject(); - try { - organization.put("id", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Organization._ID))); - organization.put("pref", false); // Android does not store pref attribute - organization.put("type", getOrgType(cursor.getInt(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Organization.TYPE)))); - organization.put("department", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Organization.DEPARTMENT))); - organization.put("name", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Organization.COMPANY))); - organization.put("title", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Organization.TITLE))); - } catch (JSONException e) { - Log.e(LOG_TAG, e.getMessage(), e); - } - return organization; - } - - /** - * Create a ContactAddress JSONObject - * @param cursor the current database row - * @return a JSONObject representing a ContactAddress - */ - private JSONObject addressQuery(Cursor cursor) { - JSONObject address = new JSONObject(); - try { - address.put("id", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal._ID))); - address.put("pref", false); // Android does not store pref attribute - address.put("type", getAddressType(cursor.getInt(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Organization.TYPE)))); - address.put("formatted", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS))); - address.put("streetAddress", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.STREET))); - address.put("locality", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.CITY))); - address.put("region", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.REGION))); - address.put("postalCode", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.POSTCODE))); - address.put("country", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY))); - } catch (JSONException e) { - Log.e(LOG_TAG, e.getMessage(), e); - } - return address; - } - - /** - * Create a ContactName JSONObject - * @param cursor the current database row - * @return a JSONObject representing a ContactName - */ - private JSONObject nameQuery(Cursor cursor) { - JSONObject contactName = new JSONObject(); - try { - String familyName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME)); - String givenName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME)); - String middleName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.MIDDLE_NAME)); - String honorificPrefix = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.PREFIX)); - String honorificSuffix = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.SUFFIX)); - - // Create the formatted name - StringBuffer formatted = new StringBuffer(""); - if (honorificPrefix != null) { - formatted.append(honorificPrefix + " "); - } - if (givenName != null) { - formatted.append(givenName + " "); - } - if (middleName != null) { - formatted.append(middleName + " "); - } - if (familyName != null) { - formatted.append(familyName); - } - if (honorificSuffix != null) { - formatted.append(" " + honorificSuffix); - } - - contactName.put("familyName", familyName); - contactName.put("givenName", givenName); - contactName.put("middleName", middleName); - contactName.put("honorificPrefix", honorificPrefix); - contactName.put("honorificSuffix", honorificSuffix); - contactName.put("formatted", formatted); - } catch (JSONException e) { - Log.e(LOG_TAG, e.getMessage(), e); - } - return contactName; - } - - /** - * Create a ContactField JSONObject - * @param cursor the current database row - * @return a JSONObject representing a ContactField - */ - private JSONObject phoneQuery(Cursor cursor) { - JSONObject phoneNumber = new JSONObject(); - try { - phoneNumber.put("id", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone._ID))); - phoneNumber.put("pref", false); // Android does not store pref attribute - phoneNumber.put("value", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER))); - phoneNumber.put("type", getPhoneType(cursor.getInt(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE)))); - } catch (JSONException e) { - Log.e(LOG_TAG, e.getMessage(), e); - } catch (Exception excp) { - Log.e(LOG_TAG, excp.getMessage(), excp); - } - return phoneNumber; - } - - /** - * Create a ContactField JSONObject - * @param cursor the current database row - * @return a JSONObject representing a ContactField - */ - private JSONObject emailQuery(Cursor cursor) { - JSONObject email = new JSONObject(); - try { - email.put("id", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Email._ID))); - email.put("pref", false); // Android does not store pref attribute - email.put("value", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA))); - email.put("type", getContactType(cursor.getInt(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Email.TYPE)))); - } catch (JSONException e) { - Log.e(LOG_TAG, e.getMessage(), e); - } - return email; - } - - /** - * Create a ContactField JSONObject - * @param cursor the current database row - * @return a JSONObject representing a ContactField - */ - private JSONObject imQuery(Cursor cursor) { - JSONObject im = new JSONObject(); - try { - im.put("id", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Im._ID))); - im.put("pref", false); // Android does not store pref attribute - im.put("value", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Im.DATA))); - im.put("type", getImType(cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Im.PROTOCOL)))); - } catch (JSONException e) { - Log.e(LOG_TAG, e.getMessage(), e); - } - return im; - } - - /** - * Create a ContactField JSONObject - * @param cursor the current database row - * @return a JSONObject representing a ContactField - */ - private JSONObject websiteQuery(Cursor cursor) { - JSONObject website = new JSONObject(); - try { - website.put("id", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Website._ID))); - website.put("pref", false); // Android does not store pref attribute - website.put("value", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Website.URL))); - website.put("type", getContactType(cursor.getInt(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Website.TYPE)))); - } catch (JSONException e) { - Log.e(LOG_TAG, e.getMessage(), e); - } - return website; - } - - /** - * Create a ContactField JSONObject - * @param contactId - * @return a JSONObject representing a ContactField - */ - private JSONObject photoQuery(Cursor cursor, String contactId) { - JSONObject photo = new JSONObject(); - try { - photo.put("id", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Photo._ID))); - photo.put("pref", false); - photo.put("type", "url"); - Uri person = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, (new Long(contactId))); - Uri photoUri = Uri.withAppendedPath(person, ContactsContract.Contacts.Photo.CONTENT_DIRECTORY); - photo.put("value", photoUri.toString()); - } catch (JSONException e) { - Log.e(LOG_TAG, e.getMessage(), e); - } - return photo; - } - - @Override - /** - * This method will save a contact object into the devices contacts database. - * - * @param contact the contact to be saved. - * @returns the id if the contact is successfully saved, null otherwise. - */ - public String save(JSONObject contact) { - AccountManager mgr = AccountManager.get(mApp.getActivity()); - Account[] accounts = mgr.getAccounts(); - String accountName = null; - String accountType = null; - - if (accounts.length == 1) { - accountName = accounts[0].name; - accountType = accounts[0].type; - } - else if (accounts.length > 1) { - for (Account a : accounts) { - if (a.type.contains("eas") && a.name.matches(EMAIL_REGEXP)) /*Exchange ActiveSync*/{ - accountName = a.name; - accountType = a.type; - break; - } - } - if (accountName == null) { - for (Account a : accounts) { - if (a.type.contains("com.google") && a.name.matches(EMAIL_REGEXP)) /*Google sync provider*/{ - accountName = a.name; - accountType = a.type; - break; - } - } - } - if (accountName == null) { - for (Account a : accounts) { - if (a.name.matches(EMAIL_REGEXP)) /*Last resort, just look for an email address...*/{ - accountName = a.name; - accountType = a.type; - break; - } - } - } - } - - String id = getJsonString(contact, "id"); - if (id == null) { - // Create new contact - return createNewContact(contact, accountType, accountName); - } else { - // Modify existing contact - return modifyContact(id, contact, accountType, accountName); - } - } - - /** - * Creates a new contact and stores it in the database - * - * @param id the raw contact id which is required for linking items to the contact - * @param contact the contact to be saved - * @param account the account to be saved under - */ - private String modifyContact(String id, JSONObject contact, String accountType, String accountName) { - // Get the RAW_CONTACT_ID which is needed to insert new values in an already existing contact. - // But not needed to update existing values. - int rawId = (new Integer(getJsonString(contact, "rawId"))).intValue(); - - // Create a list of attributes to add to the contact database - ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>(); - - //Add contact type - ops.add(ContentProviderOperation.newUpdate(ContactsContract.RawContacts.CONTENT_URI) - .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, accountType) - .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, accountName) - .build()); - - // Modify name - JSONObject name; - try { - String displayName = getJsonString(contact, "displayName"); - name = contact.getJSONObject("name"); - if (displayName != null || name != null) { - ContentProviderOperation.Builder builder = ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI) - .withSelection(ContactsContract.Data.CONTACT_ID + "=? AND " + - ContactsContract.Data.MIMETYPE + "=?", - new String[] { id, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE }); - - if (displayName != null) { - builder.withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, displayName); - } - - String familyName = getJsonString(name, "familyName"); - if (familyName != null) { - builder.withValue(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME, familyName); - } - String middleName = getJsonString(name, "middleName"); - if (middleName != null) { - builder.withValue(ContactsContract.CommonDataKinds.StructuredName.MIDDLE_NAME, middleName); - } - String givenName = getJsonString(name, "givenName"); - if (givenName != null) { - builder.withValue(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, givenName); - } - String honorificPrefix = getJsonString(name, "honorificPrefix"); - if (honorificPrefix != null) { - builder.withValue(ContactsContract.CommonDataKinds.StructuredName.PREFIX, honorificPrefix); - } - String honorificSuffix = getJsonString(name, "honorificSuffix"); - if (honorificSuffix != null) { - builder.withValue(ContactsContract.CommonDataKinds.StructuredName.SUFFIX, honorificSuffix); - } - - ops.add(builder.build()); - } - } catch (JSONException e1) { - Log.d(LOG_TAG, "Could not get name"); - } - - // Modify phone numbers - JSONArray phones = null; - try { - phones = contact.getJSONArray("phoneNumbers"); - if (phones != null) { - // Delete all the phones - if (phones.length() == 0) { - ops.add(ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI) - .withSelection(ContactsContract.Data.RAW_CONTACT_ID + "=? AND " + - ContactsContract.Data.MIMETYPE + "=?", - new String[] { "" + rawId, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE }) - .build()); - } - // Modify or add a phone - else { - for (int i = 0; i < phones.length(); i++) { - JSONObject phone = (JSONObject) phones.get(i); - String phoneId = getJsonString(phone, "id"); - // This is a new phone so do a DB insert - if (phoneId == null) { - ContentValues contentValues = new ContentValues(); - contentValues.put(ContactsContract.Data.RAW_CONTACT_ID, rawId); - contentValues.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE); - contentValues.put(ContactsContract.CommonDataKinds.Phone.NUMBER, getJsonString(phone, "value")); - contentValues.put(ContactsContract.CommonDataKinds.Phone.TYPE, getPhoneType(getJsonString(phone, "type"))); - - ops.add(ContentProviderOperation.newInsert( - ContactsContract.Data.CONTENT_URI).withValues(contentValues).build()); - } - // This is an existing phone so do a DB update - else { - ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI) - .withSelection(ContactsContract.CommonDataKinds.Phone._ID + "=? AND " + - ContactsContract.Data.MIMETYPE + "=?", - new String[] { phoneId, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE }) - .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, getJsonString(phone, "value")) - .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, getPhoneType(getJsonString(phone, "type"))) - .build()); - } - } - } - } - } catch (JSONException e) { - Log.d(LOG_TAG, "Could not get phone numbers"); - } - - // Modify emails - JSONArray emails = null; - try { - emails = contact.getJSONArray("emails"); - if (emails != null) { - // Delete all the emails - if (emails.length() == 0) { - ops.add(ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI) - .withSelection(ContactsContract.Data.RAW_CONTACT_ID + "=? AND " + - ContactsContract.Data.MIMETYPE + "=?", - new String[] { "" + rawId, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE }) - .build()); - } - // Modify or add a email - else { - for (int i = 0; i < emails.length(); i++) { - JSONObject email = (JSONObject) emails.get(i); - String emailId = getJsonString(email, "id"); - // This is a new email so do a DB insert - if (emailId == null) { - ContentValues contentValues = new ContentValues(); - contentValues.put(ContactsContract.Data.RAW_CONTACT_ID, rawId); - contentValues.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE); - contentValues.put(ContactsContract.CommonDataKinds.Email.DATA, getJsonString(email, "value")); - contentValues.put(ContactsContract.CommonDataKinds.Email.TYPE, getContactType(getJsonString(email, "type"))); - - ops.add(ContentProviderOperation.newInsert( - ContactsContract.Data.CONTENT_URI).withValues(contentValues).build()); - } - // This is an existing email so do a DB update - else { - String emailValue=getJsonString(email, "value"); - if(!emailValue.isEmpty()) { - ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI) - .withSelection(ContactsContract.CommonDataKinds.Email._ID + "=? AND " + - ContactsContract.Data.MIMETYPE + "=?", - new String[] { emailId, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE }) - .withValue(ContactsContract.CommonDataKinds.Email.DATA, getJsonString(email, "value")) - .withValue(ContactsContract.CommonDataKinds.Email.TYPE, getContactType(getJsonString(email, "type"))) - .build()); - } else { - ops.add(ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI) - .withSelection(ContactsContract.CommonDataKinds.Email._ID + "=? AND " + - ContactsContract.Data.MIMETYPE + "=?", - new String[] { emailId, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE }) - .build()); - } - } - } - } - } - } catch (JSONException e) { - Log.d(LOG_TAG, "Could not get emails"); - } - - // Modify addresses - JSONArray addresses = null; - try { - addresses = contact.getJSONArray("addresses"); - if (addresses != null) { - // Delete all the addresses - if (addresses.length() == 0) { - ops.add(ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI) - .withSelection(ContactsContract.Data.RAW_CONTACT_ID + "=? AND " + - ContactsContract.Data.MIMETYPE + "=?", - new String[] { "" + rawId, ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE }) - .build()); - } - // Modify or add a address - else { - for (int i = 0; i < addresses.length(); i++) { - JSONObject address = (JSONObject) addresses.get(i); - String addressId = getJsonString(address, "id"); - // This is a new address so do a DB insert - if (addressId == null) { - ContentValues contentValues = new ContentValues(); - contentValues.put(ContactsContract.Data.RAW_CONTACT_ID, rawId); - contentValues.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE); - contentValues.put(ContactsContract.CommonDataKinds.StructuredPostal.TYPE, getAddressType(getJsonString(address, "type"))); - contentValues.put(ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS, getJsonString(address, "formatted")); - contentValues.put(ContactsContract.CommonDataKinds.StructuredPostal.STREET, getJsonString(address, "streetAddress")); - contentValues.put(ContactsContract.CommonDataKinds.StructuredPostal.CITY, getJsonString(address, "locality")); - contentValues.put(ContactsContract.CommonDataKinds.StructuredPostal.REGION, getJsonString(address, "region")); - contentValues.put(ContactsContract.CommonDataKinds.StructuredPostal.POSTCODE, getJsonString(address, "postalCode")); - contentValues.put(ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY, getJsonString(address, "country")); - - ops.add(ContentProviderOperation.newInsert( - ContactsContract.Data.CONTENT_URI).withValues(contentValues).build()); - } - // This is an existing address so do a DB update - else { - ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI) - .withSelection(ContactsContract.CommonDataKinds.StructuredPostal._ID + "=? AND " + - ContactsContract.Data.MIMETYPE + "=?", - new String[] { addressId, ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE }) - .withValue(ContactsContract.CommonDataKinds.StructuredPostal.TYPE, getAddressType(getJsonString(address, "type"))) - .withValue(ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS, getJsonString(address, "formatted")) - .withValue(ContactsContract.CommonDataKinds.StructuredPostal.STREET, getJsonString(address, "streetAddress")) - .withValue(ContactsContract.CommonDataKinds.StructuredPostal.CITY, getJsonString(address, "locality")) - .withValue(ContactsContract.CommonDataKinds.StructuredPostal.REGION, getJsonString(address, "region")) - .withValue(ContactsContract.CommonDataKinds.StructuredPostal.POSTCODE, getJsonString(address, "postalCode")) - .withValue(ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY, getJsonString(address, "country")) - .build()); - } - } - } - } - } catch (JSONException e) { - Log.d(LOG_TAG, "Could not get addresses"); - } - - // Modify organizations - JSONArray organizations = null; - try { - organizations = contact.getJSONArray("organizations"); - if (organizations != null) { - // Delete all the organizations - if (organizations.length() == 0) { - ops.add(ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI) - .withSelection(ContactsContract.Data.RAW_CONTACT_ID + "=? AND " + - ContactsContract.Data.MIMETYPE + "=?", - new String[] { "" + rawId, ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE }) - .build()); - } - // Modify or add a organization - else { - for (int i = 0; i < organizations.length(); i++) { - JSONObject org = (JSONObject) organizations.get(i); - String orgId = getJsonString(org, "id"); - // This is a new organization so do a DB insert - if (orgId == null) { - ContentValues contentValues = new ContentValues(); - contentValues.put(ContactsContract.Data.RAW_CONTACT_ID, rawId); - contentValues.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE); - contentValues.put(ContactsContract.CommonDataKinds.Organization.TYPE, getOrgType(getJsonString(org, "type"))); - contentValues.put(ContactsContract.CommonDataKinds.Organization.DEPARTMENT, getJsonString(org, "department")); - contentValues.put(ContactsContract.CommonDataKinds.Organization.COMPANY, getJsonString(org, "name")); - contentValues.put(ContactsContract.CommonDataKinds.Organization.TITLE, getJsonString(org, "title")); - - ops.add(ContentProviderOperation.newInsert( - ContactsContract.Data.CONTENT_URI).withValues(contentValues).build()); - } - // This is an existing organization so do a DB update - else { - ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI) - .withSelection(ContactsContract.CommonDataKinds.Organization._ID + "=? AND " + - ContactsContract.Data.MIMETYPE + "=?", - new String[] { orgId, ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE }) - .withValue(ContactsContract.CommonDataKinds.Organization.TYPE, getOrgType(getJsonString(org, "type"))) - .withValue(ContactsContract.CommonDataKinds.Organization.DEPARTMENT, getJsonString(org, "department")) - .withValue(ContactsContract.CommonDataKinds.Organization.COMPANY, getJsonString(org, "name")) - .withValue(ContactsContract.CommonDataKinds.Organization.TITLE, getJsonString(org, "title")) - .build()); - } - } - } - } - } catch (JSONException e) { - Log.d(LOG_TAG, "Could not get organizations"); - } - - // Modify IMs - JSONArray ims = null; - try { - ims = contact.getJSONArray("ims"); - if (ims != null) { - // Delete all the ims - if (ims.length() == 0) { - ops.add(ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI) - .withSelection(ContactsContract.Data.RAW_CONTACT_ID + "=? AND " + - ContactsContract.Data.MIMETYPE + "=?", - new String[] { "" + rawId, ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE }) - .build()); - } - // Modify or add a im - else { - for (int i = 0; i < ims.length(); i++) { - JSONObject im = (JSONObject) ims.get(i); - String imId = getJsonString(im, "id"); - // This is a new IM so do a DB insert - if (imId == null) { - ContentValues contentValues = new ContentValues(); - contentValues.put(ContactsContract.Data.RAW_CONTACT_ID, rawId); - contentValues.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE); - contentValues.put(ContactsContract.CommonDataKinds.Im.DATA, getJsonString(im, "value")); - contentValues.put(ContactsContract.CommonDataKinds.Im.TYPE, getImType(getJsonString(im, "type"))); - - ops.add(ContentProviderOperation.newInsert( - ContactsContract.Data.CONTENT_URI).withValues(contentValues).build()); - } - // This is an existing IM so do a DB update - else { - ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI) - .withSelection(ContactsContract.CommonDataKinds.Im._ID + "=? AND " + - ContactsContract.Data.MIMETYPE + "=?", - new String[] { imId, ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE }) - .withValue(ContactsContract.CommonDataKinds.Im.DATA, getJsonString(im, "value")) - .withValue(ContactsContract.CommonDataKinds.Im.TYPE, getContactType(getJsonString(im, "type"))) - .build()); - } - } - } - } - } catch (JSONException e) { - Log.d(LOG_TAG, "Could not get emails"); - } - - // Modify note - String note = getJsonString(contact, "note"); - ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI) - .withSelection(ContactsContract.Data.CONTACT_ID + "=? AND " + - ContactsContract.Data.MIMETYPE + "=?", - new String[] { id, ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE }) - .withValue(ContactsContract.CommonDataKinds.Note.NOTE, note) - .build()); - - // Modify nickname - String nickname = getJsonString(contact, "nickname"); - if (nickname != null) { - ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI) - .withSelection(ContactsContract.Data.CONTACT_ID + "=? AND " + - ContactsContract.Data.MIMETYPE + "=?", - new String[] { id, ContactsContract.CommonDataKinds.Nickname.CONTENT_ITEM_TYPE }) - .withValue(ContactsContract.CommonDataKinds.Nickname.NAME, nickname) - .build()); - } - - // Modify urls - JSONArray websites = null; - try { - websites = contact.getJSONArray("urls"); - if (websites != null) { - // Delete all the websites - if (websites.length() == 0) { - Log.d(LOG_TAG, "This means we should be deleting all the phone numbers."); - ops.add(ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI) - .withSelection(ContactsContract.Data.RAW_CONTACT_ID + "=? AND " + - ContactsContract.Data.MIMETYPE + "=?", - new String[] { "" + rawId, ContactsContract.CommonDataKinds.Website.CONTENT_ITEM_TYPE }) - .build()); - } - // Modify or add a website - else { - for (int i = 0; i < websites.length(); i++) { - JSONObject website = (JSONObject) websites.get(i); - String websiteId = getJsonString(website, "id"); - // This is a new website so do a DB insert - if (websiteId == null) { - ContentValues contentValues = new ContentValues(); - contentValues.put(ContactsContract.Data.RAW_CONTACT_ID, rawId); - contentValues.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Website.CONTENT_ITEM_TYPE); - contentValues.put(ContactsContract.CommonDataKinds.Website.DATA, getJsonString(website, "value")); - contentValues.put(ContactsContract.CommonDataKinds.Website.TYPE, getContactType(getJsonString(website, "type"))); - - ops.add(ContentProviderOperation.newInsert( - ContactsContract.Data.CONTENT_URI).withValues(contentValues).build()); - } - // This is an existing website so do a DB update - else { - ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI) - .withSelection(ContactsContract.CommonDataKinds.Website._ID + "=? AND " + - ContactsContract.Data.MIMETYPE + "=?", - new String[] { websiteId, ContactsContract.CommonDataKinds.Website.CONTENT_ITEM_TYPE }) - .withValue(ContactsContract.CommonDataKinds.Website.DATA, getJsonString(website, "value")) - .withValue(ContactsContract.CommonDataKinds.Website.TYPE, getContactType(getJsonString(website, "type"))) - .build()); - } - } - } - } - } catch (JSONException e) { - Log.d(LOG_TAG, "Could not get websites"); - } - - // Modify birthday - String birthday = getJsonString(contact, "birthday"); - if (birthday != null) { - ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI) - .withSelection(ContactsContract.Data.CONTACT_ID + "=? AND " + - ContactsContract.Data.MIMETYPE + "=? AND " + - ContactsContract.CommonDataKinds.Event.TYPE + "=?", - new String[] { id, ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE, new String("" + ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY) }) - .withValue(ContactsContract.CommonDataKinds.Event.TYPE, ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY) - .withValue(ContactsContract.CommonDataKinds.Event.START_DATE, birthday) - .build()); - } - - // Modify photos - JSONArray photos = null; - try { - photos = contact.getJSONArray("photos"); - if (photos != null) { - // Delete all the photos - if (photos.length() == 0) { - ops.add(ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI) - .withSelection(ContactsContract.Data.RAW_CONTACT_ID + "=? AND " + - ContactsContract.Data.MIMETYPE + "=?", - new String[] { "" + rawId, ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE }) - .build()); - } - // Modify or add a photo - else { - for (int i = 0; i < photos.length(); i++) { - JSONObject photo = (JSONObject) photos.get(i); - String photoId = getJsonString(photo, "id"); - byte[] bytes = getPhotoBytes(getJsonString(photo, "value")); - // This is a new photo so do a DB insert - if (photoId == null) { - ContentValues contentValues = new ContentValues(); - contentValues.put(ContactsContract.Data.RAW_CONTACT_ID, rawId); - contentValues.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE); - contentValues.put(ContactsContract.Data.IS_SUPER_PRIMARY, 1); - contentValues.put(ContactsContract.CommonDataKinds.Photo.PHOTO, bytes); - - ops.add(ContentProviderOperation.newInsert( - ContactsContract.Data.CONTENT_URI).withValues(contentValues).build()); - } - // This is an existing photo so do a DB update - else { - ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI) - .withSelection(ContactsContract.CommonDataKinds.Photo._ID + "=? AND " + - ContactsContract.Data.MIMETYPE + "=?", - new String[] { photoId, ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE }) - .withValue(ContactsContract.Data.IS_SUPER_PRIMARY, 1) - .withValue(ContactsContract.CommonDataKinds.Photo.PHOTO, bytes) - .build()); - } - } - } - } - } catch (JSONException e) { - Log.d(LOG_TAG, "Could not get photos"); - } - - boolean retVal = true; - - //Modify contact - try { - mApp.getActivity().getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops); - } catch (RemoteException e) { - Log.e(LOG_TAG, e.getMessage(), e); - Log.e(LOG_TAG, Log.getStackTraceString(e), e); - retVal = false; - } catch (OperationApplicationException e) { - Log.e(LOG_TAG, e.getMessage(), e); - Log.e(LOG_TAG, Log.getStackTraceString(e), e); - retVal = false; - } - - // if the save was a success return the contact ID - if (retVal) { - return id; - } else { - return null; - } - } - - /** - * Add a website to a list of database actions to be performed - * - * @param ops the list of database actions - * @param website the item to be inserted - */ - private void insertWebsite(ArrayList<ContentProviderOperation> ops, - JSONObject website) { - ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) - .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) - .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Website.CONTENT_ITEM_TYPE) - .withValue(ContactsContract.CommonDataKinds.Website.DATA, getJsonString(website, "value")) - .withValue(ContactsContract.CommonDataKinds.Website.TYPE, getContactType(getJsonString(website, "type"))) - .build()); - } - - /** - * Add an im to a list of database actions to be performed - * - * @param ops the list of database actions - * @param im the item to be inserted - */ - private void insertIm(ArrayList<ContentProviderOperation> ops, JSONObject im) { - ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) - .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) - .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE) - .withValue(ContactsContract.CommonDataKinds.Im.DATA, getJsonString(im, "value")) - .withValue(ContactsContract.CommonDataKinds.Im.TYPE, getImType(getJsonString(im, "type"))) - .build()); - } - - /** - * Add an organization to a list of database actions to be performed - * - * @param ops the list of database actions - * @param org the item to be inserted - */ - private void insertOrganization(ArrayList<ContentProviderOperation> ops, - JSONObject org) { - ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) - .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) - .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE) - .withValue(ContactsContract.CommonDataKinds.Organization.TYPE, getOrgType(getJsonString(org, "type"))) - .withValue(ContactsContract.CommonDataKinds.Organization.DEPARTMENT, getJsonString(org, "department")) - .withValue(ContactsContract.CommonDataKinds.Organization.COMPANY, getJsonString(org, "name")) - .withValue(ContactsContract.CommonDataKinds.Organization.TITLE, getJsonString(org, "title")) - .build()); - } - - /** - * Add an address to a list of database actions to be performed - * - * @param ops the list of database actions - * @param address the item to be inserted - */ - private void insertAddress(ArrayList<ContentProviderOperation> ops, - JSONObject address) { - ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) - .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) - .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE) - .withValue(ContactsContract.CommonDataKinds.StructuredPostal.TYPE, getAddressType(getJsonString(address, "type"))) - .withValue(ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS, getJsonString(address, "formatted")) - .withValue(ContactsContract.CommonDataKinds.StructuredPostal.STREET, getJsonString(address, "streetAddress")) - .withValue(ContactsContract.CommonDataKinds.StructuredPostal.CITY, getJsonString(address, "locality")) - .withValue(ContactsContract.CommonDataKinds.StructuredPostal.REGION, getJsonString(address, "region")) - .withValue(ContactsContract.CommonDataKinds.StructuredPostal.POSTCODE, getJsonString(address, "postalCode")) - .withValue(ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY, getJsonString(address, "country")) - .build()); - } - - /** - * Add an email to a list of database actions to be performed - * - * @param ops the list of database actions - * @param email the item to be inserted - */ - private void insertEmail(ArrayList<ContentProviderOperation> ops, - JSONObject email) { - ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) - .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) - .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE) - .withValue(ContactsContract.CommonDataKinds.Email.DATA, getJsonString(email, "value")) - .withValue(ContactsContract.CommonDataKinds.Email.TYPE, getContactType(getJsonString(email, "type"))) - .build()); - } - - /** - * Add a phone to a list of database actions to be performed - * - * @param ops the list of database actions - * @param phone the item to be inserted - */ - private void insertPhone(ArrayList<ContentProviderOperation> ops, - JSONObject phone) { - ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) - .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) - .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) - .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, getJsonString(phone, "value")) - .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, getPhoneType(getJsonString(phone, "type"))) - .build()); - } - - /** - * Add a phone to a list of database actions to be performed - * - * @param ops the list of database actions - * @param phone the item to be inserted - */ - private void insertPhoto(ArrayList<ContentProviderOperation> ops, - JSONObject photo) { - byte[] bytes = getPhotoBytes(getJsonString(photo, "value")); - ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) - .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) - .withValue(ContactsContract.Data.IS_SUPER_PRIMARY, 1) - .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE) - .withValue(ContactsContract.CommonDataKinds.Photo.PHOTO, bytes) - .build()); - } - - /** - * Gets the raw bytes from the supplied filename - * - * @param filename the file to read the bytes from - * @return a byte array - * @throws IOException - */ - private byte[] getPhotoBytes(String filename) { - ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - try { - int bytesRead = 0; - long totalBytesRead = 0; - byte[] data = new byte[8192]; - InputStream in = getPathFromUri(filename); - - while ((bytesRead = in.read(data, 0, data.length)) != -1 && totalBytesRead <= MAX_PHOTO_SIZE) { - buffer.write(data, 0, bytesRead); - totalBytesRead += bytesRead; - } - - in.close(); - buffer.flush(); - } catch (FileNotFoundException e) { - Log.e(LOG_TAG, e.getMessage(), e); - } catch (IOException e) { - Log.e(LOG_TAG, e.getMessage(), e); - } - return buffer.toByteArray(); - } - - /** - * Get an input stream based on file path or uri content://, http://, file:// - * - * @param path - * @return an input stream - * @throws IOException - */ - private InputStream getPathFromUri(String path) throws IOException { - if (path.startsWith("content:")) { - Uri uri = Uri.parse(path); - return mApp.getActivity().getContentResolver().openInputStream(uri); - } - if (path.startsWith("http:") || path.startsWith("https:") || path.startsWith("file:")) { - URL url = new URL(path); - return url.openStream(); - } - else { - return new FileInputStream(path); - } - } - - /** - * Creates a new contact and stores it in the database - * - * @param contact the contact to be saved - * @param account the account to be saved under - */ - private String createNewContact(JSONObject contact, String accountType, String accountName) { - // Create a list of attributes to add to the contact database - ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>(); - - //Add contact type - ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI) - .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, accountType) - .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, accountName) - .build()); - - // Add name - try { - JSONObject name = contact.optJSONObject("name"); - String displayName = contact.getString("displayName"); - if (displayName != null || name != null) { - ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) - .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) - .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) - .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, displayName) - .withValue(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME, getJsonString(name, "familyName")) - .withValue(ContactsContract.CommonDataKinds.StructuredName.MIDDLE_NAME, getJsonString(name, "middleName")) - .withValue(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, getJsonString(name, "givenName")) - .withValue(ContactsContract.CommonDataKinds.StructuredName.PREFIX, getJsonString(name, "honorificPrefix")) - .withValue(ContactsContract.CommonDataKinds.StructuredName.SUFFIX, getJsonString(name, "honorificSuffix")) - .build()); - } - } catch (JSONException e) { - Log.d(LOG_TAG, "Could not get name object"); - } - - //Add phone numbers - JSONArray phones = null; - try { - phones = contact.getJSONArray("phoneNumbers"); - if (phones != null) { - for (int i = 0; i < phones.length(); i++) { - JSONObject phone = (JSONObject) phones.get(i); - insertPhone(ops, phone); - } - } - } catch (JSONException e) { - Log.d(LOG_TAG, "Could not get phone numbers"); - } - - // Add emails - JSONArray emails = null; - try { - emails = contact.getJSONArray("emails"); - if (emails != null) { - for (int i = 0; i < emails.length(); i++) { - JSONObject email = (JSONObject) emails.get(i); - insertEmail(ops, email); - } - } - } catch (JSONException e) { - Log.d(LOG_TAG, "Could not get emails"); - } - - // Add addresses - JSONArray addresses = null; - try { - addresses = contact.getJSONArray("addresses"); - if (addresses != null) { - for (int i = 0; i < addresses.length(); i++) { - JSONObject address = (JSONObject) addresses.get(i); - insertAddress(ops, address); - } - } - } catch (JSONException e) { - Log.d(LOG_TAG, "Could not get addresses"); - } - - // Add organizations - JSONArray organizations = null; - try { - organizations = contact.getJSONArray("organizations"); - if (organizations != null) { - for (int i = 0; i < organizations.length(); i++) { - JSONObject org = (JSONObject) organizations.get(i); - insertOrganization(ops, org); - } - } - } catch (JSONException e) { - Log.d(LOG_TAG, "Could not get organizations"); - } - - // Add IMs - JSONArray ims = null; - try { - ims = contact.getJSONArray("ims"); - if (ims != null) { - for (int i = 0; i < ims.length(); i++) { - JSONObject im = (JSONObject) ims.get(i); - insertIm(ops, im); - } - } - } catch (JSONException e) { - Log.d(LOG_TAG, "Could not get emails"); - } - - // Add note - String note = getJsonString(contact, "note"); - if (note != null) { - ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) - .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) - .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE) - .withValue(ContactsContract.CommonDataKinds.Note.NOTE, note) - .build()); - } - - // Add nickname - String nickname = getJsonString(contact, "nickname"); - if (nickname != null) { - ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) - .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) - .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Nickname.CONTENT_ITEM_TYPE) - .withValue(ContactsContract.CommonDataKinds.Nickname.NAME, nickname) - .build()); - } - - // Add urls - JSONArray websites = null; - try { - websites = contact.getJSONArray("urls"); - if (websites != null) { - for (int i = 0; i < websites.length(); i++) { - JSONObject website = (JSONObject) websites.get(i); - insertWebsite(ops, website); - } - } - } catch (JSONException e) { - Log.d(LOG_TAG, "Could not get websites"); - } - - // Add birthday - String birthday = getJsonString(contact, "birthday"); - if (birthday != null) { - ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) - .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) - .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE) - .withValue(ContactsContract.CommonDataKinds.Event.TYPE, ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY) - .withValue(ContactsContract.CommonDataKinds.Event.START_DATE, birthday) - .build()); - } - - // Add photos - JSONArray photos = null; - try { - photos = contact.getJSONArray("photos"); - if (photos != null) { - for (int i = 0; i < photos.length(); i++) { - JSONObject photo = (JSONObject) photos.get(i); - insertPhoto(ops, photo); - } - } - } catch (JSONException e) { - Log.d(LOG_TAG, "Could not get photos"); - } - - String newId = null; - //Add contact - try { - ContentProviderResult[] cpResults = mApp.getActivity().getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops); - if (cpResults.length >= 0) { - newId = cpResults[0].uri.getLastPathSegment(); - } - } catch (RemoteException e) { - Log.e(LOG_TAG, e.getMessage(), e); - } catch (OperationApplicationException e) { - Log.e(LOG_TAG, e.getMessage(), e); - } - return newId; - } - - @Override - /** - * This method will remove a Contact from the database based on ID. - * @param id the unique ID of the contact to remove - */ - public boolean remove(String id) { - int result = 0; - Cursor cursor = mApp.getActivity().getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, - null, - ContactsContract.Contacts._ID + " = ?", - new String[] { id }, null); - if (cursor.getCount() == 1) { - cursor.moveToFirst(); - String lookupKey = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY)); - Uri uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_LOOKUP_URI, lookupKey); - result = mApp.getActivity().getContentResolver().delete(uri, null, null); - } else { - Log.d(LOG_TAG, "Could not find contact with ID"); - } - - return (result > 0) ? true : false; - } - - /************************************************************************** - * - * All methods below this comment are used to convert from JavaScript - * text types to Android integer types and vice versa. - * - *************************************************************************/ - - /** - * Converts a string from the W3C Contact API to it's Android int value. - * @param string - * @return Android int value - */ - private int getPhoneType(String string) { - int type = ContactsContract.CommonDataKinds.Phone.TYPE_OTHER; - if (string != null) { - if ("home".equals(string.toLowerCase())) { - return ContactsContract.CommonDataKinds.Phone.TYPE_HOME; - } - else if ("mobile".equals(string.toLowerCase())) { - return ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE; - } - else if ("work".equals(string.toLowerCase())) { - return ContactsContract.CommonDataKinds.Phone.TYPE_WORK; - } - else if ("work fax".equals(string.toLowerCase())) { - return ContactsContract.CommonDataKinds.Phone.TYPE_FAX_WORK; - } - else if ("home fax".equals(string.toLowerCase())) { - return ContactsContract.CommonDataKinds.Phone.TYPE_FAX_HOME; - } - else if ("fax".equals(string.toLowerCase())) { - return ContactsContract.CommonDataKinds.Phone.TYPE_FAX_WORK; - } - else if ("pager".equals(string.toLowerCase())) { - return ContactsContract.CommonDataKinds.Phone.TYPE_PAGER; - } - else if ("other".equals(string.toLowerCase())) { - return ContactsContract.CommonDataKinds.Phone.TYPE_OTHER; - } - else if ("car".equals(string.toLowerCase())) { - return ContactsContract.CommonDataKinds.Phone.TYPE_CAR; - } - else if ("company main".equals(string.toLowerCase())) { - return ContactsContract.CommonDataKinds.Phone.TYPE_COMPANY_MAIN; - } - else if ("isdn".equals(string.toLowerCase())) { - return ContactsContract.CommonDataKinds.Phone.TYPE_ISDN; - } - else if ("main".equals(string.toLowerCase())) { - return ContactsContract.CommonDataKinds.Phone.TYPE_MAIN; - } - else if ("other fax".equals(string.toLowerCase())) { - return ContactsContract.CommonDataKinds.Phone.TYPE_OTHER_FAX; - } - else if ("radio".equals(string.toLowerCase())) { - return ContactsContract.CommonDataKinds.Phone.TYPE_RADIO; - } - else if ("telex".equals(string.toLowerCase())) { - return ContactsContract.CommonDataKinds.Phone.TYPE_TELEX; - } - else if ("work mobile".equals(string.toLowerCase())) { - return ContactsContract.CommonDataKinds.Phone.TYPE_WORK_MOBILE; - } - else if ("work pager".equals(string.toLowerCase())) { - return ContactsContract.CommonDataKinds.Phone.TYPE_WORK_PAGER; - } - else if ("assistant".equals(string.toLowerCase())) { - return ContactsContract.CommonDataKinds.Phone.TYPE_ASSISTANT; - } - else if ("mms".equals(string.toLowerCase())) { - return ContactsContract.CommonDataKinds.Phone.TYPE_MMS; - } - else if ("callback".equals(string.toLowerCase())) { - return ContactsContract.CommonDataKinds.Phone.TYPE_CALLBACK; - } - else if ("tty ttd".equals(string.toLowerCase())) { - return ContactsContract.CommonDataKinds.Phone.TYPE_TTY_TDD; - } - else if ("custom".equals(string.toLowerCase())) { - return ContactsContract.CommonDataKinds.Phone.TYPE_CUSTOM; - } - } - return type; - } - - /** - * getPhoneType converts an Android phone type into a string - * @param type - * @return phone type as string. - */ - private String getPhoneType(int type) { - String stringType; - switch (type) { - case ContactsContract.CommonDataKinds.Phone.TYPE_CUSTOM: - stringType = "custom"; - break; - case ContactsContract.CommonDataKinds.Phone.TYPE_FAX_HOME: - stringType = "home fax"; - break; - case ContactsContract.CommonDataKinds.Phone.TYPE_FAX_WORK: - stringType = "work fax"; - break; - case ContactsContract.CommonDataKinds.Phone.TYPE_HOME: - stringType = "home"; - break; - case ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE: - stringType = "mobile"; - break; - case ContactsContract.CommonDataKinds.Phone.TYPE_PAGER: - stringType = "pager"; - break; - case ContactsContract.CommonDataKinds.Phone.TYPE_WORK: - stringType = "work"; - break; - case ContactsContract.CommonDataKinds.Phone.TYPE_CALLBACK: - stringType = "callback"; - break; - case ContactsContract.CommonDataKinds.Phone.TYPE_CAR: - stringType = "car"; - break; - case ContactsContract.CommonDataKinds.Phone.TYPE_COMPANY_MAIN: - stringType = "company main"; - break; - case ContactsContract.CommonDataKinds.Phone.TYPE_OTHER_FAX: - stringType = "other fax"; - break; - case ContactsContract.CommonDataKinds.Phone.TYPE_RADIO: - stringType = "radio"; - break; - case ContactsContract.CommonDataKinds.Phone.TYPE_TELEX: - stringType = "telex"; - break; - case ContactsContract.CommonDataKinds.Phone.TYPE_TTY_TDD: - stringType = "tty tdd"; - break; - case ContactsContract.CommonDataKinds.Phone.TYPE_WORK_MOBILE: - stringType = "work mobile"; - break; - case ContactsContract.CommonDataKinds.Phone.TYPE_WORK_PAGER: - stringType = "work pager"; - break; - case ContactsContract.CommonDataKinds.Phone.TYPE_ASSISTANT: - stringType = "assistant"; - break; - case ContactsContract.CommonDataKinds.Phone.TYPE_MMS: - stringType = "mms"; - break; - case ContactsContract.CommonDataKinds.Phone.TYPE_ISDN: - stringType = "isdn"; - break; - case ContactsContract.CommonDataKinds.Phone.TYPE_OTHER: - default: - stringType = "other"; - break; - } - return stringType; - } - - /** - * Converts a string from the W3C Contact API to it's Android int value. - * @param string - * @return Android int value - */ - private int getContactType(String string) { - int type = ContactsContract.CommonDataKinds.Email.TYPE_OTHER; - if (string != null) { - if ("home".equals(string.toLowerCase())) { - return ContactsContract.CommonDataKinds.Email.TYPE_HOME; - } - else if ("work".equals(string.toLowerCase())) { - return ContactsContract.CommonDataKinds.Email.TYPE_WORK; - } - else if ("other".equals(string.toLowerCase())) { - return ContactsContract.CommonDataKinds.Email.TYPE_OTHER; - } - else if ("mobile".equals(string.toLowerCase())) { - return ContactsContract.CommonDataKinds.Email.TYPE_MOBILE; - } - else if ("custom".equals(string.toLowerCase())) { - return ContactsContract.CommonDataKinds.Email.TYPE_CUSTOM; - } - } - return type; - } - - /** - * getPhoneType converts an Android phone type into a string - * @param type - * @return phone type as string. - */ - private String getContactType(int type) { - String stringType; - switch (type) { - case ContactsContract.CommonDataKinds.Email.TYPE_CUSTOM: - stringType = "custom"; - break; - case ContactsContract.CommonDataKinds.Email.TYPE_HOME: - stringType = "home"; - break; - case ContactsContract.CommonDataKinds.Email.TYPE_WORK: - stringType = "work"; - break; - case ContactsContract.CommonDataKinds.Email.TYPE_MOBILE: - stringType = "mobile"; - break; - case ContactsContract.CommonDataKinds.Email.TYPE_OTHER: - default: - stringType = "other"; - break; - } - return stringType; - } - - /** - * Converts a string from the W3C Contact API to it's Android int value. - * @param string - * @return Android int value - */ - private int getOrgType(String string) { - int type = ContactsContract.CommonDataKinds.Organization.TYPE_OTHER; - if (string != null) { - if ("work".equals(string.toLowerCase())) { - return ContactsContract.CommonDataKinds.Organization.TYPE_WORK; - } - else if ("other".equals(string.toLowerCase())) { - return ContactsContract.CommonDataKinds.Organization.TYPE_OTHER; - } - else if ("custom".equals(string.toLowerCase())) { - return ContactsContract.CommonDataKinds.Organization.TYPE_CUSTOM; - } - } - return type; - } - - /** - * getPhoneType converts an Android phone type into a string - * @param type - * @return phone type as string. - */ - private String getOrgType(int type) { - String stringType; - switch (type) { - case ContactsContract.CommonDataKinds.Organization.TYPE_CUSTOM: - stringType = "custom"; - break; - case ContactsContract.CommonDataKinds.Organization.TYPE_WORK: - stringType = "work"; - break; - case ContactsContract.CommonDataKinds.Organization.TYPE_OTHER: - default: - stringType = "other"; - break; - } - return stringType; - } - - /** - * Converts a string from the W3C Contact API to it's Android int value. - * @param string - * @return Android int value - */ - private int getAddressType(String string) { - int type = ContactsContract.CommonDataKinds.StructuredPostal.TYPE_OTHER; - if (string != null) { - if ("work".equals(string.toLowerCase())) { - return ContactsContract.CommonDataKinds.StructuredPostal.TYPE_WORK; - } - else if ("other".equals(string.toLowerCase())) { - return ContactsContract.CommonDataKinds.StructuredPostal.TYPE_OTHER; - } - else if ("home".equals(string.toLowerCase())) { - return ContactsContract.CommonDataKinds.StructuredPostal.TYPE_HOME; - } - } - return type; - } - - /** - * getPhoneType converts an Android phone type into a string - * @param type - * @return phone type as string. - */ - private String getAddressType(int type) { - String stringType; - switch (type) { - case ContactsContract.CommonDataKinds.StructuredPostal.TYPE_HOME: - stringType = "home"; - break; - case ContactsContract.CommonDataKinds.StructuredPostal.TYPE_WORK: - stringType = "work"; - break; - case ContactsContract.CommonDataKinds.StructuredPostal.TYPE_OTHER: - default: - stringType = "other"; - break; - } - return stringType; - } - - /** - * Converts a string from the W3C Contact API to it's Android int value. - * @param string - * @return Android int value - */ - private int getImType(String string) { - int type = ContactsContract.CommonDataKinds.Im.PROTOCOL_CUSTOM; - if (string != null) { - if ("aim".equals(string.toLowerCase())) { - return ContactsContract.CommonDataKinds.Im.PROTOCOL_AIM; - } - else if ("google talk".equals(string.toLowerCase())) { - return ContactsContract.CommonDataKinds.Im.PROTOCOL_GOOGLE_TALK; - } - else if ("icq".equals(string.toLowerCase())) { - return ContactsContract.CommonDataKinds.Im.PROTOCOL_ICQ; - } - else if ("jabber".equals(string.toLowerCase())) { - return ContactsContract.CommonDataKinds.Im.PROTOCOL_JABBER; - } - else if ("msn".equals(string.toLowerCase())) { - return ContactsContract.CommonDataKinds.Im.PROTOCOL_MSN; - } - else if ("netmeeting".equals(string.toLowerCase())) { - return ContactsContract.CommonDataKinds.Im.PROTOCOL_NETMEETING; - } - else if ("qq".equals(string.toLowerCase())) { - return ContactsContract.CommonDataKinds.Im.PROTOCOL_QQ; - } - else if ("skype".equals(string.toLowerCase())) { - return ContactsContract.CommonDataKinds.Im.PROTOCOL_SKYPE; - } - else if ("yahoo".equals(string.toLowerCase())) { - return ContactsContract.CommonDataKinds.Im.PROTOCOL_YAHOO; - } - } - return type; - } - - /** - * getPhoneType converts an Android phone type into a string - * @param type - * @return phone type as string. - */ - @SuppressWarnings("unused") - private String getImType(int type) { - String stringType; - switch (type) { - case ContactsContract.CommonDataKinds.Im.PROTOCOL_AIM: - stringType = "AIM"; - break; - case ContactsContract.CommonDataKinds.Im.PROTOCOL_GOOGLE_TALK: - stringType = "Google Talk"; - break; - case ContactsContract.CommonDataKinds.Im.PROTOCOL_ICQ: - stringType = "ICQ"; - break; - case ContactsContract.CommonDataKinds.Im.PROTOCOL_JABBER: - stringType = "Jabber"; - break; - case ContactsContract.CommonDataKinds.Im.PROTOCOL_MSN: - stringType = "MSN"; - break; - case ContactsContract.CommonDataKinds.Im.PROTOCOL_NETMEETING: - stringType = "NetMeeting"; - break; - case ContactsContract.CommonDataKinds.Im.PROTOCOL_QQ: - stringType = "QQ"; - break; - case ContactsContract.CommonDataKinds.Im.PROTOCOL_SKYPE: - stringType = "Skype"; - break; - case ContactsContract.CommonDataKinds.Im.PROTOCOL_YAHOO: - stringType = "Yahoo"; - break; - default: - stringType = "custom"; - break; - } - return stringType; - } -} -
diff --git a/src/android/ContactManager.java b/src/android/ContactManager.java deleted file mode 100644 index a50d799..0000000 --- a/src/android/ContactManager.java +++ /dev/null
@@ -1,122 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT 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 org.apache.cordova.contacts; - -import org.apache.cordova.CallbackContext; -import org.apache.cordova.CordovaPlugin; -import org.apache.cordova.PluginResult; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import android.util.Log; - -public class ContactManager extends CordovaPlugin { - - private ContactAccessor contactAccessor; - private static final String LOG_TAG = "Contact Query"; - - public static final int UNKNOWN_ERROR = 0; - public static final int INVALID_ARGUMENT_ERROR = 1; - public static final int TIMEOUT_ERROR = 2; - public static final int PENDING_OPERATION_ERROR = 3; - public static final int IO_ERROR = 4; - public static final int NOT_SUPPORTED_ERROR = 5; - public static final int PERMISSION_DENIED_ERROR = 20; - - /** - * Constructor. - */ - public ContactManager() { - } - - /** - * Executes the request and returns PluginResult. - * - * @param action The action to execute. - * @param args JSONArray of arguments for the plugin. - * @param callbackContext The callback context used when calling back into JavaScript. - * @return True if the action was valid, false otherwise. - */ - public boolean execute(String action, JSONArray args, final CallbackContext callbackContext) throws JSONException { - /** - * Check to see if we are on an Android 1.X device. If we are return an error as we - * do not support this as of Cordova 1.0. - */ - if (android.os.Build.VERSION.RELEASE.startsWith("1.")) { - callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, ContactManager.NOT_SUPPORTED_ERROR)); - return true; - } - - /** - * Only create the contactAccessor after we check the Android version or the program will crash - * older phones. - */ - if (this.contactAccessor == null) { - this.contactAccessor = new ContactAccessorSdk5(this.cordova); - } - - if (action.equals("search")) { - final JSONArray filter = args.getJSONArray(0); - final JSONObject options = args.getJSONObject(1); - this.cordova.getThreadPool().execute(new Runnable() { - public void run() { - JSONArray res = contactAccessor.search(filter, options); - callbackContext.success(res); - } - }); - } - else if (action.equals("save")) { - final JSONObject contact = args.getJSONObject(0); - this.cordova.getThreadPool().execute(new Runnable() { - public void run() { - JSONObject res = null; - String id = contactAccessor.save(contact); - if (id != null) { - try { - res = contactAccessor.getContactById(id); - } catch (JSONException e) { - Log.e(LOG_TAG, "JSON fail.", e); - } - } - if (res != null) { - callbackContext.success(res); - } else { - callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, UNKNOWN_ERROR)); - } - } - }); - } - else if (action.equals("remove")) { - final String contactId = args.getString(0); - this.cordova.getThreadPool().execute(new Runnable() { - public void run() { - if (contactAccessor.remove(contactId)) { - callbackContext.success(); - } else { - callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, UNKNOWN_ERROR)); - } - } - }); - } - else { - return false; - } - return true; - } -}
diff --git a/src/blackberry10/ContactActivity.js b/src/blackberry10/ContactActivity.js deleted file mode 100644 index 0205194..0000000 --- a/src/blackberry10/ContactActivity.js +++ /dev/null
@@ -1,31 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * -*/ -var ContactActivity = function (args) { - this.direction = args.direction || null; - this.description = args.description || ""; - this.mimeType = args.mimeType || ""; - this.timestamp = new Date(parseInt(args.timestamp, 10)) || null; -}; - -Object.defineProperty(ContactActivity, "INCOMING", {"value": true}); -Object.defineProperty(ContactActivity, "OUTGOING", {"value": false}); - -module.exports = ContactActivity;
diff --git a/src/blackberry10/ContactAddress.js b/src/blackberry10/ContactAddress.js deleted file mode 100644 index 30e9cbd..0000000 --- a/src/blackberry10/ContactAddress.js +++ /dev/null
@@ -1,35 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * -*/ -var ContactAddress = function (properties) { - this.type = properties && properties.type ? properties.type : ""; - this.streetAddress = properties && properties.streetAddress ? properties.streetAddress : ""; - this.streetOther = properties && properties.streetOther ? properties.streetOther : ""; - this.locality = properties && properties.locality ? properties.locality : ""; - this.region = properties && properties.region ? properties.region : ""; - this.postalCode = properties && properties.postalCode ? properties.postalCode : ""; - this.country = properties && properties.country ? properties.country : ""; -}; - -Object.defineProperty(ContactAddress, "HOME", {"value": "home"}); -Object.defineProperty(ContactAddress, "WORK", {"value": "work"}); -Object.defineProperty(ContactAddress, "OTHER", {"value": "other"}); - -module.exports = ContactAddress;
diff --git a/src/blackberry10/ContactError.js b/src/blackberry10/ContactError.js deleted file mode 100644 index a44a546..0000000 --- a/src/blackberry10/ContactError.js +++ /dev/null
@@ -1,35 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * -*/ -var ContactError = function (code, msg) { - this.code = code; - this.message = msg; -}; - -Object.defineProperty(ContactError, "UNKNOWN_ERROR", { "value": 0 }); -Object.defineProperty(ContactError, "INVALID_ARGUMENT_ERROR", { "value": 1 }); -Object.defineProperty(ContactError, "TIMEOUT_ERROR", { "value": 2 }); -Object.defineProperty(ContactError, "PENDING_OPERATION_ERROR", { "value": 3 }); -Object.defineProperty(ContactError, "IO_ERROR", { "value": 4 }); -Object.defineProperty(ContactError, "NOT_SUPPORTED_ERROR", { "value": 5 }); -Object.defineProperty(ContactError, "PERMISSION_DENIED_ERROR", { "value": 20 }); - -module.exports = ContactError; -
diff --git a/src/blackberry10/ContactField.js b/src/blackberry10/ContactField.js deleted file mode 100644 index 9651700..0000000 --- a/src/blackberry10/ContactField.js +++ /dev/null
@@ -1,32 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * -*/ -var ContactField = function (type, value) { - this.type = type || ""; - this.value = value || ""; -}; - -Object.defineProperty(ContactField, "HOME", {"value": "home"}); -Object.defineProperty(ContactField, "WORK", {"value": "work"}); -Object.defineProperty(ContactField, "OTHER", {"value": "other"}); -Object.defineProperty(ContactField, "MOBILE", {"value": "mobile"}); -Object.defineProperty(ContactField, "DIRECT", {"value": "direct"}); - -module.exports = ContactField;
diff --git a/src/blackberry10/ContactFindOptions.js b/src/blackberry10/ContactFindOptions.js deleted file mode 100644 index 6f8ccfe..0000000 --- a/src/blackberry10/ContactFindOptions.js +++ /dev/null
@@ -1,55 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * -*/ - -/** - * ContactFindOptions. - * @constructor - * @param filter search fields - * @param sort sort fields and order - * @param limit max number of contacts to return - * @param favorite if set, only favorite contacts will be returned - */ - -var ContactFindOptions = function (filter, sort, limit, favorite) { - this.filter = filter || null; - this.sort = sort || null; - this.limit = limit || -1; // -1 for returning all results - this.favorite = favorite || false; - this.includeAccounts = []; - this.excludeAccounts = []; -}; - -Object.defineProperty(ContactFindOptions, "SEARCH_FIELD_GIVEN_NAME", { "value": 0 }); -Object.defineProperty(ContactFindOptions, "SEARCH_FIELD_FAMILY_NAME", { "value": 1 }); -Object.defineProperty(ContactFindOptions, "SEARCH_FIELD_ORGANIZATION_NAME", { "value": 2 }); -Object.defineProperty(ContactFindOptions, "SEARCH_FIELD_PHONE", { "value": 3 }); -Object.defineProperty(ContactFindOptions, "SEARCH_FIELD_EMAIL", { "value": 4 }); -Object.defineProperty(ContactFindOptions, "SEARCH_FIELD_BBMPIN", { "value": 5 }); -Object.defineProperty(ContactFindOptions, "SEARCH_FIELD_LINKEDIN", { "value": 6 }); -Object.defineProperty(ContactFindOptions, "SEARCH_FIELD_TWITTER", { "value": 7 }); -Object.defineProperty(ContactFindOptions, "SEARCH_FIELD_VIDEO_CHAT", { "value": 8 }); - -Object.defineProperty(ContactFindOptions, "SORT_FIELD_GIVEN_NAME", { "value": 0 }); -Object.defineProperty(ContactFindOptions, "SORT_FIELD_FAMILY_NAME", { "value": 1 }); -Object.defineProperty(ContactFindOptions, "SORT_FIELD_ORGANIZATION_NAME", { "value": 2 }); - -module.exports = ContactFindOptions; -
diff --git a/src/blackberry10/ContactName.js b/src/blackberry10/ContactName.js deleted file mode 100644 index 80136c9..0000000 --- a/src/blackberry10/ContactName.js +++ /dev/null
@@ -1,44 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * -*/ - -function toFormattedName(properties) { - var formatted = ""; - if (properties && properties.givenName) { - formatted = properties.givenName; - if (properties && properties.familyName) { - formatted += " " + properties.familyName; - } - } - return formatted; -} - -var ContactName = function (properties) { - this.familyName = properties && properties.familyName ? properties.familyName : ""; - this.givenName = properties && properties.givenName ? properties.givenName : ""; - this.formatted = toFormattedName(properties); - this.middleName = properties && properties.middleName ? properties.middleName : ""; - this.honorificPrefix = properties && properties.honorificPrefix ? properties.honorificPrefix : ""; - this.honorificSuffix = properties && properties.honorificSuffix ? properties.honorificSuffix : ""; - this.phoneticFamilyName = properties && properties.phoneticFamilyName ? properties.phoneticFamilyName : ""; - this.phoneticGivenName = properties && properties.phoneticGivenName ? properties.phoneticGivenName : ""; -}; - -module.exports = ContactName;
diff --git a/src/blackberry10/ContactNews.js b/src/blackberry10/ContactNews.js deleted file mode 100644 index e47a4cd..0000000 --- a/src/blackberry10/ContactNews.js +++ /dev/null
@@ -1,31 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * -*/ -var ContactNews = function (args) { - this.title = args.title || ""; - this.body = args.body || ""; - this.articleSource = args.articleSource || ""; - this.companies = args.companies || []; - this.publishedAt = new Date(parseInt(args.publishedAt, 10)) || null; - this.uri = args.uri || ""; - this.type = args.type || ""; -}; - -module.exports = ContactNews;
diff --git a/src/blackberry10/ContactOrganization.js b/src/blackberry10/ContactOrganization.js deleted file mode 100644 index fc953f2..0000000 --- a/src/blackberry10/ContactOrganization.js +++ /dev/null
@@ -1,27 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * -*/ -var ContactOrganization = function (properties) { - this.name = properties && properties.name ? properties.name : ""; - this.department = properties && properties.department ? properties.department : ""; - this.title = properties && properties.title ? properties.title : ""; -}; - -module.exports = ContactOrganization;
diff --git a/src/blackberry10/ContactPhoto.js b/src/blackberry10/ContactPhoto.js deleted file mode 100644 index 4604710..0000000 --- a/src/blackberry10/ContactPhoto.js +++ /dev/null
@@ -1,28 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * -*/ -var ContactPhoto = function (originalFilePath, pref) { - this.originalFilePath = originalFilePath || ""; - this.pref = pref || false; - this.largeFilePath = ""; - this.smallFilePath = ""; -}; - -module.exports = ContactPhoto;
diff --git a/src/blackberry10/contactConsts.js b/src/blackberry10/contactConsts.js deleted file mode 100644 index ef25206..0000000 --- a/src/blackberry10/contactConsts.js +++ /dev/null
@@ -1,225 +0,0 @@ -/* -* Copyright 2012 Research In Motion Limited. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -var ATTRIBUTE_KIND, - ATTRIBUTE_SUBKIND, - kindAttributeMap = {}, - subKindAttributeMap = {}, - _TITLE = 26, - _START_DATE = 43, - _END_DATE = 44; - -function populateKindAttributeMap() { - ATTRIBUTE_KIND = { - Invalid: 0, - Phone: 1, - Fax: 2, - Pager: 3, - Email: 4, - Website: 5, - Feed: 6, - Profile: 7, - Family: 8, - Person: 9, - Date: 10, - Group: 11, - Name: 12, - StockSymbol: 13, - Ranking: 14, - OrganizationAffiliation: 15, - Education: 16, - Note: 17, - InstantMessaging: 18, - VideoChat: 19, - ConnectionCount: 20, - Hidden: 21, - Biography: 22, - Sound: 23, - Notification: 24, - MessageSound: 25, - MessageNotification: 26 - }; - - kindAttributeMap[ATTRIBUTE_KIND.Phone] = "phoneNumbers"; - kindAttributeMap[ATTRIBUTE_KIND.Fax] = "faxNumbers"; - kindAttributeMap[ATTRIBUTE_KIND.Pager] = "pagerNumber"; - kindAttributeMap[ATTRIBUTE_KIND.Email] = "emails"; - kindAttributeMap[ATTRIBUTE_KIND.Website] = "urls"; - kindAttributeMap[ATTRIBUTE_KIND.Profile] = "socialNetworks"; - kindAttributeMap[ATTRIBUTE_KIND.OrganizationAffiliation] = "organizations"; - kindAttributeMap[ATTRIBUTE_KIND.Education] = "education"; - kindAttributeMap[ATTRIBUTE_KIND.Note] = "note"; - kindAttributeMap[ATTRIBUTE_KIND.InstantMessaging] = "ims"; - kindAttributeMap[ATTRIBUTE_KIND.VideoChat] = "videoChat"; - kindAttributeMap[ATTRIBUTE_KIND.Sound] = "ringtone"; -} - -function populateSubKindAttributeMap() { - ATTRIBUTE_SUBKIND = { - Invalid: 0, - Other: 1, - Home: 2, - Work: 3, - PhoneMobile: 4, - FaxDirect: 5, - Blog: 6, - WebsiteResume: 7, - WebsitePortfolio: 8, - WebsitePersonal: 9, - WebsiteCompany: 10, - ProfileFacebook: 11, - ProfileTwitter: 12, - ProfileLinkedIn: 13, - ProfileGist: 14, - ProfileTungle: 15, - FamilySpouse: 16, - FamilyChild: 17, - FamilyParent: 18, - PersonManager: 19, - PersonAssistant: 20, - DateBirthday: 21, - DateAnniversary: 22, - GroupDepartment: 23, - NameGiven: 24, - NameSurname: 25, - Title: _TITLE, - NameSuffix: 27, - NameMiddle: 28, - NameNickname: 29, - NameAlias: 30, - NameDisplayName: 31, - NamePhoneticGiven: 32, - NamePhoneticSurname: 33, - StockSymbolNyse: 34, - StockSymbolNasdaq: 35, - StockSymbolTse: 36, - StockSymbolLse: 37, - StockSymbolTsx: 38, - RankingKlout: 39, - RankingTrstRank: 40, - OrganizationAffiliationName: 41, - OrganizationAffiliationPhoneticName: 42, - OrganizationAffiliationTitle: _TITLE, - StartDate: _START_DATE, - EndDate: _END_DATE, - OrganizationAffiliationDetails: 45, - EducationInstitutionName: 46, - EducationStartDate: _START_DATE, - EducationEndDate: _END_DATE, - EducationDegree: 47, - EducationConcentration: 48, - EducationActivities: 49, - EducationNotes: 50, - InstantMessagingBbmPin: 51, - InstantMessagingAim: 52, - InstantMessagingAliwangwang: 53, - InstantMessagingGoogleTalk: 54, - InstantMessagingSametime: 55, - InstantMessagingIcq: 56, - InstantMessagingIrc: 57, - InstantMessagingJabber: 58, - InstantMessagingMsLcs: 59, - InstantMessagingMsn: 60, - InstantMessagingQq: 61, - InstantMessagingSkype: 62, - InstantMessagingYahooMessenger: 63, - InstantMessagingYahooMessengerJapan: 64, - VideoChatBbPlaybook: 65, - HiddenLinkedIn: 66, - HiddenFacebook: 67, - HiddenTwitter: 68, - ConnectionCountLinkedIn: 69, - ConnectionCountFacebook: 70, - ConnectionCountTwitter: 71, - HiddenChecksum: 72, - HiddenSpeedDial: 73, - BiographyFacebook: 74, - BiographyTwitter: 75, - BiographyLinkedIn: 76, - SoundRingtone: 77, - SimContactType: 78, - EcoID: 79, - Personal: 80, - StockSymbolAll: 81, - NotificationVibration: 82, - NotificationLED: 83, - MessageNotificationVibration: 84, - MessageNotificationLED: 85, - MessageNotificationDuringCall: 86, - VideoChatPin: 87 - }; - - subKindAttributeMap[ATTRIBUTE_SUBKIND.Other] = "other"; - subKindAttributeMap[ATTRIBUTE_SUBKIND.Home] = "home"; - subKindAttributeMap[ATTRIBUTE_SUBKIND.Work] = "work"; - subKindAttributeMap[ATTRIBUTE_SUBKIND.PhoneMobile] = "mobile"; - subKindAttributeMap[ATTRIBUTE_SUBKIND.FaxDirect] = "direct"; - subKindAttributeMap[ATTRIBUTE_SUBKIND.Blog] = "blog"; - subKindAttributeMap[ATTRIBUTE_SUBKIND.WebsiteResume] = "resume"; - subKindAttributeMap[ATTRIBUTE_SUBKIND.WebsitePortfolio] = "portfolio"; - subKindAttributeMap[ATTRIBUTE_SUBKIND.WebsitePersonal] = "personal"; - subKindAttributeMap[ATTRIBUTE_SUBKIND.WebsiteCompany] = "company"; - subKindAttributeMap[ATTRIBUTE_SUBKIND.ProfileFacebook] = "facebook"; - subKindAttributeMap[ATTRIBUTE_SUBKIND.ProfileTwitter] = "twitter"; - subKindAttributeMap[ATTRIBUTE_SUBKIND.ProfileLinkedIn] = "linkedin"; - subKindAttributeMap[ATTRIBUTE_SUBKIND.ProfileGist] = "gist"; - subKindAttributeMap[ATTRIBUTE_SUBKIND.ProfileTungle] = "tungle"; - subKindAttributeMap[ATTRIBUTE_SUBKIND.DateBirthday] = "birthday"; - subKindAttributeMap[ATTRIBUTE_SUBKIND.DateAnniversary] = "anniversary"; - subKindAttributeMap[ATTRIBUTE_SUBKIND.NameGiven] = "givenName"; - subKindAttributeMap[ATTRIBUTE_SUBKIND.NameSurname] = "familyName"; - subKindAttributeMap[ATTRIBUTE_SUBKIND.Title] = "honorificPrefix"; - subKindAttributeMap[ATTRIBUTE_SUBKIND.NameSuffix] = "honorificSuffix"; - subKindAttributeMap[ATTRIBUTE_SUBKIND.NameMiddle] = "middleName"; - subKindAttributeMap[ATTRIBUTE_SUBKIND.NamePhoneticGiven] = "phoneticGivenName"; - subKindAttributeMap[ATTRIBUTE_SUBKIND.NamePhoneticSurname] = "phoneticFamilyName"; - subKindAttributeMap[ATTRIBUTE_SUBKIND.NameNickname] = "nickname"; - subKindAttributeMap[ATTRIBUTE_SUBKIND.NameDisplayName] = "displayName"; - subKindAttributeMap[ATTRIBUTE_SUBKIND.OrganizationAffiliationName] = "name"; - subKindAttributeMap[ATTRIBUTE_SUBKIND.OrganizationAffiliationDetails] = "department"; - subKindAttributeMap[ATTRIBUTE_SUBKIND.Title] = "title"; - subKindAttributeMap[ATTRIBUTE_SUBKIND.InstantMessagingBbmPin] = "BbmPin"; - subKindAttributeMap[ATTRIBUTE_SUBKIND.InstantMessagingAim] = "Aim"; - subKindAttributeMap[ATTRIBUTE_SUBKIND.InstantMessagingAliwangwang] = "Aliwangwang"; - subKindAttributeMap[ATTRIBUTE_SUBKIND.InstantMessagingGoogleTalk] = "GoogleTalk"; - subKindAttributeMap[ATTRIBUTE_SUBKIND.InstantMessagingSametime] = "Sametime"; - subKindAttributeMap[ATTRIBUTE_SUBKIND.InstantMessagingIcq] = "Icq"; - subKindAttributeMap[ATTRIBUTE_SUBKIND.InstantMessagingJabber] = "Jabber"; - subKindAttributeMap[ATTRIBUTE_SUBKIND.InstantMessagingMsLcs] = "MsLcs"; - subKindAttributeMap[ATTRIBUTE_SUBKIND.InstantMessagingSkype] = "Skype"; - subKindAttributeMap[ATTRIBUTE_SUBKIND.InstantMessagingYahooMessenger] = "YahooMessenger"; - subKindAttributeMap[ATTRIBUTE_SUBKIND.InstantMessagingYahooMessengerJapan] = "YahooMessegerJapan"; - subKindAttributeMap[ATTRIBUTE_SUBKIND.VideoChatBbPlaybook] = "BbPlaybook"; - subKindAttributeMap[ATTRIBUTE_SUBKIND.SoundRingtone] = "ringtone"; - subKindAttributeMap[ATTRIBUTE_SUBKIND.Personal] = "personal"; -} - -module.exports = { - getKindAttributeMap: function () { - if (!ATTRIBUTE_KIND) { - populateKindAttributeMap(); - } - - return kindAttributeMap; - }, - getSubKindAttributeMap: function () { - if (!ATTRIBUTE_SUBKIND) { - populateSubKindAttributeMap(); - } - - return subKindAttributeMap; - } -};
diff --git a/src/blackberry10/contactUtils.js b/src/blackberry10/contactUtils.js deleted file mode 100644 index e1f7d67..0000000 --- a/src/blackberry10/contactUtils.js +++ /dev/null
@@ -1,228 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * -*/ - -var self, - ContactFindOptions = require("./ContactFindOptions"), - ContactError = require("./ContactError"), - ContactName = require("./ContactName"), - ContactOrganization = require("./ContactOrganization"), - ContactAddress = require("./ContactAddress"), - ContactField = require("./ContactField"), - contactConsts = require("./contactConsts"), - ContactPhoto = require("./ContactPhoto"), - ContactNews = require("./ContactNews"), - ContactActivity = require("./ContactActivity"); - -function populateFieldArray(contactProps, field, ClassName) { - if (contactProps[field]) { - var list = [], - obj; - - contactProps[field].forEach(function (args) { - if (ClassName === ContactField) { - list.push(new ClassName(args.type, args.value)); - } else if (ClassName === ContactPhoto) { - obj = new ContactPhoto(args.originalFilePath, args.pref); - obj.largeFilePath = args.largeFilePath; - obj.smallFilePath = args.smallFilePath; - list.push(obj); - } else if (ClassName === ContactNews) { - obj = new ContactNews(args); - list.push(obj); - } else if (ClassName === ContactActivity) { - obj = new ContactActivity(args); - list.push(obj); - } else { - list.push(new ClassName(args)); - } - }); - contactProps[field] = list; - } -} - -function populateDate(contactProps, field) { - if (contactProps[field]) { - contactProps[field] = new Date(contactProps[field]); - } -} - -function validateFindArguments(findOptions) { - var error = false; - - // findOptions is mandatory - if (!findOptions) { - error = true; - } else { - // findOptions.filter is optional - if (findOptions.filter) { - findOptions.filter.forEach(function (f) { - switch (f.fieldName) { - case ContactFindOptions.SEARCH_FIELD_GIVEN_NAME: - case ContactFindOptions.SEARCH_FIELD_FAMILY_NAME: - case ContactFindOptions.SEARCH_FIELD_ORGANIZATION_NAME: - case ContactFindOptions.SEARCH_FIELD_PHONE: - case ContactFindOptions.SEARCH_FIELD_EMAIL: - case ContactFindOptions.SEARCH_FIELD_BBMPIN: - case ContactFindOptions.SEARCH_FIELD_LINKEDIN: - case ContactFindOptions.SEARCH_FIELD_TWITTER: - case ContactFindOptions.SEARCH_FIELD_VIDEO_CHAT: - break; - default: - error = true; - } - - if (!f.fieldValue) { - error = true; - } - }); - } - - //findOptions.limit is optional - if (findOptions.limit) { - if (typeof findOptions.limit !== "number") { - error = true; - } - } - - //findOptions.favorite is optional - if (findOptions.favorite) { - if (typeof findOptions.favorite !== "boolean") { - error = true; - } - } - - // findOptions.sort is optional - if (!error && findOptions.sort && Array.isArray(findOptions.sort)) { - findOptions.sort.forEach(function (s) { - switch (s.fieldName) { - case ContactFindOptions.SORT_FIELD_GIVEN_NAME: - case ContactFindOptions.SORT_FIELD_FAMILY_NAME: - case ContactFindOptions.SORT_FIELD_ORGANIZATION_NAME: - break; - default: - error = true; - } - - if (s.desc === undefined || typeof s.desc !== "boolean") { - error = true; - } - }); - } - - if (!error && findOptions.includeAccounts) { - if (!Array.isArray(findOptions.includeAccounts)) { - error = true; - } else { - findOptions.includeAccounts.forEach(function (acct) { - if (!error && (!acct.id || window.isNaN(window.parseInt(acct.id, 10)))) { - error = true; - } - }); - } - } - - if (!error && findOptions.excludeAccounts) { - if (!Array.isArray(findOptions.excludeAccounts)) { - error = true; - } else { - findOptions.excludeAccounts.forEach(function (acct) { - if (!error && (!acct.id || window.isNaN(window.parseInt(acct.id, 10)))) { - error = true; - } - }); - } - } - } - return !error; -} - -function validateContactsPickerFilter(filter) { - var isValid = true, - availableFields = {}; - - if (typeof(filter) === "undefined") { - isValid = false; - } else { - if (filter && Array.isArray(filter)) { - availableFields = contactConsts.getKindAttributeMap(); - filter.forEach(function (e) { - isValid = isValid && Object.getOwnPropertyNames(availableFields).reduce( - function (found, key) { - return found || availableFields[key] === e; - }, false); - }); - } - } - - return isValid; -} - -function validateContactsPickerOptions(options) { - var isValid = false, - mode = options.mode; - - if (typeof(options) === "undefined") { - isValid = false; - } else { - isValid = mode === ContactPickerOptions.MODE_SINGLE || mode === ContactPickerOptions.MODE_MULTIPLE || mode === ContactPickerOptions.MODE_ATTRIBUTE; - - // if mode is attribute, fields must be defined - if (mode === ContactPickerOptions.MODE_ATTRIBUTE && !validateContactsPickerFilter(options.fields)) { - isValid = false; - } - } - - return isValid; -} - -self = module.exports = { - populateContact: function (contact) { - if (contact.name) { - contact.name = new ContactName(contact.name); - } - - populateFieldArray(contact, "addresses", ContactAddress); - populateFieldArray(contact, "organizations", ContactOrganization); - populateFieldArray(contact, "emails", ContactField); - populateFieldArray(contact, "phoneNumbers", ContactField); - populateFieldArray(contact, "faxNumbers", ContactField); - populateFieldArray(contact, "pagerNumbers", ContactField); - populateFieldArray(contact, "ims", ContactField); - populateFieldArray(contact, "socialNetworks", ContactField); - populateFieldArray(contact, "urls", ContactField); - populateFieldArray(contact, "photos", ContactPhoto); - populateFieldArray(contact, "news", ContactNews); - populateFieldArray(contact, "activities", ContactActivity); - // TODO categories - - populateDate(contact, "birthday"); - populateDate(contact, "anniversary"); - }, - invokeErrorCallback: function (errorCallback, code) { - if (errorCallback) { - errorCallback(new ContactError(code)); - } - }, - validateFindArguments: validateFindArguments, - validateContactsPickerFilter: validateContactsPickerFilter, - validateContactsPickerOptions: validateContactsPickerOptions -}; -
diff --git a/src/blackberry10/index.js b/src/blackberry10/index.js deleted file mode 100644 index 09a4bd2..0000000 --- a/src/blackberry10/index.js +++ /dev/null
@@ -1,374 +0,0 @@ -/* - * Copyright 2013 Research In Motion Limited. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -var pimContacts, - contactUtils = require("./contactUtils"), - contactConsts = require("./contactConsts"), - ContactError = require("./ContactError"), - ContactName = require("./ContactName"), - ContactFindOptions = require("./ContactFindOptions"), - noop = function () {}; - -function getAccountFilters(options) { - if (options.includeAccounts) { - options.includeAccounts = options.includeAccounts.map(function (acct) { - return acct.id.toString(); - }); - } - - if (options.excludeAccounts) { - options.excludeAccounts = options.excludeAccounts.map(function (acct) { - return acct.id.toString(); - }); - } -} - -function populateSearchFields(fields) { - var i, - l, - key, - searchFieldsObject = {}, - searchFields = []; - - for (i = 0, l = fields.length; i < l; i++) { - if (fields[i] === "*") { - searchFieldsObject[ContactFindOptions.SEARCH_FIELD_GIVEN_NAME] = true; - searchFieldsObject[ContactFindOptions.SEARCH_FIELD_FAMILY_NAME] = true; - searchFieldsObject[ContactFindOptions.SEARCH_FIELD_PHONE] = true; - searchFieldsObject[ContactFindOptions.SEARCH_FIELD_EMAIL] = true; - searchFieldsObject[ContactFindOptions.SEARCH_FIELD_ORGANIZATION_NAME] = true; - } else if (fields[i] === "displayName" || fields[i] === "name") { - searchFieldsObject[ContactFindOptions.SEARCH_FIELD_GIVEN_NAME] = true; - searchFieldsObject[ContactFindOptions.SEARCH_FIELD_FAMILY_NAME] = true; - } else if (fields[i] === "nickname") { - // not supported by Cascades - } else if (fields[i] === "phoneNumbers") { - searchFieldsObject[ContactFindOptions.SEARCH_FIELD_PHONE] = true; - } else if (fields[i] === "emails") { - searchFieldsObject[ContactFindOptions.SEARCH_FIELD_EMAIL] = true; - } else if (field === "addresses") { - // not supported by Cascades - } else if (field === "ims") { - // not supported by Cascades - } else if (field === "organizations") { - searchFieldsObject[ContactFindOptions.SEARCH_FIELD_ORGANIZATION_NAME] = true; - } else if (field === "birthday") { - // not supported by Cascades - } else if (field === "note") { - // not supported by Cascades - } else if (field === "photos") { - // not supported by Cascades - } else if (field === "categories") { - // not supported by Cascades - } else if (field === "urls") { - // not supported by Cascades - } - } - - for (key in searchFieldsObject) { - if (searchFieldsObject.hasOwnProperty(key)) { - searchFields.push(window.parseInt(key)); - } - } - - return searchFields; -} - -function convertBirthday(birthday) { - //Convert date string from native to milliseconds since epoch for cordova-js - var birthdayInfo; - if (birthday) { - birthdayInfo = birthday.split("-"); - return new Date(birthdayInfo[0], birthdayInfo[1] - 1, birthdayInfo[2]).getTime(); - } else { - return null; - } -} - -function processJnextSaveData(result, JnextData) { - var data = JnextData, - birthdayInfo; - - if (data._success === true) { - data.birthday = convertBirthday(data.birthday); - result.callbackOk(data, false); - } else { - result.callbackError(data.code, false); - } -} - -function processJnextRemoveData(result, JnextData) { - var data = JnextData; - - if (data._success === true) { - result.callbackOk(data); - } else { - result.callbackError(ContactError.UNKNOWN_ERROR, false); - } -} - -function processJnextFindData(eventId, eventHandler, JnextData) { - var data = JnextData, - i, - l, - more = false, - resultsObject = {}, - birthdayInfo; - - if (data.contacts) { - for (i = 0, l = data.contacts.length; i < l; i++) { - data.contacts[i].birthday = convertBirthday(data.contacts[i].birthday); - data.contacts[i].name = new ContactName(data.contacts[i].name); - } - } else { - data.contacts = []; // if JnextData.contacts return null, return an empty array - } - - if (data._success === true) { - eventHandler.error = false; - } - - if (eventHandler.multiple) { - // Concatenate results; do not add the same contacts - for (i = 0, l = eventHandler.searchResult.length; i < l; i++) { - resultsObject[eventHandler.searchResult[i].id] = true; - } - - for (i = 0, l = data.contacts.length; i < l; i++) { - if (resultsObject[data.contacts[i].id]) { - // Already existing - } else { - eventHandler.searchResult.push(data.contacts[i]); - } - } - - // check if more search is required - eventHandler.searchFieldIndex++; - if (eventHandler.searchFieldIndex < eventHandler.searchFields.length) { - more = true; - } - } else { - eventHandler.searchResult = data.contacts; - } - - if (more) { - pimContacts.getInstance().invokeJnextSearch(eventId); - } else { - if (eventHandler.error) { - eventHandler.result.callbackError(data.code, false); - } else { - eventHandler.result.callbackOk(eventHandler.searchResult, false); - } - } -} - -module.exports = { - search: function (successCb, failCb, args, env) { - var cordovaFindOptions = {}, - result = new PluginResult(args, env), - key; - - for (key in args) { - if (args.hasOwnProperty(key)) { - cordovaFindOptions[key] = JSON.parse(decodeURIComponent(args[key])); - } - } - - pimContacts.getInstance().find(cordovaFindOptions, result, processJnextFindData); - result.noResult(true); - }, - save: function (successCb, failCb, args, env) { - var attributes = {}, - result = new PluginResult(args, env), - key, - nativeEmails = []; - - attributes = JSON.parse(decodeURIComponent(args[0])); - - //convert birthday format for our native .so file - if (attributes.birthday) { - attributes.birthday = new Date(attributes.birthday).toDateString(); - } - - if (attributes.emails) { - attributes.emails.forEach(function (email) { - if (email.value) { - if (email.type) { - nativeEmails.push({ "type" : email.type, "value" : email.value }); - } else { - nativeEmails.push({ "type" : "home", "value" : email.value }); - } - } - }); - attributes.emails = nativeEmails; - } - - if (attributes.id !== null) { - attributes.id = window.parseInt(attributes.id); - } - - attributes._eventId = result.callbackId; - pimContacts.getInstance().save(attributes, result, processJnextSaveData); - result.noResult(true); - }, - remove: function (successCb, failCb, args, env) { - var result = new PluginResult(args, env), - attributes = { - "contactId": window.parseInt(JSON.parse(decodeURIComponent(args[0]))), - "_eventId": result.callbackId - }; - - if (!window.isNaN(attributes.contactId)) { - pimContacts.getInstance().remove(attributes, result, processJnextRemoveData); - result.noResult(true); - } else { - result.error(ContactError.UNKNOWN_ERROR); - result.noResult(false); - } - } -}; - -/////////////////////////////////////////////////////////////////// -// JavaScript wrapper for JNEXT plugin -/////////////////////////////////////////////////////////////////// - -JNEXT.PimContacts = function () -{ - var self = this, - hasInstance = false; - - self.find = function (cordovaFindOptions, pluginResult, handler) { - //register find eventHandler for when JNEXT onEvent fires - self.eventHandlers[cordovaFindOptions.callbackId] = { - "result" : pluginResult, - "action" : "find", - "multiple" : cordovaFindOptions[1].filter ? true : false, - "fields" : cordovaFindOptions[0], - "searchFilter" : cordovaFindOptions[1].filter, - "searchFields" : cordovaFindOptions[1].filter ? populateSearchFields(cordovaFindOptions[0]) : null, - "searchFieldIndex" : 0, - "searchResult" : [], - "handler" : handler, - "error" : true - }; - - self.invokeJnextSearch(cordovaFindOptions.callbackId); - return ""; - }; - - self.invokeJnextSearch = function(eventId) { - var jnextArgs = {}, - findHandler = self.eventHandlers[eventId]; - - jnextArgs._eventId = eventId; - jnextArgs.fields = findHandler.fields; - jnextArgs.options = {}; - jnextArgs.options.filter = []; - - if (findHandler.multiple) { - jnextArgs.options.filter.push({ - "fieldName" : findHandler.searchFields[findHandler.searchFieldIndex], - "fieldValue" : findHandler.searchFilter - }); - //findHandler.searchFieldIndex++; - } - - JNEXT.invoke(self.m_id, "find " + JSON.stringify(jnextArgs)); - } - - self.getContact = function (args) { - return JSON.parse(JNEXT.invoke(self.m_id, "getContact " + JSON.stringify(args))); - }; - - self.save = function (args, pluginResult, handler) { - //register save eventHandler for when JNEXT onEvent fires - self.eventHandlers[args._eventId] = { - "result" : pluginResult, - "action" : "save", - "handler" : handler - }; - JNEXT.invoke(self.m_id, "save " + JSON.stringify(args)); - return ""; - }; - - self.remove = function (args, pluginResult, handler) { - //register remove eventHandler for when JNEXT onEvent fires - self.eventHandlers[args._eventId] = { - "result" : pluginResult, - "action" : "remove", - "handler" : handler - }; - JNEXT.invoke(self.m_id, "remove " + JSON.stringify(args)); - return ""; - }; - - self.getId = function () { - return self.m_id; - }; - - self.getContactAccounts = function () { - var value = JNEXT.invoke(self.m_id, "getContactAccounts"); - return JSON.parse(value); - }; - - self.init = function () { - if (!JNEXT.require("libpimcontacts")) { - return false; - } - - self.m_id = JNEXT.createObject("libpimcontacts.PimContacts"); - - if (self.m_id === "") { - return false; - } - - JNEXT.registerEvents(self); - }; - - // Handle data coming back from JNEXT native layer. Each async function registers a handler and a PluginResult object. - // When JNEXT fires onEvent we parse the result string back into JSON and trigger the appropriate handler (eventHandlers map - // uses callbackId as key), along with the actual data coming back from the native layer. Each function may have its own way of - // processing native data so we do not do any processing here. - - self.onEvent = function (strData) { - var arData = strData.split(" "), - strEventDesc = arData[0], - eventHandler, - args = {}; - - if (strEventDesc === "result") { - args.result = escape(strData.split(" ").slice(2).join(" ")); - eventHandler = self.eventHandlers[arData[1]]; - if (eventHandler.action === "save" || eventHandler.action === "remove") { - eventHandler.handler(eventHandler.result, JSON.parse(decodeURIComponent(args.result))); - } else if (eventHandler.action === "find") { - eventHandler.handler(arData[1], eventHandler, JSON.parse(decodeURIComponent(args.result))); - } - } - }; - - self.m_id = ""; - self.eventHandlers = {}; - - self.getInstance = function () { - if (!hasInstance) { - self.init(); - hasInstance = true; - } - return self; - }; -}; - -pimContacts = new JNEXT.PimContacts();
diff --git a/src/firefoxos/ContactsProxy.js b/src/firefoxos/ContactsProxy.js deleted file mode 100644 index a5b6667..0000000 --- a/src/firefoxos/ContactsProxy.js +++ /dev/null
@@ -1,464 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * -*/ - -// Cordova contact definition: -// http://cordova.apache.org/docs/en/2.5.0/cordova_contacts_contacts.md.html#Contact -// FxOS contact definition: -// https://developer.mozilla.org/en-US/docs/Web/API/mozContact - - -var Contact = require('./Contact'); -var ContactField = require('./ContactField'); -var ContactAddress = require('./ContactAddress'); -var ContactName = require('./ContactName'); - -// XXX: a hack to check if id is "empty". Cordova inserts a -// string "this string is supposed to be a unique identifier that will -// never show up on a device" if id is empty -function _hasId(id) { - if (!id || id.indexOf(' ') >= 0) { - return false; - } - return true; -} - -// Extend mozContact prototype to provide update from Cordova -function updateFromCordova(contact, fromContact) { - - function exportContactFieldArray(contactFieldArray, key) { - if (!key) { - key = 'value'; - } - var arr = []; - for (var i=0; i < contactFieldArray.length; i++) { - arr.push(contactFieldArray[i][key]); - }; - return arr; - } - - function exportAddress(addresses) { - // TODO: check moz address format - var arr = []; - - for (var i=0; i < addresses.length; i++) { - var addr = {}; - for (var key in addresses[i]) { - if (key == 'formatted' || key == 'id') { - continue; - } else if (key == 'type') { - addr[key] = [addresses[i][key]]; - } else if (key == 'country') { - addr['countryName'] = addresses[i][key]; - } else { - addr[key] = addresses[i][key]; - } - } - arr.push(addr); - } - return arr; - } - - function exportContactField(data) { - var contactFields = []; - for (var i=0; i < data.length; i++) { - var item = data[i]; - if (item.value) { - var itemData = {value: item.value}; - if (item.type) { - itemData.type = [item.type]; - } - if (item.pref) { - itemData.pref = item.pref; - } - contactFields.push(itemData); - } - } - return contactFields; - } - // adding simple fields [contactField, eventualMozContactField] - var nameFields = [['givenName'], ['familyName'], - ['honorificPrefix'], ['honorificSuffix'], - ['middleName', 'additionalName']]; - var baseArrayFields = [['displayName', 'name'], ['nickname']]; - var baseStringFields = []; - var j = 0; while(field = nameFields[j++]) { - if (fromContact.name[field[0]]) { - contact[field[1] || field[0]] = fromContact.name[field[0]].split(' '); - } - } - j = 0; while(field = baseArrayFields[j++]) { - if (fromContact[field[0]]) { - contact[field[1] || field[0]] = fromContact[field[0]].split(' '); - } - } - j = 0; while(field = baseStringFields[j++]) { - if (fromContact[field[0]]) { - contact[field[1] || field[0]] = fromContact[field[0]]; - } - } - if (fromContact.birthday) { - contact.bday = new Date(fromContact.birthday); - } - if (fromContact.emails) { - var emails = exportContactField(fromContact.emails) - contact.email = emails; - } - if (fromContact.categories) { - contact.category = exportContactFieldArray(fromContact.categories); - } - if (fromContact.addresses) { - contact.adr = exportAddress(fromContact.addresses); - } - if (fromContact.phoneNumbers) { - contact.tel = exportContactField(fromContact.phoneNumbers); - } - if (fromContact.organizations) { - // XXX: organizations are saved in 2 arrays - org and jobTitle - // depending on the usecase it might generate issues - // where wrong title will be added to an organization - contact.org = exportContactFieldArray(fromContact.organizations, 'name'); - contact.jobTitle = exportContactFieldArray(fromContact.organizations, 'title'); - } - if (fromContact.note) { - contact.note = [fromContact.note]; - } -} - - -// Extend Cordova Contact prototype to provide update from FFOS contact -Contact.prototype.updateFromMozilla = function(moz) { - function exportContactField(data) { - var contactFields = []; - for (var i=0; i < data.length; i++) { - var item = data[i]; - var itemData = new ContactField(item.type, item.value, item.pref); - contactFields.push(itemData); - } - return contactFields; - } - - function makeContactFieldFromArray(data) { - var contactFields = []; - for (var i=0; i < data.length; i++) { - var itemData = new ContactField(null, data[i]); - contactFields.push(itemData); - } - return contactFields; - } - - function exportAddresses(addresses) { - // TODO: check moz address format - var arr = []; - - for (var i=0; i < addresses.length; i++) { - var addr = {}; - for (var key in addresses[i]) { - if (key == 'countryName') { - addr['country'] = addresses[i][key]; - } else if (key == 'type') { - addr[key] = addresses[i][key].join(' '); - } else { - addr[key] = addresses[i][key]; - } - } - arr.push(addr); - } - return arr; - } - - function createOrganizations(orgs, jobs) { - orgs = (orgs) ? orgs : []; - jobs = (jobs) ? jobs : []; - var max_length = Math.max(orgs.length, jobs.length); - var organizations = []; - for (var i=0; i < max_length; i++) { - organizations.push(new ContactOrganization( - null, null, orgs[i] || null, null, jobs[i] || null)); - } - return organizations; - } - - function createFormatted(name) { - var fields = ['honorificPrefix', 'givenName', 'middleName', - 'familyName', 'honorificSuffix']; - var f = ''; - for (var i = 0; i < fields.length; i++) { - if (name[fields[i]]) { - if (f) { - f += ' '; - } - f += name[fields[i]]; - } - } - return f; - } - - - if (moz.id) { - this.id = moz.id; - } - var nameFields = [['givenName'], ['familyName'], - ['honorificPrefix'], ['honorificSuffix'], - ['additionalName', 'middleName']]; - var baseArrayFields = [['name', 'displayName'], 'nickname', ['note']]; - var baseStringFields = []; - var name = new ContactName(); - var j = 0; while(field = nameFields[j++]) { - if (moz[field[0]]) { - name[field[1] || field[0]] = moz[field[0]].join(' '); - } - } - this.name = name; - j = 0; while(field = baseArrayFields[j++]) { - if (moz[field[0]]) { - this[field[1] || field[0]] = moz[field[0]].join(' '); - } - } - j = 0; while(field = baseStringFields[j++]) { - if (moz[field[0]]) { - this[field[1] || field[0]] = moz[field[0]]; - } - } - // emails - if (moz.email) { - this.emails = exportContactField(moz.email); - } - // categories - if (moz.category) { - this.categories = makeContactFieldFromArray(moz.category); - } - - // addresses - if (moz.adr) { - this.addresses = exportAddresses(moz.adr); - } - - // phoneNumbers - if (moz.tel) { - this.phoneNumbers = exportContactField(moz.tel); - } - // birthday - if (moz.bday) { - this.birthday = Date.parse(moz.bday); - } - // organizations - if (moz.org || moz.jobTitle) { - // XXX: organizations array is created from org and jobTitle - this.organizations = createOrganizations(moz.org, moz.jobTitle); - } - // construct a read-only formatted value - this.name.formatted = createFormatted(this.name); - - /* Find out how to translate these parameters - // photo: Blob - // url: Array with metadata (?) - // impp: exportIM(contact.ims), TODO: find the moz impp definition - // anniversary - // sex - // genderIdentity - // key - */ -} - - -function createMozillaFromCordova(successCB, errorCB, contact) { - var moz; - // get contact if exists - if (_hasId(contact.id)) { - var search = navigator.mozContacts.find({ - filterBy: ['id'], filterValue: contact.id, filterOp: 'equals'}); - search.onsuccess = function() { - moz = search.result[0]; - updateFromCordova(moz, contact); - successCB(moz); - }; - search.onerror = errorCB; - return; - } - - // create empty contact - moz = new mozContact(); - // if ('init' in moz) { - // 1.2 and below compatibility - // moz.init(); - // } - updateFromCordova(moz, contact); - successCB(moz); -} - - -function createCordovaFromMozilla(moz) { - var contact = new Contact(); - contact.updateFromMozilla(moz); - return contact; -} - - -// However API requires the ability to save multiple contacts, it is -// used to save only one element array -function saveContacts(successCB, errorCB, contacts) { - // a closure which is holding the right moz contact - function makeSaveSuccessCB(moz) { - return function(result) { - // create contact from FXOS contact (might be different than - // the original one due to differences in API) - var contact = createCordovaFromMozilla(moz); - // call callback - successCB(contact); - } - } - var i=0; - var contact; - while(contact = contacts[i++]){ - var moz = createMozillaFromCordova(function(moz) { - var request = navigator.mozContacts.save(moz); - // success and/or fail will be called every time a contact is saved - request.onsuccess = makeSaveSuccessCB(moz); - request.onerror = errorCB; - }, function() {}, contact); - } -} - - -// API provides a list of ids to be removed -function remove(successCB, errorCB, ids) { - var i=0; - var id; - for (var i=0; i < ids.length; i++){ - // throw an error if no id provided - if (!_hasId(ids[i])) { - console.error('FFOS: Attempt to remove unsaved contact'); - errorCB(0); - return; - } - // check if provided id actually exists - var search = navigator.mozContacts.find({ - filterBy: ['id'], filterValue: ids[i], filterOp: 'equals'}); - search.onsuccess = function() { - if (search.result.length === 0) { - console.error('FFOS: Attempt to remove a non existing contact'); - errorCB(0); - return; - } - var moz = search.result[0]; - var request = navigator.mozContacts.remove(moz); - request.onsuccess = successCB; - request.onerror = errorCB; - }; - search.onerror = errorCB; - } -} - - -var mozContactSearchFields = [['name', 'displayName'], ['givenName'], - ['familyName'], ['email'], ['tel'], ['jobTitle'], ['note'], - ['tel', 'phoneNumbers'], ['email', 'emails']]; -// Searching by nickname and additionalName is forbidden in 1.3 and below -// Searching by name is forbidden in 1.2 and below - -// finds if a key is allowed and returns FFOS name if different -function getMozSearchField(key) { - if (mozContactSearchFields.indexOf([key]) >= 0) { - return key; - } - for (var i=0; i < mozContactSearchFields.length; i++) { - if (mozContactSearchFields[i].length > 1) { - if (mozContactSearchFields[i][1] === key) { - return mozContactSearchFields[i][0]; - } - } - } - return false; -} - - -function _getAll(successCB, errorCB, params) { - // [contactField, eventualMozContactField] - var getall = navigator.mozContacts.getAll({}); - var contacts = []; - - getall.onsuccess = function() { - if (getall.result) { - contacts.push(createCordovaFromMozilla(getall.result)); - getall.continue(); - } else { - successCB(contacts); - } - }; - getall.onerror = errorCB; -} - - -function search(successCB, errorCB, params) { - var options = params[1] || {}; - if (!options.filter) { - return _getAll(successCB, errorCB, params); - } - var filterBy = []; - // filter and translate fields - for (var i=0; i < params[0].length; i++) { - var searchField = params[0][i]; - var mozField = getMozSearchField(searchField); - if (searchField === 'name') { - // Cordova uses name for search by all name fields. - filterBy.push('givenName'); - filterBy.push('familyName'); - continue; - } - if (searchField === 'displayName' && 'init' in new mozContact()) { - // ``init`` in ``mozContact`` indicates FFOS version 1.2 or below - // Searching by name (in moz) is then forbidden - console.log('FFOS ContactProxy: Unable to search by displayName on FFOS 1.2'); - continue; - } - if (mozField) { - filterBy.push(mozField); - } else { - console.log('FXOS ContactProxy: inallowed field passed to search filtered out: ' + searchField); - } - } - - var mozOptions = {filterBy: filterBy, filterOp: 'startsWith'}; - if (!options.multiple) { - mozOptions.filterLimit = 1; - } - mozOptions.filterValue = options.filter; - var request = navigator.mozContacts.find(mozOptions); - request.onsuccess = function() { - var contacts = []; - var mozContacts = request.result; - var moz = mozContacts[0]; - for (var i=0; i < mozContacts.length; i++) { - contacts.push(createCordovaFromMozilla(mozContacts[i])); - } - successCB(contacts); - }; - request.onerror = errorCB; -} - - -module.exports = { - save: saveContacts, - remove: remove, - search: search -}; - -require("cordova/firefoxos/commandProxy").add("Contacts", module.exports); \ No newline at end of file
diff --git a/src/ios/CDVContact.h b/src/ios/CDVContact.h deleted file mode 100644 index 5187efc..0000000 --- a/src/ios/CDVContact.h +++ /dev/null
@@ -1,136 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import <Foundation/Foundation.h> -#import <AddressBook/ABAddressBook.h> -#import <AddressBookUI/AddressBookUI.h> - -enum CDVContactError { - UNKNOWN_ERROR = 0, - INVALID_ARGUMENT_ERROR = 1, - TIMEOUT_ERROR = 2, - PENDING_OPERATION_ERROR = 3, - IO_ERROR = 4, - NOT_SUPPORTED_ERROR = 5, - PERMISSION_DENIED_ERROR = 20 -}; -typedef NSUInteger CDVContactError; - -@interface CDVContact : NSObject { - ABRecordRef record; // the ABRecord associated with this contact - NSDictionary* returnFields; // dictionary of fields to return when performing search -} - -@property (nonatomic, assign) ABRecordRef record; -@property (nonatomic, strong) NSDictionary* returnFields; - -+ (NSDictionary*)defaultABtoW3C; -+ (NSDictionary*)defaultW3CtoAB; -+ (NSSet*)defaultW3CtoNull; -+ (NSDictionary*)defaultObjectAndProperties; -+ (NSDictionary*)defaultFields; - -+ (NSDictionary*)calcReturnFields:(NSArray*)fields; -- (id)init; -- (id)initFromABRecord:(ABRecordRef)aRecord; -- (bool)setFromContactDict:(NSDictionary*)aContact asUpdate:(BOOL)bUpdate; - -+ (BOOL)needsConversion:(NSString*)W3Label; -+ (CFStringRef)convertContactTypeToPropertyLabel:(NSString*)label; -+ (NSString*)convertPropertyLabelToContactType:(NSString*)label; -+ (BOOL)isValidW3ContactType:(NSString*)label; -- (bool)setValue:(id)aValue forProperty:(ABPropertyID)aProperty inRecord:(ABRecordRef)aRecord asUpdate:(BOOL)bUpdate; - -- (NSDictionary*)toDictionary:(NSDictionary*)withFields; -- (NSNumber*)getDateAsNumber:(ABPropertyID)datePropId; -- (NSObject*)extractName; -- (NSObject*)extractMultiValue:(NSString*)propertyId; -- (NSObject*)extractAddresses; -- (NSObject*)extractIms; -- (NSObject*)extractOrganizations; -- (NSObject*)extractPhotos; - -- (NSMutableDictionary*)translateW3Dict:(NSDictionary*)dict forProperty:(ABPropertyID)prop; -- (bool)setMultiValueStrings:(NSArray*)fieldArray forProperty:(ABPropertyID)prop inRecord:(ABRecordRef)person asUpdate:(BOOL)bUpdate; -- (bool)setMultiValueDictionary:(NSArray*)array forProperty:(ABPropertyID)prop inRecord:(ABRecordRef)person asUpdate:(BOOL)bUpdate; -- (ABMultiValueRef)allocStringMultiValueFromArray:array; -- (ABMultiValueRef)allocDictMultiValueFromArray:array forProperty:(ABPropertyID)prop; -- (BOOL)foundValue:(NSString*)testValue inFields:(NSDictionary*)searchFields; -- (BOOL)testStringValue:(NSString*)testValue forW3CProperty:(NSString*)property; -- (BOOL)testDateValue:(NSString*)testValue forW3CProperty:(NSString*)property; -- (BOOL)searchContactFields:(NSArray*)fields forMVStringProperty:(ABPropertyID)propId withValue:testValue; -- (BOOL)testMultiValueStrings:(NSString*)testValue forProperty:(ABPropertyID)propId ofType:(NSString*)type; -- (NSArray*)valuesForProperty:(ABPropertyID)propId inRecord:(ABRecordRef)aRecord; -- (NSArray*)labelsForProperty:(ABPropertyID)propId inRecord:(ABRecordRef)aRecord; -- (BOOL)searchContactFields:(NSArray*)fields forMVDictionaryProperty:(ABPropertyID)propId withValue:(NSString*)testValue; - -@end - -// generic ContactField types -#define kW3ContactFieldType @"type" -#define kW3ContactFieldValue @"value" -#define kW3ContactFieldPrimary @"pref" -// Various labels for ContactField types -#define kW3ContactWorkLabel @"work" -#define kW3ContactHomeLabel @"home" -#define kW3ContactOtherLabel @"other" -#define kW3ContactPhoneFaxLabel @"fax" -#define kW3ContactPhoneMobileLabel @"mobile" -#define kW3ContactPhonePagerLabel @"pager" -#define kW3ContactUrlBlog @"blog" -#define kW3ContactUrlProfile @"profile" -#define kW3ContactImAIMLabel @"aim" -#define kW3ContactImICQLabel @"icq" -#define kW3ContactImMSNLabel @"msn" -#define kW3ContactImYahooLabel @"yahoo" -#define kW3ContactFieldId @"id" -// special translation for IM field value and type -#define kW3ContactImType @"type" -#define kW3ContactImValue @"value" - -// Contact object -#define kW3ContactId @"id" -#define kW3ContactName @"name" -#define kW3ContactFormattedName @"formatted" -#define kW3ContactGivenName @"givenName" -#define kW3ContactFamilyName @"familyName" -#define kW3ContactMiddleName @"middleName" -#define kW3ContactHonorificPrefix @"honorificPrefix" -#define kW3ContactHonorificSuffix @"honorificSuffix" -#define kW3ContactDisplayName @"displayName" -#define kW3ContactNickname @"nickname" -#define kW3ContactPhoneNumbers @"phoneNumbers" -#define kW3ContactAddresses @"addresses" -#define kW3ContactAddressFormatted @"formatted" -#define kW3ContactStreetAddress @"streetAddress" -#define kW3ContactLocality @"locality" -#define kW3ContactRegion @"region" -#define kW3ContactPostalCode @"postalCode" -#define kW3ContactCountry @"country" -#define kW3ContactEmails @"emails" -#define kW3ContactIms @"ims" -#define kW3ContactOrganizations @"organizations" -#define kW3ContactOrganizationName @"name" -#define kW3ContactTitle @"title" -#define kW3ContactDepartment @"department" -#define kW3ContactBirthday @"birthday" -#define kW3ContactNote @"note" -#define kW3ContactPhotos @"photos" -#define kW3ContactCategories @"categories" -#define kW3ContactUrls @"urls"
diff --git a/src/ios/CDVContact.m b/src/ios/CDVContact.m deleted file mode 100644 index 5bf9f3c..0000000 --- a/src/ios/CDVContact.m +++ /dev/null
@@ -1,1752 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import "CDVContact.h" -#import <Cordova/NSDictionary+Extensions.h> - -#define DATE_OR_NULL(dateObj) ((aDate != nil) ? (id)([aDate descriptionWithLocale:[NSLocale currentLocale]]) : (id)([NSNull null])) -#define IS_VALID_VALUE(value) ((value != nil) && (![value isKindOfClass:[NSNull class]])) - -static NSDictionary* org_apache_cordova_contacts_W3CtoAB = nil; -static NSDictionary* org_apache_cordova_contacts_ABtoW3C = nil; -static NSSet* org_apache_cordova_contacts_W3CtoNull = nil; -static NSDictionary* org_apache_cordova_contacts_objectAndProperties = nil; -static NSDictionary* org_apache_cordova_contacts_defaultFields = nil; - -@implementation CDVContact : NSObject - - @synthesize returnFields; - -- (id)init -{ - if ((self = [super init]) != nil) { - ABRecordRef rec = ABPersonCreate(); - self.record = rec; - if (rec) { - CFRelease(rec); - } - } - return self; -} - -- (id)initFromABRecord:(ABRecordRef)aRecord -{ - if ((self = [super init]) != nil) { - self.record = aRecord; - } - return self; -} - -/* synthesize 'record' ourselves to have retain properties for CF types */ - -- (void)setRecord:(ABRecordRef)aRecord -{ - if (record != NULL) { - CFRelease(record); - } - if (aRecord != NULL) { - record = CFRetain(aRecord); - } -} - -- (ABRecordRef)record -{ - return record; -} - -/* Rather than creating getters and setters for each AddressBook (AB) Property, generic methods are used to deal with - * simple properties, MultiValue properties( phone numbers and emails) and MultiValueDictionary properties (Ims and addresses). - * The dictionaries below are used to translate between the W3C identifiers and the AB properties. Using the dictionaries, - * allows looping through sets of properties to extract from or set into the W3C dictionary to/from the ABRecord. - */ - -/* The two following dictionaries translate between W3C properties and AB properties. It currently mixes both - * Properties (kABPersonAddressProperty for example) and Strings (kABPersonAddressStreetKey) so users should be aware of - * what types of values are expected. - * a bit. -*/ -+ (NSDictionary*)defaultABtoW3C -{ - if (org_apache_cordova_contacts_ABtoW3C == nil) { - org_apache_cordova_contacts_ABtoW3C = [NSDictionary dictionaryWithObjectsAndKeys: - kW3ContactNickname, [NSNumber numberWithInt:kABPersonNicknameProperty], - kW3ContactGivenName, [NSNumber numberWithInt:kABPersonFirstNameProperty], - kW3ContactFamilyName, [NSNumber numberWithInt:kABPersonLastNameProperty], - kW3ContactMiddleName, [NSNumber numberWithInt:kABPersonMiddleNameProperty], - kW3ContactHonorificPrefix, [NSNumber numberWithInt:kABPersonPrefixProperty], - kW3ContactHonorificSuffix, [NSNumber numberWithInt:kABPersonSuffixProperty], - kW3ContactPhoneNumbers, [NSNumber numberWithInt:kABPersonPhoneProperty], - kW3ContactAddresses, [NSNumber numberWithInt:kABPersonAddressProperty], - kW3ContactStreetAddress, kABPersonAddressStreetKey, - kW3ContactLocality, kABPersonAddressCityKey, - kW3ContactRegion, kABPersonAddressStateKey, - kW3ContactPostalCode, kABPersonAddressZIPKey, - kW3ContactCountry, kABPersonAddressCountryKey, - kW3ContactEmails, [NSNumber numberWithInt:kABPersonEmailProperty], - kW3ContactIms, [NSNumber numberWithInt:kABPersonInstantMessageProperty], - kW3ContactOrganizations, [NSNumber numberWithInt:kABPersonOrganizationProperty], - kW3ContactOrganizationName, [NSNumber numberWithInt:kABPersonOrganizationProperty], - kW3ContactTitle, [NSNumber numberWithInt:kABPersonJobTitleProperty], - kW3ContactDepartment, [NSNumber numberWithInt:kABPersonDepartmentProperty], - kW3ContactBirthday, [NSNumber numberWithInt:kABPersonBirthdayProperty], - kW3ContactUrls, [NSNumber numberWithInt:kABPersonURLProperty], - kW3ContactNote, [NSNumber numberWithInt:kABPersonNoteProperty], - nil]; - } - - return org_apache_cordova_contacts_ABtoW3C; -} - -+ (NSDictionary*)defaultW3CtoAB -{ - if (org_apache_cordova_contacts_W3CtoAB == nil) { - org_apache_cordova_contacts_W3CtoAB = [NSDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithInt:kABPersonNicknameProperty], kW3ContactNickname, - [NSNumber numberWithInt:kABPersonFirstNameProperty], kW3ContactGivenName, - [NSNumber numberWithInt:kABPersonLastNameProperty], kW3ContactFamilyName, - [NSNumber numberWithInt:kABPersonMiddleNameProperty], kW3ContactMiddleName, - [NSNumber numberWithInt:kABPersonPrefixProperty], kW3ContactHonorificPrefix, - [NSNumber numberWithInt:kABPersonSuffixProperty], kW3ContactHonorificSuffix, - [NSNumber numberWithInt:kABPersonPhoneProperty], kW3ContactPhoneNumbers, - [NSNumber numberWithInt:kABPersonAddressProperty], kW3ContactAddresses, - kABPersonAddressStreetKey, kW3ContactStreetAddress, - kABPersonAddressCityKey, kW3ContactLocality, - kABPersonAddressStateKey, kW3ContactRegion, - kABPersonAddressZIPKey, kW3ContactPostalCode, - kABPersonAddressCountryKey, kW3ContactCountry, - [NSNumber numberWithInt:kABPersonEmailProperty], kW3ContactEmails, - [NSNumber numberWithInt:kABPersonInstantMessageProperty], kW3ContactIms, - [NSNumber numberWithInt:kABPersonOrganizationProperty], kW3ContactOrganizations, - [NSNumber numberWithInt:kABPersonJobTitleProperty], kW3ContactTitle, - [NSNumber numberWithInt:kABPersonDepartmentProperty], kW3ContactDepartment, - [NSNumber numberWithInt:kABPersonBirthdayProperty], kW3ContactBirthday, - [NSNumber numberWithInt:kABPersonNoteProperty], kW3ContactNote, - [NSNumber numberWithInt:kABPersonURLProperty], kW3ContactUrls, - kABPersonInstantMessageUsernameKey, kW3ContactImValue, - kABPersonInstantMessageServiceKey, kW3ContactImType, - [NSNull null], kW3ContactFieldType, /* include entries in dictionary to indicate ContactField properties */ - [NSNull null], kW3ContactFieldValue, - [NSNull null], kW3ContactFieldPrimary, - [NSNull null], kW3ContactFieldId, - [NSNumber numberWithInt:kABPersonOrganizationProperty], kW3ContactOrganizationName, /* careful, name is used multiple times*/ - nil]; - } - return org_apache_cordova_contacts_W3CtoAB; -} - -+ (NSSet*)defaultW3CtoNull -{ - // these are values that have no AddressBook Equivalent OR have not been implemented yet - if (org_apache_cordova_contacts_W3CtoNull == nil) { - org_apache_cordova_contacts_W3CtoNull = [NSSet setWithObjects:kW3ContactDisplayName, - kW3ContactCategories, kW3ContactFormattedName, nil]; - } - return org_apache_cordova_contacts_W3CtoNull; -} - -/* - * The objectAndProperties dictionary contains the all of the properties of the W3C Contact Objects specified by the key - * Used in calcReturnFields, and various extract<Property> methods - */ -+ (NSDictionary*)defaultObjectAndProperties -{ - if (org_apache_cordova_contacts_objectAndProperties == nil) { - org_apache_cordova_contacts_objectAndProperties = [NSDictionary dictionaryWithObjectsAndKeys: - [NSArray arrayWithObjects:kW3ContactGivenName, kW3ContactFamilyName, - kW3ContactMiddleName, kW3ContactHonorificPrefix, kW3ContactHonorificSuffix, kW3ContactFormattedName, nil], kW3ContactName, - [NSArray arrayWithObjects:kW3ContactStreetAddress, kW3ContactLocality, kW3ContactRegion, - kW3ContactPostalCode, kW3ContactCountry, /*kW3ContactAddressFormatted,*/ nil], kW3ContactAddresses, - [NSArray arrayWithObjects:kW3ContactOrganizationName, kW3ContactTitle, kW3ContactDepartment, nil], kW3ContactOrganizations, - [NSArray arrayWithObjects:kW3ContactFieldType, kW3ContactFieldValue, kW3ContactFieldPrimary, nil], kW3ContactPhoneNumbers, - [NSArray arrayWithObjects:kW3ContactFieldType, kW3ContactFieldValue, kW3ContactFieldPrimary, nil], kW3ContactEmails, - [NSArray arrayWithObjects:kW3ContactFieldType, kW3ContactFieldValue, kW3ContactFieldPrimary, nil], kW3ContactPhotos, - [NSArray arrayWithObjects:kW3ContactFieldType, kW3ContactFieldValue, kW3ContactFieldPrimary, nil], kW3ContactUrls, - [NSArray arrayWithObjects:kW3ContactImValue, kW3ContactImType, nil], kW3ContactIms, - nil]; - } - return org_apache_cordova_contacts_objectAndProperties; -} - -+ (NSDictionary*)defaultFields -{ - if (org_apache_cordova_contacts_defaultFields == nil) { - org_apache_cordova_contacts_defaultFields = [NSDictionary dictionaryWithObjectsAndKeys: - [[CDVContact defaultObjectAndProperties] objectForKey:kW3ContactName], kW3ContactName, - [NSNull null], kW3ContactNickname, - [[CDVContact defaultObjectAndProperties] objectForKey:kW3ContactAddresses], kW3ContactAddresses, - [[CDVContact defaultObjectAndProperties] objectForKey:kW3ContactOrganizations], kW3ContactOrganizations, - [[CDVContact defaultObjectAndProperties] objectForKey:kW3ContactPhoneNumbers], kW3ContactPhoneNumbers, - [[CDVContact defaultObjectAndProperties] objectForKey:kW3ContactEmails], kW3ContactEmails, - [[CDVContact defaultObjectAndProperties] objectForKey:kW3ContactIms], kW3ContactIms, - [[CDVContact defaultObjectAndProperties] objectForKey:kW3ContactPhotos], kW3ContactPhotos, - [[CDVContact defaultObjectAndProperties] objectForKey:kW3ContactUrls], kW3ContactUrls, - [NSNull null], kW3ContactBirthday, - [NSNull null], kW3ContactNote, - nil]; - } - return org_apache_cordova_contacts_defaultFields; -} - -/* Translate W3C Contact data into ABRecordRef - * - * New contact information comes in as a NSMutableDictionary. All Null entries in Contact object are set - * as [NSNull null] in the dictionary when translating from the JSON input string of Contact data. However, if - * user did not set a value within a Contact object or sub-object (by not using the object constructor) some data - * may not exist. - * bUpdate = YES indicates this is a save of an existing record - */ -- (bool)setFromContactDict:(NSDictionary*)aContact asUpdate:(BOOL)bUpdate -{ - if (![aContact isKindOfClass:[NSDictionary class]]) { - return FALSE; // can't do anything if no dictionary! - } - - ABRecordRef person = self.record; - bool bSuccess = TRUE; - CFErrorRef error; - - // set name info - // iOS doesn't have displayName - might have to pull parts from it to create name - bool bName = false; - NSDictionary* dict = [aContact valueForKey:kW3ContactName]; - if ([dict isKindOfClass:[NSDictionary class]]) { - bName = true; - NSArray* propArray = [[CDVContact defaultObjectAndProperties] objectForKey:kW3ContactName]; - - for (id i in propArray) { - if (![(NSString*)i isEqualToString : kW3ContactFormattedName]) { // kW3ContactFormattedName is generated from ABRecordCopyCompositeName() and can't be set - [self setValue:[dict valueForKey:i] forProperty:(ABPropertyID)[(NSNumber*)[[CDVContact defaultW3CtoAB] objectForKey:i] intValue] - inRecord:person asUpdate:bUpdate]; - } - } - } - - id nn = [aContact valueForKey:kW3ContactNickname]; - if (![nn isKindOfClass:[NSNull class]]) { - bName = true; - [self setValue:nn forProperty:kABPersonNicknameProperty inRecord:person asUpdate:bUpdate]; - } - if (!bName) { - // if no name or nickname - try and use displayName as W3Contact must have displayName or ContactName - [self setValue:[aContact valueForKey:kW3ContactDisplayName] forProperty:kABPersonNicknameProperty - inRecord:person asUpdate:bUpdate]; - } - - // set phoneNumbers - // NSLog(@"setting phoneNumbers"); - NSArray* array = [aContact valueForKey:kW3ContactPhoneNumbers]; - if ([array isKindOfClass:[NSArray class]]) { - [self setMultiValueStrings:array forProperty:kABPersonPhoneProperty inRecord:person asUpdate:bUpdate]; - } - // set Emails - // NSLog(@"setting emails"); - array = [aContact valueForKey:kW3ContactEmails]; - if ([array isKindOfClass:[NSArray class]]) { - [self setMultiValueStrings:array forProperty:kABPersonEmailProperty inRecord:person asUpdate:bUpdate]; - } - // set Urls - // NSLog(@"setting urls"); - array = [aContact valueForKey:kW3ContactUrls]; - if ([array isKindOfClass:[NSArray class]]) { - [self setMultiValueStrings:array forProperty:kABPersonURLProperty inRecord:person asUpdate:bUpdate]; - } - - // set multivalue dictionary properties - // set addresses: streetAddress, locality, region, postalCode, country - // set ims: value = username, type = servicetype - // iOS addresses and im are a MultiValue Properties with label, value=dictionary of info, and id - // NSLog(@"setting addresses"); - error = nil; - array = [aContact valueForKey:kW3ContactAddresses]; - if ([array isKindOfClass:[NSArray class]]) { - [self setMultiValueDictionary:array forProperty:kABPersonAddressProperty inRecord:person asUpdate:bUpdate]; - } - // ims - // NSLog(@"setting ims"); - array = [aContact valueForKey:kW3ContactIms]; - if ([array isKindOfClass:[NSArray class]]) { - [self setMultiValueDictionary:array forProperty:kABPersonInstantMessageProperty inRecord:person asUpdate:bUpdate]; - } - - // organizations - // W3C ContactOrganization has pref, type, name, title, department - // iOS only supports name, title, department - // NSLog(@"setting organizations"); - // TODO this may need work - should Organization information be removed when array is empty?? - array = [aContact valueForKey:kW3ContactOrganizations]; // iOS only supports one organization - use first one - if ([array isKindOfClass:[NSArray class]]) { - BOOL bRemove = NO; - NSDictionary* dict = nil; - if ([array count] > 0) { - dict = [array objectAtIndex:0]; - } else { - // remove the organization info entirely - bRemove = YES; - } - if ([dict isKindOfClass:[NSDictionary class]] || (bRemove == YES)) { - [self setValue:(bRemove ? @"" : [dict valueForKey:@"name"]) forProperty:kABPersonOrganizationProperty inRecord:person asUpdate:bUpdate]; - [self setValue:(bRemove ? @"" : [dict valueForKey:kW3ContactTitle]) forProperty:kABPersonJobTitleProperty inRecord:person asUpdate:bUpdate]; - [self setValue:(bRemove ? @"" : [dict valueForKey:kW3ContactDepartment]) forProperty:kABPersonDepartmentProperty inRecord:person asUpdate:bUpdate]; - } - } - // add dates - // Dates come in as milliseconds in NSNumber Object - id ms = [aContact valueForKey:kW3ContactBirthday]; - NSDate* aDate = nil; - if (ms && [ms isKindOfClass:[NSNumber class]]) { - double msValue = [ms doubleValue]; - msValue = msValue / 1000; - aDate = [NSDate dateWithTimeIntervalSince1970:msValue]; - } - if ((aDate != nil) || [ms isKindOfClass:[NSString class]]) { - [self setValue:aDate != nil ? aDate:ms forProperty:kABPersonBirthdayProperty inRecord:person asUpdate:bUpdate]; - } - // don't update creation date - // modification date will get updated when save - // anniversary is removed from W3C Contact api Dec 9, 2010 spec - don't waste time on it yet - - // kABPersonDateProperty - - // kABPersonAnniversaryLabel - - // iOS doesn't have gender - ignore - // note - [self setValue:[aContact valueForKey:kW3ContactNote] forProperty:kABPersonNoteProperty inRecord:person asUpdate:bUpdate]; - - // iOS doesn't have preferredName- ignore - - // photo - array = [aContact valueForKey:kW3ContactPhotos]; - if ([array isKindOfClass:[NSArray class]]) { - if (bUpdate && ([array count] == 0)) { - // remove photo - bSuccess = ABPersonRemoveImageData(person, &error); - } else if ([array count] > 0) { - NSDictionary* dict = [array objectAtIndex:0]; // currently only support one photo - if ([dict isKindOfClass:[NSDictionary class]]) { - id value = [dict objectForKey:kW3ContactFieldValue]; - if ([value isKindOfClass:[NSString class]]) { - if (bUpdate && ([value length] == 0)) { - // remove the current image - bSuccess = ABPersonRemoveImageData(person, &error); - } else { - // use this image - // don't know if string is encoded or not so first unencode it then encode it again - NSString* cleanPath = [value stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; - NSURL* photoUrl = [NSURL URLWithString:[cleanPath stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; - // caller is responsible for checking for a connection, if no connection this will fail - NSError* err = nil; - NSData* data = nil; - if (photoUrl) { - data = [NSData dataWithContentsOfURL:photoUrl options:NSDataReadingUncached error:&err]; - } - if (data && ([data length] > 0)) { - bSuccess = ABPersonSetImageData(person, (__bridge CFDataRef)data, &error); - } - if (!data || !bSuccess) { - NSLog(@"error setting contact image: %@", (err != nil ? [err localizedDescription] : @"")); - } - } - } - } - } - } - - // TODO WebURLs - - // TODO timezone - - return bSuccess; -} - -/* Set item into an AddressBook Record for the specified property. - * aValue - the value to set into the address book (code checks for null or [NSNull null] - * aProperty - AddressBook property ID - * aRecord - the record to update - * bUpdate - whether this is a possible update vs a new entry - * RETURN - * true - property was set (or input value as null) - * false - property was not set - */ -- (bool)setValue:(id)aValue forProperty:(ABPropertyID)aProperty inRecord:(ABRecordRef)aRecord asUpdate:(BOOL)bUpdate -{ - bool bSuccess = true; // if property was null, just ignore and return success - CFErrorRef error; - - if (aValue && ![aValue isKindOfClass:[NSNull class]]) { - if (bUpdate && ([aValue isKindOfClass:[NSString class]] && ([aValue length] == 0))) { // if updating, empty string means to delete - aValue = NULL; - } // really only need to set if different - more efficient to just update value or compare and only set if necessary??? - bSuccess = ABRecordSetValue(aRecord, aProperty, (__bridge CFTypeRef)aValue, &error); - if (!bSuccess) { - NSLog(@"error setting %d property", aProperty); - } - } - - return bSuccess; -} - -- (bool)removeProperty:(ABPropertyID)aProperty inRecord:(ABRecordRef)aRecord -{ - CFErrorRef err; - bool bSuccess = ABRecordRemoveValue(aRecord, aProperty, &err); - - if (!bSuccess) { - CFStringRef errDescription = CFErrorCopyDescription(err); - NSLog(@"Unable to remove property %d: %@", aProperty, errDescription); - CFRelease(errDescription); - } - return bSuccess; -} - -- (bool)addToMultiValue:(ABMultiValueRef)multi fromDictionary:dict -{ - bool bSuccess = FALSE; - id value = [dict valueForKey:kW3ContactFieldValue]; - - if (IS_VALID_VALUE(value)) { - CFStringRef label = [CDVContact convertContactTypeToPropertyLabel:[dict valueForKey:kW3ContactFieldType]]; - bSuccess = ABMultiValueAddValueAndLabel(multi, (__bridge CFTypeRef)value, label, NULL); - if (!bSuccess) { - NSLog(@"Error setting Value: %@ and label: %@", value, label); - } - } - return bSuccess; -} - -- (ABMultiValueRef)allocStringMultiValueFromArray:array -{ - ABMutableMultiValueRef multi = ABMultiValueCreateMutable(kABMultiStringPropertyType); - - for (NSDictionary* dict in array) { - [self addToMultiValue:multi fromDictionary:dict]; - } - - return multi; // caller is responsible for releasing multi -} - -- (bool)setValue:(CFTypeRef)value forProperty:(ABPropertyID)prop inRecord:(ABRecordRef)person -{ - CFErrorRef error; - bool bSuccess = ABRecordSetValue(person, prop, value, &error); - - if (!bSuccess) { - NSLog(@"Error setting value for property: %d", prop); - } - return bSuccess; -} - -/* Set MultiValue string properties into Address Book Record. - * NSArray* fieldArray - array of dictionaries containing W3C properties to be set into record - * ABPropertyID prop - the property to be set (generally used for phones and emails) - * ABRecordRef person - the record to set values into - * BOOL bUpdate - whether or not to update date or set as new. - * When updating: - * empty array indicates to remove entire property - * empty string indicates to remove - * [NSNull null] do not modify (keep existing record value) - * RETURNS - * bool false indicates error - * - * used for phones and emails - */ -- (bool)setMultiValueStrings:(NSArray*)fieldArray forProperty:(ABPropertyID)prop inRecord:(ABRecordRef)person asUpdate:(BOOL)bUpdate -{ - bool bSuccess = TRUE; - ABMutableMultiValueRef multi = nil; - - if (!bUpdate) { - multi = [self allocStringMultiValueFromArray:fieldArray]; - bSuccess = [self setValue:multi forProperty:prop inRecord:person]; - } else if (bUpdate && ([fieldArray count] == 0)) { - // remove entire property - bSuccess = [self removeProperty:prop inRecord:person]; - } else { // check for and apply changes - ABMultiValueRef copy = ABRecordCopyValue(person, prop); - if (copy != nil) { - multi = ABMultiValueCreateMutableCopy(copy); - CFRelease(copy); - - for (NSDictionary* dict in fieldArray) { - id val; - NSString* label = nil; - val = [dict valueForKey:kW3ContactFieldValue]; - label = (__bridge NSString*)[CDVContact convertContactTypeToPropertyLabel:[dict valueForKey:kW3ContactFieldType]]; - if (IS_VALID_VALUE(val)) { - // is an update, find index of entry with matching id, if values are different, update. - id idValue = [dict valueForKey:kW3ContactFieldId]; - int identifier = [idValue isKindOfClass:[NSNumber class]] ? [idValue intValue] : -1; - CFIndex i = identifier >= 0 ? ABMultiValueGetIndexForIdentifier(multi, identifier) : kCFNotFound; - if (i != kCFNotFound) { - if ([val length] == 0) { - // remove both value and label - ABMultiValueRemoveValueAndLabelAtIndex(multi, i); - } else { - NSString* valueAB = (__bridge_transfer NSString*)ABMultiValueCopyValueAtIndex(multi, i); - NSString* labelAB = (__bridge_transfer NSString*)ABMultiValueCopyLabelAtIndex(multi, i); - if ((valueAB == nil) || ![val isEqualToString:valueAB]) { - ABMultiValueReplaceValueAtIndex(multi, (__bridge CFTypeRef)val, i); - } - if ((labelAB == nil) || ![label isEqualToString:labelAB]) { - ABMultiValueReplaceLabelAtIndex(multi, (__bridge CFStringRef)label, i); - } - } - } else { - // is a new value - insert - [self addToMultiValue:multi fromDictionary:dict]; - } - } // end of if value - } // end of for - } else { // adding all new value(s) - multi = [self allocStringMultiValueFromArray:fieldArray]; - } - // set the (updated) copy as the new value - bSuccess = [self setValue:multi forProperty:prop inRecord:person]; - } - - if (multi) { - CFRelease(multi); - } - - return bSuccess; -} - -// used for ims and addresses -- (ABMultiValueRef)allocDictMultiValueFromArray:array forProperty:(ABPropertyID)prop -{ - ABMutableMultiValueRef multi = ABMultiValueCreateMutable(kABMultiDictionaryPropertyType); - NSMutableDictionary* newDict; - NSMutableDictionary* addDict; - - for (NSDictionary* dict in array) { - newDict = [self translateW3Dict:dict forProperty:prop]; - addDict = [NSMutableDictionary dictionaryWithCapacity:2]; - if (newDict) { // create a new dictionary with a Label and Value, value is the dictionary previously created - // June, 2011 W3C Contact spec adds type into ContactAddress book - // get the type out of the original dictionary for address - NSString* addrType = (NSString*)[dict valueForKey:kW3ContactFieldType]; - if (!addrType) { - addrType = (NSString*)kABOtherLabel; - } - NSObject* typeValue = ((prop == kABPersonInstantMessageProperty) ? (NSObject*)kABOtherLabel : addrType); - // NSLog(@"typeValue: %@", typeValue); - [addDict setObject:typeValue forKey:kW3ContactFieldType]; // im labels will be set as Other and address labels as type from dictionary - [addDict setObject:newDict forKey:kW3ContactFieldValue]; - [self addToMultiValue:multi fromDictionary:addDict]; - } - } - - return multi; // caller is responsible for releasing -} - -// used for ims and addresses to convert W3 dictionary of values to AB Dictionary -// got messier when June, 2011 W3C Contact spec added type field into ContactAddress -- (NSMutableDictionary*)translateW3Dict:(NSDictionary*)dict forProperty:(ABPropertyID)prop -{ - NSArray* propArray = [[CDVContact defaultObjectAndProperties] valueForKey:[[CDVContact defaultABtoW3C] objectForKey:[NSNumber numberWithInt:prop]]]; - - NSMutableDictionary* newDict = [NSMutableDictionary dictionaryWithCapacity:1]; - id value; - - for (NSString* key in propArray) { // for each W3 Contact key get the value - if (((value = [dict valueForKey:key]) != nil) && ![value isKindOfClass:[NSNull class]]) { - // if necessary convert the W3 value to AB Property label - NSString* setValue = value; - if ([CDVContact needsConversion:key]) { // IM types must be converted - setValue = (NSString*)[CDVContact convertContactTypeToPropertyLabel:value]; - // IMs must have a valid AB value! - if ((prop == kABPersonInstantMessageProperty) && [setValue isEqualToString:(NSString*)kABOtherLabel]) { - setValue = @""; // try empty string - } - } - // set the AB value into the dictionary - [newDict setObject:setValue forKey:(NSString*)[[CDVContact defaultW3CtoAB] valueForKey:(NSString*)key]]; - } - } - - if ([newDict count] == 0) { - newDict = nil; // no items added - } - return newDict; -} - -/* set multivalue dictionary properties into an AddressBook Record - * NSArray* array - array of dictionaries containing the W3C properties to set into the record - * ABPropertyID prop - the property id for the multivalue dictionary (addresses and ims) - * ABRecordRef person - the record to set the values into - * BOOL bUpdate - YES if this is an update to an existing record - * When updating: - * empty array indicates to remove entire property - * value/label == "" indicates to remove - * value/label == [NSNull null] do not modify (keep existing record value) - * RETURN - * bool false indicates fatal error - * - * iOS addresses and im are a MultiValue Properties with label, value=dictionary of info, and id - * set addresses: streetAddress, locality, region, postalCode, country - * set ims: value = username, type = servicetype - * there are some special cases in here for ims - needs cleanup / simplification - * - */ -- (bool)setMultiValueDictionary:(NSArray*)array forProperty:(ABPropertyID)prop inRecord:(ABRecordRef)person asUpdate:(BOOL)bUpdate -{ - bool bSuccess = FALSE; - ABMutableMultiValueRef multi = nil; - - if (!bUpdate) { - multi = [self allocDictMultiValueFromArray:array forProperty:prop]; - bSuccess = [self setValue:multi forProperty:prop inRecord:person]; - } else if (bUpdate && ([array count] == 0)) { - // remove property - bSuccess = [self removeProperty:prop inRecord:person]; - } else { // check for and apply changes - ABMultiValueRef copy = ABRecordCopyValue(person, prop); - if (copy) { - multi = ABMultiValueCreateMutableCopy(copy); - CFRelease(copy); - // get the W3C values for this property - NSArray* propArray = [[CDVContact defaultObjectAndProperties] valueForKey:[[CDVContact defaultABtoW3C] objectForKey:[NSNumber numberWithInt:prop]]]; - id value; - id valueAB; - - for (NSDictionary* field in array) { - NSMutableDictionary* dict; - // find the index for the current property - id idValue = [field valueForKey:kW3ContactFieldId]; - int identifier = [idValue isKindOfClass:[NSNumber class]] ? [idValue intValue] : -1; - CFIndex idx = identifier >= 0 ? ABMultiValueGetIndexForIdentifier(multi, identifier) : kCFNotFound; - BOOL bUpdateLabel = NO; - if (idx != kCFNotFound) { - dict = [NSMutableDictionary dictionaryWithCapacity:1]; - // NSDictionary* existingDictionary = (NSDictionary*)ABMultiValueCopyValueAtIndex(multi, idx); - CFTypeRef existingDictionary = ABMultiValueCopyValueAtIndex(multi, idx); - NSString* existingABLabel = (__bridge_transfer NSString*)ABMultiValueCopyLabelAtIndex(multi, idx); - NSString* testLabel = [field valueForKey:kW3ContactFieldType]; - // fixes cb-143 where setting empty label could cause address to not be removed - // (because empty label would become 'other' in convertContactTypeToPropertyLabel - // which may not have matched existing label thus resulting in an incorrect updating of the label - // and the address not getting removed at the end of the for loop) - if (testLabel && [testLabel isKindOfClass:[NSString class]] && ([testLabel length] > 0)) { - CFStringRef w3cLabel = [CDVContact convertContactTypeToPropertyLabel:testLabel]; - if (w3cLabel && ![existingABLabel isEqualToString:(__bridge NSString*)w3cLabel]) { - // replace the label - ABMultiValueReplaceLabelAtIndex(multi, w3cLabel, idx); - bUpdateLabel = YES; - } - } // else was invalid or empty label string so do not update - - for (id k in propArray) { - value = [field valueForKey:k]; - bool bSet = (value != nil && ![value isKindOfClass:[NSNull class]] && ([value isKindOfClass:[NSString class]] && [value length] > 0)); - // if there is a contact value, put it into dictionary - if (bSet) { - NSString* setValue = [CDVContact needsConversion:(NSString*)k] ? (NSString*)[CDVContact convertContactTypeToPropertyLabel:value] : value; - [dict setObject:setValue forKey:(NSString*)[[CDVContact defaultW3CtoAB] valueForKey:(NSString*)k]]; - } else if ((value == nil) || ([value isKindOfClass:[NSString class]] && ([value length] != 0))) { - // value not provided in contact dictionary - if prop exists in AB dictionary, preserve it - valueAB = [(__bridge NSDictionary*)existingDictionary valueForKey : [[CDVContact defaultW3CtoAB] valueForKey:k]]; - if (valueAB != nil) { - [dict setValue:valueAB forKey:[[CDVContact defaultW3CtoAB] valueForKey:k]]; - } - } // else if value == "" it will not be added into updated dict and thus removed - } // end of for loop (moving here fixes cb-143, need to end for loop before replacing or removing multivalue) - - if ([dict count] > 0) { - // something was added into new dict, - ABMultiValueReplaceValueAtIndex(multi, (__bridge CFTypeRef)dict, idx); - } else if (!bUpdateLabel) { - // nothing added into new dict and no label change so remove this property entry - ABMultiValueRemoveValueAndLabelAtIndex(multi, idx); - } - - CFRelease(existingDictionary); - } else { - // not found in multivalue so add it - dict = [self translateW3Dict:field forProperty:prop]; - if (dict) { - NSMutableDictionary* addDict = [NSMutableDictionary dictionaryWithCapacity:2]; - // get the type out of the original dictionary for address - NSObject* typeValue = ((prop == kABPersonInstantMessageProperty) ? (NSObject*)kABOtherLabel : (NSString*)[field valueForKey:kW3ContactFieldType]); - // NSLog(@"typeValue: %@", typeValue); - [addDict setObject:typeValue forKey:kW3ContactFieldType]; // im labels will be set as Other and address labels as type from dictionary - [addDict setObject:dict forKey:kW3ContactFieldValue]; - [self addToMultiValue:multi fromDictionary:addDict]; - } - } - } // end of looping through dictionaries - - // set the (updated) copy as the new value - bSuccess = [self setValue:multi forProperty:prop inRecord:person]; - } - } // end of copy and apply changes - if (multi) { - CFRelease(multi); - } - - return bSuccess; -} - -/* Determine which W3C labels need to be converted - */ -+ (BOOL)needsConversion:(NSString*)W3Label -{ - BOOL bConvert = NO; - - if ([W3Label isEqualToString:kW3ContactFieldType] || [W3Label isEqualToString:kW3ContactImType]) { - bConvert = YES; - } - return bConvert; -} - -/* Translation of property type labels contact API ---> iPhone - * - * phone: work, home, other, mobile, fax, pager --> - * kABWorkLabel, kABHomeLabel, kABOtherLabel, kABPersonPhoneMobileLabel, kABPersonHomeFAXLabel || kABPersonHomeFAXLabel, kABPersonPhonePagerLabel - * emails: work, home, other ---> kABWorkLabel, kABHomeLabel, kABOtherLabel - * ims: aim, gtalk, icq, xmpp, msn, skype, qq, yahoo --> kABPersonInstantMessageService + (AIM, ICG, MSN, Yahoo). No support for gtalk, xmpp, skype, qq - * addresses: work, home, other --> kABWorkLabel, kABHomeLabel, kABOtherLabel - * - * - */ -+ (CFStringRef)convertContactTypeToPropertyLabel:(NSString*)label -{ - CFStringRef type; - - if ([label isKindOfClass:[NSNull class]] || ![label isKindOfClass:[NSString class]]) { - type = NULL; // no label - } else if ([label caseInsensitiveCompare:kW3ContactWorkLabel] == NSOrderedSame) { - type = kABWorkLabel; - } else if ([label caseInsensitiveCompare:kW3ContactHomeLabel] == NSOrderedSame) { - type = kABHomeLabel; - } else if ([label caseInsensitiveCompare:kW3ContactOtherLabel] == NSOrderedSame) { - type = kABOtherLabel; - } else if ([label caseInsensitiveCompare:kW3ContactPhoneMobileLabel] == NSOrderedSame) { - type = kABPersonPhoneMobileLabel; - } else if ([label caseInsensitiveCompare:kW3ContactPhonePagerLabel] == NSOrderedSame) { - type = kABPersonPhonePagerLabel; - } else if ([label caseInsensitiveCompare:kW3ContactImAIMLabel] == NSOrderedSame) { - type = kABPersonInstantMessageServiceAIM; - } else if ([label caseInsensitiveCompare:kW3ContactImICQLabel] == NSOrderedSame) { - type = kABPersonInstantMessageServiceICQ; - } else if ([label caseInsensitiveCompare:kW3ContactImMSNLabel] == NSOrderedSame) { - type = kABPersonInstantMessageServiceMSN; - } else if ([label caseInsensitiveCompare:kW3ContactImYahooLabel] == NSOrderedSame) { - type = kABPersonInstantMessageServiceYahoo; - } else if ([label caseInsensitiveCompare:kW3ContactUrlProfile] == NSOrderedSame) { - type = kABPersonHomePageLabel; - } else { - type = kABOtherLabel; - } - - return type; -} - -+ (NSString*)convertPropertyLabelToContactType:(NSString*)label -{ - NSString* type = nil; - - if (label != nil) { // improve efficiency...... - if ([label isEqualToString:(NSString*)kABPersonPhoneMobileLabel]) { - type = kW3ContactPhoneMobileLabel; - } else if ([label isEqualToString:(NSString*)kABPersonPhoneHomeFAXLabel] || - [label isEqualToString:(NSString*)kABPersonPhoneWorkFAXLabel]) { - type = kW3ContactPhoneFaxLabel; - } else if ([label isEqualToString:(NSString*)kABPersonPhonePagerLabel]) { - type = kW3ContactPhonePagerLabel; - } else if ([label isEqualToString:(NSString*)kABHomeLabel]) { - type = kW3ContactHomeLabel; - } else if ([label isEqualToString:(NSString*)kABWorkLabel]) { - type = kW3ContactWorkLabel; - } else if ([label isEqualToString:(NSString*)kABOtherLabel]) { - type = kW3ContactOtherLabel; - } else if ([label isEqualToString:(NSString*)kABPersonInstantMessageServiceAIM]) { - type = kW3ContactImAIMLabel; - } else if ([label isEqualToString:(NSString*)kABPersonInstantMessageServiceICQ]) { - type = kW3ContactImICQLabel; - } else if ([label isEqualToString:(NSString*)kABPersonInstantMessageServiceJabber]) { - type = kW3ContactOtherLabel; - } else if ([label isEqualToString:(NSString*)kABPersonInstantMessageServiceMSN]) { - type = kW3ContactImMSNLabel; - } else if ([label isEqualToString:(NSString*)kABPersonInstantMessageServiceYahoo]) { - type = kW3ContactImYahooLabel; - } else if ([label isEqualToString:(NSString*)kABPersonHomePageLabel]) { - type = kW3ContactUrlProfile; - } else { - type = kW3ContactOtherLabel; - } - } - return type; -} - -/* Check if the input label is a valid W3C ContactField.type. This is used when searching, - * only search field types if the search string is a valid type. If we converted any search - * string to a ABPropertyLabel it could convert to kABOtherLabel which is probably not want - * the user wanted to search for and could skew the results. - */ -+ (BOOL)isValidW3ContactType:(NSString*)label -{ - BOOL isValid = NO; - - if ([label isKindOfClass:[NSNull class]] || ![label isKindOfClass:[NSString class]]) { - isValid = NO; // no label - } else if ([label caseInsensitiveCompare:kW3ContactWorkLabel] == NSOrderedSame) { - isValid = YES; - } else if ([label caseInsensitiveCompare:kW3ContactHomeLabel] == NSOrderedSame) { - isValid = YES; - } else if ([label caseInsensitiveCompare:kW3ContactOtherLabel] == NSOrderedSame) { - isValid = YES; - } else if ([label caseInsensitiveCompare:kW3ContactPhoneMobileLabel] == NSOrderedSame) { - isValid = YES; - } else if ([label caseInsensitiveCompare:kW3ContactPhonePagerLabel] == NSOrderedSame) { - isValid = YES; - } else if ([label caseInsensitiveCompare:kW3ContactImAIMLabel] == NSOrderedSame) { - isValid = YES; - } else if ([label caseInsensitiveCompare:kW3ContactImICQLabel] == NSOrderedSame) { - isValid = YES; - } else if ([label caseInsensitiveCompare:kW3ContactImMSNLabel] == NSOrderedSame) { - isValid = YES; - } else if ([label caseInsensitiveCompare:kW3ContactImYahooLabel] == NSOrderedSame) { - isValid = YES; - } else { - isValid = NO; - } - - return isValid; -} - -/* Create a new Contact Dictionary object from an ABRecordRef that contains information in a format such that - * it can be returned to JavaScript callback as JSON object string. - * Uses: - * ABRecordRef set into Contact Object - * NSDictionary withFields indicates which fields to return from the AddressBook Record - * - * JavaScript Contact: - * @param {DOMString} id unique identifier - * @param {DOMString} displayName - * @param {ContactName} name - * @param {DOMString} nickname - * @param {ContactField[]} phoneNumbers array of phone numbers - * @param {ContactField[]} emails array of email addresses - * @param {ContactAddress[]} addresses array of addresses - * @param {ContactField[]} ims instant messaging user ids - * @param {ContactOrganization[]} organizations - * @param {DOMString} published date contact was first created - * @param {DOMString} updated date contact was last updated - * @param {DOMString} birthday contact's birthday - * @param (DOMString} anniversary contact's anniversary - * @param {DOMString} gender contact's gender - * @param {DOMString} note user notes about contact - * @param {DOMString} preferredUsername - * @param {ContactField[]} photos - * @param {ContactField[]} tags - * @param {ContactField[]} relationships - * @param {ContactField[]} urls contact's web sites - * @param {ContactAccounts[]} accounts contact's online accounts - * @param {DOMString} timezone UTC time zone offset - * @param {DOMString} connected - */ - -- (NSDictionary*)toDictionary:(NSDictionary*)withFields -{ - // if not a person type record bail out for now - if (ABRecordGetRecordType(self.record) != kABPersonType) { - return NULL; - } - id value = nil; - self.returnFields = withFields; - - NSMutableDictionary* nc = [NSMutableDictionary dictionaryWithCapacity:1]; // new contact dictionary to fill in from ABRecordRef - // id - [nc setObject:[NSNumber numberWithInt:ABRecordGetRecordID(self.record)] forKey:kW3ContactId]; - if (self.returnFields == nil) { - // if no returnFields specified, W3C says to return empty contact (but Cordova will at least return id) - return nc; - } - if ([self.returnFields objectForKey:kW3ContactDisplayName]) { - // displayname requested - iOS doesn't have so return null - [nc setObject:[NSNull null] forKey:kW3ContactDisplayName]; - // may overwrite below if requested ContactName and there are no values - } - // nickname - if ([self.returnFields valueForKey:kW3ContactNickname]) { - value = (__bridge_transfer NSString*)ABRecordCopyValue(self.record, kABPersonNicknameProperty); - [nc setObject:(value != nil) ? value:[NSNull null] forKey:kW3ContactNickname]; - } - - // name dictionary - // NSLog(@"getting name info"); - NSObject* data = [self extractName]; - if (data != nil) { - [nc setObject:data forKey:kW3ContactName]; - } - if ([self.returnFields objectForKey:kW3ContactDisplayName] && ((data == nil) || ([(NSDictionary*)data objectForKey : kW3ContactFormattedName] == [NSNull null]))) { - // user asked for displayName which iOS doesn't support but there is no other name data being returned - // try and use Composite Name so some name is returned - id tryName = (__bridge_transfer NSString*)ABRecordCopyCompositeName(self.record); - if (tryName != nil) { - [nc setObject:tryName forKey:kW3ContactDisplayName]; - } else { - // use nickname or empty string - value = (__bridge_transfer NSString*)ABRecordCopyValue(self.record, kABPersonNicknameProperty); - [nc setObject:(value != nil) ? value:@"" forKey:kW3ContactDisplayName]; - } - } - // phoneNumbers array - // NSLog(@"getting phoneNumbers"); - value = [self extractMultiValue:kW3ContactPhoneNumbers]; - if (value != nil) { - [nc setObject:value forKey:kW3ContactPhoneNumbers]; - } - // emails array - // NSLog(@"getting emails"); - value = [self extractMultiValue:kW3ContactEmails]; - if (value != nil) { - [nc setObject:value forKey:kW3ContactEmails]; - } - // urls array - value = [self extractMultiValue:kW3ContactUrls]; - if (value != nil) { - [nc setObject:value forKey:kW3ContactUrls]; - } - // addresses array - // NSLog(@"getting addresses"); - value = [self extractAddresses]; - if (value != nil) { - [nc setObject:value forKey:kW3ContactAddresses]; - } - // im array - // NSLog(@"getting ims"); - value = [self extractIms]; - if (value != nil) { - [nc setObject:value forKey:kW3ContactIms]; - } - // organization array (only info for one organization in iOS) - // NSLog(@"getting organizations"); - value = [self extractOrganizations]; - if (value != nil) { - [nc setObject:value forKey:kW3ContactOrganizations]; - } - - // for simple properties, could make this a bit more efficient by storing all simple properties in a single - // array in the returnFields dictionary and setting them via a for loop through the array - - // add dates - // NSLog(@"getting dates"); - NSNumber* ms; - - /** Contact Revision field removed from June 16, 2011 version of specification - - if ([self.returnFields valueForKey:kW3ContactUpdated]){ - ms = [self getDateAsNumber: kABPersonModificationDateProperty]; - if (!ms){ - // try and get published date - ms = [self getDateAsNumber: kABPersonCreationDateProperty]; - } - if (ms){ - [nc setObject: ms forKey:kW3ContactUpdated]; - } - - } - */ - - if ([self.returnFields valueForKey:kW3ContactBirthday]) { - ms = [self getDateAsNumber:kABPersonBirthdayProperty]; - if (ms) { - [nc setObject:ms forKey:kW3ContactBirthday]; - } - } - - /* Anniversary removed from 12-09-2010 W3C Contacts api spec - if ([self.returnFields valueForKey:kW3ContactAnniversary]){ - // Anniversary date is stored in a multivalue property - ABMultiValueRef multi = ABRecordCopyValue(self.record, kABPersonDateProperty); - if (multi){ - CFStringRef label = nil; - CFIndex count = ABMultiValueGetCount(multi); - // see if contains an Anniversary date - for(CFIndex i=0; i<count; i++){ - label = ABMultiValueCopyLabelAtIndex(multi, i); - if(label && [(NSString*)label isEqualToString:(NSString*)kABPersonAnniversaryLabel]){ - CFDateRef aDate = ABMultiValueCopyValueAtIndex(multi, i); - if(aDate){ - [nc setObject: (NSString*)aDate forKey: kW3ContactAnniversary]; - CFRelease(aDate); - } - CFRelease(label); - break; - } - } - CFRelease(multi); - } - }*/ - - if ([self.returnFields valueForKey:kW3ContactNote]) { - // note - value = (__bridge_transfer NSString*)ABRecordCopyValue(self.record, kABPersonNoteProperty); - [nc setObject:(value != nil) ? value:[NSNull null] forKey:kW3ContactNote]; - } - - if ([self.returnFields valueForKey:kW3ContactPhotos]) { - value = [self extractPhotos]; - [nc setObject:(value != nil) ? value:[NSNull null] forKey:kW3ContactPhotos]; - } - - /* TimeZone removed from June 16, 2011 Contacts spec - * - if ([self.returnFields valueForKey:kW3ContactTimezone]){ - [NSTimeZone resetSystemTimeZone]; - NSTimeZone* currentTZ = [NSTimeZone localTimeZone]; - NSInteger seconds = [currentTZ secondsFromGMT]; - NSString* tz = [NSString stringWithFormat:@"%2d:%02u", seconds/3600, seconds % 3600 ]; - [nc setObject:tz forKey:kW3ContactTimezone]; - } - */ - // TODO WebURLs - // [nc setObject:[NSNull null] forKey:kW3ContactUrls]; - // online accounts - not available on iOS - - return nc; -} - -- (NSNumber*)getDateAsNumber:(ABPropertyID)datePropId -{ - NSNumber* msDate = nil; - NSDate* aDate = nil; - CFTypeRef cfDate = ABRecordCopyValue(self.record, datePropId); - - if (cfDate) { - aDate = (__bridge NSDate*)cfDate; - msDate = [NSNumber numberWithDouble:([aDate timeIntervalSince1970] * 1000)]; - CFRelease(cfDate); - } - return msDate; -} - -/* Create Dictionary to match JavaScript ContactName object: - * formatted - ABRecordCopyCompositeName - * familyName - * givenName - * middleName - * honorificPrefix - * honorificSuffix -*/ - -- (NSObject*)extractName -{ - NSArray* fields = [self.returnFields objectForKey:kW3ContactName]; - - if (fields == nil) { // no name fields requested - return nil; - } - - NSMutableDictionary* newName = [NSMutableDictionary dictionaryWithCapacity:6]; - id value; - - for (NSString* i in fields) { - if ([i isEqualToString:kW3ContactFormattedName]) { - value = (__bridge_transfer NSString*)ABRecordCopyCompositeName(self.record); - [newName setObject:(value != nil) ? value:[NSNull null] forKey:kW3ContactFormattedName]; - } else { - // W3CtoAB returns NSNumber for AB name properties, get intValue and cast to ABPropertyID) - value = (__bridge_transfer NSString*)ABRecordCopyValue(self.record, (ABPropertyID)[[[CDVContact defaultW3CtoAB] valueForKey:i] intValue]); - [newName setObject:(value != nil) ? value:[NSNull null] forKey:(NSString*)i]; - } - } - - return newName; -} - -/* Create array of Dictionaries to match JavaScript ContactField object for simple multiValue properties phoneNumbers, emails - * Input: (NSString*) W3Contact Property name - * type - * for phoneNumbers type is one of (work,home,other, mobile, fax, pager) - * for emails type is one of (work,home, other) - * value - phone number or email address - * (bool) primary (not supported on iphone) - * id -*/ -- (NSObject*)extractMultiValue:(NSString*)propertyId -{ - NSArray* fields = [self.returnFields objectForKey:propertyId]; - - if (fields == nil) { - return nil; - } - ABMultiValueRef multi = nil; - NSObject* valuesArray = nil; - NSNumber* propNumber = [[CDVContact defaultW3CtoAB] valueForKey:propertyId]; - ABPropertyID propId = [propNumber intValue]; - multi = ABRecordCopyValue(self.record, propId); - // multi = ABRecordCopyValue(self.record, (ABPropertyID)[[[Contact defaultW3CtoAB] valueForKey:propertyId] intValue]); - CFIndex count = multi != nil ? ABMultiValueGetCount(multi) : 0; - id value; - if (count) { - valuesArray = [NSMutableArray arrayWithCapacity:count]; - - for (CFIndex i = 0; i < count; i++) { - NSMutableDictionary* newDict = [NSMutableDictionary dictionaryWithCapacity:4]; - if ([fields containsObject:kW3ContactFieldType]) { - NSString* label = (__bridge_transfer NSString*)ABMultiValueCopyLabelAtIndex(multi, i); - value = [CDVContact convertPropertyLabelToContactType:label]; - [newDict setObject:(value != nil) ? value:[NSNull null] forKey:kW3ContactFieldType]; - } - if ([fields containsObject:kW3ContactFieldValue]) { - value = (__bridge_transfer NSString*)ABMultiValueCopyValueAtIndex(multi, i); - [newDict setObject:(value != nil) ? value:[NSNull null] forKey:kW3ContactFieldValue]; - } - if ([fields containsObject:kW3ContactFieldPrimary]) { - [newDict setObject:[NSNumber numberWithBool:(BOOL)NO] forKey:kW3ContactFieldPrimary]; // iOS doesn't support primary so set all to false - } - // always set id - value = [NSNumber numberWithUnsignedInt:ABMultiValueGetIdentifierAtIndex(multi, i)]; - [newDict setObject:(value != nil) ? value:[NSNull null] forKey:kW3ContactFieldId]; - [(NSMutableArray*)valuesArray addObject : newDict]; - } - } else { - valuesArray = [NSNull null]; - } - if (multi) { - CFRelease(multi); - } - - return valuesArray; -} - -/* Create array of Dictionaries to match JavaScript ContactAddress object for addresses - * pref - not supported - * type - address type - * formatted - formatted for mailing label (what about localization?) - * streetAddress - * locality - * region; - * postalCode - * country - * id - * - * iOS addresses are a MultiValue Properties with label, value=dictionary of address info, and id - */ -- (NSObject*)extractAddresses -{ - NSArray* fields = [self.returnFields objectForKey:kW3ContactAddresses]; - - if (fields == nil) { // no name fields requested - return nil; - } - CFStringRef value; - NSObject* addresses; - ABMultiValueRef multi = ABRecordCopyValue(self.record, kABPersonAddressProperty); - CFIndex count = multi ? ABMultiValueGetCount(multi) : 0; - if (count) { - addresses = [NSMutableArray arrayWithCapacity:count]; - - for (CFIndex i = 0; i < count; i++) { - NSMutableDictionary* newAddress = [NSMutableDictionary dictionaryWithCapacity:7]; - // if we got this far, at least some address info is being requested. - - // Always set id - id identifier = [NSNumber numberWithUnsignedInt:ABMultiValueGetIdentifierAtIndex(multi, i)]; - [newAddress setObject:(identifier != nil) ? identifier:[NSNull null] forKey:kW3ContactFieldId]; - // set the type label - NSString* label = (__bridge_transfer NSString*)ABMultiValueCopyLabelAtIndex(multi, i); - - [newAddress setObject:(label != nil) ? (NSObject*)[[CDVContact class] convertPropertyLabelToContactType:label]:[NSNull null] forKey:kW3ContactFieldType]; - // set the pref - iOS doesn't support so set to default of false - [newAddress setObject:@"false" forKey:kW3ContactFieldPrimary]; - // get dictionary of values for this address - CFDictionaryRef dict = (CFDictionaryRef)ABMultiValueCopyValueAtIndex(multi, i); - - for (id k in fields) { - bool bFound; - id key = [[CDVContact defaultW3CtoAB] valueForKey:k]; - if (key && ![k isKindOfClass:[NSNull class]]) { - bFound = CFDictionaryGetValueIfPresent(dict, (__bridge const void*)key, (void*)&value); - if (bFound && (value != NULL)) { - CFRetain(value); - [newAddress setObject:(__bridge id)value forKey:k]; - CFRelease(value); - } else { - [newAddress setObject:[NSNull null] forKey:k]; - } - } else { - // was a property that iPhone doesn't support - [newAddress setObject:[NSNull null] forKey:k]; - } - } - - if ([newAddress count] > 0) { // ?? this will always be true since we set id,label,primary field?? - [(NSMutableArray*)addresses addObject : newAddress]; - } - CFRelease(dict); - } // end of loop through addresses - } else { - addresses = [NSNull null]; - } - if (multi) { - CFRelease(multi); - } - - return addresses; -} - -/* Create array of Dictionaries to match JavaScript ContactField object for ims - * type one of [aim, gtalk, icq, xmpp, msn, skype, qq, yahoo] needs other as well - * value - * (bool) primary - * id - * - * iOS IMs are a MultiValue Properties with label, value=dictionary of IM details (service, username), and id - */ -- (NSObject*)extractIms -{ - NSArray* fields = [self.returnFields objectForKey:kW3ContactIms]; - - if (fields == nil) { // no name fields requested - return nil; - } - NSObject* imArray; - ABMultiValueRef multi = ABRecordCopyValue(self.record, kABPersonInstantMessageProperty); - CFIndex count = multi ? ABMultiValueGetCount(multi) : 0; - if (count) { - imArray = [NSMutableArray arrayWithCapacity:count]; - - for (CFIndex i = 0; i < ABMultiValueGetCount(multi); i++) { - NSMutableDictionary* newDict = [NSMutableDictionary dictionaryWithCapacity:3]; - // iOS has label property (work, home, other) for each IM but W3C contact API doesn't use - CFDictionaryRef dict = (CFDictionaryRef)ABMultiValueCopyValueAtIndex(multi, i); - CFStringRef value; // all values should be CFStringRefs / NSString* - bool bFound; - if ([fields containsObject:kW3ContactFieldValue]) { - // value = user name - bFound = CFDictionaryGetValueIfPresent(dict, kABPersonInstantMessageUsernameKey, (void*)&value); - if (bFound && (value != NULL)) { - CFRetain(value); - [newDict setObject:(__bridge id)value forKey:kW3ContactFieldValue]; - CFRelease(value); - } else { - [newDict setObject:[NSNull null] forKey:kW3ContactFieldValue]; - } - } - if ([fields containsObject:kW3ContactFieldType]) { - bFound = CFDictionaryGetValueIfPresent(dict, kABPersonInstantMessageServiceKey, (void*)&value); - if (bFound && (value != NULL)) { - CFRetain(value); - [newDict setObject:(id)[[CDVContact class] convertPropertyLabelToContactType : (__bridge NSString*)value] forKey:kW3ContactFieldType]; - CFRelease(value); - } else { - [newDict setObject:[NSNull null] forKey:kW3ContactFieldType]; - } - } - // always set ID - id identifier = [NSNumber numberWithUnsignedInt:ABMultiValueGetIdentifierAtIndex(multi, i)]; - [newDict setObject:(identifier != nil) ? identifier:[NSNull null] forKey:kW3ContactFieldId]; - - [(NSMutableArray*)imArray addObject : newDict]; - CFRelease(dict); - } - } else { - imArray = [NSNull null]; - } - - if (multi) { - CFRelease(multi); - } - return imArray; -} - -/* Create array of Dictionaries to match JavaScript ContactOrganization object - * pref - not supported in iOS - * type - not supported in iOS - * name - * department - * title - */ - -- (NSObject*)extractOrganizations -{ - NSArray* fields = [self.returnFields objectForKey:kW3ContactOrganizations]; - - if (fields == nil) { // no name fields requested - return nil; - } - NSObject* array = nil; - NSMutableDictionary* newDict = [NSMutableDictionary dictionaryWithCapacity:5]; - id value; - int validValueCount = 0; - - for (id i in fields) { - id key = [[CDVContact defaultW3CtoAB] valueForKey:i]; - if (key && [key isKindOfClass:[NSNumber class]]) { - value = (__bridge_transfer NSString*)ABRecordCopyValue(self.record, (ABPropertyID)[[[CDVContact defaultW3CtoAB] valueForKey:i] intValue]); - if (value != nil) { - // if there are no organization values we should return null for organization - // this counter keeps indicates if any organization values have been set - validValueCount++; - } - [newDict setObject:(value != nil) ? value:[NSNull null] forKey:i]; - } else { // not a key iOS supports, set to null - [newDict setObject:[NSNull null] forKey:i]; - } - } - - if (([newDict count] > 0) && (validValueCount > 0)) { - // add pref and type - // they are not supported by iOS and thus these values never change - [newDict setObject:@"false" forKey:kW3ContactFieldPrimary]; - [newDict setObject:[NSNull null] forKey:kW3ContactFieldType]; - array = [NSMutableArray arrayWithCapacity:1]; - [(NSMutableArray*)array addObject : newDict]; - } else { - array = [NSNull null]; - } - return array; -} - -// W3C Contacts expects an array of photos. Can return photos in more than one format, currently -// just returning the default format -// Save the photo data into tmp directory and return FileURI - temp directory is deleted upon application exit -- (NSObject*)extractPhotos -{ - NSMutableArray* photos = nil; - - if (ABPersonHasImageData(self.record)) { - CFDataRef photoData = ABPersonCopyImageData(self.record); - NSData* data = (__bridge NSData*)photoData; - // write to temp directory and store URI in photos array - // get the temp directory path - NSString* docsPath = [NSTemporaryDirectory()stringByStandardizingPath]; - NSError* err = nil; - NSString* filePath = [NSString stringWithFormat:@"%@/photo_XXXXX", docsPath]; - char template[filePath.length + 1]; - strcpy(template, [filePath cStringUsingEncoding:NSASCIIStringEncoding]); - mkstemp(template); - filePath = [[NSFileManager defaultManager] - stringWithFileSystemRepresentation:template - length:strlen(template)]; - - // save file - if ([data writeToFile:filePath options:NSAtomicWrite error:&err]) { - photos = [NSMutableArray arrayWithCapacity:1]; - NSMutableDictionary* newDict = [NSMutableDictionary dictionaryWithCapacity:2]; - [newDict setObject:filePath forKey:kW3ContactFieldValue]; - [newDict setObject:@"url" forKey:kW3ContactFieldType]; - [newDict setObject:@"false" forKey:kW3ContactFieldPrimary]; - [photos addObject:newDict]; - } - - CFRelease(photoData); - } - return photos; -} - -/** - * given an array of W3C Contact field names, create a dictionary of field names to extract - * if field name represents an object, return all properties for that object: "name" - returns all properties in ContactName - * if field name is an explicit property, return only those properties: "name.givenName - returns a ContactName with only ContactName.givenName - * if field contains ONLY ["*"] return all fields - * dictionary format: - * key is W3Contact #define - * value is NSMutableArray* for complex keys: name,addresses,organizations, phone, emails, ims - * value is [NSNull null] for simple keys -*/ -+ (NSDictionary*)calcReturnFields:(NSArray*)fieldsArray // NSLog(@"getting self.returnFields"); -{ - NSMutableDictionary* d = [NSMutableDictionary dictionaryWithCapacity:1]; - - if ((fieldsArray != nil) && [fieldsArray isKindOfClass:[NSArray class]]) { - if (([fieldsArray count] == 1) && [[fieldsArray objectAtIndex:0] isEqualToString:@"*"]) { - return [CDVContact defaultFields]; // return all fields - } - - for (id i in fieldsArray) { - NSMutableArray* keys = nil; - NSString* fieldStr = nil; - if ([i isKindOfClass:[NSNumber class]]) { - fieldStr = [i stringValue]; - } else { - fieldStr = i; - } - - // see if this is specific property request in object - object.property - NSArray* parts = [fieldStr componentsSeparatedByString:@"."]; // returns original string if no separator found - NSString* name = [parts objectAtIndex:0]; - NSString* property = nil; - if ([parts count] > 1) { - property = [parts objectAtIndex:1]; - } - // see if this is a complex field by looking for its array of properties in objectAndProperties dictionary - id fields = [[CDVContact defaultObjectAndProperties] objectForKey:name]; - - // if find complex name (name,addresses,organizations, phone, emails, ims) in fields, add name as key - // with array of associated properties as the value - if ((fields != nil) && (property == nil)) { // request was for full object - keys = [NSMutableArray arrayWithArray:fields]; - if (keys != nil) { - [d setObject:keys forKey:name]; // will replace if prop array already exists - } - } else if ((fields != nil) && (property != nil)) { - // found an individual property request in form of name.property - // verify is real property name by using it as key in W3CtoAB - id abEquiv = [[CDVContact defaultW3CtoAB] objectForKey:property]; - if (abEquiv || [[CDVContact defaultW3CtoNull] containsObject:property]) { - // if existing array add to it - if ((keys = [d objectForKey:name]) != nil) { - [keys addObject:property]; - } else { - keys = [NSMutableArray arrayWithObject:property]; - [d setObject:keys forKey:name]; - } - } else { - NSLog(@"Contacts.find -- request for invalid property ignored: %@.%@", name, property); - } - } else { // is an individual property, verify is real property name by using it as key in W3CtoAB - id valid = [[CDVContact defaultW3CtoAB] objectForKey:name]; - if (valid || [[CDVContact defaultW3CtoNull] containsObject:name]) { - [d setObject:[NSNull null] forKey:name]; - } - } - } - } - if ([d count] == 0) { - // no array or nothing in the array. W3C spec says to return nothing - return nil; // [Contact defaultFields]; - } - return d; -} - -/* - * Search for the specified value in each of the fields specified in the searchFields dictionary. - * NSString* value - the string value to search for (need clarification from W3C on how to search for dates) - * NSDictionary* searchFields - a dictionary created via calcReturnFields where the key is the top level W3C - * object and the object is the array of specific fields within that object or null if it is a single property - * RETURNS - * YES as soon as a match is found in any of the fields - * NO - the specified value does not exist in any of the fields in this contact - * - * Note: I'm not a fan of returning in the middle of methods but have done it some in this method in order to - * keep the code simpler. bgibson - */ -- (BOOL)foundValue:(NSString*)testValue inFields:(NSDictionary*)searchFields -{ - BOOL bFound = NO; - - if ((testValue == nil) || ![testValue isKindOfClass:[NSString class]] || ([testValue length] == 0)) { - // nothing to find so return NO - return NO; - } - NSInteger valueAsInt = [testValue integerValue]; - - // per W3C spec, always include id in search - int recordId = ABRecordGetRecordID(self.record); - if (valueAsInt && (recordId == valueAsInt)) { - return YES; - } - - if (searchFields == nil) { - // no fields to search - return NO; - } - - if ([searchFields valueForKey:kW3ContactNickname]) { - bFound = [self testStringValue:testValue forW3CProperty:kW3ContactNickname]; - if (bFound == YES) { - return bFound; - } - } - - if ([searchFields valueForKeyIsArray:kW3ContactName]) { - // test name fields. All are string properties obtained via ABRecordCopyValue except kW3ContactFormattedName - NSArray* fields = [searchFields valueForKey:kW3ContactName]; - - for (NSString* testItem in fields) { - if ([testItem isEqualToString:kW3ContactFormattedName]) { - NSString* propValue = (__bridge_transfer NSString*)ABRecordCopyCompositeName(self.record); - if ((propValue != nil) && ([propValue length] > 0)) { - NSRange range = [propValue rangeOfString:testValue options:NSCaseInsensitiveSearch]; - bFound = (range.location != NSNotFound); - propValue = nil; - } - } else { - bFound = [self testStringValue:testValue forW3CProperty:testItem]; - } - - if (bFound) { - break; - } - } - } - if (!bFound && [searchFields valueForKeyIsArray:kW3ContactPhoneNumbers]) { - bFound = [self searchContactFields:(NSArray*)[searchFields valueForKey:kW3ContactPhoneNumbers] - forMVStringProperty:kABPersonPhoneProperty withValue:testValue]; - } - if (!bFound && [searchFields valueForKeyIsArray:kW3ContactEmails]) { - bFound = [self searchContactFields:(NSArray*)[searchFields valueForKey:kW3ContactEmails] - forMVStringProperty:kABPersonEmailProperty withValue:testValue]; - } - - if (!bFound && [searchFields valueForKeyIsArray:kW3ContactAddresses]) { - bFound = [self searchContactFields:[searchFields valueForKey:kW3ContactAddresses] - forMVDictionaryProperty:kABPersonAddressProperty withValue:testValue]; - } - - if (!bFound && [searchFields valueForKeyIsArray:kW3ContactIms]) { - bFound = [self searchContactFields:[searchFields valueForKey:kW3ContactIms] - forMVDictionaryProperty:kABPersonInstantMessageProperty withValue:testValue]; - } - - if (!bFound && [searchFields valueForKeyIsArray:kW3ContactOrganizations]) { - NSArray* fields = [searchFields valueForKey:kW3ContactOrganizations]; - - for (NSString* testItem in fields) { - bFound = [self testStringValue:testValue forW3CProperty:testItem]; - if (bFound == YES) { - break; - } - } - } - if (!bFound && [searchFields valueForKey:kW3ContactNote]) { - bFound = [self testStringValue:testValue forW3CProperty:kW3ContactNote]; - } - - // if searching for a date field is requested, get the date field as a localized string then look for match against testValue in date string - // searching for photos is not supported - if (!bFound && [searchFields valueForKey:kW3ContactBirthday]) { - bFound = [self testDateValue:testValue forW3CProperty:kW3ContactBirthday]; - } - if (!bFound && [searchFields valueForKeyIsArray:kW3ContactUrls]) { - bFound = [self searchContactFields:(NSArray*)[searchFields valueForKey:kW3ContactUrls] - forMVStringProperty:kABPersonURLProperty withValue:testValue]; - } - - return bFound; -} - -/* - * Test for the existence of a given string within the value of a ABPersonRecord string property based on the W3c property name. - * - * IN: - * NSString* testValue - the value to find - search is case insensitive - * NSString* property - the W3c property string - * OUT: - * BOOL YES if the given string was found within the property value - * NO if the testValue was not found, W3C property string was invalid or the AddressBook property was not a string - */ -- (BOOL)testStringValue:(NSString*)testValue forW3CProperty:(NSString*)property -{ - BOOL bFound = NO; - - if ([[CDVContact defaultW3CtoAB] valueForKeyIsNumber:property]) { - ABPropertyID propId = [[[CDVContact defaultW3CtoAB] objectForKey:property] intValue]; - if (ABPersonGetTypeOfProperty(propId) == kABStringPropertyType) { - NSString* propValue = (__bridge_transfer NSString*)ABRecordCopyValue(self.record, propId); - if ((propValue != nil) && ([propValue length] > 0)) { - NSPredicate* containPred = [NSPredicate predicateWithFormat:@"SELF contains[cd] %@", testValue]; - bFound = [containPred evaluateWithObject:propValue]; - // NSRange range = [propValue rangeOfString:testValue options: NSCaseInsensitiveSearch]; - // bFound = (range.location != NSNotFound); - } - } - } - return bFound; -} - -/* - * Test for the existence of a given Date string within the value of a ABPersonRecord datetime property based on the W3c property name. - * - * IN: - * NSString* testValue - the value to find - search is case insensitive - * NSString* property - the W3c property string - * OUT: - * BOOL YES if the given string was found within the localized date string value - * NO if the testValue was not found, W3C property string was invalid or the AddressBook property was not a DateTime - */ -- (BOOL)testDateValue:(NSString*)testValue forW3CProperty:(NSString*)property -{ - BOOL bFound = NO; - - if ([[CDVContact defaultW3CtoAB] valueForKeyIsNumber:property]) { - ABPropertyID propId = [[[CDVContact defaultW3CtoAB] objectForKey:property] intValue]; - if (ABPersonGetTypeOfProperty(propId) == kABDateTimePropertyType) { - NSDate* date = (__bridge_transfer NSDate*)ABRecordCopyValue(self.record, propId); - if (date != nil) { - NSString* dateString = [date descriptionWithLocale:[NSLocale currentLocale]]; - NSPredicate* containPred = [NSPredicate predicateWithFormat:@"SELF contains[cd] %@", testValue]; - bFound = [containPred evaluateWithObject:dateString]; - } - } - } - return bFound; -} - -/* - * Search the specified fields within an AddressBook multivalue string property for the specified test value. - * Used for phoneNumbers, emails and urls. - * IN: - * NSArray* fields - the fields to search for within the multistring property (value and/or type) - * ABPropertyID - the property to search - * NSString* testValue - the value to search for. Will convert between W3C types and AB types. Will only - * search for types if the testValue is a valid ContactField type. - * OUT: - * YES if the test value was found in one of the specified fields - * NO if the test value was not found - */ -- (BOOL)searchContactFields:(NSArray*)fields forMVStringProperty:(ABPropertyID)propId withValue:testValue -{ - BOOL bFound = NO; - - for (NSString* type in fields) { - NSString* testString = nil; - if ([type isEqualToString:kW3ContactFieldType]) { - if ([CDVContact isValidW3ContactType:testValue]) { - // only search types if the filter string is a valid ContactField.type - testString = (NSString*)[CDVContact convertContactTypeToPropertyLabel:testValue]; - } - } else { - testString = testValue; - } - - if (testString != nil) { - bFound = [self testMultiValueStrings:testString forProperty:propId ofType:type]; - } - if (bFound == YES) { - break; - } - } - - return bFound; -} - -/* - * Searches a multiString value of the specified type for the specified test value. - * - * IN: - * NSString* testValue - the value to test for - * ABPropertyID propId - the property id of the multivalue property to search - * NSString* type - the W3C contact type to search for (value or type) - * OUT: - * YES is the test value was found - * NO if the test value was not found - */ -- (BOOL)testMultiValueStrings:(NSString*)testValue forProperty:(ABPropertyID)propId ofType:(NSString*)type -{ - BOOL bFound = NO; - - if (ABPersonGetTypeOfProperty(propId) == kABMultiStringPropertyType) { - NSArray* valueArray = nil; - if ([type isEqualToString:kW3ContactFieldType]) { - valueArray = [self labelsForProperty:propId inRecord:self.record]; - } else if ([type isEqualToString:kW3ContactFieldValue]) { - valueArray = [self valuesForProperty:propId inRecord:self.record]; - } - if (valueArray) { - NSString* valuesAsString = [valueArray componentsJoinedByString:@" "]; - NSPredicate* containPred = [NSPredicate predicateWithFormat:@"SELF contains[cd] %@", testValue]; - bFound = [containPred evaluateWithObject:valuesAsString]; - } - } - return bFound; -} - -/* - * Returns the array of values for a multivalue string property of the specified property id - */ -- (__autoreleasing NSArray*)valuesForProperty:(ABPropertyID)propId inRecord:(ABRecordRef)aRecord -{ - ABMultiValueRef multi = ABRecordCopyValue(aRecord, propId); - NSArray* values = (__bridge_transfer NSArray*)ABMultiValueCopyArrayOfAllValues(multi); - - CFRelease(multi); - return values; -} - -/* - * Returns the array of labels for a multivalue string property of the specified property id - */ -- (NSArray*)labelsForProperty:(ABPropertyID)propId inRecord:(ABRecordRef)aRecord -{ - ABMultiValueRef multi = ABRecordCopyValue(aRecord, propId); - CFIndex count = ABMultiValueGetCount(multi); - NSMutableArray* labels = [NSMutableArray arrayWithCapacity:count]; - - for (int i = 0; i < count; i++) { - NSString* label = (__bridge_transfer NSString*)ABMultiValueCopyLabelAtIndex(multi, i); - if (label) { - [labels addObject:label]; - } - } - - CFRelease(multi); - return labels; -} - -/* search for values within MultiValue Dictionary properties Address or IM property - * IN: - * (NSArray*) fields - the array of W3C field names to search within - * (ABPropertyID) propId - the AddressBook property that returns a multivalue dictionary - * (NSString*) testValue - the string to search for within the specified fields - * - */ -- (BOOL)searchContactFields:(NSArray*)fields forMVDictionaryProperty:(ABPropertyID)propId withValue:(NSString*)testValue -{ - BOOL bFound = NO; - - NSArray* values = [self valuesForProperty:propId inRecord:self.record]; // array of dictionaries (as CFDictionaryRef) - NSUInteger dictCount = [values count]; - - // for ims dictionary contains with service (w3C type) and username (W3c value) - // for addresses dictionary contains street, city, state, zip, country - for (int i = 0; i < dictCount; i++) { - CFDictionaryRef dict = (__bridge CFDictionaryRef)[values objectAtIndex:i]; - - for (NSString* member in fields) { - NSString* abKey = [[CDVContact defaultW3CtoAB] valueForKey:member]; // im and address fields are all strings - CFStringRef abValue = nil; - if (abKey) { - NSString* testString = nil; - if ([member isEqualToString:kW3ContactImType]) { - if ([CDVContact isValidW3ContactType:testValue]) { - // only search service/types if the filter string is a valid ContactField.type - testString = (NSString*)[CDVContact convertContactTypeToPropertyLabel:testValue]; - } - } else { - testString = testValue; - } - if (testString != nil) { - BOOL bExists = CFDictionaryGetValueIfPresent(dict, (__bridge const void*)abKey, (void*)&abValue); - if (bExists) { - CFRetain(abValue); - NSPredicate* containPred = [NSPredicate predicateWithFormat:@"SELF contains[cd] %@", testString]; - bFound = [containPred evaluateWithObject:(__bridge id)abValue]; - CFRelease(abValue); - } - } - } - if (bFound == YES) { - break; - } - } // end of for each member in fields - - if (bFound == YES) { - break; - } - } // end of for each dictionary - - return bFound; -} - -@end
diff --git a/src/ios/CDVContacts.h b/src/ios/CDVContacts.h deleted file mode 100644 index e3deb21..0000000 --- a/src/ios/CDVContacts.h +++ /dev/null
@@ -1,151 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import <Foundation/Foundation.h> -#import <AddressBook/ABAddressBook.h> -#import <AddressBookUI/AddressBookUI.h> -#import <Cordova/CDVPlugin.h> -#import "CDVContact.h" - -@interface CDVContacts : CDVPlugin <ABNewPersonViewControllerDelegate, - ABPersonViewControllerDelegate, - ABPeoplePickerNavigationControllerDelegate - > -{ - ABAddressBookRef addressBook; -} - -/* - * newContact - create a new contact via the GUI - * - * arguments: - * 1: successCallback: this is the javascript function that will be called with the newly created contactId - */ -- (void)newContact:(CDVInvokedUrlCommand*)command; - -/* - * displayContact - IN PROGRESS - * - * arguments: - * 1: recordID of the contact to display in the iPhone contact display - * 2: successCallback - currently not used - * 3: error callback - * options: - * allowsEditing: set to true to allow the user to edit the contact - currently not supported - */ -- (void)displayContact:(CDVInvokedUrlCommand*)command; - -/* - * chooseContact - * - * arguments: - * 1: this is the javascript function that will be called with the contact data as a JSON object (as the first param) - * options: - * allowsEditing: set to true to not choose the contact, but to edit it in the iPhone contact editor - */ -- (void)chooseContact:(CDVInvokedUrlCommand*)command; - -- (void)newPersonViewController:(ABNewPersonViewController*)newPersonViewController didCompleteWithNewPerson:(ABRecordRef)person; -- (BOOL)personViewController:(ABPersonViewController*)personViewController shouldPerformDefaultActionForPerson:(ABRecordRef)person - property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifierForValue; - -/* - * search - searches for contacts. Only person records are currently supported. - * - * arguments: - * 1: successcallback - this is the javascript function that will be called with the array of found contacts - * 2: errorCallback - optional javascript function to be called in the event of an error with an error code. - * options: dictionary containing ContactFields and ContactFindOptions - * fields - ContactFields array - * findOptions - ContactFindOptions object as dictionary - * - */ -- (void)search:(CDVInvokedUrlCommand*)command; - -/* - * save - saves a new contact or updates and existing contact - * - * arguments: - * 1: success callback - this is the javascript function that will be called with the JSON representation of the saved contact - * search calls a fixed navigator.service.contacts._findCallback which then calls the success callback stored before making the call into obj-c - */ -- (void)save:(CDVInvokedUrlCommand*)command; - -/* - * remove - removes a contact from the address book - * - * arguments: - * 1: 1: successcallback - this is the javascript function that will be called with a (now) empty contact object - * - * options: dictionary containing Contact object to remove - * contact - Contact object as dictionary - */ -- (void)remove:(CDVInvokedUrlCommand*)command; - -// - (void) dealloc; - -@end - -@interface CDVContactsPicker : ABPeoplePickerNavigationController -{ - BOOL allowsEditing; - NSString* callbackId; - NSDictionary* options; - NSDictionary* pickedContactDictionary; -} - -@property BOOL allowsEditing; -@property (copy) NSString* callbackId; -@property (nonatomic, strong) NSDictionary* options; -@property (nonatomic, strong) NSDictionary* pickedContactDictionary; - -@end - -@interface CDVNewContactsController : ABNewPersonViewController -{ - NSString* callbackId; -} -@property (copy) NSString* callbackId; -@end - -/* ABPersonViewController does not have any UI to dismiss. Adding navigationItems to it does not work properly, the navigationItems are lost when the app goes into the background. - The solution was to create an empty NavController in front of the ABPersonViewController. This - causes the ABPersonViewController to have a back button. By subclassing the ABPersonViewController, - we can override viewWillDisappear and take down the entire NavigationController at that time. - */ -@interface CDVDisplayContactViewController : ABPersonViewController -{} -@property (nonatomic, strong) CDVPlugin* contactsPlugin; - -@end -@interface CDVAddressBookAccessError : NSObject -{} -@property (assign) CDVContactError errorCode; -- (CDVAddressBookAccessError*)initWithCode:(CDVContactError)code; -@end - -typedef void (^ CDVAddressBookWorkerBlock)( - ABAddressBookRef addressBook, - CDVAddressBookAccessError* error - ); -@interface CDVAddressBookHelper : NSObject -{} - -- (void)createAddressBook:(CDVAddressBookWorkerBlock)workerBlock; -@end
diff --git a/src/ios/CDVContacts.m b/src/ios/CDVContacts.m deleted file mode 100644 index 56ca2ab..0000000 --- a/src/ios/CDVContacts.m +++ /dev/null
@@ -1,604 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import "CDVContacts.h" -#import <UIKit/UIKit.h> -#import <Cordova/NSArray+Comparisons.h> -#import <Cordova/NSDictionary+Extensions.h> -//#import "CDVNotification.h" - -@implementation CDVContactsPicker - -@synthesize allowsEditing; -@synthesize callbackId; -@synthesize options; -@synthesize pickedContactDictionary; - -@end -@implementation CDVNewContactsController - -@synthesize callbackId; - -@end - -@implementation CDVContacts - -// no longer used since code gets AddressBook for each operation. -// If address book changes during save or remove operation, may get error but not much we can do about it -// If address book changes during UI creation, display or edit, we don't control any saves so no need for callback - -/*void addressBookChanged(ABAddressBookRef addressBook, CFDictionaryRef info, void* context) -{ - // note that this function is only called when another AddressBook instance modifies - // the address book, not the current one. For example, through an OTA MobileMe sync - Contacts* contacts = (Contacts*)context; - [contacts addressBookDirty]; - }*/ - -- (CDVPlugin*)initWithWebView:(UIWebView*)theWebView -{ - self = (CDVContacts*)[super initWithWebView:(UIWebView*)theWebView]; - - /*if (self) { - addressBook = ABAddressBookCreate(); - ABAddressBookRegisterExternalChangeCallback(addressBook, addressBookChanged, self); - }*/ - - return self; -} - -// overridden to clean up Contact statics -- (void)onAppTerminate -{ - // NSLog(@"Contacts::onAppTerminate"); -} - -// iPhone only method to create a new contact through the GUI -- (void)newContact:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - - CDVAddressBookHelper* abHelper = [[CDVAddressBookHelper alloc] init]; - CDVContacts* __weak weakSelf = self; // play it safe to avoid retain cycles - - [abHelper createAddressBook: ^(ABAddressBookRef addrBook, CDVAddressBookAccessError* errCode) { - if (addrBook == NULL) { - // permission was denied or other error just return (no error callback) - return; - } - CDVNewContactsController* npController = [[CDVNewContactsController alloc] init]; - npController.addressBook = addrBook; // a CF retaining assign - CFRelease(addrBook); - - npController.newPersonViewDelegate = self; - npController.callbackId = callbackId; - - UINavigationController* navController = [[UINavigationController alloc] initWithRootViewController:npController]; - - SEL selector = NSSelectorFromString(@"presentViewController:animated:completion:"); - if ([weakSelf.viewController respondsToSelector:selector]) { - [weakSelf.viewController presentViewController:navController animated:YES completion:nil]; - } else { - // deprecated as of iOS >= 6.0 - [weakSelf.viewController presentModalViewController:navController animated:YES]; - } - }]; -} - -- (void)newPersonViewController:(ABNewPersonViewController*)newPersonViewController didCompleteWithNewPerson:(ABRecordRef)person -{ - ABRecordID recordId = kABRecordInvalidID; - CDVNewContactsController* newCP = (CDVNewContactsController*)newPersonViewController; - NSString* callbackId = newCP.callbackId; - - if (person != NULL) { - // return the contact id - recordId = ABRecordGetRecordID(person); - } - - if ([newPersonViewController respondsToSelector:@selector(presentingViewController)]) { - [[newPersonViewController presentingViewController] dismissViewControllerAnimated:YES completion:nil]; - } else { - [[newPersonViewController parentViewController] dismissModalViewControllerAnimated:YES]; - } - - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:recordId]; - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; -} - -- (void)displayContact:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - ABRecordID recordID = [[command.arguments objectAtIndex:0] intValue]; - NSDictionary* options = [command.arguments objectAtIndex:1 withDefault:[NSNull null]]; - bool bEdit = [options isKindOfClass:[NSNull class]] ? false : [options existsValue:@"true" forKey:@"allowsEditing"]; - - CDVAddressBookHelper* abHelper = [[CDVAddressBookHelper alloc] init]; - CDVContacts* __weak weakSelf = self; // play it safe to avoid retain cycles - - [abHelper createAddressBook: ^(ABAddressBookRef addrBook, CDVAddressBookAccessError* errCode) { - if (addrBook == NULL) { - // permission was denied or other error - return error - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageToErrorObject:errCode ? (int)errCode.errorCode:UNKNOWN_ERROR]; - [weakSelf.commandDelegate sendPluginResult:result callbackId:callbackId]; - return; - } - ABRecordRef rec = ABAddressBookGetPersonWithRecordID(addrBook, recordID); - - if (rec) { - CDVDisplayContactViewController* personController = [[CDVDisplayContactViewController alloc] init]; - personController.displayedPerson = rec; - personController.personViewDelegate = self; - personController.allowsEditing = NO; - - // create this so DisplayContactViewController will have a "back" button. - UIViewController* parentController = [[UIViewController alloc] init]; - UINavigationController* navController = [[UINavigationController alloc] initWithRootViewController:parentController]; - - [navController pushViewController:personController animated:YES]; - - SEL selector = NSSelectorFromString(@"presentViewController:animated:completion:"); - if ([self.viewController respondsToSelector:selector]) { - [self.viewController presentViewController:navController animated:YES completion:nil]; - } else { - // deprecated as of iOS >= 6.0 - [self.viewController presentModalViewController:navController animated:YES]; - } - - if (bEdit) { - // create the editing controller and push it onto the stack - ABPersonViewController* editPersonController = [[ABPersonViewController alloc] init]; - editPersonController.displayedPerson = rec; - editPersonController.personViewDelegate = self; - editPersonController.allowsEditing = YES; - [navController pushViewController:editPersonController animated:YES]; - } - } else { - // no record, return error - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:UNKNOWN_ERROR]; - [weakSelf.commandDelegate sendPluginResult:result callbackId:callbackId]; - } - CFRelease(addrBook); - }]; -} - -- (BOOL)personViewController:(ABPersonViewController*)personViewController shouldPerformDefaultActionForPerson:(ABRecordRef)person - property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifierForValue -{ - return YES; -} - -- (void)chooseContact:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - NSDictionary* options = [command.arguments objectAtIndex:0 withDefault:[NSNull null]]; - - CDVContactsPicker* pickerController = [[CDVContactsPicker alloc] init]; - - pickerController.peoplePickerDelegate = self; - pickerController.callbackId = callbackId; - pickerController.options = options; - pickerController.pickedContactDictionary = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:kABRecordInvalidID], kW3ContactId, nil]; - id allowsEditingValue = [options valueForKey:@"allowsEditing"]; - BOOL allowsEditing = NO; - if ([allowsEditingValue isKindOfClass:[NSNumber class]]) { - allowsEditing = [(NSNumber*)allowsEditingValue boolValue]; - } - pickerController.allowsEditing = allowsEditing; - - SEL selector = NSSelectorFromString(@"presentViewController:animated:completion:"); - if ([self.viewController respondsToSelector:selector]) { - [self.viewController presentViewController:pickerController animated:YES completion:nil]; - } else { - // deprecated as of iOS >= 6.0 - [self.viewController presentModalViewController:pickerController animated:YES]; - } -} - -- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController*)peoplePicker - shouldContinueAfterSelectingPerson:(ABRecordRef)person -{ - CDVContactsPicker* picker = (CDVContactsPicker*)peoplePicker; - NSNumber* pickedId = [NSNumber numberWithInt:ABRecordGetRecordID(person)]; - - if (picker.allowsEditing) { - ABPersonViewController* personController = [[ABPersonViewController alloc] init]; - personController.displayedPerson = person; - personController.personViewDelegate = self; - personController.allowsEditing = picker.allowsEditing; - // store id so can get info in peoplePickerNavigationControllerDidCancel - picker.pickedContactDictionary = [NSDictionary dictionaryWithObjectsAndKeys:pickedId, kW3ContactId, nil]; - - [peoplePicker pushViewController:personController animated:YES]; - } else { - // Retrieve and return pickedContact information - CDVContact* pickedContact = [[CDVContact alloc] initFromABRecord:(ABRecordRef)person]; - NSArray* fields = [picker.options objectForKey:@"fields"]; - NSDictionary* returnFields = [[CDVContact class] calcReturnFields:fields]; - picker.pickedContactDictionary = [pickedContact toDictionary:returnFields]; - - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:picker.pickedContactDictionary]; - [self.commandDelegate sendPluginResult:result callbackId:picker.callbackId]; - - if ([picker respondsToSelector:@selector(presentingViewController)]) { - [[picker presentingViewController] dismissViewControllerAnimated:YES completion:nil]; - } else { - [[picker parentViewController] dismissModalViewControllerAnimated:YES]; - } - } - return NO; -} - -- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController*)peoplePicker - shouldContinueAfterSelectingPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier -{ - return YES; -} - -- (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController*)peoplePicker -{ - // return contactId or invalid if none picked - CDVContactsPicker* picker = (CDVContactsPicker*)peoplePicker; - - if (picker.allowsEditing) { - // get the info after possible edit - // if we got this far, user has already approved/ disapproved addressBook access - ABAddressBookRef addrBook = nil; -#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 60000 - if (&ABAddressBookCreateWithOptions != NULL) { - addrBook = ABAddressBookCreateWithOptions(NULL, NULL); - } else -#endif - { - // iOS 4 & 5 - addrBook = ABAddressBookCreate(); - } - ABRecordRef person = ABAddressBookGetPersonWithRecordID(addrBook, (int)[[picker.pickedContactDictionary objectForKey:kW3ContactId] integerValue]); - if (person) { - CDVContact* pickedContact = [[CDVContact alloc] initFromABRecord:(ABRecordRef)person]; - NSArray* fields = [picker.options objectForKey:@"fields"]; - NSDictionary* returnFields = [[CDVContact class] calcReturnFields:fields]; - picker.pickedContactDictionary = [pickedContact toDictionary:returnFields]; - } - CFRelease(addrBook); - } - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:picker.pickedContactDictionary]; - [self.commandDelegate sendPluginResult:result callbackId:picker.callbackId]; - - if ([peoplePicker respondsToSelector:@selector(presentingViewController)]) { - [[peoplePicker presentingViewController] dismissViewControllerAnimated:YES completion:nil]; - } else { - [[peoplePicker parentViewController] dismissModalViewControllerAnimated:YES]; - } -} - -- (void)search:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - NSArray* fields = [command.arguments objectAtIndex:0]; - NSDictionary* findOptions = [command.arguments objectAtIndex:1 withDefault:[NSNull null]]; - - [self.commandDelegate runInBackground:^{ - // from Apple: Important You must ensure that an instance of ABAddressBookRef is used by only one thread. - // which is why address book is created within the dispatch queue. - // more details here: http: //blog.byadrian.net/2012/05/05/ios-addressbook-framework-and-gcd/ - CDVAddressBookHelper* abHelper = [[CDVAddressBookHelper alloc] init]; - CDVContacts* __weak weakSelf = self; // play it safe to avoid retain cycles - // it gets uglier, block within block..... - [abHelper createAddressBook: ^(ABAddressBookRef addrBook, CDVAddressBookAccessError* errCode) { - if (addrBook == NULL) { - // permission was denied or other error - return error - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageToErrorObject:errCode ? (int)errCode.errorCode:UNKNOWN_ERROR]; - [weakSelf.commandDelegate sendPluginResult:result callbackId:callbackId]; - return; - } - - NSArray* foundRecords = nil; - // get the findOptions values - BOOL multiple = NO; // default is false - NSString* filter = nil; - if (![findOptions isKindOfClass:[NSNull class]]) { - id value = nil; - filter = (NSString*)[findOptions objectForKey:@"filter"]; - value = [findOptions objectForKey:@"multiple"]; - if ([value isKindOfClass:[NSNumber class]]) { - // multiple is a boolean that will come through as an NSNumber - multiple = [(NSNumber*)value boolValue]; - // NSLog(@"multiple is: %d", multiple); - } - } - - NSDictionary* returnFields = [[CDVContact class] calcReturnFields:fields]; - - NSMutableArray* matches = nil; - if (!filter || [filter isEqualToString:@""]) { - // get all records - foundRecords = (__bridge_transfer NSArray*)ABAddressBookCopyArrayOfAllPeople(addrBook); - if (foundRecords && ([foundRecords count] > 0)) { - // create Contacts and put into matches array - // doesn't make sense to ask for all records when multiple == NO but better check - int xferCount = multiple == YES ? (int)[foundRecords count] : 1; - matches = [NSMutableArray arrayWithCapacity:xferCount]; - - for (int k = 0; k < xferCount; k++) { - CDVContact* xferContact = [[CDVContact alloc] initFromABRecord:(__bridge ABRecordRef)[foundRecords objectAtIndex:k]]; - [matches addObject:xferContact]; - xferContact = nil; - } - } - } else { - foundRecords = (__bridge_transfer NSArray*)ABAddressBookCopyArrayOfAllPeople(addrBook); - matches = [NSMutableArray arrayWithCapacity:1]; - BOOL bFound = NO; - int testCount = (int)[foundRecords count]; - - for (int j = 0; j < testCount; j++) { - CDVContact* testContact = [[CDVContact alloc] initFromABRecord:(__bridge ABRecordRef)[foundRecords objectAtIndex:j]]; - if (testContact) { - bFound = [testContact foundValue:filter inFields:returnFields]; - if (bFound) { - [matches addObject:testContact]; - } - testContact = nil; - } - } - } - NSMutableArray* returnContacts = [NSMutableArray arrayWithCapacity:1]; - - if ((matches != nil) && ([matches count] > 0)) { - // convert to JS Contacts format and return in callback - // - returnFields determines what properties to return - @autoreleasepool { - int count = multiple == YES ? (int)[matches count] : 1; - - for (int i = 0; i < count; i++) { - CDVContact* newContact = [matches objectAtIndex:i]; - NSDictionary* aContact = [newContact toDictionary:returnFields]; - [returnContacts addObject:aContact]; - } - } - } - // return found contacts (array is empty if no contacts found) - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:returnContacts]; - [weakSelf.commandDelegate sendPluginResult:result callbackId:callbackId]; - // NSLog(@"findCallback string: %@", jsString); - - if (addrBook) { - CFRelease(addrBook); - } - }]; - }]; // end of workQueue block - - return; -} - -- (void)save:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - NSDictionary* contactDict = [command.arguments objectAtIndex:0]; - - [self.commandDelegate runInBackground:^{ - CDVAddressBookHelper* abHelper = [[CDVAddressBookHelper alloc] init]; - CDVContacts* __weak weakSelf = self; // play it safe to avoid retain cycles - - [abHelper createAddressBook: ^(ABAddressBookRef addrBook, CDVAddressBookAccessError* errorCode) { - CDVPluginResult* result = nil; - if (addrBook == NULL) { - // permission was denied or other error - return error - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:errorCode ? (int)errorCode.errorCode:UNKNOWN_ERROR]; - [weakSelf.commandDelegate sendPluginResult:result callbackId:callbackId]; - return; - } - - bool bIsError = FALSE, bSuccess = FALSE; - BOOL bUpdate = NO; - CDVContactError errCode = UNKNOWN_ERROR; - CFErrorRef error; - NSNumber* cId = [contactDict valueForKey:kW3ContactId]; - CDVContact* aContact = nil; - ABRecordRef rec = nil; - if (cId && ![cId isKindOfClass:[NSNull class]]) { - rec = ABAddressBookGetPersonWithRecordID(addrBook, [cId intValue]); - if (rec) { - aContact = [[CDVContact alloc] initFromABRecord:rec]; - bUpdate = YES; - } - } - if (!aContact) { - aContact = [[CDVContact alloc] init]; - } - - bSuccess = [aContact setFromContactDict:contactDict asUpdate:bUpdate]; - if (bSuccess) { - if (!bUpdate) { - bSuccess = ABAddressBookAddRecord(addrBook, [aContact record], &error); - } - if (bSuccess) { - bSuccess = ABAddressBookSave(addrBook, &error); - } - if (!bSuccess) { // need to provide error codes - bIsError = TRUE; - errCode = IO_ERROR; - } else { - // give original dictionary back? If generate dictionary from saved contact, have no returnFields specified - // so would give back all fields (which W3C spec. indicates is not desired) - // for now (while testing) give back saved, full contact - NSDictionary* newContact = [aContact toDictionary:[CDVContact defaultFields]]; - // NSString* contactStr = [newContact JSONRepresentation]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:newContact]; - } - } else { - bIsError = TRUE; - errCode = IO_ERROR; - } - CFRelease(addrBook); - - if (bIsError) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:(int)errCode]; - } - - if (result) { - [weakSelf.commandDelegate sendPluginResult:result callbackId:callbackId]; - } - }]; - }]; // end of queue -} - -- (void)remove:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - NSNumber* cId = [command.arguments objectAtIndex:0]; - - CDVAddressBookHelper* abHelper = [[CDVAddressBookHelper alloc] init]; - CDVContacts* __weak weakSelf = self; // play it safe to avoid retain cycles - - [abHelper createAddressBook: ^(ABAddressBookRef addrBook, CDVAddressBookAccessError* errorCode) { - CDVPluginResult* result = nil; - if (addrBook == NULL) { - // permission was denied or other error - return error - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:errorCode ? (int)errorCode.errorCode:UNKNOWN_ERROR]; - [weakSelf.commandDelegate sendPluginResult:result callbackId:callbackId]; - return; - } - - bool bIsError = FALSE, bSuccess = FALSE; - CDVContactError errCode = UNKNOWN_ERROR; - CFErrorRef error; - ABRecordRef rec = nil; - if (cId && ![cId isKindOfClass:[NSNull class]] && ([cId intValue] != kABRecordInvalidID)) { - rec = ABAddressBookGetPersonWithRecordID(addrBook, [cId intValue]); - if (rec) { - bSuccess = ABAddressBookRemoveRecord(addrBook, rec, &error); - if (!bSuccess) { - bIsError = TRUE; - errCode = IO_ERROR; - } else { - bSuccess = ABAddressBookSave(addrBook, &error); - if (!bSuccess) { - bIsError = TRUE; - errCode = IO_ERROR; - } else { - // set id to null - // [contactDict setObject:[NSNull null] forKey:kW3ContactId]; - // result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary: contactDict]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; - // NSString* contactStr = [contactDict JSONRepresentation]; - } - } - } else { - // no record found return error - bIsError = TRUE; - errCode = UNKNOWN_ERROR; - } - } else { - // invalid contact id provided - bIsError = TRUE; - errCode = INVALID_ARGUMENT_ERROR; - } - - if (addrBook) { - CFRelease(addrBook); - } - if (bIsError) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:(int)errCode]; - } - if (result) { - [weakSelf.commandDelegate sendPluginResult:result callbackId:callbackId]; - } - }]; - return; -} - -@end - -/* ABPersonViewController does not have any UI to dismiss. Adding navigationItems to it does not work properly - * The navigationItems are lost when the app goes into the background. The solution was to create an empty - * NavController in front of the ABPersonViewController. This will cause the ABPersonViewController to have a back button. By subclassing the ABPersonViewController, we can override viewDidDisappear and take down the entire NavigationController. - */ -@implementation CDVDisplayContactViewController -@synthesize contactsPlugin; - -- (void)viewWillDisappear:(BOOL)animated -{ - [super viewWillDisappear:animated]; - - if ([self respondsToSelector:@selector(presentingViewController)]) { - [[self presentingViewController] dismissViewControllerAnimated:YES completion:nil]; - } else { - [[self parentViewController] dismissModalViewControllerAnimated:YES]; - } -} - -@end -@implementation CDVAddressBookAccessError - -@synthesize errorCode; - -- (CDVAddressBookAccessError*)initWithCode:(CDVContactError)code -{ - self = [super init]; - if (self) { - self.errorCode = code; - } - return self; -} - -@end - -@implementation CDVAddressBookHelper - -/** - * NOTE: workerBlock is responsible for releasing the addressBook that is passed to it - */ -- (void)createAddressBook:(CDVAddressBookWorkerBlock)workerBlock -{ - // TODO: this probably should be reworked - seems like the workerBlock can just create and release its own AddressBook, - // and also this important warning from (http://developer.apple.com/library/ios/#documentation/ContactData/Conceptual/AddressBookProgrammingGuideforiPhone/Chapters/BasicObjects.html): - // "Important: Instances of ABAddressBookRef cannot be used by multiple threads. Each thread must make its own instance." - ABAddressBookRef addressBook; - -#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 60000 - if (&ABAddressBookCreateWithOptions != NULL) { - CFErrorRef error = nil; - // CFIndex status = ABAddressBookGetAuthorizationStatus(); - addressBook = ABAddressBookCreateWithOptions(NULL, &error); - // NSLog(@"addressBook access: %lu", status); - ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) { - // callback can occur in background, address book must be accessed on thread it was created on - dispatch_sync(dispatch_get_main_queue(), ^{ - if (error) { - workerBlock(NULL, [[CDVAddressBookAccessError alloc] initWithCode:UNKNOWN_ERROR]); - } else if (!granted) { - workerBlock(NULL, [[CDVAddressBookAccessError alloc] initWithCode:PERMISSION_DENIED_ERROR]); - } else { - // access granted - workerBlock(addressBook, [[CDVAddressBookAccessError alloc] initWithCode:UNKNOWN_ERROR]); - } - }); - }); - } else -#endif - { - // iOS 4 or 5 no checks needed - addressBook = ABAddressBookCreate(); - workerBlock(addressBook, NULL); - } -} - -@end
diff --git a/src/ubuntu/contacts.cpp b/src/ubuntu/contacts.cpp deleted file mode 100644 index 373a276..0000000 --- a/src/ubuntu/contacts.cpp +++ /dev/null
@@ -1,576 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * -*/ - -#include "contacts.h" - -#if defined QTCONTACTS_USE_NAMESPACE -QTCONTACTS_USE_NAMESPACE -#endif - -Contacts::Contacts(Cordova *cordova): CPlugin(cordova) { - m_fieldNamePairs.clear(); - - m_fieldNamePairs["displayName"] = QContactDetail::TypeDisplayLabel; - m_fieldNamePairs["name"] = QContactDetail::TypeName; - m_fieldNamePairs["nickname"] = QContactDetail::TypeNickname; - m_fieldNamePairs["phoneNumbers"] = QContactDetail::TypePhoneNumber; - m_fieldNamePairs["emails"] = QContactDetail::TypeEmailAddress; - m_fieldNamePairs["addresses"] = QContactDetail::TypeAddress; - m_fieldNamePairs["ims"] = QContactDetail::TypeOnlineAccount; - m_fieldNamePairs["organizations"] = QContactDetail::TypeOrganization; - m_fieldNamePairs["birthday"] = QContactDetail::TypeBirthday; - m_fieldNamePairs["note"] = QContactDetail::TypeNote; - m_fieldNamePairs["photos"] = QContactDetail::TypeAvatar; - m_fieldNamePairs["urls"] = QContactDetail::TypeUrl; - - m_notSupportedFields.clear(); - m_notSupportedFields << "categories"; - m_manager.clear(); - m_manager = QSharedPointer<QContactManager>(new QContactManager()); -} - -void Contacts::save(int scId, int ecId, const QVariantMap ¶ms) { - QContact result; - QList<QContactDetail *> detailsToDelete; - - if (params.find("id") != params.end()) { - QString id = params.find("id")->toString(); - if (!id.isEmpty()) { - result = m_manager->contact(QContactId::fromString(id)); - result.clearDetails(); - } - } - - foreach (QString field, params.keys()) { - QContactDetail::DetailType qtDefinition = cordovaFieldNameToQtDefinition(field); - if (qtDefinition == QContactDetail::TypeUndefined) - continue; - - if (field == "nickname") { - QContactNickname *detail = new QContactNickname; - detail->setNickname(params[field].toString()); - detailsToDelete << detail; - result.saveDetail(detail); - } else if (field == "note") { - QContactNote *detail = new QContactNote; - detail->setNote(params[field].toString()); - detailsToDelete << detail; - result.saveDetail(detail); - } else if (field == "phoneNumbers") { - if (params[field].type() != QVariant::List) - continue; - QVariantList phonesList = params[field].toList(); - foreach (const QVariant &phoneDesc, phonesList) { - if (phoneDesc.type() != QVariant::Map) - continue; - QContactPhoneNumber *detail = new QContactPhoneNumber; - detail->setNumber(phoneDesc.toMap()["value"].toString()); - if (!phoneDesc.toMap()["type"].toString().isEmpty() && - phoneDesc.toMap()["type"].toString() != "phone") - detail->setSubTypes(QList<int>() << - subTypePhoneFromString(phoneDesc.toMap()["type"].toString())); - detailsToDelete << detail; - result.saveDetail(detail); - } - } else if (field == "emails") { - if (params[field].type() != QVariant::List) - continue; - QVariantList emailsList = params[field].toList(); - foreach (const QVariant &emailDesc, emailsList) { - if (emailDesc.type() != QVariant::Map) - continue; - if (emailDesc.toMap()["value"].toString().isEmpty()) - continue; - QContactEmailAddress *detail = new QContactEmailAddress; - detail->setEmailAddress(emailDesc.toMap()["value"].toString()); - detailsToDelete << detail; - result.saveDetail(detail); - } - } else if (field == "ims") { - if (params[field].type() != QVariant::List) - continue; - QVariantList imsList = params[field].toList(); - foreach (const QVariant &imDesc, imsList) { - if (imDesc.type() != QVariant::Map) - continue; - QContactOnlineAccount *detail = new QContactOnlineAccount; - detail->setAccountUri(imDesc.toMap()["value"].toString()); - if (!imDesc.toMap()["type"].toString().isEmpty()) - detail->setSubTypes(QList<int>() << - subTypeOnlineAccountFromString(imDesc.toMap()["type"].toString())); - detailsToDelete << detail; - result.saveDetail(detail); - } - } else if (field == "photos") { - if (params[field].type() != QVariant::List) - continue; - QVariantList photosList = params[field].toList(); - foreach (const QVariant &photoDesc, photosList) { - if (photoDesc.type() != QVariant::Map) - continue; - //TODO: we need to decide should we support base64 images or not - if (photoDesc.toMap()["type"].toString() != "url") - continue; - QContactAvatar *detail = new QContactAvatar; - detail->setImageUrl(QUrl(photoDesc.toMap()["value"].toString())); - detailsToDelete << detail; - result.saveDetail(detail); - } - } else if (field == "urls") { - if (params[field].type() != QVariant::List) - continue; - QVariantList urlsList = params[field].toList(); - foreach (const QVariant &urlDesc, urlsList) { - if (urlDesc.type() != QVariant::Map) - continue; - QContactUrl *detail = new QContactUrl; - detail->setUrl(urlDesc.toMap()["value"].toString()); - if (!urlDesc.toMap()["type"].toString().isEmpty()) - detail->setSubType((QContactUrl::SubType) subTypeUrlFromString(urlDesc.toMap()["type"].toString())); - detailsToDelete << detail; - result.saveDetail(detail); - } - } else if (field == "birthday") { - QDateTime birthday; - birthday.setTime_t(params[field].toLongLong() / 1000); - - QContactBirthday *detail = new QContactBirthday; - detail->setDateTime(birthday); - detailsToDelete << detail; - result.saveDetail(detail); - } else if (field == "organizations") { - - if (params[field].type() != QVariant::List) - continue; - QVariantList organizationsList = params[field].toList(); - foreach (const QVariant &organizationDesc, organizationsList) { - if (organizationDesc.type() != QVariant::Map) - continue; - QContactOrganization *detail = new QContactOrganization; - detail->setName(organizationDesc.toMap()["name"].toString()); - detail->setDepartment(QStringList() << organizationDesc.toMap()["department"].toString()); - detail->setRole(organizationDesc.toMap()["title"].toString()); - detailsToDelete << detail; - result.saveDetail(detail); - } - - } else if (field == "name") { - QContactName *detail = new QContactName; - QVariantMap nameMap = params[field].toMap(); - detail->setLastName(nameMap["familyName"].toString()); - detail->setFirstName(nameMap["givenName"].toString()); - detail->setMiddleName(nameMap["middleName"].toString()); - detail->setPrefix(nameMap["honorificPrefix"].toString()); - detail->setSuffix(nameMap["honorificSuffix"].toString()); - detailsToDelete << detail; - result.saveDetail(detail); - } - - } - if (!m_manager->saveContact(&result)) { - switch (m_manager->error()) { - case QContactManager::DoesNotExistError: - case QContactManager::AlreadyExistsError: - case QContactManager::InvalidDetailError: - case QContactManager::InvalidRelationshipError: - case QContactManager::BadArgumentError: - case QContactManager::InvalidContactTypeError: - callback(ecId, "ContactError.INVALID_ARGUMENT_ERROR"); - break; - case QContactManager::DetailAccessError: - case QContactManager::PermissionsError: - callback(ecId, "ContactError.PERMISSION_DENIED_ERROR"); - break; - case QContactManager::NotSupportedError: - callback(ecId, "ContactError.NOT_SUPPORTED_ERROR"); - break; - case QContactManager::TimeoutError: - callback(ecId, "ContactError.TIMEOUT_ERROR"); - break; - case QContactManager::UnspecifiedError: - case QContactManager::LockedError: - case QContactManager::OutOfMemoryError: - case QContactManager::VersionMismatchError: - case QContactManager::LimitReachedError: - case QContactManager::NoError: - default: - callback(ecId, "ContactError.UNKNOWN_ERROR"); - break; - } - } else { - callback(scId, jsonedContact(result)); - } - qDeleteAll(detailsToDelete); -} - -void Contacts::remove(int scId, int ecId, const QString &localId) { - QContactId id = QContactId::fromString(localId); - - if (!m_manager->removeContact(id)) { - switch (m_manager->error()) { - case QContactManager::AlreadyExistsError: - case QContactManager::InvalidDetailError: - case QContactManager::InvalidRelationshipError: - case QContactManager::BadArgumentError: - case QContactManager::InvalidContactTypeError: - callback(ecId, "ContactError.INVALID_ARGUMENT_ERROR"); - break; - case QContactManager::DetailAccessError: - case QContactManager::PermissionsError: - callback(ecId, "ContactError.PERMISSION_DENIED_ERROR"); - break; - case QContactManager::NotSupportedError: - callback(ecId, "ContactError.NOT_SUPPORTED_ERROR"); - break; - case QContactManager::TimeoutError: - callback(ecId, "ContactError.TIMEOUT_ERROR"); - break; - case QContactManager::UnspecifiedError: - case QContactManager::LockedError: - case QContactManager::OutOfMemoryError: - case QContactManager::VersionMismatchError: - case QContactManager::LimitReachedError: - case QContactManager::NoError: - case QContactManager::DoesNotExistError: - default: - callback(ecId, "ContactError.UNKNOWN_ERROR"); - break; - } - - } else { - cb(scId); - } -} - -void Contacts::search(int scId, int ecId, const QStringList &fields, const QVariantMap ¶ms) { - QString filter; - bool multiple = true; - - if (params.find("filter") != params.end()) { - filter = params["filter"].toString(); - } - if (params.find("multiple") != params.end()) { - multiple = params["multiple"].toBool(); - } - - findContacts(scId, ecId, fields, filter, multiple); -} - -void Contacts::findContacts(int scId, int ecId, const QStringList &fields, const QString &filter, bool multiple) { - if (fields.length() <= 0){ - callback(ecId, "new ContactError(ContactError.INVALID_ARGUMENT_ERROR)"); - } - - QContactUnionFilter unionFilter; - - QMap<QContactDetail::DetailType, QList<int> > fieldNames; - fieldNames[QContactDetail::TypeDisplayLabel] << QContactDisplayLabel::FieldLabel; - fieldNames[QContactDetail::TypeName] << QContactName::FieldFirstName << QContactName::FieldLastName << QContactName::FieldMiddleName << QContactName::FieldPrefix << QContactName::FieldSuffix; - fieldNames[QContactDetail::TypeNickname] << QContactNickname::FieldNickname; - fieldNames[QContactDetail::TypePhoneNumber] << QContactPhoneNumber::FieldNumber; - fieldNames[QContactDetail::TypeEmailAddress] << QContactEmailAddress::FieldEmailAddress; - fieldNames[QContactDetail::TypeAddress] << QContactAddress::FieldCountry << QContactAddress::FieldLocality << QContactAddress::FieldPostcode << QContactAddress::FieldPostOfficeBox << QContactAddress::FieldRegion << QContactAddress::FieldStreet; - fieldNames[QContactDetail::TypeOnlineAccount] << QContactOnlineAccount::FieldAccountUri; - fieldNames[QContactDetail::TypeOrganization] << QContactOrganization::FieldAssistantName << QContactOrganization::FieldDepartment << QContactOrganization::FieldLocation << QContactOrganization::FieldName << QContactOrganization::FieldRole << QContactOrganization::FieldTitle; - fieldNames[QContactDetail::TypeBirthday] << QContactBirthday::FieldBirthday; - fieldNames[QContactDetail::TypeNote] << QContactNote::FieldNote; - fieldNames[QContactDetail::TypeUrl] << QContactUrl::FieldUrl; - - foreach (const QContactDetail::DetailType &defName, fieldNames.keys()) { - foreach(int fieldName, fieldNames[defName]) { - QContactDetailFilter subFilter; - subFilter.setDetailType(defName, fieldName); - subFilter.setValue(filter); - subFilter.setMatchFlags(QContactFilter::MatchContains); - unionFilter.append(subFilter); - } - } - - QList<QContact> contacts = m_manager->contacts(unionFilter); - if (contacts.empty()) { - callback(scId, "[]"); - } else { - QStringList stringifiedContacts; - foreach (const QContact &contact, contacts) { - stringifiedContacts << jsonedContact(contact, fields); - - if (!multiple) - break; - } - callback(scId, QString("[%1]").arg(stringifiedContacts.join(", "))); - } -} - -QContactDetail::DetailType Contacts::cordovaFieldNameToQtDefinition(const QString &cordovaFieldName) const { - if (m_fieldNamePairs.contains(cordovaFieldName)) - return m_fieldNamePairs[cordovaFieldName]; - - return QContactDetail::TypeUndefined; -} - -int Contacts::subTypePhoneFromString(const QString &cordovaSubType) const -{ - QString preparedSubType = cordovaSubType.toLower(); - if (preparedSubType == "mobile") - return QContactPhoneNumber::SubTypeMobile; - else if (preparedSubType == "fax") - return QContactPhoneNumber::SubTypeFax; - else if (preparedSubType == "pager") - return QContactPhoneNumber::SubTypePager; - else if (preparedSubType == "voice") - return QContactPhoneNumber::SubTypeVoice; - else if (preparedSubType == "modem") - return QContactPhoneNumber::SubTypeModem; - else if (preparedSubType == "video") - return QContactPhoneNumber::SubTypeVideo; - else if (preparedSubType == "car") - return QContactPhoneNumber::SubTypeCar; - else if (preparedSubType == "assistant") - return QContactPhoneNumber::SubTypeAssistant; - return QContactPhoneNumber::SubTypeLandline; -} - -int Contacts::subTypeOnlineAccountFromString(const QString &cordovaSubType) const { - QString preparedSubType = cordovaSubType.toLower(); - if (preparedSubType == "aim") - return QContactOnlineAccount::ProtocolAim; - else if (preparedSubType == "icq") - return QContactOnlineAccount::ProtocolIcq; - else if (preparedSubType == "irc") - return QContactOnlineAccount::ProtocolIrc; - else if (preparedSubType == "jabber") - return QContactOnlineAccount::ProtocolJabber; - else if (preparedSubType == "msn") - return QContactOnlineAccount::ProtocolMsn; - else if (preparedSubType == "qq") - return QContactOnlineAccount::ProtocolQq; - else if (preparedSubType == "skype") - return QContactOnlineAccount::ProtocolSkype; - else if (preparedSubType == "yahoo") - return QContactOnlineAccount::ProtocolYahoo; - return QContactOnlineAccount::ProtocolUnknown; -} - -int Contacts::subTypeUrlFromString(const QString &cordovaSubType) const { - QString preparedSubType = cordovaSubType.toLower(); - if (preparedSubType == "blog") - return QContactUrl::SubTypeBlog; - else if (preparedSubType == "favourite") - return QContactUrl::SubTypeFavourite; - return QContactUrl::SubTypeHomePage; -} - -QString Contacts::subTypePhoneToString(int qtSubType) const { - if (qtSubType == QContactPhoneNumber::SubTypeMobile) - return "mobile"; - else if (qtSubType == QContactPhoneNumber::SubTypeFax) - return "fax"; - else if (qtSubType == QContactPhoneNumber::SubTypePager) - return "pager"; - else if (qtSubType == QContactPhoneNumber::SubTypeVoice) - return "voice"; - else if (qtSubType == QContactPhoneNumber::SubTypeModem) - return "modem"; - else if (qtSubType == QContactPhoneNumber::SubTypeVideo) - return "video"; - else if (qtSubType == QContactPhoneNumber::SubTypeCar) - return "car"; - else if (qtSubType == QContactPhoneNumber::SubTypeAssistant) - return "assistant"; - return "home"; -} - -QString Contacts::subTypeOnlineAccountToString(int qtSubType) const { - if (qtSubType == QContactOnlineAccount::ProtocolAim) - return "aim"; - else if (qtSubType == QContactOnlineAccount::ProtocolIcq) - return "icq"; - else if (qtSubType == QContactOnlineAccount::ProtocolIrc) - return "irc"; - else if (qtSubType == QContactOnlineAccount::ProtocolJabber) - return "jabber"; - else if (qtSubType == QContactOnlineAccount::ProtocolMsn) - return "msn"; - else if (qtSubType == QContactOnlineAccount::ProtocolQq) - return "qq"; - else if (qtSubType == QContactOnlineAccount::ProtocolSkype) - return "skype"; - else if (qtSubType == QContactOnlineAccount::ProtocolYahoo) - return "yahoo"; - return "unknown"; -} - -QString Contacts::subTypeUrlToString(int qtSubType) const { - if (qtSubType == QContactUrl::SubTypeBlog) - return "blog"; - else if (qtSubType == QContactUrl::SubTypeFavourite) - return "favourite"; - return "homepage"; -} - -QString Contacts::jsonedContact(const QContact &contact, const QStringList &fields) const { - QStringList resultingFields = fields; - if (resultingFields.empty()) - resultingFields.append(m_fieldNamePairs.keys()); - if (!resultingFields.contains("id")) - resultingFields << "id"; - QStringList fieldValuesList; - foreach (const QString &field, resultingFields) { - QContactDetail::DetailType qtDefinitionName = cordovaFieldNameToQtDefinition(field); - if (field == "id") { - fieldValuesList << QString("%1: \"%2\"") - .arg(field) - .arg(contact.id().toString()); - } else if (field == "displayName") { - QContactDisplayLabel detail = contact.detail(qtDefinitionName); - fieldValuesList << QString("%1: \"%2\"") - .arg(field) - .arg(detail.label()); - } else if (field == "nickname") { - QContactNickname detail = contact.detail(qtDefinitionName); - fieldValuesList << QString("%1: \"%2\"") - .arg(field) - .arg(detail.nickname()); - } else if (field == "note") { - QContactNote detail = contact.detail(qtDefinitionName); - fieldValuesList << QString("%1: \"%2\"") - .arg(field) - .arg(detail.note()); - } else if (field == "phoneNumbers") { - QStringList fieldValues; - QList<QContactDetail> details = contact.details(qtDefinitionName); - foreach (const QContactDetail &detail, details) { - QContactPhoneNumber castedDetail = detail; - QStringList subTypes; - foreach (int subType, castedDetail.subTypes()) - subTypes << subTypePhoneToString(subType); - - if (subTypes.isEmpty()) - subTypes << "phone"; - foreach(const QString &subType, subTypes) { - fieldValues << QString("{type: \"%1\", value: \"%2\", pref: %3}") - .arg(subType) - .arg(castedDetail.number()) - .arg("false"); - } - } - fieldValuesList << QString("%1: [%2]") - .arg(field) - .arg(fieldValues.join(", ")); - } else if (field == "emails") { - QStringList fieldValues; - QList<QContactDetail> details = contact.details(qtDefinitionName); - foreach (const QContactDetail &detail, details) { - QContactEmailAddress castedDetail = detail; - fieldValues << QString("{type: \"%1\", value: \"%2\", pref: %3}") - .arg("email") - .arg(castedDetail.emailAddress()) - .arg("false"); - } - fieldValuesList << QString("%1: [%2]") - .arg(field) - .arg(fieldValues.join(", ")); - } else if (field == "ims") { - QStringList fieldValues; - QList<QContactDetail> details = contact.details(qtDefinitionName); - foreach (const QContactDetail &detail, details) { - QContactOnlineAccount castedDetail = detail; - QStringList subTypes; - foreach (int subType, castedDetail.subTypes()) - subTypes << subTypeOnlineAccountToString(subType); - - if (subTypes.isEmpty()) - subTypes << "IM"; - foreach(const QString &subType, subTypes) { - fieldValues << QString("{type: \"%1\", value: \"%2\", pref: %3}") - .arg(subType) - .arg(castedDetail.accountUri()) - .arg("false"); - } - } - fieldValuesList << QString("%1: [%2]") - .arg(field) - .arg(fieldValues.join(", ")); - } else if (field == "photos") { - QStringList fieldValues; - QList<QContactDetail> details = contact.details(qtDefinitionName); - foreach (const QContactDetail &detail, details) { - QContactAvatar castedDetail = detail; - fieldValues << QString("{type: \"%1\", value: \"%2\", pref: %3}") - .arg("url") - .arg(castedDetail.imageUrl().toString()) - .arg("false"); - } - fieldValuesList << QString("%1: [%2]") - .arg(field) - .arg(fieldValues.join(", ")); - } else if (field == "urls") { - QStringList fieldValues; - QList<QContactDetail> details = contact.details(qtDefinitionName); - - foreach (const QContactDetail &detail, details) { - QContactUrl castedDetail = detail; - QString subType = subTypeUrlToString(castedDetail.subType()); - - fieldValues << QString("{type: \"%1\", value: \"%2\", pref: %3}") - .arg(subType) - .arg(castedDetail.url()) - .arg("false"); - } - fieldValuesList << QString("%1: [%2]") - .arg(field) - .arg(fieldValues.join(", ")); - } else if (field == "birthday") { - QContactBirthday detail = contact.detail(qtDefinitionName); - fieldValuesList << QString("%1: %2") - .arg(field) - .arg(detail.dateTime().toMSecsSinceEpoch()); - } else if (field == "organizations") { - QStringList fieldValues; - QList<QContactDetail> details = contact.details(qtDefinitionName); - foreach (const QContactDetail &detail, details) { - QContactOrganization castedDetail = detail; - fieldValues << QString("{type: \"%1\", name: \"%2\", department: \"%3\", title: \"%4\", pref: %5}") - .arg("organization") - .arg(castedDetail.name()) - .arg(castedDetail.department().join(" ")) - .arg(castedDetail.role()) - .arg("false"); - } - fieldValuesList << QString("%1: [%2]") - .arg(field) - .arg(fieldValues.join(", ")); - } else if (field == "name") { - QContactName detail = contact.detail(qtDefinitionName); - fieldValuesList << QString("%1: {familyName: \"%2\", givenName: \"%3\", middleName: \"%4\", honorificPrefix: \"%5\", honorificSuffix: \"%6\"}") - .arg(field) - .arg(detail.lastName()) - .arg(detail.firstName()) - .arg(detail.middleName()) - .arg(detail.prefix()) - .arg(detail.suffix()); - } - - - } - - return QString("{%1}").arg(fieldValuesList.join(", ")); -}
diff --git a/src/ubuntu/contacts.h b/src/ubuntu/contacts.h deleted file mode 100644 index 4c1343b..0000000 --- a/src/ubuntu/contacts.h +++ /dev/null
@@ -1,70 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * -*/ - -#ifndef CONTACTS_H_SSSSSSS -#define CONTACTS_H_SSSSSSS - -#include <cplugin.h> - -#include <QtContacts> -#include <QtCore> - -QTCONTACTS_USE_NAMESPACE - -class Contacts : public CPlugin { - Q_OBJECT -public: - explicit Contacts(Cordova *cordova); - - virtual const QString fullName() override { - return Contacts::fullID(); - } - - virtual const QString shortName() override { - return "Contacts"; - } - - static const QString fullID() { - return "Contacts"; - } - -public slots: - void save(int scId, int ecId, const QVariantMap ¶ms); - void remove(int scId, int ecId, const QString &localId); - void search(int scId, int ecId, const QStringList &fields, const QVariantMap ¶ms); - -private: - void findContacts(int scId, int ecId, const QStringList &fields, const QString &filter, bool multiple); - QContactDetail::DetailType cordovaFieldNameToQtDefinition(const QString &cordovaFieldName) const; - int subTypePhoneFromString(const QString &cordovaSubType) const; - int subTypeOnlineAccountFromString(const QString &cordovaSubType) const; - int subTypeUrlFromString(const QString &cordovaSubType) const; - QString subTypePhoneToString(int qtSubType) const; - QString subTypeOnlineAccountToString(int qtSubType) const; - QString subTypeUrlToString(int qtSubType) const; - QString jsonedContact(const QContact &contact, const QStringList &fields = QStringList()) const; - - QHash<QString, QContactDetail::DetailType> m_fieldNamePairs; - QSet<QString> m_notSupportedFields; - QSharedPointer<QContactManager> m_manager; -}; - -#endif
diff --git a/src/windows8/ContactProxy.js b/src/windows8/ContactProxy.js deleted file mode 100644 index 10f9402..0000000 --- a/src/windows8/ContactProxy.js +++ /dev/null
@@ -1,151 +0,0 @@ -//cordova.define("org.apache.cordova.contacts.ContactProxy", function (require, exports, module) { -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * -*/ - - -module.exports = { - search:function(win,fail,args){ - var fields = args[0]; // ignored, always returns entire object - var options = args[1]; - - var filter = options.filter; // ignored - var multiple = true;//options.multiple; - - var picker = new Windows.ApplicationModel.Contacts.ContactPicker(); - picker.selectionMode = Windows.ApplicationModel.Contacts.ContactSelectionMode.contacts; // select entire contact - if (picker.pickContactAsync) { - // TODO: 8.1 has better contact support via the 'Contact' object - } - else { - // 8.0 use the ContactInformation class - // decide which function we will call - var pickerFunkName = multiple ? 'pickMultipleContactsAsync' : 'pickSingleContactAsync'; - picker[pickerFunkName]().done(function (res) { - if (!res) { - fail && setTimeout(function () { - fail(new Error("User did not pick a contact.")); - }, 0); - return; - } - - var contactResults = []; - - for (var i = 0; i < res.length; i++) { - - - var index, - contactResult = res[i], - contact = { - id: "", - name: { formatted: contactResult.name }, // ContactName - displayName: contactResult.name, // DOMString - nickname: contactResult.name, // DOMString - phoneNumbers: contactResult.phoneNumbers, // ContactField[] - addresses: contactResult.locations, // ContactAddress[] - emails: [], // ContactField - ims: contactResult.instantMessages, // ContactField[] - organizations: [], // ContactOrganization[] - birthday: null, // Date - note: "", // DOMString - photos: [], // ContactField[] - categories: [], // ContactField[] - urls: [] // ContactField[] - }; - - // Win8-ContactField is {category, name, type, value}; - // Cordova ContactField is {type,value, pref:bool }; - // Win8 type means 'email' cordova type means 'work|home|...' so we convert them - if (contact.emails && contact.emails.length) { - contact.emails[0].pref = true; // add a preferred prop - for (index = 0; index < contacts.emails.length; index++) { - contact.emails[index].type = contact.emails[index].category; - } - } - - if (contact.phoneNumbers && contact.phoneNumbers.length) { - contact.phoneNumbers[0].pref = true; // cordova contact field needs a 'prefered' property on a contact - // change the meaning of type from 'telephonenumber' to 'work|home|...' - for (index = 0; index < contact.phoneNumbers.length; index++) { - contact.phoneNumbers[index].type = contact.phoneNumbers[index].category; - } - } - - if (contact.addresses && contact.addresses.length) { - - // convert addresses/locations to Cordova.ContactAddresses - // constr: ContactAddress(pref, type, formatted, streetAddress, locality, region, postalCode, country) - var address, formatted; - for (index = 0; index < contact.addresses.length; index++) { - address = contact.addresses[index]; // make an alias - var formattedArray = []; - // get rid of the empty fields. - var fields = [address.street, address.city, address.region, address.country, address.postalCode]; - for (var n = 0; n < fields.length; n++) { - if (fields[n].length > 0) { - formattedArray.push(fields[n]); - } - } - formattedAddress = formattedArray.join(", "); - console.log(contact.name.formatted + " formatted looks like " + formattedAddress); - contact.addresses[index] = new ContactAddress(false, - address.name, - formattedAddress, - address.street, - address.city, - address.region, - address.postalCode, - address.country); - } - - } - - // convert ims to ContactField - if (contact.ims && contact.ims.length) { - // MS ContactInstantMessageField has : displayText, launchUri, service, userName, category, type - contact.ims[0].pref = true; - for (index = 0; index < contact.ims.length; index++) { - contact.ims[index] = new ContactField(contact.ims[index].type, contact.ims[index].value, false); - } - } - - contactResults.push(contact); - - } - // send em back - win(contactResults); - - }); - } - }, - - save:function(win,fail,args){ - console && console.error && console.error("Error : Windows 8 does not support creating/saving contacts"); - fail && setTimeout(function () { - fail(new Error("Contact create/save not supported on Windows 8")); - }, 0); - - } - - -} - -require("cordova/exec/proxy").add("Contacts", module.exports); -// });
diff --git a/src/wp/Contacts.cs b/src/wp/Contacts.cs deleted file mode 100644 index 5ae2144..0000000 --- a/src/wp/Contacts.cs +++ /dev/null
@@ -1,693 +0,0 @@ -/* - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -using Microsoft.Phone.Tasks; -using Microsoft.Phone.UserData; -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.Globalization; -using System.Linq; -using System.Runtime.Serialization; -using System.Windows; -using DeviceContacts = Microsoft.Phone.UserData.Contacts; - - -namespace WPCordovaClassLib.Cordova.Commands -{ - [DataContract] - public class SearchOptions - { - [DataMember] - public string filter { get; set; } - [DataMember] - public bool multiple { get; set; } - } - - [DataContract] - public class ContactSearchParams - { - [DataMember] - public string[] fields { get; set; } - [DataMember] - public SearchOptions options { get; set; } - } - - [DataContract] - public class JSONContactAddress - { - [DataMember] - public string formatted { get; set; } - [DataMember] - public string type { get; set; } - [DataMember] - public string streetAddress { get; set; } - [DataMember] - public string locality { get; set; } - [DataMember] - public string region { get; set; } - [DataMember] - public string postalCode { get; set; } - [DataMember] - public string country { get; set; } - [DataMember] - public bool pref { get; set; } - } - - [DataContract] - public class JSONContactName - { - [DataMember] - public string formatted { get; set; } - [DataMember] - public string familyName { get; set; } - [DataMember] - public string givenName { get; set; } - [DataMember] - public string middleName { get; set; } - [DataMember] - public string honorificPrefix { get; set; } - [DataMember] - public string honorificSuffix { get; set; } - } - - [DataContract] - public class JSONContactField - { - [DataMember] - public string type { get; set; } - [DataMember] - public string value { get; set; } - [DataMember] - public bool pref { get; set; } - } - - [DataContract] - public class JSONContactOrganization - { - [DataMember] - public string type { get; set; } - [DataMember] - public string name { get; set; } - [DataMember] - public bool pref { get; set; } - [DataMember] - public string department { get; set; } - [DataMember] - public string title { get; set; } - } - - [DataContract] - public class JSONContact - { - [DataMember] - public string id { get; set; } - [DataMember] - public string rawId { get; set; } - [DataMember] - public string displayName { get; set; } - [DataMember] - public string nickname { get; set; } - [DataMember] - public string note { get; set; } - - [DataMember] - public JSONContactName name { get; set; } - - [DataMember] - public JSONContactField[] emails { get; set; } - - [DataMember] - public JSONContactField[] phoneNumbers { get; set; } - - [DataMember] - public JSONContactField[] ims { get; set; } - - [DataMember] - public JSONContactField[] photos { get; set; } - - [DataMember] - public JSONContactField[] categories { get; set; } - - [DataMember] - public JSONContactField[] urls { get; set; } - - [DataMember] - public JSONContactOrganization[] organizations { get; set; } - - [DataMember] - public JSONContactAddress[] addresses { get; set; } - } - - - public class Contacts : BaseCommand - { - - public const int UNKNOWN_ERROR = 0; - public const int INVALID_ARGUMENT_ERROR = 1; - public const int TIMEOUT_ERROR = 2; - public const int PENDING_OPERATION_ERROR = 3; - public const int IO_ERROR = 4; - public const int NOT_SUPPORTED_ERROR = 5; - public const int PERMISSION_DENIED_ERROR = 20; - public const int SYNTAX_ERR = 8; - - public Contacts() - { - - } - - // refer here for contact properties we can access: http://msdn.microsoft.com/en-us/library/microsoft.phone.tasks.savecontacttask_members%28v=VS.92%29.aspx - public void save(string jsonContact) - { - - // jsonContact is actually an array of 1 {contact} - string[] args = JSON.JsonHelper.Deserialize<string[]>(jsonContact); - - - JSONContact contact = JSON.JsonHelper.Deserialize<JSONContact>(args[0]); - - SaveContactTask contactTask = new SaveContactTask(); - - if (contact.nickname != null) - { - contactTask.Nickname = contact.nickname; - } - if (contact.urls != null && contact.urls.Length > 0) - { - contactTask.Website = contact.urls[0].value; - } - if (contact.note != null) - { - contactTask.Notes = contact.note; - } - - #region contact.name - if (contact.name != null) - { - if (contact.name.givenName != null) - contactTask.FirstName = contact.name.givenName; - if (contact.name.familyName != null) - contactTask.LastName = contact.name.familyName; - if (contact.name.middleName != null) - contactTask.MiddleName = contact.name.middleName; - if (contact.name.honorificSuffix != null) - contactTask.Suffix = contact.name.honorificSuffix; - if (contact.name.honorificPrefix != null) - contactTask.Title = contact.name.honorificPrefix; - } - #endregion - - #region contact.org - if (contact.organizations != null && contact.organizations.Count() > 0) - { - contactTask.Company = contact.organizations[0].name; - contactTask.JobTitle = contact.organizations[0].title; - } - #endregion - - #region contact.phoneNumbers - if (contact.phoneNumbers != null && contact.phoneNumbers.Length > 0) - { - foreach (JSONContactField field in contact.phoneNumbers) - { - string fieldType = field.type.ToLower(); - if (fieldType == "work") - { - contactTask.WorkPhone = field.value; - } - else if (fieldType == "home") - { - contactTask.HomePhone = field.value; - } - else if (fieldType == "mobile") - { - contactTask.MobilePhone = field.value; - } - } - } - #endregion - - #region contact.emails - - if (contact.emails != null && contact.emails.Length > 0) - { - - // set up different email types if they are not explicitly defined - foreach (string type in new string[] { "personal", "work", "other" }) - { - foreach (JSONContactField field in contact.emails) - { - if (field != null && String.IsNullOrEmpty(field.type)) - { - field.type = type; - break; - } - } - } - - foreach (JSONContactField field in contact.emails) - { - if (field != null) - { - if (field.type != null && field.type != "other") - { - string fieldType = field.type.ToLower(); - if (fieldType == "work") - { - contactTask.WorkEmail = field.value; - } - else if (fieldType == "home" || fieldType == "personal") - { - contactTask.PersonalEmail = field.value; - } - } - else - { - contactTask.OtherEmail = field.value; - } - } - - } - } - #endregion - - if (contact.note != null && contact.note.Length > 0) - { - contactTask.Notes = contact.note; - } - - #region contact.addresses - if (contact.addresses != null && contact.addresses.Length > 0) - { - foreach (JSONContactAddress address in contact.addresses) - { - if (address.type == null) - { - address.type = "home"; // set a default - } - string fieldType = address.type.ToLower(); - if (fieldType == "work") - { - contactTask.WorkAddressCity = address.locality; - contactTask.WorkAddressCountry = address.country; - contactTask.WorkAddressState = address.region; - contactTask.WorkAddressStreet = address.streetAddress; - contactTask.WorkAddressZipCode = address.postalCode; - } - else if (fieldType == "home" || fieldType == "personal") - { - contactTask.HomeAddressCity = address.locality; - contactTask.HomeAddressCountry = address.country; - contactTask.HomeAddressState = address.region; - contactTask.HomeAddressStreet = address.streetAddress; - contactTask.HomeAddressZipCode = address.postalCode; - } - else - { - // no other address fields available ... - Debug.WriteLine("Creating contact with unsupported address type :: " + address.type); - } - } - } - #endregion - - - contactTask.Completed += new EventHandler<SaveContactResult>(ContactSaveTaskCompleted); - contactTask.Show(); - } - - void ContactSaveTaskCompleted(object sender, SaveContactResult e) - { - SaveContactTask task = sender as SaveContactTask; - - if (e.TaskResult == TaskResult.OK) - { - - Deployment.Current.Dispatcher.BeginInvoke(() => - { - DeviceContacts deviceContacts = new DeviceContacts(); - deviceContacts.SearchCompleted += new EventHandler<ContactsSearchEventArgs>(postAdd_SearchCompleted); - - string displayName = String.Format("{0}{2}{1}", task.FirstName, task.LastName, String.IsNullOrEmpty(task.FirstName) ? "" : " "); - - deviceContacts.SearchAsync(displayName, FilterKind.DisplayName, task); - }); - - - } - else if (e.TaskResult == TaskResult.Cancel) - { - DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Operation cancelled.")); - } - } - - void postAdd_SearchCompleted(object sender, ContactsSearchEventArgs e) - { - if (e.Results.Count() > 0) - { - List<Contact> foundContacts = new List<Contact>(); - - int n = (from Contact contact in e.Results select contact.GetHashCode()).Max(); - Contact newContact = (from Contact contact in e.Results - where contact.GetHashCode() == n - select contact).First(); - - DispatchCommandResult(new PluginResult(PluginResult.Status.OK, FormatJSONContact(newContact, null))); - } - else - { - DispatchCommandResult(new PluginResult(PluginResult.Status.NO_RESULT)); - } - } - - - - public void remove(string id) - { - // note id is wrapped in [] and always has exactly one string ... - DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "{\"code\":" + NOT_SUPPORTED_ERROR + "}")); - } - - public void search(string searchCriteria) - { - string[] args = JSON.JsonHelper.Deserialize<string[]>(searchCriteria); - - ContactSearchParams searchParams = new ContactSearchParams(); - try - { - searchParams.fields = JSON.JsonHelper.Deserialize<string[]>(args[0]); - searchParams.options = JSON.JsonHelper.Deserialize<SearchOptions>(args[1]); - } - catch (Exception) - { - DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, INVALID_ARGUMENT_ERROR)); - return; - } - - if (searchParams.options == null) - { - searchParams.options = new SearchOptions(); - searchParams.options.filter = ""; - searchParams.options.multiple = true; - } - else if (searchParams.options.filter == null) - { - searchParams.options.filter = ""; - } - - DeviceContacts deviceContacts = new DeviceContacts(); - deviceContacts.SearchCompleted += new EventHandler<ContactsSearchEventArgs>(contacts_SearchCompleted); - - // default is to search all fields - FilterKind filterKind = FilterKind.None; - // if only one field is specified, we will try the 3 available DeviceContact search filters - if (searchParams.fields.Count() == 1) - { - if (searchParams.fields.Contains("name")) - { - filterKind = FilterKind.DisplayName; - } - else if (searchParams.fields.Contains("emails")) - { - filterKind = FilterKind.EmailAddress; - } - else if (searchParams.fields.Contains("phoneNumbers")) - { - filterKind = FilterKind.PhoneNumber; - } - } - - try - { - - deviceContacts.SearchAsync(searchParams.options.filter, filterKind, searchParams); - } - catch (Exception ex) - { - Debug.WriteLine("search contacts exception :: " + ex.Message); - } - } - - private void contacts_SearchCompleted(object sender, ContactsSearchEventArgs e) - { - ContactSearchParams searchParams = (ContactSearchParams)e.State; - - List<Contact> foundContacts = null; - // used for comparing strings, "" instantiates with InvariantCulture - CultureInfo culture = new CultureInfo(""); - // make the search comparisons case insensitive. - CompareOptions compare_option = CompareOptions.IgnoreCase; - - // if we have multiple search fields - - if (!String.IsNullOrEmpty(searchParams.options.filter) && searchParams.fields.Count() > 1) - { - foundContacts = new List<Contact>(); - if (searchParams.fields.Contains("emails")) - { - foundContacts.AddRange(from Contact con in e.Results - from ContactEmailAddress a in con.EmailAddresses - where culture.CompareInfo.IndexOf(a.EmailAddress, searchParams.options.filter, compare_option) >= 0 - select con); - } - if (searchParams.fields.Contains("displayName")) - { - foundContacts.AddRange(from Contact con in e.Results - where culture.CompareInfo.IndexOf(con.DisplayName, searchParams.options.filter, compare_option) >= 0 - select con); - } - if (searchParams.fields.Contains("name")) - { - foundContacts.AddRange( - from Contact con in e.Results - where con.CompleteName != null && ( - (con.CompleteName.FirstName != null && culture.CompareInfo.IndexOf(con.CompleteName.FirstName, searchParams.options.filter, compare_option) >= 0) || - (con.CompleteName.LastName != null && culture.CompareInfo.IndexOf(con.CompleteName.LastName, searchParams.options.filter, compare_option) >= 0) || - (con.CompleteName.MiddleName != null && culture.CompareInfo.IndexOf(con.CompleteName.MiddleName, searchParams.options.filter, compare_option) >= 0) || - (con.CompleteName.Nickname != null && culture.CompareInfo.IndexOf(con.CompleteName.Nickname, searchParams.options.filter, compare_option) >= 0) || - (con.CompleteName.Suffix != null && culture.CompareInfo.IndexOf(con.CompleteName.Suffix, searchParams.options.filter, compare_option) >= 0) || - (con.CompleteName.Title != null && culture.CompareInfo.IndexOf(con.CompleteName.Title, searchParams.options.filter, compare_option) >= 0) || - (con.CompleteName.YomiFirstName != null && culture.CompareInfo.IndexOf(con.CompleteName.YomiFirstName, searchParams.options.filter, compare_option) >= 0) || - (con.CompleteName.YomiLastName != null && culture.CompareInfo.IndexOf(con.CompleteName.YomiLastName, searchParams.options.filter, compare_option) >= 0)) - select con); - } - if (searchParams.fields.Contains("phoneNumbers")) - { - foundContacts.AddRange(from Contact con in e.Results - from ContactPhoneNumber a in con.PhoneNumbers - where culture.CompareInfo.IndexOf(a.PhoneNumber, searchParams.options.filter, compare_option) >= 0 - select con); - } - if (searchParams.fields.Contains("urls")) - { - foundContacts.AddRange(from Contact con in e.Results - from string a in con.Websites - where culture.CompareInfo.IndexOf(a, searchParams.options.filter, compare_option) >= 0 - select con); - } - } - else - { - foundContacts = new List<Contact>(e.Results); - } - - //List<string> contactList = new List<string>(); - - string strResult = ""; - - IEnumerable<Contact> distinctContacts = foundContacts.Distinct(); - - foreach (Contact contact in distinctContacts) - { - strResult += FormatJSONContact(contact, null) + ","; - //contactList.Add(FormatJSONContact(contact, null)); - if (!searchParams.options.multiple) - { - break; // just return the first item - } - } - PluginResult result = new PluginResult(PluginResult.Status.OK); - result.Message = "[" + strResult.TrimEnd(',') + "]"; - DispatchCommandResult(result); - - } - - private string FormatJSONPhoneNumbers(Contact con) - { - string retVal = ""; - string contactFieldFormat = "\"type\":\"{0}\",\"value\":\"{1}\",\"pref\":\"false\""; - foreach (ContactPhoneNumber number in con.PhoneNumbers) - { - - string contactField = string.Format(contactFieldFormat, - number.Kind.ToString(), - number.PhoneNumber); - - retVal += "{" + contactField + "},"; - } - return retVal.TrimEnd(','); - } - - private string FormatJSONEmails(Contact con) - { - string retVal = ""; - string contactFieldFormat = "\"type\":\"{0}\",\"value\":\"{1}\",\"pref\":\"false\""; - foreach (ContactEmailAddress address in con.EmailAddresses) - { - string contactField = string.Format(contactFieldFormat, - address.Kind.ToString(), - EscapeJson(address.EmailAddress)); - - retVal += "{" + contactField + "},"; - } - return retVal.TrimEnd(','); - } - - private string getFormattedJSONAddress(ContactAddress address, bool isPrefered) - { - - string addressFormatString = "\"pref\":{0}," + // bool - "\"type\":\"{1}\"," + - "\"formatted\":\"{2}\"," + - "\"streetAddress\":\"{3}\"," + - "\"locality\":\"{4}\"," + - "\"region\":\"{5}\"," + - "\"postalCode\":\"{6}\"," + - "\"country\":\"{7}\""; - - string formattedAddress = EscapeJson(address.PhysicalAddress.AddressLine1 + " " - + address.PhysicalAddress.AddressLine2 + " " - + address.PhysicalAddress.City + " " - + address.PhysicalAddress.StateProvince + " " - + address.PhysicalAddress.CountryRegion + " " - + address.PhysicalAddress.PostalCode); - - string jsonAddress = string.Format(addressFormatString, - isPrefered ? "\"true\"" : "\"false\"", - address.Kind.ToString(), - formattedAddress, - EscapeJson(address.PhysicalAddress.AddressLine1 + " " + address.PhysicalAddress.AddressLine2), - address.PhysicalAddress.City, - address.PhysicalAddress.StateProvince, - address.PhysicalAddress.PostalCode, - address.PhysicalAddress.CountryRegion); - - //Debug.WriteLine("getFormattedJSONAddress returning :: " + jsonAddress); - - return "{" + jsonAddress + "}"; - } - - private string FormatJSONAddresses(Contact con) - { - string retVal = ""; - foreach (ContactAddress address in con.Addresses) - { - retVal += this.getFormattedJSONAddress(address, false) + ","; - } - - //Debug.WriteLine("FormatJSONAddresses returning :: " + retVal); - return retVal.TrimEnd(','); - } - - private string FormatJSONWebsites(Contact con) - { - string retVal = ""; - foreach (string website in con.Websites) - { - retVal += "\"" + EscapeJson(website) + "\","; - } - return retVal.TrimEnd(','); - } - - /* - * formatted: The complete name of the contact. (DOMString) - familyName: The contacts family name. (DOMString) - givenName: The contacts given name. (DOMString) - middleName: The contacts middle name. (DOMString) - honorificPrefix: The contacts prefix (example Mr. or Dr.) (DOMString) - honorificSuffix: The contacts suffix (example Esq.). (DOMString) - */ - private string FormatJSONName(Contact con) - { - string retVal = ""; - string formatStr = "\"formatted\":\"{0}\"," + - "\"familyName\":\"{1}\"," + - "\"givenName\":\"{2}\"," + - "\"middleName\":\"{3}\"," + - "\"honorificPrefix\":\"{4}\"," + - "\"honorificSuffix\":\"{5}\""; - - if (con.CompleteName != null) - { - retVal = string.Format(formatStr, - EscapeJson(con.CompleteName.FirstName + " " + con.CompleteName.LastName), // TODO: does this need suffix? middlename? - EscapeJson(con.CompleteName.LastName), - EscapeJson(con.CompleteName.FirstName), - EscapeJson(con.CompleteName.MiddleName), - EscapeJson(con.CompleteName.Title), - EscapeJson(con.CompleteName.Suffix)); - } - else - { - retVal = string.Format(formatStr,"","","","","",""); - } - - return "{" + retVal + "}"; - } - - private string FormatJSONContact(Contact con, string[] fields) - { - - string contactFormatStr = "\"id\":\"{0}\"," + - "\"displayName\":\"{1}\"," + - "\"nickname\":\"{2}\"," + - "\"phoneNumbers\":[{3}]," + - "\"emails\":[{4}]," + - "\"addresses\":[{5}]," + - "\"urls\":[{6}]," + - "\"name\":{7}," + - "\"note\":\"{8}\"," + - "\"birthday\":\"{9}\""; - - - string jsonContact = String.Format(contactFormatStr, - con.GetHashCode(), - EscapeJson(con.DisplayName), - EscapeJson(con.CompleteName != null ? con.CompleteName.Nickname : ""), - FormatJSONPhoneNumbers(con), - FormatJSONEmails(con), - FormatJSONAddresses(con), - FormatJSONWebsites(con), - FormatJSONName(con), - EscapeJson(con.Notes.FirstOrDefault()), - EscapeJson(Convert.ToString(con.Birthdays.FirstOrDefault()))); - - return "{" + jsonContact + "}"; - - } - - - private static string EscapeJson(string str) - { - if (String.IsNullOrEmpty(str)) - { - return str; - } - - return str.Replace("\n", "\\n").Replace("\r", "\\r").Replace("\t", "\\t").Replace("\"", "\\\"").Replace("&", "\\&"); - } - } -}
diff --git a/www/Contact.js b/www/Contact.js deleted file mode 100644 index 9c46a0c..0000000 --- a/www/Contact.js +++ /dev/null
@@ -1,177 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * -*/ - -var argscheck = require('cordova/argscheck'), - exec = require('cordova/exec'), - ContactError = require('./ContactError'), - utils = require('cordova/utils'); - -/** -* Converts primitives into Complex Object -* Currently only used for Date fields -*/ -function convertIn(contact) { - var value = contact.birthday; - try { - contact.birthday = new Date(parseFloat(value)); - } catch (exception){ - console.log("Cordova Contact convertIn error: exception creating date."); - } - return contact; -} - -/** -* Converts Complex objects into primitives -* Only conversion at present is for Dates. -**/ - -function convertOut(contact) { - var value = contact.birthday; - if (value !== null) { - // try to make it a Date object if it is not already - if (!utils.isDate(value)){ - try { - value = new Date(value); - } catch(exception){ - value = null; - } - } - if (utils.isDate(value)){ - value = value.valueOf(); // convert to milliseconds - } - contact.birthday = value; - } - return contact; -} - -/** -* Contains information about a single contact. -* @constructor -* @param {DOMString} id unique identifier -* @param {DOMString} displayName -* @param {ContactName} name -* @param {DOMString} nickname -* @param {Array.<ContactField>} phoneNumbers array of phone numbers -* @param {Array.<ContactField>} emails array of email addresses -* @param {Array.<ContactAddress>} addresses array of addresses -* @param {Array.<ContactField>} ims instant messaging user ids -* @param {Array.<ContactOrganization>} organizations -* @param {DOMString} birthday contact's birthday -* @param {DOMString} note user notes about contact -* @param {Array.<ContactField>} photos -* @param {Array.<ContactField>} categories -* @param {Array.<ContactField>} urls contact's web sites -*/ -var Contact = function (id, displayName, name, nickname, phoneNumbers, emails, addresses, - ims, organizations, birthday, note, photos, categories, urls) { - this.id = id || null; - this.rawId = null; - this.displayName = displayName || null; - this.name = name || null; // ContactName - this.nickname = nickname || null; - this.phoneNumbers = phoneNumbers || null; // ContactField[] - this.emails = emails || null; // ContactField[] - this.addresses = addresses || null; // ContactAddress[] - this.ims = ims || null; // ContactField[] - this.organizations = organizations || null; // ContactOrganization[] - this.birthday = birthday || null; - this.note = note || null; - this.photos = photos || null; // ContactField[] - this.categories = categories || null; // ContactField[] - this.urls = urls || null; // ContactField[] -}; - -/** -* Removes contact from device storage. -* @param successCB success callback -* @param errorCB error callback -*/ -Contact.prototype.remove = function(successCB, errorCB) { - argscheck.checkArgs('FF', 'Contact.remove', arguments); - var fail = errorCB && function(code) { - errorCB(new ContactError(code)); - }; - if (this.id === null) { - fail(ContactError.UNKNOWN_ERROR); - } - else { - exec(successCB, fail, "Contacts", "remove", [this.id]); - } -}; - -/** -* Creates a deep copy of this Contact. -* With the contact ID set to null. -* @return copy of this Contact -*/ -Contact.prototype.clone = function() { - var clonedContact = utils.clone(this); - clonedContact.id = null; - clonedContact.rawId = null; - - function nullIds(arr) { - if (arr) { - for (var i = 0; i < arr.length; ++i) { - arr[i].id = null; - } - } - } - - // Loop through and clear out any id's in phones, emails, etc. - nullIds(clonedContact.phoneNumbers); - nullIds(clonedContact.emails); - nullIds(clonedContact.addresses); - nullIds(clonedContact.ims); - nullIds(clonedContact.organizations); - nullIds(clonedContact.categories); - nullIds(clonedContact.photos); - nullIds(clonedContact.urls); - return clonedContact; -}; - -/** -* Persists contact to device storage. -* @param successCB success callback -* @param errorCB error callback -*/ -Contact.prototype.save = function(successCB, errorCB) { - argscheck.checkArgs('FFO', 'Contact.save', arguments); - var fail = errorCB && function(code) { - errorCB(new ContactError(code)); - }; - var success = function(result) { - if (result) { - if (successCB) { - var fullContact = require('./contacts').create(result); - successCB(convertIn(fullContact)); - } - } - else { - // no Entry object returned - fail(ContactError.UNKNOWN_ERROR); - } - }; - var dupContact = convertOut(utils.clone(this)); - exec(success, fail, "Contacts", "save", [dupContact]); -}; - - -module.exports = Contact;
diff --git a/www/ContactAddress.js b/www/ContactAddress.js deleted file mode 100644 index 3d39086..0000000 --- a/www/ContactAddress.js +++ /dev/null
@@ -1,46 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * -*/ - -/** -* Contact address. -* @constructor -* @param {DOMString} id unique identifier, should only be set by native code -* @param formatted // NOTE: not a W3C standard -* @param streetAddress -* @param locality -* @param region -* @param postalCode -* @param country -*/ - -var ContactAddress = function(pref, type, formatted, streetAddress, locality, region, postalCode, country) { - this.id = null; - this.pref = (typeof pref != 'undefined' ? pref : false); - this.type = type || null; - this.formatted = formatted || null; - this.streetAddress = streetAddress || null; - this.locality = locality || null; - this.region = region || null; - this.postalCode = postalCode || null; - this.country = country || null; -}; - -module.exports = ContactAddress;
diff --git a/www/ContactError.js b/www/ContactError.js deleted file mode 100644 index 01b229a..0000000 --- a/www/ContactError.js +++ /dev/null
@@ -1,42 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * -*/ - -/** - * ContactError. - * An error code assigned by an implementation when an error has occurred - * @constructor - */ -var ContactError = function(err) { - this.code = (typeof err != 'undefined' ? err : null); -}; - -/** - * Error codes - */ -ContactError.UNKNOWN_ERROR = 0; -ContactError.INVALID_ARGUMENT_ERROR = 1; -ContactError.TIMEOUT_ERROR = 2; -ContactError.PENDING_OPERATION_ERROR = 3; -ContactError.IO_ERROR = 4; -ContactError.NOT_SUPPORTED_ERROR = 5; -ContactError.PERMISSION_DENIED_ERROR = 20; - -module.exports = ContactError;
diff --git a/www/ContactField.js b/www/ContactField.js deleted file mode 100644 index e84107a..0000000 --- a/www/ContactField.js +++ /dev/null
@@ -1,37 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * -*/ - -/** -* Generic contact field. -* @constructor -* @param {DOMString} id unique identifier, should only be set by native code // NOTE: not a W3C standard -* @param type -* @param value -* @param pref -*/ -var ContactField = function(type, value, pref) { - this.id = null; - this.type = (type && type.toString()) || null; - this.value = (value && value.toString()) || null; - this.pref = (typeof pref != 'undefined' ? pref : false); -}; - -module.exports = ContactField;
diff --git a/www/ContactFindOptions.js b/www/ContactFindOptions.js deleted file mode 100644 index bd8bf35..0000000 --- a/www/ContactFindOptions.js +++ /dev/null
@@ -1,34 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * -*/ - -/** - * ContactFindOptions. - * @constructor - * @param filter used to match contacts against - * @param multiple boolean used to determine if more than one contact should be returned - */ - -var ContactFindOptions = function(filter, multiple) { - this.filter = filter || ''; - this.multiple = (typeof multiple != 'undefined' ? multiple : false); -}; - -module.exports = ContactFindOptions;
diff --git a/www/ContactName.js b/www/ContactName.js deleted file mode 100644 index 15cf60b..0000000 --- a/www/ContactName.js +++ /dev/null
@@ -1,41 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * -*/ - -/** -* Contact name. -* @constructor -* @param formatted // NOTE: not part of W3C standard -* @param familyName -* @param givenName -* @param middle -* @param prefix -* @param suffix -*/ -var ContactName = function(formatted, familyName, givenName, middle, prefix, suffix) { - this.formatted = formatted || null; - this.familyName = familyName || null; - this.givenName = givenName || null; - this.middleName = middle || null; - this.honorificPrefix = prefix || null; - this.honorificSuffix = suffix || null; -}; - -module.exports = ContactName;
diff --git a/www/ContactOrganization.js b/www/ContactOrganization.js deleted file mode 100644 index 5dd242b..0000000 --- a/www/ContactOrganization.js +++ /dev/null
@@ -1,44 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * -*/ - -/** -* Contact organization. -* @constructor -* @param {DOMString} id unique identifier, should only be set by native code // NOTE: not a W3C standard -* @param name -* @param dept -* @param title -* @param startDate -* @param endDate -* @param location -* @param desc -*/ - -var ContactOrganization = function(pref, type, name, dept, title) { - this.id = null; - this.pref = (typeof pref != 'undefined' ? pref : false); - this.type = type || null; - this.name = name || null; - this.department = dept || null; - this.title = title || null; -}; - -module.exports = ContactOrganization;
diff --git a/www/contacts.js b/www/contacts.js deleted file mode 100644 index 5e6b4db..0000000 --- a/www/contacts.js +++ /dev/null
@@ -1,76 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * -*/ - -var argscheck = require('cordova/argscheck'), - exec = require('cordova/exec'), - ContactError = require('./ContactError'), - utils = require('cordova/utils'), - Contact = require('./Contact'); - -/** -* Represents a group of Contacts. -* @constructor -*/ -var contacts = { - /** - * Returns an array of Contacts matching the search criteria. - * @param fields that should be searched - * @param successCB success callback - * @param errorCB error callback - * @param {ContactFindOptions} options that can be applied to contact searching - * @return array of Contacts matching search criteria - */ - find:function(fields, successCB, errorCB, options) { - argscheck.checkArgs('afFO', 'contacts.find', arguments); - if (!fields.length) { - errorCB && errorCB(new ContactError(ContactError.INVALID_ARGUMENT_ERROR)); - } else { - var win = function(result) { - var cs = []; - for (var i = 0, l = result.length; i < l; i++) { - cs.push(contacts.create(result[i])); - } - successCB(cs); - }; - exec(win, errorCB, "Contacts", "search", [fields, options]); - } - }, - - /** - * This function creates a new contact, but it does not persist the contact - * to device storage. To persist the contact to device storage, invoke - * contact.save(). - * @param properties an object whose properties will be examined to create a new Contact - * @returns new Contact object - */ - create:function(properties) { - argscheck.checkArgs('O', 'contacts.create', arguments); - var contact = new Contact(); - for (var i in properties) { - if (typeof contact[i] !== 'undefined' && properties.hasOwnProperty(i)) { - contact[i] = properties[i]; - } - } - return contact; - } -}; - -module.exports = contacts;
diff --git a/www/ios/Contact.js b/www/ios/Contact.js deleted file mode 100644 index b40c41a..0000000 --- a/www/ios/Contact.js +++ /dev/null
@@ -1,51 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * -*/ - -var exec = require('cordova/exec'), - ContactError = require('./ContactError'); - -/** - * Provides iOS Contact.display API. - */ -module.exports = { - display : function(errorCB, options) { - /* - * Display a contact using the iOS Contact Picker UI - * NOT part of W3C spec so no official documentation - * - * @param errorCB error callback - * @param options object - * allowsEditing: boolean AS STRING - * "true" to allow editing the contact - * "false" (default) display contact - */ - - if (this.id === null) { - if (typeof errorCB === "function") { - var errorObj = new ContactError(ContactError.UNKNOWN_ERROR); - errorCB(errorObj); - } - } - else { - exec(null, errorCB, "Contacts","displayContact", [this.id, options]); - } - } -};
diff --git a/www/ios/contacts.js b/www/ios/contacts.js deleted file mode 100644 index 67cf421..0000000 --- a/www/ios/contacts.js +++ /dev/null
@@ -1,62 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * -*/ - -var exec = require('cordova/exec'); - -/** - * Provides iOS enhanced contacts API. - */ -module.exports = { - newContactUI : function(successCallback) { - /* - * Create a contact using the iOS Contact Picker UI - * NOT part of W3C spec so no official documentation - * - * returns: the id of the created contact as param to successCallback - */ - exec(successCallback, null, "Contacts","newContact", []); - }, - chooseContact : function(successCallback, options) { - /* - * Select a contact using the iOS Contact Picker UI - * NOT part of W3C spec so no official documentation - * - * @param errorCB error callback - * @param options object - * allowsEditing: boolean AS STRING - * "true" to allow editing the contact - * "false" (default) display contact - * fields: array of fields to return in contact object (see ContactOptions.fields) - * - * @returns - * id of contact selected - * ContactObject - * if no fields provided contact contains just id information - * if fields provided contact object contains information for the specified fields - * - */ - var win = function(result) { - var fullContact = require('./contacts').create(result); - successCallback(fullContact.id, fullContact); - }; - exec(win, null, "Contacts","chooseContact", [options]); - } -};