open failed: EACCES (Permission denied) ANDROID 11 - android

I'm converting a base64 file to a pdf, so first i'm converting from base64 to an array of bytes and then I write it on a FileOutputStream. My problem is when I try to store it adn then open it with pdf viewer i get this error:
Faild to generate pdf from base64: /storage/emulated/0/Download/conclusions.pdf: open failed: EACCES (Permission denied)
Also I'm giving it the necesarry permissions to work, as I use a File provider because the app works on android 11. Here is the code I use:
Activity:
private fun generatePDFFromBase64(base64: String?, fileName: String?) {
try {
val decodedBytes: ByteArray = Base64.decode(base64, Base64.DEFAULT)
val fos = FileOutputStream(fileName?.let { getFilePath(it) })
fos.write(decodedBytes)
fos.flush()
fos.close()
fileName?.let { openDownloadedPDF(it) }
} catch (e: IOException) {
Log.e("TAG", "Faild to generate pdf from base64: ${e.localizedMessage}")
}
}
private fun openDownloadedPDF(fileName: String) {
val file = File(getFilePath(fileName))
if (file.exists()) {
val path: Uri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
FileProvider.getUriForFile(requireContext(), BuildConfig.APPLICATION_ID + ".provider", file)
} else {
Uri.fromFile(file)
}
generalFile = file
val intent = Intent(Intent.ACTION_VIEW)
intent.setDataAndType(path, "application/pdf")
intent.flags = Intent.FLAG_ACTIVITY_NO_HISTORY or Intent.FLAG_GRANT_READ_URI_PERMISSION
val chooserIntent = Intent.createChooser(intent, "Open with")
try {
startActivity(chooserIntent)
} catch (e: ActivityNotFoundException) {
Log.e("TAG", "Failed to open PDF ${e.localizedMessage}")
}
}
}
private fun getFilePath(filename: String): String {
val file =
File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).path)
if (!file.exists()) {
file.mkdirs()
}
return file.absolutePath.toString() + "/" + filename + ".pdf"
}
Android manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
android:name="university"
android:allowBackup="false"
android:icon="${appIcon}"
android:roundIcon="${appIconRound}"
android:label="#string/app_name"
android:supportsRtl="true"
android:hardwareAccelerated="true"
android:theme="#style/Theme.University"
android:usesCleartextTraffic="true">
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true"
tools:replace="android:authorities">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/filepaths"
tools:replace="android:resource" />
</provider>
filepaths:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path
name="external"
path="." />
<external-files-path
name="external_files"
path="." />
<cache-path
name="cache"
path="." />
<external-cache-path
name="external_cache"
path="." />
<files-path
name="files"
path="." />
</paths>

open your app info an app permission click all permissions after show all permission click to enable after problem resolved.

Related

Doesnt attach file to Gmail

Programming in kotlin and using an implicit intent. I have created a txt-file and want to attach this automatically to the email created with the intent. This file is not attaching.
binding.shareAction.setOnClickListener {
lifecycleScope.launch {
val sendIntent = Intent(Intent.ACTION_SEND)
sendIntent.putExtra(Intent.EXTRA_STREAM, File("src/main/java/com/example/openlog/item_logs.txt"))
sendIntent.type = "*/*"
startActivity(Intent.createChooser(sendIntent, "SHARE"))
}
}
Need to convert File into Uri.
val contentUri = FileProvider.getUriForFile(
this,
"com.stackkotlin.provider", //use your app signature + ".provider"
newFile
)
Try below code:
val newFile = getFileFromAssets(this, "demo.txt")
val contentUri = FileProvider.getUriForFile(
this,
"com.stackkotlin.provider", //use your app signature + ".provider"
newFile
)
Log.e("filePath-----",""+contentUri)
val sendIntent = Intent(Intent.ACTION_SEND)
sendIntent.type = "*/*"
sendIntent.putExtra(Intent.EXTRA_STREAM, contentUri)
startActivity(Intent.createChooser(sendIntent, "SHARE"))
I am using asset file, Get file from assets folder.
#Throws(IOException::class)
fun getFileFromAssets(context: Context, fileName: String): File = File(context.cacheDir, fileName)
.also {
if (!it.exists()) {
it.outputStream().use { cache ->
context.assets.open(fileName).use { inputStream ->
inputStream.copyTo(cache)
}
}
}
}
For getting Uri from File we need file provider
Add FileProvider in AndroidManifest.xml
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths" />
</provider>
Add file_paths.xml file under res-> xml folder
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path
name="external"
path="." />
<external-files-path
name="external_files"
path="." />
<cache-path
name="cache"
path="." />
<external-cache-path
name="external_cache"
path="." />
<files-path
name="files"
path="." />
</paths>

Android Intent to Gmail not attaching file by FileProvider "Unable to attach file"

When attaching file to Gmail I briefly see the file in attachments and then get Toast saying "Unable to attach file" and then it's gone. It works fine with Drive, Discord and other apps..
Also the file stays in attachments on emulator but when I send it, the mail is send without attachments. I have a simple .csv file and attach it via FileProvider.
Tried writing to internal storage, didn't help.
val fileLocation = File(requireContext().getExternalFilesDir("data"), "data.csv")
// Saving the file into device
val streamOut =
FileOutputStream(fileLocation)
streamOut.write(myString.toByteArray())
streamOut.close()
// Exporting
val contentUri = FileProvider.getUriForFile(
requireContext(),
"mypackage.fileprovider",
fileLocation
)
val fileIntent = Intent(Intent.ACTION_SEND)
.setType("text/csv")
.putExtra(Intent.EXTRA_SUBJECT, "Data")
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
.putExtra(Intent.EXTRA_STREAM, contentUri)
val chooser = Intent.createChooser(
fileIntent,
requireContext().resources.getText(R.string.send_to)
)
chooser.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
val resInfoList: List<ResolveInfo> = requireActivity().packageManager
.queryIntentActivities(chooser, PackageManager.MATCH_DEFAULT_ONLY)
for (resolveInfo in resInfoList) {
val packageName = resolveInfo.activityInfo.packageName
requireActivity().grantUriPermission(
packageName,
contentUri,
Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION
)
}
requireActivity().startActivity(
chooser
)
provider_paths
<paths>
<external-files-path
name="data"
path="." />
</paths>
Manifest
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="mypackage.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths" />
</provider>
Solved it by changing file_paths.xml according to this template:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path
name="external"
path="." />
<external-files-path
name="external_files"
path="." />
<cache-path
name="cache"
path="." />
<external-cache-path
name="external_cache"
path="." />
<files-path
name="files"
path="." />
</paths>
Can you try to update your file_paths.xml to use a specific path with the external-path and try if it works?
See my working solution below. It uses multiple attachments but it works with the Gmail app:
java class
private void prepareEmail(File report, List<Expense> openExpenses) {
Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
intent.setType("message/rfc822");
intent.putExtra(Intent.EXTRA_EMAIL, new String[]{preferences.getEmailReceiver()});
intent.putExtra(Intent.EXTRA_SUBJECT, preferences.getEmailSubject());
intent.putExtra(Intent.EXTRA_TEXT, preferences.getEmailBody());
ArrayList<Uri> uris = new ArrayList<>();
uris.add(FileProvider.getUriForFile(getApplicationContext(), "my.package", report));
for (Expense expense : openExpenses) {
if (expense.getType() == ExpenseType.EXPENSE.getValue()) {
File file = new File(expense.getReceipt());
uris.add(FileProvider.getUriForFile(getApplicationContext(), "my.package", file));
}
}
intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
startActivity(Intent.createChooser(intent, getResources().getString(R.string.report_report_send)));
}
file_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="my_images" path="Android/data/my.package/files/Pictures" />
<external-path name="my_pdfs" path="Android/data/my.package/files/Documents" />
<external-path name="my_reports" path="Android/data/my.package/files" />
<files-path name="files" path="." />
</paths>
manifest
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
...
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="my.package"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths" />
</provider>

StartActivity - ActionView cannot open document - Xamarin

var storage_path = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads).AbsolutePath;
filePathh = Path.Combine(storage_path, filename);
Java.IO.File file = new Java.IO.File(filePathh);
Console.WriteLine("Downloaded file PATH: " + Query.filePathh);
Intent open = new Intent(Intent.ActionView);
open.AddFlags(ActivityFlags.GrantReadUriPermission);
open.SetFlags(ActivityFlags.NewTask);
Context context = Android.App.Application.Context;
Android.Net.Uri fileUri = FileProvider.GetUriForFile(context, "com.companyname.Login.provider", file).NormalizeScheme();
Console.WriteLine("File uri: " + fileUri.Path);
open.SetDataAndType(fileUri, "*/*");
Intent intentC = Intent.CreateChooser(open, "Open With");
intentC.AddFlags(ActivityFlags.GrantReadUriPermission);
intentC.SetFlags(ActivityFlags.NewTask);
Android.App.Application.Context.StartActivity(intentC);
When trying to open a file (when choosing an app to open it - like Docs or HTML reader) we get error File Not Found.
We saw that filePathh and fileUri are different and are not pointing to the same location.
For storage_path:
storage/emulated/0/Download/How_to_initialize_your_Xamarin_app_to_use_AppConnect_C#_APIs.pdf
For Uri path:
/external/Download/How_to_initialize_your_Xamarin_app_to_use_AppConnect_C#_APIs.pdf
Do you want to achieve the result like following GIF?
I put a PDF in Download folder, I use following code to open it.
private void Button1_Click(object sender, System.EventArgs e)
{
var storage_path = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads).AbsolutePath;
var filePathh = Path.Combine(storage_path, "test.pdf");
Java.IO.File file = new Java.IO.File(filePathh);
Intent open = new Intent(Intent.ActionView);
Uri photoURI = FileProvider.GetUriForFile(this, PackageName + ".provider", file);
open.SetDataAndType(photoURI, "application/pdf");
open.SetFlags(ActivityFlags.NoHistory | ActivityFlags.GrantReadUriPermission);
Intent intent = Intent.CreateChooser(open, "Open File");
try
{
StartActivity(intent);
}
catch (System.Exception)
{
throw;
}
}
Please add provider in your AndroidManifest.xml and read/write persmission.
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.companyname.app17" android:installLocation="auto">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28" />
<application android:allowBackup="true" android:icon="#mipmap/ic_launcher" android:label="#string/app_name" android:roundIcon="#mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="#style/AppTheme">
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths"/>
</provider>
</application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
</manifest>
Create a xml folder in Resource folder and add following provider_paths.xml file
<?xml version="1.0" encoding="utf-8" ?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="."/>
</paths>
Here is my demo's link.
https://github.com/851265601/Xamarin.Android_ListviewSelect/blob/master/App17.zip
Please put PDF in the Download folder like following screenshot.

How to open file from storage by Provider in Android 8.1

I want to open and install a apk file from storage, i used code below:
File fileToOpen = new File(path);
MimeTypeMap mime = MimeTypeMap.getSingleton();
String ext = path.substring(path.lastIndexOf(".") + 1);
String type = mime.getMimeTypeFromExtension(ext);
if (fileToOpen.exists()) {
Intent intent = new Intent(Intent.ACTION_VIEW);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Uri uri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".provider", fileToOpen);
intent.setDataAndType(uri, type);
} else {
intent.setDataAndType(Uri.fromFile(fileToOpen), type);
}
context.startActivity(intent);
}
and in my manifest file:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<provider
android:authorities="${applicationId}.provider"
android:name="android.support.v4.content.FileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_path" />
</provider>
my provider_path.xml:
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path path="." name="external_files" />
</paths>
I have to request permission in runtime and accepted, but after i call this method, nothing happen. File is already existed, what happend in my code? please help me find it, thank so much :((
To request APK for installation,
File file = new File("YOUR_FILE_PATH");
Uri uri;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
uri = getUriForFile(this, BuildConfig.APPLICATION_ID + ".provider", file);
} else {
uri = Uri.fromFile(file);
}
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(uri, "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
startActivityForResult(intent);
Your manifeast should be,
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="YOUR_PACKAGENAME_HERE.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths" />
</provider>
And provider_path should be (It will cover almost all of available devices),
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path
name="external_files"
path="." />
<root-path
name="external_files"
path="/storage/" />
</paths>

Xamarin Android Open file using default app not work in Android 7 or above

I need to open documents or images using default app in android phone. so I implemented following codes and it works good but not work only on Android 7 or above. Please let me know what is wrong and how to fix.
var documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
var filePath = Path.Combine(documentsPath, fileName);
var bytes = File.ReadAllBytes(filePath);
//Copy the private file's data to the EXTERNAL PUBLIC location
string externalStorageState = global::Android.OS.Environment.ExternalStorageState;
var externalPath = global::Android.OS.Environment.ExternalStorageDirectory.Path + "/" + global::Android.OS.Environment.DirectoryDownloads + "/" + fileName;
File.WriteAllBytes(externalPath, bytes);
Java.IO.File file = new Java.IO.File(externalPath);
file.SetReadable(true);
string application = "";
string extension = Path.GetExtension(filePath);
// get mimeTye
switch (extension.ToLower())
{
case ".txt":
application = "text/plain";
break;
case ".doc":
case ".docx":
application = "application/msword";
break;
case ".pdf":
application = "application/pdf";
break;
case ".xls":
case ".xlsx":
application = "application/vnd.ms-excel";
break;
case ".jpg":
case ".jpeg":
case ".png":
application = "image/jpeg";
break;
default:
application = "*/*";
break;
}
Intent intent = new Intent(Intent.ActionView);
Android.Net.Uri uri = Android.Net.Uri.FromFile(file);
Context context = MainActivity.instance;
if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.N)
{
uri = FileProvider.GetUriForFile(context, context.PackageName + ".fileprovider", file);
intent.SetDataAndType(uri, application);
intent.SetFlags(ActivityFlags.GrantReadUriPermission);
intent.AddFlags(ActivityFlags.NoHistory);
}
else
{
intent.SetDataAndType(uri, application);
intent.SetFlags(ActivityFlags.ClearWhenTaskReset | ActivityFlags.NewTask);
}
context.StartActivity(intent);
Originally I wasn't corresponding the android version for this functionality but after I read some questions like this, I added it.
Here is my manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1" package="com.ibase.mtwpublicapp">
<uses-sdk android:minSdkVersion="15" android:targetSdkVersion="26" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<application android:label="OKS" android:largeHeap="true">
<provider android:name="android.support.v4.content.FileProvider" android:authorities="com.oks.mobileapp.fileprovider" android:exported="false" android:grantUriPermissions="true">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="#xml/file_paths"></meta-data>
</provider>
<meta-data android:name="com.facebook.sdk.ApplicationId" android:value="#string/facebook_app_id" />
</application>
</manifest>
When I test the app, it shows an exception in this line.
uri = FileProvider.GetUriForFile(context, context.PackageName + ".fileprovider", file);
here is the exception message.
{Java.Lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/0/Download/237309880.doc
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <657aa8fea4454dc898a9e5f379c58734>:0
at Java.Interop.JniEnvironment+StaticMethods.CallStaticObjectMethod (Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo method, Java.Interop.JniArgumentValue* args) [0x00069] in <54816278eed9488eb28d3597fecd78f8>:0
at Android.Runtime.JNIEnv.CallStaticObjectMethod (System.IntPtr jclass, System.IntPtr jmethod, Android.Runtime.JValue* parms) [0x00000] in /Users/builder/data/lanes/5749/d8c6e504/source/xamarin-android/src/Mono.Android/Android.Runtime/JNIEnv.g.cs:562
at Android.Support.V4.Content.FileProvider.GetUriForFile (Android.Content.Context context, System.String authority, Java.IO.File file) [0x00077] in <e43264129f744fc09346a273ec4f6c48>:0
at FileManagement.Helpers.FileHelper.OpenFileByName (System.String fileName) [0x0022a] in FileManagement/Helpers/FileHelper.cs:141
--- End of managed Java.Lang.IllegalArgumentException stack trace ---
java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/0/Download/237309880.doc
at android.support.v4.content.FileProvider$SimplePathStrategy.getUriForFile(FileProvider.java:712)
at android.support.v4.content.FileProvider.getUriForFile(FileProvider.java:401)
at android.support.v7.app.AlertDialog_IDialogInterfaceOnClickListenerImplementor.n_onClick(Native Method)
at android.support.v7.app.AlertDialog_IDialogInterfaceOnClickListenerImplementor.onClick(AlertDialog_IDialogInterfaceOnClickListenerImplementor.java:30)
at android.support.v7.app.AlertController$ButtonHandler.handleMessage(AlertController.java:162)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6776)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1518)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1408)
}
Here is the file_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-files-path name="my_images" path="Pictures" />
<external-files-path name="my_movies" path="Movies" />
</paths>
I think it may be related to the FileProvider that I declare in manifest.
Thanks for your help!
I got the answer from #CommonsWare after having some discussion.
It needs to add one line to file_path.xml
<external-path name="my_downloads" path="Download" />
here is full xml.
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="my_downloads" path="Download" />
<external-files-path name="my_images" path="Pictures" />
<external-files-path name="my_movies" path="Movies" />
</paths>

Categories

Resources