-1

I'm using the FileProvider pattern for creating content:// uri to files, with the

FileProvider.getUriForFile(this, "com.myapp.provider", file) 

function. I have the manifest, provider_paths and everything set the standard way, It creates an uri like content://com.myapp.provider/external_files/music/mysong.mp3.

My issue is that if I try getting the real file path in another app, it doesn't work as the _data column doesn't exist (to be specific the error in logs is E/CursorWindow: Failed to read row 0, column -1 from a CursorWindow which has 1 rows, 0 columns.). For fetching the real path I'm using the also pretty much standard function

final String column = MediaStore.Files.FileColumns.DATA;
final String[] projection = { column  };
try {
    cursor = context.getContentResolver().query(uri, projection, null, null, null);
    if (cursor != null && cursor.moveToFirst()) {
        final int column_index = cursor.getColumnIndexOrThrow(column);
        return cursor.getString(column_index);
    }
} finally {
    if (cursor != null)
        cursor.close();
}

If I use a different app for sharing the same file it generates an uri like content://com.otherapp.provider/external_files/music/mysong.mp3, from which I can already retrieve the real file path. Any ideas what do I have to do to make sure that my app properly inserts the given uri to ContentResolver? Manual contentResolver.insert(...) functions are not allowed. I've tried different versions of provider_paths.xml and granting all possible read/write permissions to the given uri, but I could never retrieve the real path.

The uri itself generated by me works fine as I can read the file or play the song, my issue is just that I cannot retrieve the real file path that I need.

Thanks

tibbi
  • 249
  • 4
  • 27
  • 1
    Yet another... There is no proper way to get "real file path", end of story. Also you DON'T NEED IT. – Selvin Apr 02 '18 at 21:16

1 Answers1

5

My issue is that if I try getting the real file path in another app

The other app should not be trying to do this.

For fetching the real path I'm using the also pretty much standard function

That works for very few Uri values.

If I use a different app for sharing the same file it generates an uri like content://com.otherapp.provider/external_files/music/mysong.mp3, from which I can already retrieve the real file path.

That is not guaranteed.

Any ideas what do I have to do to make sure that my app properly inserts the given uri to ContentResolver?

You don't. You fix the client app, which should not be attempting to get a "real file path" from a Uri.

my issue is just that I cannot retrieve the real file path that I need.

Instead, for a Uri with a content scheme:

Step #1: Get a ContentResolver, by calling getContentResolver() on some Context (e.g., an activity)

Step #2: Call openInputStream() on the ContentResolver, passing in your Uri, to get an InputStream on that content

Step #3: Consume the content via that InputStream

If you are using some third-party library that can only work with files, copy the data from that InputStream to some FileOutputStream, then use the resulting file with that library.

This way, no matter where the content is coming from (a file that you could access, a file that you cannot access, a BLOB column in a database, etc.), you will have code that works.

See also:

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • I use a third-party image processing library that only works with paths to files and heavily depends on the file extension to help it decode said file. I can do as you suggest and create a new file from the stream but i need the file extension or perhaps full filename and extension of the original file, is there anyway this can get passed via the URI? – Asiimwe Oct 30 '18 at 15:29
  • @Asiimwe: No. There is no requirement for the `Uri` to point to anything that might have ever been a file anywhere. You can get a MIME type, and you can try to use `MimeTypeMap` to derive a file extension, but there is no guarantee that the MIME type reported for that `Uri` is known to `MimeTypeMap`. You can get a "display name", but there is no requirement that it is a filename. If you absolutely need a file, [use a file-picker library](https://android-arsenal.com/tag/35?sort=created) that only works with the filesystem, instead of `ACTION_GET_CONTENT`, `ACTION_OPEN_DOCUMENT`, etc. – CommonsWare Oct 30 '18 at 21:06