java.lang.IllegalArgumentException occurs upon retrieving external storage path android - android

I have implemented an android application which uses device camera to take images. I want to save the images to the external storage directory of device. I have been following the instructions given here in android documentation to achieve this.
Here is my code:
I have added the provider in manifest file.
<provider
android:authorities="com.efftronics.android.eEmployee.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_paths"/>
</provider>
In xml folder, I created paths.xml file and defined the path elements.
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path name="my_images" path="images/"/>
<files-path name="my_docs" path="docs/"/>
</paths>
Here is the Java code:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
//mContext.checkImageDirectories();
String fileName = EmpConstants.startImgName +
new SimpleDateFormat(EmpConstants.PhotoFileFormat, Locale.US).format(new Date());
File outFile = new File(
mContext.getEmpImageDirPath() + fileName + ".jpg");
// File newfile = new File(outFile,"default_image.jpg");
/* mCurrentPhotoPath = outFile.getPath();
cameraOpeningIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(outFile));*/
Intent i = new Intent(Intent.ACTION_VIEW,FileProvider.getUriForFile(mContext, BuildConfig.APPLICATION_ID +".provider",outFile));
i.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
/*cameraOpeningIntent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);*/
startActivityForResult(i, REQUEST_IMAGE_CAPTURE);
}
public String getEmpImageDirPath() {
try {
return Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).toString()
+ EmpConstants.appDir;
} catch (Exception e) {
Log.d("eEmp/ImgDir", e.toString());
return "";
}
}
Now when I open the camera, the following exception is thrown:
Error raised due to java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/0/DCIM/eEmployee/IMG_20180103_150825.jpg
I am unable to figure out the reason for this exception. Please help me resolve this issue.

You don't need the <files-path name="my_images" path="images/"/> element in <paths> in paths.xml file. The link you are following states that:
<files-path name="name" path="path" /> Represents files in the files/ subdirectory of your app's internal storage area. This subdirectory is the same as the value returned by Context.getFilesDir().
Similarly it also states that:
<external-path name="name" path="path" />Represents files in the root of the external storage area. The root path of this subdirectory is the same as the value returned by Environment.getExternalStorageDirectory().
From the code that you have shared above, we can see that you are using Environment.getExternalStoragePublicDirectory() in your function getEmpImageDirPath().
So to resolve the error, you have to replace <files-path name="my_images" path="images/"/>by <external-path name="my_images" path="images/" />

Related

Android Open Assets Image File with Intent and FileProvider Shows Size 0

I place all the files in assets folder and use following functions to open them:
fun Fragment.openAssetsFile(fileName: String) {
val file = getAssetsFile(fileName)
val fileUri = FileProvider.getUriForFile(requireContext(), "${requireContext().packageName}.provider", file)
val intent = Intent(Intent.ACTION_VIEW).apply {
type = "application/${file.extension}" //<- doesn't work for image (jpg, png)
data = fileUri
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}
startActivity(intent)
}
fun Fragment.getAssetsFile(fileName: String): File {
val file = File(requireContext().filesDir, fileName)
if (!file.exists()) {
file.outputStream().use { outputStream ->
requireContext().assets.open(fileName).use { inputStream ->
inputStream.copyTo(outputStream)
}
}
}
return file
}
Working perfectly fine with Word, Excel, PPT, PDF, Mp4, Mp3, but for JPG, PNG it shows 0 size like this:
(Had tried setting the mime type image/* but no help.)
Update: Tested on Samsung Tab S5e tablet, Samsung S22 Ultra, Huawei P50 Pro and Samsung Note 9, only the Note 9 has the issue.
I tried by copying a .png and .jpeg into the assets folder and I can able to access and view both files using the above functions.
I just passed my file name along with extensions like below:
openAssetsFile("fileName.png")
OR
openAssetsFile("fileName.jpeg")
Make sure you have added the file provider in the Android Manifest file:
<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/provider_paths" />
</provider>
add this provider_paths.xml under res/xml directory
<?xml version="1.0" encoding="utf-8"?>
<paths>
<files-path
name="files"
path="." />
<external-cache-path
name="external_files"
path="." />
<external-path
name="external_files"
path="." />
</paths>
Then it should work.
`

Open files in external apps with android (API 30) file provider with write access

I want to open files from my Android app (Cordova) in external apps with write access, so they can make changes. (Example: sign a PDF).
The files to open are under external-files-path and can be opened. Unfortunately, the changes are not saved.
Since Android 11 (API Level 30) the file:// calls don't work anymore (with disableDeathOnFileUriExposure hack). With the content:// call I get no write access passed to the app.
I use the following logic to open the file (the coding is from https://github.com/pwlin/cordova-plugin-file-opener2):
File file = new File(fileName);
Intent intent = new Intent(Intent.ACTION_VIEW);
Context context = cordova.getActivity().getApplicationContext();
Uri path = FileProvider.getUriForFile(context, cordova.getActivity().getPackageName() + ".fileOpener2.provider", file);
intent.setDataAndType(path, contentType);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
if (openWithDefault) {
cordova.getActivity().startActivity(intent);
} else {
cordova.getActivity().startActivity(Intent.createChooser(intent, "Open File in..."));
}
AndroidManifest.json
<provider android:authorities="${applicationId}.fileOpener2.provider" android:exported="false" android:grantUriPermissions="true" android:name="io.github.pwlin.cordova.plugins.fileopener2.FileProvider">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="#xml/opener_paths" />
</provider>
opener_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path name="files" path="." />
<cache-path name="cache" path="." />
<external-files-path name="external-files" path="." />
<external-cache-path name="external-cache" path="." />
<external-path name="external" path="." />
</paths>

Android - FileProvider getUriForFile when the file is on an external SD

Currently, FileProvider getUriForFile method generates IllegalArgumentException when the file is on an external SD
When the file is in the device memory (under /storage/emulated/0), it works fine.
Uri videoUri = FileProvider.getUriForFile(this,
getApplicationContext().getPackageName() + ".provider",
new File(videoPath));
here videoPath had the following value :
videoPath = /storage/extSdCard/Android/data/com.podcastcutter.debug/files/episodeMp3/TEDTalks (video)/Why you should love statistics - Alan Smith.mp4
My Manifest file contains :
<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>
and here the provider_paths :
<external-path name="external_files" path="."/>
How can I modify the FileProvider configuration to solve this problem?
Thanks in advance.
Exception generated:
java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/extSdCard/Android/data/com.podcastcutter.debug/files/episodeMp3/TEDTalks (video)/Why you should love statistics - Alan Smith.mp4
android.support.v4.content.FileProvider$SimplePathStrategy.getUriForFile(FileProvider.java:711)
android.support.v4.content.FileProvider.getUriForFile(FileProvider.java:400)
Additional Configuration information:
compileSdkVersion 25
buildToolsVersion "23.0.3"
minSdkVersion 16
targetSdkVersion 25
support libraries version : 25.1.1
I added in my provider.xml this line and works fine to get file URI from SD card:
<root-path name="external_files" path="/storage/" />
Complete xml file:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path
name="external_files"
path="." />
<root-path
name="external_files"
path="/storage/" />
</paths>
How can I modify the FileProvider configuration to solve this problem?
You can't. FileProvider does not support removable storage.
Your provider path is the wrong type. Your videoPath shows a path to your app's external storage but your provider path is using external-path which links to the device root external storage. (/storage/emulated/0)
Change your provider path to be <external-files-path>...</external-files-path>

Android : FileProvider on custom external storage folder

I'm trying to set up a fileprovider for sharing file. My files are saved in a folder "AppName" in the external storage (same level as Android, Movies and Pictures folders).
Here is my file provider config :
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.mydomain.appname.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths"/>
</provider>
and the file_paths.xml :
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="mypath" path="AppName" />
</paths>
When i try to access my file with :
Uri fileUri = FileProvider.getUriForFile(activity, "com.mydomain.appname.fileprovider",
new File("/storage/emulated/0/AppName/IMG_20160419_095211.jpg"));
It returns an error:
java.lang.IllegalArgumentException:
Failed to find configured root that contains /storage/emulated/0/AppName/IMG_20160419_095211.jpg
at android.support.v4.content.FileProvider$SimplePathStrategy.getUriForFile(FileProvider.java:678)
at android.support.v4.content.FileProvider.getUriForFile(FileProvider.java:377)
It worked fine before when I was using built-in directory like Pictures or Movies, my file_paths.xml was define like this :
<external-path name="photos" path="Pictures" />
<external-path name="videos" path="Movies" />
But now I want to store my file in my own folder. Did I miss something with the FileProvider config ?
<files-path name="name" path="path" />
Represents files in the files/ subdirectory of your app's internal storage area. This subdirectory is the same as the value
returned by Context.getFilesDir().
<external-path name="name" path="path" />
Represents files in the root of the external storage area. The root
path of this subdirectory is the same as the value returned by
Environment.getExternalStorageDirectory().
<external-files-path name="name" path="path" />
Represents files in the root of your app's external storage area. The
root path of this subdirectory is the same as the value returned by
Context#getExternalFilesDir(String) Context.getExternalFilesDir(null).
for more details please check Android's doc of FileProvider.
some configuration like following picture,com.view.asim.enterprise is my package name.
First, I know this is an old post but it's the closest question posted that was similar to my problem so I'll post my solution.
The reason for that error is because the path you're supplying in the provider file is either
a) Spelled incorrectly and doesn't exist in the external-path
b) Using the /storage/emulated/0 absolute path
It returns Failed to find configured root that contains ... because it can't find that folder. So make sure you write only the directory you want to share, and ensure it's spelled correctly. Remember that when you declare external-path it is the equivelant of calling Enviornment.getExternalStorageDirectory() Since you write the name of the directory when you create your file, you don't need to provide a path in your provider file as all it does is mask whatever value is in the path with the name.
So your provider path would be:
<external-path name="my_files" />
and your code would be:
File file = new File(new File(Environment.getExternalStorageDirectory(), "myfolder"), "file.ext");
Uri uri = FileProvider.getUriForFile(context, fileProvider, file);
Your uri path would then yield the following
content://fileprovider/my_files/myfolder/file.ext
If you had supplied a path in your provider file then your uri path would look like this:
content://fileprovider/my_files/file.ext
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path
name="external_files"
path="." />
<external-files-path
name="external_files"
path="." />
<!-- FOR SD CARD-->
<root-path
name="sdcard1"
path="." />
</paths>
I fixed it
<!--THIS IS EVIL-->
<root-path
name="sdcard1"
path="." />
File Provider
java.lang.IllegalArgumentException: Failed to find configured root that contains
It is due to path is configured correctly in fileprovider_path.xml declared in manifest.
whether it may be image path external-file path etc so declare as mentioned.
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path
name="external"
path="." />
<external-files-path
name="external_files"
path="." />
<files-path
name="files"
path="." />
</paths>
I had the same thing. In my case I had to clean the build in Android Studio (Build > Clean Project) every time I modified the path of the fileprovider in 'file_paths.xml'.
In <external-path name="mypath" path="AppName" />
name="mypath" - mypath must be a specific piece from your image file name, say name="IMG" would work if all your image files have "IMG" in their name, judging by your sample code it is the case here.
path="AppName" is a folder name that you created in external for your images and it needs "/" at the end, i.e. path="AppName/"
so, <external-path name="IMG" path="AppName/" /> should do it and FileProvider should find and let other apps access your images when you request Uri with FileProvider.getUriForFile().
Hope it helps.
Replace your xml path with
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-files-path
name="extfiles" path="."/> </paths>

Android: FileProvider IllegalArgumentException Failed to find configured root that contains /data/data/**/files/Videos/final.mp4

I am trying to use FileProvider to play a video from private path.Facing
java.lang.IllegalArgumentException: Failed to find configured root that contains /data/data/XXXXX(Package)/files/Videos/final.mp4
Code:
<paths>
<files-path path="my_docs" name="Videos/" />
</paths>
Java code:
File imagePath = new File(getFilesDir(), "Videos");
File newFile = new File(imagePath, "final.mp4");
Log.d(TAG, "-------------newFile:"+newFile.exists());//True here
//Exception in below line
Uri contentUri = FileProvider.getUriForFile(this,"com.wow.fileprovider", newFile);
Manifest.xml
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.wow.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths" />
Any clues on this?
Thanks
Nitz
You have your name and your path flipped. name is what goes in the Uri, and path is the relative location within the root on the filesystem.
Go with:
<paths>
<files-path name="my_docs" path="Videos/" />
</paths>
change your provider XML to this.
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path name="external_files" path="." />
<root-path name="external_files" path="/storage/" />
</paths>
I had the very same basic situation. I defined everything correctly (files-path in xml) but there is one more thing which leads to the same exception. I add another answer just as an addition and a comment would not be well readable.
I created/read the directory where i store the files like:
context.getDir("Documents", Context.MODE_PRIVATE)
This leads to a path like:
/data/user/0/ch.myapp/app_Documents/6c3c70d5-af66-48ef-8dfc-f4341de4e1bd.docx
Then i changed creating the directory to:
File directory = new File(context.getFilesDir(), "Documents");
if (!directory.exists()) {
directory.mkdir();
}
This leads to a path like:
/data/user/0/ch.myapp/files/Documents/6c3c70d5-af66-48ef-8dfc-f4341de4e1bd.docx
According to the documentation Open a directory the two methods should be equivalent as far as i understand it. But it creates a different path... Maybe the formulation is just not clear for me in the documentation, but for me its wrongly written.
getDir(name, mode)
Creates a new directory (or opens an existing directory) within your
app's unique file system directory. This new directory appears inside
the directory provided by getFilesDir().

Categories

Resources