Search code examples
androidandroid-download-manager

Pausing and resuming a download


I know there are some libraries for this, but i want to implement my own pause/resume functionality for android.

i'm now using DownloadManager for downloading and this is the service i implemented for download:

public class DownloadService extends Service {

    public static boolean isServiceRunning = false;
    private static String downloadingPackageName;

    private DownloadManager downloadManager;

    long downloadRef;

    RemoteViews contentView;
    private boolean isDownloading = false;
    Notification notification;
    NotificationManager manager;
    DownloadRequestListener downloadRequestListener;

    NotificationManager notifManager;

    private String dirPath;
    private String packageName;

    public static String PACKAGE_NAME;

    @Override
    public void onCreate() {
        super.onCreate();
        PACKAGE_NAME = getApplicationContext().getPackageName();
        Log.e("OnCreate","OnCreateCommandClled...");
        downloadRequestListener = new DownloadRequestListener();
        IntentFilter filter = new IntentFilter("ir.amulay.downloadRequest");
        registerReceiver(downloadRequestListener, filter);
        registerReceiver(onDownloadComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
    }


    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        isServiceRunning = true;
        return  START_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }


    @Override
    public void onDestroy() {
        Log.e("Service","Service Destroyed...");
        unregisterReceiver(downloadRequestListener);
        isServiceRunning = false;
        super.onDestroy();
    }



    public Long downloadFile(String path, String packageName, String dirPath){
        if(isDownloading) return null;
        isDownloading =true;
        this.dirPath = dirPath;


        notifManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        contentView = new RemoteViews(getPackageName(), R.layout.download_notification_bar);
        contentView.setImageViewResource(R.id.image, R.mipmap.ic_launcher);
        contentView.setTextViewText(R.id.title, "Custom notification");


        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel serviceChanel = new NotificationChannel(
                    "downloadChanel",
                    "Example Service Chanel",
                    NotificationManager.IMPORTANCE_LOW
            );

            manager = getSystemService(NotificationManager.class);
            manager.createNotificationChannel(serviceChanel);
        }
        notification = new NotificationCompat.Builder(this,"downloadChanel")
                .setContentTitle("test")
                .setContentText("test Againg")
                .setContent(contentView)
                .setSmallIcon(R.drawable.ic_launcher_foreground)
                .setAutoCancel(false)
                .build();


        startForeground(1,notification);


        //I Dont Want many files to be downloaded at same time, so here is a check...
        downloadingPackageName = packageName;

        Uri uri = Uri.parse(path);

        //Uri dir = Uri.parse(dirPath + "/" + packageName + ".apk");
        downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
        DownloadManager.Request request = new DownloadManager.Request(uri);

        this.packageName = packageName;
        request.setTitle("Download File");
        request.setDestinationInExternalPublicDir(dirPath, packageName+".apk");
        request.setDescription("download apk files using download manager");
        request.setMimeType(getMimeType(uri.toString()));
        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN);
        request.setVisibleInDownloadsUi(false);

        // request.setDestinationUri(dir);


        request.setAllowedOverMetered(true);
        request.setAllowedOverRoaming(true);



        downloadRef = downloadManager.enqueue(request);

        Handler handler = new Handler();
        handler.post(new Runnable() {
            @Override
            public void run() {


                boolean downloading = true;

                DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);


                DownloadManager.Query q = new DownloadManager.Query();
                q.setFilterById(downloadRef); //filter by id which you have receieved when reqesting download from download manager
                Cursor cursor = manager.query(q);
                if(cursor.getCount() <= 0 ){
                    return;
                }
                cursor.moveToFirst();
                //if its Running Send BroadCast... :)
                if (cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)) == DownloadManager.STATUS_RUNNING) {

                    int bytes_downloaded = cursor.getInt(cursor
                            .getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
                    int bytes_total = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));

                    final int dl_progress = (int) ((bytes_downloaded * 100L) / bytes_total);

                    Log.e("DownloadProgress", "progress= " + dl_progress);
                    contentView.setTextViewText(R.id.title,"Downloading " +dl_progress);
                    //  contentView.setProgressBar(R.id.downloadProgress,200,dl_progress,true);
                    notification.contentView.setProgressBar(R.id.downloadProgress, 100, dl_progress, false);
                    notifManager.notify(1, notification );
                    Intent intent = new Intent();
                    intent.setAction("ir.amulay.downloadEvent");
                    intent.putExtra("eventType","downloadProgress");
                    intent.putExtra("progresspercent",""+dl_progress);
                    intent.putExtra("packagename",packageName);
                    intent.putExtra("refID",""+downloadRef);
                    sendBroadcast(intent);

                }


                if (cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)) == DownloadManager.STATUS_SUCCESSFUL) {
                    downloading = false;
                }

                if (cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)) == DownloadManager.STATUS_FAILED) {
                    downloading = false;
                }

                cursor.close();

                if(!downloading) {
                    Intent intent= new Intent();
                    intent.setAction("ir.amulay.downloadEvent");
                    intent.putExtra("eventType","downloadCompleted");
                    intent.putExtra("packagename",packageName);
                    intent.putExtra("refID",""+downloadRef);
                    sendBroadcast(intent);
                    //send a broadcast to tell its completed
                    return;
                }
                handler.postDelayed(this,300);
            }
        });
        return downloadRef;
    }


    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 (downloadRef == id) {


                long downloadId = intent.getLongExtra(
                        DownloadManager.EXTRA_DOWNLOAD_ID, 0);

                openDownloadedAttachment(context, downloadId);

            }
        }
    };


    private String getMimeType(String url) {
        String type = null;
        String extension = MimeTypeMap.getFileExtensionFromUrl(url);
        if (extension != null) {
            MimeTypeMap mime = MimeTypeMap.getSingleton();
            type = mime.getMimeTypeFromExtension(extension);
        }
        return type;
    }


    private void openDownloadedAttachment(final Context context, final long downloadId) {
        DownloadManager downloadManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
        DownloadManager.Query query = new DownloadManager.Query();
        query.setFilterById(downloadId);
        Cursor cursor = downloadManager.query(query);
        if (cursor.moveToFirst()) {
            int downloadStatus = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS));
            String downloadLocalUri = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
            String downloadMimeType = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_MEDIA_TYPE));
            if ((downloadStatus == DownloadManager.STATUS_SUCCESSFUL) && downloadLocalUri != null) {
                openDownloadedAttachment(context, Uri.parse(downloadLocalUri), downloadMimeType);
            }
        }
        cursor.close();
    }

    private void openDownloadedAttachment(final Context context, Uri attachmentUri, final String attachmentMimeType) {
        if(attachmentUri!=null) {
            // Get Content Uri.
            if (ContentResolver.SCHEME_FILE.equals(attachmentUri.getScheme())) {
                // FileUri - Convert it to contentUri.
                File file = new File(attachmentUri.getPath());
                attachmentUri = FileProvider.getUriForFile(this, "com.freshdesk.helpdesk.provider", file);
            }

            Intent openAttachmentIntent = new Intent(Intent.ACTION_VIEW);
            openAttachmentIntent.setDataAndType(attachmentUri, attachmentMimeType);
            openAttachmentIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            try {
                context.startActivity(openAttachmentIntent);
            } catch (ActivityNotFoundException e) {
               // Toast.makeText(context, context.getString("cant O"), Toast.LENGTH_LONG).show();
            }
            finally {
                stopSelf();
            }
        }
    }

    private class DownloadRequestListener extends BroadcastReceiver{

        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context, "Received", Toast.LENGTH_SHORT).show();
            String reqType = intent.getStringExtra("reqType");
            String packageName =intent.getStringExtra("package");

            if(reqType.equals("download")){
                String url = intent.getStringExtra("url");
                String dirPath = intent.getStringExtra("dirPath");
                downloadFile(url,packageName,dirPath);
            }
            else if(reqType.equals("stop")){
                if(downloadingPackageName.equals(packageName) && downloadManager!= null){
                    downloadManager.remove(downloadRef);
                    isDownloading =false;
                    unregisterReceiver(onDownloadComplete);
                    stopSelf();
                }
            }
        }
    }

}

how can i implement Pause/Resume for my downloads? WITHOUT a library? is it possible trough Download manager itself or i should use some other methods?


Solution

  • You can send message to the DownloadService you created, and invoke the DownloadManager to do the pause and resume action.

    When DownloadManager enqueue a download task, you will get a id (long) DownloadManager keep the download info in the ContentProvider, just update the ContentProvider info with the given id (long), if the network or other conditions satisfied the action will execute.

    You can extends DownloadManager and create a pair of methods like below.

    • Pause Download
    /**
     * pause download
     * 
     * @param ids the IDs of the downloads to be paused
     * @return the number of downloads actually paused
     */
    public int pauseDownload(long... ids) {
        if (ids == null || ids.length == 0) {
            // called with nothing to remove!
            throw new IllegalArgumentException("input param 'ids' can't be null");
        }
    
        ContentValues values = new ContentValues();
        values.put(Downloads.Impl.COLUMN_CONTROL, Downloads.Impl.CONTROL_PAUSED);
        values.put(Downloads.Impl.COLUMN_STATUS, Downloads.Impl.STATUS_PAUSED_BY_APP);
        if (ids.length == 1) {
            return mResolver.update(ContentUris.withAppendedId(mBaseUri, ids[0]), values,
                    null, null);
        } 
        return mResolver.update(mBaseUri, values, getWhereClauseForIds(ids),
                getWhereArgsForIds(ids));
    }
    
    • Resume download
    /**
     * resume download
     * 
     * @param ids the IDs of the downloads to be resumed
     * @return the number of downloads actually resumed
     */
    public int resumeDownload(long... ids) {
        if (ids == null || ids.length == 0) {
            // called with nothing to remove!
            throw new IllegalArgumentException("input param 'ids' can't be null");
        }
    
        ContentValues values = new ContentValues();
        values.put(Downloads.Impl.COLUMN_CONTROL, Downloads.Impl.CONTROL_RUN);
        values.put(Downloads.Impl.COLUMN_STATUS, Downloads.Impl.STATUS_RUNNING);
        if (ids.length == 1) {
            return mResolver.update(ContentUris.withAppendedId(mBaseUri, ids[0]), values,
                    null, null);
        } 
        return mResolver.update(mBaseUri, values, getWhereClauseForIds(ids),
                getWhereArgsForIds(ids));
    }