198

How can you filter out specific apps when using the ACTION_SEND intent? This question has been asked in various ways, but I haven't been able to gather a solution based on the answers given. Hopefully someone can help. I would like to provide the ability to share within an app. Following Android Dev Alexander Lucas' advice, I'd prefer to do it using intents and not using the Facebook/Twitter APIs.

Sharing using ACTION_SEND intent

Sharing using the ACTION_SEND intent is great, but the problem is (1) I don't want every sharing option there, I'd rather limit it to FB, Twitter, and Email, and (2) I don't want to share the same thing to each sharing app. For example, in my twitter share I'm going to include some mentions and hashtags limited it to 140 chars or less, while the facebook share is going to include a link and a feature image.

Is it possible to limit the options for ACTION_SEND (share) intent? I've seen something about using PackageManager and queryIntentActivities, but haven't been able to figure out the connection between the PackageManager and the ACTION_SEND intent.

OR

Rather than filter the sharing apps, my problem could also be solved if I could use the ACTION_SEND intent to go directly to facebook or twitter rather than popping up the dialog. If that were the case then I could create my own dialog and when they click "Facebook" create a Facebook-specific intent and just send them all the way to Facebook. Same with Twitter.

OR is it not possible? Are the Facebook and Twitter APIs the only way?

Community
  • 1
  • 1
Kyle Clegg
  • 38,547
  • 26
  • 130
  • 141
  • Possible duplicate: [custom-filtering-of-intent-chooser-based-on-installed-android-package-name][1] [1]: http://stackoverflow.com/questions/5734678/custom-filtering-of-intent-chooser-based-on-installed-android-package-name – Asaf Pinhassi Jun 11 '13 at 06:44
  • 1
    This blogpost seems to be the perfect answer: http://hkdevtips.blogspot.com/2013/02/customize-your-actionchooser-intent.html – olshevski Oct 21 '13 at 18:56
  • 2
    hey friend... when i am click my send button then open share dialog and share dialog list is "gmail ,email ,zapiya , hookup "etc. but not showing facebook ,whatsapp,facebook messanger ,hike hangouts ... how can i show its ?? – GB_Bhayani ツ Jun 26 '14 at 09:49
  • how to not show the chooser when there is only one item/option of intent action on android 6.0? the problem doesn't show on less than android 6.0 – zys Mar 16 '16 at 07:50

12 Answers12

329

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.

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.

starball
  • 20,030
  • 7
  • 43
  • 238
dacoinminster
  • 3,637
  • 2
  • 18
  • 23
  • 1
    I'm using this code, but somehow evernote is sneaking into the list. When I check the package names, it's com.evernote, so I'm not sure why this is happening. – James Harpe Aug 20 '13 at 14:28
  • @JamesHarpe I bet Evernote supports intent type "message/rfc822", so it shows up in the pared-down list that we're starting from. If there's a sneaky way to further customize this to exclude Evernote, I'd be interested to hear it! – dacoinminster Oct 02 '13 at 19:42
  • @dacoinminster Hi, i have added this code it is showing gmail & facebook app to choose but not messaging app in my micromax canvas HD phone. Can u help me what i can change here? – kumar Apr 07 '14 at 16:04
  • 1
    @user2249287 I'd suggest you step through the code until you see the messaging app that is getting skipped, then look at the packagename to determine what string you need to add to whitelist that app to appear. – dacoinminster Apr 07 '14 at 19:33
  • @dacoinminster. Hi, I do not understand the purpose of the line "emailIntent.setPackage(packageName);" in your solution. Why is it in the "for" loop? Please can you explain it? Thanks! – Gilbou Jun 22 '14 at 06:33
  • @dacoinminster another question... Do you have a solution to prevent Facebook and Twitter to appear in the list but not Facebook Messenger. Basically I want to prevent my users to broadcast private information on their Facebook walls or Twitter. But I want them to be able to use the Facebook Messenger in the list (because some people use it as they would use Whatsapp, SMS or emails)... – Gilbou Jun 22 '14 at 06:57
  • 1
    @Gilbou Hi! Sorry - it's been a long time since I looked at this code . . . As I recall, the setPackage command chooses the single intent which you will append everything else to. To include or exclude various other intents, I recommend stepping through the code and looking at the Package names. – dacoinminster Jun 23 '14 at 15:21
  • 2
    To filter for ONLY the email apps the user has you can use the second answer from this question: http://stackoverflow.com/questions/8701634/send-email-intent. It doesnt requiring using a data type of message/rfc822 which other apps, such as EverNote in this case, use too. – mpellegr Aug 11 '14 at 15:41
  • this makes GMAIL appear twice in the chooser – frankelot Mar 09 '15 at 13:43
  • @feresr It's been awhile since I posted this - things may have changed. Some tweaking may be required. It should be possible to de-duplicate gmail - try stepping through the code as it executes. If you solve the problem, post your improvement here, and I'll try to update the answer appropriately. – dacoinminster Mar 10 '15 at 14:38
  • 2
    @dacoinminster your code has been awesome for letting me define different text for apps like Twitter and Whatsapp. To remove the duplicate gmail, I just took "android.gm" out of the equation. I still get gmail and the built-in mail app in the chooser list and the subject and text are still intact. – h_k Jun 10 '15 at 15:08
  • @h_k Thanks for the tip! I updated the answer to include your suggestion. – dacoinminster Jun 10 '15 at 23:27
  • 1
    @dacoinminster I have tried your solution for filter specific app for send intent. It's working fine when I have sent (share) text message using this line shareIntent.setType("message/rfc822"), but it's not working for share image. I have use following line for share image. i.e.shareIntent.setType("image/*"); – Maroti Jun 16 '15 at 13:21
  • 1
    @Shailesh I'm sorry - I've never tried sharing images before using this method. You might need to create a new question about that. – dacoinminster Jun 16 '15 at 22:56
  • Any Luck with Images?? – kgandroid Aug 17 '15 at 08:27
  • hii.. i want the name of an app in callback method or after returning from `startActivity(openInChooser); ` on which i have shared the data? is it possible? – iMDroid Sep 24 '15 at 12:07
  • Does this way still works with Android 5.0+? I got always duplicated entries on the emulator at least. No problem for Android < 5.0 – Daniele Sep 27 '15 at 01:45
  • On my xperia Z3 the package name for sms/mms is `com.sonyericsson.conversations`. Any other way to safely match sms? – Hjalmar Dec 29 '15 at 11:26
  • Text messenger was not showing. I had to add packageName.contains("messaging") (e.g. com.google.android.apps.messaging). I'm running 6.0.1 on a Nexus 5X. – Paul Jan 12 '16 at 14:43
  • as for me, the main point is "emailIntent.setPackage(packageName);" – SDJSK Mar 17 '17 at 19:12
  • @Dacoinminster I want to display only sms app but i tried your code for sms app only and did not get solution please help me – humayoon siddique Jul 20 '17 at 13:30
  • @humayoonsiddique I expect you will have to step through the code in debug mode to see what your options are. – dacoinminster Jul 20 '17 at 19:58
  • @dacoinminster in that steps intentList.add(new LabeledIntent(intent, packageName, ri.loadLabel(pm), ri.icon)); i check in debug mode in intentlist have only one app detail that is sms but when go for display its show me all sharing app – humayoon siddique Jul 21 '17 at 05:20
  • @dacoinminster here is my problem https://stackoverflow.com/questions/45214085/how-to-share-sms-app-only-on-share-dialog – humayoon siddique Jul 21 '17 at 05:59
  • Any specific reason to pass View? – sziraqui Dec 17 '17 at 11:12
  • 1
    Is anyone having trouble with this working on Android Q? I had used this solution in the past and it worked great. However, now it seems like the EXTRA_TEXT that is used in the intent that is used for the chooser (in this case, emailIntent) is applied to all other intents that are added with EXTRA_INITIAL_INTENTS), even if those other intents have a different EXTRA_TEXT specified. – etrado Sep 05 '19 at 19:44
28

If you want a customized option then you should not rely on the default dialog provided by android for this action.

What you need to do instead is roll out your own. You will need to query the PackageManager on which packages handle the action you require and then based on the reply, you apply filtering and customized text.

Specifically, take a look at the method queryIntentActivities of the PackageManager class. You build the intent that would launch the default dialog (the ACTION_SEND intent), pass that to this method and you will receive a list of objects that contain info on the activities that can handle that intent. Using that, you can choose the ones you want.

Once you build your list of packages you want to present, you need to build your own list dialog (preferably an activity with the dialog theme) which will display that list.

One thing to note though is that it's very hard to make that custom dialog look like the default one. The problem is that the theme used in that dialog is an internal theme and cannot be used by your application. You can either try to make it as similar to the native one as you want or go for a completely custom look (many apps do that like the gallery app etc)

Savvas Dalkitsis
  • 11,476
  • 16
  • 65
  • 104
  • 1
    Marking this answer correct since it most closely answers the original question, even though I ended up going a different route (see my answer). Thanks. – Kyle Clegg Aug 06 '12 at 21:44
24

Found a solution that works for me looking here (see the third comment on the first answer). This code looks for a valid twitter client and uses it to post the tweet. Note: It does not give you an Intent with the various Twitter clients and allow you to choose.

Share using twitter:

Intent shareIntent = findTwitterClient(); 
shareIntent.putExtra(Intent.EXTRA_TEXT, "test");
startActivity(Intent.createChooser(shareIntent, "Share"));

Calling this method:

public Intent findTwitterClient() {
    final String[] twitterApps = {
            // package // name - nb installs (thousands)
            "com.twitter.android", // official - 10 000
            "com.twidroid", // twidroid - 5 000
            "com.handmark.tweetcaster", // Tweecaster - 5 000
            "com.thedeck.android" }; // TweetDeck - 5 000 };
    Intent tweetIntent = new Intent();
    tweetIntent.setType("text/plain");
    final PackageManager packageManager = getPackageManager();
    List<ResolveInfo> list = packageManager.queryIntentActivities(
            tweetIntent, PackageManager.MATCH_DEFAULT_ONLY);

    for (int i = 0; i < twitterApps.length; i++) {
        for (ResolveInfo resolveInfo : list) {
            String p = resolveInfo.activityInfo.packageName;
            if (p != null && p.startsWith(twitterApps[i])) {
                tweetIntent.setPackage(p);
                return tweetIntent;
            }
        }
    }

    return null;
}

Facebook will be similar using "com.facebook.katana", although you still can't set the message text (deprecated July 2011).

Code source: Intent to open twitter client on Android

Prags
  • 2,457
  • 2
  • 21
  • 38
Kyle Clegg
  • 38,547
  • 26
  • 130
  • 141
  • 4
    I don't like this answer because it relies on knowing the package names of all the twitter apps. For another way see http://stackoverflow.com/questions/6827407/how-to-customize-share-intent-in-android/9229654 – Ed Burnette Jun 12 '13 at 14:47
  • I agree with you, although the answer you linked to has a similar problem. I never like relying on string comparisons especially when I have no control or guarantee the string won't change. – Kyle Clegg Jul 03 '13 at 15:38
22

Try this one for sharing only three apps-Facebook, Twitter, KakaoStory.

public void onShareClick(View v){
    List<Intent> targetShareIntents=new ArrayList<Intent>();
    Intent shareIntent=new Intent();
    shareIntent.setAction(Intent.ACTION_SEND);
    shareIntent.setType("text/plain");
    List<ResolveInfo> resInfos=getPackageManager().queryIntentActivities(shareIntent, 0);
    if(!resInfos.isEmpty()){
        System.out.println("Have package");
        for(ResolveInfo resInfo : resInfos){
            String packageName=resInfo.activityInfo.packageName;
            Log.i("Package Name", packageName);
            if(packageName.contains("com.twitter.android") || packageName.contains("com.facebook.katana") || packageName.contains("com.kakao.story")){
                Intent intent=new Intent();
                intent.setComponent(new ComponentName(packageName, resInfo.activityInfo.name));
                intent.setAction(Intent.ACTION_SEND);
                intent.setType("text/plain");
                intent.putExtra(Intent.EXTRA_TEXT, "Text");
                intent.putExtra(Intent.EXTRA_SUBJECT, "Subject");
                intent.setPackage(packageName);
                targetShareIntents.add(intent);
            }
        }
        if(!targetShareIntents.isEmpty()){
            System.out.println("Have Intent");
            Intent chooserIntent=Intent.createChooser(targetShareIntents.remove(0), "Choose app to share");
            chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetShareIntents.toArray(new Parcelable[]{}));
            startActivity(chooserIntent);
        }else{
            System.out.println("Do not Have Intent");
            showDialaog(this);
        }
    }
}
user3098538
  • 1,201
  • 3
  • 13
  • 15
15

Thanks to @dacoinminster. I make some modifications to his answer including package names of the popular apps and sorting of those apps.

List<Intent> targetShareIntents = new ArrayList<Intent>();
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.setType("text/plain");
PackageManager pm = getActivity().getPackageManager();
List<ResolveInfo> resInfos = pm.queryIntentActivities(shareIntent, 0);
if (!resInfos.isEmpty()) {
    System.out.println("Have package");
    for (ResolveInfo resInfo : resInfos) {
        String packageName = resInfo.activityInfo.packageName;
        Log.i("Package Name", packageName);

        if (packageName.contains("com.twitter.android") || packageName.contains("com.facebook.katana")
                || packageName.contains("com.whatsapp") || packageName.contains("com.google.android.apps.plus")
                || packageName.contains("com.google.android.talk") || packageName.contains("com.slack")
                || packageName.contains("com.google.android.gm") || packageName.contains("com.facebook.orca")
                || packageName.contains("com.yahoo.mobile") || packageName.contains("com.skype.raider")
                || packageName.contains("com.android.mms")|| packageName.contains("com.linkedin.android")
                || packageName.contains("com.google.android.apps.messaging")) {
            Intent intent = new Intent();

            intent.setComponent(new ComponentName(packageName, resInfo.activityInfo.name));
            intent.putExtra("AppName", resInfo.loadLabel(pm).toString());
            intent.setAction(Intent.ACTION_SEND);
            intent.setType("text/plain");
            intent.putExtra(Intent.EXTRA_TEXT, "https://website.com/");
            intent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.share_text));
            intent.setPackage(packageName);
            targetShareIntents.add(intent);
        }
    }
    if (!targetShareIntents.isEmpty()) {
        Collections.sort(targetShareIntents, new Comparator<Intent>() {
            @Override
            public int compare(Intent o1, Intent o2) {
                return o1.getStringExtra("AppName").compareTo(o2.getStringExtra("AppName"));
            }
        });
        Intent chooserIntent = Intent.createChooser(targetShareIntents.remove(0), "Select app to share");
        chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetShareIntents.toArray(new Parcelable[]{}));
        startActivity(chooserIntent);
    } else {
        Toast.makeText(getActivity(), "No app to share.", Toast.LENGTH_LONG).show();
    }
}
Oguz Ozcan
  • 1,694
  • 19
  • 26
11

You can try the code below, it works perfectly.

Here we share to some specific apps, that are Facebook, Messenger, Twitter, Google Plus and Gmail.

public void shareIntentSpecificApps() {
        List<Intent> intentShareList = new ArrayList<Intent>();
        Intent shareIntent = new Intent();
        shareIntent.setAction(Intent.ACTION_SEND);
        shareIntent.setType("text/plain");
        List<ResolveInfo> resolveInfoList = getPackageManager().queryIntentActivities(shareIntent, 0);

        for (ResolveInfo resInfo : resolveInfoList) {
            String packageName = resInfo.activityInfo.packageName;
            String name = resInfo.activityInfo.name;
            Log.d(TAG, "Package Name : " + packageName);
            Log.d(TAG, "Name : " + name);

            if (packageName.contains("com.facebook") ||
                    packageName.contains("com.twitter.android") ||
                    packageName.contains("com.google.android.apps.plus") ||
                    packageName.contains("com.google.android.gm")) {

                if (name.contains("com.twitter.android.DMActivity")) {
                    continue;
                }

                Intent intent = new Intent();
                intent.setComponent(new ComponentName(packageName, name));
                intent.setAction(Intent.ACTION_SEND);
                intent.setType("text/plain");
                intent.putExtra(Intent.EXTRA_SUBJECT, "Your Subject");
                intent.putExtra(Intent.EXTRA_TEXT, "Your Content");
                intentShareList.add(intent);
            }
        }

        if (intentShareList.isEmpty()) {
            Toast.makeText(MainActivity.this, "No apps to share !", Toast.LENGTH_SHORT).show();
        } else {
            Intent chooserIntent = Intent.createChooser(intentShareList.remove(0), "Share via");
            chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentShareList.toArray(new Parcelable[]{}));
            startActivity(chooserIntent);
        }
    }
Dang Nguyen
  • 354
  • 2
  • 9
8

This solution shows a list of applications in a ListView dialog that resembles the chooser:

screenshot

It is up to you to:

  1. obtain the list of relevant application packages
  2. given a package name, invoke the relevant intent

The adapter class:

import java.util.List;

import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.drawable.Drawable;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;

public class ChooserArrayAdapter extends ArrayAdapter<String> {
    PackageManager mPm;
    int mTextViewResourceId;
    List<String> mPackages;

    public ChooserArrayAdapter(Context context, int resource, int textViewResourceId, List<String> packages) {
        super(context, resource, textViewResourceId, packages);
        mPm = context.getPackageManager();
        mTextViewResourceId = textViewResourceId;
        mPackages = packages;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        String pkg = mPackages.get(position);
        View view = super.getView(position, convertView, parent);

        try {
            ApplicationInfo ai = mPm.getApplicationInfo(pkg, 0);

            CharSequence appName = mPm.getApplicationLabel(ai);
            Drawable appIcon = mPm.getApplicationIcon(pkg);

            TextView textView = (TextView) view.findViewById(mTextViewResourceId);
            textView.setText(appName);
            textView.setCompoundDrawablesWithIntrinsicBounds(appIcon, null, null, null);
            textView.setCompoundDrawablePadding((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 12, getContext().getResources().getDisplayMetrics()));
        } catch (NameNotFoundException e) {
            e.printStackTrace();
        }

        return view;
    }

}

and its usage:

    void doXxxButton() {
        final List<String> packages = ...;
        if (packages.size() > 1) {
            ArrayAdapter<String> adapter = new ChooserArrayAdapter(MyActivity.this, android.R.layout.select_dialog_item, android.R.id.text1, packages);

            new AlertDialog.Builder(MyActivity.this)
            .setTitle(R.string.app_list_title)
            .setAdapter(adapter, new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int item ) {
                    invokeApplication(packages.get(item));
                }
            })
            .show();
        } else if (packages.size() == 1) {
            invokeApplication(packages.get(0));
        }
    }

    void invokeApplication(String packageName) {
        // given a package name, create an intent and fill it with data
        ...
        startActivityForResult(intent, rq);
    }
18446744073709551615
  • 16,368
  • 4
  • 94
  • 127
4

The cleanest way is to copy the following classes: ShareActionProvider, ActivityChooserView, ActivityChooserModel. Add the ability to filter the intents in the ActivityChooserModel, and the appropriate support methods in the ShareActionProvider. I created the necessary classes, you can copy them into your project (https://gist.github.com/saulpower/10557956). This not only adds the ability to filter the apps you would like to share with (if you know the package name), but also to turn off history.

private final String[] INTENT_FILTER = new String[] {
    "com.twitter.android",
    "com.facebook.katana"
};

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.journal_entry_menu, menu);

    // Set up ShareActionProvider's default share intent
    MenuItem shareItem = menu.findItem(R.id.action_share);

    if (shareItem instanceof SupportMenuItem) {
        mShareActionProvider = new ShareActionProvider(this);
        mShareActionProvider.setShareIntent(ShareUtils.share(mJournalEntry));
        mShareActionProvider.setIntentFilter(Arrays.asList(INTENT_FILTER));
        mShareActionProvider.setShowHistory(false);
        ((SupportMenuItem) shareItem).setSupportActionProvider(mShareActionProvider);
    }

    return super.onCreateOptionsMenu(menu);
}
saulpower
  • 1,258
  • 1
  • 10
  • 13
3

I have improved @dacoinminster answer and this is the result with an example to share your app:

// Intents with SEND action
PackageManager packageManager = context.getPackageManager();
Intent sendIntent = new Intent(Intent.ACTION_SEND);
sendIntent.setType("text/plain");
List<ResolveInfo> resolveInfoList = packageManager.queryIntentActivities(sendIntent, 0);

List<LabeledIntent> intentList = new ArrayList<LabeledIntent>();
Resources resources = context.getResources();

for (int j = 0; j < resolveInfoList.size(); j++) {
    ResolveInfo resolveInfo = resolveInfoList.get(j);
    String packageName = resolveInfo.activityInfo.packageName;
    Intent intent = new Intent();
    intent.setAction(Intent.ACTION_SEND);
    intent.setComponent(new ComponentName(packageName,
    resolveInfo.activityInfo.name));
    intent.setType("text/plain");

    if (packageName.contains("twitter")) {
        intent.putExtra(Intent.EXTRA_TEXT, resources.getString(R.string.twitter) + "https://play.google.com/store/apps/details?id=" + context.getPackageName());
    } else {
        // skip android mail and gmail to avoid adding to the list twice
        if (packageName.contains("android.email") || packageName.contains("android.gm")) {
            continue;
        }
        intent.putExtra(Intent.EXTRA_TEXT, resources.getString(R.string.largeTextForFacebookWhatsapp) + "https://play.google.com/store/apps/details?id=" + context.getPackageName());
    }

    intentList.add(new LabeledIntent(intent, packageName, resolveInfo.loadLabel(packageManager), resolveInfo.icon));
}

Intent emailIntent = new Intent(Intent.ACTION_SENDTO, Uri.parse("mailto:"));
emailIntent.putExtra(Intent.EXTRA_SUBJECT, resources.getString(R.string.subjectForMailApps));
emailIntent.putExtra(Intent.EXTRA_TEXT, resources.getString(R.string.largeTextForMailApps) + "https://play.google.com/store/apps/details?id=" + context.getPackageName());

context.startActivity(Intent.createChooser(emailIntent, resources.getString(R.string.compartirEn)).putExtra(Intent.EXTRA_INITIAL_INTENTS, intentList.toArray(new LabeledIntent[intentList.size()])));
3
Intent emailIntent = new Intent(Intent.ACTION_SENDTO, 
    Uri.fromParts("mailto", "android@gmail.com", null));
emailIntent.putExtra(Intent.EXTRA_SUBJECT, text);
startActivity(Intent.createChooser(emailIntent, "Send email..."));
murugan
  • 94
  • 4
3

I had same problem and this accepted solution didn't helped me, if someone has same problem you can use my code snippet:

// example of filtering and sharing multiple images with texts
// remove facebook from sharing intents
private void shareFilter(){

    String share = getShareTexts();
    ArrayList<Uri> uris = getImageUris();

    List<Intent> targets = new ArrayList<>();
    Intent template = new Intent(Intent.ACTION_SEND_MULTIPLE);
    template.setType("image/*");
    List<ResolveInfo> candidates = getActivity().getPackageManager().
            queryIntentActivities(template, 0);

    // remove facebook which has a broken share intent
    for (ResolveInfo candidate : candidates) {
        String packageName = candidate.activityInfo.packageName;
        if (!packageName.equals("com.facebook.katana")) {
            Intent target = new Intent(Intent.ACTION_SEND_MULTIPLE);
            target.setType("image/*");
            target.putParcelableArrayListExtra(Intent.EXTRA_STREAM,uris);
            target.putExtra(Intent.EXTRA_TEXT, share);
            target.setPackage(packageName);
            targets.add(target);
        }
    }
    Intent chooser = Intent.createChooser(targets.remove(0), "Share Via");
    chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, targets.toArray(new Parcelable[targets.size()]));
    startActivity(chooser);

}
JAL
  • 41,701
  • 23
  • 172
  • 300
Jemo Mgebrishvili
  • 5,187
  • 7
  • 38
  • 63
0

So simple and concise. Thanks to the Open source developer, cketti for sharing this solution:

String mailto = "mailto:bob@example.org" +
    "?cc=" + "alice@example.com" +
    "&subject=" + Uri.encode(subject) +
    "&body=" + Uri.encode(bodyText);

Intent emailIntent = new Intent(Intent.ACTION_SENDTO);
emailIntent.setData(Uri.parse(mailto));

try {
  startActivity(emailIntent);
} catch (ActivityNotFoundException e) {
  //TODO: Handle case where no email app is available
}

And this is the link to his/her gist.

user10496632
  • 463
  • 4
  • 13