Downloading file with JSF on Android's WebView - android

I have a Java Web Application that uses JSF and PrimeFaces. On a backing bean, I download a local pdf or document file:
public void download() throws FileNotFoundException, IOException {
File file = new File("C:/file.pdf");
FacesContext facesContext = FacesContext.getCurrentInstance();
HttpServletResponse response =
(HttpServletResponse) facesContext.getExternalContext().getResponse();
response.reset();
response.setHeader("Content-Type", "application/pdf");
OutputStream responseOutputStream = response.getOutputStream();
InputStream fileInputStream = new FileInputStream(file);
byte[] bytesBuffer = new byte[2048];
int bytesRead;
while ((bytesRead = fileInputStream.read(bytesBuffer)) > 0)
{
responseOutputStream.write(bytesBuffer, 0, bytesRead);
}
responseOutputStream.flush();
fileInputStream.close();
responseOutputStream.close();
facesContext.responseComplete();
}
This is how I call the download method on the xhtml:
<p:commandButton action="#{mybean.download()}" value="Download File" ajax="false" >
And I created a simple Android application for my Java application just by calling it's url inside a WebView:
mWebView.loadUrl("http://myappurl.com");
Then I listen for downloads on the WebView using the DownloadListener event:
mWebView.setDownloadListener(new DownloadListener() {
public void onDownloadStart(String url, String userAgent,
String contentDisposition, String mimetype,
long contentLength) {
DownloadManager.Request request = new DownloadManager.Request(
Uri.parse(url));
request.allowScanningByMediaScanner();
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, url);
DownloadManager dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
dm.enqueue(request);
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*");
Toast.makeText(getApplicationContext(), "Downloading File",
Toast.LENGTH_LONG).show();
}
});
The problem is, the DownloadListener event for WebView does not get called when I press the download button. It works fine by accessing the application URL from the phone's browser, but not in the android application that I created.
It also works on the android application if I put the pdf inside the application directory and call it using a simple <a href="/file.pdf" download>, but that is not what I want, because the pdf files will be on the server's directory and not in the application.
What I've tried:
Using PrimeFaces p:fileDownload - got the same result, nothing happens when button is pressed;
I looked into google docs online viewer, but I cant use that because my files are local;
I tried PDF.js, but this same download button will be used for all kinds of documents, not only pdf, so I don't really need to view the file, I just need to download and save it on the device.
Please help me. Thanks in advance.
EDIT
I tried Chrome Custom Tabs that replaces the Android WebView, it works great, my JSF download was recognized and the file was downloaded, I didn't have to do anything. The only problem is that there is no way of removing the toolbar from Chrome Custom Tabs, because I want my application to seem like it's a native application and not a webpage.

Related

Reusing code for sharing/saving pdf document

So I have a fragment where I show the user terms and conditions for something and those terms and conditions are in the form of pdf file which is retrieved from the server.
This is the code that retrieves the pdf and gives the pdfView an inputstream to show the data.
class RetrievePDFFromUrl extends AsyncTask<String, Void, InputStream> {
#Override
protected InputStream doInBackground(String... strings) {
InputStream inputStream = null;
try {
URL url = new URL(strings[0]);
HttpURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
if (urlConnection.getResponseCode() == 200) {
inputStream = new BufferedInputStream(urlConnection.getInputStream());
}
} catch (IOException e) {
e.printStackTrace();
return null;
}
return inputStream;
}
#Override
protected void onPostExecute(InputStream inputStream) {
pdfView.fromStream(inputStream).load();
}
}
So far so good.
But now I have to add the functionality to share and save the document.
The problem is that I have to use other pieces of code to accomplish the task.
And since I cant share the document without downloading it, its a little messy.
Heres how I download the document.
private void downloadPDFContent(){
String fileName = getCurrentDocumentName();;
String urlToDownload = !secondDocument ? documentUrl1 : documentUrl2;
File outputFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), fileName);
if (outputFile.exists()) {
return;
}
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(urlToDownload));
request.setTitle(fileName);
request.setMimeType("application/pdf");
request.allowScanningByMediaScanner();
request.setAllowedOverMetered(true);
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName);
DownloadManager downloadManager = (DownloadManager) getContext().getSystemService(Context.DOWNLOAD_SERVICE);
downloadManager.enqueue(request);
}
The problem comes when trying to share the document, Its just wrong to put 200ms delay before trying to share it, because no one knows how slow a connection can be sometimes and it wont work.
private void shareDocument() {
downloadPDFContent();
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
#Override
public void run() {
File outputFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), getCurrentDocumentName());
Uri uri = FileProvider.getUriForFile(getContext(),
getContext().getPackageName() + ".provider", outputFile);
Intent share = new Intent();
share.setAction(Intent.ACTION_SEND);
share.setType("application/pdf");
share.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
share.putExtra(Intent.EXTRA_STREAM, uri);
startActivity(Intent.createChooser(share, "Share document"));
}
}, 200);
}
Does anyone have any better ideas how can I achieve those 3 tasks - using inputstream to load the doc for the user to view and to share/save it also while reusing code and not doing it in different and unstable ways?
**UPDATE: I added a broadcastreceiver to start when the downloading is finished, instead of waiting a fixed amount of time like i do here.
Which is one idea better but still not what i wanted.
You have been using many legacy tools for this task and it is not clear do you have business constraints for it or not.
If your business use case just to download pdf and share it with another android app within your device, I would use Kotlin Flow for the async download task.
When you download your pdf and save it in storage, you could use a callback from Kotlin Flow as a trigger for your sharing intent. You would not need anymore any delay.
Please note, depends on your business use case you could use ContentProvider to give access to your app's files and p2p 3rd party tools for downloading and sharing your files.

Android DownloadManager error Unsuccessful

I'm working with Android downloadmanager. I got this error when passing url to downloadmanager. It's said that Download unsuccessfully, But I tried to use my browser then paste url . It's response file mp3. I don't know why downloadmanager did not recognize file to download.
Here is example URL to test:
http://htstar.design/mp3zing.php?q=320&link=http://mp3.zing.vn/bai-hat/Tired-Alan-Walker-Gavin-James/ZW7FA7WA.html
Update Here is my method download:
private void downloadFile(String url, String name) {
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
request.setTitle(name.replace(ext, ""));
request.setMimeType("audio/MP3");
request.setDescription(name);
request.setDestinationInExternalPublicDir("/Music", name);
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
downloadManager.enqueue(request);
fabOpenDownload.setVisibility(View.VISIBLE);
}

File Not Getting Download Within WebView

I am working with an android application where i need to open a form URL in my webview. I am able to open the form in webview, there is a submit button with form, click on this button will download the file within webview but its not happening. I am able to download the file with normal browser on mobile like google chrome. How can i download the file within my application webview.
i don't know how the you are trying, but you can use this code to download the file inside the webview
mWebView.setDownloadListener(new DownloadListener() {
public void onDownloadStart(String url, String userAgent,
String contentDisposition, String mimetype,
long contentLength) {
DownloadManager.Request request = new DownloadManager.Request(
Uri.parse(url));
request.allowScanningByMediaScanner();
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); //Notify client once download is completed!
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "Name of your downloadble file goes here, example: Mathematics II ");
DownloadManager dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
dm.enqueue(request);
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); //This is important!
intent.addCategory(Intent.CATEGORY_OPENABLE); //CATEGORY.OPENABLE
intent.setType("*/*");//any application,any extension
Toast.makeText(getApplicationContext(), "Downloading File", //To notify the Client that the file is being downloaded
Toast.LENGTH_LONG).show();
}
});
and add this permission to your android manifest file
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
hope it will help.!

Downloading to download folder in Android

I have a webview in my app. One of my pages has a link to a mp3 which I should download directly from my app, so using a downloadlistener like this:
mWebView.setDownloadListener(new DownloadListener() {
public void onDownloadStart(String url, String userAgent,
String contentDisposition, String mimetype,
long contentLength) {
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse(url));
startActivity(i);
}
});
is not good for me, because it launches the default browser before actually donwloading the file.
Is there any way I can manage the download myself, to the OS download folder, so that it appears when user goes to the "Downloads" option in the Android menu?
try to do it with an async task like this
mWebView.setDownloadListener(new DownloadListener() {
public void onDownloadStart(String url, String userAgent,
String contentDisposition, String mimetype,
long contentLength) {
new MyDowloadTask().execute(url);
}
});
Where the doInBackground method of your MyDownload task is something like that:
see http://www.androidsnippets.com/download-an-http-file-to-sdcard-with-progress-notification
You may do that by not using DownloadListener. You just have to override onPageFinished of WebViewClient. Check content type if it is "application/octet-stream" .. Then handle downloading thru InputStream. Create the file, save then open. :)
You can download it yourself to the downloads directory requesting the file yourself and storing it into Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
Here's some non-functional pseudocode that should help you on your way (but will probably ask you to catch Exceptions and give errors that no network activity may take place on the UI Thread; so you have to embed it in a AsyncTask like Matthew Fisher suggested).
public void onDownloadStart(String url, String userAgent,
String contentDisposition, String mimetype, long contentLength)
{
// Define where we want the output file to go
File fileOut = new File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
"Filename.zip"
);
// Request it from the interwebz.
HttpClient android = AndroidHttpClient.newInstance(userAgent);
HttpResponse fileResponse = android.execute(new HttpGet(url));
// Write the response to the file
fileResponse.getEntity().writeTo(new FileOutputStream(fileOut));
}

How to change default download location in android

I have a webview and i want to download files to the sdcard custom folder when user clicking download link from webview.
I'm using the following code for downloading file from webview:
webView.setDownloadListener(new DownloadListener() {
public void onDownloadStart(String url, String userAgent,
String contentDisposition, String mimetype,
long contentLength) {
strurl = url;
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse(url));
startActivity(i);
}
It works properly. But it directly downloads to the /sdcard/download/ folder. But i want it to download to some other folder on the sdcard. How can I accomplish this?

Categories

Resources