How do I determine if Android can handle PDF - android

I know Android cannot handle PDFs natively. However, the Nexus One (and possibly other phones) come pre-installed with QuickOffice Viewer. How would I determine whether the user has a PDF viewer installed?
Currently, the code to start the PDF download looks pretty simple:
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(url));
startActivity(intent);
After the download, the user clicks on the downloaded file to invoke the viewer.
However, if there is no PDF viewer, Android reports "Cannot download. The content is not supported on the phone."
I want to determine if the user will get this message, and if so, direct them to PDF apps in the Android Market.

I have been testing this and found that the following works. First you download the file independently and store it on the device and then you go do this:
File file = new File("/sdcard/download/somepdf.pdf");
PackageManager packageManager = getPackageManager();
Intent testIntent = new Intent(Intent.ACTION_VIEW);
testIntent.setType("application/pdf");
List list = packageManager.queryIntentActivities(testIntent, PackageManager.MATCH_DEFAULT_ONLY);
if (list.size() > 0 && file.isFile()) {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
Uri uri = Uri.fromFile(file);
intent.setDataAndType(uri, "application/pdf");
startActivity(intent);
I have tested this on various emulator and a rooted cyanogen phone as well as a HTC Magic. If no pdf renderer is available the list will return zero and nothing will happen.
It seems to be important to set the data type to the pdf mime type to get the correct behaviour.
If you e.g. install droidreader it will react to the intent and display the pdf.
Of course you could do the check before you download the pdf as well depending on your use case or do things like popping up alerts or redirecting do other intents for download or whatever.
Edit: I have since refactored this out into a separate method ..
public static final String MIME_TYPE_PDF = "application/pdf";
/**
* Check if the supplied context can render PDF files via some installed application that reacts to a intent
* with the pdf mime type and viewing action.
*
* #param context
* #return
*/
public static boolean canDisplayPdf(Context context) {
PackageManager packageManager = context.getPackageManager();
Intent testIntent = new Intent(Intent.ACTION_VIEW);
testIntent.setType(MIME_TYPE_PDF);
if (packageManager.queryIntentActivities(testIntent, PackageManager.MATCH_DEFAULT_ONLY).size() > 0) {
return true;
} else {
return false;
}
}

You can query the PackageManager to see if there's a package that can handle your Intent. Here's an example: http://www.curious-creature.org/2008/12/15/android-can-i-use-this-intent/

You will probably use asynch task to download any file.so simple way is Just add below code in post execute() method of asynch task.it will ask for choice.
FileOpener.open(context, file);
and file should contain info about filepath and filename.Example
File file = new File(Environment
.getExternalStoragePublicDirectory("/MDroid")
+ filepath + fileName );
Hope it helps

Related

Send File Path in order to choose the respective application to open in Android

In my application I will have list with different file paths.
Example list:
/storage/emulated/0/Edited/myjpeg_file.JPG
/storage/emulated/0/Downloads/bill.pdf
/storage/emulated/0/Downloads/mytextfile.txt
This list is showed in list view. When I click on one entry, it should open list of supported installed applications to process it further.
When I click on entry wit .JPG then it should show apps related to that.
And If i select .pdf file it should show supported apps
And for all paths default it should show file browser such as default file manager , Es Explorer etc...
I am referring to
http://developer.android.com/training/sharing/send.html
But need the selection based on file type (txt, xml, pdf jpeg etc..).
If i select .JPG file it is not showing gallery or Es file explorer (i have it on my mobile)
In same way when I click on .pdf file it is not showing adobe reader etc..
Below is my code:
public void openFile(String minmeType, Uri uriFromPath) {
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_STREAM, uriFromPath);
if(minmeType.contains("text/plain")) {
shareIntent.setType("text/plain");
} else {
shareIntent.setType("image/jpeg");
}
startActivity(Intent.createChooser(shareIntent, "sending out"));
}
Above function is called from below code:
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
String path = pathList[position];
Uri uriFromPath = Uri.fromFile(new File(path));
Toast.makeText(getActivity().getApplicationContext(),"Uri: "+ uriFromPath, Toast.LENGTH_LONG).show();
if(path.contains(".JPG")) {
openFile("image/*", uriFromPath);
} else {
openFile("text/plain", uriFromPath);
}
return;
}
});
Have you tried using ACTION_VIEW instead of ACTION_SEND?
ACTION_SEND implies you want to send the document to somebody else. Adobe Reader won't catch those Intents that want to do ACTION_SEND, because sending pdfs is not what they do. VIEWing them, on the other hand, is.
You also need to match the intent that the target application is filtering for.
In this case, it's pretty simple what you want to do: you want Adobe Reader to open your file. And Adobe Reader actually has the intent filter you would expect. If you look into its Manifest file, you'll see that (among others) it includes an intent filter that matches Uris with schema file, any host, and any path that ends in .pdf. If you change your openFile method to this:
public void openFile(Uri uriFromPath) {
Intent shareIntent = new Intent(Intent.ACTION_VIEW, uriFromPath);
startActivity(Intent.createChooser(shareIntent, "sending out"));
}
It will work. It should also work for most apps that handle content from files.

Android: Finding/choosing an intent that "shouldn't" be associated with a certain file?

I have an app that stores files in getExternalFilesDir(null)... for whatever reason (how other programmers coded their intent filter), not all the apps that I could normally open up for a file if it was in a less nested/non-dotted directory show up as options with this code:
intent = new Intent();
intent.setAction(android.content.Intent.ACTION_VIEW);
Uri uri = Uri.fromFile(file);
try{
intent.setType(MimeTypeMap.getSingleton().getMimeTypeFromExtension(MimeTypeMap.getFileExtensionFromUrl(uri.toString())));
intent.setData(uri);
Log.v(TAG, "Mime type="+MimeTypeMap.getSingleton().getMimeTypeFromExtension(MimeTypeMap.getFileExtensionFromUrl(uri.toString())));
Log.v(TAG, "Uri="+uri.toString());
}catch(Exception e){
Log.v(TAG, "Uri="+uri.toString());
intent.setData(uri);
}
How can I get a listing of the available apps for a certain MIME type, and/or fudge the URI to get around the intent filter (but still pass in the true URI to the app), so I can make a dialog and my user can pick one? Or, is there a builtin way to do this and display the dialog?

Open PDF in Android

I would like to open a PDF file from my android application. I've searched how to do it in internet, and it seems very easy, but it doesn't work, at least in my mobile (Sony XPeria P).
File file = ....
Intent intent = new Intent(Intent.ACTION_VIEW,
Uri.fromFile (file));
intent.setType("application/pdf");
startActivity(intent);
When this code is executed, a window is opened asking to choose an application to show the PDF. When I choose the Adobe Reader, it's opened by no document is shown.
What I'm doing wrong?
Try this, Its working for me
//Method to open the pdf file in the PDF Viewer
public void OpenPDFFile() {
File pdfFile = new File(Environment.getExternalStorageDirectory(),"PdfFile.pdf");//File path
if (pdfFile.exists()) //Checking for the file is exist or not
{
Uri path = Uri.fromFile(pdfFile);
Intent objIntent = new Intent(Intent.ACTION_VIEW);
objIntent.setDataAndType(path, "application/pdf");
objIntent.setFlags(Intent. FLAG_ACTIVITY_CLEAR_TOP);
startActivity(objIntent);//Staring the pdf viewer
}
}
The setType("application/pdf") function removes all the previous data.
If the targetSdkVersion >= 24 we need to use file provider to get the Uri. See this post for details: https://stackoverflow.com/a/38858040/8192914
So, the final code would look something like this:
Uri pathUri = FileProvider.getUriForFile(getBaseContext(), context.getApplicationContext().getPackageName() + ".provider", finalFile);
Intent pdfViewerIntent = new Intent(Intent.ACTION_VIEW);
pdfViewerIntent.setDataAndType(pathUri, "application/pdf");
pdfViewerIntent.setFlags(Intent. FLAG_ACTIVITY_CLEAR_TOP);
pdfViewerIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(pdfViewerIntent);

Browse path on SD card via Intent

I'd like to know if there's a way to open a file browser (system or 3rd party like Astro) to a specific path. There's not much else to say here... pretty straight-forward question.
Sounds like ACTION_GET_CONTENT is what you want. See here. The relevant bits would be:
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("file/*");
startActivityForResult(intent,PICKFILE_RESULT_CODE);
On my phone (which has astro already installed), this brings up an astro dialog for /sdcard. I'm not sure what this will do on a phone with no file browser installed. I'm also unsure about whether you are able to actually specify the starting path using this method. The docs make it sound like you can't specify a starting uri for ACTION_GET_CONTENT.
EDIT: I think I understand the question better now. I thought you were wanting a picker style browser to just get a file path from the user. If you want a full blown browser to handle your uri, then this worked for me:
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse("file:///mnt/sdcard/Music"), "*/*");
startActivity(intent);
That will probably give you quite a long list of possible handlers, but I'd bet any file manager on the system would be in the list (astro certainly is).
I don't believe that any of the manufacturer provided File Browsers provide such a thing.
Though I don't see anything glaringly wrong with the theory of doing so. I imagine you are more likely to find a 3rd party file browser with this feature, but I've never come across any of those either.
You might look in to the Open Intents OI File Manager this concept seems right up their ally, if they don't already have this feature, I bet they might consider adding it if you get in contact with them.
Here i am going to show you that how to create a BROWSE button, which when you will click, it will open up the SDCARD, you will select a File and in result you will get the File Name and File path of the selected one:
// A button which you will hit**
browse.setOnClickListener(new OnClickListener()
{
public void onClick(View v)
{
Intent intent = new Intent();
intent.setAction(Intent.ACTION_PICK);
Uri startDir = Uri.fromFile(new File("/sdcard"));
startActivityForResult(intent, PICK_REQUEST_CODE);
}
});
//The function which will get the Resulted File Name and File Path
protected void onActivityResult(int requestCode, int resultCode, Intent intent)
{
if (requestCode == PICK_REQUEST_CODE)
{
if (resultCode == RESULT_OK)
{
Uri uri = intent.getData();
if (uri.getScheme().toString().compareTo("content")==0)
{
Cursor cursor =getContentResolver().query(uri, null, null, null, null);
if (cursor.moveToFirst())
{
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);//Instead of "MediaStore.Images.Media.DATA" can be used "_data"
Uri filePathUri = Uri.parse(cursor.getString(column_index));
String file_name = filePathUri.getLastPathSegment().toString();
String file_path=filePathUri.getPath();
Toast.makeText(this,"File Name & PATH are:"+file_name+"\n"+file_path, Toast.LENGTH_LONG).show();
}
}
}
}
}

How to get a list of installed media players

In my app I have a menu item that I want to open up the user's preferred media player, only interested in audio. Ideally the first time the user chooses this item it would choose the only media player on the phone if they only have one installed, or present them with a list if they have more than one. I would then save off their choice so next time it would open that one.
As I understand it, Android has no default media player. I have the original Droid and it has a media player, but I understand other carriers use their own, or the user can uninstall the standard one.
I have tried a few things but can't get anything to work.
I tried this code, which is supposed to get a list of packages that support the intent. It works for some things like "application/pdf" and "video/*". When I try it with "audio/*" I get an empty list, even though I have both the stock Android media player and MixZing installed. Have also tried it with "media/*" and get nothing.
PackageManager packageManager = getPackageManager();
Intent testIntent = new Intent(Intent.ACTION_VIEW);
testIntent.setType("audio/*");
List list = packageManager.queryIntentActivities(testIntent, 0);
I have seen this code which works and opens an audio file with the default player, however I don't want to open a file, I just want to open up the audio app as if the user opened it from the application drawer.
Intent i = new Intent(Intent.ACTION_VIEW);
Uri u = Uri.withAppendedPath(MediaStore.Audio.Media.INTERNAL_CONTENT_URI,"1");
i.setData(u);
startActivity(i);
The only other thing I can think to do is go out and get the package names of the most popular media players and hard code them in and search the phone to see which ones are installed, but this doesn't seem like the best approach. I don't understand why the first bit of code doesn't work. Maybe the intent filters aren't properly set for those apps or I am using the wrong code or mime types.
OK here is how I ask the OS for a list of installed audio players.
Intent intent = new Intent(Intent.ACTION_VIEW);
Uri uri = Uri.withAppendedPath(MediaStore.Audio.Media.INTERNAL_CONTENT_URI,"1");
intent.setData(uri);
List<ResolveInfo> playerList;
playerList = packageManager.queryIntentActivities(intent, 0);
playerList will then be populated with ResolveInfo objects for every app on the phone that claims to handle audio. From the ResolveInfo you can get things like package name to launch the activity, you can get icons and app names. I use it to populate a custom dialog that looks and acts like the stock Android dialog for choosing an activity to launch. I also have the option for the user to set the chosen app as default.
This isn't perfect. You are at the mercy of the OS and the app's intent filters. I have tried this with a few phones and the following apps show up properly: Stock media player for original Droid, stock media player for HTC phones, doubleTwist and MixZing. However, I installed Zimly and it does not show up. I suspect their intent filters aren't set up for audio.
I was also worried there may be cases when MediaStore.Audio.Media.INTERNAL_CONTENT_URI does not have any audio. I have tried this code immediately following a reboot and it works. I have not tried it on a phone with no user media installed.
/*
For my samsung galaxy s4 running android version 5.0, none of the solutions above works but i found another solution. Works perfectly. Here is the code for someone who might need help.
*/
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(new File("content://media/internal/audio/media")), "audio/*");
List activities = this.getPackageManager().queryIntentActivities(intent, 0);
List activities; activities = getPackageManager().queryIntentActivities(intent, 0); int count = activities.size(); String a = Integer.toString(count);
//set alert for executing the task
AlertDialog.Builder builder1 = new AlertDialog.Builder(this);
builder1.setMessage("Handle: " + a);
builder1.setCancelable(true);
AlertDialog alert11 = builder1.create();
alert11.show();
Intent resolveIntent = new Intent(Intent.ACTION_VIEW);
if (type.startsWith("audio/*")) {
Uri uri = Uri.withAppendedPath(
MediaStore.Audio.Media.INTERNAL_CONTENT_URI, "1");
resolveIntent.setDataAndType(uri, type);
} else if (type.startsWith("video/*")) {
Uri uri = Uri.withAppendedPath(
MediaStore.Video.Media.INTERNAL_CONTENT_URI, "1");
resolveIntent.setDataAndType(uri, type);
} else if (type.startsWith("application/pdf")) {
resolveIntent.setType(type);
}
List<ResolveInfo> pkgAppsList = mContext.getPackageManager().queryIntentActivities(resolveIntent, PackageManager.GET_RESOLVED_FILTER);
Here is my solution, If you want get a list of "video/" or "audio/" APPs, you should use "setDataAndType"; But if you want to get a list of "text/*" or "pdf" APPs, you can use "setType".
/**
* get apps supporting video playing
* #return
*/
private List<String> queryPlayerPackageNameLst()
{
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse(video), "video/*");
PackageManager pm = getPackageManager();
List<ResolveInfo> infos = pm.queryIntentActivities(intent,PackageManager.MATCH_UNINSTALLED_PACKAGES);
List<String> packageNameLst = null;
if (infos != null && infos.size() > 0)
{
packageNameLst = new ArrayList<String>(infos.size());
for(int i=0; i<infos.size(); i++)
{
ResolveInfo info = infos.get(i);
packageNameLst.add(info.activityInfo.packageName);
//info.activityInfo.name
}
}
return packageNameLst;
}
Intent resolveIntent = new Intent(Intent.ACTION_VIEW);
resolveIntent.setDataAndType(Uri.parse("file://"), MIMEType);
List<ResolveInfo> pkgAppsList = mContext.getPackageManager().queryIntentActivities(resolveIntent, PackageManager.MATCH_DEFAULT_ONLY| PackageManager.GET_RESOLVED_FILTER);
I think this is better!
For my Samsung Galaxy S4 running Android version 5.0, none of the solutions above work, but I found another solution. Works perfectly.
Here is the code for someone who might need help.
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(new File("content://media/internal/audio/media")), "audio/*");
List<ResolveInfo> activities = this.getPackageManager().queryIntentActivities(intent, 0);
// content://media/internal/audio/media
//List<ResolveInfo> activities;
activities = getPackageManager().queryIntentActivities(intent, 0);
int count = activities.size();
String a = Integer.toString(count);
//set alert for executing the task
AlertDialog.Builder builder1 = new AlertDialog.Builder(this);
builder1.setMessage("Handle: " + a);
builder1.setCancelable(true);
AlertDialog alert11 = builder1.create();
alert11.show();

Categories

Resources