Android download manager completed

Small question about the download manager in android. It's the first time I'm working with it and have successfully downloaded multiple files and opened them. But my question is how do i check if the download completed.

The situation is I download a PDF file and open it, and usually the file is so small it complets before opening. But if the file is somewhat bigger how do I check if the download manager is finished with the download before opening it.

How I download:

Intent intent = getIntent();
DownloadManager downloadManager = (DownloadManager)getSystemService(DOWNLOAD_SERVICE);
Uri Download_Uri = Uri.parse(intent.getStringExtra("Document_href"));
DownloadManager.Request request = new DownloadManager.Request(Download_Uri);

//Restrict the types of networks over which this download may proceed.
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI | DownloadManager.Request.NETWORK_MOBILE);
//Set whether this download may proceed over a roaming connection.
request.setAllowedOverRoaming(false);
//Set the title of this download, to be displayed in notifications.
request.setTitle(intent.getStringExtra("Document_title"));
//Set the local destination for the downloaded file to a path within the application's external files directory
request.setDestinationInExternalFilesDir(this,Environment.DIRECTORY_DOWNLOADS,intent.getStringExtra("Document_title") + ".pdf");
//Enqueue a new download and same the referenceId
Long downloadReference = downloadManager.enqueue(request);

How I open the file

Uri uri = Uri.parse("content://com.app.applicationname/" + "/Download/" + intent.getStringExtra("Document_title") + ".pdf");
Intent target = new Intent(Intent.ACTION_VIEW);
target.setDataAndType(uri, "application/pdf");
target.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

startActivity(target);

So somewhere between downloading and opening the file I want a if statement to check if it should continue or wait for the file.


Solution 1:

A broadcast is sent by the DownloadManager whenever a download completes, so you need to register a broadcast receiver with the appropriate intent action( ACTION_DOWNLOAD_COMPLETE ) to catch this broadcast:

To register receiver

registerReceiver(onComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));

and a BroadcastReciever handler

BroadcastReceiver onComplete=new BroadcastReceiver() {
    public void onReceive(Context ctxt, Intent intent) {
        // your code
    }
};

You can also create AsyncTask to handle the downloading of big files

Create a download dialog of some sort to display downloading in notification area and than handle the opening of the file:

protected void openFile(String fileName) {
    Intent install = new Intent(Intent.ACTION_VIEW);
    install.setDataAndType(Uri.fromFile(new File(fileName)),"MIME-TYPE");
    startActivity(install);
}

you can also check the sample link

Sample Code

Solution 2:

Courtesy: Android DonwnloadManager Example

The accepted answer is not completely correct. Receiving ACTION_DOWNLOAD_COMPLETE broadcast doesnt mean your download is complete. Note that ACTION_DOWNLOAD_COMPLETE is broadcasted by DownloadManager when any download is completed. It doesnt necessarily mean it is the same download which you are waiting for

Solution is to save the download id returned by enqueue() when starting the download. This long download id is unique across the system and can be used to check the download status

DownloadManager downloadManager= (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
long downloadID = downloadManager.enqueue(request);// enqueue puts the download request in the queue.

You can be notified when your download is complete by following three steps

Create a BroadcastReceiver as shown in snippet below.Inside the receiver we just check if the received broadcast is for our download by matching the received download id with our enqueued download.

private BroadcastReceiver onDownloadComplete = new BroadcastReceiver() {
       @Override
       public void onReceive(Context context, Intent intent) {
           //Fetching the download id received with the broadcast
           long id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
           //Checking if the received broadcast is for our enqueued download by matching download id
           if (downloadID == id) {
               Toast.makeText(MainActivity.this, "Download Completed", Toast.LENGTH_SHORT).show();
           }
       }
   };

Once the BroadcastReceiver is created you can register for ACTION_DOWNLOAD_COMPLETE in the onCreate method of your activity.

@Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);

       registerReceiver(onDownloadComplete,new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));

   }

It is also important that you unregister the BroadcastReceiver in onDestroy. This ensures you only listen for this broadcast as long as the activity is active

@Override
  public void onDestroy() {
      super.onDestroy();
      unregisterReceiver(onDownloadComplete);
  }

I urge your to read the complete example here

Solution 3:

I have spent over a week researching how to download and open files with the DownloadManager and never quite found an answer that was completely perfect for me, so it was up to me to take bits and pieces to find what worked. I made sure to document my code to the best of my ability. If there are any questions, please feel free to leave them in the comments below the answer.

Also, don't forget to add this line to your AndroidManifest.xml file!!

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

My download manager:

import android.app.DownloadManager;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.os.Environment;
import android.webkit.CookieManager;
import android.webkit.DownloadListener;
import android.widget.Toast;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class MyDownloadListener implements DownloadListener {
    private Context mContext;
    private DownloadManager mDownloadManager;
    private long mDownloadedFileID;
    private DownloadManager.Request mRequest;

    public MyDownloadListener(Context context) {
        mContext = context;
        mDownloadManager = (DownloadManager) mContext
            .getSystemService(Context.DOWNLOAD_SERVICE);
    }

    @Override
    public void onDownloadStart(String url, String userAgent, String
        contentDisposition, final String mimetype, long contentLength) {

        // Function is called once download completes.
        BroadcastReceiver onComplete = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                // Prevents the occasional unintentional call. I needed this.
                if (mDownloadedFileID == -1)
                    return;
                Intent fileIntent = new Intent(Intent.ACTION_VIEW);

                // Grabs the Uri for the file that was downloaded.
                Uri mostRecentDownload =
                    mDownloadManager.getUriForDownloadedFile(mDownloadedFileID);
                // DownloadManager stores the Mime Type. Makes it really easy for us.
                String mimeType =
                    mDownloadManager.getMimeTypeForDownloadedFile(mDownloadedFileID);
                fileIntent.setDataAndType(mostRecentDownload, mimeType);
                fileIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                try {
                    mContext.startActivity(fileIntent);
                } catch (ActivityNotFoundException e) {
                    Toast.makeText(mContext, "No handler for this type of file.",
                        Toast.LENGTH_LONG).show();
                }
                // Sets up the prevention of an unintentional call. I found it necessary. Maybe not for others.
                mDownloadedFileID = -1;
            }
        };
        // Registers function to listen to the completion of the download.
        mContext.registerReceiver(onComplete, new
            IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));

        mRequest = new DownloadManager.Request(Uri.parse(url));
        // Limits the download to only over WiFi. Optional.
        mRequest.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI);
        // Makes download visible in notifications while downloading, but disappears after download completes. Optional.
        mRequest.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE);
        mRequest.setMimeType(mimetype);

        // If necessary for a security check. I needed it, but I don't think it's mandatory.
        String cookie = CookieManager.getInstance().getCookie(url);
        mRequest.addRequestHeader("Cookie", cookie);

        // Grabs the file name from the Content-Disposition
        String filename = null;
        Pattern regex = Pattern.compile("(?<=filename=\").*?(?=\")");
        Matcher regexMatcher = regex.matcher(contentDisposition);
        if (regexMatcher.find()) {
            filename = regexMatcher.group();
        }

        // Sets the file path to save to, including the file name. Make sure to have the WRITE_EXTERNAL_STORAGE permission!!
        mRequest.setDestinationInExternalFilesDir(mContext, Environment.DIRECTORY_DOWNLOADS, filename);
        // Sets the title of the notification and how it appears to the user in the saved directory.
        mRequest.setTitle(filename);

        // Adds the request to the DownloadManager queue to be executed at the next available opportunity.
        mDownloadedFileID = mDownloadManager.enqueue(mRequest);
    }
}

Simply add this to your existing WebView by adding this line to your WebView class:

webView.setDownloadListener(new MyDownloadListener(webView.getContext()));

Solution 4:

Just adding a contribution. In my case I'm downloading a PDF and that's how I open it after it get downloaded:

val onComplete: BroadcastReceiver = object : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        if(intent.action == DownloadManager.ACTION_DOWNLOAD_COMPLETE){
            intent.extras?.let {
                
                //retrieving the file
                val downloadedFileId = it.getLong(DownloadManager.EXTRA_DOWNLOAD_ID)
                val downloadManager = getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
                val uri: Uri = downloadManager.getUriForDownloadedFile(downloadedFileId)
                
                //opening it
                val intent = Intent(Intent.ACTION_VIEW, uri)
                intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
                context.startActivity(intent)
            }
        }
    }
}