I have the problem that on emulator some things in my app doesn't work. The thing is onDownloadListener() method. In real device, it runs perfectly: I can download image and send it by messenger e.g. In the emulator it doesn't work, the method just doesn't run itself. It is terrible, I have tried different emulators and different devices. On each device I tried it was working but none of the emulators can run this code:
public class MyExport implements DownloadListener {
private final WebView webView;
private Context context;
private Activity activity;
public MyExport(Context c, Activity a, WebView webView) {
this.activity = a;
this.context = c;
this.webView = webView;
}
#Override
public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) {
System.out.println("IM IN onDwoanloadStart");
String intentType = "image/png";
String fileName = "img.png";
try {
if(url != null) {
FileOutputStream fos;
fos = context.openFileOutput(fileName, Context.MODE_PRIVATE);
//conversion stuff
fos.write(decodedStr);
fos.getFD().sync();
fos.flush();
fos.close();
Intent sendIntent = new Intent();
sendIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION);
sendIntent.setAction(Intent.ACTION_SEND);
File filePath = new File(String.valueOf(context.getFilesDir()));
File newFile = new File(filePath, fileName);
sendIntent.putExtra(Intent.EXTRA_STREAM, FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".FileProvider", newFile));
sendIntent.setType(intentType);
context.startActivity(sendIntent);
}
} catch (IOException e) {
e.printStackTrace();
}
}
#JavascriptInterface
public void runExport(){
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
webView.loadUrl("javascript: obj.exportImage()");
}
});
}
And this is how I add it to the webView:
MyExport export = new MyExport(activity.getBaseContext(), activity, this.webView);
this.webView.setDownloadListener(export);
this.webView.addJavascriptInterface(export, "jsint");
When I click on the button in WebView the exportImage() from Javascript is called but the onDownloadListener is not. This is happening ONLY on emulators!
Related
Typical Scenario
In order to upload a file using WebView, it's typically needed to override WebChromeClient, and start a file chooser Activity for result:
...
webView.setWebChromeClient(new WebChromeClient() {
#Override
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback,
FileChooserParams fileChooserParams) {
mFilePathCallback = filePathCallback;
Intent intent = new Intent(MainActivity.this, FilePickerActivity.class);
startActivityForResult(intent, 1);
return true;
}
});
...
Then, once file is selected (for simplicity, only a single file can be selected at a time), onActivityResult() is called with a file uri stored in a data object. So, the uri is retrieved and handed over to filePathCallback and the file gets uploaded:
...
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
if (requestCode == 1) {
mFilePathCallback.onReceiveValue(new Uri[] {data.getData()});
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
...
Basically, filePathCallback requires a uri to a file so that to upload it.
The problem
What if I have only an InputStream that contains the data I need to upload rather than a file with a URI? And I cannot save that data to a file so that to generate a URI (for security reasons). Is there a way to upload the data as a file in such case? In particular, can I convert an InputStream to a content URI and then upload it?
Approach 1
This approach works fine, if uri is generated using Uri.fromFile() as below:
...
Uri uri = Uri.fromFile(file);
...
Approach 2
If I implement my own ContentProvider and override openFile there in such a way, that it uses ParcelFileDescriptor.open() to create a ParcelFileDescriptor, then uploading a file based on a uri provided by getContentUri(...) is working without problems:
FileUploadProvider.java
public class FileUploadProvider extends ContentProvider {
public static Uri getContentUri(String name) {
return new Uri.Builder()
.scheme("content")
.authority(PROVIDER_AUTHORITY)
.appendEncodedPath(name)
.appendQueryParameter(OpenableColumns.DISPLAY_NAME, name)
.build();
}
#Nullable
#Override
public ParcelFileDescriptor openFile(#NonNull Uri uri, #NonNull String mode) throws FileNotFoundException {
List<String> segments = uri.getPathSegments();
File file = new File(getContext().getApplicationContext().getCacheDir(),
TextUtils.join(File.separator, segments));
return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
}
...
}
Approach 3
However, if I create a ParcelFileDescriptor with help of ParcelFileDescriptor.createPipe(), then file upload never finishes, so it basically doesn't work:
...
public ParcelFileDescriptor openFile(#NonNull Uri uri, #NonNull String mode) throws FileNotFoundException {
List<String> segments = uri.getPathSegments();
File file = new File(getContext().getApplicationContext().getCacheDir(),
TextUtils.join(File.separator, segments));
InputStream inputStream = new FileInputStream(file);
ParcelFileDescriptor[] pipe;
try {
pipe = ParcelFileDescriptor.createPipe();
} catch (IOException e) {
throw new RuntimeException(e);
}
ParcelFileDescriptor readPart = pipe[0];
ParcelFileDescriptor writePart = pipe[1];
try {
IOUtils.copy(inputStream, new ParcelFileDescriptor.AutoCloseOutputStream(writePart));
} catch (IOException e) {
throw new RuntimeException(e);
}
return readPart;
}
...
Approach 4
To make matters worse, if I create a ParcelFileDescriptor with help of MemoryFile, then file upload never finishes as well:
...
public ParcelFileDescriptor openFile(#NonNull Uri uri, #NonNull String mode) throws FileNotFoundException {
List<String> segments = uri.getPathSegments();
File file = new File(getContext().getApplicationContext().getCacheDir(),
TextUtils.join(File.separator, segments));
try {
MemoryFile memoryFile = new MemoryFile(file.getName(), (int) file.length());
byte[] fileBytes = Files.readAllBytes(file.toPath());
memoryFile.writeBytes(fileBytes, 0, 0, (int) file.length());
Method method = memoryFile.getClass().getDeclaredMethod("getFileDescriptor");
FileDescriptor fileDescriptor = (FileDescriptor) method.invoke(memoryFile);
Constructor<ParcelFileDescriptor> constructor = ParcelFileDescriptor.class.getConstructor(FileDescriptor.class);
ParcelFileDescriptor parcelFileDescriptor = constructor.newInstance(fileDescriptor);
return parcelFileDescriptor;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
...
Why is file upload not working for Approach 3 and Approach 4?
Example
I created a sample app to showcase my issue here.
Below are steps to follow to reproduce it. First log in to your gmail account and click "create new message".
Solution
My colleagues have found a solution to this with help of StorageManager - please read more about the component here.
First, create a callback that handles file system requests from ProxyFileDescriptor in FileUploadProvider:
private static class CustomProxyFileDescriptorCallback extends ProxyFileDescriptorCallback {
private ByteArrayInputStream inputStream;
private long length;
public CustomProxyFileDescriptorCallback(File file) {
try {
byte[] fileBytes = Files.readAllBytes(file.toPath());
length = fileBytes.length;
inputStream = new ByteArrayInputStream(fileBytes);
} catch (IOException e) {
// do nothing here
}
}
#Override
public long onGetSize() {
return length;
}
#Override
public int onRead(long offset, int size, byte[] out) {
inputStream.skip(offset);
return inputStream.read(out,0, size);
}
#Override
public void onRelease() {
try {
inputStream.close();
} catch (IOException e) {
//ignore this for now
}
inputStream = null;
}
}
Then, create a file descriptor using StorageManager that will read the InputStream with help of the callback above.
...
StorageManager storageManager = (StorageManager) getContext().getSystemService(Context.STORAGE_SERVICE);
ParcelFileDescriptor descriptor;
try {
descriptor = storageManager.openProxyFileDescriptor(
ParcelFileDescriptor.MODE_READ_ONLY,
new CustomProxyFileDescriptorCallback(file),
new Handler(Looper.getMainLooper()));
} catch (IOException e) {
throw new RuntimeException(e);
}
return descriptor;
...
Please find the full code on github here.
Limitation
This approach is working only for Android API higher than 25.
I have to share an image in my app.
Glide.with(PhotoFullScreenActivity.this)
.asBitmap()
.load(getBestDownscaledAlternative(mPhotoList.get(mCurrentPosition)))
.into(new SimpleTarget<Bitmap>() {
#Override
public void onResourceReady(Bitmap resource, Transition<? super Bitmap> transition) {
startShareImageTask(resource);
}
#Override
public void onLoadFailed(#Nullable Drawable errorDrawable) {
super.onLoadFailed(errorDrawable);
Log.e("Check","error");
}
});
I'm using the above snippet to convert the URL into a bitmap and after the resource is ready I call the startShareImageTask to create a file.
The startShareImageTask looks like this:
private void startShareImageTask(Bitmap resource){
new AsyncTask<Bitmap, Void, Uri>(){
#Override
protected void onPreExecute() {
super.onPreExecute();
mShareLoadingPB.setVisibility(View.VISIBLE);
Log.d("ShareImageTask", "onPreExecute: " + System.currentTimeMillis());
}
#Override
protected Uri doInBackground(Bitmap... bitmaps) {
Uri bmpUri = null;
try {
// Use methods on Context to access package-specific directories on external storage.
// This way, you don't need to request external read/write permission.
File file = new File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), "share_image_" + System.currentTimeMillis() + ".png");
FileOutputStream out = new FileOutputStream(file);
resource.compress(Bitmap.CompressFormat.JPEG, 90, out);
out.close();
// wrap File object into a content provider. NOTE: authority here should match authority in manifest declaration
bmpUri = ImageFileProvider.getUriForFile(PhotoFullScreenActivity.this, getApplicationContext().getPackageName() + ".fileprovider", file); // use this version for API >= 24
} catch (IOException e) {
e.printStackTrace();
mShareLoadingPB.setVisibility(View.GONE);
}
return bmpUri;
}
#Override
protected void onPostExecute(Uri uri) {
super.onPostExecute(uri);
mShareLoadingPB.setVisibility(View.GONE);
mShareIntent = new Intent();
mShareIntent.setAction(Intent.ACTION_SEND);
mShareIntent.putExtra(Intent.EXTRA_STREAM, uri);
mShareIntent.setType("image/*");
startActivity(Intent.createChooser(mShareIntent, "Share image"));
}
}.execute();
}
All works out great but my app needs to record something in a background task and when it does, my doInBackground method is not called until I finish the recording...I want to share the image while I'm recording something.
What can I do when my background thread is busy with another task?
Is there any workaround to this?
I was able to make this work by changing the AsyncTask to RxJava. I'll leave the code difference here in case anyone bumps into this issue.
mShareLoadingPB.setVisibility(View.VISIBLE);
Log.d("ShareImageTask", "onPreExecute: " + System.currentTimeMillis());
Observable.fromCallable(() -> {
Uri bmpUri = null;
try {
// Use methods on Context to access package-specific directories on external storage.
// This way, you don't need to request external read/write permission.
File file = new File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), "share_image_" + System.currentTimeMillis() + ".png");
FileOutputStream out = new FileOutputStream(file);
resource.compress(Bitmap.CompressFormat.JPEG, 90, out);
out.close();
// wrap File object into a content provider. NOTE: authority here should match authority in manifest declaration
bmpUri = ImageFileProvider.getUriForFile(PhotoFullScreenActivity.this, getApplicationContext().getPackageName() + ".fileprovider", file); // use this version for API >= 24
} catch (IOException e) {
e.printStackTrace();
mShareLoadingPB.setVisibility(View.GONE);
}
return bmpUri;
})
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new DefaultObserver<Uri>() {
#Override
public void onNext(Uri uri) {
mShareLoadingPB.setVisibility(View.GONE);
mShareIntent = new Intent();
mShareIntent.setAction(Intent.ACTION_SEND);
mShareIntent.putExtra(Intent.EXTRA_STREAM, uri);
mShareIntent.setType("image/*");
startActivity(Intent.createChooser(mShareIntent, "Share image"));
}
#Override
public void onError(Throwable e) {
Log.e("Error","Error");
}
#Override
public void onComplete() {
}
});
I have gone through many articles. But somehow i could not achieve what i wanted to achieve. I have a http image link in my app and i want to share this as an image attachment from Twitter application. I have tried following. But it seems not to be working as Twitter expects it to be a local url.
TweetComposer.Builder builder = new TweetComposer.Builder(context)
.text(text)
.image(Uri.parse("https://dummyimage.com/300/09f/fff.png"));
builder.show();
So now that i know it requires a local path, i tried to download the image to phone using Picasso as below.
Picasso.get().load(CONSTANT.IAMGE_URI + list.get(position).getEvent_model().getPhoto_link())
.placeholder(R.drawable.placeholder)
.error(R.drawable.placeholder)
.into(getTarget(list.get(position).getEvent_model().getPhoto_link()));
File myImageFile = new File(getFileFullPath(list.get(position).getEvent_model().getPhoto_link()));
Picasso.get().load(myImageFile).into(holder.iv_album_image);
And this is code to get the target.
private static Target getTarget(final String fileName) {
Target target = new Target() {
//This method in target is called by picasso when image downloaded
#Override
public void onBitmapLoaded(final Bitmap bitmap, Picasso.LoadedFrom from) {
new Thread(new Runnable() {
#Override
public void run() {
try {
File file = new File(getFilename(fileName));
if (file.exists()) {
file.delete();
}
file.createNewFile();
FileOutputStream fileoutputstream = new FileOutputStream(file);
ByteArrayOutputStream bytearrayoutputstream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 60, bytearrayoutputstream);
fileoutputstream.write(bytearrayoutputstream.toByteArray());
fileoutputstream.close();
} catch (IOException e) {
Log.e("IOException", e.getLocalizedMessage());
}
}
}).start();
}
#Override
public void onBitmapFailed(Exception e, Drawable errorDrawable) {
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
};
return target;
}
public static String getFilename(String fileName) {
File file = new File(Environment.getExternalStorageDirectory().getPath(), "Images");
if (!file.exists()) {
file.mkdirs();
}
return (file.getAbsolutePath() + "/" + fileName);
}
In this case photo is not loading in to imageview and also not being downloaded to local.
You need to download the image to your phone, and use a local path.
https://docs.fabric.io/javadocs/tweet-composer/2.0.0/com/twitter/sdk/android/tweetcomposer/TweetComposer.Builder.html#image(android.net.Uri)
Ultimately for image:
The Uri should be a file Uri to a local file
Uri.fromFile(someExternalStorageFile)
Can you change your getFilename to match as such:
public static String getFilename(String fileName, Context context) {
int code = context.getPackageManager().checkPermission(
android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
context.getPackageName());
if (code == PackageManager.PERMISSION_GRANTED) {
File file = new File(Environment.getExternalStorageDirectory().getPath(), "Images");
if (!file.exists()) {
file.mkdirs();
}
return (file.getAbsolutePath() + "/" + fileName);
}
return "";
}
And set a breakpoint at each return. My assumption is you're returning "";
I have uploaded a Pdf file to firebase storage, after uploading the pdf file to firebase storage, I am getting the download url. Now I want to open the pdf file from this download url in my application.
Below is the url I am getting after uploading the pdf file to firebase storage.
https://firebasestorage.googleapis.com/v0/b/realtime-chat-46f4c.appspot.com/o/documents%2Fbf307aa5-79ae-4532-8128-ee394537b357.pdf?alt=media&token=2d0c5329-4717-4adc-9418-6614913e5bfa
Now I want to open an intent to view this pdf file, I've used the below code for this :
String url = "https://firebasestorage.googleapis.com/v0/b/realtime-chat-46f4c.appspot.com/o/documents%2Fbf307aa5-79ae-4532-8128-ee394537b357.pdf?alt=media&token=2d0c5329-4717-4adc-9418-6614913e5bfa";
Intent intent = new Intent(android.content.Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse(url), "application/pdf");
startActivity(Intent.createChooser(intent, "Choose an Application:"));
My phone is having applications which can open this pdf file, still it says there are no applications installed to view this file.
If I convert this url in File and use the below code, then the chooser of applications get opened but it gives error that the file can't be opened.
Intent intent = new Intent(android.content.Intent.ACTION_VIEW);
File file = new File(name);
intent.setDataAndType(Uri.fromFile(file), "aplication/pdf");
I've seen many answers that says first download the file and then open it, but I don't want to download the file, I just want to view it.
Please help me if anyone have any idea about this.
Thanks a lot in advanced.
You should use the Intent Chooser
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse(url), "application/pdf");
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
Intent newIntent = Intent.createChooser(intent, "Open File");
try {
startActivity(newIntent);
} catch (ActivityNotFoundException e) {
// Instruct the user to install a PDF reader here, or something
}
Your phone is not detecting the PDF because the URL you are using is a String object and not a PDF object. Technically, it should never open from the phone as PDF unless you download the PDF. PDF viewers on a phone only get activated once the Android OS tells them that it has a valid PDF file. Please take a look at source code of any of the PDF libraries to understand this better -> https://android-arsenal.com/tag/72?sort=created
However, to answer your problem, you should try opening your URL as a URL. It will activate the browser on your phone which in turn will detect that it needs a PDF reader and will activate the appropriate reader.
Something like
String url = "https://firebasestorage.googleapis.com/v0/b/realtime-chat-46f4c.appspot.com/o/documents%2Fbf307aa5-79ae-4532-8128-ee394537b357.pdf?alt=media&token=2d0c5329-4717-4adc-9418-6614913e5bfa";
public void openWebPage(String url) {
Uri webpage = Uri.parse(url);
Intent intent = new Intent(Intent.ACTION_VIEW, webpage);
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
}
However, I am thinking that you want to just validate if the file got uploaded successfully. And if there is a local copy on the phone then just open the local copy instead of downloading another copy. If that is the case, then I recommend using file metadata to achieve that. Something like:
// Create file metadata including the content type
StorageMetadata metadata = new StorageMetadata.Builder()
.setCustomMetadata("myPDFfile", "localPDFfileName")
.build();
// Upload the file and metadata
uploadTask = storageRef.child("pdf/localPDFfileName.pdf").putFile(file, metadata);
And on your success listener, retrieve the file metadata. If it is downloaded and looks complete, then open the PDF from your local phone storage. If not, then try downloading from the downloadURL as I mention at the start of the post. That should cover the validations you are trying to do.
Do elaborate more if I did not understand your problem, correctly. I will pick it up and amend my reply accordingly.
Please add following files/method to your project
PdfDownloader.java
PDFDownloaderAsyncTask.java
and then using following method handleViewPdf to view pdf:
private void handleViewPdf () {
File folder = getAppDirectory(context);
String fileName = "test.pdf";// getPdfFileName(pdfUrl);
File pdfFile = new File(folder, fileName);
if (pdfFile.exists () && pdfFile.length () > 0) {
openPDFFile (context, Uri.fromFile(pdfFile));
}
else {
if (pdfFile.length () == 0) {
pdfFile.delete ();
}
try {
pdfFile.createNewFile ();
}
catch (IOException e) {
e.printStackTrace ();
}
ArrayList<String> fileNameAndURL = new ArrayList<> ();
fileNameAndURL.add (pdfFile.toString ());
fileNameAndURL.add (pdfUrl);
fileNameAndURL.add (fileName);
if (pdfDownloaderAsyncTask == null) {
pdfDownloaderAsyncTask = new PDFDownloaderAsyncTask (context, pdfFile);
}
if (hasInternetConnection (context)) {
if (!pdfDownloaderAsyncTask.isDownloadingPdf ()) {
pdfDownloaderAsyncTask = new PDFDownloaderAsyncTask (context, pdfFile);
pdfDownloaderAsyncTask.execute (fileNameAndURL);
}
}
else {
//show error
}
}
}
PDFDownloaderAsyncTask.java
import java.io.File;
import java.util.ArrayList;
import android.content.Context;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Handler;
import android.text.TextUtils;
import android.widget.Toast;
public class PDFDownloaderAsyncTask extends AsyncTask<ArrayList<String>, Void, String> {
private boolean isDownloadingPdf = false;
private File file;
private Context context;
public PDFDownloaderAsyncTask (Context context, File file) {
this.file = file;
this.context = context;
this.isDownloadingPdf = false;
}
public boolean isDownloadingPdf () {
return this.isDownloadingPdf;
}
#Override
protected void onPreExecute () {
super.onPreExecute ();
//show loader etc
}
#Override
protected String doInBackground (ArrayList<String>... params) {
isDownloadingPdf = true;
File file = new File (params[0].get (0));
String fileStatus = PdfDownloader.downloadFile (params[0].get (1), file);
return fileStatus;
}
#Override
protected void onPostExecute (String result) {
super.onPostExecute (result);
Loader.hideLoader ();
if (!TextUtils.isEmpty (result) && result.equalsIgnoreCase (context.getString (R.string.txt_success))) {
showPdf ();
}
else {
isDownloadingPdf = false;
Toast.makeText (context, context.getString (R.string.error_could_not_download_pdf), Toast.LENGTH_LONG).show ();
file.delete ();
}
}
#Override
protected void onCancelled () {
isDownloadingPdf = false;
super.onCancelled ();
//Loader.hideLoader ();
}
#Override
protected void onCancelled (String s) {
isDownloadingPdf = false;
super.onCancelled (s);
//Loader.hideLoader ();
}
private void showPdf () {
new Handler ().postDelayed (new Runnable () {
#Override
public void run () {
isDownloadingPdf = false;
openPDFFile (context, Uri.fromFile (file));
}
}, 1000);
}
}
PdfDownloader.java
package com.pdf;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
public class PdfDownloader {
private static final int MEGABYTE = 1024 * 1024;
public static String downloadFile (String fileUrl, File directory) {
String downloadStatus;
try {
URL url = new URL (fileUrl);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection ();
urlConnection.connect ();
InputStream inputStream = urlConnection.getInputStream ();
FileOutputStream fileOutputStream = new FileOutputStream (directory);
int totalSize = urlConnection.getContentLength ();
Log.d ("PDF", "Total size: " + totalSize);
byte[] buffer = new byte[MEGABYTE];
int bufferLength = 0;
while ((bufferLength = inputStream.read (buffer)) > 0) {
fileOutputStream.write (buffer, 0, bufferLength);
}
downloadStatus = "success";
fileOutputStream.close ();
}
catch (FileNotFoundException e) {
downloadStatus = "FileNotFoundException";
e.printStackTrace ();
}
catch (MalformedURLException e) {
downloadStatus = "MalformedURLException";
e.printStackTrace ();
}
catch (IOException e) {
downloadStatus = "IOException";
e.printStackTrace ();
}
Log.d ("PDF", "Download Status: " + downloadStatus);
return downloadStatus;
}
public static void openPDFFile (Context context, Uri path) {
Intent intent = new Intent (Intent.ACTION_VIEW);
intent.setDataAndType (path, "application/pdf");
intent.setFlags (Intent.FLAG_ACTIVITY_CLEAR_TOP);
try {
context.startActivity (intent);
}
catch (ActivityNotFoundException e) {
Toast.makeText (context, context.getString (R.string.txt_no_pdf_available), Toast.LENGTH_SHORT).show ();
}
Loader.hideLoader ();
}
public static File getAppDirectory (Context context) {
String extStorageDirectory = Environment.getExternalStorageDirectory ().toString ();
File folder = new File (extStorageDirectory, context.getString (R.string.app_folder_name).trim ());
if (!folder.exists ()) {
boolean success = folder.mkdirs();
Log.d ("Directory", "mkdirs():" + success);
}
return folder;
}
}
if you want to open the saved pdf file in your application rather than creating a intent to open in other application, you can use the following library to create the PdfView in Xml file. AndroidPdfViewer (this library also provides the zoom in-out facility)
After that as mentioned in the Firebase Document use the saved path reference of the file location in firebase Storage to fetch the file in Bytes and add it to your PdfView as
For example your file path will be like : "/folder1/yourfile.pdf"
pdfView = (PDFView) findViewById(R.id.pdfView);
mFirebaseStorage=FirebaseStorage.getInstance().getReference();
final long ONE_MEGABYTE = 1024 * 1024;
mFirebaseStorage.child("YourSavedFilePathRef").getBytes(ONE_MEGABYTE).addOnSuccessListener(new OnSuccessListener<byte[]>() {
#Override
public void onSuccess(byte[] bytes) {
pdfView.fromBytes(bytes).load();
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(MainActivity.this,"download unsuccessful",Toast.LENGTH_LONG).show();
}
});
Simple code :)
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Uri fileuri = Uri.parse("URL of file on storage") ;
intent.setDataAndType(fileuri,"application/pdf");
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
Intent in = Intent.createChooser(intent,"open file");
in.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(in);
Hope this works :)
try to encode your firebase database file url. it work with me
Use Webview for view pdf file-
WebView webview = (WebView) findViewById(R.id.webview);
webview.getSettings().setJavaScriptEnabled(true);
String pdf = "https://firebasestorage.googleapis.com/v0/b/realtime-chat-46f4c.appspot.com/o/documents%2Fbf307aa5-79ae-4532-8128-ee394537b357.pdf?alt=media&token=2d0c5329-4717-4adc-9418-6614913e5bfa";
webview.loadUrl("http://drive.google.com/viewerng/viewer?embedded=true&url=" + pdf);
I am downloading a file from ftp server. downloading code worked fine, however after download code screen doesn't show anything ,it gets black. Also download function is not returning true value, even the file is being saved in the specified directory.
public class FTPClass{
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_file_player);
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
Intent intent = getIntent();
dirname = intent.getStringExtra("currentDirName");
MyFTPClient mftp = new MyFTPClient();
createPath = mftp.getAppRootPath().concat("/"+ dirname);
mftp.setCurrentDir(createPath);
System.out.println(mftp.ftpChangeDirectory(createPath));
FTPFile[] farr = mftp.ftpListAllFiles();
System.out.println(farr.length);
for(int i = 0; i<farr.length;i++){
System.out.println("SRC: "+createPath+"/"+farr[i].getName());
String src = createPath+"/"+farr[i].getName();
System.out.println("DEST: "+"/data/data/com.example.ftpplayer" + "/app_"+dirname);
String dest ="/data/data/com.example.ftpplayer" + "/app_"+dirname+"/"+farr[i].getName();
System.out.println(mftp.downloadFile(src,dest));
}
}
}
public class CallingIntent extends Activity{
System.out.println("In item click ");
Intent intent = new Intent(getApplicationContext(), FTPClass.class);
String dir = ((TextView) view).getText().toString();
intent.putExtra("currentDirName", dir);
startActivity(intent);
}
public class MyFTPClient{
public boolean downloadFile(String srcPath , String destPath){
try {
FileOutputStream fos = new FileOutputStream(destPath);
System.out.println(mftp.retrieveFile(srcPath, fos)); // retrieve file doesn't return true
fos.flush();
fos.close();
return true;
} catch (FileNotFoundException e) {
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}
return false;
}
}
You need to run your code on the background thread, try using an asyncTask.