Android opening a file with ACTION_GET_CONTENT results into different Uri's

android get file path from content uri
android get pdf file path from content uri
android get file from content uri
android open file from path
android choose file from internal storage
how to open file in android programmatically
get file name from uri android
android select file to upload

I am trying to open files by using Intent.ACTION_GET_CONTENT.

Dependent on the Android version/device brand the file browser opens and I get the following results:

Selecting a file from Downloads:

content://com.android.providers.downloads.documents/document/446

Selecting a file from Fotos:

content://media/external/images/media/309

Selecting a file from FileCommander:

file:///storage/emulated/0/DCIM/Camera/20141027_132114.jpg

I can open all these files except when I try to open a file from Downloads,, Audio , Afbeeldingen(Images)

It's likely I can't handle this kind of Uri: content://com.android.providers.downloads.documents/document/446

I have tried the following things:

  • Trying to open the file by new File(uri.getPath()). File.exists() returns false.
  • Trying to open/reach the file by getContext().getContentResolver().openInputStream(uri). Results into a FileNotFoundException
  • Trying to open the file with the following code:

    public static String getRealPathFromURI_API19(Context context, Uri uri) {
    
    Log.i("uri", uri.getPath());
    String filePath = "";
    if (uri.getScheme().equals("file")) {
        return uri.getPath();
    } else if (DocumentsContract.isDocumentUri(context, uri)) {
        String wholeID = DocumentsContract.getDocumentId(uri);
        Log.i("wholeID", wholeID);
        // Split at colon, use second item in the array
        String[] splits = wholeID.split(":");
    if (splits.length == 2) {
        String id = splits[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();
        }
    } else {
        filePath = AttachmentUtils.getPath(context, uri);
    }
    return filePath;
    }
    

What am I doing wrong?

UPDATE: I have noticed that the files that are listed in the screenshot that they are not physically existing in the storage. The device I am using is a tablet from the company containing rubbish data. My colleague told me that this device once was connected with a different Google account. These files could be the files from the previous account which are not existing/reachable anymore.

My own conclusion about it is that I am encountering some bug in Android. My bug report

Update 6 february 2017:

Android banned the file:// URI. Please consider to think about it.

Ban on file: Uri Scheme The biggest compatibility issue so far with Android 7.0 is that the file: scheme for Uri values is banned, in effect. If you attempt to pass a file: Uri in an Intent that is going to another app — whether via an extra or as the "data" facet of the Intent — you will crash with a FileUriExposedException exception. You will face similar issues with putting file: Uri values on the clipboard in ClipData . This is coming from an updated edition of StrictMode . StrictMode.VmPolicy.Builder has a penaltyDeathOnFileUriExposure() method that triggers the detection of file: Uri values and the resulting FileUriExposedException exceptions. And, it appears that this is pre-configured, much as how StrictMode is pre-configured to apply penaltyDeathOnNetwork() (the source of your NetworkOnMainThreadException crashes).

Use below code.This will work for sure.

public static String getPath(Context context, Uri uri) {

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        // DocumentProvider
        if (DocumentsContract.isDocumentUri(context, uri)) {
            // ExternalStorageProvider
            if (isExternalStorageDocument(uri)) {
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] split = docId.split(":");
                final String type = split[0];

                if ("primary".equalsIgnoreCase(type)) {
                    return Environment.getExternalStorageDirectory() + "/" + split[1];
                }
                // TODO handle non-primary volumes
            }
            // DownloadsProvider
            else if (isDownloadsDocument(uri)) {
                final String id = DocumentsContract.getDocumentId(uri);
                final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
                return getDataColumn(context, contentUri, null, null);
            }
            // MediaProvider
            else if (isMediaDocument(uri)) {
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] split = docId.split(":");
                final String type = split[0];
                Uri contentUri = null;
                if ("image".equals(type)) {
                    contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
                } else if ("video".equals(type)) {
                    contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
                } else if ("audio".equals(type)) {
                    contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
                }
                final String selection = "_id=?";
                final String[] selectionArgs = new String[]{split[1]};
                return getDataColumn(context, contentUri, selection, selectionArgs);
            }
        }
    }
    // MediaStore (and general)
    else if ("content".equalsIgnoreCase(uri.getScheme())) {
        // Return the remote address
        if (isGooglePhotosUri(uri))
            return uri.getLastPathSegment();
        return getDataColumn(context, uri, null, null);
    }
    // File
    else if ("file".equalsIgnoreCase(uri.getScheme())) {
        return uri.getPath();
    }
    return null;
}

public static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
    Cursor cursor = null;
    final String column = "_data";
    final String[] projection = {column};
    try {
        cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
        if (cursor != null && cursor.moveToFirst()) {
            final int index = cursor.getColumnIndexOrThrow(column);
            return cursor.getString(index);
        }
    } finally {
        if (cursor != null)
            cursor.close();
    }
    return null;
}

public static boolean isExternalStorageDocument(Uri uri) {
    return "com.android.externalstorage.documents".equals(uri.getAuthority());
}

/**
 * @param uri The Uri to check.
 * @return Whether the Uri authority is DownloadsProvider.
 */
public static boolean isDownloadsDocument(Uri uri) {
    return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}

/**
 * @param uri The Uri to check.
 * @return Whether the Uri authority is MediaProvider.
 */
public static boolean isMediaDocument(Uri uri) {
    return "com.android.providers.media.documents".equals(uri.getAuthority());
}

/**
 * @param uri The Uri to check.
 * @return Whether the Uri authority is Google Photos.
 */
public static boolean isGooglePhotosUri(Uri uri) {
    return "com.google.android.apps.photos.content".equals(uri.getAuthority());
}

Use the below code to browse the file in any format.

public void browseClick() {

    Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
    intent.setType("*/*");
    intent.addCategory(Intent.CATEGORY_OPENABLE);
    //intent.putExtra("browseCoa", itemToBrowse);
    //Intent chooser = Intent.createChooser(intent, "Select a File to Upload");
    try {
        //startActivityForResult(chooser, FILE_SELECT_CODE);
        startActivityForResult(Intent.createChooser(intent, "Select a File to Upload"),FILE_SELECT_CODE);
    } catch (Exception ex) {
        System.out.println("browseClick :"+ex);//android.content.ActivityNotFoundException ex
    }
}

Then get that file path in the onActivityResult like below.

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == FILE_SELECT_CODE) {
        if (resultCode == RESULT_OK) {
            try {
              Uri uri = data.getData();

                if (filesize >= FILE_SIZE_LIMIT) {
                    Toast.makeText(this,"The selected file is too large. Selet a new file with size less than 2mb",Toast.LENGTH_LONG).show();
                } else {
                    String mimeType = getContentResolver().getType(uri);
                    if (mimeType == null) {
                        String path = getPath(this, uri);
                        if (path == null) {
                            filename = FilenameUtils.getName(uri.toString());
                        } else {
                            File file = new File(path);
                            filename = file.getName();
                        }
                    } else {
                        Uri returnUri = data.getData();
                        Cursor returnCursor = getContentResolver().query(returnUri, null, null, null, null);
                        int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
                        int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
                        returnCursor.moveToFirst();
                        filename = returnCursor.getString(nameIndex);
                        String size = Long.toString(returnCursor.getLong(sizeIndex));
                    }
   File fileSave = getExternalFilesDir(null);
    String sourcePath = getExternalFilesDir(null).toString();
    try {
                        copyFileStream(new File(sourcePath + "/" + filename), uri,this);

                    } catch (Exception e) {
                        e.printStackTrace();
                    }
  }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
private void copyFileStream(File dest, Uri uri, Context context)
        throws IOException {
    InputStream is = null;
    OutputStream os = null;
    try {
        is = context.getContentResolver().openInputStream(uri);
        os = new FileOutputStream(dest);
        byte[] buffer = new byte[1024];
        int length;

        while ((length = is.read(buffer)) > 0) {
            os.write(buffer, 0, length);

        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        is.close();
        os.close();
    }
}

After this you can open this file from your application external storage where you saved the file with appropriate action.

Open files using storage access framework, Taken from the following link * https://developer.android.com/training/secure-file- sharing/retrieve-info.html#RetrieveFileInfo * * @param uri a uri to query� So we need to get the uri represent file real local path, then we can read it and save a copy to our app folder. Because from android KitKat ( sdk version 19 ), the system returned uri is not real local file path uri, it is a content provider style uri, so we should parse the uri and get the real file local path by query related content provider ( image provider, audio provider, video provider

The accepted answer on kotlin

@Suppress("SpellCheckingInspection")
object PathCompat {

    @WorkerThread
    fun getFilePath(context: Context, uri: Uri): String? = context.run {
        return try {
            when {
                Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT -> getDataColumn(uri, null, null)
                else -> getPathKitkatPlus(uri)
            }
        } catch (e: Throwable) {
            Timber.e(e)
            null
        }
    }

    @Suppress("DEPRECATION")
    @SuppressLint("NewApi", "DefaultLocale")
    private fun Context.getPathKitkatPlus(uri: Uri): String? {
        when {
            DocumentsContract.isDocumentUri(applicationContext, uri) -> {
                val docId = DocumentsContract.getDocumentId(uri)
                when {
                    uri.isExternalStorageDocument -> {
                        val parts = docId.split(":")
                        if ("primary".equals(parts[0], true)) {
                            return "${Environment.getExternalStorageDirectory()}/${parts[1]}"
                        }
                    }
                    uri.isDownloadsDocument -> {
                        val contentUri = ContentUris.withAppendedId(
                            Uri.parse("content://downloads/public_downloads"),
                            docId.toLong()
                        )
                        return getDataColumn(contentUri, null, null)
                    }
                    uri.isMediaDocument -> {
                        val parts = docId.split(":")
                        val contentUri = when (parts[0].toLowerCase()) {
                            "image" -> MediaStore.Images.Media.EXTERNAL_CONTENT_URI
                            "video" -> MediaStore.Video.Media.EXTERNAL_CONTENT_URI
                            "audio" -> MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
                            else -> return null
                        }
                        return getDataColumn(contentUri, "_id=?", arrayOf(parts[1]))
                    }
                }
            }
            "content".equals(uri.scheme, true) -> {
                return if (uri.isGooglePhotosUri) {
                    uri.lastPathSegment
                } else {
                    getDataColumn(uri, null, null)
                }
            }
            "file".equals(uri.scheme, true) -> {
                return uri.path
            }
        }
        return null
    }

    private fun Context.getDataColumn(uri: Uri, selection: String?, args: Array<String>?): String? {
        contentResolver?.query(uri, arrayOf("_data"), selection, args, null)?.use {
            if (it.moveToFirst()) {
                return it.getString(it.getColumnIndexOrThrow("_data"))
            }
        }
        return null
    }

    private val Uri.isExternalStorageDocument: Boolean
        get() = authority == "com.android.externalstorage.documents"

    private val Uri.isDownloadsDocument: Boolean
        get() = authority == "com.android.providers.downloads.documents"

    private val Uri.isMediaDocument: Boolean
        get() = authority == "com.android.providers.media.documents"

    private val Uri.isGooglePhotosUri: Boolean
        get() = authority == "com.google.android.apps.photos.content"
}

Android, Android opening a file with ACTION_GET_CONTENT results into different Uri's我正在尝试使用Intent.ACTION_GET_CONTENT打开文件。 Android opening a file with ACTION_GET_CONTENT results into different Uri's; Storing an NSMutableArray of NSObjects into NSUserDefaults; Storing data into array of hashes; JSON parsing in iOS and storing the results into Array; Storing the results from a function into a retrievable DataFrame in Python [duplicate] Storing query results into a

There is a bug I just faced

final String docId = DocumentsContract.getDocumentId(uri);

return different URI (e.g: content://com.android.providers.downloads.documents/document/11 and sometime content://com.android.providers.downloads.documents/document/abc%aile.jpg in that case Long.valueOf(id) throws an exception to fix that

String id = DocumentsContract.getDocumentId(uri);
                if (id.startsWith("raw:")) {
                    id = id.replaceFirst("raw:", "");
                    return id;
                }
                final Uri contentUri = ContentUris.withAppendedId(
                    Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));

                return getDataColumn(contentUri, null, null);

do this return the id, it worked for me

Android将具有ACTION_GET_CONTENT结果的文件打开到不同的Uri , if (cursor == null) { // Source is Dropbox or other similar local file path result = contentURI.getPath(); Best Java code snippets using android.net.Uri.getPath ( Showing top 20 results out of 4,185) URI from Intent.ACTION_GET_CONTENT into File. Uri How to open private files saved to the internal storage using Intent. A file's data type indicates to the client app how it should handle the file's contents. To get the data type of a shared file given its content URI, the client app calls ContentResolver.getType(). This method returns the file's MIME type. By default, a FileProvider determines the file's MIME type from its filename extension.

How to use getPath method in android.net.Uri, example of image picker using intent in Android Pick an image file using Intent. ACTION_GET_CONTENT is you don't have to develop open dialog box of them and then some data inside of it and returning the resulting URI to the caller. Doing hard-coded CSS and JS are quite difficult with no promising result on� Please find my code below. I need to get the file path of the pdf document, selected by the user from SDcard. The issue is that the URI.getPath() returns:

Pick a file using Intent.ACTION_GET_CONTENT, Android Gallery on Android 4.4 (KitKat) returns different URI for Intent. do is to open the InputStream from the ContentProvider, then create a Bitmap out of it. I' ve combine multiple answers into one working solution that results with file path� Hey Pratik, I have various documents (.doc, .ppt, .pdf, .xls etc) on my server, I just want to open those documents in my android app, I have tried with Google Doc Viewer url which will open in webView, but it has some limitations like bandwidth limitation, thats why i am stuck. will you please help me for opening those documents using server urls into my android application?

URI from Intent.ACTION_GET_CONTENT into File, Cannot create a file using the Uri of `ACTION_GET_CONTENT` - android. createChooser(intent, "Select PDF"), 1); } }); On activity result I get the Uri and save That Uri could point to anything that the user and the other app choose: A file I would like to open a directory, after which I should able to pick a file then delete it. The following are top voted examples for showing how to use android.net.Uri.These examples are extracted from open source projects. You can vote up the examples you like and your votes will be used in our system to generate more good examples.

Comments
  • What is your AOS version/API level? Could it be that such files you're having issues with are GoogleDrive files?
  • minSdkVersion 19 targetSdkVersion 23. The device I am testing runs on Android 5.0.2
  • getContentResolver().openInputStream(uri) should work, unless there isn't anything at given location or you don't have proper permission to access the file at given Uri.
  • @com2ghz hey, I know this is a year ago, but do you mind telling me if you built the file chooser your self?
  • No this is the native Android file picker. It could be different on some branded operating systems. So it' s even possible that you need a 3th party app to open the file browser like File Commander or TotalCommander.
  • if u got a valid file path then try to write that file to your application internal or external storage and then open the file from there.I will update my answer.
  • I'll just accept this answer. For some reason the file browser shows unexisting files. If I download a new file into the Downloads folder, then I can open the file correctly. I'm not sure if this is a bug in Android.
  • Your code can't handle microSD paths, when a file is picked from microSD, the document ID contains XXXX-XXXX instead of "primary", someone will have to add an else to "primary".equalsIgnoreCase(type).
  • @user5395084 For me split[0] contained the XXXX-XXXX id of microSD so "/storage/"+split[0]+"/"+split[1] worked for SD card. You can check if it's correct by checking new File("/storage/"+split[0]+"/"+split[1]).exists()
  • In some cases (for me api 27 with a file I dropped in the emulator), the returned uri looks like "content://com.android.providers.downloads.documents/document/raw%3A%2Fstorage%2Femulated%2F0%2FDownload%2FCprBPostLabel2850351.pdf" and getPath crashes when reconstructing the uri because the id is not convertible to a Long.
  • I've used this example to pick files. I can get files from internal storage, except "/documents". I can't pick files from external SD card too. The docId part is "home" for them.