Home > Mobile >  Android: Pass Uri Access from one activity to another
Android: Pass Uri Access from one activity to another

Time:03-28

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:

  1. 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.
  2. 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)

  • Related