2

I'm trying to update contact images via the ContentProvider in my app. This works nearly always (I use this method for about 4 years in a production app, with ~50000 users and 1M downloads). I nearly never have problems, but it seems like the function is not bullet proof. It fails on one users device repeatedly and I don't know why.

What I do

I simply have bitmap and try to save if for a known contact id. If the contact already has an image, I replace it, otherwise I add the image.

Result and Quesiton

The contact image is not updated on one users device. The log says, the failing contact does not have an image yet. That's fine, so I just create a new one. The function returns an Uri but this one is null, so saving the image failed. Why? Any ideas?

Log info:

Contact image set - updated: -1, newUri: NULL, old photoId: -1

Device info:

  • other contacts do work, only a handful of contacts fail
  • the device has plenty of space left, so this can't be the source either
  • user only uses google contacts and no other service (like outlook or similar, so no read only contacts or similar)

Code

// the id of the contact
long contactRawId = ...;

// 1) get bitmap
Bitmap bitmap = ...;

// 2) Convert Bitmap to byte
byte[] photo = 

// 3) save or update contact picture via content provider
ContentValues values = new ContentValues();
int photoId = -1;
String where = ContactsContract.Data.RAW_CONTACT_ID + " == " +
        contactRawId + " AND " + ContactsContract.Contacts.Data.MIMETYPE + "=='" +
        ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE + "'";
Cursor cursor = MainApp.get().getContentResolver().query(
        ContactsContract.Data.CONTENT_URI,
        null,
        where,
        null,
        null);
int idIdx = cursor.getColumnIndexOrThrow(ContactsContract.Data._ID);
if (cursor.moveToFirst()) {
    photoId = cursor.getInt(idIdx);
}
cursor.close();
values.put(ContactsContract.Data.RAW_CONTACT_ID, contactRawId);
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);

int updated = -1;
Uri newUri = null;
if (photoId >= 0) {
    updated = MainApp.get().getContentResolver().update(
            ContactsContract.Data.CONTENT_URI,
            values,
            ContactsContract.Data._ID + " = " + photoId, null);
} else {
    newUri = MainApp.get().getContentResolver().insert(
            ContactsContract.Data.CONTENT_URI,
            values);
}

L.d("Contact image set - updated: %d, newUri: %s, old photoId: %d", updated, newUri, photoId);

Observations

  • one guy with this problem had a rooted OnePlus 3t running Nougat 7.1.1
  • in the meantime he cleared the app data and now all contacts are working
prom85
  • 16,896
  • 17
  • 122
  • 242
  • Looks like you'll get a null Uri if the row can't be inserted in the database: https://android.googlesource.com/platform/packages/providers/ContactsProvider/+/master/src/com/android/providers/contacts/ContactsProvider2.java#2769 Why that is though I don't know. Is there anything different with that photo's byte array? Does it only happen on certain devices (i.e. the vendor may have some patch in the contacts provider), or on certain cookies? – fejd Jun 11 '18 at 15:46
  • I know that the insert fails, the result (no change in t the contact) shows this as well. The questions is why... The weird thing, on the problematic device, SOME contacts work, SOME not. The ones that don't work don't work repeatedly.... The device was a rooted OnePlus 3t running Nougat 7.1.1... – prom85 Jun 12 '18 at 06:13
  • Additionally, this guy just cleared app data and now it's working... Not sure if this really is the cause for the changed beahviour though... – prom85 Jun 12 '18 at 06:15
  • posting the logcat of the device would really help – Lucem Jun 12 '18 at 15:51

2 Answers2

0

Probably you are running the update process in main Thread. Move the update process in an AsyncTask.

Heavy tasks, or tasks that includes asynchronous operations like download tasks must be always moved in another thread, otherwise they will be bond to UI thread and skipped if they will not complete the work fast enough, leading to strange undesired effects.

Silverstorm
  • 15,398
  • 2
  • 38
  • 52
0

This does not look like an issue with the code but with the phone

It fails on one users device repeatedly and I don't know why.

I had a similar issue with an app but different functionality. To fix the problem, You will need to use the user's device and debug the app (You can clone it). Having issues on a single device exempting others shows that the device is the problem, it may require "Weird" permissions.

Lucem
  • 2,912
  • 3
  • 20
  • 33