Yaniv
Yaniv

Reputation: 3381

Exception No photo file found for ID 0

I have a code in my app that gets URI of a contact, then verifies that contact has a photo by trying to open an input stream to the photo, gets URI to the photo and decode it.

Rarely, I get a strange exception that the URI does not exist. I get URI to a photo file which does not exist.

Get the photo URI:

// Get Uri to the contact
Uri contact = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI,
        c.getInt(c.getColumnIndex(PhoneLookup._ID)));

// Get input stream of the photo
InputStream is = Contacts.openContactPhotoInputStream(context.getContentResolver(), contact);
// If no input stream (then there is no photo of contact), return 'null' instead of photo Uri
if (is == null) {
    Log.d(TAG, "No photo");
    return;
}

// Get display photo Uri of the contact
Uri photoUri = Uri.withAppendedPath(contact, ContactsContract.Contacts.Photo.DISPLAY_PHOTO);

At this moment, when a contact does not have a photo, is gets null and return. But rarely, photoUri gets content://com.android.contacts/contacts/303/display_photo.

Now decode it (in other function):

InputStream isPhoto = context.getContentResolver().openInputStream(photoUri);

The exception that is thrown from this line is:

java.io.FileNotFoundException: No photo file found for ID 0
    at android.database.DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(DatabaseUtils.java:146)
    at android.content.ContentProviderProxy.openTypedAssetFile(ContentProviderNative.java:617)
    at android.content.ContentResolver.openTypedAssetFileDescriptor(ContentResolver.java:717)
    at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:614)
    at android.content.ContentResolver.openInputStream(ContentResolver.java:449)
    at com.app.android.utils.ImageUtils.decodeBitmapFromPhotoUri(ImageUtils.java:39)
    ...

How is it possible that the content resolver gives me URI to a photo that does not exist (contact exists and does not have a photo, for sure) instead of returning null?

UPDATE: I see that it happens only with photos that were not taken by the device (like photos that were received from the google account or photos that were downloaded from the internet).

Upvotes: 1

Views: 1961

Answers (2)

Adrian
Adrian

Reputation: 735

While following the example from ContactsContract.Contacts.Photo I got the same exception as you did when trying to use openDisplayPhoto:

    public InputStream openDisplayPhoto(long contactId) {
    Uri contactUri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI,
            contactId);
    Uri displayPhotoUri = Uri.withAppendedPath(contactUri, ContactsContract.Contacts.Photo
            .DISPLAY_PHOTO);
    try {
        AssetFileDescriptor fd =
                getContentResolver().openAssetFileDescriptor(displayPhotoUri, "r");
        return fd.createInputStream();
    } catch (IOException e) {
        e.printStackTrace();
        return null;
    }
}

And it worked fine when using openPhoto (which is actually the thumbnail):

    public InputStream 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 new ByteArrayInputStream(data);
            }
        }
    } finally {
        cursor.close();
    }
    return null;
}

Indeed, when the contact image comes from Google+ for example, it will only be available as thumbnail and not as a normal full sized image.

Upvotes: 0

Yaniv
Yaniv

Reputation: 3381

After changing the way of getting the input stream of the photo, all work.

Instead of:

InputStream isPhoto = context.getContentResolver().openInputStream(photoUri);

I used:

InputStream photoInputStream =
    Contacts.openContactPhotoInputStream(context.getContentResolver(), contactUri);

Pay attention: Now the Uri is of the contact and not of the his photo.

Upvotes: 3

Related Questions