How to Load a Contact Photo

How do I load a contact Photo?

Having scanned the many questions and answers to the problem of displaying a thumbnail I thought I would post my solution to this particular conundrum as I could only find a couple that worked at all and none that provided a good canned solution for the lazy developer.

The class below takes a Context, QuickContactBadge and a telephone number and will attach a locally stored image to the badge if there is one available for the specified phone number.

Here's the class:

public final class QuickContactHelper {

private static final String[] PHOTO_ID_PROJECTION = new String[] {
ContactsContract.Contacts.PHOTO_ID
};

private static final String[] PHOTO_BITMAP_PROJECTION = new String[] {
ContactsContract.CommonDataKinds.Photo.PHOTO
};

private final QuickContactBadge badge;

private final String phoneNumber;

private final ContentResolver contentResolver;

public QuickContactHelper(final Context context, final QuickContactBadge badge, final String phoneNumber) {

this.badge = badge;
this.phoneNumber = phoneNumber;
contentResolver = context.getContentResolver();

}

public void addThumbnail() {

final Integer thumbnailId = fetchThumbnailId();
if (thumbnailId != null) {
final Bitmap thumbnail = fetchThumbnail(thumbnailId);
if (thumbnail != null) {
badge.setImageBitmap(thumbnail);
}
}

}

private Integer fetchThumbnailId() {

final Uri uri = Uri.withAppendedPath(ContactsContract.CommonDataKinds.Phone.CONTENT_FILTER_URI, Uri.encode(phoneNumber));
final Cursor cursor = contentResolver.query(uri, PHOTO_ID_PROJECTION, null, null, ContactsContract.Contacts.DISPLAY_NAME + " ASC");

try {
Integer thumbnailId = null;
if (cursor.moveToFirst()) {
thumbnailId = cursor.getInt(cursor.getColumnIndex(ContactsContract.Contacts.PHOTO_ID));
}
return thumbnailId;
}
finally {
cursor.close();
}

}

final Bitmap fetchThumbnail(final int thumbnailId) {

final Uri uri = ContentUris.withAppendedId(ContactsContract.Data.CONTENT_URI, thumbnailId);
final Cursor cursor = contentResolver.query(uri, PHOTO_BITMAP_PROJECTION, null, null, null);

try {
Bitmap thumbnail = null;
if (cursor.moveToFirst()) {
final byte[] thumbnailBytes = cursor.getBlob(0);
if (thumbnailBytes != null) {
thumbnail = BitmapFactory.decodeByteArray(thumbnailBytes, 0, thumbnailBytes.length);
}
}
return thumbnail;
}
finally {
cursor.close();
}

}

}

And here's a typical use case inside an activity:

String phoneNumber = "...";
QuickContactBadge badge = (QuickContactBadge) view.findViewById(R.id.friend);
new QuickContactHelper(this, badge, phoneNumber).addThumbnail();

In a fragment it will be slightly different:

String phoneNumber = "...";
QuickContactBadge badge = (QuickContactBadge) view.findViewById(R.id.friend);
new QuickContactHelper(getActivity(), badge, phoneNumber).addThumbnail();

Now there are ways to be more efficient - for example if you are rendering a message timeline you'd want to re-use the same bitmap object for every badge instance for a given phone number instead of constantly creating new helper class instances and re-retrieving the bitmap - but my purpose here was to post a solution that is stripped down to the absolute minimum for clarity whilst at the same time providing a complete and usable solution out of the box. This solution has been built and tested on Andriod 4.0, and tested on 4.1 as well.

Insert Contact (ContactsContract) via Intent with Image (Photo)


Bitmap bit = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher); // your image

ArrayList<ContentValues> data = new ArrayList<ContentValues>();

ContentValues row = new ContentValues();
row.put(Data.MIMETYPE, ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE);
row.put(ContactsContract.CommonDataKinds.Photo.PHOTO, bitmapToByteArray(bit));
data.add(row);

Intent intent = new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI);
intent.putParcelableArrayListExtra(Insert.DATA, data);

Android - Get Contact Photo from phone number


public static Bitmap retrieveContactPhoto(Context context, String number) {
ContentResolver contentResolver = context.getContentResolver();
String contactId = null;
Uri uri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));

String[] projection = new String[]{ContactsContract.PhoneLookup.DISPLAY_NAME, ContactsContract.PhoneLookup._ID};

Cursor cursor =
contentResolver.query(
uri,
projection,
null,
null,
null);

if (cursor != null) {
while (cursor.moveToNext()) {
contactId = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.PhoneLookup._ID));
}
cursor.close();
}

Bitmap photo = BitmapFactory.decodeResource(context.getResources(),
R.drawable.default_image);

try {
if(contactId != null) {
InputStream inputStream = ContactsContract.Contacts.openContactPhotoInputStream(context.getContentResolver(),
ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, new Long(contactId)));

if (inputStream != null) {
photo = BitmapFactory.decodeStream(inputStream);
}

assert inputStream != null;
inputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
return photo;
}

Getting a Photo from a Contact

Probably this will help you(contact is identified by getId()):

/**
* @return the photo URI
*/
public Uri getPhotoUri() {
try {
Cursor cur = this.ctx.getContentResolver().query(
ContactsContract.Data.CONTENT_URI,
null,
ContactsContract.Data.CONTACT_ID + "=" + this.getId() + " AND "
+ ContactsContract.Data.MIMETYPE + "='"
+ ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE + "'", null,
null);
if (cur != null) {
if (!cur.moveToFirst()) {
return null; // no photo
}
} else {
return null; // error in cursor process
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
Uri person = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, Long
.parseLong(getId()));
return Uri.withAppendedPath(person, ContactsContract.Contacts.Photo.CONTENT_DIRECTORY);
}

Usage is:

Uri u = objItem.getPhotoUri();
if (u != null) {
mPhotoView.setImageURI(u);
} else {
mPhotoView.setImageResource(R.drawable.ic_contact_picture_2);
}

Simple way to add contact photo to ImageView?

Good job in getting the URI. You're almost there. First of all consider using PHOTO_THUMBNAIL_URI instead of PHOTO_URI, as it may be what you need in terms of size.

Edit : FYI, PHOTO_THUMBNAIL_URI is available starting API 11. You can still use it conditionally.

If you want to use an external library, 'Android Universal Image Loader' is definitely what you are looking for, as starting from it's 1.7.1 version from a few days ago, it added support for content schemes and it is pretty smart, memory wise. It also has a lot of customization options.

Edit: this lib is already dead. Use Fresco instead.

If you'd rather be nicer to your final bundle size and write the code yourself,

You need to get and decode the input stream of that content; This should be done on a background thread. Check out this connivence method; You initialise it with your image view and the uri you got and start it when you want to load the ImageView.

private class ContactThumbnailTask extends AsyncTask<Void, Void, Bitmap> {

private WeakReference<ImageView> imageViewWeakReference;
private Uri uri;
private String path;
private Context context;


public ContactThumbnailTask(ImageView imageView, Uri uri, Context context) {
this.uri = uri;
this.imageViewWeakReference = new WeakReference<ImageView>(imageView);
this.path = (String)imageViewWeakReference.get().getTag(); // to make sure we don't put the wrong image on callback
this.context = context;
}

@Override
protected Bitmap doInBackground(Void... params) {
InputStream is = null;
try {
is = context.getContentResolver().openInputStream(uri);
} catch (FileNotFoundException e) {
e.printStackTrace();
}

Bitmap image = null;
if (null!= is)
image= BitmapFactory.decodeStream(is);

return image;
}

@Override
protected void onPostExecute(Bitmap bitmap) {
if (imageViewWeakReference != null && imageViewWeakReference.get() != null && ((String)imageViewWeakReference.get().getTag()).equals(path) && null != bitmap)
imageViewWeakReference.get().setImageBitmap(bitmap);
}
}

Load a contact's picture into ListView (part 2)

There are two problems in your code. The first one is easy to overcome, the others need more work.

Lets start with the easy one:
The method ContactsContract.Contacts.openContactPhotoInputStream(cr, uri) takes a contact uri and not a photo uri. That is the id in your call to ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, id) has to be a contact id.

Also you create a lot of Bitmap objects when iterating over the result set. Don't do this. Though this might work at first, it probably crashes with OutOfMemory errors when the list get's to long. Try to create as few Bitmapobjects as necessary. That is: Only for those rows visible. When scrolling the list view you have to recycle existing Bitmaps.

unable to load contact photo android

Use ContactsContract.Contacts.CONTENT_URI instead of Contacts.CONTENT_URI, to get the contacts uri. According to this reference page, Contacts.CONTENT_URI has been deprecated.

Additionally, check these out:

Example Code 1

Example Code 2



Related Topics



Leave a reply



Submit