I have this application wherein a feature of it will allow you to download a video. The download part is working, but I need to do another function right after the download has been completed. Currently, I am using AsyncTask, but whenever I try to toast on the PostExecute, nothing happens. I'd like to call another function to encrypt then delete the original file after the download has been completed.
And btw, the encryption part is working as well. The only thing I need is something that will allow me to know if the download has been completed.
This is the code where in I'll be downloading the file from a URL. But, I need to know if the download is complete to execute the AsyncTask
public void downloadTutorial() throws Exception {
myURL = "";
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(myURL));
request.setTitle(injuryType + " Video");
request.setDescription("File is being downloaded...");
request.allowScanningByMediaScanner();
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
String fileName = URLUtil.guessFileName(myURL, null, MimeTypeMap.getFileExtensionFromUrl(myURL));
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName);
DownloadManager manager = (DownloadManager) getActivity().getSystemService(Context.DOWNLOAD_SERVICE);
manager.enqueue(request);
//if the download is complete execute this
//new JSONTask().execute();
}
The code of the AsyncTask is:
public class JSONTask extends AsyncTask<Void, Void, Void>{
#Override
protected Void doInBackground(Void... params) {
try {
Encrypter.encrypt(injuryType);
} catch (IOException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
Toast.makeText(getActivity(), "Download Done", Toast.LENGTH_SHORT).show();
}
}
So you want to access the file after downloading the file using Download Manager.
First you will need a Broadcast receiver which will inform you after downloading a file.
In Manifest :
<receiver
android:name="<your download receiver class extends Broadcast receiver>"
android:enabled="true"
android:protectionLevel= "signature"
>
<intent-filter>
<action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
</intent-filter>
</receiver>
Now you will need to save the download reference id in sharedpref or database
Now save this download reference id in your sharedpref or database so that we can get it in broadcast receiver.
Uri uri = Uri.parse(content.url);
DownloadManager.Request request = new DownloadManager.Request(uri);
request.setDescription("Your App Title").setTitle(<file title>);
request.setDestinationInExternalFilesDir(getActivity(), Environment.DIRECTORY_DOWNLOADS, <file title>);
request.setVisibleInDownloadsUi(false); //the content will not shown in Download Manager App
mydownlodreference = downloadManager.enqueue(request);
Now the main part, in onReceive of BroadcastReceiver class
#Override
public void onReceive(Context context, Intent intent) {
DownloadManager downloadManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
long reference = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
// take out the reference id from your sharedpref or database and check that referenceId with this reference
DownloadManager.Query query = new DownloadManager.Query();
query.setFilterById(reference);
Cursor c = downloadManager.query(query);
c.moveToFirst();
int columnIndex = c.getColumnIndex(DownloadManager.COLUMN_STATUS);
int status = c.getInt(columnIndex);
int fileNameIndex = c.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME);
String filePath = c.getString(fileNameIndex);
if (status == DownloadManager.STATUS_SUCCESSFUL) {
// do whatever you want here
}
}
Related
I am downloading audio files from a parse server. The results after running the code below is that when the client clicks the notification, it plays. However, when the client closes the music player, and opens it back up, it is no longer listed. My question is, where is this file located? I have seen methods for setting the external storage location, but I would like for it to download to the internal storage with the other downloads. How can I accomplish this?
private class DownloadFileTask extends AsyncTask<String, Void, String> {
#Override
protected void onPreExecute() {
Toast.makeText(getActivity(), getString(R.string.downloading), Toast.LENGTH_SHORT).show();
super.onPreExecute();
}
#Override
protected String doInBackground(String... urls) {
String currentSong = urls[0];
try {
downloadManager = (DownloadManager) getActivity().getSystemService(Context.DOWNLOAD_SERVICE);
Uri uri = Uri.parse(currentSong);
DownloadManager.Request request = new DownloadManager.Request(uri);
request.allowScanningByMediaScanner();
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE);
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
downloadManager.enqueue(request);
}
catch (Exception e) {
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
}
return currentSong;
}
#Override
protected void onPostExecute(String s) {
Toast.makeText(getActivity(), getString(R.string.download_complete), Toast.LENGTH_SHORT).show();
super.onPostExecute(s);
}
I have a download manager that downloads an image on clicking a button. with help of broadcast receivers I will do this.
below is my code:
public void myDownloadManager(){
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 c = dm.query(query);
if (c.moveToFirst()) {
int columnIndex = c.getColumnIndex(DownloadManager.COLUMN_STATUS);
if (DownloadManager.STATUS_SUCCESSFUL == c.getInt(columnIndex)) {
// download finished successfully
Log.e("count downloads", "counting");
db.insertDownloadsRows(image_id);
}
}
}
}
};
getActivity().registerReceiver(receiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
}
public void downloadImage(){
myDownloadManager();
dm = (DownloadManager) getActivity().getSystemService(getActivity().DOWNLOAD_SERVICE);
DownloadManager.Request request = new DownloadManager.Request(Uri.parse("some uri"));
request.setDestinationInExternalPublicDir("some directory", name);
enqueue = dm.enqueue(request);
}
and downloadImage() is called in button's onClickListener. when I tap the button for the first time, the image will be downloaded once and the Log message shown up once, for the second time when I tap the button, the image will be downloaded once but the Log message shown up twice, and this happens as much as I tap button. why is it this way? how should it be fixed?
That happens because you are registering the receiver multiple times without unregistering it, so you have to do one of two things:
even register the receiver only once like within your onCreate() method for example (which is absolutely the better solution):
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.videoview);
myDownloadManager();
}
public void downloadImage(){
dm = (DownloadManager) getActivity().getSystemService(getActivity().DOWNLOAD_SERVICE);
DownloadManager.Request request = new DownloadManager.Request(Uri.parse("some uri"));
request.setDestinationInExternalPublicDir("some directory", name);
enqueue = dm.enqueue(request);
}
OR call unregister receiver each time you finish dealing with the downloading file:
public void downloadImage(){
// Un-registering the receiver
unregisterReceiver(receiver);
myDownloadManager();
dm = (DownloadManager) getActivity().getSystemService(getActivity().DOWNLOAD_SERVICE);
DownloadManager.Request request = new DownloadManager.Request(Uri.parse("some uri"));
request.setDestinationInExternalPublicDir("some directory", name);
enqueue = dm.enqueue(request);
}
Iam trying to update my app by downloading the apk using download manager. I have registered broadcast receiver to listen to DownloadManager.ACTION_DOWNLOAD_COMPLETE in MainActivity and open the apk in onReceive method.
Following is the code:
public class MainActivity extends CordovaActivity {
private long downloadReference;
private DownloadManager downloadManager;
private IntentFilter intentFilter = new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
registerReceiver(downloadReceiver, intentFilter);
}
public void updateApp(String url) {
//start downloading the file using the download manager
downloadManager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
Uri Download_Uri = Uri.parse(url);
DownloadManager.Request request = new DownloadManager.Request(Download_Uri);
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI);
request.setAllowedOverRoaming(false);
request.setDestinationInExternalFilesDir(MainActivity.this, Environment.DIRECTORY_DOWNLOADS, "myapk.apk");
downloadReference = downloadManager.enqueue(request);
}
#Override
public void onDestroy() {
//unregister your receivers
this.unregisterReceiver(downloadReceiver);
super.onDestroy();
}
private BroadcastReceiver downloadReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//check if the broadcast message is for our Enqueued download
long referenceId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
if (downloadReference == referenceId) {
//start the installation of the latest version
Intent installIntent = new Intent(Intent.ACTION_VIEW);
installIntent.setDataAndType(downloadManager.getUriForDownloadedFile(downloadReference),
"application/vnd.android.package-archive");
installIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(installIntent);
}
}
};
}
updateApp(url) is called on click of a button in UI.
Now after clicking the button, the download starts. Lets say the app is closed (receiver is unregistered) after initiating the download, I have problem with two scenarios when the app is started again.
The previous download completes after my app is restarted -
downloadReference is lost and when my receiver receives the broadcast, the referenceId wont be same as downloadReference, so installIntent is never started. So
I have to click on Update button again and initiate the download. Is
there a way to avoid this problem?
The previous download completes before my app is restarted - There is no way of knowing that my previous download is complete in
the newly started activity. Again I have to click the button and reinitiate the download. Is there a way to enable sticky
broadcast for download manager?
For this, you have to store the download reference in your preference. Then you can query the DownloadManager using DownloadManager.Query() which will return a cursor holding all the download requests posted to DownloadManager by your app. Then you can match the downloadReference id and then check the status of your download. If it's complete then you can get the path from DownloadManager.COLUMN_LOCAL_FILENAME.
private void updateDownloadStatus(long downloadReference) {
DownloadManager.Query query = new DownloadManager.Query();
// if you have stored the downloadReference. Else you have to loop through the cursor.
query.setFilterById(downloadReference);
Cursor cursor = null;
try {
cursor = DOWNLOAD_MANAGER.query(query);
if (cursor == null || !cursor.moveToFirst()) {
// restart download
return;
}
float bytesDownloaded =
cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
float bytesTotal =
cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
int columnIndex = cursor.getColumnIndex(DownloadManager.COLUMN_STATUS);
int downloadStatus = cursor.getInt(columnIndex);
int columnReason = cursor.getColumnIndex(DownloadManager.COLUMN_REASON);
int failureStatus = cursor.getInt(columnReason);
int filePathInt = cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME);
String filePath = cursor.getString(filePathInt);
switch (downloadStatus) {
case DownloadManager.STATUS_FAILED:
case DownloadManager.ERROR_FILE_ERROR:
// restart download
break;
case DownloadManager.STATUS_SUCCESSFUL:
if (filePath != null) {
//got the file
} else {
//restart
}
break;
case DownloadManager.STATUS_PENDING:
case DownloadManager.STATUS_RUNNING:
case DownloadManager.STATUS_PAUSED:
/// wait till download finishes
break;
}
} catch (Exception e) {
Log.e("Error","message" + e.getMessage(), e);
} finally {
if (cursor != null) {
cursor.close();
}
}
}
In my app i have started download service,it is working fine in background.During download my testing team doing force stop and clear data or Uninstall.But After uninstall or clear data still my Download service is running in background.During download i have installed the same app again but it is misbehaving some thing.While uninstall or clear data or force stop i have to cancel the download How?
public class FileDownloaderService extends IntentService {
private CarcarePreferences preferences;
public FileDownloaderService() {
super("FileDownloaderService");
}
#Override
public void onCreate() {
super.onCreate();
preferences = CarcarePreferences.getCarcarePreferencesObject(getApplicationContext());
DBHelper.getInstance(getApplicationContext()).open();
downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
}
#Override
protected void onHandleIntent(Intent intent) {
Bundle extras = intent.getExtras();
if (extras == null) {
return;
}
if (extras.containsKey("ResultReceiver")) {
resultReceiver = extras.getParcelable("ResultReceiver");
}
if (extras.containsKey("ContentToDownload")) {
contentToDownload = extras.getInt("ContentToDownload");
} else {
return;
}
if (contentToDownload != Carcare.ContentToDownload.IMAGES) {
isDefaultVehicle = extras.getBoolean("IsDefaultVehicle");
fetchVehicle();
}
switch (contentToDownload) {
case Carcare.ContentToDownload.HEADUNIT_IMAGES:
if (extras.containsKey("HeadUnits")) {
headUnits = (ArrayList<Unit>) extras.getSerializable("Units");
downloadHeadUnits();
resultReceiver.send(0, null);
}
break;
}
}
private void fetchVehicle() {
Object[] objects;
if (isDefaultVehicle) {
objects = DBAdapter.getAllVehicles(preferences.getDefaultModel(),
preferences.getDefaultYear(), isDefaultVehicle);
} else {
objects = DBAdapter.getAllVehicles(preferences.getCurrentModel(),
preferences.getCurrentYear(), isDefaultVehicle);
}
vehicle = (Vehicle) objects[0];
}
private void downloadHeadUnits() {
mHeadUnitDir = SdUtils.getDir(this);
//clearHeadUnits();
for (CUnit unit : Units) {
String fileName = mDir + "/" + unit.getGuid() + ".png";
InputStream stream = null;
final HttpGet httpRequest = new HttpGet(unit.getHuImageUrl());
httpRequest.setHeader(HTTP.CONN_DIRECTIVE, HTTP.CONN_KEEP_ALIVE);
try {
File file = new File(fileName);
if (!file.exists()) {
FileOutputStream out = new FileOutputStream(file); //openFileOutput(fileName);
stream = new DefaultHttpClient().execute(httpRequest).getEntity().getContent();
Bitmap bitmap = BitmapFactory.decodeStream(stream);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
}
} catch (IOException ex) {
ex.printStackTrace();
} catch (IllegalStateException ex) {
ex.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
private void download() {
cancelDownload(Carcare.FileType.QRG, vehicle.getPath());
deleteDoc(vehicle.getQRGPath());
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(vehicle.getUrl()));
request.setDestinationUri(Uri.parse(vehicle.getPath()));
request.setTitle("Unit");
request.setDescription("Quick Reference Guide");
preferences.setDownloadID(Carcare.FileType.QRG, downloadManager.enqueue(request));
}
}
You must use a Service.
In the Service's onDestroy(), you can write the code to finish the DownloadManager.
The Service will be killed before the app is about to uninstall.
This way the Download will stop.
Take a look at the remove() method of the DownloadManager.
It says:
public int remove (long... ids) Added in API level 9
Cancel downloads and remove them from the download manager. Each
download will be stopped if it was running, and it will no longer be
accessible through the download manager. If there is a downloaded
file, partial or complete, it is deleted. Parameters ids the IDs of
the downloads to remove Returns
the number of downloads actually removed
Edit
To intercept your application uninstall take a look at this answer.
Here's my problem.
I'm trying to download file from my server using download manager intent via Asynctask.
in my doInBackground of asynctask class, i was call download manager intent, and doinBackground will return boolean value when download finish (Success or Failed).
Here's my code
protected Boolean doInBackground(String... f_url) {
boolean flag = true;
boolean downloading =true;
try{
DownloadManager mManager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
Request mRqRequest = new Request(
Uri.parse("http://"+model.getDownloadURL()));
long idDownLoad=mManager.enqueue(mRqRequest);
DownloadManager.Query query = null;
query = new DownloadManager.Query();
Cursor c = null;
if(query!=null) {
query.setFilterByStatus(DownloadManager.STATUS_FAILED|DownloadManager.STATUS_PAUSED|DownloadManager.STATUS_SUCCESSFUL|
DownloadManager.STATUS_RUNNING|DownloadManager.STATUS_PENDING);
} else {
return flag;
}
c = mManager.query(query);
if(c.moveToFirst()) {
int status =c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS));
while (downloading)
{ Log.i ("FLAG","Downloading");
if (status==DownloadManager.STATUS_SUCCESSFUL)
{ Log.i ("FLAG","done");
downloading = false;
flag=true;
break;
}
if (status==DownloadManager.STATUS_FAILED)
{Log.i ("FLAG","Fail");
downloading = false;
flag=false;
break;
}
c.moveToFirst();
}
}
return flag;
}
catch (Exception e)
{
flag = false;
return flag;
}
}
But DownloadManager status never jump on DownloadManager.STATUS_SUCCESSFUL or DownloadManager.STATUS_FAILED.
There's no need for the AsyncTask or the synchronous query. DownloadManager is already asynchronous. You should register a BroadcastReceiver for ACTION_DOWNLOAD_COMPLETE so that you get notified when the download completes (or fails).
There's a very good example at http://blog.vogella.com/2011/06/14/android-downloadmanager-example
You have to requery the download manager. The cursor stays the same even if the data changes. Try like this:
protected Boolean doInBackground(String... f_url) {
boolean flag = true;
boolean downloading =true;
try{
DownloadManager mManager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
Request mRqRequest = new Request(
Uri.parse("http://"+model.getDownloadURL()));
long idDownLoad=mManager.enqueue(mRqRequest);
DownloadManager.Query query = null;
query = new DownloadManager.Query();
Cursor c = null;
if(query!=null) {
query.setFilterByStatus(DownloadManager.STATUS_FAILED|DownloadManager.STATUS_PAUSED|DownloadManager.STATUS_SUCCESSFUL|DownloadManager.STATUS_RUNNING|DownloadManager.STATUS_PENDING);
} else {
return flag;
}
while (downloading) {
c = mManager.query(query);
if(c.moveToFirst()) {
Log.i ("FLAG","Downloading");
int status =c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS));
if (status==DownloadManager.STATUS_SUCCESSFUL) {
Log.i ("FLAG","done");
downloading = false;
flag=true;
break;
}
if (status==DownloadManager.STATUS_FAILED) {
Log.i ("FLAG","Fail");
downloading = false;
flag=false;
break;
}
}
}
return flag;
}catch (Exception e) {
flag = false;
return flag;
}
}
Download Manager download files in asynchronous manner. So no need to put download manager inside an Asyntask.
You can use Receiver for get the status of download manager if download complete.
public class CheckDownloadComplete extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
String action = intent.getAction();
if (action.equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE))
{
DownloadManager.Query query = new DownloadManager.Query();
query.setFilterById(intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0));
DownloadManager manager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
Cursor cursor = manager.query(query);
if (cursor.moveToFirst()) {
if (cursor.getCount() > 0) {
int status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS));
Long download_id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID,0);
// status contain Download Status
// download_id contain current download reference id
if (status == DownloadManager.STATUS_SUCCESSFUL)
{
String file = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME));
//file contains downloaded file name
// do your stuff here on download success
}
}
}
cursor.close();
}
}
}
Dont forget to add your receiver in Manifest
<receiver
android:name=".CheckDownloadComplete"
android:enabled="true"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
</intent-filter>
</receiver>