A final answer on how to get Exif data from URI

Getting EXIF from a content URI (an InputStream actually) is now available in the support library. See: https://android-developers.googleblog.com/2016/12/introducing-the-exifinterface-support-library.html


To expand on alex.dorokhov's answer with some sample code. The support library is a great way to go.

build.gradle

dependencies {
...    
compile "com.android.support:exifinterface:25.0.1"
...
}

Example code:

import android.support.media.ExifInterface;
...
try (InputStream inputStream = context.getContentResolver().openInputStream(uri)) {
      ExifInterface exif = new ExifInterface(inputStream);
      int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
    } catch (IOException e) {
      e.printStackTrace();
    }

The reason I had to do it this way once we started targeting api 25 (maybe a problem on 24+ also) but still supporting back to api 19, on android 7 our app would crash if I passed in a URI to the camera that was just referencing a file. Hence I had to create a URI to pass to the camera intent like this.

FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".fileprovider", tempFile);

The issue there is that file its not possible to turn the URI into a real file path (other than holding on to the temp file path).


The following works with all apps I have tested, in any case:

That will only work if the Uri happens to be something coming from the MediaStore. It will fail if the Uri happens to come from anything else.

The immediate answer is You don’t, you don’t find file paths from content uris in newer version of the OS. It could be said that not all content uris point to pictures or even files.

Correct. I have pointed this out on many occasions, such as here.

How are we supposed to use the ExifInterface class if we should not use paths?

You don't. Use other code to get the EXIF headers.

There might be external libraries that read Exif stuff from a stream, but I’m wondering about the common/platform way to solve this.

Use external libraries.

I have searched for similar code in google’s open source apps, but found nothing.

You will find some in the Mms app.

UPDATE: 2020-01-10: Use ExifInterface from the AndroidX libraries. It supports using InputStream to read in the EXIF data, and you can get an InputStream for content identified by a Uri by means of a ContentResolver.


Don't use EXIF. You can get orientation of image from Uri like this:

private static int getOrientation(Context context, Uri photoUri) {
    Cursor cursor = context.getContentResolver().query(photoUri,
            new String[]{MediaStore.Images.ImageColumns.ORIENTATION}, null, null, null);

    if (cursor.getCount() != 1) {
        cursor.close();
        return -1;
    }

    cursor.moveToFirst();
    int orientation = cursor.getInt(0);
    cursor.close();
    cursor = null;
    //orientation here can be 90, 180, 270!
}