Reputation: 669
I'm developing an app that fills an email template and adds a picture. I want to use the app as follows: from the gallery, I share an image with my app via ACTION_SEND. My app does some processing and then shares an email with attachment.
Now I'm trying to simply get the image Uri and pass it on, but then I get a SecurityException.
protected void onCreate(Bundle savedInstanceState) {
// Read the incoming intent
Intent intent = getIntent();
String action = intent.getAction();
String type = intent.getType();
Uri imageUri;
if (Intent.ACTION_SEND.equals(action) && type != null) {
if (type.startsWith("image/")) {
imageUri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM);
}
}
// Create the outgoing intent
Intent emailIntent = new Intent(Intent.ACTION_SEND);
emailIntent.setType("message/rfc822");
if(imageUri != null){
emailIntent.putExtra(Intent.EXTRA_STREAM, imageUri);
}
startActivity(Intent.createChooser(emailIntent, getString(R.string.chooserText)));
}
Logging:
02-12 14:07:11.196 10241-10241/? E/ResolverActivity: Unable to launch as uid 10156 package ***, while running in android:ui
java.lang.SecurityException: Uid 10156 does not have permission to uri 0 @ content://com.google.android.apps.photos.contentprovider/0/1/content%3A%2F%2Fmedia%2Fexternal%2Fimages%2Fmedia%2F19546/FORMAT_JPEG/778368258
What would be the right way to do this? I have tried setting flags and permissions, but I can't find how to do this exactly.
Upvotes: 1
Views: 637
Reputation: 1377
Starting with API 16 it should suffice to add FLAG_GRANT_READ_URI_PERMISSION
to the share intent. That will grant the receiving app the permission to read the content://
URI. It also works transitively, i.e. the permission was granted to your app and you can grant it to the receiving app.
emailIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
On versions prior to API 16 this won't work because the content://
URI is stored in EXTRA_STREAM
and URI permissions only apply to URIs set with setData(Uri)
. To work around that limitation you could add the following line.
emailIntent.setData(imageUri);
On a side note: Using "message/rfc822" won't limit the chooser list to email apps. No email client I know of has an intent filter to specifically match "message/rfc822". It only works because most email clients support attaching arbitrary files, i.e. "*/*". But so do e.g. file managers, and so they also show up in that list. You might as well use the correct MIME type for the image.
Upvotes: 0
Reputation: 1006564
from the image library, I share a picture with my app
You did not explain what this means. I am interpreting this as meaning that you have added an ACTION_SEND
activity in your app, and that you are using some "share" option in the image library app to send the image to your app.
What would be the right way to do this?
To some extent, there isn't a right way to do this. Your options are:
Copy the image into your app (e.g., into internal storage), then share the local copy (e.g., via FileProvider
)
Do not use ACTION_SEND
to receive the image. Instead, use MediaStore
to find images and present your own UI with those images. Then, send the Uri
for the chosen image out via ACTION_SEND
. This probably works, though I am not as confident as I am in the other two options.
Do not use ACTION_SEND
to send the email, but instead use JavaMail or some equivalent library (requires the user give you lots of icky stuff, like email passwords), or use your Web server to send it (requires that you upload the image to your server).
Don't write this app, as the user can send the image via email themselves, from the same "share" menu in the "image library" app that they are using to trigger your app.
The problem is that you have three apps here: A, B, and C:
A is the image library
B is your app
C is the email client you are trying to invoke via ACTION_SEND
When A uses ACTION_SEND
to invoke B, A grants rights for B to work with the image. However, B has no ability to turn around and grant rights to C to work with A's image.
Upvotes: 1