I have a helper method for choosing images and videos, let's call it Activity B
.
So, this is how it works:
// were in Activity A
// user wants to choose a video
startActivityB(callbacks);
------------------------------------
// were in Activity B now
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType("video/*");
chooseVideoLauncher.launch(intent);
------------------------------------
// were in chooseVideoLauncher now
Uri videoURI = ...;
callbacks.passVideoURI(videoURI); // this way, Activity A gets the videoURI
// do some more things...
finish(); // so the helper activity B is finished now, as the video is chosen already
------------------------------------
// were in activity A again, but now we have the videoURI
// user clicked a button: "Upload video"
uploadVideo(videoURI);
This is the error I get:
java.lang.SecurityException: Permission Denial: opening provider com.miui.gallery.provider.GalleryOpenProvider from ProcessRecord{f5899ab 29899:com.xxx} (pid=xxx, uid=xxx) that is not exported from UID xxx
I have googled the error and found this SO thread: here
@CommonsWare explains the error in a comment and links his blog post: Uri Access Lifetime: Shorter Than You Might Think
So the error happens because the helper Activity B
chose the file, so the access is tied to Activity B
. No other activity has access, and as soon as Activity B
is destroyed (what happens in my code), the access to videoURI
is completely gone. So when I later try to upload the video, it throws this error.
I tried these solutions:
- Create a local copy of the video and pass that copy to
Activity A
. This works, but is a bad solution. For longer videos the app crashes with a memory overflow. So it's not an option. - Setting the flags @CommonsWare mentioned. So the code looks like this:
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType("video/*");
intent.setFlags(FLAG_GRANT_READ_URI_PERMISSION);
intent.setFlags(FLAG_GRANT_WRITE_URI_PERMISSION);
chooseVideoLauncher.launch(intent);
But this doesn't seem to change anything. The error message remains exactly the same. Am I setting them wrong?
@CommonsWare says using a service would also be a solution. I would prefer not to create a service purely for fixing this permission error. If there's no other solution, I will of course.
But is there no way to grant Activity A
permission to that Uri as well?
CodePudding user response:
The best solution, by far, is to combine Activity A and Activity B into a single activity. Use fragments or composables for separate screens.
Setting the flags @CommonsWare mentioned. So the code looks like this:
You would not set the flags on the ACTION_PICK
Intent
. Instead, Activity B needs to start Activity A (in addition to finish()
). You would put the Uri
into the "data" facet of the Intent
(e.g., via setData()
), and you would put the flags on that Intent
. You would also need something like FLAG_ACTIVITY_REORDER_TO_FRONT
or something to avoid having two copies of Activity A on the back stack.
CodePudding user response:
For the second way Set the flags to get the long lifetime, you can try to add the following code, to get the permission, then start the activity
val contentResolver = applicationContext.contentResolver
val takeFlags: Int = Intent.FLAG_GRANT_READ_URI_PERMISSION or
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
// Check for the freshest data.
contentResolver.takePersistableUriPermission(uri, takeFlags)