38

I'm using Download Manger to download some multimedia files and categorize them. I'm also using Crashlytics and this is an error I frequently get on different devices and versions of Android:

java.lang.IllegalArgumentException: Unknown URL content://downloads/my_downloads
   at android.content.ContentResolver.insert(ContentResolver.java:862)
   at android.app.DownloadManager.enqueue(DownloadManager.java:1252)
   at com.myapp.LessonFragment$DownloadClickListener.onClick(SourceFile:570)
   at android.view.View.performClick(View.java:4262)
   at android.view.View$PerformClick.run(View.java:17351)
   at android.os.Handler.handleCallback(Handler.java:615)
   at android.os.Handler.dispatchMessage(Handler.java:92)
   at android.os.Looper.loop(Looper.java:137)
   at android.app.ActivityThread.main(ActivityThread.java:4921)
   at java.lang.reflect.Method.invokeNative(Method.java)
   at java.lang.reflect.Method.invoke(Method.java:511)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1038)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:805)
   at dalvik.system.NativeStart.main(NativeStart.java)

You can see my codes below:

private class DownloadClickListener implements View.OnClickListener {
    @Override
    public void onClick(View view) {
        // Check if download manager available before request
        if (!DownloadHelper.isDownloadManagerAvailable(getActivity())) {
            // Build custom alert dialog
            AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
            builder.setMessage(R.string.download_manager_disabled);
            builder.setCancelable(false);
            builder.setPositiveButton(R.string.ok, (dialog, which) -> {
                dialog.dismiss();
            });
            // Create and display alert dialog
            AlertDialog dialog = builder.create();
            dialog.show();
            return;
        }

        // Display short toast on download clicked
        Toast.makeText(getActivity(), R.string.lesson_download_start, Toast.LENGTH_SHORT).show();

        // Get attach from view tag
        Attache attache = (Attache) view.getTag();

        // Get lesson using lesson id
        Lesson lesson = new Select().from(Lesson.class)
                .where(Condition.column("id").is(attache.getLessonId()))
                .querySingle();

        // Set file name from url and attache name
        Uri uri = Uri.parse(attache.getFile());
        String fileName = attache.getName() + '.'
                + MimeTypeMap.getFileExtensionFromUrl(attache.getFile());

        // Check if path directory not exist and create it
        String filePath = Environment.getExternalStorageDirectory() + "/myapp/" + lesson.getTitle() + "/";
        File path = new File(filePath);
        if (!path.exists() || !path.isDirectory()) {
            if (!path.mkdirs()) {
                Timber.e("Could not create path directory.");
            }
        }

        // Check if file exist and then delete it
        File file = new File(filePath, fileName);
        if (file.exists() && file.isFile()) {
            if (file.delete()) {
                Timber.v("%s just deleted.", fileName);
            }
        }

        // Create download manager request using url
        DownloadManager.Request request = new DownloadManager.Request(uri);
        request.setTitle(attache.getName());
        request.setDestinationInExternalPublicDir("/myapp/" + lesson.getTitle(), fileName);

        // Using DownloadManager for download attache file
        DownloadManager manager = (DownloadManager) getActivity().getSystemService(Context.DOWNLOAD_SERVICE);
        manager.enqueue(request);
    }
}
Nimantha
  • 6,405
  • 6
  • 28
  • 69
nekofar
  • 1,497
  • 1
  • 18
  • 25
  • I guess `attache.getFile()` returns `content://downloads/my_downloads`? In that case, you might be storing wrong values. The link you give to the downloadmanager is a local URI used to identify a download from Androids downloadmanager. – Lukas Knuth Jun 05 '15 at 19:24
  • Thank you, but actually your guess is wrong. `attache.getFile()` return url of file on the server. – nekofar Jun 06 '15 at 09:52
  • 2
    There are something wrong with "DownloadManager" process in your phone, the most probably problem is that the "DownloadManager" is disabled in your phone. see "Settings->Applications-> All->DownloadManager", enable it if disabled. – smallzhan Aug 03 '15 at 07:14
  • 4
    Duplicate of : http://stackoverflow.com/questions/21551538/how-to-enable-android-download-manager – nilsi Aug 15 '15 at 02:49
  • [Please check this link.very good solution of this issue ](http://stackoverflow.com/questions/21551538/how-to-enable-android-download-manager) – Lalit kumar Jun 16 '16 at 08:43
  • Actually I use crashlytics and this issue is one of most reported ones. I did not found any solution yet. – nekofar Nov 25 '16 at 15:56
  • Did you find the reason?because I have same problem – Maryam Dec 19 '16 at 12:47
  • please look there [how-to-enable-android-download-manager](http://stackoverflow.com/questions/21551538/how-to-enable-android-download-manager) – Zero Mar 09 '17 at 03:56
  • Looks like this is an issue in android 8 only.For me its coming only for android 8 phones. – KJEjava48 Aug 29 '19 at 14:29

3 Answers3

67

For those who are getting Error Unknown URI: content://downloads/public_downloads. I managed to solve this by getting a hint given by @Commonsware in this answer. I found out the class FileUtils on GitHub. Here InputStream methods are used to fetch file from Download directory.

 // DownloadsProvider
            else if (isDownloadsDocument(uri)) {

                final String id = DocumentsContract.getDocumentId(uri);

                if (id != null && id.startsWith("raw:")) {
                    return id.substring(4);
                }

                String[] contentUriPrefixesToTry = new String[]{
                        "content://downloads/public_downloads",
                        "content://downloads/my_downloads",
                        "content://downloads/all_downloads"
                };

                for (String contentUriPrefix : contentUriPrefixesToTry) {
                    Uri contentUri = ContentUris.withAppendedId(Uri.parse(contentUriPrefix), Long.valueOf(id));
                    try {
                        String path = getDataColumn(context, contentUri, null, null);
                        if (path != null) {
                            return path;
                        }
                    } catch (Exception e) {}
                }

                // path could not be retrieved using ContentResolver, therefore copy file to accessible cache using streams
                String fileName = getFileName(context, uri);
                File cacheDir = getDocumentCacheDir(context);
                File file = generateFileName(fileName, cacheDir);
                String destinationPath = null;
                if (file != null) {
                    destinationPath = file.getAbsolutePath();
                    saveFileFromUri(context, uri, destinationPath);
                }

                return destinationPath;
            }
karanatwal.github.io
  • 3,613
  • 3
  • 25
  • 57
  • 1
    Just to add to this answer, mentioned two contentUriPrefixes weren't enough in my case, had to add `"content://downloads/all_downloads"` as well. – zoroz Oct 29 '18 at 13:24
  • It depends upon different phones. We can add your `content://downloads/all_downloads` too to this code. If these does not work then we use InputStream functions. – karanatwal.github.io Oct 29 '18 at 13:31
  • 1
    This doesn't work, I replaced my FileUtils with the one you mentioned in the link. I then replaced the DowloadsProvider section with what you provided above. When I select a video/mp4 from my SD Card, the Uri is empty. – HB. Nov 23 '18 at 06:02
  • Getting exception or empty without any exception? Also, i haven't tested with removable sd card . – karanatwal.github.io Nov 23 '18 at 17:23
  • Thanks a lot... The last default step worked for me. on Redmi 4. – Aram Dec 21 '18 at 08:38
  • when I select `excel` file then app is crashes with the error `java.lang.SecurityException: Permission Denial: reading com.android.providers.downloads.DownloadProvider uri content://downloads/all_downloads/5039 from pid=17320, uid=11517 requires android.permission.ACCESS_ALL_DOWNLOADS, or grantUriPermission()` i have already granted `READ WRITE EXTERNAL STORAGE PEREMISSOIONS` – Ravi Vaniya May 17 '19 at 11:04
  • Have you declared in manifest and asked on runtime too ? WRITE_EXTERNAL_STORAGE permissions @RaviVaniya – karanatwal.github.io May 17 '19 at 11:27
  • Try asking android.permission.ACCESS_ALL_DOWNLOADS at runtime – karanatwal.github.io May 17 '19 at 11:39
  • @karanatwal.github.io tried, but it says [ http://prntscr.com/npt0ak ], so i did this [ http://prntscr.com/npt0n6 ] but this time it opens file picker and when i select the file it throws this error `java.lang.SecurityException: Permission Denial: reading com.android.providers.downloads.DownloadProvider uri content://downloads/all_downloads/5039 from pid=3540, uid=11521 requires android.permission.ACCESS_ALL_DOWNLOADS, or grantUriPermission()` – Ravi Vaniya May 17 '19 at 12:21
  • https://stackoverflow.com/a/10441848/5996106 Have a look. I will try to look into your issue. Please update me if you got solution. – karanatwal.github.io May 17 '19 at 12:57
  • I tried oreo and nougat using real devices,it's working fine .But when using emulator it is showing error – Abraham Mathew Nov 07 '19 at 06:46
  • Can you specify the error and check hw your emulator storage is set up – karanatwal.github.io Nov 08 '19 at 08:52
  • @karanatwal.github.io where the method *getFileName,getDocumentCacheDir,generateFileName* ? – Bipin Bharti Nov 12 '19 at 07:07
  • 5
    @BipinBharti here is answers to your question https://github.com/coltoscosmin/FileUtils/blob/master/FileUtils.java Happy Coding. – karanatwal.github.io Nov 13 '19 at 18:28
  • @karanatwal.github.io In my case , even `getContentResolver().openInputStream(uri)` inside `saveFileFromUri` generating `Unknown URI: error``..so not an ideal solution for Unknown URI: error – Android Developer Jul 22 '20 at 16:30
  • THANKS BRO! It what I need – nicolas asinovich Jan 13 '21 at 09:36
8

I have encountered the exception java.lang.IllegalArgumentException: Unknown URI: content://downloads/public_downloads/7505 in getting the doucument from the downloads. This solution worked for me.

else if (isDownloadsDocument(uri)) {
            String fileName = getFilePath(context, uri);
            if (fileName != null) {
                return Environment.getExternalStorageDirectory().toString() + "/Download/" + fileName;
            }

            String id = DocumentsContract.getDocumentId(uri);
            if (id.startsWith("raw:")) {
                id = id.replaceFirst("raw:", "");
                File file = new File(id);
                if (file.exists())
                    return id;
            }

            final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
            return getDataColumn(context, contentUri, null, null);
        }

This the method used to get the filepath

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

    Cursor cursor = null;
    final String[] projection = {
            MediaStore.MediaColumns.DISPLAY_NAME
    };

    try {
        cursor = context.getContentResolver().query(uri, projection, null, null,
                null);
        if (cursor != null && cursor.moveToFirst()) {
            final int index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DISPLAY_NAME);
            return cursor.getString(index);
        }
    } finally {
        if (cursor != null)
            cursor.close();
    }
    return null;
}
viveksuggu
  • 737
  • 2
  • 7
  • 12
  • I had a problem with filename getting for Android 9 -> content://com.android.providers.downloads.documents -> * , but other content pathways give right filenames. This solution helped me to get right filename. Thank you! – Anton Petrusha Aug 27 '20 at 14:00
  • yes in android 10 adding file name with the public_download worked well i am Using SAF process thanks – Sunil Chaudhary Aug 03 '23 at 09:52
1

I got the same issue and after a lot of time spent on the search I found the solution

Just change your method especially // DownloadsProvider part

getpath()

to

@SuppressLint("NewApi") public static String getPath(final Context context, final Uri uri) {

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

    // DocumentProvider
    if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
        // ExternalStorageProvider
        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(":", "/");
            }

        }
        // DownloadsProvider
        else if (isDownloadsDocument(uri)) {
            String fileName = getFilePath(context, uri);
            if (fileName != null) {
                return Environment.getExternalStorageDirectory().toString() + "/Download/" + fileName;
            }

            String id = DocumentsContract.getDocumentId(uri);
            if (id.startsWith("raw:")) {
                id = id.replaceFirst("raw:", "");
                File file = new File(id);
                if (file.exists())
                    return id;
            }

            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;
}

For more solution click on the link here

https://gist.github.com/HBiSoft/15899990b8cd0723c3a894c1636550a8

I hope will do the same for you!

Chandela
  • 262
  • 5
  • 18