I ask a user to choose a PDF document using ACTION_OPEN_DOCUMENT. The intent returns a content URI.
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.setType("application/pdf");
intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
intent.addCategory(Intent.CATEGORY_OPENABLE);
The content URI is in the format - content://com.android.providers.downloads.documents/document/raw%3A%2Fstorage%2Femulated%2F0%2FDownload%2FSample%20PDF.pdf
Now, I want the user to access the same document again - later on, from a separate activity. So I write the following code -
Intent pdfIntent = new Intent(Intent.ACTION_VIEW);
pdfIntent.setData(document.getLocalUri());
pdfIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
mContext.startActivity(pdfIntent);
But I get the following error -
java.lang.SecurityException: UID 10197 does not have permission to content://com.android.providers.downloads.documents/document/raw%3A%2Fstorage%2Femulated%2F0%2FDownload%2FSample%20PDF.pdf [user 0]; you could obtain access using ACTION_OPEN_DOCUMENT or related APIs
What am I doing wrong?
What am I doing wrong?
Most likely, your problem lies here:
I want the user to access the same document again - later on, from a separate activity
The activity that requested and received the Uri
to the content has rights to that content... but nothing else of your app does. That includes other components in your current process any any components in future processes.
If this is a separate activity, but still in the same app instance (i.e., your process has not been terminated since when you got the Uri
), you need to pass the rights to that content to the separate activity. Pass the Uri
via the "data" facet of the Intent
and use setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
as you are doing with the ACTION_VIEW
Intent
. See this sample app, where I use FLAG_GRANT_READ_URI_PERMISSION
to grant rights to a Service
to be able to read the content.
If your intention is to persist the Uri
value itself (e.g., store it as a string in a database) and use it in the future, you can instead use takePersistableUriPermission()
on ContentResolver
to request long-term access to the content. This should succeed (I don't know of any scenario where you're immediately denied access). You should have access until something drastic happens to the content, such as the user deleting it.