this is my code and i want to add resumable feature but i couldn't is it posible?
downloadManager = (DownloadManager)getSystemService(DOWNLOAD_SERVICE);
Uri Download_Uri = Uri.parse("http://download.thinkbroadband.com/20MB.zip");
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 (if enabled).
request.setTitle("My Data Download");
//Set a description of this download, to be displayed in notifications (if enabled)
request.setDescription("Android Data download using DownloadManager.");
//Set the local destination for the downloaded file to a path within the application's external files directory
request.setDestinationInExternalFilesDir(this, Environment.DIRECTORY_DOWNLOADS,"20MB.zip");
//Enqueue a new download and same the referenceId
downloadReference = downloadManager.enqueue(request);
I was able to implement Pause/Resume functionality using the following implementation via the Android DownloadManager and Downloads Content Provider:
private boolean resumeDownload(Context context, String downloadTitle) {
int updatedRows = 0;
ContentValues resumeDownload = new ContentValues();
resumeDownload.put("control", 0); // Resume Control Value
try {
updatedRows = context
.getContentResolver()
.update(Uri.parse("content://downloads/my_downloads"),
resumeDownload,
"title=?",
new String[]{ downloadTitle });
} catch (Exception e) {
Log.e(TAG, "Failed to update control for downloading video");
}
return 0 < updatedRows;
}
private boolean pauseDownload(Context context, String downloadTitle) {
int updatedRows = 0;
ContentValues pauseDownload = new ContentValues();
pauseDownload.put("control", 1); // Pause Control Value
try {
updatedRows = context
.getContentResolver()
.update(Uri.parse("content://downloads/my_downloads"),
pauseDownload,
"title=?",
new String[]{ downloadTitle });
} catch (Exception e) {
Log.e(TAG, "Failed to update control for downloading video");
}
return 0 < updatedRows;
}
Related
Download Manager gets the error below on Android 10 devices. The target version is 29.
I added android:requestLegacyExternalStorage="true" tag to the Manifest, but it didn't work.
java.lang.SecurityException: Unsupported path /storage/emulated/0/Contents/Awesome App.apk
Here is the code
public static void startDownload(Context context, String url, String token, String subPath) {
DownloadManager.Request request;
DownloadManager manager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
Uri uri = Uri.parse(url); // A url to download a file
try {
request = new DownloadManager.Request(uri);
request.addRequestHeader("X-Auth-Token", token);
} catch (IllegalArgumentException e) {
e.printStackTrace();
return;
}
request.setVisibleInDownloadsUi(true);
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE);
try {
File downloadFileDir = new File(Environment
.getExternalStorageDirectory().getAbsolutePath() + "/Contents");
if (downloadFileDir != null) {
if (!downloadFileDir.exists()) {
downloadFileDir.mkdirs();
}
File file = new File(downloadFileDir.getAbsolutePath() + File.separator + subPath);
// subPath is name of the file to download. e.g. Awesome App.apk
if (file.exists()) {
file.delete();
}
Uri localUri = Uri.fromFile(file);
request.setDestinationUri(localUri);
if (localUri != null) {
request.setMimeType(MimeTypeMap.getSingleton().getMimeTypeFromExtension(MimeTypeMap.getFileExtensionFromUrl(localUri.toString())));
}
}
} catch (SecurityException e) {
e.printStackTrace();
}
request.setTitle(subPath);
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
try {
manager.enqueue(request);
} catch (SecurityException e) {
e.printStackTrace();
//Got exception here
}
}
/storage/emulated/0/Contents/Awesome App.apk
In an Android 10 device the DownloadManager will not download to your own directories on external storage.
You need to use one of the already available public directories like Document, Download, DCIM, Music and so on.
So you can let download to
/storage/emulated/0/Music/Contents/Awesome App.apk
No need to create your subdirectory yourself as the download manager will do it.
You app does not need any permission to let the download manager execute its task.
I am downloading mp3 file from this url using DownloadManager. Here is my code.
// Downloading file from internet and save to internal storage.
private void downloadFromOnline() {
downloadManager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
registerReceiver(onComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
DownloadManager.Request request = null;
request = new DownloadManager.Request(Uri.parse("https://alquran.technobdapis.com/quranallaudio/arabic_with_bangla/arbn_001.mp3"));
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI | DownloadManager.Request.NETWORK_MOBILE);
request.setAllowedOverRoaming(false);
request.setTitle("Downloading...");
request.setDescription("Downloading...arbn_001.mp3");
request.setVisibleInDownloadsUi(true);
File SDCardpath = getFilesDir();
File myDataPath = new File(SDCardpath.getAbsolutePath());
// Internal storage file path to save the downloaded file
// /data/data/com.technobd.internalstoragetest/files/arabic_with_bangla/arbn_001.mp3
if (!myDataPath.exists())
myDataPath.mkdir();
request.setDestinationInExternalFilesDir(getApplicationContext(), myDataPath.getPath() + "/arabic_with_bangla", "arbn_001.mp3");
long refid = downloadManager.enqueue(request);
id = refid;
}
I have tried to play the downloaded file in media player using this code. But unfortunately targetFile.exists() returns false although file exists in that path. Here is the code -
public BroadcastReceiver onComplete = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
File SDCardpath = getFilesDir();
File myDataPath = new File(SDCardpath.getAbsolutePath());
File targetFile = new File(myDataPath.getPath() + "/arabic_with_bangla/" +"arbn_001.mp3");
Log.d("FileExists", targetFile.exists() + " ");
// Downloaded file path
// /data/data/com.technobd.internalstoragetest/files/arabic_with_bangla/arbn_001.mp3
// Although target file exists in device It's targetFile.exists() returning false
// TODO: This is the main problem.
if(targetFile.exists()){
MediaPlayer mp = new MediaPlayer();
try {
mp.setDataSource(MainActivity.this, Uri.parse(targetFile.getParent()));
mp.prepare();
mp.start();
} catch (Exception e) {
e.printStackTrace();
}
}else{
// File Not Exists
Log.d("FileExists", targetFile.exists() + " ");
}
}
};
File exists in my device.
I am downloading a pdf file using DownloadManager class. It works fine on a Huawei GRA-L09 with android 5.0.1 but on my Nexus 6p with android 7.1.1 I experience the following behavior:
After the file is downloaded I try to open it via intent Action_View so it will be opened with pdf viewer. But when I try to open it I got an error that the file size is 0 and cannot be opened. If I wait about 10 seconds I am able to open the file.
This is the source code of DownloadManager:
DownloadManager dm = (DownloadManager) mContext.getSystemService(Context.DOWNLOAD_SERVICE);
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url)); request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
request.setDestinationInExternalPublicDir("/Download", "test.pdf");
long enqueue = dm.enqueue(request);
This is the source code of the BroadcastReceiver:
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)) {
DownloadManager.Query query = new DownloadManager.Query();
query.setFilterById(enqueue);
Cursor cursor = null;
String uri = null;
String mime = null;
try {
cursor = downloadManager.query(query);
if (cursor.moveToFirst()) {
int status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS));
if (status == DownloadManager.STATUS_SUCCESSFUL) {
// process download
uri = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
mime = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_MEDIA_TYPE));
}
}
} finally {
if (cursor != null) {
cursor.close();
}
}
openFile(Uri.parse(uri), mime);
}
}
};
private void openFile(final Uri fileLocation, final String mimeType) {
Intent objIntent = new Intent(Intent.ACTION_VIEW);
objIntent.setDataAndType(fileLocation, mimeType);
Log.d(Constants.TAG, "Downloaded file Uri: " + fileLocation.toString() + " mime:" + mimeType);
objIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
Intent chooserIntent = Intent.createChooser(objIntent, getString(R.string.choose_application));
startActivity(chooserIntent);//Starting the pdf viewer
}
I tried opening it without the intent for pdf, just by pressing the notification icon on the status bar. The same thing happens, as if the file is locked or not downloaded yet.
UPDATE: On the Nexus device I get file size = 0 when i check file.length() after the download is completed. On the Huawei GRA-L09 the file size is 1882670.
So why do I get Download completed broadcast for a file with size 0?
have an use case like the following:
There are several files to download e.g. A B C D E F
When the downloading is started , say the A B is finished and C is downloading, I would like to interrupt the download of C and start the download of E
Then, after E is finished (if there is no other interruption), continue to C D F.
So far form my research there is only cancel method
downloadManager.remove(downloadReference);
How to achieve this through Download manager or are there other approach ? thanks
private long startDownload(String url) {
Uri DownloadUri = Uri.parse(url);
String fileName = StorageUtils.getFileNameFromUrl(url);
String destination = null;
downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
DownloadManager.Request request = new DownloadManager.Request(
DownloadUri);
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI | DownloadManager.Request.NETWORK_MOBILE);
request.setAllowedOverRoaming(false);
request.setTitle(fileName);
request.setDescription("com.example.services");
if (StorageUtils.isSDCardPresent()
&& StorageUtils.isSdCardWrittenable()
&& StorageUtils.checkAvailableStorage()) {
destination = StorageUtils.SDCARD_ROOT;
}
try {
StorageUtils.mkdir();
} catch (IOException e) {
e.printStackTrace();
}
request.setDestinationInExternalPublicDir(destination, fileName);
downloadReference = downloadManager.enqueue(request);
Log.d("Downloader","Start download manager: " + destination + fileName);
return downloadReference;
}
Regarding this answer, it looks like you can cancel the download and then download the rest of the file. For example:
Register a BrodcastReciever to notify you when C is completed:
BroadcastReceiver onComplete = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//check if it is B that is complete
//cancel C
// download E
//check if it is E that is complete
// Open connection to URL.
HttpURLConnection connection =
(HttpURLConnection) url.openConnection();
// Specify what portion of file to download.
connection.setRequestProperty("Range", "bytes=" + downloaded + "-");
// here "downloaded" is the data length already previously downloaded.
// Connect to server.
connection.connect();
}
};
registerReceiver(onComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
//download A
//download B
//download C
I am facing problem of opening downloaded file after successfull download via DownloadManager API. In my code:
Uri uri=Uri.parse("http://www.nasa.gov/images/content/206402main_jsc2007e113280_hires.jpg");
Environment
.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
.mkdirs();
lastDownload = mgr.enqueue(new DownloadManager.Request(uri)
.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI |
DownloadManager.Request.NETWORK_MOBILE)
.setAllowedOverRoaming(false)
.setTitle("app update")
.setDescription("New version 1.1")
.setShowRunningNotification(true)
.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "a.apk"));
Cursor c=mgr.query(new DownloadManager.Query().setFilterById(lastDownload));
if(c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS)) == 8) {
try {
mgr.openDownloadedFile(c.getLong(c.getColumnIndex(DownloadManager.COLUMN_ID)));
} catch (NumberFormatException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Log.d("MGR", "Error");
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Log.d("MGR", "Error");
}
}
Problem is when is if(c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS))==8) evoked. I got status -1 and an exception. Is there any better way, how to open downloaded files with DownloadManager API? In my example I am downloading a big image, in a real situation I would be downloading an APK file and I need to display an installation dialog immediately after udpate.
Edit: I figured out that status=8 is after successfull download. You might have different "checking successfull download" approach
Thanks
Problem
Android DownloadManager API - opening file after download?
Solution
/**
* Used to download the file from url.
* <p/>
* 1. Download the file using Download Manager.
*
* #param url Url.
* #param fileName File Name.
*/
public void downloadFile(final Activity activity, final String url, final String fileName) {
try {
if (url != null && !url.isEmpty()) {
Uri uri = Uri.parse(url);
activity.registerReceiver(attachmentDownloadCompleteReceive, new IntentFilter(
DownloadManager.ACTION_DOWNLOAD_COMPLETE));
DownloadManager.Request request = new DownloadManager.Request(uri);
request.setMimeType(getMimeType(uri.toString()));
request.setTitle(fileName);
request.setDescription("Downloading attachment..");
request.allowScanningByMediaScanner();
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName);
DownloadManager dm = (DownloadManager) activity.getSystemService(Context.DOWNLOAD_SERVICE);
dm.enqueue(request);
}
} catch (IllegalStateException e) {
Toast.makeText(activity, "Please insert an SD card to download file", Toast.LENGTH_SHORT).show();
}
}
/**
* Used to get MimeType from url.
*
* #param url Url.
* #return Mime Type for the given url.
*/
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;
}
/**
* Attachment download complete receiver.
* <p/>
* 1. Receiver gets called once attachment download completed.
* 2. Open the downloaded file.
*/
BroadcastReceiver attachmentDownloadCompleteReceive = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)) {
long downloadId = intent.getLongExtra(
DownloadManager.EXTRA_DOWNLOAD_ID, 0);
openDownloadedAttachment(context, downloadId);
}
}
};
/**
* Used to open the downloaded attachment.
*
* #param context Content.
* #param downloadId Id of the downloaded file to open.
*/
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();
}
/**
* Used to open the downloaded attachment.
* <p/>
* 1. Fire intent to open download file using external application.
*
* 2. Note:
* 2.a. We can't share fileUri directly to other application (because we will get FileUriExposedException from Android7.0).
* 2.b. Hence we can only share content uri with other application.
* 2.c. We must have declared FileProvider in manifest.
* 2.c. Refer - https://developer.android.com/reference/android/support/v4/content/FileProvider.html
*
* #param context Context.
* #param attachmentUri Uri of the downloaded attachment to be opened.
* #param attachmentMimeType MimeType of the downloaded attachment.
*/
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(activity, "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(R.string.unable_to_open_file), Toast.LENGTH_LONG).show();
}
}
}
Initialize FileProvider Details
Decleare FileProvider in AndroidManifest
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.freshdesk.helpdesk.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_path"/>
</provider>
Add the following file "res -> xml -> file_path.xml"
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="attachment_file" path="."/>
</paths>
Note
Why Use FileProvider
From Android 7.0 we can't share FileUri with other appliction.
Using "DownloadManager.COLUMN_LOCAL_URI" we will get only FileUri hence we need to convert it into ContentUri & share with other application.
Provblem with using "DownloadManager.getUriForDownloadedFile(long id)"
Don't use "DownloadManager.getUriForDownloadedFile(long id)" - To get Uri from downloadId to open the file using external application.
Because from Android 6.0 & 7.0 "getUriForDownloadedFile" method returns local uri (Which can be accessed only by our application), we can't share that Uri with other application because they can't access that uri (But it is fixed in Android 7.1 see Android Commit Here).
Refere Android source code DownloadManager.java & Downloads.java
Hence always use Column "DownloadManager.COLUMN_LOCAL_URI" to get Uri.
Reference
https://developer.android.com/reference/android/app/DownloadManager.html
https://developer.android.com/reference/android/support/v4/content/FileProvider.html
You need to register a reciever for when the download is complete:
registerReceiver(onComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
and a BroadcastReciever handler
BroadcastReceiver onComplete=new BroadcastReceiver() {
public void onReceive(Context ctxt, Intent intent) {
// Do Something
}
};
Buy instead of me ripping off everything, I suggest you'll check this out.
EDIT:
Just as a suggestion, I wouldn't recommend using API 9 just yet: http://developer.android.com/resources/dashboard/platform-versions.html
There are ways around this, by creating your very own download handler, like I did, because we didn't want to alienate most of our android's user base, for that you'll need:
Create AsyncTask which handles the file download.
and i'll recommend to create a download dialog of some sort (if you say it's a big file, i'd make it appear in the notification area).
and than you'll need to 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);
}
For Kotlin, you can easily just use the URL.openStream() method to read and save your file in your directory.
If you want to do more fancier, like background threads.
You should checkout Elye's article on Medium.
https://medium.com/mobile-app-development-publication/download-file-in-android-with-kotlin-874d50bccaa2
private fun downloadVcfFile() {
CoroutineScope(Dispatchers.IO).launch {
val url = "https://srv-store5.gofile.io/download/JXLVFW/vcard.vcf"
val path = "${Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)}/contacts.vcf"
URL(url).openStream().use { input ->
FileOutputStream(File(path)).use { output ->
input.copyTo(output)
val file = File(path)
file.createNewFile()
onMain { saveVcfFile(file) }
}
}
}
}
remember add <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" /> to your AndroidMannifest.xml file