Reputation: 2096
I'm developing an Android application and I have to open some files.
This is my code using intent:
public class FacturaActivity extends Activity {
(...)
public void downloadInvoice(View view) {
File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() +"/"+ filename);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(file),"application/pdf");
intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
startActivity(intent);
}
}
File is in the root directory of the SD card and I can manually open it.
Problem
Application is closed when it arrives at startActivity(intent). I think the problem is in AndroidManifest.xml file, but I don't know how to put it correctly.
AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="8" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme"
android:name="###.MyApplication" > <!--cant show complete name-->
<activity
android:name="###.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".FacturaActivity" >
</activity>
</application>
LogCat
07-03 15:49:13.094: E/AndroidRuntime(1032): FATAL EXCEPTION: main
07-03 15:49:13.094: E/AndroidRuntime(1032): java.lang.IllegalStateException: Could not execute method of the activity
(...)
07-03 15:49:13.094: E/AndroidRuntime(1032): Caused by: android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.VIEW dat=file:///mnt/sdcard/201209_F2012212782.PDF typ=application/pdf flg=0x40000000 }
07-03 15:49:13.094: E/AndroidRuntime(1032): at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:1408)
07-03 15:49:13.094: E/AndroidRuntime(1032): at android.app.Instrumentation.execStartActivity(Instrumentation.java:1378)
07-03 15:49:13.094: E/AndroidRuntime(1032): at android.app.Activity.startActivityForResult(Activity.java:2817)
07-03 15:49:13.094: E/AndroidRuntime(1032): at android.app.Activity.startActivity(Activity.java:2923)
Can you help me to complete AndroidManifest? Or how can I open that pdf?
Upvotes: 42
Views: 154760
Reputation: 101
Want to chime in with the answers above. The code is nearly identical, except it's in an Android Jetpack Compose composable (and therefore in Kotlin). That, and I did two videos talking through it. Here's the happy path version, (clocking in at 10 minutes).
For the whole hog, this behemoth 30 minute screenshow has me provide a significant amount of context and a/b options of the code.
If you want to see the code, you can find it in this repo branch.
Upvotes: 1
Reputation: 520
The reason you don't have permissions to open file is because you didn't grant other apps to open or view the file on your intent. To grant other apps to open the downloaded file, include the flag(as shown below): FLAG_GRANT_READ_URI_PERMISSION
Intent browserIntent = new Intent(Intent.ACTION_VIEW);
browserIntent.setDataAndType(getUriFromFile(localFile), "application/pdf");
browserIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION|
Intent.FLAG_ACTIVITY_NO_HISTORY);
startActivity(browserIntent);
And for function:
getUriFromFile(localFile)
private Uri getUriFromFile(File file){
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
return Uri.fromFile(file);
}else {
return FileProvider.getUriForFile(itemView.getContext(), itemView.getContext().getApplicationContext().getPackageName() + ".provider", file);
}
}
Upvotes: 2
Reputation: 16066
As of API 24, sending a file://
URI to another app will throw a FileUriExposedException. Instead, use FileProvider to send a content://
URI:
public File getFile(Context context, String fileName) {
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
return null;
}
File storageDir = context.getExternalFilesDir(null);
return new File(storageDir, fileName);
}
public Uri getFileUri(Context context, String fileName) {
File file = getFile(context, fileName);
return FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".provider", file);
}
You must also define the FileProvider in your manifest:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.mydomain.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
Example file_paths.xml:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-files-path name="name" path="path" />
</paths>
Replace "name" and "path" as appropriate.
To give the PDF viewer access to the file, you also have to add the FLAG_GRANT_READ_URI_PERMISSION
flag to the intent:
private void displayPdf(String fileName) {
Uri uri = getFileUri(this, fileName);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(uri, "application/pdf");
// FLAG_GRANT_READ_URI_PERMISSION is needed on API 24+ so the activity opening the file can read it
intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_GRANT_READ_URI_PERMISSION);
if (intent.resolveActivity(getPackageManager()) == null) {
// Show an error
} else {
startActivity(intent);
}
}
See the FileProvider documentation for more details.
Upvotes: 14
Reputation: 1736
Kotlin version below (Updated version of @paul-burke response:
fun openPDFDocument(context: Context, filename: String) {
//Create PDF Intent
val pdfFile = File(Environment.getExternalStorageDirectory().absolutePath + "/" + filename)
val pdfIntent = Intent(Intent.ACTION_VIEW)
pdfIntent.setDataAndType(Uri.fromFile(pdfFile), "application/pdf")
pdfIntent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY)
//Create Viewer Intent
val viewerIntent = Intent.createChooser(pdfIntent, "Open PDF")
context.startActivity(viewerIntent)
}
Upvotes: 2
Reputation: 139
String dir="/Attendancesystem";
public void displaypdf() {
File file = null;
file = new File(Environment.getExternalStorageDirectory()+dir+ "/sample.pdf");
Toast.makeText(getApplicationContext(), file.toString() , Toast.LENGTH_LONG).show();
if(file.exists()) {
Intent target = new Intent(Intent.ACTION_VIEW);
target.setDataAndType(Uri.fromFile(file), "application/pdf");
target.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
Intent intent = Intent.createChooser(target, "Open File");
try {
startActivity(intent);
} catch (ActivityNotFoundException e) {
// Instruct the user to install a PDF reader here, or something
}
}
else
Toast.makeText(getApplicationContext(), "File path is incorrect." , Toast.LENGTH_LONG).show();
}
Upvotes: 8
Reputation: 25584
The problem is that there is no app installed to handle opening the PDF. You should use the Intent Chooser, like so:
File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() +"/"+ filename);
Intent target = new Intent(Intent.ACTION_VIEW);
target.setDataAndType(Uri.fromFile(file),"application/pdf");
target.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
Intent intent = Intent.createChooser(target, "Open File");
try {
startActivity(intent);
} catch (ActivityNotFoundException e) {
// Instruct the user to install a PDF reader here, or something
}
Upvotes: 109