You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by st...@apache.org on 2013/12/03 00:45:20 UTC

[1/3] git commit: [ubuntu] specify policy_group

Updated Branches:
  refs/heads/dev 12ac1fd03 -> 7720e9d70


[ubuntu] specify policy_group


Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-contacts/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugin-contacts/commit/00e94efe
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-contacts/tree/00e94efe
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-contacts/diff/00e94efe

Branch: refs/heads/dev
Commit: 00e94efe155f0ebdc2895885bcbb41af77d70c11
Parents: 47a9230
Author: Maxim Ermilov <ma...@canonical.com>
Authored: Mon Nov 11 18:00:09 2013 +0400
Committer: Steven Gill <st...@gmail.com>
Committed: Mon Dec 2 15:44:38 2013 -0800

----------------------------------------------------------------------
 plugin.xml | 5 +++++
 1 file changed, 5 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-plugin-contacts/blob/00e94efe/plugin.xml
----------------------------------------------------------------------
diff --git a/plugin.xml b/plugin.xml
index 304f04b..3ea3b6a 100644
--- a/plugin.xml
+++ b/plugin.xml
@@ -88,6 +88,11 @@
     
     <!-- ubuntu -->
     <platform name="ubuntu">
+        <config-file target="config.xml" parent="/*">
+            <feature name="Camera">
+                <param policy_group="contacts" policy_version="1" />
+            </feature>
+        </config-file>
         <header-file src="src/ubuntu/contacts.h" />
         <source-file src="src/ubuntu/contacts.cpp" />
     </platform>


[3/3] git commit: fixed ubuntu policy error

Posted by st...@apache.org.
fixed ubuntu policy error


Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-contacts/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugin-contacts/commit/7720e9d7
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-contacts/tree/7720e9d7
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-contacts/diff/7720e9d7

Branch: refs/heads/dev
Commit: 7720e9d70ada386ad3b9a03f1aa045d9e2ec0c4f
Parents: 00e94ef
Author: Steven Gill <st...@gmail.com>
Authored: Mon Dec 2 15:45:16 2013 -0800
Committer: Steven Gill <st...@gmail.com>
Committed: Mon Dec 2 15:45:16 2013 -0800

----------------------------------------------------------------------
 plugin.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-plugin-contacts/blob/7720e9d7/plugin.xml
----------------------------------------------------------------------
diff --git a/plugin.xml b/plugin.xml
index 3ea3b6a..6b4cfbe 100644
--- a/plugin.xml
+++ b/plugin.xml
@@ -89,7 +89,7 @@
     <!-- ubuntu -->
     <platform name="ubuntu">
         <config-file target="config.xml" parent="/*">
-            <feature name="Camera">
+            <feature name="Contacts">
                 <param policy_group="contacts" policy_version="1" />
             </feature>
         </config-file>


[2/3] git commit: add ubuntu platform

Posted by st...@apache.org.
add ubuntu platform


Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-contacts/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugin-contacts/commit/47a92306
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-contacts/tree/47a92306
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-contacts/diff/47a92306

Branch: refs/heads/dev
Commit: 47a923063e4ebc716f960101a257bce829337db6
Parents: 12ac1fd
Author: Maxim Ermilov <er...@gmail.com>
Authored: Mon Sep 30 03:04:21 2013 +0400
Committer: Steven Gill <st...@gmail.com>
Committed: Mon Dec 2 15:44:38 2013 -0800

----------------------------------------------------------------------
 plugin.xml              |   6 +
 src/ubuntu/contacts.cpp | 576 +++++++++++++++++++++++++++++++++++++++++++
 src/ubuntu/contacts.h   |  70 ++++++
 3 files changed, 652 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-plugin-contacts/blob/47a92306/plugin.xml
----------------------------------------------------------------------
diff --git a/plugin.xml b/plugin.xml
index 1b6830f..304f04b 100644
--- a/plugin.xml
+++ b/plugin.xml
@@ -86,6 +86,12 @@
         <source-file src="src/android/ContactManager.java" target-dir="src/org/apache/cordova/contacts" />
     </platform>
     
+    <!-- ubuntu -->
+    <platform name="ubuntu">
+        <header-file src="src/ubuntu/contacts.h" />
+        <source-file src="src/ubuntu/contacts.cpp" />
+    </platform>
+
     <!-- ios -->
     <platform name="ios">
         <config-file target="config.xml" parent="/*">

http://git-wip-us.apache.org/repos/asf/cordova-plugin-contacts/blob/47a92306/src/ubuntu/contacts.cpp
----------------------------------------------------------------------
diff --git a/src/ubuntu/contacts.cpp b/src/ubuntu/contacts.cpp
new file mode 100644
index 0000000..373a276
--- /dev/null
+++ b/src/ubuntu/contacts.cpp
@@ -0,0 +1,576 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+#include "contacts.h"
+
+#if defined QTCONTACTS_USE_NAMESPACE
+QTCONTACTS_USE_NAMESPACE
+#endif
+
+Contacts::Contacts(Cordova *cordova): CPlugin(cordova) {
+    m_fieldNamePairs.clear();
+
+    m_fieldNamePairs["displayName"] = QContactDetail::TypeDisplayLabel;
+    m_fieldNamePairs["name"] = QContactDetail::TypeName;
+    m_fieldNamePairs["nickname"] = QContactDetail::TypeNickname;
+    m_fieldNamePairs["phoneNumbers"] = QContactDetail::TypePhoneNumber;
+    m_fieldNamePairs["emails"] = QContactDetail::TypeEmailAddress;
+    m_fieldNamePairs["addresses"] = QContactDetail::TypeAddress;
+    m_fieldNamePairs["ims"] = QContactDetail::TypeOnlineAccount;
+    m_fieldNamePairs["organizations"] = QContactDetail::TypeOrganization;
+    m_fieldNamePairs["birthday"] = QContactDetail::TypeBirthday;
+    m_fieldNamePairs["note"] = QContactDetail::TypeNote;
+    m_fieldNamePairs["photos"] = QContactDetail::TypeAvatar;
+    m_fieldNamePairs["urls"] = QContactDetail::TypeUrl;
+
+    m_notSupportedFields.clear();
+    m_notSupportedFields << "categories";
+    m_manager.clear();
+    m_manager = QSharedPointer<QContactManager>(new QContactManager());
+}
+
+void Contacts::save(int scId, int ecId, const QVariantMap &params) {
+    QContact result;
+    QList<QContactDetail *> detailsToDelete;
+
+    if (params.find("id") != params.end()) {
+        QString id = params.find("id")->toString();
+        if (!id.isEmpty()) {
+            result = m_manager->contact(QContactId::fromString(id));
+            result.clearDetails();
+        }
+    }
+
+    foreach (QString field, params.keys()) {
+        QContactDetail::DetailType qtDefinition = cordovaFieldNameToQtDefinition(field);
+        if (qtDefinition == QContactDetail::TypeUndefined)
+            continue;
+
+        if (field == "nickname") {
+            QContactNickname *detail = new QContactNickname;
+            detail->setNickname(params[field].toString());
+            detailsToDelete << detail;
+            result.saveDetail(detail);
+        } else if (field == "note") {
+            QContactNote *detail = new QContactNote;
+            detail->setNote(params[field].toString());
+            detailsToDelete << detail;
+            result.saveDetail(detail);
+        } else if (field == "phoneNumbers") {
+            if (params[field].type() != QVariant::List)
+                continue;
+            QVariantList phonesList = params[field].toList();
+            foreach (const QVariant &phoneDesc, phonesList) {
+                if (phoneDesc.type() != QVariant::Map)
+                    continue;
+                QContactPhoneNumber *detail = new QContactPhoneNumber;
+                detail->setNumber(phoneDesc.toMap()["value"].toString());
+                if (!phoneDesc.toMap()["type"].toString().isEmpty() &&
+                        phoneDesc.toMap()["type"].toString() != "phone")
+                    detail->setSubTypes(QList<int>() <<
+                                        subTypePhoneFromString(phoneDesc.toMap()["type"].toString()));
+                detailsToDelete << detail;
+                result.saveDetail(detail);
+            }
+        } else if (field == "emails") {
+            if (params[field].type() != QVariant::List)
+                continue;
+            QVariantList emailsList = params[field].toList();
+            foreach (const QVariant &emailDesc, emailsList) {
+                if (emailDesc.type() != QVariant::Map)
+                    continue;
+                if (emailDesc.toMap()["value"].toString().isEmpty())
+                    continue;
+                QContactEmailAddress *detail = new QContactEmailAddress;
+                detail->setEmailAddress(emailDesc.toMap()["value"].toString());
+                detailsToDelete << detail;
+                result.saveDetail(detail);
+            }
+        } else if (field == "ims") {
+            if (params[field].type() != QVariant::List)
+                continue;
+            QVariantList imsList = params[field].toList();
+            foreach (const QVariant &imDesc, imsList) {
+                if (imDesc.type() != QVariant::Map)
+                    continue;
+                QContactOnlineAccount *detail = new QContactOnlineAccount;
+                detail->setAccountUri(imDesc.toMap()["value"].toString());
+                if (!imDesc.toMap()["type"].toString().isEmpty())
+                    detail->setSubTypes(QList<int>() <<
+                                        subTypeOnlineAccountFromString(imDesc.toMap()["type"].toString()));
+                detailsToDelete << detail;
+                result.saveDetail(detail);
+            }
+        } else if (field == "photos") {
+            if (params[field].type() != QVariant::List)
+                continue;
+            QVariantList photosList = params[field].toList();
+            foreach (const QVariant &photoDesc, photosList) {
+                if (photoDesc.type() != QVariant::Map)
+                    continue;
+                //TODO: we need to decide should we support base64 images or not
+                if (photoDesc.toMap()["type"].toString() != "url")
+                    continue;
+                QContactAvatar *detail = new QContactAvatar;
+                detail->setImageUrl(QUrl(photoDesc.toMap()["value"].toString()));
+                detailsToDelete << detail;
+                result.saveDetail(detail);
+            }
+        } else if (field == "urls") {
+            if (params[field].type() != QVariant::List)
+                continue;
+            QVariantList urlsList = params[field].toList();
+            foreach (const QVariant &urlDesc, urlsList) {
+                if (urlDesc.type() != QVariant::Map)
+                    continue;
+                QContactUrl *detail = new QContactUrl;
+                detail->setUrl(urlDesc.toMap()["value"].toString());
+                if (!urlDesc.toMap()["type"].toString().isEmpty())
+                    detail->setSubType((QContactUrl::SubType) subTypeUrlFromString(urlDesc.toMap()["type"].toString()));
+                detailsToDelete << detail;
+                result.saveDetail(detail);
+            }
+        } else if (field == "birthday") {
+            QDateTime birthday;
+            birthday.setTime_t(params[field].toLongLong() / 1000);
+
+            QContactBirthday *detail = new QContactBirthday;
+            detail->setDateTime(birthday);
+            detailsToDelete << detail;
+            result.saveDetail(detail);
+        } else if (field == "organizations") {
+
+            if (params[field].type() != QVariant::List)
+                continue;
+            QVariantList organizationsList = params[field].toList();
+            foreach (const QVariant &organizationDesc, organizationsList) {
+                if (organizationDesc.type() != QVariant::Map)
+                    continue;
+                QContactOrganization *detail = new QContactOrganization;
+                detail->setName(organizationDesc.toMap()["name"].toString());
+                detail->setDepartment(QStringList() << organizationDesc.toMap()["department"].toString());
+                detail->setRole(organizationDesc.toMap()["title"].toString());
+                detailsToDelete << detail;
+                result.saveDetail(detail);
+            }
+
+        } else if (field == "name") {
+            QContactName *detail = new QContactName;
+            QVariantMap nameMap = params[field].toMap();
+            detail->setLastName(nameMap["familyName"].toString());
+            detail->setFirstName(nameMap["givenName"].toString());
+            detail->setMiddleName(nameMap["middleName"].toString());
+            detail->setPrefix(nameMap["honorificPrefix"].toString());
+            detail->setSuffix(nameMap["honorificSuffix"].toString());
+            detailsToDelete << detail;
+            result.saveDetail(detail);
+        }
+
+    }
+    if (!m_manager->saveContact(&result)) {
+        switch (m_manager->error()) {
+        case QContactManager::DoesNotExistError:
+        case QContactManager::AlreadyExistsError:
+        case QContactManager::InvalidDetailError:
+        case QContactManager::InvalidRelationshipError:
+        case QContactManager::BadArgumentError:
+        case QContactManager::InvalidContactTypeError:
+            callback(ecId, "ContactError.INVALID_ARGUMENT_ERROR");
+            break;
+        case QContactManager::DetailAccessError:
+        case QContactManager::PermissionsError:
+            callback(ecId, "ContactError.PERMISSION_DENIED_ERROR");
+            break;
+        case QContactManager::NotSupportedError:
+            callback(ecId, "ContactError.NOT_SUPPORTED_ERROR");
+            break;
+        case QContactManager::TimeoutError:
+            callback(ecId, "ContactError.TIMEOUT_ERROR");
+            break;
+        case QContactManager::UnspecifiedError:
+        case QContactManager::LockedError:
+        case QContactManager::OutOfMemoryError:
+        case QContactManager::VersionMismatchError:
+        case QContactManager::LimitReachedError:
+        case QContactManager::NoError:
+        default:
+            callback(ecId, "ContactError.UNKNOWN_ERROR");
+            break;
+        }
+    } else {
+        callback(scId, jsonedContact(result));
+    }
+    qDeleteAll(detailsToDelete);
+}
+
+void Contacts::remove(int scId, int ecId, const QString &localId) {
+    QContactId id = QContactId::fromString(localId);
+
+    if (!m_manager->removeContact(id)) {
+        switch (m_manager->error()) {
+        case QContactManager::AlreadyExistsError:
+        case QContactManager::InvalidDetailError:
+        case QContactManager::InvalidRelationshipError:
+        case QContactManager::BadArgumentError:
+        case QContactManager::InvalidContactTypeError:
+            callback(ecId, "ContactError.INVALID_ARGUMENT_ERROR");
+            break;
+        case QContactManager::DetailAccessError:
+        case QContactManager::PermissionsError:
+            callback(ecId, "ContactError.PERMISSION_DENIED_ERROR");
+            break;
+        case QContactManager::NotSupportedError:
+            callback(ecId, "ContactError.NOT_SUPPORTED_ERROR");
+            break;
+        case QContactManager::TimeoutError:
+            callback(ecId, "ContactError.TIMEOUT_ERROR");
+            break;
+        case QContactManager::UnspecifiedError:
+        case QContactManager::LockedError:
+        case QContactManager::OutOfMemoryError:
+        case QContactManager::VersionMismatchError:
+        case QContactManager::LimitReachedError:
+        case QContactManager::NoError:
+        case QContactManager::DoesNotExistError:
+        default:
+            callback(ecId, "ContactError.UNKNOWN_ERROR");
+            break;
+        }
+
+    } else {
+        cb(scId);
+    }
+}
+
+void Contacts::search(int scId, int ecId, const QStringList &fields, const QVariantMap &params) {
+    QString filter;
+    bool multiple = true;
+
+    if (params.find("filter") != params.end()) {
+        filter = params["filter"].toString();
+    }
+    if (params.find("multiple") != params.end()) {
+        multiple = params["multiple"].toBool();
+    }
+
+    findContacts(scId, ecId, fields, filter, multiple);
+}
+
+void Contacts::findContacts(int scId, int ecId, const QStringList &fields, const QString &filter, bool multiple) {
+    if (fields.length() <= 0){
+        callback(ecId, "new ContactError(ContactError.INVALID_ARGUMENT_ERROR)");
+    }
+
+    QContactUnionFilter unionFilter;
+
+    QMap<QContactDetail::DetailType, QList<int> > fieldNames;
+    fieldNames[QContactDetail::TypeDisplayLabel] << QContactDisplayLabel::FieldLabel;
+    fieldNames[QContactDetail::TypeName] << QContactName::FieldFirstName << QContactName::FieldLastName << QContactName::FieldMiddleName << QContactName::FieldPrefix << QContactName::FieldSuffix;
+    fieldNames[QContactDetail::TypeNickname] << QContactNickname::FieldNickname;
+    fieldNames[QContactDetail::TypePhoneNumber] << QContactPhoneNumber::FieldNumber;
+    fieldNames[QContactDetail::TypeEmailAddress] << QContactEmailAddress::FieldEmailAddress;
+    fieldNames[QContactDetail::TypeAddress] << QContactAddress::FieldCountry << QContactAddress::FieldLocality << QContactAddress::FieldPostcode << QContactAddress::FieldPostOfficeBox << QContactAddress::FieldRegion << QContactAddress::FieldStreet;
+    fieldNames[QContactDetail::TypeOnlineAccount] << QContactOnlineAccount::FieldAccountUri;
+    fieldNames[QContactDetail::TypeOrganization] << QContactOrganization::FieldAssistantName << QContactOrganization::FieldDepartment << QContactOrganization::FieldLocation << QContactOrganization::FieldName << QContactOrganization::FieldRole << QContactOrganization::FieldTitle;
+    fieldNames[QContactDetail::TypeBirthday] << QContactBirthday::FieldBirthday;
+    fieldNames[QContactDetail::TypeNote] << QContactNote::FieldNote;
+    fieldNames[QContactDetail::TypeUrl] << QContactUrl::FieldUrl;
+
+    foreach (const QContactDetail::DetailType &defName, fieldNames.keys()) {
+        foreach(int fieldName, fieldNames[defName]) {
+            QContactDetailFilter subFilter;
+            subFilter.setDetailType(defName, fieldName);
+            subFilter.setValue(filter);
+            subFilter.setMatchFlags(QContactFilter::MatchContains);
+            unionFilter.append(subFilter);
+        }
+    }
+
+    QList<QContact> contacts = m_manager->contacts(unionFilter);
+    if (contacts.empty()) {
+        callback(scId, "[]");
+    } else {
+        QStringList stringifiedContacts;
+        foreach (const QContact &contact, contacts) {
+            stringifiedContacts << jsonedContact(contact, fields);
+
+            if (!multiple)
+                break;
+        }
+        callback(scId, QString("[%1]").arg(stringifiedContacts.join(", ")));
+    }
+}
+
+QContactDetail::DetailType Contacts::cordovaFieldNameToQtDefinition(const QString &cordovaFieldName) const {
+    if (m_fieldNamePairs.contains(cordovaFieldName))
+        return m_fieldNamePairs[cordovaFieldName];
+
+    return QContactDetail::TypeUndefined;
+}
+
+int Contacts::subTypePhoneFromString(const QString &cordovaSubType) const
+{
+    QString preparedSubType = cordovaSubType.toLower();
+    if (preparedSubType == "mobile")
+        return QContactPhoneNumber::SubTypeMobile;
+    else if (preparedSubType == "fax")
+        return QContactPhoneNumber::SubTypeFax;
+    else if (preparedSubType == "pager")
+        return QContactPhoneNumber::SubTypePager;
+    else if (preparedSubType == "voice")
+        return QContactPhoneNumber::SubTypeVoice;
+    else if (preparedSubType == "modem")
+        return QContactPhoneNumber::SubTypeModem;
+    else if (preparedSubType == "video")
+        return QContactPhoneNumber::SubTypeVideo;
+    else if (preparedSubType == "car")
+        return QContactPhoneNumber::SubTypeCar;
+    else if (preparedSubType == "assistant")
+        return QContactPhoneNumber::SubTypeAssistant;
+    return QContactPhoneNumber::SubTypeLandline;
+}
+
+int Contacts::subTypeOnlineAccountFromString(const QString &cordovaSubType) const {
+    QString preparedSubType = cordovaSubType.toLower();
+    if (preparedSubType == "aim")
+        return QContactOnlineAccount::ProtocolAim;
+    else if (preparedSubType == "icq")
+        return QContactOnlineAccount::ProtocolIcq;
+    else if (preparedSubType == "irc")
+        return QContactOnlineAccount::ProtocolIrc;
+    else if (preparedSubType == "jabber")
+        return QContactOnlineAccount::ProtocolJabber;
+    else if (preparedSubType == "msn")
+        return QContactOnlineAccount::ProtocolMsn;
+    else if (preparedSubType == "qq")
+        return QContactOnlineAccount::ProtocolQq;
+    else if (preparedSubType == "skype")
+        return QContactOnlineAccount::ProtocolSkype;
+    else if (preparedSubType == "yahoo")
+        return QContactOnlineAccount::ProtocolYahoo;
+    return QContactOnlineAccount::ProtocolUnknown;
+}
+
+int Contacts::subTypeUrlFromString(const QString &cordovaSubType) const {
+    QString preparedSubType = cordovaSubType.toLower();
+    if (preparedSubType == "blog")
+        return QContactUrl::SubTypeBlog;
+    else if (preparedSubType == "favourite")
+        return QContactUrl::SubTypeFavourite;
+    return QContactUrl::SubTypeHomePage;
+}
+
+QString Contacts::subTypePhoneToString(int qtSubType) const {
+    if (qtSubType == QContactPhoneNumber::SubTypeMobile)
+        return "mobile";
+    else if (qtSubType == QContactPhoneNumber::SubTypeFax)
+        return "fax";
+    else if (qtSubType == QContactPhoneNumber::SubTypePager)
+        return "pager";
+    else if (qtSubType == QContactPhoneNumber::SubTypeVoice)
+        return "voice";
+    else if (qtSubType == QContactPhoneNumber::SubTypeModem)
+        return "modem";
+    else if (qtSubType == QContactPhoneNumber::SubTypeVideo)
+        return "video";
+    else if (qtSubType == QContactPhoneNumber::SubTypeCar)
+        return "car";
+    else if (qtSubType == QContactPhoneNumber::SubTypeAssistant)
+        return "assistant";
+    return "home";
+}
+
+QString Contacts::subTypeOnlineAccountToString(int qtSubType) const {
+    if (qtSubType == QContactOnlineAccount::ProtocolAim)
+        return "aim";
+    else if (qtSubType == QContactOnlineAccount::ProtocolIcq)
+        return "icq";
+    else if (qtSubType == QContactOnlineAccount::ProtocolIrc)
+        return "irc";
+    else if (qtSubType == QContactOnlineAccount::ProtocolJabber)
+        return "jabber";
+    else if (qtSubType == QContactOnlineAccount::ProtocolMsn)
+        return "msn";
+    else if (qtSubType == QContactOnlineAccount::ProtocolQq)
+        return "qq";
+    else if (qtSubType == QContactOnlineAccount::ProtocolSkype)
+        return "skype";
+    else if (qtSubType == QContactOnlineAccount::ProtocolYahoo)
+        return "yahoo";
+    return "unknown";
+}
+
+QString Contacts::subTypeUrlToString(int qtSubType) const {
+    if (qtSubType == QContactUrl::SubTypeBlog)
+        return "blog";
+    else if (qtSubType == QContactUrl::SubTypeFavourite)
+        return "favourite";
+    return "homepage";
+}
+
+QString Contacts::jsonedContact(const QContact &contact, const QStringList &fields) const {
+    QStringList resultingFields = fields;
+    if (resultingFields.empty())
+        resultingFields.append(m_fieldNamePairs.keys());
+    if (!resultingFields.contains("id"))
+        resultingFields << "id";
+    QStringList fieldValuesList;
+    foreach (const QString &field, resultingFields) {
+        QContactDetail::DetailType qtDefinitionName = cordovaFieldNameToQtDefinition(field);
+        if (field == "id") {
+            fieldValuesList << QString("%1: \"%2\"")
+                               .arg(field)
+                               .arg(contact.id().toString());
+        } else if (field == "displayName") {
+            QContactDisplayLabel detail = contact.detail(qtDefinitionName);
+            fieldValuesList << QString("%1: \"%2\"")
+                               .arg(field)
+                               .arg(detail.label());
+        } else if (field == "nickname") {
+            QContactNickname detail = contact.detail(qtDefinitionName);
+            fieldValuesList << QString("%1: \"%2\"")
+                               .arg(field)
+                               .arg(detail.nickname());
+        } else if (field == "note") {
+            QContactNote detail = contact.detail(qtDefinitionName);
+            fieldValuesList << QString("%1: \"%2\"")
+                               .arg(field)
+                               .arg(detail.note());
+        } else if (field == "phoneNumbers") {
+            QStringList fieldValues;
+            QList<QContactDetail> details = contact.details(qtDefinitionName);
+            foreach (const QContactDetail &detail, details) {
+                QContactPhoneNumber castedDetail = detail;
+                QStringList subTypes;
+                foreach (int subType, castedDetail.subTypes())
+                    subTypes << subTypePhoneToString(subType);
+
+                if (subTypes.isEmpty())
+                    subTypes << "phone";
+                foreach(const QString &subType, subTypes) {
+                    fieldValues << QString("{type: \"%1\", value: \"%2\", pref: %3}")
+                                   .arg(subType)
+                                   .arg(castedDetail.number())
+                                   .arg("false");
+                }
+            }
+            fieldValuesList << QString("%1: [%2]")
+                               .arg(field)
+                               .arg(fieldValues.join(", "));
+        } else if (field == "emails") {
+            QStringList fieldValues;
+            QList<QContactDetail> details = contact.details(qtDefinitionName);
+            foreach (const QContactDetail &detail, details) {
+                QContactEmailAddress castedDetail = detail;
+                fieldValues << QString("{type: \"%1\", value: \"%2\", pref: %3}")
+                               .arg("email")
+                               .arg(castedDetail.emailAddress())
+                               .arg("false");
+            }
+            fieldValuesList << QString("%1: [%2]")
+                               .arg(field)
+                               .arg(fieldValues.join(", "));
+        } else if (field == "ims") {
+            QStringList fieldValues;
+            QList<QContactDetail> details = contact.details(qtDefinitionName);
+            foreach (const QContactDetail &detail, details) {
+                QContactOnlineAccount castedDetail = detail;
+                QStringList subTypes;
+                foreach (int subType, castedDetail.subTypes())
+                    subTypes << subTypeOnlineAccountToString(subType);
+
+                if (subTypes.isEmpty())
+                    subTypes << "IM";
+                foreach(const QString &subType, subTypes) {
+                    fieldValues << QString("{type: \"%1\", value: \"%2\", pref: %3}")
+                                   .arg(subType)
+                                   .arg(castedDetail.accountUri())
+                                   .arg("false");
+                }
+            }
+            fieldValuesList << QString("%1: [%2]")
+                               .arg(field)
+                               .arg(fieldValues.join(", "));
+        } else if (field == "photos") {
+            QStringList fieldValues;
+            QList<QContactDetail> details = contact.details(qtDefinitionName);
+            foreach (const QContactDetail &detail, details) {
+                QContactAvatar castedDetail = detail;
+                fieldValues << QString("{type: \"%1\", value: \"%2\", pref: %3}")
+                               .arg("url")
+                               .arg(castedDetail.imageUrl().toString())
+                               .arg("false");
+            }
+            fieldValuesList << QString("%1: [%2]")
+                               .arg(field)
+                               .arg(fieldValues.join(", "));
+        } else if (field == "urls") {
+            QStringList fieldValues;
+            QList<QContactDetail> details = contact.details(qtDefinitionName);
+
+            foreach (const QContactDetail &detail, details) {
+                QContactUrl castedDetail = detail;
+                QString subType = subTypeUrlToString(castedDetail.subType());
+
+                fieldValues << QString("{type: \"%1\", value: \"%2\", pref: %3}")
+                               .arg(subType)
+                               .arg(castedDetail.url())
+                               .arg("false");
+            }
+            fieldValuesList << QString("%1: [%2]")
+                               .arg(field)
+                               .arg(fieldValues.join(", "));
+        } else if (field == "birthday") {
+            QContactBirthday detail = contact.detail(qtDefinitionName);
+            fieldValuesList << QString("%1: %2")
+                               .arg(field)
+                               .arg(detail.dateTime().toMSecsSinceEpoch());
+        } else if (field == "organizations") {
+            QStringList fieldValues;
+            QList<QContactDetail> details = contact.details(qtDefinitionName);
+            foreach (const QContactDetail &detail, details) {
+                QContactOrganization castedDetail = detail;
+                fieldValues << QString("{type: \"%1\", name: \"%2\", department: \"%3\", title: \"%4\", pref: %5}")
+                               .arg("organization")
+                               .arg(castedDetail.name())
+                               .arg(castedDetail.department().join(" "))
+                               .arg(castedDetail.role())
+                               .arg("false");
+            }
+            fieldValuesList << QString("%1: [%2]")
+                               .arg(field)
+                               .arg(fieldValues.join(", "));
+        } else if (field == "name") {
+            QContactName detail = contact.detail(qtDefinitionName);
+            fieldValuesList <<  QString("%1: {familyName: \"%2\", givenName: \"%3\", middleName: \"%4\", honorificPrefix: \"%5\", honorificSuffix: \"%6\"}")
+                                .arg(field)
+                                .arg(detail.lastName())
+                                .arg(detail.firstName())
+                                .arg(detail.middleName())
+                                .arg(detail.prefix())
+                                .arg(detail.suffix());
+        }
+
+
+    }
+
+    return QString("{%1}").arg(fieldValuesList.join(", "));
+}

http://git-wip-us.apache.org/repos/asf/cordova-plugin-contacts/blob/47a92306/src/ubuntu/contacts.h
----------------------------------------------------------------------
diff --git a/src/ubuntu/contacts.h b/src/ubuntu/contacts.h
new file mode 100644
index 0000000..4c1343b
--- /dev/null
+++ b/src/ubuntu/contacts.h
@@ -0,0 +1,70 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+#ifndef CONTACTS_H_SSSSSSS
+#define CONTACTS_H_SSSSSSS
+
+#include <cplugin.h>
+
+#include <QtContacts>
+#include <QtCore>
+
+QTCONTACTS_USE_NAMESPACE
+
+class Contacts : public CPlugin {
+    Q_OBJECT
+public:
+    explicit Contacts(Cordova *cordova);
+
+    virtual const QString fullName() override {
+        return Contacts::fullID();
+    }
+
+    virtual const QString shortName() override {
+        return "Contacts";
+    }
+
+    static const QString fullID() {
+        return "Contacts";
+    }
+
+public slots:
+    void save(int scId, int ecId, const QVariantMap &params);
+    void remove(int scId, int ecId, const QString &localId);
+    void search(int scId, int ecId, const QStringList &fields, const QVariantMap &params);
+
+private:
+    void findContacts(int scId, int ecId, const QStringList &fields, const QString &filter, bool multiple);
+    QContactDetail::DetailType cordovaFieldNameToQtDefinition(const QString &cordovaFieldName) const;
+    int subTypePhoneFromString(const QString &cordovaSubType) const;
+    int subTypeOnlineAccountFromString(const QString &cordovaSubType) const;
+    int subTypeUrlFromString(const QString &cordovaSubType) const;
+    QString subTypePhoneToString(int qtSubType) const;
+    QString subTypeOnlineAccountToString(int qtSubType) const;
+    QString subTypeUrlToString(int qtSubType) const;
+    QString jsonedContact(const QContact &contact, const QStringList &fields = QStringList()) const;
+
+    QHash<QString, QContactDetail::DetailType> m_fieldNamePairs;
+    QSet<QString> m_notSupportedFields;
+    QSharedPointer<QContactManager> m_manager;
+};
+
+#endif