I have an app that downloads files using Android's DownloadManager to a folder on the external file storage (SD card). This normally works fine, but there are some sources that cause the DownloadManager to trash the file when it finishes downloading it. A good example of a source file is:
http://traffic.libsyn.com/hdtvpodcast/HDTV-2012-06-01.mp3
It looks like maybe the problem is only with files from libsyn.com, but I'm not positive. I've looked around for ways to change how DownloadManager handles saving files, but can't find any options in the class.
This is where I enqueue the URL for download:
request = new Request(Uri.parse(currUrl));
external = Uri.fromFile(externalFile);
request.setDestinationUri(external);
request.setVisibleInDownloadsUi(false);
request.setNotificationVisibility(
DownloadManager.Request.VISIBILITY_HIDDEN);
currDownloadId = dm.enqueue(request);
The file locations are created using this:
Environment.getExternalStorageDirectory().getAbsolutePath() +
File.separator + "Podcatcher" + File.separator + "Feeds" + File.separator +
[int] + File.separator + [int] + [string extension];
Which turns out to be something like this when I query DownloadManager.COLUMN_LOCAL_FILENAME column from DownloadManager:
/mnt/sdcard/Podcatcher/Feeds/19/225.mp3
Most of the files are fine and persist after download, but not in this case. Any ideas about how I can force DownloadManager to leave the file after it is downloaded?
EDIT: I neglected to mention that when I use the standalone Download Manager when downloading this file from a browser that it reports failed at the end of the download. Perhaps my only solution is to download it from scratch, without DownloadManager?
try please followed code - worked for me:
request.setMimeType(application/octet-stream);
Related
What I'm trying to achieve is to check before download if the file exists so i don't have to re-download it again. For example, i have to open for the first time this pdf from the Internet "history-of-comics.pdf", in order to do so i have to download it and open inside my app, the second time i choose to re-read it, i have to be sure that "history-of-comics.pdf" if exists inside Downloads/MyDocs, i don't have to waste resources and let the user wait to download it again. Currently the app targetSdkVersion is 29 and what i have done so far is:
Give permissions for READ_EXTERNAL_STORAGE & WRITE_EXTERNAL_STORAGE
Included in manifest android:requestLegacyExternalStorage="true" inside application tag
Download the pdf file in the MyDocs inside Downloads folder
Below is a quick sample of my code (i have commented the other combinations i have tried):
private void checkIfPdfExists(String pdfFileName) {
String uriFile = String.valueOf(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS+File.separator+"MyDocs"+File.separator+pdfFileName+".pdf"));
File file = new File(uriFile);
//File file = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)+"/MyDocs", pdfFileName+".pdf");
//File file = new File(Environment.DIRECTORY_DOWNLOADS+File.separatorChar+"MyDocs"+File.separatorChar+pdfFileName+".pdf");
//File file = new File(Environment.DIRECTORY_DOWNLOADS+File.separatorChar+"MyDocs", pdfFileName+".pdf");
if (file.exists() && file!=null) {
Toast.makeText(getApplicationContext(), file.getPath() + "/n exists", Toast.LENGTH_SHORT).show();
displayFromUri(Uri.parse(file.getPath()));
} else {
beginDownload("https://www.heritagestatic.com/comics/d/history-of-comics.pdf",pdfFileName);
}
}
And this is how i define the path when i download the pdf, the downloader works as it should:
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
request.addRequestHeader("Accept", "application/pdf");
request.setDescription(file_name);
request.setTitle("Getting your doc");
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS,"MyDocs/"+file_name+".pdf");
I did some research before posting the question and in some threads i found that is related to Android Q, but i can't find a real solution for it. Any help would be appreciated, thanks in advance!
The solution to my problem was how i was referring to file path and the method used for download. As #blackapps mentioned that if you use "setDestinationInExternalFilesDir" to save the file, the proper way to check if the file exist is with "getExternalFilesDir", in my case:
File file = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)+File.separator+"MyDocs"+File.separator+pdfFileName+".pdf");
To make visible to my folder from Windows with USB connection (MTP) : /storage/emulated/0/MyFolder
I put a dummy file on this folder and use MediaScannerConnection.scanFile to scan this file.
File file = new File(Environment.getExternalStorageDirectory() + "MyFolder" + File.separator + "dummy.txt");
MediaScannerConnection.scanFile(this, new String[] { file.toString() }, null, null);
All work well at the first time, i see that folder and dymmy file on windows. But if i delete the whole folder, when folder are re-created, it is seen as a file of 4K on windows.
Is there any cache on this level ? And how can i refresh this cache ?
Thank you
This bug of MTP still persists :
https://issuetracker.google.com/issues/36956498
https://issuetracker.google.com/issues/37071807
MediaScannerConnection.scanFile is not a perfect solution.
My app downloads image files for offline use. Using the DownloadManager, the files are saved to the app's /data/ folder (retrieved with Environment.getDataDirectory().getAbsolutePath()). When displaying the images, the function File.exists for the path /data/filename returns false. When I provide the full path (kinda harcoded with the following function) everything works.
private static String getImageUri(Context c, String name) {
return Environment.getExternalStorageDirectory().getPath() + File.separator +
"Android" + File.separator + "data" + File.separator +
c.getPackageName() + File.separator +
"files" + File.separator + name;
}
It seems the File api requires the full path but I couldn't find a more elegant way of getting the full path.
Is there a better way of doing this? Another api that allows r/w and treats paths the same way the DownloadManager does? Or a better way of retrieving the full path?
The code returns the path storage/emulated/0/android/data/com.package.app/files/data.
I assume that your lowercase android is a typo, as that location should be Android.
You can obtain that location more simply via getExternalFilesDir() (method on Context), though you will need to append the trailing data segment yourself.
The line request.setDestinationInExternalFilesDir(context, Environment.getDataDirectory().getAbsolutePath(), name); works
It would be simpler — and far more compliant with the documentation — to just use request.setDestnationInExternalFilesDir(context, null, name). Then, your downloaded file would be in the location new File(getExternalFilesDir(null), name).
My HTTP-server allows downloading files with a 'dynamic' url: e.g. http://myserver.com/query?id=12345 which will give me my_song.mp3.
The filename is indicated in the content-disposition header.
Downloading this kind of file with Android DownloadManager works fine but I want to be able to control where the file is being saved to.
The normal way to do this would be to call
DownloadManager.Request r = new DownloadManager.Request(uri);
r.setDestinationInExternalPublicDir(String dirType, String subPath);
Unfortunately this requires to know the filename up front which I don't know. I tried calling the above function with a null for subPath but it does not work...
I want to save some data in the user's external directory (ie. SD card), but there seems to be a weird problem. I'm using Environment.getExternalStorageDirectory() which returns "mnt/sdcard/" (which is fine). I want to create two folders on in this directory so I do:
File main = new File(getExternalStorageDirectory() + "/my_app/some_data");
if(!main.isDirectory())
main.mkdirs();
Now I thought this would make the directory "mnt/sdcard/my_app/some_data", but after using a file manager to look at the SD card, it turns out that this folder is created at "mnt/sdcard/my_app/mnt/sdcard/my_app/some_data", which is quite bizarre. Can anyone tell me how to fix this?
Try the following and see what you get...
String packageName = this.getPackageName();
File myFilesDir = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "Android" + File.separator + "data" + File.separator + packageName + File.separator + "files");
myFilesDir.mkdirs();
It's exacly what I use to create a working directory on an SD card. For me it creates...
/mnt/sdcard/Android/data/com.mycompany.myApp/files
...where 'com.mycompany.myApp' is the actual package name of my app.