You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by lo...@apache.org on 2013/05/13 22:34:53 UTC
[1/2] Contacts core plugin
Updated Branches:
refs/heads/future 42b066f65 -> 1890c10c2
http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1890c10c/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/pim_contacts_qt.cpp
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/pim_contacts_qt.cpp b/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/pim_contacts_qt.cpp
new file mode 100644
index 0000000..7c70b48
--- /dev/null
+++ b/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/pim_contacts_qt.cpp
@@ -0,0 +1,1611 @@
+/*
+ * 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.
+ */
+
+#include <json/value.h>
+#include <json/writer.h>
+#include <stdio.h>
+#include <webworks_utils.hpp>
+#include <bb/cascades/pickers/ContactPicker>
+#include <bb/cascades/pickers/ContactSelectionMode>
+#include <QSet>
+#include <QMap>
+#include <QtAlgorithms>
+#include <string>
+#include <sstream>
+#include <map>
+#include <algorithm>
+#include "pim_contacts_qt.hpp"
+
+namespace webworks {
+
+StringToKindMap PimContactsQt::_attributeKindMap;
+StringToSubKindMap PimContactsQt::_attributeSubKindMap;
+KindToStringMap PimContactsQt::_kindAttributeMap;
+SubKindToStringMap PimContactsQt::_subKindAttributeMap;
+QList<bbpim::SortSpecifier> PimContactsQt::_sortSpecs;
+std::map<bbpim::ContactId, bbpim::Contact> PimContactsQt::_contactSearchMap;
+ContactAccount& PimContactsQt::_contactAccount = ContactAccount::GetAccountInstance();
+
+PimContactsQt::PimContactsQt()
+{
+ static bool mapInit = false;
+
+ if (!mapInit) {
+ createAttributeKindMap();
+ createAttributeSubKindMap();
+ createKindAttributeMap();
+ createSubKindAttributeMap();
+ mapInit = true;
+ }
+}
+
+PimContactsQt::~PimContactsQt()
+{
+}
+
+/****************************************************************
+ * Public Functions
+ ****************************************************************/
+
+Json::Value PimContactsQt::Find(const Json::Value& args)
+{
+ Json::Value returnObj;
+
+ if (!args.isMember("fields") || args["fields"].empty() || !args.isMember("options") || args["options"].isNull()) {
+ returnObj["_success"] = false;
+ returnObj["code"] = INVALID_ARGUMENT_ERROR;
+ return returnObj;
+ }
+
+ QSet<bbpim::ContactId> results;
+ int limit = -1;
+ bool favorite = false;
+ Json::Value includeAccounts = args["options"].get("includeAccounts", Json::nullValue);
+ Json::Value excludeAccounts = args["options"].get("excludeAccounts", Json::nullValue);
+
+ if (args["options"].isMember("favorite") && args["options"]["favorite"].isBool()) {
+ favorite = args["options"]["favorite"].asBool();
+ }
+
+ if (args["options"].isMember("limit") && args["options"]["limit"].isInt()) {
+ limit = args["options"]["limit"].asInt();
+ }
+
+ if (args["options"].isMember("filter") && !args["options"]["filter"].empty()) {
+ results = getPartialSearchResults(args["options"]["filter"], args["fields"], favorite, includeAccounts, excludeAccounts);
+
+ getSortSpecs(args["options"]["sort"]);
+
+ returnObj["_success"] = true;
+ returnObj["contacts"] = assembleSearchResults(results, args["fields"], limit);
+ } else {
+ // if no filters specified, use list filters to get all contacts
+ bbpim::ContactService service;
+ bbpim::ContactListFilters listFilters;
+ QList<bbpim::Contact> results;
+ Json::Value contacts;
+
+ getSortSpecs(args["options"]["sort"]);
+ if (!_sortSpecs.empty()) {
+ listFilters.setSortBy(_sortSpecs);
+ }
+
+ listFilters.setIncludeAttributes(getIncludeAttributesList(args["fields"], &listFilters));
+
+ if (favorite) {
+ listFilters.setIsFavourite(favorite);
+ }
+
+ if (limit != -1) {
+ listFilters.setLimit(limit);
+ }
+
+ getAccountFilters(NULL, &listFilters, includeAccounts, excludeAccounts);
+
+ results = service.contacts(listFilters);
+ for (QList<bbpim::Contact>::const_iterator i = results.constBegin(); i != results.constEnd(); i++) {
+ Json::Value contactItem = populateContact(*i, args["fields"]);
+ contacts.append(contactItem);
+ }
+
+ returnObj["_success"] = true;
+ returnObj["contacts"] = contacts;
+ }
+
+ return returnObj;
+}
+
+Json::Value PimContactsQt::Save(const Json::Value& attributeObj)
+{
+ if (!attributeObj.isMember("id") || attributeObj["id"].isNull()) {
+ return CreateContact(attributeObj);
+ } else if (attributeObj.isMember("id") && attributeObj["id"].isInt()) {
+ int contactId = attributeObj["id"].asInt();
+ bbpim::ContactService service;
+
+ if (contactId > 0) {
+ bbpim::Contact contact = service.contactDetails(contactId);
+
+ if (contact.isValid()) {
+ return EditContact(contact, attributeObj);
+ }
+ } else {
+ bbpim::Contact contact = service.contactDetails(contactId * -1);
+
+ if (contact.isValid()) {
+ return CloneContact(contact, attributeObj);
+ }
+ }
+ }
+
+ Json::Value returnObj;
+ returnObj["_success"] = false;
+ returnObj["code"] = INVALID_ARGUMENT_ERROR;
+ return returnObj;
+}
+
+Json::Value PimContactsQt::CreateContact(const Json::Value& attributeObj)
+{
+ const Json::Value::Members attributeKeys = attributeObj.getMemberNames();
+ Json::Value contactFields;
+
+ bbpim::Contact newContact;
+ bbpim::ContactBuilder contactBuilder(newContact.edit());
+
+ for (unsigned int i = 0; i < attributeKeys.size(); i++) {
+ const std::string key = attributeKeys[i];
+ contactFields.append(Json::Value(key));
+ addAttributeKind(contactBuilder, attributeObj[key], key);
+ }
+
+ bbpim::ContactService service;
+ newContact = service.createContact(newContact, attributeObj["isWork"].asBool(), true);
+
+ Json::Value returnObj;
+
+ if (newContact.isValid()) {
+ returnObj = populateContact(newContact, contactFields);
+ returnObj["_success"] = true;
+ } else {
+ returnObj["_success"] = false;
+ returnObj["code"] = UNKNOWN_ERROR;
+ }
+
+ return returnObj;
+}
+
+Json::Value PimContactsQt::DeleteContact(const Json::Value& contactObj)
+{
+ Json::Value returnObj;
+
+ if (contactObj.isMember("contactId") && contactObj["contactId"].isInt()) {
+ bbpim::ContactId contactId = contactObj["contactId"].asInt();
+
+ bbpim::ContactService service;
+ bbpim::Contact contact = service.contactDetails(contactId);
+
+ if (contact.isValid()) {
+ service.deleteContact(contactId);
+ returnObj["_success"] = true;
+ return returnObj;
+ }
+ }
+
+ returnObj["_success"] = false;
+ returnObj["code"] = INVALID_ARGUMENT_ERROR;
+ return returnObj;
+}
+
+Json::Value PimContactsQt::EditContact(bbpim::Contact& contact, const Json::Value& attributeObj)
+{
+ bbpim::ContactBuilder contactBuilder(contact.edit());
+ const Json::Value::Members attributeKeys = attributeObj.getMemberNames();
+ Json::Value contactFields;
+
+ for (unsigned int i = 0; i < attributeKeys.size(); i++) {
+ const std::string key = attributeKeys[i];
+ contactFields.append(Json::Value(key));
+ syncAttributeKind(contact, attributeObj[key], key);
+ }
+
+ bbpim::ContactService service;
+ contact = service.updateContact(contact);
+
+ Json::Value returnObj;
+
+ if (contact.isValid()) {
+ returnObj = populateContact(contact, contactFields);
+ returnObj["_success"] = true;
+ } else {
+ returnObj["_success"] = false;
+ returnObj["code"] = UNKNOWN_ERROR;
+ }
+
+ return returnObj;
+}
+
+Json::Value PimContactsQt::CloneContact(bbpim::Contact& contact, const Json::Value& attributeObj)
+{
+ bbpim::ContactService service;
+ bbpim::Contact newContact;
+ bbpim::ContactBuilder contactBuilder(newContact.edit());
+ contactBuilder = contactBuilder.addFromContact(contact);
+ contactBuilder = contactBuilder.setFavorite(contact.isFavourite());
+
+ const Json::Value::Members attributeKeys = attributeObj.getMemberNames();
+ Json::Value contactFields;
+
+ for (unsigned int i = 0; i < attributeKeys.size(); i++) {
+ const std::string key = attributeKeys[i];
+ contactFields.append(Json::Value(key));
+ syncAttributeKind(newContact, attributeObj[key], key);
+ }
+
+ newContact = service.createContact(newContact, attributeObj["isWork"].asBool(), true);
+
+ Json::Value returnObj;
+
+ if (newContact.isValid()) {
+ returnObj = populateContact(newContact, contactFields);
+ returnObj["_success"] = true;
+ } else {
+ returnObj["_success"] = false;
+ returnObj["code"] = UNKNOWN_ERROR;
+ }
+
+ return returnObj;
+}
+
+Json::Value PimContactsQt::GetContact(const Json::Value& args)
+{
+ Json::Value returnObj;
+ Json::Value fields;
+ bbpim::ContactService contactService;
+ StringToKindMap::const_iterator it;
+ int loop = 0;
+
+ for (it = _attributeKindMap.begin(); it != _attributeKindMap.end(); ++it) {
+ fields[loop] = it->first;
+ loop++;
+ }
+
+ if (args.isMember("contactId")) {
+ bbpim::Contact contact;
+ bbpim::ContactId contactId = Utils::strToInt(args["contactId"].asString());
+
+ if (contactId == -1) {
+ returnObj["_success"] = false;
+ returnObj["code"] = INVALID_ARGUMENT_ERROR;
+ } else {
+ contact = contactService.contactDetails(contactId);
+ returnObj["_success"] = true;
+ if (contact.isValid()) {
+ returnObj["contact"] = populateContact(contact, fields);
+ }
+ }
+ } else {
+ returnObj["_success"] = false;
+ returnObj["code"] = INVALID_ARGUMENT_ERROR;
+ }
+
+ if (returnObj.empty()) {
+ returnObj["_success"] = false;
+ returnObj["code"] = UNKNOWN_ERROR;
+ }
+
+ return returnObj;
+}
+
+Json::Value PimContactsQt::InvokePicker(const Json::Value& args)
+{
+ bb::cascades::pickers::ContactPicker picker;
+ bb::cascades::pickers::ContactSelectionMode::Type mode;
+ QSet<bbpim::AttributeKind::Type> filters;
+ Json::Value result;
+
+ if (args.isMember("mode")) {
+ switch (args["mode"].asInt()) {
+ case bb::cascades::pickers::ContactSelectionMode::Single:
+ mode = bb::cascades::pickers::ContactSelectionMode::Single;
+ break;
+ case bb::cascades::pickers::ContactSelectionMode::Multiple:
+ mode = bb::cascades::pickers::ContactSelectionMode::Multiple;
+ break;
+ case bb::cascades::pickers::ContactSelectionMode::Attribute:
+ mode = bb::cascades::pickers::ContactSelectionMode::Attribute;
+ break;
+ default:
+ result["_success"] = false;
+ result["code"] = INVALID_ARGUMENT_ERROR;
+ return result;
+ }
+
+ picker.setMode(mode);
+
+ if (args.isMember("fields") && !args["fields"].empty()) {
+ std::string fieldName;
+ StringToKindMap::iterator found;
+
+ if (_attributeKindMap.empty()) {
+ createAttributeKindMap();
+ }
+
+ for (unsigned int i = 0; i < args["fields"].size(); i++) {
+ fieldName = args["fields"][i].asString();
+
+ if ((found = _attributeKindMap.find(fieldName)) != _attributeKindMap.end()) {
+ filters << found->second;
+ }
+ }
+
+ picker.setKindFilters(filters);
+ }
+
+ // cannot open picker if mode = attribute unless filters are specified
+ if (mode == bb::cascades::pickers::ContactSelectionMode::Attribute && filters.empty()) {
+ result["_success"] = false;
+ result["code"] = INVALID_ARGUMENT_ERROR;
+ return result;
+ }
+
+ if (args.isMember("title") && args["title"].isString()) {
+ picker.setTitle(QString(args["title"].asCString()));
+ }
+
+ if (args.isMember("confirmButtonLabel") && args["confirmButtonLabel"].isString()) {
+ picker.setConfirmButtonLabel(QString(args["confirmButtonLabel"].asCString()));
+ }
+
+ picker.open();
+
+ result["_success"] = true;
+ return result;
+ }
+
+ result["_success"] = false;
+ result["code"] = INVALID_ARGUMENT_ERROR;
+ return result;
+}
+
+Json::Value PimContactsQt::GetContactAccounts()
+{
+ Json::Value retVal;
+
+ retVal["accounts"] = Json::Value();
+ QList<bb::pim::account::Account> accounts = _contactAccount.GetContactAccounts();
+ for (int i = 0; i < accounts.size(); ++i) {
+ retVal["accounts"].append(ContactAccount::Account2Json(accounts[i]));
+ }
+ retVal["_success"] = true;
+ return retVal;
+}
+
+/****************************************************************
+ * Helper functions for Find
+ ****************************************************************/
+
+QList<bbpim::SearchField::Type> PimContactsQt::getSearchFields(const Json::Value& searchFieldsJson)
+{
+ QList<bbpim::SearchField::Type> searchFields;
+
+ switch (searchFieldsJson["fieldName"].asInt()) {
+ case bbpim::SearchField::FirstName:
+ searchFields.append(bbpim::SearchField::FirstName);
+ break;
+ case bbpim::SearchField::LastName:
+ searchFields.append(bbpim::SearchField::LastName);
+ break;
+ case bbpim::SearchField::CompanyName:
+ searchFields.append(bbpim::SearchField::CompanyName);
+ break;
+ case bbpim::SearchField::Phone:
+ searchFields.append(bbpim::SearchField::Phone);
+ break;
+ case bbpim::SearchField::Email:
+ searchFields.append(bbpim::SearchField::Email);
+ break;
+ case bbpim::SearchField::BBMPin:
+ searchFields.append(bbpim::SearchField::BBMPin);
+ break;
+ case bbpim::SearchField::LinkedIn:
+ searchFields.append(bbpim::SearchField::LinkedIn);
+ break;
+ case bbpim::SearchField::Twitter:
+ searchFields.append(bbpim::SearchField::Twitter);
+ break;
+ case bbpim::SearchField::VideoChat:
+ searchFields.append(bbpim::SearchField::VideoChat);
+ break;
+ }
+
+ return searchFields;
+}
+
+void PimContactsQt::getSortSpecs(const Json::Value& sort)
+{
+ _sortSpecs.clear();
+
+ if (sort.isArray()) {
+ for (unsigned int j = 0; j < sort.size(); j++) {
+ bbpim::SortOrder::Type order;
+ bbpim::SortColumn::Type sortField = bbpim::SortColumn::LastName;
+
+ if (sort[j]["desc"].asBool()) {
+ order = bbpim::SortOrder::Descending;
+ } else {
+ order = bbpim::SortOrder::Ascending;
+ }
+
+ switch (sort[j]["fieldName"].asInt()) {
+ case bbpim::SortColumn::FirstName:
+ sortField = bbpim::SortColumn::FirstName;
+ break;
+ case bbpim::SortColumn::LastName:
+ sortField = bbpim::SortColumn::LastName;
+ break;
+ case bbpim::SortColumn::CompanyName:
+ sortField = bbpim::SortColumn::CompanyName;
+ break;
+ }
+
+ _sortSpecs.append(bbpim::SortSpecifier(sortField, order));
+ }
+ }
+}
+
+QSet<bbpim::ContactId> PimContactsQt::getPartialSearchResults(const Json::Value& filter, const Json::Value& contactFields, const bool favorite, const Json::Value& includeAccounts, const Json::Value& excludeAccounts)
+{
+ QSet<bbpim::ContactId> results;
+
+ _contactSearchMap.clear();
+
+ if (!filter.empty()) {
+ for (unsigned int j = 0; j < filter.size(); j++) {
+ QSet<bbpim::ContactId> currentResults = singleFieldSearch(filter[j], contactFields, favorite, includeAccounts, excludeAccounts);
+
+ if (currentResults.empty()) {
+ // no need to continue, can return right away
+ results = currentResults;
+ break;
+ } else {
+ if (j == 0) {
+ results = currentResults;
+ } else {
+ results.intersect(currentResults);
+ }
+ }
+ }
+ }
+
+ return results;
+}
+
+void PimContactsQt::getAccountFilters(bbpim::ContactSearchFilters* searchFilter, bbpim::ContactListFilters* listFilter, const Json::Value& includeAccounts, const Json::Value& excludeAccounts)
+{
+ if (!includeAccounts.empty() && includeAccounts.isArray()) {
+ QList<bbpim::AccountId> accountIds;
+
+ for (unsigned int i = 0; i < includeAccounts.size(); i++) {
+ accountIds << Utils::strToInt(includeAccounts[i].asString());
+ }
+
+ if (searchFilter != NULL) {
+ searchFilter->setHasAccounts(accountIds);
+ }
+
+ if (listFilter != NULL) {
+ listFilter->setHasAccounts(accountIds);
+ }
+ }
+
+ if (!excludeAccounts.empty() && excludeAccounts.isArray()) {
+ QList<bbpim::AccountId> accountIds;
+
+ for (unsigned int i = 0; i < excludeAccounts.size(); i++) {
+ accountIds << Utils::strToInt(excludeAccounts[i].asString());
+ }
+
+ if (searchFilter != NULL) {
+ searchFilter->setExcludeAccounts(accountIds);
+ }
+
+ if (listFilter != NULL) {
+ listFilter->setExcludeAccounts(accountIds);
+ }
+ }
+}
+
+QList<bbpim::AttributeKind::Type> PimContactsQt::getIncludeAttributesList(const Json::Value& contactFields, bbpim::ContactListFilters* listFilters)
+{
+ QList<bbpim::AttributeKind::Type> includeFields;
+
+ for (unsigned int i = 0; i < contactFields.size(); i++) {
+ // favorite is always included, no need to include
+ if (contactFields[i].asString() == "favorite") {
+ continue;
+ }
+
+ StringToKindMap::const_iterator kindIter = _attributeKindMap.find(contactFields[i].asString());
+
+ if (kindIter != _attributeKindMap.end()) {
+ // multiple fields can map to the same kind, only add kind to the list if it's not already added
+ if (includeFields.count(kindIter->second) == 0) {
+ includeFields.append(kindIter->second);
+ }
+ } else if (contactFields[i].asString() == "displayName" || contactFields[i].asString() == "nickname") {
+ // special case: displayName and nickname are first-level fields under Contact but only map to AttributeSubKind
+ if (includeFields.count(bbpim::AttributeKind::Name) == 0) {
+ includeFields.append(bbpim::AttributeKind::Name);
+ }
+ } else if (contactFields[i].asString() == "addresses") {
+ if (listFilters != NULL) {
+ listFilters->setIncludePostalAddress(true);
+ }
+ } else if (contactFields[i].asString() == "photos") {
+ if (listFilters != NULL) {
+ listFilters->setIncludePhotos(true);
+ }
+ }
+ }
+
+ return includeFields;
+}
+
+QSet<bbpim::ContactId> PimContactsQt::singleFieldSearch(const Json::Value& searchFieldsJson, const Json::Value& contactFields, const bool favorite, const Json::Value& includeAccounts, const Json::Value& excludeAccounts)
+{
+ QList<bbpim::SearchField::Type> searchFields = PimContactsQt::getSearchFields(searchFieldsJson);
+ QSet<bbpim::ContactId> contactIds;
+
+ if (!searchFields.empty()) {
+ bbpim::ContactService contactService;
+ bbpim::ContactSearchFilters contactFilter;
+ QList<bbpim::Contact> results;
+
+ contactFilter.setSearchFields(searchFields);
+ contactFilter.setSearchValue(QString(searchFieldsJson["fieldValue"].asString().c_str()));
+
+ if (favorite) {
+ contactFilter.setIsFavourite(favorite);
+ }
+
+ contactFilter.setShowAttributes(true);
+ contactFilter.setIncludeAttributes(getIncludeAttributesList(contactFields));
+
+ getAccountFilters(&contactFilter, NULL, includeAccounts, excludeAccounts);
+
+ results = contactService.searchContacts(contactFilter);
+
+ for (int i = 0; i < results.size(); i++) {
+ contactIds.insert(results[i].id());
+ _contactSearchMap[results[i].id()] = results[i];
+ }
+ }
+
+ return contactIds;
+}
+
+QString PimContactsQt::getSortFieldValue(const bbpim::SortColumn::Type sort_field, const bbpim::Contact& contact)
+{
+ switch (sort_field) {
+ case bbpim::SortColumn::FirstName:
+ return contact.sortFirstName();
+ case bbpim::SortColumn::LastName:
+ return contact.sortLastName();
+ case bbpim::SortColumn::CompanyName:
+ return contact.sortCompanyName();
+ }
+
+ return QString();
+}
+
+bool PimContactsQt::lessThan(const bbpim::Contact& c1, const bbpim::Contact& c2)
+{
+ QList<bbpim::SortSpecifier>::const_iterator i = PimContactsQt::_sortSpecs.constBegin();
+ bbpim::SortSpecifier sortSpec;
+ QString val1, val2;
+
+ do {
+ sortSpec = *i;
+ val1 = PimContactsQt::getSortFieldValue(sortSpec.first, c1);
+ val2 = PimContactsQt::getSortFieldValue(sortSpec.first, c2);
+ ++i;
+ } while (val1 == val2 && i != PimContactsQt::_sortSpecs.constEnd());
+
+ if (sortSpec.second == bbpim::SortOrder::Ascending) {
+ return val1 < val2;
+ } else {
+ return !(val1 < val2);
+ }
+}
+
+Json::Value PimContactsQt::assembleSearchResults(const QSet<bbpim::ContactId>& resultIds, const Json::Value& contactFields, int limit)
+{
+ QMap<bbpim::ContactId, bbpim::Contact> completeResults;
+
+ // put complete contacts in map
+ for (QSet<bbpim::ContactId>::const_iterator i = resultIds.constBegin(); i != resultIds.constEnd(); i++) {
+ completeResults.insertMulti(*i, _contactSearchMap[*i]);
+ }
+
+ // sort results based on sort specs
+ QList<bbpim::Contact> sortedResults = completeResults.values();
+ if (!_sortSpecs.empty()) {
+ qSort(sortedResults.begin(), sortedResults.end(), lessThan);
+ }
+
+ Json::Value contactArray;
+
+ // if limit is -1, returned all available results, otherwise return based on the number passed in find options
+ if (limit == -1) {
+ limit = sortedResults.size();
+ } else {
+ limit = std::min(limit, sortedResults.size());
+ }
+
+ for (int i = 0; i < limit; i++) {
+ Json::Value contactItem = populateContact(sortedResults[i], contactFields);
+ contactArray.append(contactItem);
+ }
+
+ return contactArray;
+}
+
+std::string PimContactsQt::replaceAll(const std::string& s, const std::string& souce, const std::string& target) {
+ size_t start = 0;
+ std::string temp(s);
+ while ((start = temp.find(souce, start)) != std::string::npos) {
+ temp.replace(start, souce.length(), target);
+ start += target.length();
+ }
+ return temp;
+}
+std::string PimContactsQt::replaceString(const std::string& s) {
+ std::string temp = replaceAll(replaceAll(replaceAll(replaceAll(s), "\n", "\\\\n"), "\r", ""), "\t", "\\\\t");
+ return temp;
+}
+
+/****************************************************************
+ * Helper functions shared by Find and Save
+ ****************************************************************/
+
+Json::Value PimContactsQt::populateContact(const bbpim::Contact& contact, const Json::Value& contactFields)
+{
+ Json::Value contactItem;
+
+ for (unsigned int i = 0; i < contactFields.size(); i++) {
+ std::string field = contactFields[i].asString();
+ StringToKindMap::const_iterator kindIter = _attributeKindMap.find(field);
+
+ if (kindIter != _attributeKindMap.end()) {
+ switch (kindIter->second) {
+ case bbpim::AttributeKind::Name: {
+ contactItem[field] = Json::Value();
+ populateField(contact, kindIter->second, contactItem[field], false, false);
+ break;
+ }
+
+ case bbpim::AttributeKind::OrganizationAffiliation: {
+ contactItem[field] = Json::Value();
+ populateOrganizations(contact, contactItem[field]);
+ break;
+ }
+
+ case bbpim::AttributeKind::Date:
+ case bbpim::AttributeKind::Note:
+ case bbpim::AttributeKind::Sound: {
+ populateField(contact, kindIter->second, contactItem, false, false);
+ break;
+ }
+
+ case bbpim::AttributeKind::VideoChat: {
+ contactItem[field] = Json::Value();
+ populateField(contact, kindIter->second, contactItem[field], false, true);
+ break;
+ }
+
+ case bbpim::AttributeKind::Email:
+ case bbpim::AttributeKind::Fax:
+ case bbpim::AttributeKind::Pager:
+ case bbpim::AttributeKind::Phone:
+ case bbpim::AttributeKind::Profile:
+ case bbpim::AttributeKind::Website:
+ case bbpim::AttributeKind::InstantMessaging: {
+ contactItem[field] = Json::Value();
+ populateField(contact, kindIter->second, contactItem[field], true, false);
+ break;
+ }
+
+ // Special cases (treated differently in ContactBuilder):
+ default: {
+ if (field == "addresses") {
+ contactItem[field] = Json::Value();
+ populateAddresses(contact, contactItem[field]);
+ } else if (field == "photos") {
+ contactItem[field] = Json::Value();
+ populatePhotos(contact, contactItem[field]);
+ } else if (field == "news") {
+ contactItem[field] = Json::Value();
+ populateNews(contact, contactItem[field]);
+ } else if (field == "activities") {
+ contactItem[field] = Json::Value();
+ populateActivity(contact, contactItem[field]);
+ }
+
+ break;
+ }
+ }
+ } else {
+ if (field == "displayName" || field == "nickname") {
+ populateDisplayNameNickName(contact, contactItem, field);
+ }
+ }
+ }
+
+ contactItem["sourceAccounts"] = Json::Value();
+ // fetch sourceAccounts by sourceSourceIds
+ for (int i = 0; i < contact.sourceAccountIds().size(); ++i) {
+ bb::pim::account::AccountKey id = contact.sourceAccountIds()[i];
+ bb::pim::account::Account account = _contactAccount.GetAccount(id);
+ contactItem["sourceAccounts"].append(ContactAccount::Account2Json(account));
+ }
+
+ contactItem["id"] = Utils::intToStr(contact.id());
+ contactItem["favorite"] = Json::Value(contact.isFavourite()); // always populate favorite
+
+ return contactItem;
+}
+
+void PimContactsQt::populateField(const bbpim::Contact& contact, bbpim::AttributeKind::Type kind, Json::Value& contactItem, bool isContactField, bool isArray)
+{
+ QList<bbpim::ContactAttribute> attrs = contact.filteredAttributes(kind);
+
+ for (int i = 0; i < attrs.size(); i++) {
+ bbpim::ContactAttribute currentAttr = attrs[i];
+
+ // displayName and nickname are populated separately, do not populate within the name object
+ if (currentAttr.subKind() == bbpim::AttributeSubKind::NameDisplayName || currentAttr.subKind() == bbpim::AttributeSubKind::NameNickname) {
+ continue;
+ }
+
+ Json::Value val;
+ SubKindToStringMap::const_iterator typeIter = _subKindAttributeMap.find(currentAttr.subKind());
+
+ if (typeIter != _subKindAttributeMap.end()) {
+ if (isContactField) {
+ val["type"] = Json::Value(typeIter->second);
+
+ std::string value = currentAttr.value().toStdString();
+ value = replaceString(value);
+
+ val["value"] = Json::Value(value);
+ contactItem.append(val);
+ } else {
+ if (isArray) {
+ std::string value = currentAttr.value().toStdString();
+ value = replaceString(value);
+
+ val = Json::Value(value);
+ contactItem.append(val);
+ } else {
+ if (kind == bbpim::AttributeKind::Date) {
+ QString format = "yyyy-MM-dd";
+ contactItem[typeIter->second] = Json::Value(currentAttr.valueAsDateTime().date().toString(format).toStdString());
+ } else {
+ contactItem[typeIter->second] = Json::Value(currentAttr.value().toStdString());
+ }
+ }
+ }
+ } else if (kind == bbpim::AttributeKind::Note) {
+ std::string note = currentAttr.value().toStdString();
+ note = replaceString(note);
+ contactItem["note"] = Json::Value(note);
+ break;
+ }
+ }
+}
+
+void PimContactsQt::populateDisplayNameNickName(const bbpim::Contact& contact, Json::Value& contactItem, const std::string& field)
+{
+ QList<QList<bbpim::ContactAttribute> > nameGroups = contact.filteredAttributesByGroupKey(bbpim::AttributeKind::Name);
+ bbpim::AttributeSubKind::Type subkind = (field == "displayName" ? bbpim::AttributeSubKind::NameDisplayName : bbpim::AttributeSubKind::NameNickname);
+
+ if (!nameGroups.empty()) {
+ QList<bbpim::ContactAttribute> nameAttrs = nameGroups[0];
+
+ for (int i = 0; i < nameAttrs.size(); i++) {
+ bbpim::ContactAttribute currentAttr = nameAttrs[i];
+
+ if (currentAttr.subKind() == subkind) {
+ std::string value = currentAttr.value().toStdString();
+ value = replaceString(value);
+ contactItem[field] = Json::Value(value);
+ break;
+ }
+ }
+ }
+}
+
+void PimContactsQt::populateAddresses(const bbpim::Contact& contact, Json::Value& contactAddrs)
+{
+ bbpim::ContactService contactService;
+ bbpim::Contact fullContact = contactService.contactDetails(contact.id());
+ QList<bbpim::ContactPostalAddress> addrs = fullContact.postalAddresses();
+
+ for (int i = 0; i < addrs.size(); i++) {
+ bbpim::ContactPostalAddress currentAddr = addrs[i];
+ Json::Value addr;
+
+ SubKindToStringMap::const_iterator typeIter = _subKindAttributeMap.find(currentAddr.subKind());
+
+ if (typeIter != _subKindAttributeMap.end()) {
+ addr["type"] = Json::Value(typeIter->second);
+ }
+
+ addr["streetAddress"] = Json::Value(currentAddr.line1().toStdString());
+ addr["streetOther"] = Json::Value(currentAddr.line2().toStdString());
+ addr["country"] = Json::Value(currentAddr.country().toStdString());
+ addr["locality"] = Json::Value(currentAddr.city().toStdString());
+ addr["postalCode"] = Json::Value(currentAddr.postalCode().toStdString());
+ addr["region"] = Json::Value(currentAddr.region().toStdString());
+
+ contactAddrs.append(addr);
+ }
+}
+
+void PimContactsQt::populateOrganizations(const bbpim::Contact& contact, Json::Value& contactOrgs)
+{
+ QList<QList<bbpim::ContactAttribute> > orgAttrs = contact.filteredAttributesByGroupKey(bbpim::AttributeKind::OrganizationAffiliation);
+
+ for (int i = 0; i < orgAttrs.size(); i++) {
+ QList<bbpim::ContactAttribute> currentOrgAttrs = orgAttrs[i];
+ Json::Value org;
+
+ for (int j = 0; j < currentOrgAttrs.size(); j++) {
+ bbpim::ContactAttribute attr = currentOrgAttrs[j];
+ SubKindToStringMap::const_iterator typeIter = _subKindAttributeMap.find(attr.subKind());
+
+ if (typeIter != _subKindAttributeMap.end()) {
+ std::string value = attr.value().toStdString();
+ value = replaceString(value);
+ org[typeIter->second] = Json::Value(value);
+ }
+ }
+
+ contactOrgs.append(org);
+ }
+}
+
+void PimContactsQt::populatePhotos(const bbpim::Contact& contact, Json::Value& contactPhotos)
+{
+ bbpim::ContactService contactService;
+ bbpim::Contact fullContact = contactService.contactDetails(contact.id());
+ QList<bbpim::ContactPhoto> photos = fullContact.photos();
+ bbpim::ContactPhoto primaryPhoto = fullContact.primaryPhoto();
+
+ for (int i = 0; i < photos.size(); i++) {
+ bbpim::ContactPhoto currentPhoto = photos[i];
+ Json::Value photo;
+
+ photo["originalFilePath"] = Json::Value(currentPhoto.originalPhoto().toStdString());
+ photo["largeFilePath"] = Json::Value(currentPhoto.largePhoto().toStdString());
+ photo["smallFilePath"] = Json::Value(currentPhoto.smallPhoto().toStdString());
+ photo["pref"] = Json::Value((primaryPhoto.id() == currentPhoto.id()));
+
+ contactPhotos.append(photo);
+ }
+}
+
+void PimContactsQt::populateNews(const bbpim::Contact& contact, Json::Value& contactNews)
+{
+ QList<bbpim::ContactNews> newsList = contact.news(5);
+ QList<bbpim::ContactNews>::const_iterator k = newsList.constBegin();
+
+ while (k != newsList.constEnd()) {
+ Json::Value news;
+ Json::Value companies;
+ QString format = "yyyy-MM-dd";
+
+ std::string body = k->body().toStdString();
+ body = replaceString(body);
+ news["body"] = Json::Value(body);
+
+ std::string title = k->title().toStdString();
+ title = replaceString(title);
+ news["title"] = Json::Value(title);
+
+ std::string articleSource = k->articleSource().toStdString();
+ articleSource = replaceString(articleSource);
+ news["articleSource"] = Json::Value(articleSource);
+
+ news["type"] = Json::Value(k->type().toStdString());
+ news["publishedAt"] = Json::Value(QString::number(k->publishedAt().toUTC().toMSecsSinceEpoch()).toStdString());
+ news["uri"] = Json::Value(k->uri().toString().toStdString());
+
+ QStringList companiesList = k->companies();
+ QStringList::const_iterator j = companiesList.constBegin();
+
+ while (j != companiesList.constEnd()) {
+ companies.append(j->toStdString());
+ ++j;
+ }
+
+ news["companies"] = companies;
+
+ contactNews.append(news);
+ ++k;
+ }
+}
+
+void PimContactsQt::populateActivity(const bbpim::Contact& contact, Json::Value& contactActivity)
+{
+ QList<bbpim::ContactActivity> activities = contact.activities();
+ QList<bbpim::ContactActivity>::const_iterator k = activities.constBegin();
+
+ while (k != activities.constEnd()) {
+ Json::Value activity;
+
+ std::string desc = k->description().toStdString();
+ desc = replaceString(desc);
+
+ activity["description"] = Json::Value(desc);
+ activity["direction"] = Json::Value(k->direction());
+ activity["mimeType"] = Json::Value(k->mimeType().toStdString());
+ activity["timestamp"] = Json::Value(QString::number(k->statusTimeStamp().toUTC().toMSecsSinceEpoch()).toStdString());
+
+ contactActivity.append(activity);
+ ++k;
+ }
+}
+
+/****************************************************************
+ * Helper functions for Save
+ ****************************************************************/
+
+void PimContactsQt::addAttributeKind(bbpim::ContactBuilder& contactBuilder, const Json::Value& jsonObj, const std::string& field)
+{
+ StringToKindMap::const_iterator kindIter = _attributeKindMap.find(field);
+
+ if (kindIter != _attributeKindMap.end()) {
+ switch (kindIter->second) {
+ // Attributes requiring group keys:
+ case bbpim::AttributeKind::Name: {
+ QList<SubkindValuePair> convertedList = convertGroupedAttributes(jsonObj);
+ addConvertedList(contactBuilder, kindIter->second, convertedList, "1");
+ break;
+ }
+ case bbpim::AttributeKind::OrganizationAffiliation: {
+ for (unsigned int i = 0; i < jsonObj.size(); i++) {
+ std::stringstream groupKeyStream;
+ groupKeyStream << i + 1;
+
+ QList<SubkindValuePair> convertedList = convertGroupedAttributes(jsonObj[i]);
+ addConvertedList(contactBuilder, kindIter->second, convertedList, groupKeyStream.str());
+ }
+
+ break;
+ }
+
+ // String arrays:
+ case bbpim::AttributeKind::VideoChat: {
+ QList<SubkindValuePair> convertedList = convertStringArray(jsonObj, bbpim::AttributeSubKind::VideoChatBbPlaybook);
+ addConvertedList(contactBuilder, kindIter->second, convertedList);
+ break;
+ }
+
+ // Dates:
+ case bbpim::AttributeKind::Date: {
+ StringToSubKindMap::const_iterator subkindIter = _attributeSubKindMap.find(field);
+
+ if (subkindIter != _attributeSubKindMap.end()) {
+ std::string value = jsonObj.asString();
+ addAttribute(contactBuilder, kindIter->second, subkindIter->second, value);
+ }
+
+ break;
+ }
+
+ // Strings:
+ case bbpim::AttributeKind::Note:
+ case bbpim::AttributeKind::Sound: {
+ StringToSubKindMap::const_iterator subkindIter = _attributeSubKindMap.find(field);
+
+ if (subkindIter != _attributeSubKindMap.end()) {
+ QList<SubkindValuePair> convertedList;
+ std::string value = jsonObj.asString();
+ convertedList.append(SubkindValuePair(subkindIter->second, value));
+ addConvertedList(contactBuilder, kindIter->second, convertedList);
+ }
+
+ break;
+ }
+
+ // ContactField attributes:
+ case bbpim::AttributeKind::Phone:
+ case bbpim::AttributeKind::Email:
+ case bbpim::AttributeKind::Fax:
+ case bbpim::AttributeKind::Pager:
+ case bbpim::AttributeKind::InstantMessaging:
+ case bbpim::AttributeKind::Website:
+ case bbpim::AttributeKind::Group:
+ case bbpim::AttributeKind::Profile: {
+ QList<SubkindValuePair> convertedList = convertFieldAttributes(jsonObj);
+ addConvertedList(contactBuilder, kindIter->second, convertedList);
+ break;
+ }
+
+ // Special cases (treated differently in ContactBuilder):
+ default: {
+ if (field == "addresses") {
+ for (unsigned int i = 0; i < jsonObj.size(); i++) {
+ Json::Value addressObj = jsonObj[i];
+ addPostalAddress(contactBuilder, addressObj);
+ }
+ } else if (field == "photos") {
+ for (unsigned int i = 0; i < jsonObj.size(); i++) {
+ Json::Value photoObj = jsonObj[i];
+ addPhoto(contactBuilder, photoObj);
+ }
+ } else if (field == "favorite") {
+ bool isFavorite = jsonObj.asBool();
+ contactBuilder = contactBuilder.setFavorite(isFavorite);
+ }
+
+ break;
+ }
+ }
+ } else if (field == "displayName" || field == "nickname") {
+ StringToSubKindMap::const_iterator subkindIter = _attributeSubKindMap.find(field);
+
+ if (subkindIter != _attributeSubKindMap.end()) {
+ addAttribute(contactBuilder, bbpim::AttributeKind::Name, subkindIter->second, jsonObj.asString(), "1");
+ }
+ }
+}
+
+void PimContactsQt::syncAttributeKind(bbpim::Contact& contact, const Json::Value& jsonObj, const std::string& field)
+{
+ StringToKindMap::const_iterator kindIter = _attributeKindMap.find(field);
+ bbpim::ContactBuilder contactBuilder(contact.edit());
+
+ if (kindIter != _attributeKindMap.end()) {
+ switch (kindIter->second) {
+ // Attributes requiring group keys:
+ case bbpim::AttributeKind::Name: {
+ QList<QList<bbpim::ContactAttribute> > savedList = contact.filteredAttributesByGroupKey(kindIter->second);
+ QList<SubkindValuePair> convertedList = convertGroupedAttributes(jsonObj);
+
+ if (!savedList.empty()) {
+ syncConvertedList(contactBuilder, kindIter->second, savedList[0], convertedList, "1");
+ } else {
+ addConvertedList(contactBuilder, kindIter->second, convertedList, "1");
+ }
+
+ break;
+ }
+ case bbpim::AttributeKind::OrganizationAffiliation: {
+ QList<QList<bbpim::ContactAttribute> > savedList = contact.filteredAttributesByGroupKey(kindIter->second);
+ syncAttributeGroup(contactBuilder, kindIter->second, savedList, jsonObj);
+ break;
+ }
+
+ // String arrays:
+ case bbpim::AttributeKind::VideoChat: {
+ QList<bbpim::ContactAttribute> savedList = contact.filteredAttributes(kindIter->second);
+ QList<SubkindValuePair> convertedList = convertStringArray(jsonObj, bbpim::AttributeSubKind::VideoChatBbPlaybook);
+ syncConvertedList(contactBuilder, kindIter->second, savedList, convertedList);
+ break;
+ }
+
+ // Dates:
+ case bbpim::AttributeKind::Date: {
+ StringToSubKindMap::const_iterator subkindIter = _attributeSubKindMap.find(field);
+
+ if (subkindIter != _attributeSubKindMap.end()) {
+ QList<bbpim::ContactAttribute> savedList = contact.filteredAttributes(kindIter->second);
+ syncAttribute(contactBuilder, savedList, kindIter->second, subkindIter->second, jsonObj.asString());
+ }
+
+ break;
+ }
+
+ // Strings:
+ case bbpim::AttributeKind::Note:
+ case bbpim::AttributeKind::Sound: {
+ QList<bbpim::ContactAttribute> savedList = contact.filteredAttributes(kindIter->second);
+ QList<SubkindValuePair> convertedList;
+ StringToSubKindMap::const_iterator subkindIter = _attributeSubKindMap.find(field);
+
+ if (subkindIter != _attributeSubKindMap.end()) {
+ std::string value = jsonObj.asString();
+ convertedList.append(SubkindValuePair(subkindIter->second, value));
+ }
+
+ syncConvertedList(contactBuilder, kindIter->second, savedList, convertedList);
+ break;
+ }
+
+ // ContactField attributes:
+ case bbpim::AttributeKind::Phone:
+ case bbpim::AttributeKind::Email:
+ case bbpim::AttributeKind::Fax:
+ case bbpim::AttributeKind::Pager:
+ case bbpim::AttributeKind::InstantMessaging:
+ case bbpim::AttributeKind::Website:
+ case bbpim::AttributeKind::Group:
+ case bbpim::AttributeKind::Profile: {
+ QList<bbpim::ContactAttribute> savedList = contact.filteredAttributes(kindIter->second);
+ QList<SubkindValuePair> convertedList = convertFieldAttributes(jsonObj);
+ syncConvertedList(contactBuilder, kindIter->second, savedList, convertedList);
+ break;
+ }
+
+ // Special cases (treated differently in ContactBuilder):
+ default: {
+ if (field == "addresses") {
+ QList<bbpim::ContactPostalAddress> savedList = contact.postalAddresses();
+ syncPostalAddresses(contactBuilder, savedList, jsonObj);
+ } else if (field == "photos") {
+ QList<bbpim::ContactPhoto> savedList = contact.photos();
+ syncPhotos(contactBuilder, savedList, jsonObj, contact.primaryPhoto());
+
+ } else if (field == "favorite") {
+ bool isFavorite = jsonObj.asBool();
+ contactBuilder.setFavorite(isFavorite);
+ }
+
+ break;
+ }
+ }
+ } else if (field == "displayName" || field == "nickname") {
+ StringToSubKindMap::const_iterator subkindIter = _attributeSubKindMap.find(field);
+
+ if (subkindIter != _attributeSubKindMap.end()) {
+ QList<QList<bbpim::ContactAttribute> > savedList = contact.filteredAttributesByGroupKey(bbpim::AttributeKind::Name);
+
+ if (!savedList.empty()) {
+ syncAttribute(contactBuilder, savedList[0], bbpim::AttributeKind::Name, subkindIter->second, jsonObj.asString(), "1");
+ } else {
+ addAttribute(contactBuilder, bbpim::AttributeKind::Name, subkindIter->second, jsonObj.asString(), "1");
+ }
+ }
+ }
+}
+
+
+QList<SubkindValuePair> PimContactsQt::convertGroupedAttributes(const Json::Value& fieldsObj)
+{
+ const Json::Value::Members fields = fieldsObj.getMemberNames();
+ QList<SubkindValuePair> convertedList;
+
+ for (unsigned int i = 0; i < fields.size(); i++) {
+ const std::string fieldKey = fields[i];
+ StringToSubKindMap::const_iterator subkindIter = _attributeSubKindMap.find(fieldKey);
+
+ if (subkindIter != _attributeSubKindMap.end()) {
+ convertedList.append(SubkindValuePair(subkindIter->second, fieldsObj[fieldKey].asString()));
+ }
+ }
+
+ return convertedList;
+}
+
+QList<SubkindValuePair> PimContactsQt::convertFieldAttributes(const Json::Value& fieldArray)
+{
+ QList<SubkindValuePair> convertedList;
+
+ for (unsigned int i = 0; i < fieldArray.size(); i++) {
+ Json::Value fieldObj = fieldArray[i];
+ std::string type = fieldObj.get("type", "").asString();
+ std::string value = fieldObj.get("value", "").asString();
+ StringToSubKindMap::const_iterator subkindIter = _attributeSubKindMap.find(type);
+
+ if (subkindIter != _attributeSubKindMap.end()) {
+ convertedList.append(SubkindValuePair(subkindIter->second, value));
+ }
+ }
+
+ return convertedList;
+}
+
+QList<SubkindValuePair> PimContactsQt::convertStringArray(const Json::Value& stringArray, bbpim::AttributeSubKind::Type subkind)
+{
+ QList<SubkindValuePair> convertedList;
+
+ for (unsigned int i = 0; i < stringArray.size(); i++) {
+ std::string value = stringArray[i].asString();
+ convertedList.append(SubkindValuePair(subkind, value));
+ }
+
+ return convertedList;
+}
+
+void PimContactsQt::addConvertedList(bbpim::ContactBuilder& contactBuilder, const bbpim::AttributeKind::Type kind, const QList<SubkindValuePair>& convertedList, const std::string& groupKey)
+{
+ for (int i = 0; i < convertedList.size(); i++) {
+ addAttribute(contactBuilder, kind, convertedList[i].first, convertedList[i].second, groupKey);
+ }
+}
+
+void PimContactsQt::addAttribute(bbpim::ContactBuilder& contactBuilder, const bbpim::AttributeKind::Type kind, const bbpim::AttributeSubKind::Type subkind, const std::string& value, const std::string& groupKey)
+{
+ bbpim::ContactAttribute attribute;
+ bbpim::ContactAttributeBuilder attributeBuilder(attribute.edit());
+
+ attributeBuilder = attributeBuilder.setKind(kind);
+ attributeBuilder = attributeBuilder.setSubKind(subkind);
+
+ if (kind == bbpim::AttributeKind::Date) {
+ QDateTime date = QDateTime::fromString(QString(value.c_str()), QString("ddd MMM dd yyyy"));
+
+ if (date.isValid()) {
+ attributeBuilder = attributeBuilder.setValue(date);
+ } else {
+ attributeBuilder = attributeBuilder.setValue(QString(value.c_str()));
+ }
+ } else {
+ attributeBuilder = attributeBuilder.setValue(QString(value.c_str()));
+ }
+
+ if (!groupKey.empty()) {
+ attributeBuilder = attributeBuilder.setGroupKey(QString(groupKey.c_str()));
+ }
+
+ contactBuilder.addAttribute(attribute);
+}
+
+void PimContactsQt::addPostalAddress(bbpim::ContactBuilder& contactBuilder, const Json::Value& addressObj)
+{
+ bbpim::ContactPostalAddress address;
+ bbpim::ContactPostalAddressBuilder addressBuilder(address.edit());
+
+ if (addressObj.isMember("type")) {
+ std::string value = addressObj["type"].asString();
+ StringToSubKindMap::const_iterator subkindIter = _attributeSubKindMap.find(value);
+
+ if (subkindIter != _attributeSubKindMap.end()) {
+ addressBuilder = addressBuilder.setSubKind(subkindIter->second);
+ }
+ }
+
+ addressBuilder = addressBuilder.setLine1(QString(addressObj.get("streetAddress", "").asCString()));
+ addressBuilder = addressBuilder.setLine2(QString(addressObj.get("streetOther", "").asCString()));
+ addressBuilder = addressBuilder.setCity(QString(addressObj.get("locality", "").asCString()));
+ addressBuilder = addressBuilder.setRegion(QString(addressObj.get("region", "").asCString()));
+ addressBuilder = addressBuilder.setCountry(QString(addressObj.get("country", "").asCString()));
+ addressBuilder = addressBuilder.setPostalCode(QString(addressObj.get("postalCode", "").asCString()));
+
+ contactBuilder = contactBuilder.addPostalAddress(address);
+}
+
+void PimContactsQt::addPhoto(bbpim::ContactBuilder& contactBuilder, const Json::Value& photoObj)
+{
+ bbpim::ContactPhoto photo;
+ bbpim::ContactPhotoBuilder photoBuilder(photo.edit());
+
+ std::string filepath = photoObj.get("originalFilePath", "").asString();
+ bool pref = photoObj.get("pref", false).asBool();
+
+ photoBuilder.setOriginalPhoto(QString(filepath.c_str()));
+ photoBuilder.setPrimaryPhoto(pref);
+
+ contactBuilder = contactBuilder.addPhoto(photo, pref);
+}
+
+void PimContactsQt::syncConvertedList(bbpim::ContactBuilder& contactBuilder, bbpim::AttributeKind::Type kind, QList<bbpim::ContactAttribute>& savedList, const QList<SubkindValuePair>& convertedList, const std::string& groupKey)
+{
+ int index;
+
+ for (index = 0; index < savedList.size() && index < convertedList.size(); index++) {
+ // Do not overwrite display name or nickname when syncing name
+ if (kind == bbpim::AttributeKind::Name &&
+ (savedList[index].subKind() == bbpim::AttributeSubKind::NameNickname ||
+ savedList[index].subKind() == bbpim::AttributeSubKind::NameDisplayName)) {
+ addAttribute(contactBuilder, kind, convertedList[index].first, convertedList[index].second, groupKey);
+ } else {
+ bbpim::ContactAttributeBuilder attributeBuilder(savedList[index].edit());
+ attributeBuilder = attributeBuilder.setSubKind(convertedList[index].first);
+ attributeBuilder = attributeBuilder.setValue(QString(convertedList[index].second.c_str()));
+
+ if (!groupKey.empty()) {
+ attributeBuilder = attributeBuilder.setGroupKey(QString(groupKey.c_str()));
+ }
+ }
+ }
+
+ if (index < savedList.size()) {
+ for (; index < savedList.size(); index++) {
+ // Do not delete display name or nickname when syncing name
+ if (savedList[index].subKind() != bbpim::AttributeSubKind::NameNickname &&
+ savedList[index].subKind() != bbpim::AttributeSubKind::NameDisplayName) {
+ contactBuilder = contactBuilder.deleteAttribute(savedList[index]);
+ }
+ }
+ } else if (index < convertedList.size()) {
+ for (; index < convertedList.size(); index++) {
+ QList<SubkindValuePair> remainingList = convertedList.mid(index);
+ addConvertedList(contactBuilder, kind, remainingList, groupKey);
+ }
+ }
+}
+
+void PimContactsQt::syncAttributeGroup(bbpim::ContactBuilder& contactBuilder, bbpim::AttributeKind::Type kind, QList<QList<bbpim::ContactAttribute> > savedList, const Json::Value& jsonObj)
+{
+ int i;
+
+ for (i = 0; i < static_cast<int>(jsonObj.size()) && i < savedList.size(); i++) {
+ std::stringstream groupKeyStream;
+ groupKeyStream << i + 1;
+
+ QList<SubkindValuePair> convertedList = convertGroupedAttributes(jsonObj[i]);
+ syncConvertedList(contactBuilder, kind, savedList[i], convertedList, groupKeyStream.str());
+ }
+
+ if (i < savedList.size()) {
+ for (; i < savedList.size(); i++) {
+ for (int j = 0; j < savedList[i].size(); j++) {
+ contactBuilder = contactBuilder.deleteAttribute(savedList[i][j]);
+ }
+ }
+ } else if (i < static_cast<int>(jsonObj.size())) {
+ for (; i < static_cast<int>(jsonObj.size()); i++) {
+ std::stringstream groupKeyStream;
+ groupKeyStream << i + 1;
+
+ QList<SubkindValuePair> convertedList = convertGroupedAttributes(jsonObj[i]);
+ addConvertedList(contactBuilder, kind, convertedList, groupKeyStream.str());
+ }
+ }
+}
+
+void PimContactsQt::syncAttribute(bbpim::ContactBuilder& contactBuilder, QList<bbpim::ContactAttribute>& savedList, const bbpim::AttributeKind::Type kind, const bbpim::AttributeSubKind::Type subkind, const std::string& value, const std::string& groupKey)
+{
+ bool found = false;
+
+ for (int i = 0; i < savedList.size() && !found; i++) {
+ if (savedList[i].subKind() == subkind) {
+ bbpim::ContactAttributeBuilder attributeBuilder(savedList[i].edit());
+
+ if (kind == bbpim::AttributeKind::Date) {
+ QDateTime date = QDateTime::fromString(QString(value.c_str()), QString("ddd MMM dd yyyy"));
+
+ if (date.isValid()) {
+ attributeBuilder = attributeBuilder.setValue(date);
+ } else {
+ attributeBuilder = attributeBuilder.setValue(QString(value.c_str()));
+ }
+ } else {
+ attributeBuilder = attributeBuilder.setValue(QString(value.c_str()));
+
+ if (!groupKey.empty()) {
+ attributeBuilder = attributeBuilder.setGroupKey(QString(groupKey.c_str()));
+ }
+ }
+
+ found = true;
+ }
+ }
+
+ if (!found) {
+ addAttribute(contactBuilder, kind, subkind, value, groupKey);
+ }
+}
+
+void PimContactsQt::syncPostalAddresses(bbpim::ContactBuilder& contactBuilder, QList<bbpim::ContactPostalAddress>& savedList, const Json::Value& jsonObj)
+{
+ int i;
+
+ for (i = 0; i < savedList.size() && i < static_cast<int>(jsonObj.size()); i++) {
+ Json::Value addressObj = jsonObj[i];
+ bbpim::ContactPostalAddressBuilder addressBuilder(savedList[i].edit());
+
+ std::string type = addressObj.get("type", "other").asString();
+ StringToSubKindMap::const_iterator subkindIter = _attributeSubKindMap.find(type);
+
+ if (subkindIter != _attributeSubKindMap.end()) {
+ addressBuilder = addressBuilder.setSubKind(subkindIter->second);
+ }
+
+ addressBuilder = addressBuilder.setLine1(QString(addressObj.get("streetAddress", "").asCString()));
+ addressBuilder = addressBuilder.setLine2(QString(addressObj.get("streetOther", "").asCString()));
+ addressBuilder = addressBuilder.setCity(QString(addressObj.get("locality", "").asCString()));
+ addressBuilder = addressBuilder.setRegion(QString(addressObj.get("region", "").asCString()));
+ addressBuilder = addressBuilder.setCountry(QString(addressObj.get("country", "").asCString()));
+ addressBuilder = addressBuilder.setPostalCode(QString(addressObj.get("postalCode", "").asCString()));
+ }
+
+ if (i < savedList.size()) {
+ for (; i < savedList.size(); i++) {
+ contactBuilder = contactBuilder.deletePostalAddress(savedList[i]);
+ }
+ } else if (i < static_cast<int>(jsonObj.size())) {
+ for (; i < static_cast<int>(jsonObj.size()); i++) {
+ addPostalAddress(contactBuilder, jsonObj[i]);
+ }
+ }
+}
+
+void PimContactsQt::syncPhotos(bbpim::ContactBuilder& contactBuilder, QList<bbpim::ContactPhoto>& savedList, const Json::Value& jsonObj, const bbpim::ContactPhoto& primaryPhoto)
+{
+ int i;
+
+ // We must do the delete first, because there seems to be a problem if we do it after
+ if (savedList.size() > static_cast<int>(jsonObj.size())) {
+ for (i = jsonObj.size(); i < savedList.size(); i++) {
+ contactBuilder = contactBuilder.deletePhoto(savedList[i]);
+ }
+ }
+
+ for (i = 0; i < savedList.size() && i < static_cast<int>(jsonObj.size()); i++) {
+ std::string filepath = jsonObj[i].get("originalFilePath", "").asString();
+ bool pref = jsonObj[i].get("pref", false).asBool();
+
+ if (filepath != savedList[i].originalPhoto().toStdString()) {
+ contactBuilder = contactBuilder.deletePhoto(savedList[i]);
+ addPhoto(contactBuilder, jsonObj[i]);
+ } else if (pref != (primaryPhoto.id() == savedList[i].id())) {
+ bbpim::ContactPhotoBuilder photoBuilder = savedList[i].edit();
+ photoBuilder.setPrimaryPhoto(pref);
+ }
+ }
+
+ if (i < static_cast<int>(jsonObj.size())) {
+ for (; i < static_cast<int>(jsonObj.size()); i++) {
+ addPhoto(contactBuilder, jsonObj[i]);
+ }
+ }
+}
+
+/****************************************************************
+ * Mapping functions
+ ****************************************************************/
+
+void PimContactsQt::createAttributeKindMap()
+{
+ _attributeKindMap["phoneNumbers"] = bbpim::AttributeKind::Phone;
+ _attributeKindMap["faxNumbers"] = bbpim::AttributeKind::Fax;
+ _attributeKindMap["pagerNumbers"] = bbpim::AttributeKind::Pager;
+ _attributeKindMap["emails"] = bbpim::AttributeKind::Email;
+ _attributeKindMap["urls"] = bbpim::AttributeKind::Website;
+ _attributeKindMap["socialNetworks"] = bbpim::AttributeKind::Profile;
+ _attributeKindMap["anniversary"] = bbpim::AttributeKind::Date;
+ _attributeKindMap["birthday"] = bbpim::AttributeKind::Date;
+ _attributeKindMap["categories"] = bbpim::AttributeKind::Group;
+ _attributeKindMap["name"] = bbpim::AttributeKind::Name;
+ _attributeKindMap["organizations"] = bbpim::AttributeKind::OrganizationAffiliation;
+ _attributeKindMap["education"] = bbpim::AttributeKind::Education;
+ _attributeKindMap["note"] = bbpim::AttributeKind::Note;
+ _attributeKindMap["ims"] = bbpim::AttributeKind::InstantMessaging;
+ _attributeKindMap["ringtone"] = bbpim::AttributeKind::Sound;
+ _attributeKindMap["videoChat"] = bbpim::AttributeKind::VideoChat;
+ _attributeKindMap["addresses"] = bbpim::AttributeKind::Invalid;
+ _attributeKindMap["favorite"] = bbpim::AttributeKind::Invalid;
+ _attributeKindMap["photos"] = bbpim::AttributeKind::Invalid;
+ _attributeKindMap["news"] = bbpim::AttributeKind::Invalid;
+ _attributeKindMap["activities"] = bbpim::AttributeKind::Invalid;
+}
+
+void PimContactsQt::createAttributeSubKindMap()
+{
+ _attributeSubKindMap["other"] = bbpim::AttributeSubKind::Other;
+ _attributeSubKindMap["home"] = bbpim::AttributeSubKind::Home;
+ _attributeSubKindMap["work"] = bbpim::AttributeSubKind::Work;
+ _attributeSubKindMap["mobile"] = bbpim::AttributeSubKind::PhoneMobile;
+ _attributeSubKindMap["direct"] = bbpim::AttributeSubKind::FaxDirect;
+ _attributeSubKindMap["blog"] = bbpim::AttributeSubKind::Blog;
+ _attributeSubKindMap["resume"] = bbpim::AttributeSubKind::WebsiteResume;
+ _attributeSubKindMap["portfolio"] = bbpim::AttributeSubKind::WebsitePortfolio;
+ _attributeSubKindMap["personal"] = bbpim::AttributeSubKind::WebsitePersonal;
+ _attributeSubKindMap["company"] = bbpim::AttributeSubKind::WebsiteCompany;
+ _attributeSubKindMap["facebook"] = bbpim::AttributeSubKind::ProfileFacebook;
+ _attributeSubKindMap["twitter"] = bbpim::AttributeSubKind::ProfileTwitter;
+ _attributeSubKindMap["linkedin"] = bbpim::AttributeSubKind::ProfileLinkedIn;
+ _attributeSubKindMap["gist"] = bbpim::AttributeSubKind::ProfileGist;
+ _attributeSubKindMap["tungle"] = bbpim::AttributeSubKind::ProfileTungle;
+ _attributeSubKindMap["birthday"] = bbpim::AttributeSubKind::DateBirthday;
+ _attributeSubKindMap["anniversary"] = bbpim::AttributeSubKind::DateAnniversary;
+ _attributeSubKindMap["categories"] = bbpim::AttributeSubKind::GroupDepartment;
+ _attributeSubKindMap["givenName"] = bbpim::AttributeSubKind::NameGiven;
+ _attributeSubKindMap["familyName"] = bbpim::AttributeSubKind::NameSurname;
+ _attributeSubKindMap["honorificPrefix"] = bbpim::AttributeSubKind::Title;
+ _attributeSubKindMap["honorificSuffix"] = bbpim::AttributeSubKind::NameSuffix;
+ _attributeSubKindMap["middleName"] = bbpim::AttributeSubKind::NameMiddle;
+ _attributeSubKindMap["nickname"] = bbpim::AttributeSubKind::NameNickname;
+ _attributeSubKindMap["displayName"] = bbpim::AttributeSubKind::NameDisplayName;
+ _attributeSubKindMap["phoneticGivenName"] = bbpim::AttributeSubKind::NamePhoneticGiven;
+ _attributeSubKindMap["phoneticFamilyName"] = bbpim::AttributeSubKind::NamePhoneticSurname;
+ _attributeSubKindMap["name"] = bbpim::AttributeSubKind::OrganizationAffiliationName;
+ _attributeSubKindMap["department"] = bbpim::AttributeSubKind::OrganizationAffiliationDetails;
+ _attributeSubKindMap["title"] = bbpim::AttributeSubKind::Title;
+ _attributeSubKindMap["BbmPin"] = bbpim::AttributeSubKind::InstantMessagingBbmPin;
+ _attributeSubKindMap["Aim"] = bbpim::AttributeSubKind::InstantMessagingAim;
+ _attributeSubKindMap["Aliwangwang"] = bbpim::AttributeSubKind::InstantMessagingAliwangwang;
+ _attributeSubKindMap["GoogleTalk"] = bbpim::AttributeSubKind::InstantMessagingGoogleTalk;
+ _attributeSubKindMap["Sametime"] = bbpim::AttributeSubKind::InstantMessagingSametime;
+ _attributeSubKindMap["Icq"] = bbpim::AttributeSubKind::InstantMessagingIcq;
+ _attributeSubKindMap["Jabber"] = bbpim::AttributeSubKind::InstantMessagingJabber;
+ _attributeSubKindMap["MsLcs"] = bbpim::AttributeSubKind::InstantMessagingMsLcs;
+ _attributeSubKindMap["Skype"] = bbpim::AttributeSubKind::InstantMessagingSkype;
+ _attributeSubKindMap["YahooMessenger"] = bbpim::AttributeSubKind::InstantMessagingYahooMessenger;
+ _attributeSubKindMap["YahooMessegerJapan"] = bbpim::AttributeSubKind::InstantMessagingYahooMessengerJapan;
+ _attributeSubKindMap["BbPlaybook"] = bbpim::AttributeSubKind::VideoChatBbPlaybook;
+ _attributeSubKindMap["ringtone"] = bbpim::AttributeSubKind::SoundRingtone;
+ _attributeSubKindMap["note"] = bbpim::AttributeSubKind::Invalid;
+}
+
+void PimContactsQt::createKindAttributeMap() {
+ _kindAttributeMap[bbpim::AttributeKind::Phone] = "phoneNumbers";
+ _kindAttributeMap[bbpim::AttributeKind::Fax] = "faxNumbers";
+ _kindAttributeMap[bbpim::AttributeKind::Pager] = "pagerNumber";
+ _kindAttributeMap[bbpim::AttributeKind::Email] = "emails";
+ _kindAttributeMap[bbpim::AttributeKind::Website] = "urls";
+ _kindAttributeMap[bbpim::AttributeKind::Profile] = "socialNetworks";
+ _kindAttributeMap[bbpim::AttributeKind::OrganizationAffiliation] = "organizations";
+ _kindAttributeMap[bbpim::AttributeKind::Education] = "education";
+ _kindAttributeMap[bbpim::AttributeKind::Note] = "note";
+ _kindAttributeMap[bbpim::AttributeKind::InstantMessaging] = "ims";
+ _kindAttributeMap[bbpim::AttributeKind::VideoChat] = "videoChat";
+ _kindAttributeMap[bbpim::AttributeKind::Sound] = "ringtone";
+ _kindAttributeMap[bbpim::AttributeKind::Website] = "urls";
+}
+
+void PimContactsQt::createSubKindAttributeMap() {
+ _subKindAttributeMap[bbpim::AttributeSubKind::Other] = "other";
+ _subKindAttributeMap[bbpim::AttributeSubKind::Home] = "home";
+ _subKindAttributeMap[bbpim::AttributeSubKind::Work] = "work";
+ _subKindAttributeMap[bbpim::AttributeSubKind::PhoneMobile] = "mobile";
+ _subKindAttributeMap[bbpim::AttributeSubKind::FaxDirect] = "direct";
+ _subKindAttributeMap[bbpim::AttributeSubKind::Blog] = "blog";
+ _subKindAttributeMap[bbpim::AttributeSubKind::WebsiteResume] = "resume";
+ _subKindAttributeMap[bbpim::AttributeSubKind::WebsitePortfolio] = "portfolio";
+ _subKindAttributeMap[bbpim::AttributeSubKind::WebsitePersonal] = "personal";
+ _subKindAttributeMap[bbpim::AttributeSubKind::WebsiteCompany] = "company";
+ _subKindAttributeMap[bbpim::AttributeSubKind::ProfileFacebook] = "facebook";
+ _subKindAttributeMap[bbpim::AttributeSubKind::ProfileTwitter] = "twitter";
+ _subKindAttributeMap[bbpim::AttributeSubKind::ProfileLinkedIn] = "linkedin";
+ _subKindAttributeMap[bbpim::AttributeSubKind::ProfileGist] = "gist";
+ _subKindAttributeMap[bbpim::AttributeSubKind::ProfileTungle] = "tungle";
+ _subKindAttributeMap[bbpim::AttributeSubKind::DateBirthday] = "birthday";
+ _subKindAttributeMap[bbpim::AttributeSubKind::DateAnniversary] = "anniversary";
+ _subKindAttributeMap[bbpim::AttributeSubKind::NameGiven] = "givenName";
+ _subKindAttributeMap[bbpim::AttributeSubKind::NameSurname] = "familyName";
+ _subKindAttributeMap[bbpim::AttributeSubKind::Title] = "honorificPrefix";
+ _subKindAttributeMap[bbpim::AttributeSubKind::NameSuffix] = "honorificSuffix";
+ _subKindAttributeMap[bbpim::AttributeSubKind::NameMiddle] = "middleName";
+ _subKindAttributeMap[bbpim::AttributeSubKind::NamePhoneticGiven] = "phoneticGivenName";
+ _subKindAttributeMap[bbpim::AttributeSubKind::NamePhoneticSurname] = "phoneticFamilyName";
+ _subKindAttributeMap[bbpim::AttributeSubKind::NameNickname] = "nickname";
+ _subKindAttributeMap[bbpim::AttributeSubKind::NameDisplayName] = "displayName";
+ _subKindAttributeMap[bbpim::AttributeSubKind::OrganizationAffiliationName] = "name";
+ _subKindAttributeMap[bbpim::AttributeSubKind::OrganizationAffiliationDetails] = "department";
+ _subKindAttributeMap[bbpim::AttributeSubKind::Title] = "title";
+ _subKindAttributeMap[bbpim::AttributeSubKind::InstantMessagingBbmPin] = "BbmPin";
+ _subKindAttributeMap[bbpim::AttributeSubKind::InstantMessagingAim] = "Aim";
+ _subKindAttributeMap[bbpim::AttributeSubKind::InstantMessagingAliwangwang] = "Aliwangwang";
+ _subKindAttributeMap[bbpim::AttributeSubKind::InstantMessagingGoogleTalk] = "GoogleTalk";
+ _subKindAttributeMap[bbpim::AttributeSubKind::InstantMessagingSametime] = "Sametime";
+ _subKindAttributeMap[bbpim::AttributeSubKind::InstantMessagingIcq] = "Icq";
+ _subKindAttributeMap[bbpim::AttributeSubKind::InstantMessagingJabber] = "Jabber";
+ _subKindAttributeMap[bbpim::AttributeSubKind::InstantMessagingMsLcs] = "MsLcs";
+ _subKindAttributeMap[bbpim::AttributeSubKind::InstantMessagingSkype] = "Skype";
+ _subKindAttributeMap[bbpim::AttributeSubKind::InstantMessagingYahooMessenger] = "YahooMessenger";
+ _subKindAttributeMap[bbpim::AttributeSubKind::InstantMessagingYahooMessengerJapan] = "YahooMessegerJapan";
+ _subKindAttributeMap[bbpim::AttributeSubKind::VideoChatBbPlaybook] = "BbPlaybook";
+ _subKindAttributeMap[bbpim::AttributeSubKind::SoundRingtone] = "ringtone";
+ _subKindAttributeMap[bbpim::AttributeSubKind::Personal] = "personal";
+}
+
+} // namespace webworks
+
http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1890c10c/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/pim_contacts_qt.hpp
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/pim_contacts_qt.hpp b/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/pim_contacts_qt.hpp
new file mode 100644
index 0000000..115469c
--- /dev/null
+++ b/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/pim_contacts_qt.hpp
@@ -0,0 +1,148 @@
+/*
+ * 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.
+ */
+
+#ifndef PIM_CONTACTS_QT_H_
+#define PIM_CONTACTS_QT_H_
+
+#include <json/value.h>
+#include <bb/pim/contacts/ContactService.hpp>
+#include <bb/pim/contacts/ContactConsts.hpp>
+#include <bb/pim/contacts/Contact.hpp>
+#include <bb/pim/contacts/ContactBuilder.hpp>
+#include <bb/pim/contacts/ContactAttribute.hpp>
+#include <bb/pim/contacts/ContactAttributeBuilder.hpp>
+#include <bb/pim/contacts/ContactPostalAddress.hpp>
+#include <bb/pim/contacts/ContactPostalAddressBuilder.hpp>
+#include <bb/pim/contacts/ContactPhoto.hpp>
+#include <bb/pim/contacts/ContactPhotoBuilder.hpp>
+#include <bb/pim/contacts/ContactListFilters.hpp>
+#include <bb/pim/account/AccountService.hpp>
+#include <bb/pim/account/Account.hpp>
+#include <bb/pim/account/Provider>
+#include <webworks_utils.hpp>
+
+#include <string>
+#include <utility>
+#include <map>
+
+#include "contact_account.hpp"
+
+class PimContacts;
+
+namespace webworks {
+
+namespace bbpim = bb::pim::contacts;
+namespace bbpimacc = bb::pim::account;
+
+typedef std::map<std::string, bbpim::AttributeKind::Type> StringToKindMap;
+typedef std::map<std::string, bbpim::AttributeSubKind::Type> StringToSubKindMap;
+typedef std::map<bbpim::AttributeKind::Type, std::string> KindToStringMap;
+typedef std::map<bbpim::AttributeSubKind::Type, std::string> SubKindToStringMap;
+
+typedef std::pair<bbpim::AttributeSubKind::Type, std::string> SubkindValuePair;
+
+enum PimContactsError {
+ 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,
+};
+
+struct PimContactsThreadInfo {
+ PimContacts *parent;
+ Json::Value *jsonObj;
+ std::string eventId;
+};
+
+class PimContactsQt {
+public:
+ PimContactsQt();
+ ~PimContactsQt();
+ Json::Value Find(const Json::Value& argsObj);
+ Json::Value Save(const Json::Value& attributeObj);
+ Json::Value CreateContact(const Json::Value& attributeObj);
+ Json::Value DeleteContact(const Json::Value& contactObj);
+ Json::Value EditContact(bbpim::Contact& contact, const Json::Value& attributeObj);
+ Json::Value CloneContact(bbpim::Contact& contact, const Json::Value& attributeObj);
+ Json::Value GetContact(const Json::Value& argsObj);
+ static Json::Value InvokePicker(const Json::Value& args);
+ static Json::Value GetContactAccounts();
+
+private:
+ // Helper functions for Find
+ Json::Value assembleSearchResults(const QSet<bbpim::ContactId>& results, const Json::Value& contactFields, int limit);
+ Json::Value populateContact(const bbpim::Contact& contact, const Json::Value& contactFields);
+ void populateField(const bbpim::Contact& contact, bbpim::AttributeKind::Type kind, Json::Value& contactItem, bool isContactField, bool isArray);
+ void populateDisplayNameNickName(const bbpim::Contact& contact, Json::Value& contactItem, const std::string& field);
+ void populateOrganizations(const bbpim::Contact& contact, Json::Value& contactOrgs);
+ void populateAddresses(const bbpim::Contact& contact, Json::Value& contactAddrs);
+ void populatePhotos(const bbpim::Contact& contact, Json::Value& contactPhotos);
+ void populateNews(const bbpim::Contact& contact, Json::Value& contactNews);
+ void populateActivity(const bbpim::Contact& contact, Json::Value& contactActivity);
+ static void populateAccount(const bbpimacc::Account& account, Json::Value& jsonAccount);
+
+ static QSet<bbpim::ContactId> singleFieldSearch(const Json::Value& searchFieldsJson, const Json::Value& contactFields, const bool favorite, const Json::Value& includeAccounts, const Json::Value& excludeAccounts);
+ static QString getSortFieldValue(const bbpim::SortColumn::Type sortField, const bbpim::Contact& contact);
+ static QList<bbpim::SearchField::Type> getSearchFields(const Json::Value& searchFieldsJson);
+ static void getSortSpecs(const Json::Value& sort);
+ static QSet<bbpim::ContactId> getPartialSearchResults(const Json::Value& filter, const Json::Value& contactFields, const bool favorite, const Json::Value& includeAccounts, const Json::Value& excludeAccounts);
+ static bool lessThan(const bbpim::Contact& c1, const bbpim::Contact& c2);
+ static std::string replaceAll(const std::string& s, const std::string& souce = "\"", const std::string& target = "\\\"");
+ static std::string replaceString(const std::string& s);
+ static QList<bbpim::AttributeKind::Type> getIncludeAttributesList(const Json::Value& contactFields, bbpim::ContactListFilters* listFilters = NULL);
+ static void getAccountFilters(bbpim::ContactSearchFilters* searchFilter, bbpim::ContactListFilters* listFilter, const Json::Value& includeAccounts, const Json::Value& excludeAccounts);
+
+ // Helper functions for Save
+ void addAttributeKind(bbpim::ContactBuilder& contactBuilder, const Json::Value& jsonObj, const std::string& field);
+ void addPostalAddress(bbpim::ContactBuilder& contactBuilder, const Json::Value& addressObj);
+ void addPhoto(bbpim::ContactBuilder& contactBuilder, const Json::Value& photoObj);
+
+ void syncAttributeKind(bbpim::Contact& contact, const Json::Value& jsonObj, const std::string& field);
+ void syncConvertedList(bbpim::ContactBuilder& contactBuilder, bbpim::AttributeKind::Type kind, QList<bbpim::ContactAttribute>& savedList, const QList<SubkindValuePair>& convertedList, const std::string& groupKey = "");
+ void syncAttributeGroup(bbpim::ContactBuilder& contactBuilder, bbpim::AttributeKind::Type kind, QList<QList<bbpim::ContactAttribute> > savedList, const Json::Value& jsonObj);
+ void syncAttribute(bbpim::ContactBuilder& contactBuilder, QList<bbpim::ContactAttribute>& savedList, const bbpim::AttributeKind::Type kind, const bbpim::AttributeSubKind::Type subkind, const std::string& value, const std::string& groupKey = "");
+ void syncPostalAddresses(bbpim::ContactBuilder& contactBuilder, QList<bbpim::ContactPostalAddress>& savedList, const Json::Value& jsonObj);
+ void syncPhotos(bbpim::ContactBuilder& contactBuilder, QList<bbpim::ContactPhoto>& savedList, const Json::Value& jsonObj, const bbpim::ContactPhoto& primaryPhoto);
+
+ void addConvertedList(bbpim::ContactBuilder& contactBuilder, const bbpim::AttributeKind::Type kind, const QList<SubkindValuePair>& convertedList, const std::string& groupKey = "");
+ void addAttribute(bbpim::ContactBuilder& contactBuilder, const bbpim::AttributeKind::Type kind, const bbpim::AttributeSubKind::Type subkind, const std::string& value, const std::string& groupKey = "");
+
+ QList<SubkindValuePair> convertGroupedAttributes(const Json::Value& fieldsObj);
+ QList<SubkindValuePair> convertFieldAttributes(const Json::Value& fieldArray);
+ QList<SubkindValuePair> convertStringArray(const Json::Value& stringArray, bbpim::AttributeSubKind::Type subkind);
+
+ // Mappings between JSON strings and attribute kinds/subkinds
+ static void createAttributeKindMap();
+ static void createAttributeSubKindMap();
+ static void createKindAttributeMap();
+ static void createSubKindAttributeMap();
+
+ static StringToKindMap _attributeKindMap;
+ static StringToSubKindMap _attributeSubKindMap;
+ static KindToStringMap _kindAttributeMap;
+ static SubKindToStringMap _subKindAttributeMap;
+ static QList<bbpim::SortSpecifier> _sortSpecs;
+
+ static std::map<bbpim::ContactId, bbpim::Contact> _contactSearchMap;
+ static ContactAccount& _contactAccount;
+};
+
+} // namespace webworks
+
+#endif // PIM_CONTACTS_QT_H_
http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1890c10c/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/simulator/libpimcontacts.so
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/simulator/libpimcontacts.so b/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/simulator/libpimcontacts.so
new file mode 100644
index 0000000..d6bf514
Binary files /dev/null and b/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/simulator/libpimcontacts.so differ
http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1890c10c/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/x86/Makefile
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/x86/Makefile b/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/x86/Makefile
new file mode 100644
index 0000000..0e22650
--- /dev/null
+++ b/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/x86/Makefile
@@ -0,0 +1,8 @@
+LIST=VARIANT
+ifndef QRECURSE
+QRECURSE=recurse.mk
+ifdef QCONFIG
+QRDIR=$(dir $(QCONFIG))
+endif
+endif
+include $(QRDIR)$(QRECURSE)
http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1890c10c/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/x86/so/Makefile
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/x86/so/Makefile b/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/x86/so/Makefile
new file mode 100644
index 0000000..2c76089
--- /dev/null
+++ b/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/x86/so/Makefile
@@ -0,0 +1 @@
+include ../../common.mk
http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1890c10c/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/x86/so/libpimcontacts.so
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/x86/so/libpimcontacts.so b/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/x86/so/libpimcontacts.so
new file mode 100755
index 0000000..d6bf514
Binary files /dev/null and b/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/x86/so/libpimcontacts.so differ
http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1890c10c/blackberry10/bin/test/plugins/Contacts/index.js
----------------------------------------------------------------------
diff --git a/blackberry10/bin/test/plugins/Contacts/index.js b/blackberry10/bin/test/plugins/Contacts/index.js
new file mode 100644
index 0000000..a14d89b
--- /dev/null
+++ b/blackberry10/bin/test/plugins/Contacts/index.js
@@ -0,0 +1,197 @@
+/*
+ * 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.
+ */
+
+describe("Contacts", function () {
+ var _apiDir = __dirname + "./../../../templates/project/plugins/Contacts/src/blackberry10/",
+ index,
+ ContactError = require(_apiDir + "ContactError"),
+ ContactFindOptions = require(_apiDir + "ContactFindOptions"),
+ result = {
+ noResult: jasmine.createSpy("PluginResult.noResult"),
+ error: jasmine.createSpy("PluginResult.error"),
+ ok: jasmine.createSpy("PluginResult.ok"),
+ callbackError: jasmine.createSpy("PluginResult.callbackError"),
+ callbackOk: jasmine.createSpy("PluginResult.callbackOk"),
+ callbackId: "Contacts12345"
+ };
+
+ beforeEach(function () {
+ GLOBAL.JNEXT = {
+ require: jasmine.createSpy("JNEXT.require").andCallFake(function () {
+ return true;
+ }),
+ createObject: jasmine.createSpy("JNEXT.createObject").andCallFake(function () {
+ return 123;
+ }),
+ invoke: jasmine.createSpy("JNEXT.invoke").andCallFake(function () {
+ return JSON.stringify({
+ _success: true,
+ contact: { id: "123" }
+ });
+ }),
+ registerEvents: jasmine.createSpy("JNEXT.regsiterEvents")
+ };
+ GLOBAL.PluginResult = function () {
+ return result;
+ };
+ index = require(_apiDir + "index");
+ GLOBAL.window = {
+ parseInt: jasmine.createSpy("window.parseInt"),
+ isNaN: jasmine.createSpy("window.isNaN")
+ };
+ });
+
+ afterEach(function () {
+ index = null;
+ delete GLOBAL.JNEXT;
+ delete GLOBAL.window;
+ delete GLOBAL.PluginResult;
+ });
+
+ describe("index.search", function () {
+ it("correctly parses args to pass down to native (with filter)", function () {
+ var findOptions = new ContactFindOptions("test"),
+ args = {
+ "0": encodeURIComponent(JSON.stringify(["phoneNumbers", "emails"])),
+ "1": encodeURIComponent(JSON.stringify(findOptions)),
+ "callbackId": encodeURIComponent(JSON.stringify("Contacts12345"))
+ },
+ jnextArgs = {
+ "_eventId": "Contacts12345",
+ "fields": ["phoneNumbers", "emails"],
+ "options": {
+ "filter": [
+ { "fieldValue": "test" }
+ ]
+ }
+ };
+ index.search(function () {}, function () {}, args, {});
+ expect(JNEXT.invoke).toHaveBeenCalledWith(123, 'find ' + JSON.stringify(jnextArgs));
+ expect(result.noResult).toHaveBeenCalledWith(true);
+ });
+
+ it("correctly parses args to pass down to native (with no filter)", function () {
+ var findOptions = new ContactFindOptions(),
+ args = {
+ "0": encodeURIComponent(JSON.stringify(["phoneNumbers", "emails"])),
+ "1": encodeURIComponent(JSON.stringify(findOptions)),
+ "callbackId": encodeURIComponent(JSON.stringify("Contacts12345"))
+ },
+ jnextArgs = {
+ "_eventId": "Contacts12345",
+ "fields": ["phoneNumbers", "emails"],
+ "options": {
+ "filter": []
+ }
+ };
+ index.search(function () {}, function () {}, args, {});
+ expect(JNEXT.invoke).toHaveBeenCalledWith(123, 'find ' + JSON.stringify(jnextArgs));
+ expect(result.noResult).toHaveBeenCalledWith(true);
+ });
+ });
+
+ describe("index.save", function () {
+ it("calls JNEXT save with the correct param if contactId provided", function () {
+ var contactProps = {
+ "id": "123"
+ },
+ args = {
+ "0": encodeURIComponent(JSON.stringify(contactProps)),
+ "callbackId": encodeURIComponent(JSON.stringify("Contacts12345"))
+ };
+
+ window.parseInt.andCallFake(function () {
+ return 123;
+ });
+ index.save(function () {}, function () {}, args, {});
+ expect(JNEXT.invoke).toHaveBeenCalledWith(123, 'save ' + JSON.stringify({"id": 123, "_eventId": "Contacts12345"}));
+ expect(result.noResult).toHaveBeenCalledWith(true);
+ });
+
+ it("properly converts birthdays for native", function () {
+ var contactProps = {
+ birthday: 1367259069028,
+ },
+ args = {
+ "0": encodeURIComponent(JSON.stringify(contactProps)),
+ "callbackId": encodeURIComponent(JSON.stringify("Contacts12345"))
+ },
+ processedArgs = {
+ "birthday": "Mon Apr 29 2013",
+ "_eventId": "Contacts12345"
+ };
+
+ index.save(function () {}, function () {}, args, {});
+ expect(JNEXT.invoke).toHaveBeenCalledWith(123, 'save ' + JSON.stringify(processedArgs));
+ expect(result.noResult).toHaveBeenCalledWith(true);
+ });
+
+ it("processes emails contactFeild array", function () {
+ var contactProps = {
+ "emails": [
+ { "value": "a@c.com" },
+ { "type" : "home", "value": "a@b.com" }
+ ]
+ },
+ args = {
+ "0": encodeURIComponent(JSON.stringify(contactProps)),
+ "callbackId": encodeURIComponent(JSON.stringify("Contacts12345"))
+ },
+ processedArgs = {
+ "emails": [
+ { "type": "home", "value": "a@c.com" },
+ { "type": "home", "value": "a@b.com" },
+ ],
+ "_eventId": "Contacts12345"
+ };
+ index.save(function () {}, function () {}, args, {});
+ expect(JNEXT.invoke).toHaveBeenCalledWith(123, 'save ' + JSON.stringify(processedArgs));
+ expect(result.noResult).toHaveBeenCalledWith(true);
+
+ });
+
+ });
+
+ describe("index.remove", function () {
+ it("calls JNEXT remove with the correct params for valid contactId", function () {
+ var args = {
+ "0": encodeURIComponent(JSON.stringify(123)),
+ "callbackId": encodeURIComponent(JSON.stringify("Contacts12345"))
+ };
+
+ window.parseInt.andCallFake(function () {
+ return 123;
+ });
+ index.remove(function () {}, function () {}, args, {});
+ expect(JNEXT.invoke).toHaveBeenCalledWith(123, 'remove ' + JSON.stringify({"contactId": 123, "_eventId": "Contacts12345"}));
+ expect(result.noResult).toHaveBeenCalledWith(true);
+ });
+
+ it("calls callbackError if invalid ID", function () {
+ var args = {
+ "0": encodeURIComponent(JSON.stringify("asdfas")),
+ "callbackId": encodeURIComponent(JSON.stringify("Contacts12345"))
+ };
+
+ window.isNaN.andCallFake(function() {
+ return true;
+ });
+ index.remove(function () {}, function () {}, args, {});
+ expect(result.error).toHaveBeenCalledWith(ContactError.UNKNOWN_ERROR);
+ expect(result.noResult).toHaveBeenCalledWith(false);
+ });
+ });
+});
[2/2] webworks commit: Contacts core plugin
Posted by lo...@apache.org.
Contacts core plugin
Project: http://git-wip-us.apache.org/repos/asf/cordova-blackberry/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-blackberry/commit/1890c10c
Tree: http://git-wip-us.apache.org/repos/asf/cordova-blackberry/tree/1890c10c
Diff: http://git-wip-us.apache.org/repos/asf/cordova-blackberry/diff/1890c10c
Branch: refs/heads/future
Commit: 1890c10c2604ffa1a99a9b75bd76f1b3e2180185
Parents: 42b066f
Author: Hasan Ahmad <ha...@blackberry.com>
Authored: Thu Apr 11 16:28:42 2013 -0400
Committer: lorinbeer <lo...@adobe.com>
Committed: Mon May 13 13:12:40 2013 -0700
----------------------------------------------------------------------
.../templates/project/plugins/Contacts/plugin.xml | 29 +
.../Contacts/src/blackberry10/ContactActivity.js | 26 +
.../Contacts/src/blackberry10/ContactAddress.js | 30 +
.../Contacts/src/blackberry10/ContactError.js | 30 +
.../Contacts/src/blackberry10/ContactField.js | 27 +
.../src/blackberry10/ContactFindOptions.js | 50 +
.../Contacts/src/blackberry10/ContactName.js | 39 +
.../Contacts/src/blackberry10/ContactNews.js | 26 +
.../src/blackberry10/ContactOrganization.js | 22 +
.../Contacts/src/blackberry10/ContactPhoto.js | 23 +
.../Contacts/src/blackberry10/contactConsts.js | 225 ++
.../Contacts/src/blackberry10/contactUtils.js | 223 ++
.../plugins/Contacts/src/blackberry10/index.js | 374 ++++
.../plugin.xml | 23 +
.../src/blackberry10/native/Makefile | 8 +
.../src/blackberry10/native/arm/Makefile | 8 +
.../src/blackberry10/native/arm/so.le-v7/Makefile | 1 +
.../native/arm/so.le-v7/libpimcontacts.so | Bin 0 -> 170350 bytes
.../src/blackberry10/native/common.mk | 18 +
.../src/blackberry10/native/contact_account.cpp | 74 +
.../src/blackberry10/native/contact_account.hpp | 54 +
.../blackberry10/native/device/libpimcontacts.so | Bin 0 -> 170350 bytes
.../src/blackberry10/native/pim_contacts_js.cpp | 174 ++
.../src/blackberry10/native/pim_contacts_js.hpp | 45 +
.../src/blackberry10/native/pim_contacts_qt.cpp | 1611 +++++++++++++++
.../src/blackberry10/native/pim_contacts_qt.hpp | 148 ++
.../native/simulator/libpimcontacts.so | Bin 0 -> 265964 bytes
.../src/blackberry10/native/x86/Makefile | 8 +
.../src/blackberry10/native/x86/so/Makefile | 1 +
.../blackberry10/native/x86/so/libpimcontacts.so | Bin 0 -> 265964 bytes
blackberry10/bin/test/plugins/Contacts/index.js | 197 ++
31 files changed, 3494 insertions(+), 0 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1890c10c/blackberry10/bin/templates/project/plugins/Contacts/plugin.xml
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/Contacts/plugin.xml b/blackberry10/bin/templates/project/plugins/Contacts/plugin.xml
new file mode 100644
index 0000000..6753d29
--- /dev/null
+++ b/blackberry10/bin/templates/project/plugins/Contacts/plugin.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+
+-->
+
+<plugin xmlns="http://www.phonegap.com/ns/plugins/1.0"
+ id="org.apache.cordova.core"
+ version="0.0.1">
+
+ <name>Contacts</name>
+
+ <platform name="blackberry10">
+ <config-file target="www/config.xml" parent="/widget">
+ <feature name="Contacts" value="Contacts"/>
+ </config-file>
+ </platform>
+</plugin>
http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1890c10c/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/ContactActivity.js
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/ContactActivity.js b/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/ContactActivity.js
new file mode 100644
index 0000000..0794d23
--- /dev/null
+++ b/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/ContactActivity.js
@@ -0,0 +1,26 @@
+/*
+ * 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 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;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1890c10c/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/ContactAddress.js
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/ContactAddress.js b/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/ContactAddress.js
new file mode 100644
index 0000000..1ba9fe4
--- /dev/null
+++ b/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/ContactAddress.js
@@ -0,0 +1,30 @@
+/*
+ * 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 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;
http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1890c10c/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/ContactError.js
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/ContactError.js b/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/ContactError.js
new file mode 100644
index 0000000..f20f85e
--- /dev/null
+++ b/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/ContactError.js
@@ -0,0 +1,30 @@
+/*
+ * 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 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;
+
http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1890c10c/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/ContactField.js
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/ContactField.js b/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/ContactField.js
new file mode 100644
index 0000000..aad735c
--- /dev/null
+++ b/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/ContactField.js
@@ -0,0 +1,27 @@
+/*
+ * 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 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;
http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1890c10c/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/ContactFindOptions.js
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/ContactFindOptions.js b/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/ContactFindOptions.js
new file mode 100644
index 0000000..8be830d
--- /dev/null
+++ b/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/ContactFindOptions.js
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+/**
+ * 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;
+
http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1890c10c/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/ContactName.js
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/ContactName.js b/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/ContactName.js
new file mode 100644
index 0000000..9b74753
--- /dev/null
+++ b/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/ContactName.js
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+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;
http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1890c10c/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/ContactNews.js
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/ContactNews.js b/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/ContactNews.js
new file mode 100644
index 0000000..7aa9d8c
--- /dev/null
+++ b/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/ContactNews.js
@@ -0,0 +1,26 @@
+/*
+ * 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 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;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1890c10c/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/ContactOrganization.js
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/ContactOrganization.js b/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/ContactOrganization.js
new file mode 100644
index 0000000..ecf5d0c
--- /dev/null
+++ b/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/ContactOrganization.js
@@ -0,0 +1,22 @@
+/*
+ * 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 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;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1890c10c/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/ContactPhoto.js
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/ContactPhoto.js b/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/ContactPhoto.js
new file mode 100644
index 0000000..5b1c9d6
--- /dev/null
+++ b/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/ContactPhoto.js
@@ -0,0 +1,23 @@
+/*
+ * 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 ContactPhoto = function (originalFilePath, pref) {
+ this.originalFilePath = originalFilePath || "";
+ this.pref = pref || false;
+ this.largeFilePath = "";
+ this.smallFilePath = "";
+};
+
+module.exports = ContactPhoto;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1890c10c/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/contactConsts.js
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/contactConsts.js b/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/contactConsts.js
new file mode 100644
index 0000000..ef25206
--- /dev/null
+++ b/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/contactConsts.js
@@ -0,0 +1,225 @@
+/*
+* 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;
+ }
+};
http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1890c10c/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/contactUtils.js
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/contactUtils.js b/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/contactUtils.js
new file mode 100644
index 0000000..cd022c4
--- /dev/null
+++ b/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/contactUtils.js
@@ -0,0 +1,223 @@
+/*
+ * 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 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
+};
+
http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1890c10c/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/index.js
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/index.js b/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/index.js
new file mode 100644
index 0000000..09a4bd2
--- /dev/null
+++ b/blackberry10/bin/templates/project/plugins/Contacts/src/blackberry10/index.js
@@ -0,0 +1,374 @@
+/*
+ * 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();
http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1890c10c/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/plugin.xml
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/plugin.xml b/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/plugin.xml
new file mode 100644
index 0000000..b35a83e
--- /dev/null
+++ b/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/plugin.xml
@@ -0,0 +1,23 @@
+
+<!--
+ 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://www.phonegap.com/ns/plugins/1.0"
+ id="org.apache.cordova.blackberry10.pimlib"
+ version="1.0.0">
+</plugin>
http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1890c10c/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/Makefile
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/Makefile b/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/Makefile
new file mode 100644
index 0000000..0cc5eae
--- /dev/null
+++ b/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/Makefile
@@ -0,0 +1,8 @@
+LIST=CPU
+ifndef QRECURSE
+QRECURSE=recurse.mk
+ifdef QCONFIG
+QRDIR=$(dir $(QCONFIG))
+endif
+endif
+include $(QRDIR)$(QRECURSE)
http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1890c10c/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/arm/Makefile
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/arm/Makefile b/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/arm/Makefile
new file mode 100644
index 0000000..0e22650
--- /dev/null
+++ b/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/arm/Makefile
@@ -0,0 +1,8 @@
+LIST=VARIANT
+ifndef QRECURSE
+QRECURSE=recurse.mk
+ifdef QCONFIG
+QRDIR=$(dir $(QCONFIG))
+endif
+endif
+include $(QRDIR)$(QRECURSE)
http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1890c10c/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/arm/so.le-v7/Makefile
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/arm/so.le-v7/Makefile b/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/arm/so.le-v7/Makefile
new file mode 100644
index 0000000..2c76089
--- /dev/null
+++ b/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/arm/so.le-v7/Makefile
@@ -0,0 +1 @@
+include ../../common.mk
http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1890c10c/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/arm/so.le-v7/libpimcontacts.so
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/arm/so.le-v7/libpimcontacts.so b/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/arm/so.le-v7/libpimcontacts.so
new file mode 100755
index 0000000..f90047f
Binary files /dev/null and b/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/arm/so.le-v7/libpimcontacts.so differ
http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1890c10c/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/common.mk
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/common.mk b/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/common.mk
new file mode 100644
index 0000000..7bc06fb
--- /dev/null
+++ b/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/common.mk
@@ -0,0 +1,18 @@
+ifndef QCONFIG
+QCONFIG=qconfig.mk
+endif
+include $(QCONFIG)
+
+NAME=pimcontacts
+PLUGIN=yes
+UTILS=yes
+
+include ../../../../../../meta.mk
+
+SRCS+=pim_contacts_qt.cpp \
+ pim_contacts_js.cpp \
+ contact_account.cpp
+
+include $(MKFILES_ROOT)/qtargets.mk
+
+LIBS+=bbpim bbcascadespickers QtCore img
http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1890c10c/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/contact_account.cpp
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/contact_account.cpp b/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/contact_account.cpp
new file mode 100644
index 0000000..3476e70
--- /dev/null
+++ b/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/contact_account.cpp
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+#include <webworks_utils.hpp>
+#include "contact_account.hpp"
+
+ContactAccount& ContactAccount::GetAccountInstance()
+{
+ static ContactAccount ca;
+ return ca;
+}
+
+ContactAccount::ContactAccount()
+{
+ fetchContactAccounts();
+}
+
+ContactAccount::~ContactAccount()
+{}
+
+QList<bb::pim::account::Account> ContactAccount::GetContactAccounts(bool fresh)
+{
+ if (fresh) {
+ fetchContactAccounts();
+ }
+ return _accounts;
+}
+
+bb::pim::account::Account ContactAccount::GetAccount(bb::pim::account::AccountKey id, bool fresh)
+{
+ if (fresh) {
+ fetchContactAccounts();
+ }
+ return _accountMap.value(id);
+}
+
+Json::Value ContactAccount::Account2Json(const bb::pim::account::Account& account)
+{
+ Json::Value jsonAccount;
+ jsonAccount["id"] = webworks::Utils::intToStr(account.id());
+ jsonAccount["name"] = account.displayName().isEmpty() ? account.provider().name().toStdString() : account.displayName().toStdString();
+ jsonAccount["enterprise"] = account.isEnterprise() == 1 ? true : false;
+
+ return jsonAccount;
+}
+
+void ContactAccount::fetchContactAccounts()
+{
+ QList<bb::pim::account::Account> accounts = _accountService.accounts(bb::pim::account::Service::Contacts);
+
+ _accounts.clear();
+ _accountMap.clear();
+ for (QList<bb::pim::account::Account>::const_iterator it = accounts.begin(); it != accounts.end(); ++it) {
+ if ((it->id() != ID_UNIFIED_ACCOUNT) && (it->id() != ID_ENHANCED_ACCOUNT)) {
+ _accounts.append(*it);
+ _accountMap.insert(it->id(), (bb::pim::account::Account)(*it));
+ }
+ }
+}
+
+
http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1890c10c/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/contact_account.hpp
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/contact_account.hpp b/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/contact_account.hpp
new file mode 100644
index 0000000..3910de8
--- /dev/null
+++ b/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/contact_account.hpp
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+#ifndef _CONTACT_ACCOUNT_HPP_
+#define _CONTACT_ACCOUNT_HPP_
+
+#include <bb/pim/account/Account>
+#include <bb/pim/account/AccountService>
+#include <bb/pim/account/Provider>
+
+#include <json/value.h>
+#include <QList>
+#include <QDebug>
+
+class ContactAccount
+{
+public:
+ static ContactAccount& GetAccountInstance();
+
+ // get all available accounts which provide contact service
+ QList<bb::pim::account::Account> GetContactAccounts(bool fresh = false);
+ // get the contact account with the specific id
+ bb::pim::account::Account GetAccount(bb::pim::account::AccountKey id, bool fresh = false);
+ // serialize account to json object
+ static Json::Value Account2Json(const bb::pim::account::Account& account);
+
+private:
+ ContactAccount();
+ ~ContactAccount();
+ explicit ContactAccount(ContactAccount const&);
+ void operator=(ContactAccount const&);
+ // Refresh the accounts list and map
+ void fetchContactAccounts();
+ QMap<bb::pim::account::AccountKey, bb::pim::account::Account> _accountMap;
+ QList<bb::pim::account::Account> _accounts;
+ bb::pim::account::AccountService _accountService;
+ static const int ID_UNIFIED_ACCOUNT = 4;
+ static const int ID_ENHANCED_ACCOUNT = 6;
+};
+
+#endif // end of _CONTACT_ACCOUNT_HPP_
http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1890c10c/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/device/libpimcontacts.so
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/device/libpimcontacts.so b/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/device/libpimcontacts.so
new file mode 100644
index 0000000..f90047f
Binary files /dev/null and b/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/device/libpimcontacts.so differ
http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1890c10c/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/pim_contacts_js.cpp
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/pim_contacts_js.cpp b/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/pim_contacts_js.cpp
new file mode 100644
index 0000000..4788bd1
--- /dev/null
+++ b/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/pim_contacts_js.cpp
@@ -0,0 +1,174 @@
+/*
+ * 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.
+ */
+
+#include <json/reader.h>
+#include <json/writer.h>
+#include <string>
+#include "pim_contacts_js.hpp"
+#include "pim_contacts_qt.hpp"
+
+PimContacts::PimContacts(const std::string& id) : m_id(id)
+{
+}
+
+char* onGetObjList()
+{
+ // Return list of classes in the object
+ static char name[] = "PimContacts";
+ return name;
+}
+
+JSExt* onCreateObject(const std::string& className, const std::string& id)
+{
+ // Make sure we are creating the right class
+ if (className != "PimContacts") {
+ return 0;
+ }
+
+ return new PimContacts(id);
+}
+
+std::string PimContacts::InvokeMethod(const std::string& command)
+{
+ unsigned int index = command.find_first_of(" ");
+
+ string strCommand;
+ string jsonObject;
+ Json::Value *obj;
+
+ if (index != std::string::npos) {
+ strCommand = command.substr(0, index);
+ jsonObject = command.substr(index + 1, command.length());
+
+ // Parse the JSON
+ obj = new Json::Value;
+ bool parse = Json::Reader().parse(jsonObject, *obj);
+
+ if (!parse) {
+ return "Cannot parse JSON object";
+ }
+ } else {
+ strCommand = command;
+ obj = NULL;
+ }
+
+ if (strCommand == "find") {
+ startThread(FindThread, obj);
+ } else if (strCommand == "save") {
+ startThread(SaveThread, obj);
+ } else if (strCommand == "remove") {
+ startThread(RemoveThread, obj);
+ } else if (strCommand == "getContact") {
+ std::string result = Json::FastWriter().write(webworks::PimContactsQt().GetContact(*obj));
+ delete obj;
+ return result;
+ } else if (strCommand == "invokePicker") {
+ Json::Value result = webworks::PimContactsQt::InvokePicker(*obj);
+ delete obj;
+
+ std::string event = Json::FastWriter().write(result);
+ NotifyEvent("invokeContactPicker.invokeEventId", event);
+ } else if (strCommand == "getContactAccounts") {
+ return Json::FastWriter().write(webworks::PimContactsQt::GetContactAccounts());
+ }
+
+ return "";
+}
+
+bool PimContacts::CanDelete()
+{
+ return true;
+}
+
+// Notifies JavaScript of an event
+void PimContacts::NotifyEvent(const std::string& eventId, const std::string& event)
+{
+ std::string eventString = m_id + " result ";
+ eventString.append(eventId);
+ eventString.append(" ");
+ eventString.append(event);
+ SendPluginEvent(eventString.c_str(), m_pContext);
+}
+
+bool PimContacts::startThread(ThreadFunc threadFunction, Json::Value *jsonObj) {
+ webworks::PimContactsThreadInfo *thread_info = new webworks::PimContactsThreadInfo;
+ thread_info->parent = this;
+ thread_info->jsonObj = jsonObj;
+ thread_info->eventId = jsonObj->removeMember("_eventId").asString();
+
+ pthread_attr_t thread_attr;
+ pthread_attr_init(&thread_attr);
+ pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
+
+ pthread_t thread;
+ pthread_create(&thread, &thread_attr, threadFunction, static_cast<void *>(thread_info));
+ pthread_attr_destroy(&thread_attr);
+
+ if (!thread) {
+ return false;
+ }
+
+ return true;
+}
+
+
+// Static functions:
+
+void* PimContacts::FindThread(void *args)
+{
+ webworks::PimContactsThreadInfo *thread_info = static_cast<webworks::PimContactsThreadInfo *>(args);
+
+ webworks::PimContactsQt pim_qt;
+ Json::Value result = pim_qt.Find(*(thread_info->jsonObj));
+ delete thread_info->jsonObj;
+
+ std::string event = Json::FastWriter().write(result);
+ thread_info->parent->NotifyEvent(thread_info->eventId, event);
+ delete thread_info;
+
+ return NULL;
+}
+
+void* PimContacts::SaveThread(void *args)
+{
+ webworks::PimContactsThreadInfo *thread_info = static_cast<webworks::PimContactsThreadInfo *>(args);
+
+ webworks::PimContactsQt pim_qt;
+ Json::Value result = pim_qt.Save(*(thread_info->jsonObj));
+ delete thread_info->jsonObj;
+
+ std::string event = Json::FastWriter().write(result);
+ thread_info->parent->NotifyEvent(thread_info->eventId, event);
+ delete thread_info;
+
+ return NULL;
+}
+
+void* PimContacts::RemoveThread(void *args)
+{
+ webworks::PimContactsThreadInfo *thread_info = static_cast<webworks::PimContactsThreadInfo *>(args);
+
+ webworks::PimContactsQt pim_qt;
+ Json::Value result = pim_qt.DeleteContact(*(thread_info->jsonObj));
+ delete thread_info->jsonObj;
+
+ std::string event = Json::FastWriter().write(result);
+ thread_info->parent->NotifyEvent(thread_info->eventId, event);
+ delete thread_info;
+
+ return NULL;
+}
+
http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1890c10c/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/pim_contacts_js.hpp
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/pim_contacts_js.hpp b/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/pim_contacts_js.hpp
new file mode 100644
index 0000000..df8bbd7
--- /dev/null
+++ b/blackberry10/bin/templates/project/plugins/org.apache.cordova.blackberry10.pimlib/src/blackberry10/native/pim_contacts_js.hpp
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+#ifndef PIM_CONTACTS_JS_H_
+#define PIM_CONTACTS_JS_H_
+
+#include <json/value.h>
+#include <pthread.h>
+#include <string>
+#include "../common/plugin.h"
+
+typedef void* ThreadFunc(void *args);
+
+class PimContacts : public JSExt
+{
+public:
+ explicit PimContacts(const std::string& id);
+ virtual ~PimContacts() {}
+ virtual std::string InvokeMethod(const std::string& command);
+ virtual bool CanDelete();
+ void NotifyEvent(const std::string& eventId, const std::string& event);
+
+ static void* FindThread(void *args);
+ static void* SaveThread(void *args);
+ static void* RemoveThread(void *args);
+private:
+ bool startThread(ThreadFunc threadFunction, Json::Value *jsonObj);
+
+ std::string m_id;
+};
+
+#endif // PIM_CONTACTS_JS_H_