36

Alright, I'm just trying to learn about using Contact information, but I'm a bit stuck. I would like to be able to display a picture for the contact. Using the following code that I have, how would I be able to put the photo for the contact in the ImageView in contact_entry?

ListView contacts_list = (ListView) findViewById(R.id.contacts_list);

// Gets the URI of the db
Uri uri = ContactsContract.Contacts.CONTENT_URI;
// What to grab from the db
String[] projection = new String[] {
        ContactsContract.Contacts._ID,
        ContactsContract.Contacts.DISPLAY_NAME,
        ContactsContract.Contacts.PHOTO_ID
};

String sortOrder = ContactsContract.Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC";

Cursor cursor = managedQuery(uri, projection, null, null, sortOrder);

String[] fields = new String[] {
        ContactsContract.Data.DISPLAY_NAME
};

int[] values = { 
        R.id.contactEntryText
};

SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.contact_entry, cursor,
        fields, values);
contacts_list.setAdapter(adapter);

contact_entry.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="54px">
    <ImageView
        android:id="@+id/contactPhoto"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" 
        android:src="@drawable/ic_contact_picture_3"/>
    <TextView 
        android:text="@+id/contactEntryText"
        android:id="@+id/contactEntryText"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"/>
</LinearLayout>
Chiggins
  • 8,197
  • 22
  • 56
  • 81

9 Answers9

59

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);
}
Pentium10
  • 204,586
  • 122
  • 423
  • 502
17

Android documentation says, that we should do it in this way.

public Bitmap openPhoto(long contactId) {
        Uri contactUri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, contactId);
        Uri photoUri = Uri.withAppendedPath(contactUri, ContactsContract.Contacts.Photo.CONTENT_DIRECTORY);
        Cursor cursor = getContentResolver().query(photoUri,
                new String[] {ContactsContract.Contacts.Photo.PHOTO}, null, null, null);
        if (cursor == null) {
            return null;
        }
        try {
            if (cursor.moveToFirst()) {
                byte[] data = cursor.getBlob(0);
                if (data != null) {
                    return BitmapFactory.decodeStream(new ByteArrayInputStream(data));
                }
            }
        } finally {
            cursor.close();
        }
        return null;

}

For contactId you can use:

 public static long getContactIDFromNumber(String contactNumber, Context context) {
    String UriContactNumber = Uri.encode(contactNumber);
    long phoneContactID = new Random().nextInt();
    Cursor contactLookupCursor = context.getContentResolver().query(Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, UriContactNumber),
            new String[]{ContactsContract.PhoneLookup.DISPLAY_NAME, ContactsContract.PhoneLookup._ID}, null, null, null);
    while (contactLookupCursor.moveToNext()) {
        phoneContactID = contactLookupCursor.getLong(contactLookupCursor.getColumnIndexOrThrow(ContactsContract.PhoneLookup._ID));
    }
    contactLookupCursor.close();

    return phoneContactID;
}

Source: https://developer.android.com/reference/android/provider/ContactsContract.Contacts.Photo.html

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Andrii Kovalchuk
  • 4,351
  • 2
  • 36
  • 31
14

Don't know why but this works on 2.2 and 4.1:

Uri photoUri = ContentUris.withAppendedId(ContactsContract.Data.CONTENT_URI, Long.parseLong(photoId));
imageView.setImageURI(photoUri);

The photo Uri has the following form: content://com.android.contacts/data/3345, where the number is the photoId.

AlikElzin-kilaka
  • 34,335
  • 35
  • 194
  • 277
4

This code will take an image from a contact and then will display in your imageView, it is so easy and it works perfect, in this case I am getting image from a contact and display if, if there is still query then post a comment

             ImageView profile  = (ImageView)findViewById(R.id.imageView1);                 
             Uri my_contact_Uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI, String.valueOf(Contact_Id));
                      InputStream photo_stream = ContactsContract.Contacts.openContactPhotoInputStream(getContentResolver(), my_contact_Uri);            
                      BufferedInputStream buf = new BufferedInputStream(photo_stream);
                      Bitmap my_btmp = BitmapFactory.decodeStream(buf);
                         profile.setImageBitmap(my_btmp);                      
Community
  • 1
  • 1
Pir Fahim Shah
  • 10,505
  • 1
  • 82
  • 81
  • @Uri how you can say this, and if it is good, then other can use this also – Pir Fahim Shah Feb 18 '13 at 03:02
  • 1
    IDK for me it just did... use at your own risk – Uri Apr 08 '13 at 07:46
  • @PirFahimShah you should be closing the `BufferedInputStream` since it manages the `InputStream`. So calling close on the `BufferedInputStream` will close the `InputStream` also. And the `close()` should be in a `finally` block. If the stream is not closed then it can cause a resource leak. – JBirdVegas Jul 20 '15 at 14:56
4

According to Android Developers' documentation:

A read-only sub-directory of a single contact that contains the contact's primary photo. The photo may be stored in up to two ways - the default "photo" is a thumbnail-sized image stored directly in the data row, while the "display photo", if present, is a larger version stored as a file.

https://developer.android.com/reference/android/provider/ContactsContract.Contacts.Photo

You can use the following method to get thumbnail version of contact photo:

@Nullable
public Bitmap getContactPhotoThumbnail(Context context, long contactId) {
    Uri contactUri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, contactId);
    InputStream is = ContactsContract.Contacts.openContactPhotoInputStream(context.getContentResolver(), contactUri);

    return BitmapFactory.decodeStream(is);
}

You can use the following method to the full sized contact photo:

@Nullable
public Bitmap getContactPhoto(Context context, long contactId) {
    Uri contactUri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, contactId);
    Uri displayPhotoUri = Uri.withAppendedPath(contactUri, ContactsContract.Contacts.Photo.DISPLAY_PHOTO);
    try {
        AssetFileDescriptor fd =
                context.getContentResolver().openAssetFileDescriptor(displayPhotoUri, "r");
        return BitmapFactory.decodeStream(fd.createInputStream());
    } catch (IOException e) {
        return null;
    }
}
Tousif Osman
  • 287
  • 2
  • 12
3

For future readers, loading all contacts with images takes too much time and memory if you load the images with full size. From experience, on Nexus 5 it takes up to 3 seconds to load ~500 contacts. Because of this intensity, we need to avoid fetching contacts in UI thread.

This is mainly because the thumbnail photos are in an other table, which forces us to query more. If you don't need to load any image, it takes ~400ms in the case mentioned above.

I have created a gist that fetches all contacts, with their respective thumbnail references in ~500-700ms for 500 contacts;

https://gist.github.com/bugraoral/a4d36d79621455fa3dd860ff994ae796

The key point is to query and get all thumbnail references once, load them to memory, and use the memory for querying images of contacts individually.

bugraoral
  • 2,630
  • 1
  • 21
  • 25
1

You need to use permission like this in your manifest file

 <uses-permission android:name="android.permission.READ_CONTACTS" /> 
Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
iman kazemayni
  • 1,255
  • 1
  • 19
  • 20
  • Is READ_CONTACTS permission sufficient to read contacts profile image? – Jeet Nov 16 '16 at 15:49
  • on my personal experience,in android studio just write your code and if your project need any permission and if you don't declare it in your manifest, you will front with an error and if you read your trace error, the trace will tell you what permission you need. however base on accept answer, you need just read-contacts permission – iman kazemayni Nov 16 '16 at 18:56
0

I know it is a very old question but so are some of the answers here as few things here have now been deprecated. As the question showed up in searches while I was looking for similar solution, I though I will add my two cents here...

I have created a simple contacts list with their names and photos from ContactsContract. Please check my answer at... https://stackoverflow.com/a/37710199/1209544

Community
  • 1
  • 1
EMalik
  • 2,446
  • 1
  • 26
  • 13
0

Here is the method to get all the contacts, if a contact has image it will load image in the imageview else no image will be shown in the imageview.

@SuppressLint("Range") public static void readContacts(Context context) {

if (context == null)
    return;

ContentResolver contentResolver = context.getContentResolver();

if (contentResolver == null)
    return;

String[] fieldListProjection = {
        ContactsContract.CommonDataKinds.Phone.CONTACT_ID,
        ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME_PRIMARY,
        ContactsContract.CommonDataKinds.Phone.NUMBER,
        ContactsContract.CommonDataKinds.Phone.NORMALIZED_NUMBER,
        ContactsContract.Contacts.HAS_PHONE_NUMBER,
        ContactsContract.Contacts.PHOTO_URI
        ,ContactsContract.Contacts.STARRED
};
String sort = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME_PRIMARY + " ASC";
Cursor phones = contentResolver
        .query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI
                , fieldListProjection, null, null, sort);
HashSet<String> normalizedNumbersAlreadyFound = new HashSet<>();

if (phones != null && phones.getCount() > 0) {
    while (phones.moveToNext()) {
        String normalizedNumber = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));

        if (Integer.parseInt(phones.getString(phones.getColumnIndex(
                ContactsContract.Contacts.HAS_PHONE_NUMBER))) > 0) {
            if (normalizedNumbersAlreadyFound.add(normalizedNumber)) {

                int id = phones.getInt(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.CONTACT_ID));
                String name = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
                String phoneNumber = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
                int fav = phones.getInt(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.STARRED));
                boolean isFav;
                isFav= fav == 1;

                String uri = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.PHOTO_URI));
                if(uri!=null){
                    contactList.add(new FavContact(id,isFav,uri,name,phoneNumber));
                }
                else{
                    contactList.add(new FavContact(id,isFav,name,phoneNumber));
                }

            }
        }
    }
    phones.close();
}

}

In Adapter (onBindViewHolder)

if(obj.getImage()==null){
        //Image not found then load any random image (whatever you like)
        Picasso.get().load(R.drawable.ic_circle_fav_no_dp).fit().into(holder.img_contact);
    }
    else{
        //Here it will load contact image in the imageview.
        Bitmap bp;
        try {
            bp = MediaStore.Images.Media
                    .getBitmap(context.getContentResolver(),
                            Uri.parse(obj.getImage()));
            Glide.with(context).load(bp).centerInside().into(holder.img_contact);
        } catch (IOException e) {
            e.printStackTrace();
            Picasso.get().load(R.drawable.ic_circle_fav_no_dp).fit().into(holder.img_contact);
        }

    }