Get URI file path from inconsistent Android native file pick returned URIs

You cannot get a common file URI from android's Intent.ACTION_GET_CONTENT. The URI may vary from different implementation of file providers. If you want to have a common URI, you have implement your own file picker or you can use some library.

If your requirement is to only send the file to the server then you can directly use the input stream from the URI and send this input stream to server.

See the SO question for more info.

The other way through which I have handled the scenario in my case is to get the path from GetPath method which you have mentioned and if it fails to give the path from URI then save the file somewhere in storage using the input stream provided by the URI. Below is the code to save the file:-

private void saveFileInStorage(final Uri uri) {

    new Thread(new Runnable() {
        @Override
        public void run() {
            File file = null;
            try {
                String mimeType = getActivity().getContentResolver().getType(uri);
                if (mimeType != null) {
                    InputStream inputStream = getActivity().getContentResolver().openInputStream(uri);

                        String fileName = getFileName(uri);
                        if (!fileName.equals("")) {
                            file = new File(
                                    getContext().getExternalFilesDir(
                                            Environment.DIRECTORY_DOWNLOADS).getAbsolutePath() + "/" + fileName);
                            OutputStream output = new FileOutputStream(file);
                            try {
                                byte[] buffer = new byte[inputStream.available()]; // or other buffer size
                                int read;

                                while ((read = inputStream.read(buffer)) != -1) {
                                    output.write(buffer, 0, read);
                                }

                                output.flush();
                                String path=file.getAbsolutePath();//use this path

                            } finally {
                                output.close();
                            }
                        }
                } 
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }).start();

}

public String getFileName(Uri uri) {
    // The query, since it only applies to a single document, will only return
    // one row. There's no need to filter, sort, or select fields, since we want
    // all fields for one document.
    String displayName = "";
    Cursor cursor = null;
    if (getActivity() != null)
        cursor = getActivity().getContentResolver()
                .query(uri, null, null, null, null, null);
    try {
        // moveToFirst() returns false if the cursor has 0 rows.  Very handy for
        // "if there's anything to look at, look at it" conditionals.
        if (cursor != null && cursor.moveToFirst()) {

            // Note it's called "Display Name".  This is
            // provider-specific, and might not necessarily be the file name.
            displayName = cursor.getString(
                    cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
            Log.i(TAG, "Display Name: " + displayName);
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (cursor != null) {
            cursor.close();
        }
    }
    return displayName;
}

If I understand correctly, you are trying to read data provided by other applications, so the file provider configuration is not relevant.

I think the problem in your code is that you are trying to extract a file path from the received URI. This does not work reliably. There is no guaranty that the document ID contains a path or that you can query a _DATA column containing a path. Basically a content URI is supposed to be an opaque handle that can only used via ContentResolver's methods like :

  • openInputStream() to get the content

  • query() to get informations, like the size or a display name (the only guarantied columns)

Mark Murphy has a more detailed explanation


Would you try this code in your Application.onCreate() and let me know if it works for you?

StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());