Last active
March 13, 2017 08:24
-
-
Save marinomeneghel/75a7133e9d9f8f13040d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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