So I am trying to create a pdf in my app and send that pdf as attachment to gmail app. All was good before android 11 scoped storage restrictions.
This are the files I am using :
provider_paths.xml :
<?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>
AndroidManifest.xml :
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths" />
</provider>
This is the file that I am trying to add as attachment :
File filelocation = new File(context.getCacheDir() +"/", "Some#" + printBean.getId() + ".pdf");
Using the below to access Uri :
Uri path = FileProvider.getUriForFile(this, getPackageName()+".fileprovider",filelocation);
but when I am passing the Uri with the intent for opening gmail
Intent emailIntent = new Intent(Intent.ACTION_SENDTO);
emailIntent.setData(Uri.parse("mailto:"));
emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[]{new UserPreference(context).getUser().getEmail()});
if (path != null) emailIntent.putExtra(Intent.EXTRA_STREAM, path);
emailIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Mail PDF");
emailIntent.putExtra(Intent.EXTRA_EMAIL, new UserPreference(context).getUser().getEmail());
emailIntent.putExtra(Intent.EXTRA_TEXT, printBean);
context.startActivity(Intent.createChooser(emailIntent, context.getString(R.string.send_email)));
it gives me error "couldn't attach file".
Need Help.
Edit : Getting this exception in log :
ComposeActivity:Error adding attachment
ggx: FileNotFoundException when openAssetFileDescriptor.
at ggy.a(PG:6)
at ggy.a(PG:45)
at dod.a(PG:146)
at dnk.run(PG:2)
at dod.a(PG:184)
at dod.a(PG:153)
at dod.a(PG:452)
at dkb.a(Unknown Source:3)
at aezj.a(Unknown Source:5)
at agzq.a(PG:2)
at agzs.run(PG:9)
at ahcg.run(Unknown Source:7)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:462)
at aexk.run(PG:2)
at adjn.run(Unknown Source:3)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
Well FiltUtils might be returning null. You can get the file like
val file = File(context.getCacheDir(), FILE_NAME) and afterwards pass
FileProvider.getUriForFile(requireContext(),YOUR_PROVIDER_PACKAGE ,file)
File provider will give you the uri then you can pass that inside intent of sharing file
Related
I am trying to send a list of files using tcp socket but i get this file provider error.
please help if anyone can. Thanks
Caused by: java.lang.IllegalArgumentException: Failed to find configured root that contains >/storage/708A-1A0F/- CHAIN YE DILLAN DA - MUHAMMAD UMAIR ZUBAIR QADRI - OFFICIAL HD VIDEO.mp4
at >androidx.core.content.FileProvider$SimplePathStrategy.getUriForFile(FileProvider.java:800)
at androidx.core.content.FileProvider.getUriForFile(FileProvider.java:442)
File Path
Set<String> keys = BaseApplication.sendFileStates.keySet();
if (keys.size() > 0) {
for (String s : keys) {
File newFile = new File(s);
Uri contentUri = FileProvider.getUriForFile(this, "com.Jubilant.wifiproject", newFile);
uris.add(contentUri);
}
Log.d("contentUri", "onCreate: " + uris);
}
file_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path
name="external_files"
path="." />
<cache-path
name="external_cache"
path="."/>
<external-cache-path
name="external_cache_path"
path="."/>
<external-files-path
name="external_files_path"
path="."/>
<external-media-path
name="external_media_path"
path="."/>
<files-path
name="files_path"
path="."/>
</paths>
manifest.xml:
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.Jubilant.wifiproject"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_path" />
</provider>
FileProvider standard can not serve files from a removable micro sd card.
Sometimes it can when you add
<root name="root" path="." />
to your file_paths.xml file.
In other cases write your own file provider extending ContentProvider.
I am generating a CSV file from data pulled from Firebase and then trying to attach it to an email (and about two weeks ago this code worked!), but I keep getting the same error of a toast message saving the file cannot be attached and the following error in my log cat when I perform this task now:
2020-08-20 17:05:43.355 11147-11268/com.example.cpd E/DatabaseUtils: Writing exception to parcel
java.lang.SecurityException: Permission Denial: reading androidx.core.content.FileProvider uri content://com.example.cpd.provider/external/MyCPDAudit.csv from pid=30180, uid=1000 requires the provider be exported, or grantUriPermission()
My code to generate the email Intent is as follows
//INTENT TO SEND USER EMAIL
Intent emailIntent = new Intent(Intent.ACTION_SEND);
emailIntent.setType("text/plain");
//SETS THE USERS EMAIL AS THE RECIPIENT EMAIL ADDRESS
emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[]{user.getEmail()});
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "My Audit Profile");
emailIntent.putExtra(Intent.EXTRA_TEXT, "Thank you for using CPD Journal to build your CPD Audit Profile. Please see the attached file for your records.");
emailIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
File file = new File(csv);
Uri uri = FileProvider.getUriForFile(SavedAudit.this, "com.example.cpd.provider", file);
emailIntent.putExtra(Intent.EXTRA_STREAM, uri);
//USER CAN SELECT HOW THEY WANT TO SHARE THE CSV FILE
startActivity(Intent.createChooser(emailIntent, "Pick an email provider"));
I have the following permissions in my Android Manifest
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
File provider in Manifest is
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.example.cpd.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths" />
</provider>
My file paths are
<?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>
As per the logcat, I have tried exporting the provider in my Manifest file, but this crashes the app on launch.
I have tried adding the following two lines with my email Intent, but this results in the same log cat error:
String packageName = getApplicationContext().getPackageName();
grantUriPermission(packageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
My csv and uri log as follows
2020-08-20 18:03:30.969 20914-20914/com.example.cpd D/TAG: csv = /storage/emulated/0/MyCPDAudit.csv
2020-08-20 18:03:30.974 20914-20914/com.example.cpd D/TAG: uri = content://com.example.cpd.provider/external/MyCPDAudit.csv
However, I'm not sure if I'm using this grantUriPermission method correctly by calling it like this - any ideas how to solve this?
I'm trying to open a video file stored in my device using the default media player(VLC).
Code:
public void startPlay(View view) {
String name = "VideoName.mkv";
Uri path = FileProvider.getUriForFile(this, "com.packagName.AppName",
new File("storage/[sd card directory]/Videos/"+name));
Log.d("PATHVAR", path.toString());
Intent shareIntent = new Intent(Intent.ACTION_VIEW);
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
shareIntent.setType("video/*");
startActivity(shareIntent);
}
On the other hand, when I use Environment.getExternalStorageDirectory().getAbsolutePath(), it doesn't throw any errors.
Manifest:
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.packageName.AppName"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths"/>
</provider>
Provider paths:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="."/>
<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>
Logcat:
Caused by: java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/6262-6133/Videos/VideoName.mkv
at androidx.core.content.FileProvider$SimplePathStrategy.getUriForFile(FileProvider.java:739)
at androidx.core.content.FileProvider.getUriForFile(FileProvider.java:418)
at com.packageName.AppName.MainActivity.startPlay(MainActivity.java:201)
at java.lang.reflect.Method.invoke(Native Method)
at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:385)
at android.view.View.performClick(View.java:7339)
at android.widget.TextView.performClick(TextView.java:14222)
at android.view.View.performClickInternal(View.java:7305)
at android.view.View.access$3200(View.java:846)
at android.view.View$PerformClick.run(View.java:27787)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7091)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:965)
Any idea why this is happening? I've set up the necessary permissions and am able to create a text file in internal storage. I've searched around for a solution to this but most of them are using internal storage, not the sd card.
Thanks.
I'm creating an share image button, but for some reason I'm getting such a error code:
java.lang.IllegalArgumentException: Failed to find configured root that contains /document/image:74
at androidx.core.content.FileProvider$SimplePathStrategy.getUriForFile(FileProvider.java:744)
at androidx.core.content.FileProvider.getUriForFile(FileProvider.java:418)
at com.jawad.photoeditor.MainActivity$5.onClick(MainActivity.java:163)
my Manifest looks like:
<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/fileprovider" />
</provider>
and my fileprovider.xml looks like:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path
name="external_files"
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>
And my specific code looks like :
final Button shareButton = findViewById(R.id.shareButton);
shareButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
File file = new File(imageUri.getPath());
Intent intent = new Intent(Intent.ACTION_SEND);
FileProvider.getUriForFile(Objects.requireNonNull(getApplicationContext()),
BuildConfig.APPLICATION_ID + ".provider", file);
intent.setDataAndType(imageUri, "image/*");
intent.putExtra(Intent.EXTRA_STREAM, imageUri);
startActivity(intent);
}
});
Tried this, but it didn't resolve the issue. Any help would be much appreciated, thanks in advance!
So i've just tried adding an root path in my xml file.
<root-path name="root" path="." />
and it now works as a charm. Issue solved
I have a strange problem when I try to share a my_file.html using ShareCompat.
As best practice I have created my own FileProvider but I get the error java.lang.IllegalArgumentException: Failed to find configured root that contains /forms/Proof_of_Life_Form.html I think I have set up all of the stuff correctly.
My XML I have created a provider for that.
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.douglas.sample"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/filepaths" />
</provider>
This is my filepaths created in res/xml/filepaths
<?xml version="1.0" encoding="utf-8"?>
<paths>
<cache-path path="/forms" name="forms" />
</paths>
and also my method that is responsible to call share content.
public void shareContent() {
File file = new File("/forms/", fileName + ".html");
Uri uri = FileProvider.getUriForFile(getContext(), "com.douglas.sample", file);
Intent shareIntent = ShareCompat.IntentBuilder.from(getActivity())
.setType(getActivity().getContentResolver().getType(uri))
.setStream(uri)
.getIntent();
//Provide read access
shareIntent.setData(uri);
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(Intent.createChooser(shareIntent, getString(R.string.share_form)));
}
Finally my exception:
java.lang.IllegalArgumentException: Failed to find configured root that contains /forms/Proof_of_Life_Form.html
at android.support.v4.content.FileProvider$SimplePathStrategy.getUriForFile(FileProvider.java:719)
at android.support.v4.content.FileProvider.getUriForFile(FileProvider.java:404)
at com.douglas.sample.TabbedFormsFragment$2.run(TabbedFormsFragment.java:254)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6682)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1520)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1410)
Any Idea? thanks :D
It seems there are some little mistakes in your code.
Try the following:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.FileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths"/>
</provider>
and then in your provider_paths.xml try:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<!-- We would like to give access to the External Storage of the app.
external_files will expose the path app to storage/emulated/0/ and the
"." is to actually point the root folder. The final path of the Uri will start
from path above and whatever folder we defined. For application upgrades
will be external_files/Android/data/package name/files/updates/name of update apk.-->
<external-path
name="external_files"
path="."/>
</paths>
and then whereever you want to use it try:
String path = Uri.parse(your_file_uri).getPath();
FileProvider.getUriForFile(application, PROVIDER, new File(path)),my_file_type);
where my_file_type = e.g. "application/vnd.android.package-archive" for .apk file
Hope it helps!!!