I'm having trouble loading a photo for a contact in Android. I've googled for an answer, but so far have come up empty. Does anyone have an example of querying for a Contact, then loading the Photo?
So, given a contactUri which comes from an Activity result called using
startActivityForResult(new Intent(Intent.ACTION_PICK,ContactsContract.CommonDataKinds.Phone.CONTENT_URI),PICK_CONTACT_REQUEST)
is:
content://com.android.contacts/data/1557
The loadContact(..) works fine. However when I call the getPhoto(...) method, I get a null value for the photo InputStream. It is also confusing because the URI values are different. The contactPhotoUri evaluates to:
content://com.android.contacts/contacts/1557
See the comments inline in the code below.
class ContactAccessor {
/**
* Retrieves the contact information.
*/
public ContactInfo loadContact(ContentResolver contentResolver, Uri contactUri) {
//contactUri --> content://com.android.contacts/data/1557
ContactInfo contactInfo = new ContactInfo();
// Load the display name for the specified person
Cursor cursor = contentResolver.query(contactUri,
new String[]{Contacts._ID,
Contacts.DISPLAY_NAME,
Phone.NUMBER,
Contacts.PHOTO_ID}, null, null, null);
try {
if (cursor.moveToFirst()) {
contactInfo.setId(cursor.getLong(0));
contactInfo.setDisplayName(cursor.getString(1));
contactInfo.setPhoneNumber(cursor.getString(2));
}
} finally {
cursor.close();
}
return contactInfo; // <-- returns info for contact
}
public Bitmap getPhoto(ContentResolver contentResolver, Long contactId) {
Uri contactPhotoUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
// contactPhotoUri --> content://com.android.contacts/contacts/1557
InputStream photoDataStream = Contacts.openContactPhotoInputStream(contentResolver,contactPhotoUri); // <-- always null
Bitmap photo = BitmapFactory.decodeStream(photoDataStream);
return photo;
}
public class ContactInfo {
private long id;
private String displayName;
private String phoneNumber;
private Uri photoUri;
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
public String getDisplayName() {
return displayName;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public String getPhoneNumber() {
return phoneNumber;
}
public Uri getPhotoUri() {
return this.photoUri;
}
public void setPhotoUri(Uri photoUri) {
this.photoUri = photoUri;
}
public long getId() {
return this.id;
}
public void setId(long id) {
this.id = id;
}
}
}
Clearly, I'm doing something wrong here, but I can't seem to figure out what the problem is. Thanks.
Source: Tips4all
This works for me:
ReplyDeletepublic static Bitmap loadContactPhoto(ContentResolver cr, long id) {
Uri uri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, id);
InputStream input = ContactsContract.Contacts.openContactPhotoInputStream(cr, uri);
if (input == null) {
return null;
}
return BitmapFactory.decodeStream(input);
}
Guys, I spent many hours attempting to figure this out. Here is a method I created that will get you your facebook photo by phone number (no dashes). You can, of course, modify it accordingly:
ReplyDeletepublic Bitmap getFacebookPhoto(String phoneNumber) {
Uri phoneUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phoneNumber));
Uri photoUri = null;
ContentResolver cr = this.getContentResolver();
Cursor contact = cr.query(phoneUri,
new String[] { ContactsContract.Contacts._ID }, null, null, null);
if (contact.moveToFirst()) {
long userId = contact.getLong(contact.getColumnIndex(ContactsContract.Contacts._ID));
photoUri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, userId);
}
else {
Bitmap defaultPhoto = BitmapFactory.decodeResource(getResources(), android.R.drawable.ic_menu_report_image);
return defaultPhoto;
}
if (photoUri != null) {
InputStream input = ContactsContract.Contacts.openContactPhotoInputStream(
cr, photoUri);
if (input != null) {
return BitmapFactory.decodeStream(input);
}
} else {
Bitmap defaultPhoto = BitmapFactory.decodeResource(getResources(), android.R.drawable.ic_menu_report_image);
return defaultPhoto;
}
Bitmap defaultPhoto = BitmapFactory.decodeResource(getResources(), android.R.drawable.ic_menu_report_image);
return defaultPhoto;
}
After a lot of debugging nights I discover that the best approach is to use the contact id and if it fails to use the photo id.
ReplyDeletepublic static Bitmap loadContactPhoto(ContentResolver cr, long id,long photo_id)
{
Uri uri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, id);
InputStream input = ContactsContract.Contacts.openContactPhotoInputStream(cr, uri);
if (input != null)
{
return BitmapFactory.decodeStream(input);
}
else
{
Log.d("PHOTO","first try failed to load photo");
}
byte[] photoBytes = null;
Uri photoUri = ContentUris.withAppendedId(ContactsContract.Data.CONTENT_URI, photo_id);
Cursor c = cr.query(photoUri, new String[] {ContactsContract.CommonDataKinds.Photo.PHOTO}, null, null, null);
try
{
if (c.moveToFirst())
photoBytes = c.getBlob(0);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
} finally {
c.close();
}
if (photoBytes != null)
return BitmapFactory.decodeByteArray(photoBytes,0,photoBytes.length);
else
Log.d("PHOTO","second try also failed");
return null;
}
the code tested on emulator and Nexus S device and seems to work.
None of these approaches worked for me. What did work was:
ReplyDeleteString[] projection = new String[] {
ContactsContract.Contacts.PHOTO_ID, ///< the correct ID for photo retrieval in loadLocalContactPhotoBytes()
// ContactsContract.Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.NUMBER,
// ContactsContract.CommonDataKinds.Photo.PHOTO
};
ContentResolver cr = ctx.getContentResolver();
Cursor cursor = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
// Cursor cursor = cr.query(ContactsContract.Contacts.CONTENT_URI,
// new String[] {RawContacts._ID, RawContacts.ACCOUNT_TYPE, RawContacts.ACCOUNT_NAME},
// new String[] {Contacts._ID},
projection, null, null, ContactsContract.Contacts.DISPLAY_NAME + " ASC");
....
//the 'cursor' above got passed as an argument below
private byte[] loadLocalContactPhotoBytes(ContentResolver cr, Cursor cursor, byte[] defaultPhotoBytes)
{
byte[] photoBytes = null;// = cursor.getBlob(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Photo.PHOTO));
// int id = cursor.getInt(cursor.getColumnIndex(ContactsContract.Contacts._ID));
int id = cursor.getInt(cursor.getColumnIndex(ContactsContract.Contacts.PHOTO_ID));
// Uri contactUri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, id);
// Uri photoUri = Uri.withAppendedPath(contactUri, ContactsContract.Contacts.Photo.CONTENT_DIRECTORY);
Uri photoUri = ContentUris.withAppendedId(ContactsContract.Data.CONTENT_URI, id);
Cursor c = cr.query(photoUri, new String[] {ContactsContract.CommonDataKinds.Photo.PHOTO}, null, null, null);
try
{
if (c.moveToFirst())
photoBytes = c.getBlob(0);
} catch (Exception e) {
// TODO: handle exception
Log.w(_TAG, e.toString());
} finally {
c.close();
}
photoBytes = photoBytes == null ? defaultPhotoBytes : photoBytes;
return photoBytes;
}
It seems that my problem was because the contacts in my device were synced from facebook, and the photo therefore is not available.
ReplyDeletehttp://groups.google.com/group/android-developers/msg/be8d0cf3928e4b7f