DownloadManager does not send broadcasts after INSUFFICIENT_SPACE_ERROR

Problem

If the cache directory is full, an attempt to perform a simple request will fail without sending the DownloadManager.ACTION_DOWNLOAD_COMPLETE broadcast.

Note. The problem is common, but can mostly be reproduced on younger devices with a limited cache size (/data/data/com.android.providers.downloads/cache).

Code

The receiver is configured correctly since I am still receiving broadcast when the operation succeeds and fails for other reasons.

  DownloadManager.Request request = new DownloadManager.Request(Uri.parse("http://www.apkmirror.com/wp-content/themes/APKMirror/download.php?id=44753")); request.setTitle("Facebook"); DownloadManager downloadManager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE); downloadManager.enqueue(request); 

Solution required

I am interested in solving the problem of specific , or more detailed information if you encounter it.
I'm not looking for a solution that will require me to stop using DownloadManager or add permission WRITE_EXTERNAL_STORAGE .

Magazines

When the cache becomes full and, finally, when it can no longer contain, you can watch the log in (filtered by DownloadManager )

 11-08 08:47:06.079 830-14261/? I/DownloadManager: Download 135 starting 11-08 08:47:06.989 830-14261/? W/DownloadManager: Downloads data dir: /data/data/com.android.providers.downloads/cache is running low on space. space available (in bytes): -6994124 11-08 08:47:06.999 830-14261/? I/DownloadManager: discardPurgeableFiles: destination = 2, targetBytes = 10485760 11-08 08:47:06.999 830-14261/? I/DownloadManager: Purged files, freed 0 for 10485760 requested 11-08 08:47:07.309 830-14261/? W/DownloadManager: Aborting request for download 135: not enough free space in the filesystem rooted at: /data/data/com.android.providers.downloads/cache and unable to free any more 11-08 08:47:07.319 830-14261/? I/DownloadManager: Download 135 finished with status INSUFFICIENT_SPACE_ERROR 

Here is a DEMO PROJECT that can demonstrate this problem. Remember that the cache folder must be filled with this point (unclean items, which in my experience basically mean interrupted downloads)

+9
source share
3 answers

Since DownloadManager is a ContentProvider system, in fact, you can register your own ContentObserver. Therefore, when the download provider is updated, it will notify the observer in the case of INSUFFICIENT_SPACE.

 final DownloadManager downloadManager = (DownloadManager)context.getSystemService(Context.DOWNLOAD_SERVICE); context.getContentResolver().registerContentObserver(Uri.parse("content://downloads/my_downloads"), true, new ContentObserver(null) { @Override public void onChange(boolean selfChange) { super.onChange(selfChange); Cursor localCursor = downloadManager.query( new DownloadManager.Query()); if (localCursor.getCount() == 0) { localCursor.close(); } localCursor.moveToFirst(); do { if ((localCursor.getInt(localCursor.getColumnIndex(DownloadManager.COLUMN_STATUS)) & DownloadManager.STATUS_FAILED )!=0) { // Download failed, go see why if (localCursor.getInt(localCursor.getColumnIndex(DownloadManager.COLUMN_REASON)) == DownloadManager.ERROR_INSUFFICIENT_SPACE){ Log.w("DownloadStatus", " Download failed with ERROR_INSUFFICIENT_SPACE"); } } }while (localCursor.moveToNext()); } }); 

Please note that do not set the query filter with the status DownloadManager.STATUS_FAILED, since DownloadManager strangely considers only the status from 400 to 600, but INSUFFICIENT_SPACE has an error code of 198 ...

android.app.DownloadManager.Request:

 Cursor runQuery(ContentResolver resolver, String[] projection, Uri baseUri) { ..... if ((mStatusFlags & STATUS_FAILED) != 0) { parts.add("(" + statusClause(">=", 400) + " AND " + statusClause("<", 600) + ")"); } } 
+2
source

You can receive the broadcast INSUFFICIENT_SPACE_ERROR by getting the reason DownloadManager.STATUS_FAILED by following the code

 private void DownloadStatus(Cursor cursor, long DownloadId){ //column for download status int columnIndex = cursor.getColumnIndex(DownloadManager.COLUMN_STATUS); int status = cursor.getInt(columnIndex); //column for reason code if the download failed or paused int columnReason = cursor.getColumnIndex(DownloadManager.COLUMN_REASON); int reason = cursor.getInt(columnReason); //get the download filename int filenameIndex = cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME); String filename = cursor.getString(filenameIndex); String statusText = ""; String reasonText = ""; switch(status){ case DownloadManager.STATUS_FAILED: statusText = "STATUS_FAILED"; switch(reason){ case DownloadManager.ERROR_CANNOT_RESUME: reasonText = "ERROR_CANNOT_RESUME"; break; case DownloadManager.ERROR_DEVICE_NOT_FOUND: reasonText = "ERROR_DEVICE_NOT_FOUND"; break; case DownloadManager.ERROR_FILE_ALREADY_EXISTS: reasonText = "ERROR_FILE_ALREADY_EXISTS"; break; case DownloadManager.ERROR_FILE_ERROR: reasonText = "ERROR_FILE_ERROR"; break; case DownloadManager.ERROR_HTTP_DATA_ERROR: reasonText = "ERROR_HTTP_DATA_ERROR"; break; case DownloadManager.ERROR_INSUFFICIENT_SPACE: reasonText = "ERROR_INSUFFICIENT_SPACE"; break; case DownloadManager.ERROR_TOO_MANY_REDIRECTS: reasonText = "ERROR_TOO_MANY_REDIRECTS"; break; case DownloadManager.ERROR_UNHANDLED_HTTP_CODE: reasonText = "ERROR_UNHANDLED_HTTP_CODE"; break; case DownloadManager.ERROR_UNKNOWN: reasonText = "ERROR_UNKNOWN"; break; } break; case DownloadManager.STATUS_PAUSED: statusText = "STATUS_PAUSED"; switch(reason){ case DownloadManager.PAUSED_QUEUED_FOR_WIFI: reasonText = "PAUSED_QUEUED_FOR_WIFI"; break; case DownloadManager.PAUSED_UNKNOWN: reasonText = "PAUSED_UNKNOWN"; break; case DownloadManager.PAUSED_WAITING_FOR_NETWORK: reasonText = "PAUSED_WAITING_FOR_NETWORK"; break; case DownloadManager.PAUSED_WAITING_TO_RETRY: reasonText = "PAUSED_WAITING_TO_RETRY"; break; } break; case DownloadManager.STATUS_PENDING: statusText = "STATUS_PENDING"; break; case DownloadManager.STATUS_RUNNING: statusText = "STATUS_RUNNING"; break; case DownloadManager.STATUS_SUCCESSFUL: statusText = "STATUS_SUCCESSFUL"; reasonText = "Filename:\n" + filename; break; } } 
0
source

I think the Gracie solution needs some improvements, such as unregistering and validating download identifiers.

If you do not use any restrictions for the request, you can try checking the file size after placing it in the queue - this is not an ideal solution:

 private static void checkFileSize(Context context, DownloadManager downloadManager, long myDownloadReference, DownloadInfo downloadInfo) { DownloadManager.Query query = new DownloadManager.Query(); query.setFilterById(myDownloadReference); Handler handler = new Handler(); handler.postDelayed(() -> { Cursor cursor = downloadManager.query(query); if (!cursor.moveToFirst()) { KLog.i("download list is empty"); return; } int size = cursor.getInt(cursor .getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES)); int status = cursor.getInt(cursor .getColumnIndex(DownloadManager.COLUMN_STATUS)); int reason = cursor.getInt(cursor .getColumnIndex(DownloadManager.COLUMN_REASON)); cursor.close(); if (reason == DownloadManager.ERROR_INSUFFICIENT_SPACE) DownloadedReceiver.handleInsufficientSpace(context, downloadInfo); }, 1500); } 
0
source

All Articles