I'm using Android Download Manager to download list of files. Lately I came across a crash report saying
Unknown java.lang.IllegalArgumentException: Unknown URL content://downloads/my_downloads
Then later, I figured it out that the reason is because user disabled Android Download Manager. I check if the Download Manager is disabled by checking it's package name with the code below.
int state = this.getPackageManager().getApplicationEnabledSetting("com.android.providers.downloads");
And now, I need to find a way to enable the Download Manager if it is disabled. I tried setting it's enable state with the permission in Manifest but I keep getting Security Exception.
this.getPackageManager().setApplicationEnabledSetting("com.android.providers.downloads", PackageManager.COMPONENT_ENABLED_STATE_DEFAULT, 0);
<uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/>
So I thought it might not be reachable because of it is a system app. (Google Play App does it).
Is there any way to redirect the user to the Download Manager Application Info view ? to let the user enables it ? If there is no way to enable it on run time programmatically.
Please edit my answer if is not valid
Check if download manager is available:
int state = this.getPackageManager().getApplicationEnabledSetting("com.android.providers.downloads");
if(state==PackageManager.COMPONENT_ENABLED_STATE_DISABLED||
state==PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER
||state==PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED){
// Cannot download using download manager
}
else {
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName);
request.setDescription(fileName);
manager.enqueue(request);
}
And the solution for trying to enable download manager is:
packageName = "com.android.providers.downloads"
try {
//Open the specific App Info page:
Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.parse("package:" + packageName));
startActivity(intent);
} catch ( ActivityNotFoundException e ) {
//e.printStackTrace();
//Open the generic Apps page:
Intent intent = new Intent(android.provider.Settings.ACTION_MANAGE_APPLICATIONS_SETTINGS);
startActivity(intent);
}
Some folks were looking for an answer to this question and I just realized that the Answer made to this question is somehow deleted. So I want to answer my own question.
There is no way to activate/deactivate Download Manager directly, since it's system application and we don't have access to it.
Only alternative left is to redirect the User to the Info Page of Download Manager Application.
try {
//Open the specific App Info page:
Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.parse("package:" + "com.android.providers.downloads"));
startActivity(intent);
} catch ( ActivityNotFoundException e ) {
e.printStackTrace();
//Open the generic Apps page:
Intent intent = new Intent(android.provider.Settings.ACTION_MANAGE_APPLICATIONS_SETTINGS);
startActivity(intent);
}
Google Gmail Inbox has check whether the DownloadManager is been disabled,if true then show an AlertDialog to tell user to enable the DownloadManager in Settings.The screenshot show below:
I wrote a class called DownloadManagerResolver to fix this,hope this can help your.:)
public final class DownloadManagerResolver {
private static final String DOWNLOAD_MANAGER_PACKAGE_NAME = "com.android.providers.downloads";
/**
* Resolve whether the DownloadManager is enable in current devices.
*
* #return true if DownloadManager is enable,false otherwise.
*/
public static boolean resolve(Context context) {
boolean enable = resolveEnable(context);
if (!enable) {
AlertDialog alertDialog = createDialog(context);
alertDialog.show();
}
return enable;
}
/**
* Resolve whether the DownloadManager is enable in current devices.
*
* #param context
* #return true if DownloadManager is enable,false otherwise.
*/
private static boolean resolveEnable(Context context) {
int state = context.getPackageManager()
.getApplicationEnabledSetting(DOWNLOAD_MANAGER_PACKAGE_NAME);
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2) {
return !(state == PackageManager.COMPONENT_ENABLED_STATE_DISABLED ||
state == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER
|| state == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED);
} else {
return !(state == PackageManager.COMPONENT_ENABLED_STATE_DISABLED ||
state == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER);
}
}
private static AlertDialog createDialog(final Context context) {
AppCompatTextView messageTextView = new AppCompatTextView(context);
messageTextView.setTextSize(16f);
messageTextView.setText("DownloadManager is disabled. Please enable it.");
return new AlertDialog.Builder(context)
.setView(messageTextView, 50, 30, 50, 30)
.setPositiveButton("ok", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
enableDownloadManager(context);
}
})
.setCancelable(false)
.create();
}
/**
* Start activity to Settings to enable DownloadManager.
*/
private static void enableDownloadManager(Context context) {
try {
//Open the specific App Info page:
Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.parse("package:" + DOWNLOAD_MANAGER_PACKAGE_NAME));
context.startActivity(intent);
} catch (ActivityNotFoundException e) {
e.printStackTrace();
//Open the generic Apps page:
Intent intent = new Intent(android.provider.Settings.ACTION_MANAGE_APPLICATIONS_SETTINGS);
context.startActivity(intent);
}
}
}
May be it's help to you.
downloadManager = (DownloadManager)getSystemService(DOWNLOAD_SERVICE);
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,"CountryList.json");
//Enqueue a new download and same the referenceId
downloadReference = downloadManager.enqueue(request);
http://www.mysamplecode.com/2012/09/android-downloadmanager-example.html
Related
I have created an Android application and save files using the following method:
File created = new File(dir, time.format("%Y%m%d%H%M%S") + "." + suffix);
However, even when the device is connected to my computer, the saved files only appear in the specified directory AFTER restarting the device. How do I force the files to show without restarting?
Use the media scanner. Notice the mime type, you might need to change that depending on the file you are creating
MediaScannerConnection.scanFile(this.getApplicationContext(), new String[] { filename }, new String[] { "image/jpeg" }, new OnScanCompletedListener()
{
#Override
public void onScanCompleted(final String path, final Uri uri)
{
// Eureka, your file has been scanned!
}
});
Here are some more ways to broadcast a new file:
UPDATE:
void alternativeScan(final String filename)
{
final File file = new File(filename);
final Uri fileUri = Uri.fromFile(file);
// New way
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH)
{
this.getApplicationContext().sendBroadcast(new Intent("android.hardware.action.NEW_PICTURE", fileUri));
}
// Keep compatibility
this.getApplicationContext().sendBroadcast(new Intent("com.android.camera.NEW_PICTURE", fileUri));
// Usual way
final Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
intent.setData(fileUri);
this.getApplicationContext().sendBroadcast(intent);
}
And in case still doesn't work, use the next function to check your media storage state
public static int getMediaStorageState()
{
final String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state))
{
return 0; // All Ok, supported Read & Write
}
else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state))
{
return 1; // Media storage has Read Only state
}
else
{
return 2; // Something's wrong. No Read/Write access
}
}
Assuming that dir is out on external storage somewhere and "only appear" means "only appear when I connect the device to my development machine using a USB cable", use MediaScannerConnection and scanFile() to update the MediaStore index.
Note that you may also need to do some sort of refresh operation on your development machine, if the development machine's OS (e.g., Windows) caches MTP results.
I have an Android app where I intercept a PDF file download event in the WebView, download it using the DownloadManager, and launch a new intent with the Adobe Reader to display the file. It works fine, except that when the Adobe Reader starts, it displays the following message prior to displaying the actual file:
Read-only document | To modify this document save a copy on your device.
Save | View Read-only
After I dismiss this prompt, the document gets displayed correctly. How can I get rid of the Read-only prompt?
Here is my code:
public class MyDownloadListener implements DownloadListener {
MainActivity activity;
BroadcastReceiver receiver;
DownloadManager downloadManager;
public MyDownloadListener(MainActivity a) {
activity = a;
downloadManager = (DownloadManager) activity.getSystemService(Context.DOWNLOAD_SERVICE);
receiver = 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);
Query query = new Query();
query.setFilterById(downloadId);
Cursor c = downloadManager.query(query);
if (c.moveToFirst()) {
int columnIndex = c.getColumnIndex(DownloadManager.COLUMN_STATUS);
if (DownloadManager.STATUS_SUCCESSFUL == c.getInt(columnIndex)) {
String uriString = c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME));
File fileSrc = new File(uriString);
Intent intentPdf = new Intent(Intent.ACTION_VIEW);
intentPdf.setDataAndType(Uri.fromFile(fileSrc), "application/pdf");
intentPdf.setPackage("com.adobe.reader");
intentPdf.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
activity.startActivity(intentPdf);
}
}
}
}
};
activity.registerReceiver(receiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
}
#Override
public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) {
Request request = new Request(Uri.parse(url));
downloadManager.enqueue(request);
}
}
As per the official documentation of class DownloadManager.Request
This class contains all the information necessary to request a new
download. The URI is the only required parameter. Note that the
default download destination is a shared volume where the system might
delete your file if it needs to reclaim space for system use. If this
is a problem, use a location on external storage (see
setDestinationUri(Uri).
So default location is more of a cache location and system can delete the file if it require more space. So if you want to kep the file then you can use setDestinationUri to provide the path in the SD card..
And it looks like the default space does not allow any other thread/process other then the download manager to write file in that space, hence the read only message from the adobe reader..
I am using Android DownloadManger System Service for downloading some files in following way
dwnId = mgr.enqueue(new DownloadManager.Request(serveruri)
.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI |
DownloadManager.Request.NETWORK_MOBILE)
.setAllowedOverRoaming(false)
.setTitle(getAlbumName())
.setDescription(getTrackName())
.setDestinationUri(deviceUri)
.setShowRunningNotification(true));
where mgr is Download Manager instance, dwnId is unique ID returned. I am also registering for ACTION_DOWNLOAD_COMPLETE
registerReceiver(onDownloadComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
and in the onDownloadComplete BroadcastReceiver's onReceive() method I am getting download Id like
Long dwnId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0);
After that I am querying Download Manager for Download status
Cursor c = downloadManager.query(new DownloadManager.Query().setFilterById(dwnId)); c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS));
for DownloadManager.STATUS_* constants.
The problem is I am receiving the same downId twice (means onReceive method is called twice), once with DownloadManager.STATUS_SUCCESSFUL status and once with DownloadManager.STATUS_FAILED status for same dwnId. I am issuing request to download some 10 files at a time and but on device download manager it is showing the download count as some 12 or 13 in the notification bar top left means. I think that Download manager has some problem in downloading files and resumed or automatically restarted to download the same file again. Thats why there is a difference between the files count I requested to download and actual number in download queue. Because of this only I am getting same DownloadId complete action twice. If this is true, how to restrict it. Am I wrong what might be the reason for count difference between what I requested to actual download? Why is the broadcast receiver receiving the same download Id twice. Can anybody please let me know?
Thanks In Advance...
This is a reported bug see: http://code.google.com/p/android/issues/detail?id=18462
The way around I found is to verify if the download was a success, if not ditch the intent or re-queue the file if it was never downloaded...
Lost a couple of hours figuring that one :(
** Edit: adding code example **
/**
* Check if download was valid, see issue
* http://code.google.com/p/android/issues/detail?id=18462
* #param long1
* #return
*/
private boolean validDownload(long downloadId) {
Log.d(TAG,"Checking download status for id: " + downloadId);
//Verify if download is a success
Cursor c= dMgr.query(new DownloadManager.Query().setFilterById(downloadId));
if(c.moveToFirst()){
int status = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS));
if(status == DownloadManager.STATUS_SUCCESSFUL){
return true; //Download is valid, celebrate
}else{
int reason = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_REASON));
Log.d(TAG, "Download not correct, status [" + status + "] reason [" + reason + "]");
return false;
}
}
return false;
}
For complete code see : https://github.com/flegare/JAV387_LaboWidget/blob/master/src/com/mobidroid/widgetfact/service/FactService.java
A simple way to download your files, See download progress in notification bar and even open your file when it complete to download by just clicking it in the notification bar.
Just call this method and pass your filename and download url
public void downloadFile(String name, String url){
//download link
downloadUri = Uri.parse(url);
DownloadManager.Request request = new DownloadManager.Request(downloadUri);
//allow download to take place over wifi, mobile network and roaming
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI | DownloadManager.Request.NETWORK_MOBILE ).setAllowedOverRoaming(true);
request.setAllowedOverRoaming(false);
//name to show while downloading
request.setTitle(name);
//description to show while downloading
request.setDescription("Downloading " + name);
//show on navigation
request.setVisibleInDownloadsUi(true);
//download path
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS.toString(), "/" + name);
//file open when item on navigation is clicked
request.allowScanningByMediaScanner();
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
long downloadId = downloadManager.enqueue(request);
}
Output
You can learn more here
You can also add boolean or number, condition under Broadcast Receiver to done specific work after the completion of each download task.
As like
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) {
//firstDownload is a boolean variable and assign each downloadManager as true or false
if (firstDownload) {
//First task downlaoded
} else {
//Second task downloaded
}
}
};
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
I am writing an Android application to display pdf files on the device. And I need to use the current versioncode (35498) of the Adobe Reader to display the pdf files.I have with code to display list of files on the screen. Now I need to invoke the Adobe reader (not any other pdf reader installed on the device) onclick of each document. I am not sure how I code that. I am an Android newbie. Any help will be greatly appreciated.
Thanks in Advance,
Navin
I see that you want to open Adobe specifically, but you may want to consider doing it the more Android-like way of opening a general intent and allowing the user to choose how it opens. For your reference, you'd do that with the following code:
private void openFile(File f, String mimeType)
{
Intent viewIntent = new Intent();
viewIntent.setAction(Intent.ACTION_VIEW);
viewIntent.setDataAndType(Uri.fromFile(file), mimeType);
// using the packagemanager to query is faster than trying startActivity
// and catching the activity not found exception, which causes a stack unwind.
List<ResolveInfo> resolved = getPackageManager().queryIntentActivities(viewIntent, 0);
if(resolved != null && resolved.size() > 0)
{
startActivity(viewIntent);
}
else
{
// notify the user they can't open it.
}
}
If you really need to use both Abode Reader specifically, and a specific version, you would need to query for it using PackageManager.getPackageInfo(String, int)
Try the following code
private void loadDocInReader(String doc)
throws ActivityNotFoundException, Exception {
try {
Intent intent = new Intent();
intent.setPackage("com.adobe.reader");
intent.setDataAndType(Uri.parse(doc), "application/pdf");
startActivity(intent);
} catch (ActivityNotFoundException activityNotFoundException) {
activityNotFoundException.printStackTrace();
throw activityNotFoundException;
} catch (Exception otherException) {
otherException.printStackTrace();
throw otherException;
}
}
If you are in "online mode", here is an interesting alternate solution using Google docs.
String myPDFURL = "http://{link of your pdf file}";
String link;
try {
link = "http://docs.google.com/viewer?url="
+ URLEncoder.encode(myPDFURL, "UTF-8")
+ "&embedded=true";
} catch (Exception e) {
e.printStackTrace();
}
Uri uri = Uri.parse(link);
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
This works, setDataAndType method cannot seem to correctly recognize the PDF type if used via URL.
private static Intent newPDFLinkIntent(String url) {
Uri pdfURL = Uri.parse(url);
Intent pdfDownloadIntent = new Intent(Intent.ACTION_VIEW, pdfURL);
pdfDownloadIntent.setType("application/pdf");
pdfDownloadIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
return pdfDownloadIntent ;
}
Unfortunately, the PDF applications I'm using don't anticipate downloading and caching the online content (some will have memory leak error, some will reject link downloading), so you'll eventually end up invoking an intent that downloads the PDF first, before opening the downloaded content via the notification link. I eventually used the solution below:
private static Intent newPDFLinkIntent(String url) {
Intent pdfDownloadIntent = null;
try {
pdfDownloadIntent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME);
pdfDownloadIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
} catch (URISyntaxException e) {
Log.e("PDF Link Tag", e.getMessage());
}
return pdfDownloadIntent;
}