Show PDF in Android - android

In my onCreate() I do this check:
//
// check if we have a PDF viewer, else bad things happen
//
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setType("application/pdf");
List<ResolveInfo> intents = getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
if (intents == null || intents.size() == 0) {
// display message then...
finish();
}
On my HTC Desire, this doesn't return a match, even though I have Adobe's PDF viewer. An answer to this question android: open a pdf from my app using the built in pdf viewer mentions that Adobe may not have any public Intents, so the above check will obviously return nothing.
Can anyone verify whether you should be able launch Acrobat from an intent, or is there some other method or PDF viewer to use.
The actual use case is downloading copies of invoices and storing them on local storage using code such as:
URL url = new URL(data);
InputStream myInput = url.openConnection().getInputStream();
FileOutputStream fos = openFileOutput(fname, Context.MODE_WORLD_READABLE);
// transfer bytes from the input file to the output file
byte[] buffer = new byte[8192];
int length;
while ((length = myInput.read(buffer)) > 0) {
fos.write(buffer, 0, length);
progressDialog.setProgress(i++);
}
fos.close();
and then to show
// read from disk, and call intent
openFileInput(fname); // will throw FileNotFoundException
File dir = getFilesDir(); // where files are stored
File file = new File(dir, fname); // new file with our name
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.fromFile(file));
intent.setType("application/pdf");
startActivity(intent);

Connect your phone to you PC, start Eclipse and open the LogCat. Then download a PDF file with the browser and open it. You should see a line such as (I used the HTC desire):
09-14 17:45:58.152: INFO/ActivityManager(79): Starting activity: Intent { act=android.intent.action.VIEW dat=file:///sdcard/download/FILENAME.pdf typ=application/pdf flg=0x4000000 cmp=com.htc.pdfreader/.ActPDFReader }
Have a go with an explicit intent using the component information. Docs say here:
>
component -- Specifies an explicit name of a component class to use for the intent. Normally this is determined by looking at the other information in the intent (the action, data/type, and categories) and matching that with a component that can handle it. If this attribute is set then none of the evaluation is performed, and this component is used exactly as is. By specifying this attribute, all of the other Intent attributes become optional.
Downside is you will be bound to the htc reader. But you could try an implicit intent first and if that fails try the explicit intent as a fallback.

-Copy the following code in your activity. Call the function CopyReadAssets("File_name.pdf") from onCreate() function. Place the File_name.pdf file in assets folder.
private void CopyReadAssets(String pdfname)
{
AssetManager assetManager = getAssets();
InputStream in = null;
OutputStream out = null;
File file = new File(getFilesDir(), pdfname);
try
{
in = assetManager.open(pdfname);
out = openFileOutput(file.getName(), Context.MODE_WORLD_READABLE);
copyFile(in, out);
in.close();
in = null;
out.flush();
out.close();
out = null;
} catch (Exception e)
{
Toast.makeText(getApplicationContext(), "Pdf Viewer not installed", Toast.LENGTH_SHORT).show();
}
try
{
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(
Uri.parse("file://" + getFilesDir() + "/"+pdfname),
"application/pdf");
startActivity(intent);
}catch (Exception e) {
// TODO: handle exception
Toast.makeText(getApplicationContext(), "Pdf Viewer not installed" ,Toast.LENGTH_SHORT).show();
}
}
private void copyFile(InputStream in, OutputStream out) throws IOException
{
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1)
{
out.write(buffer, 0, read);
}
}

Related

How to create a shared folder usable by my android app?

I've got a question that probably borders on opinion, but I've not any related questions or documentation that answers, so I feel like it's a fair one to ask.
I'm trying to build an android app which modifies music files, and what I'd like to do is have a shared folder so that the files and the results can be accessible and shared. I'd like it if it was among the other folders like Music, Downloads, Movies, etc, or even under Music since it's music related. However this seems like it's a security no no in Android, as after I've made something and put it in there I have to use an intent to access it again, where as I'd rather just be able to open the files and not have a permissions based fiasco. Maybe some type of symbolic link like in Linux that pointed to my apps internal folder could be used, but of this I'm still uncertain.
In any case, is there a way I should go about this? If so, are there some resources I could be pointed to?
Thank you in advance to anyone who takes this up!
Edit for CommonsWare:
I used the following to create the folder:
File mediaStorageDir = new File(Environment.getExternalStorageDirectory(), APP_NAME);
And this to copy files from elsewhere to there:
public void copyFileToHomeDirectory(Uri uri)
{
try
{
ContentResolver contentResolver = getApplicationContext().getContentResolver();
String fileName = queryName(contentResolver, uri);
//Get file extension
String fileType = fileName.substring(fileName.length() - 4, fileName.length());
if(fileType.equalsIgnoreCase(MP3_EXTENSION))
{
String path = Environment.getExternalStorageDirectory() + APP_FOLDER;
InputStream in = contentResolver.openInputStream(uri);
File outputFile = new File(path + File.separator + fileName);
outputFile.createNewFile();
OutputStream out = new FileOutputStream(outputFile);
//First we crack open the file to copy it's contents:
byte[] buffer = new byte[KB_SIZE];
int read;
while ((read = in.read(buffer)) != -1)
{
out.write(buffer, 0, read);
}
in.close();
in = null;
// write the output file (You have now copied the file)
out.flush();
out.close();
out = null;
}
}
catch(FileNotFoundException fnfe)
{
Log.e(TAG, "FileNotFoundException");
Log.e(TAG, Log.getStackTraceString(fnfe));
}
catch(IOException ioe)
{
Log.e(TAG, "IOException");
Log.e(TAG, Log.getStackTraceString(ioe));
}
catch(Exception e)
{
Log.e(TAG, "General Exception");
Log.e(TAG, Log.getStackTraceString(e));
}
}
I've tried other methods that I've overwritten in the process, but accessing the files to be used again I need something like this:
public void openDirectory(View view)
{
// Choose a directory using the system's file picker.
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
// Provide read access to files and sub-directories in the user-selected
// directory.
//intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
//intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
//intent.addCategory(Intent.CATEGORY_OPENABLE);
// Optionally, specify a URI for the directory that should be opened in
// the system file picker when it loads.
//intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, uriToLoad);
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*"); //use image/* for photos, etc.
//The result of this code will be calling the onActivityResult function below
startActivityForResult(intent, REQUEST_MUSIC_DIR);
}
Edit2:
I've reorganized the folders to what I think I should be doing so that I can work with the files freely, however, even in my internal cache storage (getCacheDir() + folder_name) either isn't letting me create the files (outputFile.createNewFile doesn't throw an error) or it isn't letting me open them when I go to get a directory listing.
Here's my code for creating the file:
String path = getCacheDir() + MY_SUB_FOLDER;
//uri is obtained through ACTION_OPEN_DOCUMENT intent
InputStream in = contentResolver.openInputStream(uri);
File outputFile = new File(path + "/" + fileName);
outputFile.createNewFile();
Log.i(TAG, "The new file's directory/path is: " + outputFile.getAbsolutePath());
//NOTE: This is returning /data/user/0/com.example.myapplication/cache/MY_SUB_FOLDER/file_name.mp3
OutputStream out = new FileOutputStream(outputFile);
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1)
{
out.write(buffer, 0, read);
}
in.close();
in = null;
out.flush();
out.close();
out = null;
This is my code for attempting to open and read these newly created files
File directory = new File(getCacheDir(), MY_SUB_FOLDER);
Log.i(TAG, "This is the directory we're trying to get the files from: " + directory.getAbsolutePath());
//NOTE: This returns /data/user/0/com.example.myapplication/cache/MY_SUB_FOLDER
File[] files = directory.listFiles();
if(files != null)
{
for(int i = 0; i < files.length; i++)
{
Log.d(TAG, "Files found: " + files[i].getAbsolutePath());
}
}
The files variable isn't null but it's length is 0 and no files are found.
Edit3:
I am catching the exceptions and logging any stack traces, which currently returns nothing.
catch(FileNotFoundException fnfe)
{
Log.i(TAG, "FileNotFoundException");
Log.i(TAG, Log.getStackTraceString(fnfe));
}
catch(IOException ioe)
{
Log.i(TAG, "IOException");
Log.i(TAG, Log.getStackTraceString(ioe));
}
catch(Exception e)
{
Log.i(TAG, "General Exception");
Log.i(TAG, Log.getStackTraceString(e));
}

How to share my own app apk to other using cordova

I want to share my own apk file to other, in cordova application. I had tried many plugin, but all the plugin are used to just share the app name and some description only.
https://www.npmjs.com/package/cordova-plugin-share
https://github.com/EddyVerbruggen/SocialSharing-PhoneGap-Plugin
So I have decided to create my own plugin and I have search share apk code for java, I got the following code, and it is working fine when I call that function from MainActivity.java
private void shareApplication() {
ApplicationInfo app = getApplicationContext().getApplicationInfo();
String filePath = app.sourceDir;
Intent intent = new Intent(Intent.ACTION_SEND);
// MIME of .apk is "application/vnd.android.package-archive".
// but Bluetooth does not accept this. Let's use "*/*" instead.
intent.setType("*/*");
// Append file and send Intent
File originalApk = new File(filePath);
try {
//Make new directory in new location
File tempFile = new File(getExternalCacheDir() + "/ExtractedApk");
//If directory doesn't exists create new
if (!tempFile.isDirectory())
if (!tempFile.mkdirs())
return;
//Get application's name and convert to lowercase
tempFile = new File(tempFile.getPath() + "/" + getString(app.labelRes).replace(" ","").toLowerCase() + ".apk");
//If file doesn't exists create new
if (!tempFile.exists()) {
if (!tempFile.createNewFile()) {
return;
}
}
//Copy file to new location
InputStream in = new FileInputStream(originalApk);
OutputStream out = new FileOutputStream(tempFile);
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.close();
System.out.println("File copied.");
//Open share dialog
intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(tempFile));
startActivity(Intent.createChooser(intent, "Share app via"));
} catch (IOException e) {
e.printStackTrace();
}
}
But I want to call that function(shareApplication()) from cordova extended java file.
public class AppVersion extends CordovaPlugin {
#Override
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
try {
if (action.equals("shareApk")) {
MainActivity cc=new MainActivity();
cc.shareApplication();
MyClass myClass = new MyClass(c);
}
return false;
} catch (NameNotFoundException e) {
callbackContext.success("N/A");
return true;
}
}
But when I call the function from cordova extended class, it show following error.
I have found the plugin in the following URLs, this can generate your app apk file and finally popup the available sharing capable applications. Then you can choose the application and share it.
https://github.com/merbin2012/cordova-plugin-codeplay-share-own-apk
https://www.npmjs.com/package/cordova-plugin-codeplay-share-own-apk
cordova plugin add cordova-plugin-codeplay-share-own-apk
you should try changing the line
ApplicationInfo app = getApplicationContext().getApplicationInfo();
ApplicationInfo app = this.getPackageManager().getApplicationInfo("package_name", 0);

Share audio file from the res/raw folder thorugh Share Intent in Android

I'm trying to share an audio file from my res/raw folder. What I've done so far is:
Uri uri = Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.sound); //parse path to uri
Intent share = new Intent(Intent.ACTION_SEND); //share intent
share.setType("audio/*");
share.putExtra(Intent.EXTRA_STREAM, uri);
startActivity(Intent.createChooser(share, "Share sound to"));
When I choose to share it on GMail, for example, it says something like "Failed to attach empty file". Looks like I'm not getting the right file path, so I'm basically sharing nothing. What am I doing wrong?
Any help would be much appreciated.
Copy the audio file from the resource to external storage and then share it:
InputStream inputStream;
FileOutputStream fileOutputStream;
try {
inputStream = getResources().openRawResource(R.raw.sound);
fileOutputStream = new FileOutputStream(
new File(Environment.getExternalStorageDirectory(), "sound.mp3"));
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) > 0) {
fileOutputStream.write(buffer, 0, length);
}
inputStream.close();
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_STREAM,
Uri.parse("file://" + Environment.getExternalStorageDirectory() + "/sound.mp3" ));
intent.setType("audio/*");
startActivity(Intent.createChooser(intent, "Share sound"));
Add WRITE_EXTERNAL_STORAGE permission to AndroidManifest.xml file:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
What am I doing wrong?
Few apps handle android.resource Uri values correctly. Your choices are:
Drop the feature, or
Copy the data from the resource into a file, then use FileProvider, perhaps in conjunction with my LegacyCompatCursorWrapper, or
Use my StreamProvider, which can serve raw resources directly, or
Copy the data from the resource into a file, then use Uri.fromFile(), but this looks like it will stop working with the next version of Android, based on preliminary results from testing with the N Developer Preview
EDIT: It was causing a NullPointException. This is what was I doing:
File dest = Environment.getExternalStorageDirectory();
InputStream in = getResources().openRawResource(R.raw.sound);
try
{
OutputStream out = new FileOutputStream(new File(dest, "sound.mp3"));
byte[] buf = new byte[1024];
int len;
while ( (len = in.read(buf, 0, buf.length)) != -1){
out.write(buf, 0, len);
}
in.close();
out.close();
}catch (Exception e) {}
final Uri uri = FileProvider.getUriForFile(Soundboard.this, "myapp.folagor.miquel.folagor", dest); //NullPointerException right here!!
final Intent intent = ShareCompat.IntentBuilder.from(Soundboard.this)
.setType("audio/*")
.setSubject(getString(R.string.share_subject))
.setStream(uri)
.setChooserTitle(R.string.share_title)
.createChooserIntent()
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET)
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(intent);
The code was just fine. The only problem was that on the Manifest's permisions, I had "WRITE_EXTERNAL_STORAGE" instead of "android.permissions.WRITE_EXTERNAL_STORAGE". So I was not having permision to write in the external storage, which caused a FileNotFoundException due to the lack of permision. Now it works fine!

How to read PDF file saved to internal storage of device?

I am using following code to download and read a PDF file from internal storage on device.
I am able to download the files successfully to the directory:
data/data/packagename/app_books/file.pdf
But I am unable to read the file using a PDF reader application like Adobe Reader.
Code to download file
//Creating an internal dir;
File mydir = getApplicationContext().getDir("books", Context.MODE_WORLD_READABLE);
try {
File file = new File(mydir, outputFileName);
URL downloadUrl = new URL(url);
URLConnection ucon = downloadUrl.openConnection();
ucon.connect();
InputStream is = ucon.getInputStream();
FileOutputStream fos = new FileOutputStream(file);
byte data[] = new byte[1024];
int current = 0;
while ((current = is.read(data)) != -1) {
fos.write(data, 0, current);
}
is.close();
fos.flush();
fos.close();
isFileDownloaded=true;
} catch (IOException e) {
e.printStackTrace();
isFileDownloaded = false;
System.out.println(outputFileName + " not downloaded");
}
if (isFileDownloaded)
System.out.println(outputFileName + " downloaded");
return isFileDownloaded;
Code to read the file
PackageManager packageManager = getPackageManager();
Intent testIntent = new Intent(Intent.ACTION_VIEW);
testIntent.setType("application/pdf");
List list = packageManager.queryIntentActivities(testIntent,
PackageManager.MATCH_DEFAULT_ONLY);
try {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
File fileToRead = new File(
"/data/data/com.example.filedownloader/app_books/Book.pdf");
Uri uri = Uri.fromFile(fileToRead.getAbsoluteFile());
intent.setDataAndType(uri, "application/pdf");
startActivity(intent);
} catch (Exception ex) {
Log.i(getClass().toString(), ex.toString());
Toast.makeText(MainActivity.this,
"Cannot open your selected file, try again later",
Toast.LENGTH_SHORT).show();
}
All works fine but the reader app says "File Path is not valid".
Your path is only valid for your app. Place the file in a place where other apps can 'see' it. Use GetExternalFilesDir() or getExternalStorageDirectory().
Note about files which are created inside the directory created by Context.getDir(String name, int mode) that they will only be accessible by your own application; you can only set the mode of the entire directory, not of individual files.
So you can use Context.openFileOutput(String name, int mode). I'm re-using your code for an example:
try {
// Now we use Context.MODE_WORLD_READABLE for this file
FileOutputStream fos = openFileOutput(outputFileName,
Context.MODE_WORLD_READABLE);
// Download data and store it to `fos`
// ...
You might want to take a look at this guide: Using the Internal Storage.
If you would like to keep the file app specific, you can use PdfRenderer available for Lollipop and above builds. There are great tutorials on google and youtube that work well. The method you are using is a secure way to store a PDF file that is only readable from inside the app ONLY. No outside application like Adobe PDF Reader will be able to even see the file.It took me a lot of seaching but I found a solution to my specific usage by using this site and especially youtube.
How to download PDF file from asset folder to storage by making folder
make sure you have storage permission are given like marshmallow device support etc then follow these steps
private void CopyReadAssets()
{
AssetManager assetManager = getContext().getAssets();
FileInputStream in = null;
FileOutputStream out = null;
File sdcard = Environment.getExternalStorageDirectory();
File dir = new File(Environment.getExternalStorageDirectory()+File.separator+ "A_level");
File dir2;
if (dir.exists() && dir.isDirectory()){
Log.e("tag out", ""+ dir);
}else {
dir.mkdir();
Log.e("tag out", "not exist");
}
File file = new File(dir, mTitle+".pdf");
try
{
Log.e("tag out", ""+ file);
out = new FileOutputStream(file);
in = new FileInputStream (new File(mPath));
Log.e("tag In", ""+ in);
copyFile(in, out);
in.close();
in = null;
out.flush();
out.close();
out = null;
} catch (Exception e)
{
Log.e("tag out", ""+ out);
Log.e("tag In", ""+ in);
Log.e("tag", e.getMessage());
Log.e("tag", ""+file);
Log.i("tag",""+sdcard.getAbsolutePath() + "A_level");
}
}
private void copyFile(InputStream in, OutputStream out) throws IOException
{
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1)
{
out.write(buffer, 0, read);
}
}

Load the pdf file in app from assets

I have a PDF file stored in my assets. I want to load the PDF from my assets and read it in the app itself without using any 3rd party app to view.
I got the solution in this link. It works fine when selecting files from sdcard.
Following snippet might help you accessing files from asset folder and then open it:
private void ReadFromAssets()
{
AssetManager assetManager = getAssets();
InputStream in = null;
OutputStream out = null;
File file = new File(getFilesDir(), "file.pdf");
try
{
in = assetManager.open("file.pdf");
out = openFileOutput(file.getName(), Context.MODE_WORLD_READABLE);
copyFile(in, out);
in.close();
in = null;
out.flush();
out.close();
out = null;
} catch (Exception e)
{
Log.e("tag", e.getMessage());
}
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(
Uri.parse("file://" + getFilesDir() + "/file.pdf"),
"application/pdf");
startActivity(intent);
}
and copyFile method is as follows:
private void copyFile(InputStream in, OutputStream out) throws IOException
{
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1)
{
out.write(buffer, 0, read);
}
}
EDIT
For that purpose you'll have to use an ecternal library. It's explained quite well in the link below:
Render a PDF file using Java on Android
Hope this will help you.
Its better if you can open it using a webview
WebView web = (WebView) findViewById(R.id.webView1);
web.loadUrl("file:///android_asset/yourpdf.pdf");
Hope it works.
Ooops just now I checked, the pdf cannot be loaded in the web view
Sorry

Categories

Resources