Android Tidbits : Understanding Intent.FLAG_GRANT_READ_URI_PERMISSION and Intent.FLAG_GRANT_WRITE_URI_PERMISSION

Anish Kothari
2 min readJan 7, 2020

--

Android Sharing through ContentUris

What are these flags?

These are flags added to an Intent sharing a ContentUri and used to grant Read and Write access respectively to the ContentUri.
They are used for accessing system data as well as for communication between apps.

Why use these flags?

These flags grant temporary permissions to the app processing the Content URI and once the workflow is completed, these permissions are automatically revoked.

The most common usage is by calling startActivityForResult(). The permissions stay active as long as the processing activity is alive.

The advantage of using this over alternate ways like Context.grantUriPermission() is that the owner of the Content URI doesn’t have to keep a track of granting/revoking the permission to each requesting app and thereby, security risks are lowered.

Usage — Apps exposing a ContentUri

A very simple example is below.

Intent leafVillageIntent = new Intent("konoha.taijutsu.attack");
leafVillageIntent.setData(leafHurricaneUri);
leafVillageIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

IMPORTANT : These flags only work on Uris passed through the setData() method or through the rarely used setClipData() method.
If a Uri is passed through defined/custom Bundle extras, the permission won’t be granted.

Usage — Apps consuming a ContentUri

An app querying/processing a ContentUri can retrieve it and can check if the flag was passed through simple bit operations.

Uri receivedUri = receivedIntent.getData();//Check if flags are passed
int receivedFlags = receivedIntent.getFlags();
if ((receivedFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0)
{
Log.e(TAG, "Read URI permission flag not available");
}

Android System Intents : Special cases

Whenever a file is “shared” across Android from/to any app, the actions for the Intent are commonly -

Intent.ACTION_SEND, Intent.ACTION_SEND_MULTIPLE

These are used when the files are single/more than one accordingly as the names suggest.

But, in these cases, the Uri(s) aren’t passed through setData()!
They are instead available as value of a defined Bundle extra key called as Intent.EXTRA_STREAM as either a Parcelable or a ParcelableArrayList.

How do these work?

Android natively handles such special system intents and allows the flags to work even on URIs not passed through setData()

http://androidxref.com/9.0.0_r3/xref/frameworks/base/core/java/android/content/Intent.java#10349

So, if your app has to use these system intents (Eg : A Camera/Gallery/File Explorer/Documents app) the URIs can be sent/read through the defined Bundle extra Intent.EXTRA_STREAM and the flags would still work!

Examples -

Sharing a single Uri

Intent leafVillageIntent = new Intent(Intent.ACTION_SEND);
leafVillageIntent.putExtra(Intent.EXTRA_STREAM, leafHurricaneUri);
leafVillageIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

Sharing multiple Uris

Intent leafVillageIntent = new Intent(Intent.ACTION_SEND_MULTIPLE);
leafVillageIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM,
listOfUris);
leafVillageIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

Thank you for reading!

--

--

Anish Kothari

Lead Android Developer at IBM MaaS360 by day …. and also by night