Open PDF in Android App - android

First I would like to say that I have tried several solutions, methods, suggestions and referred to several links on here to open a PDF. You can call me slow, but I have at least tried. I would like to open a PDF in my Android Application. I am on a Nexus 10 tablet. I cannot use a web view. I want to open this pdf via my OnClickListener in one of my fragments. I think my biggest problem is I am unsure where to save my PDF. I have tried res and assets folders. Many example use /sdcard/ - is that just saving it on my device? If so where / how to get path? I have saved a .pdf file in adobe reader on my tablet can I access that path? I am using API min 16 target API 19.
I have tried many variations of this
public void onClick(View v)
{
switch(v.getId())
{
case R.id.bizbro3:
File pdfFile = new File( // I don't know what to put here / where to save pdf. Have tried /sdcard/ , getresrouces, absolutepath, ect.);
if(pdfFile.exists())
{
Uri path = Uri.fromFile(pdfFile);
Intent pdfIntent = new Intent(Intent.ACTION_VIEW);
pdfIntent.setDataAndType(path, "application/pdf");
pdfIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
try
{
startActivity(pdfIntent);
}
catch(ActivityNotFoundException e)
{
Toast.makeText(v.getContext(), "Something went wrong. Returning to the Main Menu",
Toast.LENGTH_LONG).show();
fragment = new FragmentThree();
fragment.setArguments(args);
FragmentManager frgManager = getFragmentManager();
frgManager.beginTransaction().replace(R.id.content_frame, fragment)
.commit();
}
}
}

first declare permissions in manifest
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
then try this
String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/yourfolder";
File file = new File(path,"file.pdf");

The reason your code fails is that the extracted APK folders, assets/ included, are application-private,
and cannot be viewed by an external app. The fact that you have "invited" such an external app to view your data
by issuing an intent, makes no difference.
You will need to copy the file to a non-private location (typically: sdcard) and
things will start working:
void coptAssetToSdcard() {
InputStream input = getAssets().open("myFile.pdf");
File sdCard = Environment.getExternalStorageDirectory();
File dir = new File (sdCard.getAbsolutePath() + "/myDir/");
dir.mkdirs();
File outFile = new File(dir, "destFile.pdf");
OutputStream out = new FileOutputStream(outFile);
byte[] buffer = new byte[10*1024];
int nBytes;
while ((nBytes = input.read(buffer)) != -1) {
out.write(buffer, 0, nBytes);
}
out.flush();
out.close();
input.close();
}
Remember to place this func in an AsyncTask or something.
I also see that your code has a fall through (catch ActivityNotFoundException) for
the case device has no pdf viewer, which is the correct thing to do.

Related

Create a folder if it doesn't exist, then create a file and share it

I have an issue with my sharing option.
The option was perfectly well working (and I have saved it before trying some modifications) but I have tried to modify something and I cannot reach my goal).
The purpose is : click on the option in a menu, click on share, if the folder "test folder" doesn't exists in the "MUSIC" folder, create it, if it already exists, copie the sound, put it in the folder previously created and then use it as an extra in a SEND intent.
case R.id.share:
if (isStoragePermissionGranted()) {
File outputFile = new File("");
InputStream is = getResources().openRawResource(((Sound) adapter.getItem(index)).getMpsound());
try {
File outputDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC), "Test folder");
outputFile = new File(outputDir, getResources().getResourceEntryName(((Sound) adapter.getItem(index)).getMpsound()) + ".mp3");
if (outputDir.exists()) {
byte[] buffer = new byte[is.available()];
is.read(buffer);
OutputStream os = new FileOutputStream(outputFile);
os.write(buffer);
Intent share = new Intent(Intent.ACTION_SEND);
share.setType("audio/*");
share.putExtra(Intent.EXTRA_STREAM, FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".provider", outputFile));
share.putExtra(Intent.EXTRA_TEXT, "\"" + ((Sound) adapter.getItem(index)).getTitle_show() + "\" shared by my app");
startActivity(Intent.createChooser(share, "Share Sound File"));
} else {
outputDir.createNewFile(); //plus add code as below to share the sound after creating the folder
}
} catch (IOException e) {
e.printStackTrace();
}
}
I'm not able to create the folder and if I create it manually, the code is working well because the mp3 appears in the folder, and right after I have an error that says :
java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/0/Music/my app/sound_test.mp3
So... the app is able to access the folder to create the sound but for an unknown reason, I have this issue.
What did I do wrong ?
So, for the ones who are coming in few days, months, years with the same problem :
As CommonsWare said it, the issue in accessing the folder was from the FileProvider. After configure it properly with the good path, I had no more issue.
For the part concerning the creation of a new folder, .createNewFile() doesn't seems to be the right way. It's necessarry to use .mkdir()
And to end it, the part concerning the delete of the files in the folder, you will have your answer there :
File dir = new File(Environment.getExternalStorageDirectory()+"Dir_name_here");
if (dir.isDirectory())
{
String[] children = dir.list();
for (int i = 0; i < children.length; i++)
{
new File(dir, children[i]).delete();
}
}
Source : How to delete all files in a directory java android app? Current code is deleting the that folder

Open image from external public directory through intent

Recently I am developing a file sharing application and I created a GridView, where the downloaded files are being shown. From this View, I would like to be able to open the default application through an intent, to open the whole file. Currently I am testing the app with only image files. All the files are downloaded to the external public directory this way:
File externalFolder = new File(Environment.getExternalStorageDirectory(), "My application");
if(!externalFolder.exists()){
externalFolder.mkdir();
}
...
File folder = new File(externalFolder, "Images");
if(!folder.exists()){
folder.mkdir();
}
...
String filename = folder.getAbsolutePath() + "/" + fileToDownload.getName() + "." + fileToDownload.getExtension();
FileOutputStream fos = new FileOutputStream(filename);
When the file is downloaded, I scan it with MediaScannerConnection.scanFile. The scan is successful, the picture is visible among other files in Photos app.
After the file is downloaded, I am able to extract a thumbnail in the adapter of the GridView, so I surely have a valid path to the file.
And where the fun begins: I tried to set an onClickListener to the GridView items in the adapter to be able to open the picture in Photos app this way:
listItem.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_VIEW);
if(new File(current.getPath()).exists()){
Log.e("path", "valid");
}else{
Log.e("path", "invalid");
}
Log.e("path", Uri.parse("content://"+current.getPath()).toString());
intent.setDataAndType(Uri.parse("content://"+current.getPath()), "image/*");
getContext().startActivity(intent);
}
});
The Intent is created successfully, I get the following in the log:
E/path: valid
E/path: content:///storage/emulated/0/My application/Images/best_picture_ever.jpeg
I have the option to choose among apps to open. When I select the app, it fails to open the image, like when it does not exist. All the 5 applications.
I tested this on my device with Oreo, and on two emulated devices with Nougat and Lollipop, all of them behaves the same way.
What am I doing wrong?
What am I doing wrong?
You are not creating a valid Uri. You cannot put content:// in front of arbitrary things and have a useful Uri, any more than you can put https:// in front of arbitrary things and have a usable URL.
Use FileProvider to serve up this file.

Android: Create and Download PDF files to Downloads directory

In my Android App, in one of the activity, there is a "PDF Download" button. When this button is clicked, I create a PDF and then download it to the "Downloads" directory. Following is my code which runs on the click event of the button:
public void createAndDownloadPDF()
{
try
{
PdfDocument document = new PdfDocument();
View content = this.findViewById(android.R.id.content);
PdfDocument.PageInfo pageInfo = new PdfDocument.PageInfo.Builder(content.getWidth(),
content.getHeight() - 20, 1).create();
PdfDocument.Page page = document.startPage(pageInfo);
content.draw(page.getCanvas());
document.finishPage(page);
SimpleDateFormat sdf = new SimpleDateFormat("ddMMyyyyhhmmss");
String pdfName = "pdfdemo"
+ sdf.format(Calendar.getInstance().getTime()) + ".pdf";
File outputFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), pdfName);
try
{
outputFile.createNewFile();
OutputStream out = new FileOutputStream(outputFile);
document.writeTo(out);
document.close();
out.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
catch(Exception e)
{
Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG).show();
}
}
Please note that I added the required WRITE permission to the MANIFEST file and also asking for the permission at runtime. So, there is no issue of permissions.
When I debug the code, I notice that "outputFile" variable holds this path:
/storage/emulated/o/Download/pdfdemo07052017121233.pdf
My users will never find above path in their mobile. So, they will have no clue where their PDF got saved. I want that when users click on "Downloads" icon on their mobile, they should see the PDF file they downloaded from the app.
So, I think if I can sort out the following line:
File outputFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), pdfName);
my work will be done. What should be the path I use so that my PDF files get saved / downloaded in the "Downloads" directory? I researched over the internet, but did not find any concrete solution.
Try this:
File outDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString());
If this doesn't work, evaluate the chance of having your PDF file previously generated and saved into a folder inside your Assets folder. If this can be the case, after the above line you insert this:
copyAssets("XXX",outDir.toString());
Where "XXX" is the name of the folder inside your Assets folder which will contain the PDF file. This will copy the contents of XXX to DOWNLOADS/XXX on your device.

Creating a file unsing openFileOutput() which is visible to other applications

I'm using the openFileOutput() to create a new txt file. I need the file to be visible from other applications (as well as from a PC when the Android device is connected via USB. Ive tried using .setReadable(true); but this does not seem valid. Please advise how I should declare the file is visible / public.
try {
textIncoming.append("saving");
final String STORETEXT = "test.txt";
OutputStreamWriter out = new OutputStreamWriter(openFileOutput(STORETEXT, 0));
out.setReadable(true);
out.write("testing");
out.close();
}
catch (Throwable t) {
textIncoming.append("not saving");
}
Ive changed my program to use getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS), but for some reason it returns a path /storage/emulated/0/Documents, and I cant even find this folder on the device. Ive looked at the files on the android device using ES file explorer but cant find the folder or file I'm trying to create (Plus I want these in an documents folder on the SD card, so it seems that its not giving me a pointer to the SD card at all, and not creating the folder, and not creating the file. Following is my updated code, please advise
String root = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS).toString();
File myDir = new File(root + "/Saved_Receipts");
myDir.mkdirs();
Random generator = new Random();
int n = 10000;
n = generator.nextInt(n);
String fname = "DRcpt-" + n + ".xml";
textIncoming.append(root);
File file = new File(myDir, fname);
if (file.exists()) {
file.delete();
}
try {
FileOutputStream out = new FileOutputStream(file);
out.flush();
out.close();
}
catch (Exception e) {
e.printStackTrace();
}
Save it to sdcard if you want anyone to be able to read it.
This android documentation should tell you what you need to do.
https://developer.android.com/guide/topics/data/data-storage.html#filesExternal
openFileOutput() documentation says:
Open a private file
So the file that it creates won't be visible to other apps, unless you copy it to another directory that is visible. In that case, you have to save your data in what's called "external storage" which is shared with other apps. Use the code at this link.

Error while reading pdf using MODE_WORLD_READABLE?

I have made an app which downloads the pdf from the server and stores it in
/data/data/<package_name>files
using this code:
FileOutputStream fos = openFileOutput(pdfFileName, Context.MODE_WORLD_READABLE);
fos.write(pdfAsBytes);
fos.close();
But when reading these file from the pdf reader app which I already have on the device is sometimes showing black screen and sometimes displays the file with annoying fonts. The code I am using is:
File file = new File("/data/data/<package_Name>/files/pdffile");
Uri path = Uri.fromFile(file);
Intent pdfIntent = new Intent(Intent.ACTION_VIEW);
pdfIntent.setDataAndType(path, "application/pdf");
pdfIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
try
{
startActivity(pdfIntent);
}
catch(Exception e)
{
Log.e("Activity Not Found Exception",e.toString());
}
I have tried the same code with the same files at other path(in sdcard) they work fine.
Please help me and tell me what should have gone wrong.
What should be a possible way to correct it?
You should use method
android.content.Context.getFilesDir().
Returns the absolute path to the directory on the filesystem where files created with openFileOutput(String, int) are stored.
This code works for me:
File file = new File(this.getFilesDir(), pdfFileName);
Uri path = Uri.fromFile(file);
Intent pdfIntent = new Intent(Intent.ACTION_VIEW);
pdfIntent.setDataAndType(path, "application/pdf");
pdfIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
try {
startActivity(pdfIntent);
} catch(ActivityNotFoundException e) {
Log.e("Activity Not Found Exception",e.toString());
}
There are only 2 methods to achieve what you want:
1) Using SDCARD
You save downloaded pdf somewhere SDCARD. Something like this:
Instead of creating a file:
File pdfFile = new File(Environment.getExternalStorageDirectory(), "pdffile");
FileOutputStream fos = new FileOutputStream(pdfFile);
fos.write(pdfAsBytes);
fos.close();
...
And you use pdfFile when creating an Intent.
2) Using custom ContentProvider
The second method can be used if you still do not want to use your SDCARD storage. You can use your app's CacheDir (you will download your file there). This involves creating your own ContentProvider, and after that you will be able to pass corresponding URI to the pdfreader app.
Details on how to do this all are here.
There is no known other methods to open any downloaded file in 3rd party app in Android.

Categories

Resources