Show Download Manager progress inside activity Show Download Manager progress inside activity android android

Show Download Manager progress inside activity


If you are looking for a decent way to determine when to query the DownloadManager for progress updates, consider registering a ContentObserver for the uri content://downloads/my_downloads

Example:

DownloadManager manager = (DownloadManager) getSystemService( Context.DOWNLOAD_SERVICE );manager.enqueue( myRequest );Uri myDownloads = Uri.parse( "content://downloads/my_downloads" );getContentResolver().registerContentObserver( myDownloads, true, new DownloadObserver() );...public static class DownloadObserver extends ContentObserver {   @Override   public void onChange( boolean selfChange, Uri uri ) {      Log.d( "DownloadObserver", "Download " + uri + " updated" );   }

This yields the following output as each chunk of the long running download is received

D/DownloadObserver(15584): Download content://downloads/my_downloads/437 updatedD/DownloadObserver(15584): Download content://downloads/my_downloads/437 updatedD/DownloadObserver(15584): Download content://downloads/my_downloads/437 updatedD/DownloadObserver(15584): Download content://downloads/my_downloads/437 updated

where '437' is the ID of your download.

Note that this follows the content URI defined in the class android.provider.Downloads which appears to be hidden in the framework and may not work consistently on all devices. (https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/provider/Downloads.java#89)


You can query the number of bytes downloaded so far, and the total number of bytes that need to be downloaded, using the query method, in much the same way as you have queried the status in your example code. Once you have those values, it's fairly easy to calculate the progress as a percentage.

There doesn't appear to be any way for you to be notified when new data is received, so it would be up to you to poll the download manager at some regular interval to determine the current status of any download that you want to monitor.

Query query = new Query();query.setfilterById(downloadId);Cursor c = dm.query(query);if (c.moveToFirst()) {  int sizeIndex = c.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES);  int downloadedIndex = c.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR);  long size = c.getInt(sizeIndex);  long downloaded = c.getInt(downloadedIndex);  double progress = 0.0;  if (size != -1) progress = downloaded*100.0/size;    // At this point you have the progress as a percentage.}

Note that the total size will initially be -1 and will only be filled in once the download starts. So in the sample code above I've checked for -1 and set the progress to 0 if the size is not yet set.

However, you may find in some cases that the total size is never returned (for example, in an HTTP chunked transfer, there will be no Content-Length header from which the size can be determined). If you need to support that kind of server, you should probably provide some kind of indication to the user that the download is progressing and not just a progress bar that is stuck at zero.


I had a requirement of tracking download of multiple files. After a lot of thinking and experimenting, I came up with the following code:

private void startDownloadThread(final List<DownloadFile> list) {        // Initializing the broadcast receiver ...        mBroadCastReceiver = new BroadcastReceiver() {            @Override            public void onReceive(Context context, Intent intent) {                mFinishedFilesFromNotif.add(intent.getExtras()                        .getLong(DownloadManager.EXTRA_DOWNLOAD_ID));            }        };        IntentFilter intentFilter = new IntentFilter(                "android.intent.action.DOWNLOAD_COMPLETE");        DownloadProgressUIFragment.this.getActivity().registerReceiver(mBroadCastReceiver,                intentFilter);        // initializing the download manager instance ....        mDownloadManager = (DownloadManager) getActivity()                .getSystemService(Context.DOWNLOAD_SERVICE);        // adding files to the download manager list ...        for(DownloadFile f: list) {            mDownloadIds.add(FileUtils.addFileForDownloadInBkg(getApplicationContext(),                    f.getUrl(),                    f.getPath()));        }        // starting the thread to track the progress of the download ..        mProgressThread = new Thread(new Runnable() {            @Override            public void run() {                // Preparing the query for the download manager ...                DownloadManager.Query q = new DownloadManager.Query();                long[] ids = new long[mDownloadIds.size()];                final List<Long> idsArrList= new ArrayList<>();                int i = 0;                for (Long id: mDownloadIds) {                    ids[i++] = id;                    idsArrList.add(id);                }                q.setFilterById(ids);                // getting the total size of the data ...                Cursor c;                while(true) {                    // check if the downloads are already completed ...                    // Here I have created a set of download ids from download manager to keep                    // track of all the files that are dowloaded, which I populate by creating                    //                    if(mFinishedFilesFromNotif.containsAll(idsArrList)) {                        isDownloadSuccess = true;                        // TODO - Take appropriate action. Download is finished successfully                        return;                    }                    // start iterating and noting progress ..                    c = mDownloadManager.query(q);                    if(c != null) {                        int filesDownloaded = 0;                        float fileFracs = 0f; // this stores the fraction of all the files in                        // download                        final int columnTotalSize = c.getColumnIndex                                (DownloadManager.COLUMN_TOTAL_SIZE_BYTES);                        final int columnStatus = c.getColumnIndex(DownloadManager.COLUMN_STATUS);                        //final int columnId = c.getColumnIndex(DownloadManager.COLUMN_ID);                        final int columnDwnldSoFar =                                c.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR);                        while (c.moveToNext()) {                            // checking the progress ..                            if(c.getInt(columnStatus) == DownloadManager.STATUS_SUCCESSFUL) {                                filesDownloaded++;                            }                            // If the file is partially downloaded, take its fraction ..                            else if(c.getInt(columnTotalSize) > 0) {                                fileFracs += ((c.getInt(columnDwnldSoFar) * 1.0f) /                                        c.getInt(columnTotalSize));                            } else if(c.getInt(columnStatus) == DownloadManager.STATUS_FAILED) {                                // TODO - Take appropriate action. Error in downloading one of the                                // files.                                return;                            }                        }                        c.close();                        // calculate the progress to show ...                        float progress = (filesDownloaded + fileFracs)/ids.length;                        // setting the progress text and bar...                        final int percentage = Math.round(progress * 100.0f);                        final String txt = "Loading ... " + percentage + "%";                        // Show the progress appropriately ...                    }                }            }        });        mProgressThread.start();    }

And the function to enqueue to files are:

public static long addFileForDownloadInBkg(Context context, String url, String savePath) {        Uri uri = Uri.parse(url);        DownloadManager.Request request = new DownloadManager.Request(uri);        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN);        request.setDestinationUri(Uri.fromFile(new File(savePath)));        final DownloadManager m = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);        return m.enqueue(request);    }

Basically, I receive a notification individually for each of the files whose download has been finished and then add them to a set which is basically the set which helps me decide if all the downloads have been finished or not. I track the the progress based on the number of files and the fraction of each being complete. I hope this helps.