diff --git a/framework/src/com/phonegap/ContactAccessor.java b/framework/src/com/phonegap/ContactAccessor.java index dcf6839f..d17528ac 100644 --- a/framework/src/com/phonegap/ContactAccessor.java +++ b/framework/src/com/phonegap/ContactAccessor.java @@ -24,7 +24,6 @@ package com.phonegap; -import java.lang.reflect.Constructor; import java.util.HashMap; import android.app.Activity; @@ -44,53 +43,9 @@ import org.json.JSONObject; */ public abstract class ContactAccessor { - /** - * Static singleton instance of {@link ContactAccessor} holding the - * SDK-specific implementation of the class. - */ - private static ContactAccessor sInstance; protected final String LOG_TAG = "ContactsAccessor"; protected Activity mApp; protected WebView mView; - - public static ContactAccessor getInstance(WebView view, Activity app) { - if (sInstance == null) { - String className; - - /* - * Check the version of the SDK we are running on. Choose an - * implementation class designed for that version of the SDK. - * - * Unfortunately we have to use strings to represent the class - * names. If we used the conventional ContactAccessorSdk5.class.getName() - * syntax, we would get a ClassNotFoundException at runtime on pre-Eclair SDKs. - * Using the above syntax would force Dalvik to load the class and try to - * resolve references to all other classes it uses. Since the pre-Eclair - * does not have those classes, the loading of ContactAccessorSdk5 would fail. - */ - - if (android.os.Build.VERSION.RELEASE.startsWith("1.")) { - className = "com.phonegap.ContactAccessorSdk3_4"; - } else { - className = "com.phonegap.ContactAccessorSdk5"; - } - - /* - * Find the required class by name and instantiate it. - */ - try { - Class clazz = - Class.forName(className).asSubclass(ContactAccessor.class); - // Grab constructor for contactsmanager class dynamically. - Constructor classConstructor = clazz.getConstructor(Class.forName("android.webkit.WebView"), Class.forName("android.app.Activity")); - sInstance = classConstructor.newInstance(view, app); - } catch (Exception e) { - throw new IllegalStateException(e); - } - } - - return sInstance; - } /** * Check to see if the data associated with the key is required to diff --git a/framework/src/com/phonegap/ContactAccessorSdk3_4.java b/framework/src/com/phonegap/ContactAccessorSdk3_4.java deleted file mode 100644 index b482051f..00000000 --- a/framework/src/com/phonegap/ContactAccessorSdk3_4.java +++ /dev/null @@ -1,833 +0,0 @@ -// Taken from Android tutorials -/* - * PhoneGap is available under *either* the terms of the modified BSD license *or* the - * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text. - * - * Copyright (c) 2005-2010, Nitobi Software Inc. - * Copyright (c) 2010, IBM Corporation - */ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.phonegap; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import android.app.Activity; -import android.content.ContentResolver; -import android.content.ContentValues; -import android.database.Cursor; -import android.net.Uri; -import android.provider.Contacts; -import android.provider.Contacts.ContactMethods; -import android.provider.Contacts.ContactMethodsColumns; -import android.provider.Contacts.Organizations; -import android.provider.Contacts.People; -import android.provider.Contacts.Phones; -import android.util.Log; -import android.webkit.WebView; - -/** - * An implementation of {@link ContactAccessor} that uses legacy Contacts API. - * These APIs are deprecated and should not be used unless we are running on a - * pre-Eclair SDK. - *

- * There are several reasons why we wouldn't want to use this class on an Eclair device: - *

- */ -@SuppressWarnings("deprecation") -public class ContactAccessorSdk3_4 extends ContactAccessor { - private static final String PEOPLE_ID_EQUALS = "people._id = ?"; - /** - * A static map that converts the JavaScript property name to Android database column name. - */ - private static final Map dbMap = new HashMap(); - static { - dbMap.put("id", People._ID); - dbMap.put("displayName", People.DISPLAY_NAME); - dbMap.put("phoneNumbers", Phones.NUMBER); - dbMap.put("phoneNumbers.value", Phones.NUMBER); - dbMap.put("emails", ContactMethods.DATA); - dbMap.put("emails.value", ContactMethods.DATA); - dbMap.put("addresses", ContactMethodsColumns.DATA); - dbMap.put("addresses.formatted", ContactMethodsColumns.DATA); - dbMap.put("ims", ContactMethodsColumns.DATA); - dbMap.put("ims.value", ContactMethodsColumns.DATA); - dbMap.put("organizations", Organizations.COMPANY); - dbMap.put("organizations.name", Organizations.COMPANY); - dbMap.put("organizations.title", Organizations.TITLE); - dbMap.put("note", People.NOTES); - } - - /** - * Create an contact accessor. - */ - public ContactAccessorSdk3_4(WebView view, Activity app) - { - mApp = app; - mView = view; - } - - @Override - /** - * This method takes the fields required and search options in order to produce an - * array of contacts that matches the criteria provided. - * @param fields an array of items to be used as search criteria - * @param options that can be applied to contact searching - * @return an array of contacts - */ - public JSONArray search(JSONArray fields, JSONObject options) { - String searchTerm = ""; - int limit = Integer.MAX_VALUE; - boolean multiple = true; - - if (options != null) { - searchTerm = options.optString("filter"); - if (searchTerm.length()==0) { - searchTerm = "%"; - } - else { - searchTerm = "%" + searchTerm + "%"; - } - try { - multiple = options.getBoolean("multiple"); - if (!multiple) { - limit = 1; - } - } catch (JSONException e) { - // Multiple was not specified so we assume the default is true. - } - } - else { - searchTerm = "%"; - } - - ContentResolver cr = mApp.getContentResolver(); - - Set contactIds = buildSetOfContactIds(fields, searchTerm); - HashMap populate = buildPopulationSet(fields); - - Iterator it = contactIds.iterator(); - - JSONArray contacts = new JSONArray(); - JSONObject contact; - String contactId; - int pos = 0; - while (it.hasNext() && (pos < limit)) { - contact = new JSONObject(); - try { - contactId = it.next(); - contact.put("id", contactId); - - // Do query for name and note - Cursor cur = cr.query(People.CONTENT_URI, - new String[] {People.DISPLAY_NAME, People.NOTES}, - PEOPLE_ID_EQUALS, - new String[] {contactId}, - null); - cur.moveToFirst(); - - if (isRequired("displayName",populate)) { - contact.put("displayName", cur.getString(cur.getColumnIndex(People.DISPLAY_NAME))); - } - if (isRequired("phoneNumbers",populate)) { - contact.put("phoneNumbers", phoneQuery(cr, contactId)); - } - if (isRequired("emails",populate)) { - contact.put("emails", emailQuery(cr, contactId)); - } - if (isRequired("addresses",populate)) { - contact.put("addresses", addressQuery(cr, contactId)); - } - if (isRequired("organizations",populate)) { - contact.put("organizations", organizationQuery(cr, contactId)); - } - if (isRequired("ims",populate)) { - contact.put("ims", imQuery(cr, contactId)); - } - if (isRequired("note",populate)) { - contact.put("note", cur.getString(cur.getColumnIndex(People.NOTES))); - } - // nickname - // urls - // relationship - // birthdays - // anniversary - - pos++; - cur.close(); - } catch (JSONException e) { - Log.e(LOG_TAG, e.getMessage(), e); - } - contacts.put(contact); - } - return contacts; - } - - /** - * Query the database using the search term to build up a list of contact ID's - * matching the search term - * @param fields - * @param searchTerm - * @return a set of contact ID's - */ - private Set buildSetOfContactIds(JSONArray fields, String searchTerm) { - Set contactIds = new HashSet(); - - String key; - try { - for (int i=0; i contactIds, - Uri uri, String projection, String selection, String[] selectionArgs) { - ContentResolver cr = mApp.getContentResolver(); - - Cursor cursor = cr.query( - uri, - null, - selection, - selectionArgs, - null); - - while (cursor.moveToNext()) { - contactIds.add(cursor.getString(cursor.getColumnIndex(projection))); - } - cursor.close(); - } - - /** - * Create a ContactField JSONArray - * @param cr database access object - * @param contactId the ID to search the database for - * @return a JSONArray representing a set of ContactFields - */ - private JSONArray imQuery(ContentResolver cr, String contactId) { - String imWhere = ContactMethods.PERSON_ID - + " = ? AND " + ContactMethods.KIND + " = ?"; - String[] imWhereParams = new String[]{contactId, ContactMethods.CONTENT_IM_ITEM_TYPE}; - Cursor cursor = cr.query(ContactMethods.CONTENT_URI, - null, imWhere, imWhereParams, null); - JSONArray ims = new JSONArray(); - JSONObject im; - while (cursor.moveToNext()) { - im = new JSONObject(); - try{ - im.put("id", cursor.getString( - cursor.getColumnIndex(ContactMethods._ID))); - im.put("perf", false); - im.put("value", cursor.getString( - cursor.getColumnIndex(ContactMethodsColumns.DATA))); - im.put("type", getContactType(cursor.getInt( - cursor.getColumnIndex(ContactMethodsColumns.TYPE)))); - ims.put(im); - } catch (JSONException e) { - Log.e(LOG_TAG, e.getMessage(), e); - } - } - cursor.close(); - return null; - } - - /** - * Create a ContactOrganization JSONArray - * @param cr database access object - * @param contactId the ID to search the database for - * @return a JSONArray representing a set of ContactOrganization - */ - private JSONArray organizationQuery(ContentResolver cr, String contactId) { - String orgWhere = ContactMethods.PERSON_ID + " = ?"; - String[] orgWhereParams = new String[]{contactId}; - Cursor cursor = cr.query(Organizations.CONTENT_URI, - null, orgWhere, orgWhereParams, null); - JSONArray organizations = new JSONArray(); - JSONObject organization; - while (cursor.moveToNext()) { - organization = new JSONObject(); - try{ - organization.put("id", cursor.getString(cursor.getColumnIndex(Organizations._ID))); - organization.put("name", cursor.getString(cursor.getColumnIndex(Organizations.COMPANY))); - organization.put("title", cursor.getString(cursor.getColumnIndex(Organizations.TITLE))); - // organization.put("department", cursor.getString(cursor.getColumnIndex(Organizations))); - organizations.put(organization); - } catch (JSONException e) { - Log.e(LOG_TAG, e.getMessage(), e); - } - } - return organizations; - } - - /** - * Create a ContactAddress JSONArray - * @param cr database access object - * @param contactId the ID to search the database for - * @return a JSONArray representing a set of ContactAddress - */ - private JSONArray addressQuery(ContentResolver cr, String contactId) { - String addrWhere = ContactMethods.PERSON_ID - + " = ? AND " + ContactMethods.KIND + " = ?"; - String[] addrWhereParams = new String[]{contactId, - ContactMethods.CONTENT_POSTAL_ITEM_TYPE}; - Cursor cursor = cr.query(ContactMethods.CONTENT_URI, - null, addrWhere, addrWhereParams, null); - JSONArray addresses = new JSONArray(); - JSONObject address; - while (cursor.moveToNext()) { - address = new JSONObject(); - try{ - address.put("id", cursor.getString(cursor.getColumnIndex(ContactMethods._ID))); - address.put("formatted", cursor.getString(cursor.getColumnIndex(ContactMethodsColumns.DATA))); - addresses.put(address); - } catch (JSONException e) { - Log.e(LOG_TAG, e.getMessage(), e); - } - } - return addresses; - } - - /** - * Create a ContactField JSONArray - * @param cr database access object - * @param contactId the ID to search the database for - * @return a JSONArray representing a set of ContactFields - */ - private JSONArray phoneQuery(ContentResolver cr, String contactId) { - Cursor cursor = cr.query( - Phones.CONTENT_URI, - null, - Phones.PERSON_ID +" = ?", - new String[]{contactId}, null); - JSONArray phones = new JSONArray(); - JSONObject phone; - while (cursor.moveToNext()) { - phone = new JSONObject(); - try{ - phone.put("id", cursor.getString(cursor.getColumnIndex(Phones._ID))); - phone.put("perf", false); - phone.put("value", cursor.getString(cursor.getColumnIndex(Phones.NUMBER))); - phone.put("type", getPhoneType(cursor.getInt(cursor.getColumnIndex(Phones.TYPE)))); - phones.put(phone); - } catch (JSONException e) { - Log.e(LOG_TAG, e.getMessage(), e); - } - } - return phones; - } - - /** - * Create a ContactField JSONArray - * @param cr database access object - * @param contactId the ID to search the database for - * @return a JSONArray representing a set of ContactFields - */ - private JSONArray emailQuery(ContentResolver cr, String contactId) { - Cursor cursor = cr.query( - ContactMethods.CONTENT_EMAIL_URI, - null, - ContactMethods.PERSON_ID +" = ?", - new String[]{contactId}, null); - JSONArray emails = new JSONArray(); - JSONObject email; - while (cursor.moveToNext()) { - email = new JSONObject(); - try{ - email.put("id", cursor.getString(cursor.getColumnIndex(ContactMethods._ID))); - email.put("perf", false); - email.put("value", cursor.getString(cursor.getColumnIndex(ContactMethods.DATA))); - // TODO Find out why adding an email type throws and exception - //email.put("type", cursor.getString(cursor.getColumnIndex(ContactMethods.TYPE))); - emails.put(email); - } catch (JSONException e) { - Log.e(LOG_TAG, e.getMessage(), e); - } - } - return emails; - } - - /** - * This method will save a contact object into the devices contacts database. - * - * @param contact the contact to be saved. - * @returns true if the contact is successfully saved, false otherwise. - */ - @Override - public String save(JSONObject contact) { - ContentValues personValues = new ContentValues(); - - String id = getJsonString(contact, "id"); - - String name = getJsonString(contact, "displayName"); - if (name != null) { - personValues.put(Contacts.People.NAME, name); - } - String note = getJsonString(contact, "note"); - if (note != null) { - personValues.put(Contacts.People.NOTES, note); - } - - /* STARRED 0 = Contacts, 1 = Favorites */ - personValues.put(Contacts.People.STARRED, 0); - - Uri newPersonUri; - // Add new contact - if (id == null) { - newPersonUri = Contacts.People.createPersonInMyContactsGroup(mApp.getContentResolver(), personValues); - } - // modify existing contact - else { - newPersonUri = Uri.withAppendedPath(Contacts.People.CONTENT_URI, id); - mApp.getContentResolver().update(newPersonUri, personValues, PEOPLE_ID_EQUALS, new String[]{id}); - } - - if (newPersonUri != null) { - // phoneNumbers - savePhoneNumbers(contact, newPersonUri); - // emails - saveEntries(contact, newPersonUri, "emails", Contacts.KIND_EMAIL); - // addresses - saveAddresses(contact, newPersonUri); - // organizations - saveOrganizations(contact, newPersonUri); - // ims - saveEntries(contact, newPersonUri, "ims", Contacts.KIND_IM); - - // Successfully create a Contact - return id; - } - return null; - } - - /** - * Takes a JSON contact object and loops through the available organizations. If the - * organization has an id that is not equal to null the organization will be updated in the database. - * If the id is null then we treat it as a new organization. - * - * @param contact the contact to extract the organizations from - * @param uri the base URI for this contact. - */ - private void saveOrganizations(JSONObject contact, Uri newPersonUri) { - ContentValues values = new ContentValues(); - Uri orgUri = Uri.withAppendedPath(newPersonUri, - Contacts.Organizations.CONTENT_DIRECTORY); - String id = null; - try { - JSONArray orgs = contact.getJSONArray("organizations"); - if (orgs != null && orgs.length() > 0) { - JSONObject org; - for (int i=0; i 0) { - JSONObject entry; - values.put(Contacts.ContactMethods.KIND, Contacts.KIND_POSTAL); - for (int i=0; i 0 ) { - buffer.append(", "); - } - buffer.append(getJsonString(entry, "region")); - } - if (getJsonString(entry, "postalCode") != null ) { - if (buffer.length() > 0 ) { - buffer.append(", "); - } - buffer.append(getJsonString(entry, "postalCode")); - } - if (getJsonString(entry, "country") != null ) { - if (buffer.length() > 0 ) { - buffer.append(", "); - } - buffer.append(getJsonString(entry, "country")); - } - return buffer.toString(); - } - - /** - * Takes a JSON contact object and loops through the available entries (Emails/IM's). If the - * entry has an id that is not equal to null the entry will be updated in the database. - * If the id is null then we treat it as a new entry. - * - * @param contact the contact to extract the entries from - * @param uri the base URI for this contact. - */ - private void saveEntries(JSONObject contact, Uri uri, String dataType, int contactKind) { - ContentValues values = new ContentValues(); - Uri newUri = Uri.withAppendedPath(uri, - Contacts.People.ContactMethods.CONTENT_DIRECTORY); - String id = null; - - try { - JSONArray entries = contact.getJSONArray(dataType); - if (entries != null && entries.length() > 0) { - JSONObject entry; - values.put(Contacts.ContactMethods.KIND, contactKind); - for (int i=0; i 0) { - JSONObject phone; - for (int i=0; i 0) ? true : false; - } - - @Override - public JSONObject getContactById(String id) throws JSONException { - // TODO Auto-generated method stub - return null; - } -} \ No newline at end of file diff --git a/framework/src/com/phonegap/ContactManager.java b/framework/src/com/phonegap/ContactManager.java index 60edd545..6e41f0f2 100755 --- a/framework/src/com/phonegap/ContactManager.java +++ b/framework/src/com/phonegap/ContactManager.java @@ -16,9 +16,18 @@ import android.util.Log; public class ContactManager extends Plugin { - private static ContactAccessor contactAccessor; + private ContactAccessor contactAccessor; private static final String LOG_TAG = "Contact Query"; + public static final int UNKNOWN_ERROR = 0; + public static final int INVALID_ARGUMENT_ERROR = 1; + public static final int TIMEOUT_ERROR = 2; + public static final int PENDING_OPERATION_ERROR = 3; + public static final int IO_ERROR = 4; + public static final int NOT_SUPPORTED_ERROR = 5; + public static final int PERMISSION_DENIED_ERROR = 20; + + /** * Constructor. */ @@ -34,12 +43,34 @@ public class ContactManager extends Plugin { * @return A PluginResult object with a status and message. */ public PluginResult execute(String action, JSONArray args, String callbackId) { - if (contactAccessor == null) { - contactAccessor = ContactAccessor.getInstance(webView, ctx); - } - PluginResult.Status status = PluginResult.Status.OK; - String result = ""; - + PluginResult.Status status = PluginResult.Status.OK; + String result = ""; + + /** + * Check to see if we are on an Android 1.X device. If we are return an error as we + * do not support this as of PhoneGap 1.0. + */ + if (android.os.Build.VERSION.RELEASE.startsWith("1.")) { + JSONObject res = null; + try { + res = new JSONObject(); + res.put("code", NOT_SUPPORTED_ERROR); + res.put("message", "Contacts are not supported in Android 1.X devices"); + } catch (JSONException e) { + // This should never happen + Log.e(LOG_TAG, e.getMessage(), e); + } + return new PluginResult(PluginResult.Status.ERROR, res); + } + + /** + * Only create the contactAccessor after we check the Android version or the program will crash + * older phones. + */ + if (this.contactAccessor == null) { + this.contactAccessor = new ContactAccessorSdk5(this.webView, this.ctx); + } + try { if (action.equals("search")) { JSONArray res = contactAccessor.search(args.getJSONArray(0), args.optJSONObject(1)); @@ -61,7 +92,7 @@ public class ContactManager extends Plugin { } // If we get to this point an error has occurred JSONObject r = new JSONObject(); - r.put("code", 0); + r.put("code", UNKNOWN_ERROR); return new PluginResult(PluginResult.Status.ERROR, r); } catch (JSONException e) { Log.e(LOG_TAG, e.getMessage(), e);