My application uses FileProvider
to get a content URI for a file created in a subdirectory on the external storage and grant permissions to the selected camera application so it can save a photo to that file. It works like a charm on every device and emulator except one which I don't own - Huawei Honor 7 (I have a crash log from that device). I'm trying to understand the problem and find a way to fix it.
AndroidManifest.xml
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="<package>.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_provider_paths" />
</provider>
file_provider_paths.xml
<paths>
<external-files-path name="external_storage" path="" />
</paths>
When I create an empty file to share with the camera application, I obtain the base external directory path using Context.getExternalFilesDir(null)
.
It usually returns a path like this: /storage/emulated/0/Android/data/<package>/files
which is the same as these:
Context.getExternalFilesDirs(null)[0]
ContextCompat.getExternalFilesDirs(context, null)[0]
And I put the file a bit deeper, e.g. /storage/emulated/0/Android/data/<package>/files/247/images/ad4b7cd7-8917-43d5-8f6c-69555d76c0e0
Then I call FileProvider.getUriForFile(context, "<package>.fileprovider", file)
As I said, it works properly on everything I have, both emulators and devices, with APIs 19 to 25.
Now, there is that crash:
Caused by java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/0123-4567/Android/data/<package>/files/42/images/51e4b571-67e4-4e7d-abb0-0ae921d339f4
at android.support.v4.content.FileProvider$SimplePathStrategy.getUriForFile(FileProvider.java:711)
at android.support.v4.content.FileProvider.getUriForFile(FileProvider.java:400)
I have found out that the current FileProvider
implementation matches the external-files-path
tag with this piece of code:
} else if (TAG_EXTERNAL_FILES.equals(tag)) {
File[] externalFilesDirs = ContextCompat.getExternalFilesDirs(context, null);
if (externalFilesDirs.length > 0) {
target = externalFilesDirs[0];
}
}
So my idea is that maybe Context.getExternalFilesDir(null)
gives a different storage directory than ContextCompat.getExternalFilesDirs(context, null)
at 0
index. If so, I would create a file on the storage which is not supported by the FileProvider
.
I have also found some issue reported to Google regarding this limitation.
Do you think that's the real root cause or do you have any other ideas?