Using v4 Support Library FileProvider and Camera Intent

Alan Cooke
Sep 9, 2015 · 2 min read

As part of our goal to constantly improve our app, we decided to review out permissions and look to reduce the number of items we request our users to approve.

Android hasn’t helped the cause with it’s old permission model, what has been introduced in M aka Marshmallow is a vast improvement for users and developers. It offers developers the opportunity to explain to users why and what we are asking from them in terms of access to their device and or data.

But enough of a discussion on Android and it’s Permission model. Lets look at the problem at hand. We have added the FileProvider to our app in order to control access to files to and from our application.

The issue faced was when completing the action of taking a picture, the Camera/Gallery app would crash and the onActivityResult would be called.

java.lang.SecurityException: Permission Denial: opening provider android.support.v4.content.FileProvider from ProcessRecord{423c0ad0 13416:com.google.android.gallery3d/u0a10020} (pid=13416, uid=10020) that is not exported from uid 10079

An example of how to define the Support v4 FileProvider looks as follows:

<manifest>
...
<application>
...
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.mydomain.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
...
</provider>
...
</application>
</manifest>

A naive approach would be to simply update the FileProvider definition and set the XML attribute export to true. Doing that would resulted in another SecurityException.

Ultimately after a lot of head scratching and soul searching I decided to try the following method that is provided within the Context object grantUriPermission and revokeUriPermission.

Solution, give possible apps permission to the URI in order to complete the action. The following code snippet shows using the PackageManager to lookup for Activities that will respond to the ACTION_IMAGE_CAPTURE

Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);List<ResolveInfo> resolvedIntentActivities = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);for (ResolveInfo resolvedIntentInfo : resolvedIntentActivities) {
String packageName = resolvedIntentInfo.activityInfo.packageName;

context.grantUriPermission(packageName, fileUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
}

Similarly one needs to revoke access once you are done relying on the URI.

context.revokeUriPermissionfileUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);

I hope the following will help others who find themselves scratching their head and wondering what on earth is going on.

I welcome feedback on format and my communication of the issue, I am always keen to refine the craft of sharing knowledge.

Written by

Tech Lead Mobile Apps team @ Zendesk and gadget fan!

More From Medium

Related reads

Related reads

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade