I have written a piece of code that detects installed application in android and opens the file with the application.For example, a word document should be opened with some office apk.
Intent intent = new Intent(android.content.Intent.ACTION_VIEW);
Uri data = Uri.fromFile(temp_file);
String type = getMimeType(temp_file.getName());
intent.setDataAndType(data, type);
this.startActivity(intent);
In the above code temp_file is the file that should be opened.And below is the generalised code that I wrote to get the MIME type
public static String getMimeType(String url) {
String type = null;
String extension = MimeTypeMap.getFileExtensionFromUrl(url);
if (extension != null) {
MimeTypeMap mime = MimeTypeMap.getSingleton();
type = mime.getMimeTypeFromExtension(extension);
}
return type;
}
But when I execute ,it throws android.content.ActivityNotFoundException exception.So,am I doing anything wrong here?
You are calling getMimeType() and passing it the file name. But your method getMimeType() expects an URL. The documentation for MimeTypeMap.getFileExtensionFromUrl() specifically says:
This method is a convenience method for obtaining the extension of a url and has undefined results for other Strings.
You are probably getting null for the mime type. Add some debug logging and check what getMimeType() is returning.
Also, look in the logcat. It should tell you the content of the Intent it is trying to resolve. That should also give you a hint.
This may help you,
private void readFile(File file){
Uri path = Uri.fromFile(file);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(path, "application/pdf");// for .pdf file
//intent.setDataAndType(path, "application/msword");// for msword file
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
try {
startActivity(intent);
}
catch (ActivityNotFoundException e) {
String str= "No Application Available to View .pdf file.";
showToast(str);
}
where file is the name of file to be open
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
File file=new File("/sdcard/yourfile");
if(file.exists())
{
Uri path=Uri.fromFile(file);
Intent intent=new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(path, "application/readername");
try
{
startActivity(intent);
}
catch(ActivityNotFoundException e)
{
Toast.makeText(TestActivity.this, "No software for PDF", Toast.LENGTH_SHORT).show();
}
}
}
});
Related
i'm getting a pdf file from an api, and i got something like that http://x/docs/document1
In my android project, i have like this:
try{
Android.Content.Intent activity = new Android.Content.Intent(this, typeof(WebViewPDF));
activity.AddFlags(Android.Content.ActivityFlags.GrantReadUriPermission);
activity.AddFlags(Android.Content.ActivityFlags.NoHistory);
string uriAndroid = "http://x/docs/document1";
activity.PutExtra("url", JsonConvert.SerializeObject(uriAndroid));
StartActivity(activity);
}catch (Exception){
...
}
The main problem is, i cannot modify the api, so the endpoint is http://x/docs/document1, but if i try another uri, with the .pdf extension, for example https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf it works fine.
I don't know if i need to get that info from the API in a different way,
How can i show the pdf in the webView or external app without download first the doc?
The solution was download first and then open from local.
void PrintPdf(Uri uri)
{
var webClient = new WebClient();
webClient.Proxy = WebRequest.DefaultWebProxy;
webClient.Credentials = new NetworkCredential("UserName", "Pass");
webClient.Encoding = Encoding.UTF8;
var bytes = webClient.DownloadData(uri);
var text = bytes; // get the downloaded text
string localFilename = "NameforPdf.PDF";
string localPath = System.IO.Path.Combine(Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads).ToString(), localFilename);
File.WriteAllBytes(localPath, text); // writes to local storage
bool exists = File.Exists(localPath);
if (exists)
{
Java.IO.File file = new Java.IO.File(localPath);
file.SetReadable(true);
//That's the important part, notice the content://
Android.Net.Uri uriLocal = Android.Net.Uri.Parse("content://" + localPath);
Intent intent = new Intent(Intent.ActionView);
intent.SetFlags(ActivityFlags.NewTask);
intent.SetDataAndType(uriLocal, "application/pdf");
intent.AddFlags(ActivityFlags.GrantReadUriPermission);
try
{
StartActivity(intent);
}
catch (Exception)
{
Toast.MakeText(Xamarin.Forms.Forms.Context, "pdf reader not installed", ToastLength.Short).Show();
}
}
}
Just want to confirm that is it possible that when i click on file of any extension will open up with its compatible software in android phone or display me the list of software’s present in mobile which can open the file and if it didn't found any software it will indicate user to first download the software to open that particular file (All this thing need to be done pro grammatically).
Thanks.
Any help will be appreciated.
In order to open the file you can use the following method, If there is no application that can handle given file, it simply shows a Toast saying no application found.
private void viewFile(String filePath, String title, int fileType) {
Uri uri = Uri.parse("file://" + filePath);
Intent intent = new Intent(Intent.ACTION_VIEW);
String dataAndType = getIntentDataAndType(filePath);
intent.setDataAndType(uri, dataAndType);
intent.putExtra(Intent.EXTRA_TITLE, title);
// Verify that the intent will resolve to an activity
if (intent.resolveActivity(getActivity().getPackageManager()) != null) {
startActivity(intent);
} else {
Toast.makeText(getActivity(), "No Application found", Toast.LENGTH_SHORT).show();
}
}
UPDATED :
For finding the mime type of the file.
private String getIntentDataAndType(String filePath) {
String exten = "";
int i = filePath.lastIndexOf('.');
// If the index position is greater than zero then get the substring.
if (i > 0) {
exten = filePath.substring(i + 1);
}
String mimeType = android.webkit.MimeTypeMap.getSingleton().getMimeTypeFromExtension(exten);
mimeType = (mimeType == null) ? "*/*" : mimeType;
return mimeType;
}
I use the following snippet to open or share any file from device's storage (MyFile is my own class which extends File and should be considered as File. The flag String I'm passing is either Intent.ACTION_VIEW or Intent_ACTION_SEND):
public void openOrShare(String flag, MyFile f){
try {
MimeTypeMap mmap = MimeTypeMap.getSingleton();
String type = MimeTypeMap.getFileExtensionFromUrl(f
.getName());
String ftype = mmap.getMimeTypeFromExtension(type);
if (ftype == null)
ftype = "*/*";
Intent intent = new Intent(flag);
Uri data = Uri.fromFile(f);
intent.setDataAndType(data, ftype);
startActivity(intent);
} catch (ActivityNotFoundException e) {
e.printStackTrace();
Tools.gimmeToast(
getActivity(),
"no application found to handle this file type",
Toast.LENGTH_LONG);
} catch (Exception e) {
e.printStackTrace();
}
}
While passing Intent.ACTION_VIEW everything works fine for any (also custom) types, the system creates a chooser and lists the apps, for well-known files it launches the correct Activity to handle the file immediately .
The problem: passing Intent.ACTION_SEND seems to be working halfway - it creates the chooser as well, however most apps (Dropbox and many more that I've tested with) just crash with an NPE when confirming the action. Testing with various email clients also failed: they don't crash like most of the other apps, but create a message and put the local Uri (like //storage/.....) in the To field (gmail) OR simply create a new empty message, ignoring the Intent data (yahoo! mail), while I expect them to attach the file to a new message.
The question: what am I doing wrong to share any file type?
EDIT
I figured out that it works if using intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(f));, however there's an ActivityNotFoundException being caught when trying to share some specific files (like .dat). As far as I know, apps like Dropbox support adding any file types. Looking for a workaround.
If you don't know the MIME Type of the file, then do not set it.
So I would try:
Intent intent = new Intent(flag);
Uri data = Uri.fromFile(f);
String ftype = mmap.getMimeTypeFromExtension(type);
if (ftype != null) {
intent.setDataAndType(data, ftype);
} else {
intent.setData(data);
}
setDataAndType needs data and explicit mime type (maybe */* is not).
Never mind, I finally figured that out. So here's the working solution which allows to share any type of data using any app*:
*Note: the below code actually also lists apps that might be not able to handle specific file types, those apps (at least they should) notify the user that the file type is not supported if this is the case
public void doShare(MyFile f) {
try {
Intent intent = new Intent(Intent.ACTION_SEND);
MimeTypeMap mmap = MimeTypeMap.getSingleton();
String type = MimeTypeMap.getFileExtensionFromUrl(f.getName());
String ftype = mmap.getMimeTypeFromExtension(type);
if (ftype == null)
ftype = "*/*";
intent.setType(ftype);
intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(f));
startActivity(intent);
} catch (ActivityNotFoundException e) {
e.printStackTrace();
Tools.gimmeToast(getActivity(),
"no application found to handle this file type",
Toast.LENGTH_LONG);
} catch (Exception e) {
e.printStackTrace();
}
}
I got a activity that holds a path to a file (with unknown mime type).
I got 2 buttons. The one should open the folder in a file manager choosen by user.
The other should open the file in a application that fits to the filetype.
Clicking buttons work. openFolder let me choose a filemanager: using androzip or root explorer takes me to sdcard but astro wants me to choose a file as if i upload a file to a oneclickhoster. OpenFile gives me no choise but opens a hex Editor which unfortunatli says the file is "null".
public void openFolder(View v)
{
File f=new File(path);
if(f.exists())
{
String folder=f.getAbsolutePath().replace("/"+f.getName(),"")+"/";
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
Uri uri = Uri.parse(folder);
intent.setDataAndType(uri, "file/*");
startActivity(Intent.createChooser(intent, "Open folder"));
}
}
public void openFile(View v)
{
File f=new File(path);
if(f.exists())
{
//example for path: path=/storage/sdcard0/test.mp3
Intent intent = new Intent(Intent.ACTION_EDIT);
Uri uri = Uri.parse("file:/"+path);
intent.setDataAndType(uri, getMIME());
startActivity(Intent.createChooser(intent, "Open file"));
}
}
private String getMIME()
{
String type =null;
String extension = MimeTypeMap.getFileExtensionFromUrl(path);
if (extension != null) {
MimeTypeMap mime = MimeTypeMap.getSingleton();
type = mime.getMimeTypeFromExtension(extension);
}
if(type.equals("") || type == null)
return "UNKNOWN";
else
return type;
}
EDIT: the problem for opening the file was Intent.ACTION_EDIT, it should be Intent.ACTION_VIEW.
But I still don't know how to open the folder.
I am writing an Android application to display pdf files on the device. And I need to use the current versioncode (35498) of the Adobe Reader to display the pdf files.I have with code to display list of files on the screen. Now I need to invoke the Adobe reader (not any other pdf reader installed on the device) onclick of each document. I am not sure how I code that. I am an Android newbie. Any help will be greatly appreciated.
Thanks in Advance,
Navin
I see that you want to open Adobe specifically, but you may want to consider doing it the more Android-like way of opening a general intent and allowing the user to choose how it opens. For your reference, you'd do that with the following code:
private void openFile(File f, String mimeType)
{
Intent viewIntent = new Intent();
viewIntent.setAction(Intent.ACTION_VIEW);
viewIntent.setDataAndType(Uri.fromFile(file), mimeType);
// using the packagemanager to query is faster than trying startActivity
// and catching the activity not found exception, which causes a stack unwind.
List<ResolveInfo> resolved = getPackageManager().queryIntentActivities(viewIntent, 0);
if(resolved != null && resolved.size() > 0)
{
startActivity(viewIntent);
}
else
{
// notify the user they can't open it.
}
}
If you really need to use both Abode Reader specifically, and a specific version, you would need to query for it using PackageManager.getPackageInfo(String, int)
Try the following code
private void loadDocInReader(String doc)
throws ActivityNotFoundException, Exception {
try {
Intent intent = new Intent();
intent.setPackage("com.adobe.reader");
intent.setDataAndType(Uri.parse(doc), "application/pdf");
startActivity(intent);
} catch (ActivityNotFoundException activityNotFoundException) {
activityNotFoundException.printStackTrace();
throw activityNotFoundException;
} catch (Exception otherException) {
otherException.printStackTrace();
throw otherException;
}
}
If you are in "online mode", here is an interesting alternate solution using Google docs.
String myPDFURL = "http://{link of your pdf file}";
String link;
try {
link = "http://docs.google.com/viewer?url="
+ URLEncoder.encode(myPDFURL, "UTF-8")
+ "&embedded=true";
} catch (Exception e) {
e.printStackTrace();
}
Uri uri = Uri.parse(link);
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
This works, setDataAndType method cannot seem to correctly recognize the PDF type if used via URL.
private static Intent newPDFLinkIntent(String url) {
Uri pdfURL = Uri.parse(url);
Intent pdfDownloadIntent = new Intent(Intent.ACTION_VIEW, pdfURL);
pdfDownloadIntent.setType("application/pdf");
pdfDownloadIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
return pdfDownloadIntent ;
}
Unfortunately, the PDF applications I'm using don't anticipate downloading and caching the online content (some will have memory leak error, some will reject link downloading), so you'll eventually end up invoking an intent that downloads the PDF first, before opening the downloaded content via the notification link. I eventually used the solution below:
private static Intent newPDFLinkIntent(String url) {
Intent pdfDownloadIntent = null;
try {
pdfDownloadIntent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME);
pdfDownloadIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
} catch (URISyntaxException e) {
Log.e("PDF Link Tag", e.getMessage());
}
return pdfDownloadIntent;
}