How to Filter Specific Apps For Action_Send Intent (And Set a Different Text For Each App)

How to filter specific apps for ACTION_SEND intent (and set a different text for each app)

To my knowledge, StackOverflow has lots of people asking this question in various ways, but nobody has answered it completely yet.

My spec called for the user to be able to choose email, twitter, facebook, or SMS, with custom text for each one. Here is how I accomplished that:

public void onShareClick(View v) {
Resources resources = getResources();

Intent emailIntent = new Intent();
emailIntent.setAction(Intent.ACTION_SEND);
// Native email client doesn't currently support HTML, but it doesn't hurt to try in case they fix it
emailIntent.putExtra(Intent.EXTRA_TEXT, Html.fromHtml(resources.getString(R.string.share_email_native)));
emailIntent.putExtra(Intent.EXTRA_SUBJECT, resources.getString(R.string.share_email_subject));
emailIntent.setType("message/rfc822");

PackageManager pm = getPackageManager();
Intent sendIntent = new Intent(Intent.ACTION_SEND);
sendIntent.setType("text/plain");


Intent openInChooser = Intent.createChooser(emailIntent, resources.getString(R.string.share_chooser_text));

List<ResolveInfo> resInfo = pm.queryIntentActivities(sendIntent, 0);
List<LabeledIntent> intentList = new ArrayList<LabeledIntent>();
for (int i = 0; i < resInfo.size(); i++) {
// Extract the label, append it, and repackage it in a LabeledIntent
ResolveInfo ri = resInfo.get(i);
String packageName = ri.activityInfo.packageName;
if(packageName.contains("android.email")) {
emailIntent.setPackage(packageName);
} else if(packageName.contains("twitter") || packageName.contains("facebook") || packageName.contains("mms") || packageName.contains("android.gm")) {
Intent intent = new Intent();
intent.setComponent(new ComponentName(packageName, ri.activityInfo.name));
intent.setAction(Intent.ACTION_SEND);
intent.setType("text/plain");
if(packageName.contains("twitter")) {
intent.putExtra(Intent.EXTRA_TEXT, resources.getString(R.string.share_twitter));
} else if(packageName.contains("facebook")) {
// Warning: Facebook IGNORES our text. They say "These fields are intended for users to express themselves. Pre-filling these fields erodes the authenticity of the user voice."
// One workaround is to use the Facebook SDK to post, but that doesn't allow the user to choose how they want to share. We can also make a custom landing page, and the link
// will show the <meta content ="..."> text from that page with our link in Facebook.
intent.putExtra(Intent.EXTRA_TEXT, resources.getString(R.string.share_facebook));
} else if(packageName.contains("mms")) {
intent.putExtra(Intent.EXTRA_TEXT, resources.getString(R.string.share_sms));
} else if(packageName.contains("android.gm")) { // If Gmail shows up twice, try removing this else-if clause and the reference to "android.gm" above
intent.putExtra(Intent.EXTRA_TEXT, Html.fromHtml(resources.getString(R.string.share_email_gmail)));
intent.putExtra(Intent.EXTRA_SUBJECT, resources.getString(R.string.share_email_subject));
intent.setType("message/rfc822");
}

intentList.add(new LabeledIntent(intent, packageName, ri.loadLabel(pm), ri.icon));
}
}

// convert intentList to array
LabeledIntent[] extraIntents = intentList.toArray( new LabeledIntent[ intentList.size() ]);

openInChooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, extraIntents);
startActivity(openInChooser);
}

I found bits of how to do this in various places, but I haven't seen all of it in one place anywhere else.

Note that this method also hides all the silly options that I don't want, like sharing over wifi and bluetooth.

Hope this helps someone.

Edit:
In a comment, I was asked to explain what this code is doing. Basically, it's creating an ACTION_SEND intent for the native email client ONLY, then tacking other intents onto the chooser. Making the original intent email-specific gets rid of all the extra junk like wifi and bluetooth, then I grab the other intents I want from a generic ACTION_SEND of type plain-text, and tack them on before showing the chooser.

When I grab the additional intents, I set custom text for each one.

Edit2: It's been awhile since I posted this, and things have changed a bit. If you are seeing gmail twice in the list of options, try removing the special handling for "android.gm" as suggested in a comment by @h_k below.

Since this one answer is the source of nearly all my stackoverflow reputation points, I have to at least try to keep it up to date.

Set a different text to an ACTION_SEND intent according to the application selected in the chooser

The simple answer still stands is that u cannot do that, there is no way to identify which application is going to handle ur intent, that choice is left onto the user. You can provide user options for facebook and twitter directly which might be useful

Exception with filtering out specific apps when using the ACTION_SEND intent?[DUPLICATED]

It is because of Intent.EXTRA_INITIAL_INTENTS flag; This flag tell chooser to add Apps that support specific intent along the initial Intent's Apps.
Since Gmail app supports both emailIntent and sendIntent it appears twice in the list.
You can simply remove android.gm part since Gmail support message/rfc822 messages anyway..

Update:
Since you create chooser for two Intent you have to query both intent and only add Apps that aren't duplicate, so Query Email Intent first, add all apps, then query Send Intent but Only add Applications that their Package names aren't already present.

ACTION_SEND: Possible to filter applications which accept attachments?

  intent.setType("message/rfc822");

Use this.

Android ACTION_SEND different texts for each application

In general you can't be sure which application will receive your ACTION_SEND intent.

This answer explains why you probably shouldn't do customization based on predicting which application the user will end up in.

This answer explains a workaround for TwiDroyd, which you probably shouldn't use but may help you in the short term.

How to filter specific apps for ACTION_SEND intent (and set a different text for each app)

To my knowledge, StackOverflow has lots of people asking this question in various ways, but nobody has answered it completely yet.

My spec called for the user to be able to choose email, twitter, facebook, or SMS, with custom text for each one. Here is how I accomplished that:

public void onShareClick(View v) {
Resources resources = getResources();

Intent emailIntent = new Intent();
emailIntent.setAction(Intent.ACTION_SEND);
// Native email client doesn't currently support HTML, but it doesn't hurt to try in case they fix it
emailIntent.putExtra(Intent.EXTRA_TEXT, Html.fromHtml(resources.getString(R.string.share_email_native)));
emailIntent.putExtra(Intent.EXTRA_SUBJECT, resources.getString(R.string.share_email_subject));
emailIntent.setType("message/rfc822");

PackageManager pm = getPackageManager();
Intent sendIntent = new Intent(Intent.ACTION_SEND);
sendIntent.setType("text/plain");


Intent openInChooser = Intent.createChooser(emailIntent, resources.getString(R.string.share_chooser_text));

List<ResolveInfo> resInfo = pm.queryIntentActivities(sendIntent, 0);
List<LabeledIntent> intentList = new ArrayList<LabeledIntent>();
for (int i = 0; i < resInfo.size(); i++) {
// Extract the label, append it, and repackage it in a LabeledIntent
ResolveInfo ri = resInfo.get(i);
String packageName = ri.activityInfo.packageName;
if(packageName.contains("android.email")) {
emailIntent.setPackage(packageName);
} else if(packageName.contains("twitter") || packageName.contains("facebook") || packageName.contains("mms") || packageName.contains("android.gm")) {
Intent intent = new Intent();
intent.setComponent(new ComponentName(packageName, ri.activityInfo.name));
intent.setAction(Intent.ACTION_SEND);
intent.setType("text/plain");
if(packageName.contains("twitter")) {
intent.putExtra(Intent.EXTRA_TEXT, resources.getString(R.string.share_twitter));
} else if(packageName.contains("facebook")) {
// Warning: Facebook IGNORES our text. They say "These fields are intended for users to express themselves. Pre-filling these fields erodes the authenticity of the user voice."
// One workaround is to use the Facebook SDK to post, but that doesn't allow the user to choose how they want to share. We can also make a custom landing page, and the link
// will show the <meta content ="..."> text from that page with our link in Facebook.
intent.putExtra(Intent.EXTRA_TEXT, resources.getString(R.string.share_facebook));
} else if(packageName.contains("mms")) {
intent.putExtra(Intent.EXTRA_TEXT, resources.getString(R.string.share_sms));
} else if(packageName.contains("android.gm")) { // If Gmail shows up twice, try removing this else-if clause and the reference to "android.gm" above
intent.putExtra(Intent.EXTRA_TEXT, Html.fromHtml(resources.getString(R.string.share_email_gmail)));
intent.putExtra(Intent.EXTRA_SUBJECT, resources.getString(R.string.share_email_subject));
intent.setType("message/rfc822");
}

intentList.add(new LabeledIntent(intent, packageName, ri.loadLabel(pm), ri.icon));
}
}

// convert intentList to array
LabeledIntent[] extraIntents = intentList.toArray( new LabeledIntent[ intentList.size() ]);

openInChooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, extraIntents);
startActivity(openInChooser);
}

I found bits of how to do this in various places, but I haven't seen all of it in one place anywhere else.

Note that this method also hides all the silly options that I don't want, like sharing over wifi and bluetooth.

Hope this helps someone.

Edit:
In a comment, I was asked to explain what this code is doing. Basically, it's creating an ACTION_SEND intent for the native email client ONLY, then tacking other intents onto the chooser. Making the original intent email-specific gets rid of all the extra junk like wifi and bluetooth, then I grab the other intents I want from a generic ACTION_SEND of type plain-text, and tack them on before showing the chooser.

When I grab the additional intents, I set custom text for each one.

Edit2: It's been awhile since I posted this, and things have changed a bit. If you are seeing gmail twice in the list of options, try removing the special handling for "android.gm" as suggested in a comment by @h_k below.

Since this one answer is the source of nearly all my stackoverflow reputation points, I have to at least try to keep it up to date.



Related Topics



Leave a reply



Submit