Share a resource image with intents - android

I'm trying to share an image/jpg stored in the raw resource folder of my application, but the Intent seems not to find the image resource and sends nothing.
Here is my code for sending (in Kotlin):
val current = filePaths!![mViewPager!!.currentItem]
val uri = Uri.parse("android.resource://" + getPackageName() + "/" + current.resourceId)
val shareIntent : Intent = Intent()
shareIntent.setAction(Intent.ACTION_SEND)
shareIntent.putExtra(Intent.EXTRA_STREAM, uri)
shareIntent.setType("image/*")
startActivity(Intent.createChooser(shareIntent, getResources().getText(R.string.send_to)))
I also tried to send the Uri this way:
val uri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + File.pathSeparator + File.separator + File.separator + getPackageName() + "/raw/" + filename)
but it doesn't work either. Can somebody help me?

The Uri passed via EXTRA_STREAM needs to be a content Uri. And while some apps supporting ACTION_SNED are more flexible, few will handle the almost-completely-unused android.resource scheme.
Implement a ContentProvider to serve your content, and use a Uri for that content in your Intent. Also, use a concrete MIME type in your Intent — this is your content, so you know what the MIME type is.

After 3 days of headaches i finally solved... what i've done was just save the image resource and then serve it:
val current = filePaths!![mViewPager!!.currentItem]
val imagePath = File(Environment.getExternalStorageDirectory(), "_temp")
if(!imagePath.exists())
imagePath.mkdirs()
val imageToShare = File(imagePath, "share.jpeg")
if(imageToShare.exists())
imageToShare.delete()
imageToShare.createNewFile()
val out = FileOutputStream(imageToShare)
val imageToSave = utils.createBitmap(current.resourceId)
imageToSave.compress(Bitmap.CompressFormat.JPEG, 100, out)
out.flush()
out.close()
val uri = Uri.fromFile(imageToShare)
val shareIntent : Intent = Intent()
shareIntent.setAction(Intent.ACTION_SEND)
shareIntent.putExtra(Intent.EXTRA_STREAM, uri)
shareIntent.setType("image/jpeg")
startActivity(Intent.createChooser(shareIntent, getResources().getText(R.string.send_to)))
:)

Related

How can I set the ACTION_OPEN_DOCUMENT_TREE start path the first time a user uses my app?

I've seen a lot of questions regarding setting the start Uri for the Intent.ACTION_OPEN_DOCUMENT_TREE but all of those require a Uri that comes from having used that folder picker before.
What I want to do is send my users directly to the Download folder when picking the folder but I do not know how to convert /storage/emulated/0/Download to a Uri that I can pass as an extra using DocumentsContract.EXTRA_INITIAL_URI.
Is there a way to convert any file path to a DocumentsContract style Uri?
Edit: Just to be clear, I'm talking about the uri passed here:
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
.setFlags(
Intent.FLAG_GRANT_READ_URI_PERMISSION
or Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
)
.putExtra(DocumentsContract.EXTRA_INITIAL_URI, uri)
We manupulate INITIAL_URI of .createOpenDocumentTreeIntent().
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
StorageManager sm = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
Intent intent = sm.getPrimaryStorageVolume().createOpenDocumentTreeIntent();
//String startDir = "Android";
//String startDir = "Download"; // Not choosable on an Android 11 device
//String startDir = "DCIM";
//String startDir = "DCIM/Camera"; // replace "/", "%2F"
String startDir = "DCIM%2FCamera";
Uri uri = intent.getParcelableExtra("android.provider.extra.INITIAL_URI");
String scheme = uri.toString();
Log.d(TAG, "INITIAL_URI scheme: " + scheme);
scheme = scheme.replace("/root/", "/document/");
scheme += "%3A" + startDir;
uri = Uri.parse(scheme);
intent.putExtra("android.provider.extra.INITIAL_URI", uri);
Log.d(TAG, "uri: " + uri.toString());
((Activity) context).startActivityForResult(intent, REQUEST_ACTION_OPEN_DOCUMENT_TREE);
return;
}
The logs will print something like:
INITIAL_URI scheme: content://com.android.externalstorage.documents/root/primary
uri: content://com.android.externalstorage.documents/document/primary%3ADownload
The easiest way to do it is:
for example, if i want the user to select MEDIA folder of WhatsApp
val i = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
val initial = Uri.parse("content://com.android.externalstorage.documents/tree/primary%3AAndroid%2Fmedia%2Fcom.whatsapp%2FWhatsApp%2FMedia")
i.putExtra(DocumentsContract.EXTRA_INITIAL_URI, initial)
startActivityForResult(i, SCOPED_REQUEST_WA)

Kotlin - Share audio file from raw resource

I have a soundboard app for android and am trying to make users be able to share the sounds in the app via messenger, gmail etc. This is the code I've tried to use for that purpose:
Fragment:
val uri = SoundProvider.getUri(4,(activity as MainActivity).packageName)
val share = Intent(Intent.ACTION_SEND)
share.type = "audio/*"
share.putExtra(Intent.EXTRA_STREAM, uri)
startActivity(Intent.createChooser(share, "Share Sound File"))
getUri function:
fun getUri(id: Int, packageName: String):Uri{
val uri = Uri.parse(
ContentResolver.SCHEME_ANDROID_RESOURCE
+ File.pathSeparator + File.separator + File.separator
+ packageName
+ File.separator
+ R.raw.random_sound
)
return uri
}
Unfortunately, this code doesn't seem to work, when I click on one of the share options in the app ( for example gmail), it just opens a blank email with no attachments. Similarly with other apps. Does anyone happen to know how to make this work?
I think this is the right way means using File.pathSeparator 2 times and not 3 times consecutively:
ContentResolver.SCHEME_ANDROID_RESOURCE
+ File.pathSeparator + File.separator
+ packageName
+ File.separator
+ R.raw.random_sound

Posting Multiple Images to Instagram using Intents

Instagram allows a single image or video to be uploaded programmatically from an Android app via Android Intents. I have been able to do this successfully. What I want to know is it possible for Instagram to handle multiple images using Intents? Not much to no information on this unfortunately. The following is my last attempt which opens Instagram briefly then closes with a toast message saying "Unable to load image".
Have tried both Intent.ACTION_SEND and Intent.ACTION_SEND_MULTIPLE
val fileUris = ArrayList<Uri>()
val newFile = File("/data/user/0/com.myapp.android/files/media/961087022.jpg")
val contentUri = getUriForFile(this, "com.myapp.fileprovider", newFile)
grantUriPermission("com.instagram.android", contentUri, FLAG_GRANT_READ_URI_PERMISSION)
fileUris.add(contentUri)
val newFile2 = File("/data/user/0/com.myapp.android/files/media/961146948.jpg")
val contentUri2 = getUriForFile(this, "com.myapp.fileprovider", newFile2)
grantUriPermission("com.instagram.android", contentUri2, FLAG_GRANT_READ_URI_PERMISSION)
fileUris.add(contentUri2)
val shareIntent = Intent(Intent.ACTION_SEND)
shareIntent.type = "image/*"
shareIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
shareIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, fileUris)
shareIntent.`package` = "com.instagram.android"
startActivity(Intent.createChooser(shareIntent, "Share to"))
I was looking on how to share multiple video files to instagram stories.. I couldn't find how to do it reading the facebook documentation.
Instead i set the intent to send multiple files and set the intent package to "com.instagram.android", and surprisingly it worked..
Intent share = new Intent(Intent.ACTION_SEND_MULTIPLE) ;
share.setType("video/*");
share.putExtra(Intent.EXTRA_SUBJECT, "abc");
share.putExtra(Intent.EXTRA_TITLE, "abcd");
ArrayList<Uri> files = new ArrayList<Uri>();
for (String path : filesToSend) {
File myFiles = new File(path);
Uri doneUri = FileProvider.getUriForFile(Objects.requireNonNull(getApplicationContext()),
BuildConfig.APPLICATION_ID + ".provider", myFiles);
files.add(doneUri);
}
share.setPackage("com.instagram.android");
share.putParcelableArrayListExtra(Intent.EXTRA_STREAM, files);
startActivity(share);
Hope, this helps!!

Applications resolved by Intents with Extra "EXTRA_INITIAL_INTENTS" not shown

I am trying to share file with email clients and Google Drive. Now, in following code, only Google drive is opening and email clients are not opening at all. I can provide equivalent Java code of following code if required
val photoURI: Uri = FileProvider.getUriForFile(this, "com.emerson.oversight.com.emerson.oversight.provider",
File(this.cacheDir.path + "/SensorReport.pdf"))
val emailIntent = Intent(Intent.ACTION_SENDTO)
emailIntent.data = Uri.parse("mailto:")
emailIntent.putExtra(Intent.EXTRA_STREAM, photoURI)
emailIntent.putExtra(Intent.EXTRA_EMAIL, "asd#dsa.dsa")
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "dsadsada")
emailIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
val driveIntent = Intent()
driveIntent.`package`= "com.google.android.apps.docs"
driveIntent.action = Intent.ACTION_VIEW
val fileID = File(this.cacheDir.path + "/SensorReport.pdf")
val url = "https://docs.google.com/file/d/" + fileID
driveIntent.data = Uri.parse(url)
val openInChooser = Intent.createChooser(driveIntent, getString(R.string.share_using))
openInChooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, arrayListOf(emailIntent))
startActivity(openInChooser)
Please help
You were almost there, the only missing piece in the puzzle is the getPackageManager().queryIntentActivities method that will return all activities that can handle your email intent. With the ResolveInfo returned you can build an intent for each email option to be displayed in the chooser. Then you can pass the array of those intents as Intent.EXTRA_INITIAL_INTENTS. You could even exclude certain packages if you like here. So the final part of your code would look something like this:
val openInChooser = Intent.createChooser(driveIntent, getString(R.string.share_using))
val emailOptionIntents = mutableListOf<Intent>()
val resInfo = getPackageManager().queryIntentActivities(emailIntent, 0)
if (!resInfo.isEmpty()) {
for (resolveInfo in resInfo) {
val emailOptionIntent = Intent(Intent.ACTION_SENDTO)
emailOptionIntent.data = Uri.parse("mailto:")
emailOptionIntent.putExtra(Intent.EXTRA_STREAM, photoURI)
emailOptionIntent.putExtra(Intent.EXTRA_EMAIL, "asd#dsa.dsa")
emailOptionIntent.putExtra(Intent.EXTRA_SUBJECT, "dsadsada")
emailOptionIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
emailOptionIntent.`package` = resolveInfo.activityInfo.packageName
emailOptionIntents.add(emailOptionIntent)
}
}
openInChooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, emailOptionIntents.toTypedArray())
startActivity(openInChooser)

Share Video From Android App

Ours is a video hosting portal where users can upload and earn from their videos based on the views they get. We have recently launched an Android App and trying to integrate Share button to each video. Here is the code what we have placed
Intent intent = new Intent();
try {
URL url = new URL("https://www.clipsnow.com/videos/images/thumbnails/230/10493.jpg");
Bitmap image = BitmapFactory.decodeStream(url.openConnection().getInputStream());
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(Intent.ACTION_SEND);
intent.setData(Uri.parse("https://www.clipsnow.com"));
intent.putExtra(Intent.EXTRA_TEXT,msg);
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_STREAM, getImageUri(v.getContext(), image));
intent.setType("image/*");
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
v.getContext().startActivity(Intent.createChooser(intent, "Share Video"));
} catch (Exception e) {
e.printStackTrace();
}
When we share any video with this, only thumbnail image is getting shared along with the video title. But, we need the video URL will get shared and when user tap on the URL, user will be taken to our app.
How can we do that?
This worked with me. Give a try!
File videoFile = new File(filePath);
Uri videoURI = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
? FileProvider.getUriForFile(mContext, mContext.getPackageName(), videoFile)
: Uri.fromFile(videoFile);
ShareCompat.IntentBuilder.from(getActivity())
.setStream(videoURI)
.setType("video/mp4")
.setChooserTitle("Share video...")
.startChooser();
You should download video first. Then you can share with using ACTION_SEND.
String path = ""; //should be local path of downloaded video
ContentValues content = new ContentValues(4);
content.put(MediaStore.Video.VideoColumns.DATE_ADDED,
System.currentTimeMillis() / 1000);
content.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4");
content.put(MediaStore.Video.Media.DATA, path);
ContentResolver resolver = getApplicationContext().getContentResolver();
Uri uri = resolver.insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, content);
Intent sharingIntent = new Intent(Intent.ACTION_SEND);
sharingIntent.setType("video/*");
sharingIntent.putExtra(Intent.EXTRA_SUBJECT, "Hey this is the video subject");
sharingIntent.putExtra(Intent.EXTRA_TEXT, "Hey this is the video text");
sharingIntent.putExtra(Intent.EXTRA_STREAM,uri);
startActivity(Intent.createChooser(sharingIntent,"Share Video");
I guess, all the other solutions are obsolete. Here is the working solution for sharing the video to any platform (Youtube, Gmail, Hangout, Whatsapp etc),
startActivity(
Intent.createChooser(
Intent().setAction(Intent.ACTION_SEND)
.setType("video/*")
.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
.putExtra(
Intent.EXTRA_STREAM,
getVideoContentUri(this, File(currentVideo.videoPath))
), resources.getString(R.string.share_video)
)
)
Below is the getVideoContentUri method,
/**
* Return the URI for a file. This URI is used for
* sharing of video.
* NOTE: You cannot share a file by file path.
*
* #param context Context
* #param videoFile File
* #return Uri?
*/
fun getVideoContentUri(context: Context, videoFile: File): Uri? {
var uri: Uri? = null
val filePath = videoFile.absolutePath
val cursor = context.contentResolver.query(
MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
arrayOf(MediaStore.Video.Media._ID),
MediaStore.Video.Media.DATA + "=? ",
arrayOf(filePath), null)
if (cursor != null && cursor.moveToFirst()) {
val id = cursor.getInt(cursor
.getColumnIndex(MediaStore.MediaColumns._ID))
val baseUri = Uri.parse("content://media/external/video/media")
uri = Uri.withAppendedPath(baseUri, "" + id)
} else if (videoFile.exists()) {
val values = ContentValues()
values.put(MediaStore.Video.Media.DATA, filePath)
uri = context.contentResolver.insert(
MediaStore.Video.Media.EXTERNAL_CONTENT_URI, values)
}
closeCursor(cursor)
return uri
}
To send the video in android 10 and above use this. I used this to send the video from local storage to WhatsApp.
public void shareVideo(String filepath)
{
Intent shareintent=new Intent("android.intent.action.SEND");
shareintent.setType("video/mp4");
shareintent.putExtra("android.intent.extra.STREAM",
Uri.parse(filepath));
startActivity(Intent.createChooser(shareintent,"share"));
}

Categories

Resources