Downloaded files get deleted automatically - android

In my app, there are a few files that users can download. The files get downloaded via the android download manager. But, since a few weeks now, hundreds of users have been complaining that their files automatically keep deleting every 8-12 days, without them even uninstalling the app. (There might be many more users who haven't bothered to complain about the same.)
Now, there could be a number of user-specific reasons why that would happen on a few devices. But considering the huge number of users, it seems that I might have been doing something wrong.
Why would the system/download manager delete the files automatically? Is there a way to inform the system or the download manager to not delete certain files? Or should I just settle with renaming the files after downloading, so as to unlink them from the download manager, and hope that the problem gets solved with just that?
Edit:
Here's the code that I use to download the files:
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(trackLink));
request.setTitle(trackTitle);
request.setDestinationInExternalPublicDir("Tracks", trackTitle + ".mp3");
request.setVisibleInDownloadsUi(false);
DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
manager.enqueue(request);

I also came across this issue. Looking at the source for DownloadIdleService it appears that if the download are set to not be visible in the UI they're deleted after 7 days as they're considered "stale".
Here's the javadoc fromDownloadIdleService:
/**
* Remove stale downloads that third-party apps probably forgot about. We
* only consider non-visible downloads that haven't been touched in over a
* week.
*/
https://android.googlesource.com/platform/packages/providers/DownloadProvider/+/master/src/com/android/providers/downloads/DownloadIdleService.java#110

There is a bigger problem starting in Android Q where value set by setVisibleInDownloadsUi is ignored and it is false by default. The files will be deleted after a week. You can test it by: download file, change date in calendar by 2 months for example, call this in terminal:
adb shell cmd jobscheduler run -f com.android.providers.downloads -100
It starts job from DownloadIdleService where old and forbidden files are deleted. You can see in logcat (set no filter) that DownloadManager try to delete your files.
To prevent from that you can:
download files to Environment#getExternalStoragePublicDirectory(String) with Environment#DIRECTORY_DOWNLOADS) - this is the only path starting in Android Q where downloads are visible and should not be deleted
change file name after downloading (in DownloadedReceiver for example)

It was too big for a comment to I'm just putting it as an answer.
I don't have any clue yet why the files are missing or getting deleted over a period of time - which a bit strange. But I had to do something similar and never experienced something like this. So I though I might share what I have done in that case.
I preferred to keep the downloaded files in the internal storage which the application holds rather than keeping it in the external storage. For example, the file path where I used to save the downloaded files is something like...
/data/data/" + "com.example.myapplication" + "/musicfiles/
So what I did right after downloading is telling the media scanner about the new file so that it is immediately available to the user. So as I was downloading the file using an AsyncTask I had to run the scanner in the onPostExecute method like this after a successful download.
protected void onPostExecute() {
if(downloadCompletedSuccessfully) {
MediaScannerConnection.scanFile(context,
new String[]{file.toString()}, null,
new MediaScannerConnection.OnScanCompletedListener() {
public void onScanCompleted(String path, Uri uri) {
Log.i("ExternalStorage", "Scanned " + path + ":");
Log.i("ExternalStorage", "-> uri=" + uri);
}
});
}
}
So in your case, I think its not might be the issue that the Download button is not visible due to the unavailability of the file downloaded. It might happen if the media scanner fails to find the file in the file system as well. So you might consider giving it a try.
I don't know if clean master or some softwares like that cleans junk files every now and then if they are in external storage. You might consider investigate those as well.

Related

How to delete DownloadManager cache folder?

I'm looking to delete file(s) at /data/user/0/com.android.providers.downloads/cache programmatically but do not seem to have access to it. I have signature level app permission and can do adb root and su in the shell but Runtime.getRuntime().exec(su) receives a Permission denied exception. When I try to do File file = new File(path) and check if it exists, it returns false. The permissions for the cache folder are drwxrwx--x.
How can I delete file(s) from the DownloadManager cache directory?
Update
The best way seems to be to use DownloadManager remove(downloadId) which removes it from the cache folder. It is not well documented that it does that though.
The best way seems to be DownloadManager remove(downloadId) when you have it available. It actually removes the file with a message Deleting /data/data/com.android.providers.downloads/cache/binary.apk via provider delete
If you want the list of downloadIds to remove the whole cache, the programmer might need to use DownloadManager Query and filter by status complete to get all of them to remove.

android file.getUsableSpace returns zero with getExternalFilesDir(null), only after deleting other files

I have an app that sometimes needs to save files. Before writing, it checks usable space on the device. Here is the code I'm using to check space, with log statements.
String state = Environment.getExternalStorageState();
Log.d("Classname", "external storage state is " + state);
File file = new File(getExternalFilesDir(null) + File.separator);
Log.d("Classname", "file exists " + file.exists());
long usableSpace = file.getUsableSpace();
Log.d("Classname", "Space available " + usableSpace);
I've received a bug report that after deleting other files, around 3-5 MB, on a device that has around 3 GB free, getUsableSpace is returning 0 when trying to save another file.
The log before adding the first file:
11:21:46.879: external storage state is mounted
11:21:46.879: file exists true
11:21:46.880: Space available 3185496064
The log after deleting the first file, trying to add a second:
11:21:57.811: external storage state is mounted
11:21:57.822: file exists false
11:21:57.823: Space available 0
I have external storage permissions in my manifest, and have tried checking whether the storage is mounted and calling mkdir() when creating the external storage file, and the bug persists. I also had the tester reboot the device, thinking it might have just gotten into a weird state.
Does anyone have any ideas why this might be happening?
I found it. The solution was in the way deleting happens – if the last file deleted is gone, I was cleaning up the directory getExternalStorageDir was looking for, so when I tried to getUsableSpace on it, the directory didn't exist.

DownloadManager runs MediaScanner after download but shouldn't

it seems that MediaScanner wants to scan files that I told it not to. Now I wonder why.
My app downloads several media files from my server and shows them later with a playlist.
For that, the app gets the media files with the Android system's DownloadManager.
Using Request.setDestinationUri(), the download will be saved to a subdirectory of getExternalCacheDir() named "pending".
When the download is finished, the Android DownloadManager sends ACTION_DOWNLOAD_COMPLETE broadcast. My app's broadcast listener will then take that finished download and move it from the "pending" folder to a different folder named "media".
All this works as intended.
However, the system log is full of messages like these:
E/BitmapFactory(23779): Unable to decode stream: java.io.FileNotFoundException: /path/to/pending/image.jpg: open failed: ENOENT (No such file or directory)
E/JHEAD (23779): can't open '/path/to/pending/image.jpg'
E/StagefrightMetadataRetriever(25911): Unable to create data source for '/path/to/pending/video.mp4'.
E/MediaScannerJNI(23779): An error occurred while scanning file '/path/to/pending/video.mp4'.
So apparently, my app tells the DownloadManager to download an image / a video to the "pending" directory. It does as it's told and sends a "I completed the download" broadcast. My app receives the broadcast and moves the complete file to the "media" directory. Some moments later, the MediaScanner (or something else) tries to scan the completed file in the "pending" folder and barfs into the system log.
Now I'm wondering: Why is MediaScanner trying to read these files, anyway?
According to the Android API doc for setDestinationUri: "The downloaded file is not scanned by MediaScanner. But it can be made scannable by calling allowScanningByMediaScanner()." I don't call that method, so the downloaded file should not be scanned.
Next, I tried to put an empty .ignore in the app's cache directory and reminded the MediaScanner of the .ignore-file's existence through ACTION_MEDIA_SCANNER_SCAN_FILE, but the error messages remain.
To add to the mystique, the files do not show up in the system's gallery or video apps, so yes, the media scanner ignores them. But still: Why does it try to read them when it doesn't have to? Is it the MediaScanner at all or is it some other system service?
Next, I tried to put an empty .ignore in the app's cache directory and reminded the MediaScanner of the .ignore-file's existence through ACTION_MEDIA_SCANNER_SCAN_FILE, but the error messages remain.
The magic file to stop the Mediascanner is not ".ignore" but ".nomedia".
From MediaScanner.java:
File file = new File(path.substring(0, slashIndex) + ".nomedia");
if (file.exists()) {
// we have a .nomedia in one of the parent directories
return true;
}
And the reason why it did not appear in the system's gallery or video apps is maybe, because the scan crashed (as indicated in the log).
However, I have bad feelings about the media scanner too. For example, why doesn't it stop scanning in a more straight way. For example, in MediaScanner.java, instead of
public void scanDirectories(String[] directories, String volumeName) {
[...]
for (int i = 0; i < directories.length; i++) {
processDirectory(directories[i], mClient);
}
it could be
public void scanDirectories(String[] directories, String volumeName) {
[...]
for (int i = 0; i < directories.length; i++) {
if (! isNoMediaPath(directories[i]))
processDirectory(directories[i], mClient);
}
But instead, it goes forth and back between java code and cpp code again and again. What is the reason for that?
It really looks like the ".nomedia" won't give even half the effect some might expect. After further investigating in MediaScanner.java I would say, that this file does not stop the MediaScanner from scanning the whole tree at all. It still adds entries to MediaStore for each file, never mind of noMedia being set or not.
It just marks those entries in the MediaStore as "must not show up". On each file it does an "beginFile" and an "endFile". In the endFile it always does a mMediaInserter.insert, the one way or the other.
What bothers me so much about this is the fact, that it scans through all the files in e.g. a mounted stick, hereby taking the risk of trapping into a virus (specially designed for that scan process) and no .nomedia file can stop it from doing so.

How To delete the Partly Downloaded Media from the SD card In Android

I am working on application,there i have to download some images from the server for the fist time of running,
the issue is at the of download, if network connection fails the download interrupted at middle,then the partly downloaded not able to access from the application.
i want to delete that type of files automatically. help me please
if(isInterrupted())
{
// the download was canceled or interrupted, so let's delete the partially downloaded file
outFile.delete();
}
else
{
// notify completion
msg = Message.obtain(parentActivity.activityHandler,
AndroidFileDownloader.MESSAGE_DOWNLOAD_COMPLETE);
parentActivity.activityHandler.sendMessage(msg);
}
taken from: http://www.hassanpur.com/blog/2011/04/android-development-downloading-a-file-from-the-web/
EDIT (additional info): If you wanted to resume the file download instead of deleting and restarting, take a look at this SO post how to resume an interrupted download

Android: Problem with Media Scanner not Running

I have an app that user's can draw with, and then 'export' that drawing as a .png file to external storage, if present. Generating the PNG, copying the file to external all work like a charm, but a rather unique problem happens; after the export, if the user navigates to the image via My files (Samsung Tab running 2.2 in this case), they can see the .png file, but when they open it, the screen is black for about 10 seconds... then they see the image, Additionally, the images don't show up in the user's 'Gallery' app either.
Now, if the user connects the device to the computer via USB, or reboots the device, they can access the images no problem from My files, and they appear in 'Gallery' from that point forward, but again, any newly esported files experience the same problems until they cycle/connect the device again.
My thinking was that this had to be related to the Media Scanner (at least in the case of the 'Gallery' problem, it most certainly is).
So, as I am targetting Api 8+, I am trying to use the static MediaScannerConnection.scanFile() method to have the OS re-scan and add my images into the Gallery, etc. Also hoping this solves the issue of the strange delay in opening the images. Here is my code:
MediaScannerConnection.scanFile(
context,
new String[] { "/mnt/sdcard/MyApp" },
null,
null
);
LogCat gives me the following entries when I export an image, and thus run the above call:
DEBUG/MediaScannerService(2567): IMediaScannerService.scanFile: /mnt/sdcard/MyApp mimeType: null
DEBUG/MediaScannerService(2567): onStartCommand : intent - Intent { cmp=com.android.providers.media/.MediaScannerService (has extras) }
DEBUG/MediaScannerService(2567): onStartCommand : flags [0], startId [1]
DEBUG/MediaScannerService(2567): ServiceHandler:handleMessage volume[null], filePath[/mnt/sdcard/MyApp]
DEBUG/MediaProvider(2567): getSdSerial() sd state = removed
INFO/Database(2567): sqlite returned: error code = 17, msg = prepared statement aborts at 43: [SELECT DISTINCT sd_serial FROM images WHERE sd_serial LIKE 'external_0x%']
ERROR/MediaProvider(2567): removeMediaDBData called
DEBUG/MediaScanner(2567): prescan enter: path - /mnt/sdcard/MyApp
DEBUG/MediaScanner(2567): prescan return
So, it looks like the MediaScanner is getting the correct location, but is failing to find the SD card, which is correct, and failing. The Samsung Tab has built-in non-SD external storage, which Android gives access to via Environment.getExternalStorageDirectory(). How do I tell it to scan the non-SD storage?
Any ideas how to proceed?
Paul
Found the solution here, which involves sending a broadcast request to the media scanner via an Intent:
How to update the Android media database
Never did figure out the issue with MediaScannerConnection.scanFile.
Whenever you add a file, let MediaStore Content Provider knows about it using
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(imageAddedOrDeleted)));
Main advantage: work with any mime type supported by MediaStore
For deletion: just use getContentResolver().delete(uri, null, null)

Categories

Resources