i am calling an intent to share an image. this works with most providers, BUT with Google+. Google+ opens the post activity without the image and displays the toast "You can only post photos stored on your device." at the same time.
File f = storeImage(image); // f = /data/data/com.myapp/files/1333070776978.jpg
Uri uri = Uri.fromFile(f);
Intent share = new Intent(Intent.ACTION_SEND);
share.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
share.setType("image/jpeg");
share.putExtra(Intent.EXTRA_STREAM, uri);
share.putExtra(Intent.EXTRA_TITLE,"Share that title");
share.putExtra(Intent.EXTRA_SUBJECT,"Share that subject");
share.putExtra(Intent.EXTRA_TEXT,"Check that out...");
share.putExtra("sms_body", "sms body");
startActivity(Intent.createChooser(share, "Share Image"));
i save the image with
Context.openFileOutput(fileName, Context.MODE_WORLD_READABLE);
my understanding was that by setting FLAG_GRANT_READ_URI_PERMISSION, i give Google+ specific access to this file.
it works when i store the image into the MediaStore, but i actually don't wanna clutter the users image gallery.
ContentValues values = new ContentValues(2);
values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
values.put(MediaStore.Images.Media.DATA, f.getAbsolutePath());
Uri uri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
any advice is appreciated
Simon
Google+ cannot access file://
Uris from the private folder of another application. And the FLAG_GRANT_READ_URI_PERMISSION
doesn't work in this case because it's only for Uris in the "data" part of an Intent, but not for extras.
One common workaround is to add it to the gallery (via the MediaStore
) but it's not necessary to do so. The correct solution in this case is to use a FileProvider
:
FileProvider is a special subclass of ContentProvider that facilitates
secure sharing of files associated with an app by creating a
content://
Uri for a file instead of a file:///
Uri.
First place the following in your AndroidManifest.xml
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.myapp.testshare.fileprovider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
Then this file in res\xml\filepaths.xml
:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<files-path name="shared_images" path="shared_images/" />
</paths>
Then, to share an image file, make sure it's in the path specified above (i.e. shared_images
under getFilesDir()
) and build the intent as follows:
File file = getImageFileToShare();
Uri fileUri = FileProvider.getUriForFile(this, "com.myapp.testshare.fileprovider", file);
Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_STREAM, fileUri);
intent.setType("image/png");
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(intent);
(Make sure the authority specified in the getUriForFile()
method matches the one in the manifest).
This will produce a content://
Uri (like content://com.myapp.testshare.fileprovider/shared_images/img1.png
that the Google+ app will be able to access, and thus include in the post).
Simon,
Seems as if it works to set the permission after you set the uri.
share.putExtra(Intent.EXTRA_STREAM, uri);
share.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
try this one, I'm also having problems with this as its showing up in Gallery if I do an insert..
//out here is a File instance
String uriString = MediaStore.Images.Media.insertImage(getContentResolver(),
out.getAbsolutePath(),null,null);
intent.putExtra(Intent.EXTRA_STREAM,Uri.parse(uriString));
https://github.com/google-plus/google-plus-office-hours/blob/master/2012_08_14-curiosity-android-app/src/com/example/CuriosityActivity.java
If you are using a custom ContentProvider you must check that the MIME type of the images is correct. The correct MIME for a jpeg is "image/jpeg". If you return "image/jpg" in the overridden getType(Uri uri); method then Google+ fails to attach them. Most other one work, e.g. messaging and email. "image/jpg" is NOT a valid IANA MIME type:
http://www.iana.org/assignments/media-types/image
The specification of getType is clear about this, but it is very easy to miss (I did). Having solved this, I wanted to ensure others spot this because it is very unobbious.
You can use this :
Drawable drawable;
File file;
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.LOLLIPOP) {
drawable = getResources().getDrawable(imgResId);
} else {
drawable = getResources().getDrawable(imgResId, null);
}
if (drawable != null) {
Bitmap bm = ((BitmapDrawable) drawable).getBitmap();
String path = Environment.getExternalStorageDirectory()
.toString();
OutputStream fOut = null;
file = new File(path, "pic.jpg"); // the File to save to
try {
file.createNewFile();
fOut = new FileOutputStream(file);
// obtaining the Bitmap
bm.compress(Bitmap.CompressFormat.JPEG, 100, fOut);
fOut.flush();
fOut.close();
return file;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}