Skip to content

Instantly share code, notes, and snippets.

@marinomeneghel
Last active March 13, 2017 08:24
Show Gist options
  • Save marinomeneghel/75a7133e9d9f8f13040d to your computer and use it in GitHub Desktop.
Save marinomeneghel/75a7133e9d9f8f13040d to your computer and use it in GitHub Desktop.
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
import android.provider.ContactsContract;
import java.util.ArrayList;
import java.util.List;
import static android.provider.ContactsContract.CommonDataKinds.Email;
import static android.provider.ContactsContract.CommonDataKinds.Im;
import static android.provider.ContactsContract.CommonDataKinds.Note;
import static android.provider.ContactsContract.CommonDataKinds.Organization;
import static android.provider.ContactsContract.CommonDataKinds.Phone;
import static android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
import static android.provider.ContactsContract.CommonDataKinds.Website;
import static android.provider.ContactsContract.Contacts;
import static android.provider.ContactsContract.Data;
/**
* Created by Marino Meneghel on 1/22/16
*
* Parses all the contacts from address book, with the main related informations
*/
public class ParseAddressBookContacts extends AsyncTask<Void, Void, List<ContactDetails>> {
private static final String TAG = "ParseABContacts";
/** Sort order to get contacts ordered by Name Ascending */
private static final String ORDER_BY_NAME_ASC = Data.DISPLAY_NAME + " ASC";
/** List of colums to retrieve from the main query */
private static final String[] MAIN_QUERY_PROJECTION = {
Contacts._ID, Contacts.DISPLAY_NAME, Contacts.HAS_PHONE_NUMBER
};
private static ParseAddressBookContacts sSingleton;
private static ContentResolver mContentResolver;
private OnParseContactsFinishedListener mOnParseContactsFinishedListener;
/** Flag to know whether the contacts parsing has finished */
private static boolean sIsContactsParsingFinished;
/**
* Gets the singleton for this class
* @param context the context to use to get the content resolver for this class
* @return the current instance of this class or a new one if not present
*/
public static ParseAddressBookContacts getInstance(Context context) {
mContentResolver = context.getContentResolver();
if(sSingleton == null) {
sSingleton = new ParseAddressBookContacts();
}
return sSingleton;
}
/** Returns a flag to know whether this task has finished and contacts has been parsed */
public static boolean isContactsParsingFinished() {
return sIsContactsParsingFinished;
}
/**
* Set a {@link OnParseContactsFinishedListener} * to retrieve a callback
* with the list of the contacts parsed from the addressbook
* @param listener the listener to set
*/
public void setOnParseContactFinishedListener(OnParseContactsFinishedListener listener) {
mOnParseContactsFinishedListener = listener;
}
/**
* Interface to performs callbacks to the invoker when all the contacts are parsed
*/
public interface OnParseContactsFinishedListener {
void onFinished(List<ContactDetails> contacts);
}
@Override
protected List<ContactDetails> doInBackground(Void... params) {
sIsContactsParsingFinished = false;
return parseContacts();
}
@Override
protected void onPostExecute(List<ContactDetails> parsedContacts) {
super.onPostExecute(parsedContacts);
if(mOnParseContactsFinishedListener != null) {
sIsContactsParsingFinished = true;
mOnParseContactsFinishedListener.onFinished(parsedContacts);
}
}
/**
* Parses the address book contacts
* @return a List<{@link ContactDetails}> containing the address book contacts
*/
private List<ContactDetails> parseContacts() {
List<ContactDetails> contacts = new ArrayList<>();
Cursor mainCursor = mContentResolver.query(ContactsContract.Contacts.CONTENT_URI,
MAIN_QUERY_PROJECTION, null, null, ORDER_BY_NAME_ASC);
if(mainCursor != null && mainCursor.getCount() > 0) {
final int mainIdColumnIndex = mainCursor.getColumnIndex(Contacts._ID);
final int displayNameColumnIndex = mainCursor.getColumnIndex(Contacts.DISPLAY_NAME);
// Iterate on returned rows
while (mainCursor.moveToNext()) {
ContactDetails contactDetails = new ContactDetails();
String id = mainCursor.getString(mainIdColumnIndex);
String name = mainCursor.getString(displayNameColumnIndex);
contactDetails.id = Long.valueOf(id);
contactDetails.givenName = name;
queryContactEmails(contactDetails, id);
queryContactPhoneNumbers(contactDetails, id);
queryContactOrganization(contactDetails, id);
queryContactDescription(contactDetails, id);
queryContactWebsite(contactDetails, id);
queryContactAddress(contactDetails, id);
queryContactInstantMessaging(contactDetails, id);
queryContactAvatarUrl(contactDetails, id);
contacts.add(contactDetails);
}
mainCursor.close();
}
return contacts;
}
/**
* Queries the address book to get the contact avatar url for the given contactId
* @param contactDetails the contactDetails instance to which save the red field
* @param id the id of the contact for which query the data
*/
private void queryContactAvatarUrl(ContactDetails contactDetails, String id) {
final String avatarProjection[] = { Contacts.Photo.PHOTO };
Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, Long.parseLong(id));
Uri photoUri = Uri.withAppendedPath(contactUri, Contacts.Photo.CONTENT_DIRECTORY);
Cursor cursor = mContentResolver.query(photoUri, avatarProjection, null, null, null);
if (cursor != null) {
if(cursor.moveToFirst()) {
contactDetails.avatar = cursor.getBlob(0);
}
cursor.close();
}
}
/**
* Queries the address book to get the contact IM fields [SKYPE] for the given contactId
* @param contactDetails the contactDetails instance to which save the red field
* @param id the id of the contact for which query the data
*/
private void queryContactInstantMessaging(ContactDetails contactDetails, String id) {
final String imProjection[] = {
Im._ID,
Im.DATA,
Im.PROTOCOL
};
String imWhere = Data.CONTACT_ID + " = ? AND " + Data.MIMETYPE + " = ?";
String imWhereParams[] = new String[] { id, Im.CONTENT_ITEM_TYPE };
Cursor imCursor = mContentResolver.query(
Data.CONTENT_URI, imProjection, imWhere, imWhereParams, null);
if (imCursor != null) {
final int imDataColumnIndex = imCursor.getColumnIndex(Im.DATA);
final int imProtocolColumnIndex = imCursor.getColumnIndex(Im.PROTOCOL);
while(imCursor.moveToNext()) {
String imName = imCursor.getString(imDataColumnIndex);
int imType = imCursor.getInt(imProtocolColumnIndex);
if (imType == Im.PROTOCOL_SKYPE) {
contactDetails.skype = imName;
}
}
imCursor.close();
}
}
/**
* Queries the address book to get the contact address fields for the given contactId
* @param contactDetails the contactDetails instance to which save the red fields
* @param id the id of the contact for which query the data
*/
private void queryContactAddress(ContactDetails contactDetails, String id) {
final String addressProjection[] = {
StructuredPostal._ID,
StructuredPostal.POBOX,
StructuredPostal.STREET,
StructuredPostal.CITY,
StructuredPostal.REGION,
StructuredPostal.POSTCODE,
StructuredPostal.COUNTRY,
StructuredPostal.TYPE
};
String addressWhere = Data.CONTACT_ID + " = ? AND " + Data.MIMETYPE + " = ?";
String[] addressWhereParams = new String[] { id, StructuredPostal.CONTENT_ITEM_TYPE };
Cursor addressCursor = mContentResolver.query(
Data.CONTENT_URI, addressProjection, addressWhere, addressWhereParams, null);
if (addressCursor != null) {
final int postboxColumnIndex = addressCursor.getColumnIndex(StructuredPostal.POBOX);
final int streetColumnIndex = addressCursor.getColumnIndex(StructuredPostal.STREET);
final int cityColumnIndex = addressCursor.getColumnIndex(StructuredPostal.CITY);
final int regionColumnIndex = addressCursor.getColumnIndex(StructuredPostal.REGION);
final int postalCodeColumnIndex = addressCursor.getColumnIndex(StructuredPostal.POSTCODE);
final int countryColumnIndex = addressCursor.getColumnIndex(StructuredPostal.COUNTRY);
while (addressCursor.moveToNext()) {
String poBox = addressCursor.getString(postboxColumnIndex);
String street = addressCursor.getString(streetColumnIndex);
String city = addressCursor.getString(cityColumnIndex);
String state = addressCursor.getString(regionColumnIndex);
String postalCode = addressCursor.getString(postalCodeColumnIndex);
String country = addressCursor.getString(countryColumnIndex);
contactDetails.city = city;
contactDetails.country = country;
contactDetails.region = state;
contactDetails.zip = postalCode;
// Concat data to save the full address
contactDetails.address = (poBox != null ? poBox : "")
+ " " + (street != null ? street : "")
+ " " + (city != null ? city : "")
+ " " + (state != null ? state : "")
+ " " + (postalCode != null ? postalCode : "")
+ " " + (country != null ? country : "");
}
addressCursor.close();
}
}
/**
* Queries the address book to get the contact website field for the given contactId
* @param contactDetails the contactDetails instance to which save the red field
* @param id the id of the contact for which query the data
*/
private void queryContactWebsite(ContactDetails contactDetails, String id) {
final String siteProjection[] = { Website._ID, Website.URL };
String siteWhere = Data.CONTACT_ID + " = ? AND " + Data.MIMETYPE + " = ?";
String[] siteWhereParams = new String[] { id, Website.CONTENT_ITEM_TYPE };
Cursor siteCursor = mContentResolver.query(
Data.CONTENT_URI, siteProjection, siteWhere, siteWhereParams, null);
if (siteCursor != null) {
final int siteColumnIndex = siteCursor.getColumnIndex(Website.URL);
while (siteCursor.moveToNext()) {
contactDetails.site = siteCursor.getString(siteColumnIndex);
}
siteCursor.close();
}
}
/**
* Queries the address book to get the contact description field for the given contactId
* @param contactDetails the contactDetails instance to which save the red field
* @param id the id of the contact for which query the data
*/
private void queryContactDescription(ContactDetails contactDetails, String id) {
final String noteProjection[] = { Note._ID, Note.NOTE };
String noteWhere = Data.CONTACT_ID + " = ? AND " + Data.MIMETYPE + " = ?";
String[] noteWhereParams = new String[] { id, Note.CONTENT_ITEM_TYPE };
Cursor noteCursor = mContentResolver.query(Data.CONTENT_URI, noteProjection,
noteWhere, noteWhereParams, null);
if (noteCursor != null) {
final int noteColumnIndex = noteCursor.getColumnIndex(Note.NOTE);
while (noteCursor.moveToNext()) {
contactDetails.description = noteCursor.getString(noteColumnIndex);
}
noteCursor.close();
}
}
/**
* Queries the address book to get the contact organization data (org name and role) for the given contactId.
* Saves the red values into the given ContactDetails instance
* @param contactDetails the contactDetails instance to which save the queried data
* @param contactId the id of the contact for which query the data
*/
private void queryContactOrganization(ContactDetails contactDetails, String contactId) {
final String orgProjection[] = {
Organization._ID,
Organization.COMPANY,
Organization.TITLE,
Organization.TYPE
};
String orgWhere = Data.CONTACT_ID + " = ? AND " + Data.MIMETYPE + " = ?";
String[] orgWhereParams = new String[]{ contactId, Organization.CONTENT_ITEM_TYPE };
Cursor orgCursor = mContentResolver.query(
Data.CONTENT_URI, orgProjection, orgWhere, orgWhereParams, null);
if(orgCursor != null) {
final int companyTypeColumnIndex = orgCursor.getColumnIndex(Organization.TYPE);
final int companyNameColumnIndex = orgCursor.getColumnIndex(Organization.COMPANY);
final int companyRoleColumnIndex = orgCursor.getColumnIndex(Organization.TITLE);
while(orgCursor.moveToNext()) {
int type = orgCursor.getInt(companyTypeColumnIndex);
if(type == Organization.TYPE_WORK) {
contactDetails.organization = orgCursor.getString(companyNameColumnIndex);
contactDetails.role = orgCursor.getString(companyRoleColumnIndex);
}
}
orgCursor.close();
}
}
/**
* Queries the address book to get the contact phone numbers for the given contactId.
* Saves the red values into the given ContactDetails instance
* @param contactDetails the contact instance to which save the data returned from the query
* @param contactId the id of the contact for which query the data
*/
private void queryContactPhoneNumbers(ContactDetails contactDetails, String contactId) {
// The list of columns to get back from the query
final String phoneProjection[] = {
Phone._ID,
Phone.NUMBER,
Phone.TYPE
};
// Query addressbook to get contact phone numbers
Cursor phoneCursor = mContentResolver.query(
Phone.CONTENT_URI,
phoneProjection, Phone.CONTACT_ID + " = ?",
new String[]{contactId}, null);
if(phoneCursor != null) {
final int typeColumnIndex = phoneCursor.getColumnIndex(Phone.TYPE);
final int numberColumnIndex = phoneCursor.getColumnIndex(Phone.NUMBER);
while (phoneCursor.moveToNext()) {
int type = phoneCursor.getInt(typeColumnIndex);
String phoneNumber = phoneCursor.getString(numberColumnIndex);
switch (type) {
case Phone.TYPE_MOBILE:
contactDetails.phone = phoneNumber;
break;
case Phone.TYPE_WORK:
contactDetails.workPhone = phoneNumber;
break;
case Phone.TYPE_FAX_WORK:
contactDetails.faxPhone = phoneNumber;
break;
}
}
phoneCursor.close();
}
}
/**
* Queries the address book to get the contact emails for the given contactId.
* Saves the red values into the given ContactDetails instance
* @param contactDetails the contact to which save the data returned from the query
* @param contactId the id of the contact for which query the data
*/
private void queryContactEmails(ContactDetails contactDetails, String contactId) {
// The list of columns to get back from the query
final String emailProjection[] = { Email._ID, Email.ADDRESS, Email.TYPE };
Cursor emailCursor = mContentResolver.query(
Email.CONTENT_URI,
emailProjection, Email.CONTACT_ID + " = ?",
new String[]{contactId}, null);
if(emailCursor != null) {
final int typeColumnIndex = emailCursor.getColumnIndex(Email.TYPE);
final int addressColumnIndex = emailCursor.getColumnIndex(Email.ADDRESS);
// Iterate on this user's email addresses
while (emailCursor.moveToNext()) {
int type = emailCursor.getInt(typeColumnIndex);
String emailAddress = emailCursor.getString(addressColumnIndex);
switch(type) {
case Email.TYPE_HOME:
contactDetails.email = emailAddress;
break;
case Email.TYPE_WORK:
contactDetails.workEmail = emailAddress;
break;
case Email.TYPE_OTHER:
contactDetails.email = emailAddress;
break;
}
}
emailCursor.close();
}
}
}
@marinomeneghel
Copy link
Author

marinomeneghel commented Jan 27, 2016

It has been quite painful to me when I first met the android addressbook.
I couldn't find a clean and optimized solitution, so I've done my best to implement one.
Any suggestion to improve it is highly appreciated! :) Have fun

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment