Home » Android » java – Changing contact's image to a large photo via PHOTO_FILE_ID in Android

java – Changing contact's image to a large photo via PHOTO_FILE_ID in Android

Posted by: admin May 14, 2020 Leave a comment

Questions:

This seems to work for small images:

ContentValues values = new ContentValues();

values.put(ContactsContract.Data.RAW_CONTACT_ID, id);
values.put(ContactsContract.Data.IS_SUPER_PRIMARY, 1);
values.put(ContactsContract.CommonDataKinds.Photo.PHOTO, photo);
values.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE);
if (photoRow >= 0) {
    context.getContentResolver().update(ContactsContract.Data.CONTENT_URI, values, ContactsContract.Data._ID + " = " + photoRow, null);
} else {
    context.getContentResolver().insert(ContactsContract.Data.CONTENT_URI, values);
}

From the docs I realise that for large images I need to set the PHOTO_FILE_ID, so I can replace:

ContactsContract.CommonDataKinds.Photo.PHOTO

with:

ContactsContract.CommonDataKinds.Photo.PHOTO_FILE_ID

However, then I need to supply a PHOTO_FILE_ID rather than raw data. My question:

  1. How do I save the photo (byte []) and get a PHOTO_FILE_ID?
  2. If there is already a photo available (PHOTO not PHOTO_FILE_ID). Do I need to delete it for the big image to be seen or does the big image take precedence, if not, how do I delete it?
How to&Answers:

Your own answer will work, but it’s not very efficient because the photo needs to be encoded into an SQL query and piped through Android IPC. That also makes it a subject to Android’s IPC size limit of 1MB (i.e. if your photo is too large the content provider operation will fail).

The most efficient way to set (create or override) a RawContact’s (primary) photo is by using openAssetFileDescriptor and a ContactsContract.RawContacts.DisplayPhoto URI like so (example copied from Android docs):

public void writeDisplayPhoto(long rawContactId, byte[] photo) {
    Uri rawContactPhotoUri = Uri.withAppendedPath(
            ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId),
            RawContacts.DisplayPhoto.CONTENT_DIRECTORY);
    try {
        AssetFileDescriptor fd =
            getContentResolver().openAssetFileDescriptor(rawContactPhotoUri, "rw");
        OutputStream os = fd.createOutputStream();
        os.write(photo);
        os.close();
        fd.close();
    } catch (IOException e) {
        // Handle error cases.
    }
}

The only drawback of this approach is that it always creates/replaces the primary photo of the RawContact. If the RawContact doesn’t have a photo yet this will add one.

Unfortunately there is no way to use openAssetFileDescriptor with a PHOTO_FILE_ID, so you can’t override a specific photo identified by its ID using this method. However, in real life most contacts probably have at most one photo, so that’s not a real limitation.

This will automatically update the Photo.PHOTO column with a thumbnail of the large photo and assign a PHOTO_FILE_ID.

Answer:

Finally was able to solve it with:

public void changeContactImage(String contactId, byte[] b) {
 ArrayList < ContentProviderOperation > ops = new ArrayList < > ();

 ops.add(ContentProviderOperation
  .newUpdate(
   ContactsContract.Data.CONTENT_URI)
  .withSelection(
   ContactsContract.Data.CONTACT_ID + " = ? AND " + ContactsContract.Data.MIMETYPE + " = ?",
   new String[] {
    contactId,
    ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE
   })
  .withValue(ContactsContract.CommonDataKinds.Photo.DATA15, b).build());


 // Do something with the phone number...
 try {

  context.getContentResolver().
  applyBatch(ContactsContract.AUTHORITY, ops);

 } catch (RemoteException e) {
  Log.d("RemoteException", e.toString());
 } catch (OperationApplicationException e) {
  Log.d("OperationException", e.toString());
 }

}

Answer:

The PHOTO_FILE_ID is the ID not of a file (confusingly) but of a row in the database which contains your raw photo data. According to the docs I’ve looked at you can actually avoid using it (from the docs) :

Under PHOTO_FILE_ID

If present, this will be used to populate PHOTO_URI

and Under PHOTO_ID (which is guaranteed populated if PHOTO_FILE_ID exists)

Reference to the row in the data table holding the photo. A photo can be referred to either by ID (this field) or by URI (see PHOTO_THUMBNAIL_URI and PHOTO_URI)

This implies that if you just use PHOTO_URI you will get the same resulting image as if you made the method openDisplayPhoto. It also suggests that the URI methods are better compatible with 3rd part directories so are probably preferable to work with

Answer:

You can get the contact photo uri without using ContactsContract.CommonDataKinds.Email.PHOTO_URI this way:
Read Full Answer here More

Where! to get Contact URI as you said try this:

import android.provider.ContactsContract.PhoneLookup;

public String fetchContactIdFromPhoneNumber(String phoneNumber) {
    Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI,
        Uri.encode(phoneNumber));
    Cursor cursor = this.getContentResolver().query(uri,
        new String[] { PhoneLookup.DISPLAY_NAME, PhoneLookup._ID },
        null, null, null);

    String contactId = "";

    if (cursor.moveToFirst()) {
        do {
        contactId = cursor.getString(cursor
            .getColumnIndex(PhoneLookup._ID));
        } while (cursor.moveToNext());
    }

    return contactId;
  }

To get the conatct id using the phone number use the following code:

import android.provider.ContactsContract.PhoneLookup;

public String fetchContactIdFromPhoneNumber(String phoneNumber) {
    Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI,
        Uri.encode(phoneNumber));
    Cursor cursor = this.getContentResolver().query(uri,
        new String[] { PhoneLookup.DISPLAY_NAME, PhoneLookup._ID },
        null, null, null);

    String contactId = "";

if (cursor.moveToFirst()) {
    do {
    contactId = cursor.getString(cursor
        .getColumnIndex(PhoneLookup._ID));
    } while (cursor.moveToNext());
}

return contactId;

}

and use the contact id obtained to get the contatc photo URI. Use the following code for getting photo URI:

import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Phone;

public Uri getPhotoUri(long contactId) {
    ContentResolver contentResolver = getContentResolver();

    try {
        Cursor cursor = contentResolver
            .query(ContactsContract.Data.CONTENT_URI,
                null,
                ContactsContract.Data.CONTACT_ID
                    + "="
                    + contactId
                    + " AND "

                    + ContactsContract.Data.MIMETYPE
                    + "='"
                    + ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE
                    + "'", null, null);

        if (cursor != null) {
        if (!cursor.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, contactId);
    return Uri.withAppendedPath(person,
        ContactsContract.Contacts.Photo.CONTENT_DIRECTORY);
  }

Please let me know if this does not answer your question