Updating Contacts for June 16th W3C Spec

This commit is contained in:
macdonst 2011-06-24 22:55:19 +08:00
parent 5de4ae7554
commit 22a9cabeb9
5 changed files with 416 additions and 178 deletions

View File

@ -21,17 +21,14 @@ PhoneGap.addResource("contact");
* @param {Array.<ContactAddress>} addresses array of addresses * @param {Array.<ContactAddress>} addresses array of addresses
* @param {Array.<ContactField>} ims instant messaging user ids * @param {Array.<ContactField>} ims instant messaging user ids
* @param {Array.<ContactOrganization>} organizations * @param {Array.<ContactOrganization>} organizations
* @param {DOMString} revision date contact was last updated
* @param {DOMString} birthday contact's birthday * @param {DOMString} birthday contact's birthday
* @param {DOMString} gender contact's gender
* @param {DOMString} note user notes about contact * @param {DOMString} note user notes about contact
* @param {Array.<ContactField>} photos * @param {Array.<ContactField>} photos
* @param {Array.<ContactField>} categories * @param {Array.<ContactField>} categories
* @param {Array.<ContactField>} urls contact's web sites * @param {Array.<ContactField>} urls contact's web sites
* @param {DOMString} timezone the contacts time zone
*/ */
var Contact = function (id, displayName, name, nickname, phoneNumbers, emails, addresses, var Contact = function (id, displayName, name, nickname, phoneNumbers, emails, addresses,
ims, organizations, revision, birthday, gender, note, photos, categories, urls, timezone) { ims, organizations, birthday, note, photos, categories, urls) {
this.id = id || null; this.id = id || null;
this.rawId = null; this.rawId = null;
this.displayName = displayName || null; this.displayName = displayName || null;
@ -42,14 +39,11 @@ var Contact = function (id, displayName, name, nickname, phoneNumbers, emails, a
this.addresses = addresses || null; // ContactAddress[] this.addresses = addresses || null; // ContactAddress[]
this.ims = ims || null; // ContactField[] this.ims = ims || null; // ContactField[]
this.organizations = organizations || null; // ContactOrganization[] this.organizations = organizations || null; // ContactOrganization[]
this.revision = revision || null;
this.birthday = birthday || null; this.birthday = birthday || null;
this.gender = gender || null;
this.note = note || null; this.note = note || null;
this.photos = photos || null; // ContactField[] this.photos = photos || null; // ContactField[]
this.categories = categories || null; // ContactField[] this.categories = categories || null; // ContactField[]
this.urls = urls || null; // ContactField[] this.urls = urls || null; // ContactField[]
this.timezone = timezone || null;
}; };
/** /**
@ -66,11 +60,10 @@ var ContactError = function() {
*/ */
ContactError.UNKNOWN_ERROR = 0; ContactError.UNKNOWN_ERROR = 0;
ContactError.INVALID_ARGUMENT_ERROR = 1; ContactError.INVALID_ARGUMENT_ERROR = 1;
ContactError.NOT_FOUND_ERROR = 2; ContactError.TIMEOUT_ERROR = 2;
ContactError.TIMEOUT_ERROR = 3; ContactError.PENDING_OPERATION_ERROR = 3;
ContactError.PENDING_OPERATION_ERROR = 4; ContactError.IO_ERROR = 4;
ContactError.IO_ERROR = 5; ContactError.NOT_SUPPORTED_ERROR = 5;
ContactError.NOT_SUPPORTED_ERROR = 6;
ContactError.PERMISSION_DENIED_ERROR = 20; ContactError.PERMISSION_DENIED_ERROR = 20;
/** /**
@ -81,7 +74,7 @@ ContactError.PERMISSION_DENIED_ERROR = 20;
Contact.prototype.remove = function(successCB, errorCB) { Contact.prototype.remove = function(successCB, errorCB) {
if (this.id === null) { if (this.id === null) {
var errorObj = new ContactError(); var errorObj = new ContactError();
errorObj.code = ContactError.NOT_FOUND_ERROR; errorObj.code = ContactError.UNKNOWN_ERROR;
errorCB(errorObj); errorCB(errorObj);
} }
else { else {
@ -197,8 +190,10 @@ var ContactField = function(type, value, pref) {
* @param postalCode * @param postalCode
* @param country * @param country
*/ */
var ContactAddress = function(formatted, streetAddress, locality, region, postalCode, country) { var ContactAddress = function(pref, type, formatted, streetAddress, locality, region, postalCode, country) {
this.id = null; this.id = null;
this.pref = pref || null;
this.type = type || null;
this.formatted = formatted || null; this.formatted = formatted || null;
this.streetAddress = streetAddress || null; this.streetAddress = streetAddress || null;
this.locality = locality || null; this.locality = locality || null;
@ -219,8 +214,10 @@ var ContactAddress = function(formatted, streetAddress, locality, region, postal
* @param location * @param location
* @param desc * @param desc
*/ */
var ContactOrganization = function(name, dept, title) { var ContactOrganization = function(pref, type, name, dept, title) {
this.id = null; this.id = null;
this.pref = pref || null;
this.type = type || null;
this.name = name || null; this.name = name || null;
this.department = dept || null; this.department = dept || null;
this.title = title || null; this.title = title || null;
@ -243,7 +240,16 @@ var Contacts = function() {
* @return array of Contacts matching search criteria * @return array of Contacts matching search criteria
*/ */
Contacts.prototype.find = function(fields, successCB, errorCB, options) { Contacts.prototype.find = function(fields, successCB, errorCB, options) {
if (successCB === null) {
throw new TypeError("You must specify a success callback for the find command.");
}
if (fields === null || fields === "undefined" || fields.length === "undefined" || fields.length <= 0) {
if (typeof errorCB === "function") {
errorCB({"code": ContactError.INVALID_ARGUMENT_ERROR});
}
} else {
PhoneGap.exec(successCB, errorCB, "Contacts", "search", [fields, options]); PhoneGap.exec(successCB, errorCB, "Contacts", "search", [fields, options]);
}
}; };
/** /**
@ -267,7 +273,7 @@ Contacts.prototype.create = function(properties) {
/** /**
* This function returns and array of contacts. It is required as we need to convert raw * This function returns and array of contacts. It is required as we need to convert raw
* JSON objects into concrete Contact objects. Currently this method is called after * JSON objects into concrete Contact objects. Currently this method is called after
* navigator.service.contacts.find but before the find methods success call back. * navigator.contacts.find but before the find methods success call back.
* *
* @param jsonArray an array of JSON Objects that need to be converted to Contact objects. * @param jsonArray an array of JSON Objects that need to be converted to Contact objects.
* @returns an array of Contact objects * @returns an array of Contact objects
@ -276,7 +282,7 @@ Contacts.prototype.cast = function(pluginResult) {
var contacts = []; var contacts = [];
var i; var i;
for (i=0; i<pluginResult.message.length; i++) { for (i=0; i<pluginResult.message.length; i++) {
contacts.push(navigator.service.contacts.create(pluginResult.message[i])); contacts.push(navigator.contacts.create(pluginResult.message[i]));
} }
pluginResult.message = contacts; pluginResult.message = contacts;
return pluginResult; return pluginResult;
@ -287,23 +293,18 @@ Contacts.prototype.cast = function(pluginResult) {
* @constructor * @constructor
* @param filter used to match contacts against * @param filter used to match contacts against
* @param multiple boolean used to determine if more than one contact should be returned * @param multiple boolean used to determine if more than one contact should be returned
* @param updatedSince return only contact records that have been updated on or after the given time
*/ */
var ContactFindOptions = function(filter, multiple, updatedSince) { var ContactFindOptions = function(filter, multiple) {
this.filter = filter || ''; this.filter = filter || '';
this.multiple = multiple || true; this.multiple = multiple || false;
this.updatedSince = updatedSince || '';
}; };
/** /**
* Add the contact interface into the browser. * Add the contact interface into the browser.
*/ */
PhoneGap.addConstructor(function() { PhoneGap.addConstructor(function() {
if(typeof navigator.service === "undefined") { if(typeof navigator.contacts === "undefined") {
navigator.service = {}; navigator.contacts = new Contacts();
}
if(typeof navigator.service.contacts === "undefined") {
navigator.service.contacts = new Contacts();
} }
}); });
} }

View File

@ -114,6 +114,22 @@ public abstract class ContactAccessor {
String key; String key;
try { try {
if (fields.length() == 1 && fields.getString(0).equals("*")) {
map.put("displayName", true);
map.put("name", true);
map.put("nickname", true);
map.put("phoneNumbers", true);
map.put("emails", true);
map.put("addresses", true);
map.put("ims", true);
map.put("organizations", true);
map.put("birthday", true);
map.put("note", true);
map.put("urls", true);
map.put("photos", true);
map.put("categories", true);
}
else {
for (int i=0; i<fields.length(); i++) { for (int i=0; i<fields.length(); i++) {
key = fields.getString(i); key = fields.getString(i);
if (key.startsWith("displayName")) { if (key.startsWith("displayName")) {
@ -143,21 +159,19 @@ public abstract class ContactAccessor {
else if (key.startsWith("birthday")) { else if (key.startsWith("birthday")) {
map.put("birthday", true); map.put("birthday", true);
} }
else if (key.startsWith("anniversary")) {
map.put("anniversary", true);
}
else if (key.startsWith("note")) { else if (key.startsWith("note")) {
map.put("note", true); map.put("note", true);
} }
else if (key.startsWith("relationships")) {
map.put("relationships", true);
}
else if (key.startsWith("urls")) { else if (key.startsWith("urls")) {
map.put("urls", true); map.put("urls", true);
} }
else if (key.startsWith("photos")) { else if (key.startsWith("photos")) {
map.put("photos", true); map.put("photos", true);
} }
else if (key.startsWith("categories")) {
map.put("categories", true);
}
}
} }
} }
catch (JSONException e) { catch (JSONException e) {
@ -196,13 +210,19 @@ public abstract class ContactAccessor {
* Handles adding a JSON Contact object into the database. * Handles adding a JSON Contact object into the database.
* @return TODO * @return TODO
*/ */
public abstract boolean save(JSONObject contact); public abstract String save(JSONObject contact);
/** /**
* Handles searching through SDK-specific contacts API. * Handles searching through SDK-specific contacts API.
*/ */
public abstract JSONArray search(JSONArray filter, JSONObject options); public abstract JSONArray search(JSONArray filter, JSONObject options);
/**
* Handles searching through SDK-specific contacts API.
* @throws JSONException
*/
public abstract JSONObject getContactById(String id) throws JSONException;
/** /**
* Handles removing a contact from the database. * Handles removing a contact from the database.
*/ */

View File

@ -451,7 +451,7 @@ public class ContactAccessorSdk3_4 extends ContactAccessor {
* @returns true if the contact is successfully saved, false otherwise. * @returns true if the contact is successfully saved, false otherwise.
*/ */
@Override @Override
public boolean save(JSONObject contact) { public String save(JSONObject contact) {
ContentValues personValues = new ContentValues(); ContentValues personValues = new ContentValues();
String id = getJsonString(contact, "id"); String id = getJsonString(contact, "id");
@ -492,9 +492,9 @@ public class ContactAccessorSdk3_4 extends ContactAccessor {
saveEntries(contact, newPersonUri, "ims", Contacts.KIND_IM); saveEntries(contact, newPersonUri, "ims", Contacts.KIND_IM);
// Successfully create a Contact // Successfully create a Contact
return true; return id;
} }
return false; return null;
} }
/** /**
@ -824,4 +824,10 @@ public class ContactAccessorSdk3_4 extends ContactAccessor {
return (result > 0) ? true : false; return (result > 0) ? true : false;
} }
@Override
public JSONObject getContactById(String id) throws JSONException {
// TODO Auto-generated method stub
return null;
}
} }

View File

@ -46,6 +46,7 @@ import android.accounts.Account;
import android.accounts.AccountManager; import android.accounts.AccountManager;
import android.app.Activity; import android.app.Activity;
import android.content.ContentProviderOperation; import android.content.ContentProviderOperation;
import android.content.ContentProviderResult;
import android.content.ContentUris; import android.content.ContentUris;
import android.content.ContentValues; import android.content.ContentValues;
import android.content.OperationApplicationException; import android.content.OperationApplicationException;
@ -88,7 +89,7 @@ public class ContactAccessorSdk5 extends ContactAccessor {
*/ */
private static final Map<String, String> dbMap = new HashMap<String, String>(); private static final Map<String, String> dbMap = new HashMap<String, String>();
static { static {
dbMap.put("id", ContactsContract.Contacts._ID); dbMap.put("id", ContactsContract.Data.CONTACT_ID);
dbMap.put("displayName", ContactsContract.Contacts.DISPLAY_NAME); dbMap.put("displayName", ContactsContract.Contacts.DISPLAY_NAME);
dbMap.put("name", ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME); dbMap.put("name", ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME);
dbMap.put("name.formatted", ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME); dbMap.put("name.formatted", ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME);
@ -115,14 +116,12 @@ public class ContactAccessorSdk5 extends ContactAccessor {
dbMap.put("organizations.name", ContactsContract.CommonDataKinds.Organization.COMPANY); dbMap.put("organizations.name", ContactsContract.CommonDataKinds.Organization.COMPANY);
dbMap.put("organizations.department", ContactsContract.CommonDataKinds.Organization.DEPARTMENT); dbMap.put("organizations.department", ContactsContract.CommonDataKinds.Organization.DEPARTMENT);
dbMap.put("organizations.title", ContactsContract.CommonDataKinds.Organization.TITLE); dbMap.put("organizations.title", ContactsContract.CommonDataKinds.Organization.TITLE);
//dbMap.put("revision", null);
dbMap.put("birthday", ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE); dbMap.put("birthday", ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE);
dbMap.put("note", ContactsContract.CommonDataKinds.Note.NOTE); dbMap.put("note", ContactsContract.CommonDataKinds.Note.NOTE);
dbMap.put("photos.value", ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE); dbMap.put("photos.value", ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE);
//dbMap.put("categories.value", null); //dbMap.put("categories.value", null);
dbMap.put("urls", ContactsContract.CommonDataKinds.Website.URL); dbMap.put("urls", ContactsContract.CommonDataKinds.Website.URL);
dbMap.put("urls.value", ContactsContract.CommonDataKinds.Website.URL); dbMap.put("urls.value", ContactsContract.CommonDataKinds.Website.URL);
//dbMap.put("timezone", null);
} }
/** /**
@ -142,9 +141,6 @@ public class ContactAccessorSdk5 extends ContactAccessor {
*/ */
@Override @Override
public JSONArray search(JSONArray fields, JSONObject options) { public JSONArray search(JSONArray fields, JSONObject options) {
long totalEnd;
long totalStart = System.currentTimeMillis();
// Get the find options // Get the find options
String searchTerm = ""; String searchTerm = "";
int limit = Integer.MAX_VALUE; int limit = Integer.MAX_VALUE;
@ -206,8 +202,49 @@ public class ContactAccessorSdk5 extends ContactAccessor {
idOptions.getWhereArgs(), idOptions.getWhereArgs(),
ContactsContract.Data.CONTACT_ID + " ASC"); ContactsContract.Data.CONTACT_ID + " ASC");
JSONArray contacts = populateContactArray(limit, populate, c);
return contacts;
}
//Log.d(LOG_TAG, "Cursor length = " + c.getCount()); /**
* A special search that finds one contact by id
*
* @param id contact to find by id
* @return a JSONObject representing the contact
* @throws JSONException
*/
public JSONObject getContactById(String id) throws JSONException {
// Do the id query
Cursor c = mApp.getContentResolver().query(ContactsContract.Data.CONTENT_URI,
null,
ContactsContract.Data.CONTACT_ID + " = ? ",
new String[] { id },
ContactsContract.Data.CONTACT_ID + " ASC");
JSONArray fields = new JSONArray();
fields.put("*");
HashMap<String,Boolean> populate = buildPopulationSet(fields);
JSONArray contacts = populateContactArray(1, populate, c);
if (contacts.length() == 1) {
return contacts.getJSONObject(0);
} else {
return null;
}
}
/**
* Creates an array of contacts from the cursor you pass in
*
* @param limit max number of contacts for the array
* @param populate whether or not you should populate a certain value
* @param c the cursor
* @return a JSONArray of contacts
*/
private JSONArray populateContactArray(int limit,
HashMap<String, Boolean> populate, Cursor c) {
String contactId = ""; String contactId = "";
String rawId = ""; String rawId = "";
@ -334,10 +371,6 @@ public class ContactAccessorSdk5 extends ContactAccessor {
} }
} }
c.close(); c.close();
totalEnd = System.currentTimeMillis();
Log.d(LOG_TAG,"Total time = " + (totalEnd-totalStart));
return contacts; return contacts;
} }
@ -420,7 +453,59 @@ public class ContactAccessorSdk5 extends ContactAccessor {
WhereOptions options = new WhereOptions(); WhereOptions options = new WhereOptions();
/* /*
* Special case for when the user wants all the contacts * Special case where the user wants all fields returned
*/
if (isWildCardSearch(fields)) {
// Get all contacts with all properties
if ("%".equals(searchTerm)) {
options.setWhere("(" + ContactsContract.Contacts.DISPLAY_NAME + " LIKE ? )");
options.setWhereArgs(new String[] {searchTerm});
return options;
} else {
// Get all contacts that match the filter but return all properties
where.add("(" + dbMap.get("displayName") + " LIKE ? )");
whereArgs.add(searchTerm);
where.add("(" + dbMap.get("name") + " LIKE ? AND "
+ ContactsContract.Data.MIMETYPE + " = ? )");
whereArgs.add(searchTerm);
whereArgs.add(ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
where.add("(" + dbMap.get("nickname") + " LIKE ? AND "
+ ContactsContract.Data.MIMETYPE + " = ? )");
whereArgs.add(searchTerm);
whereArgs.add(ContactsContract.CommonDataKinds.Nickname.CONTENT_ITEM_TYPE);
where.add("(" + dbMap.get("phoneNumbers") + " LIKE ? AND "
+ ContactsContract.Data.MIMETYPE + " = ? )");
whereArgs.add(searchTerm);
whereArgs.add(ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE);
where.add("(" + dbMap.get("emails") + " LIKE ? AND "
+ ContactsContract.Data.MIMETYPE + " = ? )");
whereArgs.add(searchTerm);
whereArgs.add(ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE);
where.add("(" + dbMap.get("addresses") + " LIKE ? AND "
+ ContactsContract.Data.MIMETYPE + " = ? )");
whereArgs.add(searchTerm);
whereArgs.add(ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE);
where.add("(" + dbMap.get("ims") + " LIKE ? AND "
+ ContactsContract.Data.MIMETYPE + " = ? )");
whereArgs.add(searchTerm);
whereArgs.add(ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE);
where.add("(" + dbMap.get("organizations") + " LIKE ? AND "
+ ContactsContract.Data.MIMETYPE + " = ? )");
whereArgs.add(searchTerm);
whereArgs.add(ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE);
where.add("(" + dbMap.get("note") + " LIKE ? AND "
+ ContactsContract.Data.MIMETYPE + " = ? )");
whereArgs.add(searchTerm);
whereArgs.add(ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE);
where.add("(" + dbMap.get("urls") + " LIKE ? AND "
+ ContactsContract.Data.MIMETYPE + " = ? )");
whereArgs.add(searchTerm);
whereArgs.add(ContactsContract.CommonDataKinds.Website.CONTENT_ITEM_TYPE);
}
}
/*
* Special case for when the user wants all the contacts but
*/ */
if ("%".equals(searchTerm)) { if ("%".equals(searchTerm)) {
options.setWhere("(" + ContactsContract.Contacts.DISPLAY_NAME + " LIKE ? )"); options.setWhere("(" + ContactsContract.Contacts.DISPLAY_NAME + " LIKE ? )");
@ -434,7 +519,11 @@ public class ContactAccessorSdk5 extends ContactAccessor {
for (int i=0; i<fields.length(); i++) { for (int i=0; i<fields.length(); i++) {
key = fields.getString(i); key = fields.getString(i);
if (key.startsWith("displayName")) { if (key.equals("id")) {
where.add("(" + dbMap.get(key) + " = ? )");
whereArgs.add(searchTerm.substring(1, searchTerm.length()-1));
}
else if (key.startsWith("displayName")) {
where.add("(" + dbMap.get(key) + " LIKE ? )"); where.add("(" + dbMap.get(key) + " LIKE ? )");
whereArgs.add(searchTerm); whereArgs.add(searchTerm);
} }
@ -522,6 +611,26 @@ public class ContactAccessorSdk5 extends ContactAccessor {
return options; return options;
} }
/**
* If the user passes in the '*' wildcard character for search then they want all fields for each contact
*
* @param fields
* @return true if wildcard search requested, false otherwise
*/
private boolean isWildCardSearch(JSONArray fields) {
// Only do a wildcard search if we are passed ["*"]
if (fields.length() == 1) {
try {
if ("*".equals(fields.getString(0))) {
return true;
}
} catch (JSONException e) {
return false;
}
}
return false;
}
/** /**
* Create a ContactOrganization JSONObject * Create a ContactOrganization JSONObject
* @param cursor the current database row * @param cursor the current database row
@ -531,6 +640,8 @@ public class ContactAccessorSdk5 extends ContactAccessor {
JSONObject organization = new JSONObject(); JSONObject organization = new JSONObject();
try { try {
organization.put("id", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Organization._ID))); organization.put("id", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Organization._ID)));
organization.put("pref", false); // Android does not store pref attribute
organization.put("type", getOrgType(cursor.getInt(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Organization.TYPE))));
organization.put("department", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Organization.DEPARTMENT))); organization.put("department", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Organization.DEPARTMENT)));
organization.put("name", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Organization.COMPANY))); organization.put("name", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Organization.COMPANY)));
organization.put("title", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Organization.TITLE))); organization.put("title", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Organization.TITLE)));
@ -549,6 +660,8 @@ public class ContactAccessorSdk5 extends ContactAccessor {
JSONObject address = new JSONObject(); JSONObject address = new JSONObject();
try { try {
address.put("id", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal._ID))); address.put("id", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal._ID)));
address.put("pref", false); // Android does not store pref attribute
address.put("type", getAddressType(cursor.getInt(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Organization.TYPE))));
address.put("formatted", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS))); address.put("formatted", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS)));
address.put("streetAddress", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.STREET))); address.put("streetAddress", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.STREET)));
address.put("locality", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.CITY))); address.put("locality", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.CITY)));
@ -695,9 +808,9 @@ public class ContactAccessorSdk5 extends ContactAccessor {
* This method will save a contact object into the devices contacts database. * This method will save a contact object into the devices contacts database.
* *
* @param contact the contact to be saved. * @param contact the contact to be saved.
* @returns true if the contact is successfully saved, false otherwise. * @returns the id if the contact is successfully saved, null otherwise.
*/ */
public boolean save(JSONObject contact) { public String save(JSONObject contact) {
AccountManager mgr = AccountManager.get(mApp); AccountManager mgr = AccountManager.get(mApp);
Account[] accounts = mgr.getAccounts(); Account[] accounts = mgr.getAccounts();
Account account = null; Account account = null;
@ -732,8 +845,9 @@ public class ContactAccessorSdk5 extends ContactAccessor {
} }
} }
if(account == null) if(account == null) {
return false; return null;
}
String id = getJsonString(contact, "id"); String id = getJsonString(contact, "id");
// Create new contact // Create new contact
@ -753,7 +867,7 @@ public class ContactAccessorSdk5 extends ContactAccessor {
* @param contact the contact to be saved * @param contact the contact to be saved
* @param account the account to be saved under * @param account the account to be saved under
*/ */
private boolean modifyContact(String id, JSONObject contact, Account account) { private String modifyContact(String id, JSONObject contact, Account account) {
// Get the RAW_CONTACT_ID which is needed to insert new values in an already existing contact. // Get the RAW_CONTACT_ID which is needed to insert new values in an already existing contact.
// But not needed to update existing values. // But not needed to update existing values.
int rawId = (new Integer(getJsonString(contact,"rawId"))).intValue(); int rawId = (new Integer(getJsonString(contact,"rawId"))).intValue();
@ -894,6 +1008,7 @@ public class ContactAccessorSdk5 extends ContactAccessor {
ContentValues contentValues = new ContentValues(); ContentValues contentValues = new ContentValues();
contentValues.put(ContactsContract.Data.RAW_CONTACT_ID, rawId); contentValues.put(ContactsContract.Data.RAW_CONTACT_ID, rawId);
contentValues.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE); contentValues.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE);
contentValues.put(ContactsContract.CommonDataKinds.StructuredPostal.TYPE, getAddressType(getJsonString(address, "type")));
contentValues.put(ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS, getJsonString(address, "formatted")); contentValues.put(ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS, getJsonString(address, "formatted"));
contentValues.put(ContactsContract.CommonDataKinds.StructuredPostal.STREET, getJsonString(address, "streetAddress")); contentValues.put(ContactsContract.CommonDataKinds.StructuredPostal.STREET, getJsonString(address, "streetAddress"));
contentValues.put(ContactsContract.CommonDataKinds.StructuredPostal.CITY, getJsonString(address, "locality")); contentValues.put(ContactsContract.CommonDataKinds.StructuredPostal.CITY, getJsonString(address, "locality"));
@ -910,6 +1025,7 @@ public class ContactAccessorSdk5 extends ContactAccessor {
.withSelection(ContactsContract.CommonDataKinds.StructuredPostal._ID + "=? AND " + .withSelection(ContactsContract.CommonDataKinds.StructuredPostal._ID + "=? AND " +
ContactsContract.Data.MIMETYPE + "=?", ContactsContract.Data.MIMETYPE + "=?",
new String[]{addressId, ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE}) new String[]{addressId, ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE})
.withValue(ContactsContract.CommonDataKinds.StructuredPostal.TYPE, getAddressType(getJsonString(address, "type")))
.withValue(ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS, getJsonString(address, "formatted")) .withValue(ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS, getJsonString(address, "formatted"))
.withValue(ContactsContract.CommonDataKinds.StructuredPostal.STREET, getJsonString(address, "streetAddress")) .withValue(ContactsContract.CommonDataKinds.StructuredPostal.STREET, getJsonString(address, "streetAddress"))
.withValue(ContactsContract.CommonDataKinds.StructuredPostal.CITY, getJsonString(address, "locality")) .withValue(ContactsContract.CommonDataKinds.StructuredPostal.CITY, getJsonString(address, "locality"))
@ -938,6 +1054,7 @@ public class ContactAccessorSdk5 extends ContactAccessor {
ContentValues contentValues = new ContentValues(); ContentValues contentValues = new ContentValues();
contentValues.put(ContactsContract.Data.RAW_CONTACT_ID, rawId); contentValues.put(ContactsContract.Data.RAW_CONTACT_ID, rawId);
contentValues.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE); contentValues.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE);
contentValues.put(ContactsContract.CommonDataKinds.Organization.TYPE, getOrgType(getJsonString(org, "type")));
contentValues.put(ContactsContract.CommonDataKinds.Organization.DEPARTMENT, getJsonString(org, "department")); contentValues.put(ContactsContract.CommonDataKinds.Organization.DEPARTMENT, getJsonString(org, "department"));
contentValues.put(ContactsContract.CommonDataKinds.Organization.COMPANY, getJsonString(org, "name")); contentValues.put(ContactsContract.CommonDataKinds.Organization.COMPANY, getJsonString(org, "name"));
contentValues.put(ContactsContract.CommonDataKinds.Organization.TITLE, getJsonString(org, "title")); contentValues.put(ContactsContract.CommonDataKinds.Organization.TITLE, getJsonString(org, "title"));
@ -951,6 +1068,7 @@ public class ContactAccessorSdk5 extends ContactAccessor {
.withSelection(ContactsContract.CommonDataKinds.Organization._ID + "=? AND " + .withSelection(ContactsContract.CommonDataKinds.Organization._ID + "=? AND " +
ContactsContract.Data.MIMETYPE + "=?", ContactsContract.Data.MIMETYPE + "=?",
new String[]{orgId, ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE}) new String[]{orgId, ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE})
.withValue(ContactsContract.CommonDataKinds.Organization.TYPE, getOrgType(getJsonString(org, "type")))
.withValue(ContactsContract.CommonDataKinds.Organization.DEPARTMENT, getJsonString(org, "department")) .withValue(ContactsContract.CommonDataKinds.Organization.DEPARTMENT, getJsonString(org, "department"))
.withValue(ContactsContract.CommonDataKinds.Organization.COMPANY, getJsonString(org, "name")) .withValue(ContactsContract.CommonDataKinds.Organization.COMPANY, getJsonString(org, "name"))
.withValue(ContactsContract.CommonDataKinds.Organization.TITLE, getJsonString(org, "title")) .withValue(ContactsContract.CommonDataKinds.Organization.TITLE, getJsonString(org, "title"))
@ -1120,7 +1238,12 @@ public class ContactAccessorSdk5 extends ContactAccessor {
retVal = false; retVal = false;
} }
return retVal; // if the save was a succes return the contact ID
if (retVal) {
return id;
} else {
return null;
}
} }
/** /**
@ -1165,6 +1288,7 @@ public class ContactAccessorSdk5 extends ContactAccessor {
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE) .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.Organization.TYPE, getOrgType(getJsonString(org, "type")))
.withValue(ContactsContract.CommonDataKinds.Organization.DEPARTMENT, getJsonString(org, "department")) .withValue(ContactsContract.CommonDataKinds.Organization.DEPARTMENT, getJsonString(org, "department"))
.withValue(ContactsContract.CommonDataKinds.Organization.COMPANY, getJsonString(org, "name")) .withValue(ContactsContract.CommonDataKinds.Organization.COMPANY, getJsonString(org, "name"))
.withValue(ContactsContract.CommonDataKinds.Organization.TITLE, getJsonString(org, "title")) .withValue(ContactsContract.CommonDataKinds.Organization.TITLE, getJsonString(org, "title"))
@ -1182,6 +1306,7 @@ public class ContactAccessorSdk5 extends ContactAccessor {
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE) .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.StructuredPostal.TYPE, getAddressType(getJsonString(address, "type")))
.withValue(ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS, getJsonString(address, "formatted")) .withValue(ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS, getJsonString(address, "formatted"))
.withValue(ContactsContract.CommonDataKinds.StructuredPostal.STREET, getJsonString(address, "streetAddress")) .withValue(ContactsContract.CommonDataKinds.StructuredPostal.STREET, getJsonString(address, "streetAddress"))
.withValue(ContactsContract.CommonDataKinds.StructuredPostal.CITY, getJsonString(address, "locality")) .withValue(ContactsContract.CommonDataKinds.StructuredPostal.CITY, getJsonString(address, "locality"))
@ -1296,7 +1421,7 @@ public class ContactAccessorSdk5 extends ContactAccessor {
* @param contact the contact to be saved * @param contact the contact to be saved
* @param account the account to be saved under * @param account the account to be saved under
*/ */
private boolean createNewContact(JSONObject contact, Account account) { private String createNewContact(JSONObject contact, Account account) {
// Create a list of attributes to add to the contact database // Create a list of attributes to add to the contact database
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>(); ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
@ -1463,18 +1588,21 @@ public class ContactAccessorSdk5 extends ContactAccessor {
Log.d(LOG_TAG, "Could not get photos"); Log.d(LOG_TAG, "Could not get photos");
} }
boolean retVal = true; String newId = null;
//Add contact //Add contact
try { try {
mApp.getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops); ContentProviderResult[] cpResults = mApp.getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
if (cpResults.length >= 0) {
newId = cpResults[0].uri.getLastPathSegment();
}
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(LOG_TAG, e.getMessage(), e); Log.e(LOG_TAG, e.getMessage(), e);
retVal = false; newId = null;
} catch (OperationApplicationException e) { } catch (OperationApplicationException e) {
Log.e(LOG_TAG, e.getMessage(), e); Log.e(LOG_TAG, e.getMessage(), e);
retVal = false; newId = null;
} }
return retVal; return newId;
} }
@Override @Override
@ -1699,4 +1827,90 @@ public class ContactAccessorSdk5 extends ContactAccessor {
} }
return stringType; return stringType;
} }
/**
* Converts a string from the W3C Contact API to it's Android int value.
* @param string
* @return Android int value
*/
private int getOrgType(String string) {
int type = ContactsContract.CommonDataKinds.Organization.TYPE_OTHER;
if (string!=null) {
if ("work".equals(string.toLowerCase())) {
return ContactsContract.CommonDataKinds.Organization.TYPE_WORK;
}
else if ("other".equals(string.toLowerCase())) {
return ContactsContract.CommonDataKinds.Organization.TYPE_OTHER;
}
else if ("custom".equals(string.toLowerCase())) {
return ContactsContract.CommonDataKinds.Organization.TYPE_CUSTOM;
}
}
return type;
}
/**
* getPhoneType converts an Android phone type into a string
* @param type
* @return phone type as string.
*/
private String getOrgType(int type) {
String stringType;
switch (type) {
case ContactsContract.CommonDataKinds.Organization.TYPE_CUSTOM:
stringType = "custom";
break;
case ContactsContract.CommonDataKinds.Organization.TYPE_WORK:
stringType = "work";
break;
case ContactsContract.CommonDataKinds.Organization.TYPE_OTHER:
default:
stringType = "other";
break;
}
return stringType;
}
/**
* Converts a string from the W3C Contact API to it's Android int value.
* @param string
* @return Android int value
*/
private int getAddressType(String string) {
int type = ContactsContract.CommonDataKinds.StructuredPostal.TYPE_OTHER;
if (string!=null) {
if ("work".equals(string.toLowerCase())) {
return ContactsContract.CommonDataKinds.StructuredPostal.TYPE_WORK;
}
else if ("other".equals(string.toLowerCase())) {
return ContactsContract.CommonDataKinds.StructuredPostal.TYPE_OTHER;
}
else if ("home".equals(string.toLowerCase())) {
return ContactsContract.CommonDataKinds.StructuredPostal.TYPE_HOME;
}
}
return type;
}
/**
* getPhoneType converts an Android phone type into a string
* @param type
* @return phone type as string.
*/
private String getAddressType(int type) {
String stringType;
switch (type) {
case ContactsContract.CommonDataKinds.StructuredPostal.TYPE_HOME:
stringType = "home";
break;
case ContactsContract.CommonDataKinds.StructuredPostal.TYPE_WORK:
stringType = "work";
break;
case ContactsContract.CommonDataKinds.StructuredPostal.TYPE_OTHER:
default:
stringType = "other";
break;
}
return stringType;
}
} }

View File

@ -43,29 +43,26 @@ public class ContactManager extends Plugin {
try { try {
if (action.equals("search")) { if (action.equals("search")) {
JSONArray res = contactAccessor.search(args.getJSONArray(0), args.optJSONObject(1)); JSONArray res = contactAccessor.search(args.getJSONArray(0), args.optJSONObject(1));
return new PluginResult(status, res, "navigator.service.contacts.cast"); return new PluginResult(status, res, "navigator.contacts.cast");
} }
else if (action.equals("save")) { else if (action.equals("save")) {
if (contactAccessor.save(args.getJSONObject(0))) { String id = contactAccessor.save(args.getJSONObject(0));
return new PluginResult(status, result); if (id != null) {
JSONObject res = contactAccessor.getContactById(id);
if (res != null) {
return new PluginResult(status, res);
} }
else {
JSONObject r = new JSONObject();
r.put("code", 0);
return new PluginResult(PluginResult.Status.ERROR, r);
} }
} }
else if (action.equals("remove")) { else if (action.equals("remove")) {
if (contactAccessor.remove(args.getString(0))) { if (contactAccessor.remove(args.getString(0))) {
return new PluginResult(status, result); return new PluginResult(status, result);
} }
else { }
// If we get to this point an error has occurred
JSONObject r = new JSONObject(); JSONObject r = new JSONObject();
r.put("code", 2); r.put("code", 0);
return new PluginResult(PluginResult.Status.ERROR, r); return new PluginResult(PluginResult.Status.ERROR, r);
}
}
return new PluginResult(status, result);
} catch (JSONException e) { } catch (JSONException e) {
Log.e(LOG_TAG, e.getMessage(), e); Log.e(LOG_TAG, e.getMessage(), e);
return new PluginResult(PluginResult.Status.JSON_EXCEPTION); return new PluginResult(PluginResult.Status.JSON_EXCEPTION);