Java – crashes when selecting files from downloads

crashes when selecting files from downloads… here is a solution to the problem.

crashes when selecting files from downloads

I use this fileutils class when selecting files from the device:

public class FileUtils {
private FileUtils() {

private static final String TAG = "FileUtils";
private static final boolean DEBUG = false;

private static boolean isExternalStorageDocument(Uri uri) {
    return "".equals(uri.getAuthority());

private static boolean isDownloadsDocument(Uri uri) {
    return "".equals(uri.getAuthority());

private static boolean isMediaDocument(Uri uri) {
    return "".equals(uri.getAuthority());

private static boolean isGooglePhotosUri(Uri uri) {
    return "".equals(uri.getAuthority());

private static String getDataColumn(Context context, Uri uri, String selection,
                                    String[] selectionArgs) {

Cursor cursor = null;
    final String column = "_data";
    final String[] projection = {

try {
        cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
        if (cursor != null && cursor.moveToFirst()) {
            if (DEBUG)

final int column_index = cursor.getColumnIndexOrThrow(column);
            return cursor.getString(column_index);
    } finally {
        if (cursor != null)
    return null;

@RequiresApi(api = Build.VERSION_CODES. KITKAT)
public static String getPath(final Context context, final Uri uri) {

if (DEBUG)
        Log.d(TAG + " File -",
                "Authority: " + uri.getAuthority() +
                        ", Fragment: " + uri.getFragment() +
                        ", Port: " + uri.getPort() +
                        ", Query: " + uri.getQuery() +
                        ", Scheme: " + uri.getScheme() +
                        ", Host: " + uri.getHost() +
                        ", Segments: " + uri.getPathSegments().toString()

final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES. KITKAT;

    if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {

        if (isExternalStorageDocument(uri)) {
            final String docId = DocumentsContract.getDocumentId(uri);
            final String[] split = docId.split(":");
            final String type = split[0];

 This is for checking Main Memory
            if ("primary".equalsIgnoreCase(type)) {
                if (split.length > 1) {
                    return Environment.getExternalStorageDirectory() + "/" + split[1];
                } else {
                    return Environment.getExternalStorageDirectory() + "/";
                 This is for checking SD Card
            } else {
                return "storage" + "/" + docId.replace(":", "/");

        else if (isDownloadsDocument(uri)) {
            final String id = DocumentsContract.getDocumentId(uri);
            if (id.startsWith("raw:")) {
                String[] data = new String[2];
                data[0] = id.replaceFirst("raw:", "");
                data[1] = null;
                return data[0];
            final Uri contentUri = ContentUris.withAppendedId(
                    Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));

return getDataColumn(context, contentUri, null, null);
        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[]{

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);
    else if ("file".equalsIgnoreCase(uri.getScheme())) {
        return uri.getPath();

return null;

I call this class like this in onActivityResult:

String sourcePath = FileUtils.getPath(this, data.getData());

For some reason I’m experiencing the following crash:

Caused by java.lang.IllegalArgumentException: Unknown URI: content://downloads/public_downloads/230
   at android.database.DatabaseUtils.readExceptionFromParcel(
   at android.database.DatabaseUtils.readExceptionFromParcel(
   at android.content.ContentProviderProxy.query(
   at android.content.ContentResolver.query(
   at android.content.ContentResolver.query(
   at android.content.ContentResolver.query(
   at com. HBiSoft.ProGolf.Utils.FileUtils.getDataColumn(
   at com. HBiSoft.ProGolf.Utils.FileUtils.getPath(
   at com. HBiSoft.ProGolf.MainActivity.onActivityResult(
   at Source)
   at android.os.Handler.dispatchMessage(
   at android.os.Looper.loop(
   at java.lang.reflect.Method.invoke(

The crash only occurs when a file is selected from the download folder.

Can someone help me with this?


I’ve created a gist to fix this, here is link


When you select a file from Google Drive or Dropbox, you get the following error message:

Caused by java.lang.IllegalArgumentException: column '_data' does not exist

To fix this, you actually have to make a temporary copy of the file you are trying to select.

First you have to check if the content:// URI is from Google Drive, which you can do by doing the following:

public boolean isGoogleDrive(Uri uri) {
    return String.valueOf(uri).toLowerCase().contains("");

This will return true if it is a file from Google Drive. If yes, I’ll call an AsyncTask like this:

//The data.getData() below refers to the uri you get in onActivityResult
if (isGoogleDrive(data.getData())) {
    DownloadAsyncTask asyntask = new DownloadAsyncTask(data.getData(), this);
    asyntask.callback = this;

In AsyncTask, we will use the Uri to open an InputStream and retrieve the file of the byte data that we will use to make the copy.

This is the AsyncTask class (I added comments to make it easier to understand):

class DownloadAsyncTask extends AsyncTask<Uri, Void, String> {
    private Uri mUri;
    CallBackTask callback;
    Context mContext;
    private AlertDialog mdialog;

DownloadAsyncTask(Uri uri, Context context) {
        this.mUri = uri;
        mContext = context;

 In the onPreExecute() I'm displaying a custom dialog, this is not necessary, but recommended for when the user selects a large file
    protected void onPreExecute() {
        final AlertDialog.Builder mPro = new AlertDialog.Builder(new ContextThemeWrapper(mContext,;
        Get reference to dialog layout
        final View mPView = LayoutInflater.from(mContext).inflate(R.layout.dialog, null);
        Get reference to dialog title
        final TextView title = mPView.findViewById(;
        Get reference to dialog description
        final TextView desc = mPView.findViewById(;

Set title text
        title.setText("Please wait..");
        Set description text
        desc.setText("Drive files needs to be imported, this might take some time depending on the file size.");

        mdialog = mPro.create();;


@RequiresApi(api = Build.VERSION_CODES. KITKAT)
    protected String doInBackground(Uri... params) {
        This will be the file we will use (the one that will be copied)
        File file = null;
        try {
            Create a temporary folder where the copy will be saved to
            File temp_folder = mContext.getExternalFilesDir("TempFolder");

Use ContentResolver to get the name of the original name
            Create a cursor and pass the Uri to it
            Cursor cursor = mContext.getContentResolver().query(mUri, null, null, null, null);
            Check that the cursor is not null
            assert cursor != null;
            int nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
            Get the file name
            String filename = cursor.getString(nameIndex);
            Close the cursor

open a InputStream by passing it the Uri
            We have to do this in a try/catch
            InputStream is = null;
            try {
                is = mContext.getContentResolver().openInputStream(mUri);
            } catch (FileNotFoundException e) {

We now have a folder and a file name, now we can create a file
            file = new File(temp_folder + "/" + filename);

We can now use a BufferedInputStream to pass the InputStream we opened above to it
            BufferedInputStream bis = new BufferedInputStream(is);
            We will write the byte data to the FileOutputStream, but we first have to create it
            FileOutputStream fos = new FileOutputStream(file);

byte data[] = new byte[1024];
            long total = 0;
            int count;
            Below we will read all the byte data and write it to the FileOutputStream
            while ((count = != -1) {
                total += count;
                fos.write(data, 0, count);
            The FileOutputStream is done and the file is created and we can clean and close it

} catch (IOException e) {
            Log.e("IOException = ", String.valueOf(e));

Finally we can pass the path of the file we have copied
        return file.getAbsolutePath();


protected void onPostExecute(String result) {
        We are done and can cancel the dialog
        if (mdialog != null && mdialog.isShowing()) {
        I'm using a callback to let my Activity know that the AsyncTask is done. I pass the path along.


You can see that in onPostExecute() above I have callback.getResultFromAsynTask(result); 。 As I mentioned in the comment, I’m using the callback method to let the activity know I’m done and pass the path to the callback.

In your activity, you must implement callbacks as follows:

public class MainActivity extends AppCompatActivity implements CallBackTask {

The CallBackTask will look like this:

interface CallBackTask {
    void getResultFromAsynTask(String result);

Now you have to implement it in your activity to get results in your activity:

public void getResultFromAsynTask(String result) {
     Do what you need with the result like starting your new Activity and passing the path
    final Intent intent = new Intent();
    intent.setClass(MainActivity.this, Player.class);
    intent.putExtra("path", result);

Awesome, you now have a URI from File:// (instead of content://) that you copied temporarily. However, don’t forget to delete the files when you are done using them or your app will get bigger and bigger.

Below, I’ll

delete the TempFolder we created earlier, which I’ll do in Activity onBackPressed (this should also be done in onDestroy()):

public void onBackPressed() {
    File dir = getBaseContext().getExternalFilesDir("TempFolder");

void deleteRecursive(File fileOrDirectory) {
    if (fileOrDirectory.isDirectory())
        for (File child : fileOrDirectory.listFiles())


Read a lot, but …
In this way, you will never have any problems with content:// URIs.

Related Problems and Solutions