androidexifandroidxandroid-10.0android-exifinterface

ExifInterface GPS not read on Android Q/10


I'm having the issue that Android 10 can't read GPS information from my jpeg files. The exact same files are working on Android 9. I tried the ExifInterface (androidx) which returns null, as well as apache commons imaging which is saying "GPSLatitude: Invalid rational (0/0), Invalid rational (0/0)". Other exif information like the rating or XPKeywords are read correctly.

How to fix that?

Test code:

import androidx.exifinterface.media.ExifInterface;
ExifInterface exif2 = new ExifInterface(is);
double[] latLngArray = exif2.getLatLong();

getLatLong Implementation:

public double[] getLatLong() {
    String latValue = getAttribute(TAG_GPS_LATITUDE);
    String latRef = getAttribute(TAG_GPS_LATITUDE_REF);
    String lngValue = getAttribute(TAG_GPS_LONGITUDE);
    String lngRef = getAttribute(TAG_GPS_LONGITUDE_REF);
    if (latValue != null && latRef != null && lngValue != null && lngRef != null) {
        try {
            double latitude = convertRationalLatLonToDouble(latValue, latRef);
            double longitude = convertRationalLatLonToDouble(lngValue, lngRef);
            return new double[] {latitude, longitude};
        } catch (IllegalArgumentException e) {
            Log.w(TAG, "Latitude/longitude values are not parseable. " +
                    String.format("latValue=%s, latRef=%s, lngValue=%s, lngRef=%s",
                            latValue, latRef, lngValue, lngRef));
        }
    }
    return null;
}

All getAttribute calls are returning null on Android Q/10. On Android 9 it is working. My test photo does contain GPS information. Even Android itself was unable to index the GPS location into their media store. The field is null as well in their database. I transferred the test photo via mail.


Solution

  • As mentioned in developer android, now, on Android 10, the location embed on image files is not directly available to the apps:

    Because this location information is sensitive, however, Android 10 by default hides this information from your app if it uses scoped storage.

    On that same link, you can check how to fix:

    1. Request the ACCESS_MEDIA_LOCATION permission in your app's manifest.

    2. From your MediaStore object, call setRequireOriginal(), passing in the URI of the photograph, as shown in the following code snippet:

    Code snippet:

    Uri photoUri = Uri.withAppendedPath(
            MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
            cursor.getString(idColumnIndex));
    
    // Get location data from the ExifInterface class.
    photoUri = MediaStore.setRequireOriginal(photoUri);
    InputStream stream = getContentResolver().openInputStream(photoUri);
    if (stream != null) {
        ExifInterface exifInterface = new ExifInterface(stream);
        // Don't reuse the stream associated with the instance of "ExifInterface".
        stream.close();
    } else {
        // Failed to load the stream, so return the coordinates (0, 0).
        latLong = new double[2];
    }
    

    Note how they are now using Uri, InputStream (and also FileDescriptor) to access the file since now, you can't access a file using its file path.