3

I have an app that extracts an uploaded image's GPS coordinates (via ExifInterface) - in order to do so it has to convert the image's Uri to its filepath. It works when testing on emulators (two emulators, different Android versions), but doesn't work when testing on a real Android device.

Error output on real device:

01-08 19:39:35.203: D/fr.free.nrw.commons.upload.ShareActivity(16980): Uri: content://media/external/images/media/10716
01-08 19:39:35.203: W/Image(16980): java.lang.IllegalArgumentException: Invalid URI: content://media/external/images/media/10716
01-08 19:39:35.203: W/Image(16980):     at android.provider.DocumentsContract.getDocumentId(DocumentsContract.java:752)
01-08 19:39:35.203: W/Image(16980):     at fr.free.nrw.commons.upload.FilePathConverter.getFilePath(FilePathConverter.java:31)
01-08 19:39:35.203: W/Image(16980):     at fr.free.nrw.commons.upload.ShareActivity.onCreate(ShareActivity.java:193)
01-08 19:39:35.203: W/Image(16980):     at android.app.Activity.performCreate(Activity.java:6289)
01-08 19:39:35.203: W/Image(16980):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1119)
01-08 19:39:35.203: W/Image(16980):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2655)
01-08 19:39:35.203: W/Image(16980):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2767)
01-08 19:39:35.203: W/Image(16980):     at android.app.ActivityThread.access$900(ActivityThread.java:177)
01-08 19:39:35.203: W/Image(16980):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1449)
01-08 19:39:35.203: W/Image(16980):     at android.os.Handler.dispatchMessage(Handler.java:102)
01-08 19:39:35.203: W/Image(16980):     at android.os.Looper.loop(Looper.java:145)
01-08 19:39:35.203: W/Image(16980):     at android.app.ActivityThread.main(ActivityThread.java:5951)
01-08 19:39:35.203: W/Image(16980):     at java.lang.reflect.Method.invoke(Native Method)
01-08 19:39:35.203: W/Image(16980):     at java.lang.reflect.Method.invoke(Method.java:372)
01-08 19:39:35.203: W/Image(16980):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1399)
01-08 19:39:35.203: W/Image(16980):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194)

Relevant code in ShareActivity that calls the FilePathConverter:

    mediaUriString = mediaUri.toString();
    Log.d(TAG, "Uri: " + mediaUriString);
    //convert image Uri to file path
    FilePathConverter uriObj = new FilePathConverter(this, mediaUri);
    String filePath = uriObj.getFilePath();

FilePathCoverter code that converts image Uri to filepath:

public class FilePathConverter {

    private Uri uri;
    private Context context;

    public FilePathConverter(Context context, Uri uri) {
        this.context = context;
        this.uri = uri;
    }

    public String getFilePath(){

        String filePath ="";

        try {
            // Will return "image:x*"
            String wholeID = DocumentsContract.getDocumentId(uri);

            // Split at colon, use second item in the array
            String id = wholeID.split(":")[1];
            String[] column = {MediaStore.Images.Media.DATA};

            // where id is equal to
            String sel = MediaStore.Images.Media._ID + "=?";
            Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                    column, sel, new String[]{id}, null);

            int columnIndex = cursor.getColumnIndex(column[0]);

            if (cursor.moveToFirst()) {
                filePath = cursor.getString(columnIndex);
            }
            cursor.close();

            Log.d("Image", "File path: " + filePath);
            return filePath;
        } catch (IllegalArgumentException e) {
            Log.w("Image", e);
            return null;
        }
    }
}

The entire codebase can be found on GitHub if needed. The closest answer I can find is How to use ExifInterface with a stream or URI, but it doesn't work either.

Output on my emulator:

01-08 08:11:48.421: D/fr.free.nrw.commons.upload.ShareActivity(2188): Uri: content://com.android.providers.media.documents/document/image%3A24
01-08 08:11:48.421: D/fr.free.nrw.commons.upload.ShareActivity(2188): Ext storage dir: /storage/sdcard
01-08 08:11:48.429: D/fr.free.nrw.commons.upload.ShareActivity(2188): Filepath: /storage/sdcard/Download/20151231_234740.jpg
01-08 08:11:48.429: D/fr.free.nrw.commons.upload.ShareActivity(2188): Calling GPSExtractor
01-08 08:11:48.436: D/fr.free.nrw.commons.upload.ShareActivity(2188): Decimal coords of image: -36.85254286111111|174.7669525

Output on real device:

01-08 21:07:59.558: D/fr.free.nrw.commons.upload.ShareActivity(30904): Uri: content://media/external/images/media/10777
01-08 21:07:59.558: D/fr.free.nrw.commons.upload.ShareActivity(30904): Ext storage dir: /storage/emulated/0
Community
  • 1
  • 1
misaochan
  • 890
  • 2
  • 8
  • 25
  • what are you doing and what you want to achieve – Allay Khalil Jan 08 '16 at 07:09
  • Like I said, I need to convert the image's URI into a filepath to extract its GPS coordinates (via ExifInterface) – misaochan Jan 08 '16 at 07:10
  • I mean Are you downloading the images and saving them in the device – Allay Khalil Jan 08 '16 at 07:14
  • The images were taken by the device camera, I am checking their GPS coords and then uploading them (the upload works, it uses Uri instead of filepath) – misaochan Jan 08 '16 at 07:16
  • I think the problem is in getting the images from the path ,. – Allay Khalil Jan 08 '16 at 07:25
  • first tell me what way are you using to get the imges name , any thing from device ? – Allay Khalil Jan 08 '16 at 07:26
  • It's rather complicated as this is an existing app, the image Uri is passed through a parcel. But the Uri should be fine as the upload actually works. The entire codebase can be found at https://github.com/misaochan/apps-android-commons/tree/caching – misaochan Jan 08 '16 at 07:30
  • then its really complicated to tell you from this minimum sort of information. well I can guess that for whatever you are trying to get the file path from the uri , i think you do not need to convert the uri , You should use the coming uri as it is , as it looks like path to itself. – Allay Khalil Jan 08 '16 at 07:35
  • I think jaypal Rana has good clue – Allay Khalil Jan 08 '16 at 07:36
  • Doesn't ExifInterface's docs explicitly state that a filename and not Uri is needed? It doesn't work directly on a Uri. – misaochan Jan 08 '16 at 07:43
  • I have checked the interface in docs – Allay Khalil Jan 08 '16 at 07:50
  • and it has method public ExifInterface(String filename) throws IOException { if (filename == null) { throw new IllegalArgumentException("filename cannot be null"); } mFilename = filename; loadAttributes(); } – Allay Khalil Jan 08 '16 at 07:50

2 Answers2

19

if you want to get real path from uri than use this method.

private String getRealPathFromURI(Uri contentURI) {
        String result;
        Cursor cursor = getContentResolver().query(contentURI, null, null, null, null);
        if (cursor == null) { // Source is Dropbox or other similar local file path
            result = contentURI.getPath();
        } else {
            cursor.moveToFirst();
            int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
            result = cursor.getString(idx);
            cursor.close();
        }
        return result;
}
Mimo
  • 6,015
  • 6
  • 36
  • 46
Jaypal Rana
  • 277
  • 1
  • 10
1

try this,

Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.INTERNAL_CONTENT_URI,
                    column, sel, new String[]{id}, null);

because your emulator cannot have sdcard.

for reference. How to get my Android device Internal Download Folder path

Community
  • 1
  • 1
Jaypal Rana
  • 277
  • 1
  • 10
  • It works on the emulator (and my emulator does have an emulated sdcard). It doesn't work on the real device. Does this mean that I need different query parameters depending on whether the image is from a SD card or not? The user can select an image from anywhere, so is there a way I can tell whether the SDcard is selected? – misaochan Jan 08 '16 at 07:39
  • Edit: Also, tried this anyway and it doesn't work, same exception :( – misaochan Jan 08 '16 at 07:53