How to exclude a specific application from ACTION_SEND Intent?
Asked Answered
P

7

12

I have used the following codes to exclude facebook app from my app chooser:

 List<Intent> targetedShareIntents = new ArrayList<Intent>();
    Intent intent = new Intent(android.content.Intent.ACTION_SEND);
    intent.setType("image/*");
    List<ResolveInfo> resInfo = getActivity().getPackageManager().queryIntentActivities(intent, 0);
    if (!resInfo.isEmpty()) {
        for (ResolveInfo resolveInfo : resInfo) {
            String packageName = resolveInfo.activityInfo.packageName;
            Intent targetedShareIntent = new Intent(android.content.Intent.ACTION_SEND);
            targetedShareIntent.setType("image/*");
            targetedShareIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, "tooter.nl");
            if (!TextUtils.equals(packageName, "com.facebook.katana")) {


                targetedShareIntent.putExtra(android.content.Intent.EXTRA_TEXT, st);
                targetedShareIntent.putExtra(Intent.EXTRA_STREAM, screenshotUri);
                targetedShareIntent.setPackage(packageName);
                targetedShareIntents.add(targetedShareIntent);
            }

        }
        Intent chooserIntent = Intent.createChooser(targetedShareIntents.remove(0), "Select app to share");
        chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetedShareIntents.toArray(new Parcelable[targetedShareIntents.size()]));
        startActivity(chooserIntent);
    }

Facebook app was removed when I used the code. But the sad part was, even Twitter app was also removed from the app chooser and other unnecessary apps like "Android system" was listed on the chooser . What should i do ? Is something missing or wrong with this code ?

Pleadings answered 13/7, 2016 at 8:8 Comment(7)
Except facebook and twitter remaining only show ,,if you want share data in face book and twitter you should use Facebook and Twitter SDK@PleadingsKlondike
@muruga5000 yes i have used facebook sdk due to which i want to exclude it in my send intent's app chooser. However while i do this, twitter is also not shown. I don't need a separate share for twitter so i want to have it in app chooserPleadings
@Pleadings do you want to exclude only facebook from native share intent correct ?Almaraz
@RaguSwaminathan yesPleadings
Do you want to share image or textAlmaraz
@Pleadings check my answer belowAlmaraz
@Pleadings Whats the rationale behind removing the 1st item from targetedShareIntents and feeding it to createChooser? What happens to the rest of the resolvable intents?Professoriate
A
16

Check my answer below. It will exclude only facebook application from sharing.

 void shareOnOtherSocialMedia() {

    List<Intent> shareIntentsLists = new ArrayList<Intent>();
    Intent shareIntent = new Intent();
    shareIntent.setAction(Intent.ACTION_SEND);
    shareIntent.setType("image/*");
    List<ResolveInfo> resInfos = getPackageManager().queryIntentActivities(shareIntent, 0);
    if (!resInfos.isEmpty()) {
      for (ResolveInfo resInfo : resInfos) {
        String packageName = resInfo.activityInfo.packageName;
        if (!packageName.toLowerCase().contains("facebook")) {
          Intent intent = new Intent();
          intent.setComponent(new ComponentName(packageName, resInfo.activityInfo.name));
          intent.setAction(Intent.ACTION_SEND);
          intent.setType("image/*");
          intent.setPackage(packageName);
          shareIntentsLists.add(intent);
        }
      }
      if (!shareIntentsLists.isEmpty()) {
        Intent chooserIntent = Intent.createChooser(shareIntentsLists.remove(0), "Choose app to share");
        chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, shareIntentsLists.toArray(new Parcelable[]{}));
        startActivity(chooserIntent);
      } else
        Log.e("Error", "No Apps can perform your task");

    }
  }
}

And call the above function wherever you want. Let me know for queries.

Almaraz answered 13/7, 2016 at 12:12 Comment(4)
great .. Happy coding.. :)Almaraz
It gives me error Direct Share no availablePhotogenic
Be careful using this way, as in Android 11, Package Visibility affects which packages you can query and which ones actually will show to the user even if it found them in the query.Alba
It is working until android 9 (included), not 10 and following, where it is advised to use EXTRA_EXCLUDE_COMPONENT rather than EXTRA_INITIAL_INTENTSPelican
W
6

For Android API 24 and above, you can use this:

val components = arrayOf(ComponentName(applicationContext, YourActivity::class.java))
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) 
   startActivity(Intent.createChooser(intent, null).putExtra(Intent.EXTRA_EXCLUDE_COMPONENTS,components))

For the rest, you can have this solution I wrote about (which allows you to have a condition which to exclude

Here's a more generalized solution, to be able to choose which to exclude for all Android versions:

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val targetIntent = Intent(Intent.ACTION_SEND)
        targetIntent.type = "text/plain"
        targetIntent.putExtra(Intent.EXTRA_SUBJECT, "subject")
        targetIntent.putExtra(Intent.EXTRA_TEXT, "text")
        val excludedAppsPackageNames = hashSetOf( "com.pushbullet.android","com.android.bluetooth","com.google.android.apps.docs","com.google.android.gm")
        getIntentChooser(this, targetIntent, "choose!", object : ComponentNameFilter {
            override fun shouldBeFilteredOut(componentName: ComponentName): Boolean = excludedAppsPackageNames.contains(componentName.packageName)
        })?.let { startActivity(it) }
    }

    interface ComponentNameFilter {
        fun shouldBeFilteredOut(componentName: ComponentName): Boolean
    }

    private fun getIntentChooser(context: Context, intent: Intent, chooserTitle: CharSequence? = null, filter: ComponentNameFilter): Intent? {
        val resolveInfos = context.packageManager.queryIntentActivities(intent, 0)
//        Log.d("AppLog", "found apps to handle the intent:")
        val excludedComponentNames = HashSet<ComponentName>()
        resolveInfos.forEach {
            val activityInfo = it.activityInfo
            val componentName = ComponentName(activityInfo.packageName, activityInfo.name)
//            Log.d("AppLog", "componentName:$componentName")
            if (filter.shouldBeFilteredOut(componentName))
                excludedComponentNames.add(componentName)
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            return Intent.createChooser(intent, chooserTitle).putExtra(Intent.EXTRA_EXCLUDE_COMPONENTS, excludedComponentNames.toTypedArray())
        }
        if (resolveInfos.isNotEmpty()) {
            val targetIntents: MutableList<Intent> = ArrayList()
            for (resolveInfo in resolveInfos) {
                val activityInfo = resolveInfo.activityInfo
                if (excludedComponentNames.contains(ComponentName(activityInfo.packageName, activityInfo.name)))
                    continue
                val targetIntent = Intent(intent)
                targetIntent.setPackage(activityInfo.packageName)
                targetIntent.component = ComponentName(activityInfo.packageName, activityInfo.name)
                // wrap with LabeledIntent to show correct name and icon
                val labeledIntent = LabeledIntent(targetIntent, activityInfo.packageName, resolveInfo.labelRes, resolveInfo.icon)
                // add filtered intent to a list
                targetIntents.add(labeledIntent)
            }
            val chooserIntent: Intent?
            // deal with M list seperate problem
            chooserIntent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                // create chooser with empty intent in M could fix the empty cells problem
                Intent.createChooser(Intent(), chooserTitle)
            } else {
                // create chooser with one target intent below M
                Intent.createChooser(targetIntents.removeAt(0), chooserTitle)
            }
            if (chooserIntent == null) {
                return null
            }
            // add initial intents
            chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetIntents.toTypedArray<Parcelable>())
            return chooserIntent
        }
        return null
    }
}
Wizard answered 27/4, 2020 at 14:2 Comment(0)
R
6

I had to exclude facebook apps as they had a broken share intent (something about user originality) using Intent#EXTRA_EXCLUDE_COMPONENTS I resorted to this:

        Intent intent = new Intent(Intent.ACTION_SEND);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            intent.setTypeAndNormalize("text/plain");
        } else {
            intent.setType("text/plain");
        }
        intent.putExtra(Intent.EXTRA_TEXT, "Text to share");

        Intent chooser = Intent.createChooser(intent, "Share Text");

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {

            ArrayList<ComponentName> targets = new ArrayList<>();

            // remove facebook which has a broken share intent
            for (ResolveInfo candidate : requireActivity().getPackageManager().queryIntentActivities(intent, 0)) {
                String packageName = candidate.activityInfo.packageName;
                if (packageName.toLowerCase().contains("facebook")) {
                    targets.add(new ComponentName(packageName, candidate.activityInfo.name));
                }
            }
            chooser.putExtra(Intent.EXTRA_EXCLUDE_COMPONENTS, targets.toArray(new ComponentName[0]));
        }

        startActivity(chooser);

This only works for android N and above

Runkle answered 10/10, 2020 at 18:9 Comment(1)
This is the only solution that works in 2021 in almost all new devices. ThanksBrython
V
5

Android N (API 24) introduces blacklist Intent.EXTRA_EXCLUDE_COMPONENTS, which is better and simpler than whitelist Intent.EXTRA_INITIAL_INTENTS.

Vespucci answered 19/10, 2018 at 4:8 Comment(1)
Thank you for this verification, as I was wondering why Intent.EXTRA_EXCLUDE_COMPONENTS wasnt working.Seniority
C
2

Updated Kotlin answer based on Ragu Swaminathan's answer

fun share() {

        val shareIntent = Intent()
        shareIntent.action = Intent.ACTION_SEND
        shareIntent.type = "text/plain"
        val resInfoList = activity?.packageManager?.queryIntentActivities(shareIntent, 0)

        val shareIntentList = arrayListOf<Intent>()

        if (resInfoList?.isNotEmpty() == true) {
            for (resInfo in resInfoList) {
                val packageName = resInfo.activityInfo.packageName
                if (!packageName.toLowerCase().contains("discord")) {
                    val intent = Intent()
                    intent.component = ComponentName(packageName, resInfo.activityInfo.name)
                    intent.action = Intent.ACTION_SEND
                    intent.type = "text/plain"
                    intent.`package` = packageName
                    intent.putExtra(Intent.EXTRA_TEXT, "This is my text to send.")
                    shareIntentList.add(intent)
                }
            }
        }

        if (shareIntentList.isEmpty()) {
            Toast.makeText(activity, "No apps to share!", Toast.LENGTH_LONG).show()
        } else {
            val chooserIntent = Intent.createChooser(Intent(), "Choose app to share")
            chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, shareIntentList.toTypedArray())
            activity?.startActivity(chooserIntent)
        }
    }
Cartelize answered 14/3, 2019 at 9:45 Comment(1)
It shows only 3 intents on API 29 instead of 15 intents whitelisted.Doghouse
P
0

Thanks to Ragu Swaminathan's answer, it works perfectly to exclude specific application in an IntentChooser. However, because the 'shareIntentLists' is added in front of the 'chooserIntent', some empty spaces may occur if the size of list is not multiple of 4. To solve this, try:

Intent chooserIntent = Intent.createChooser(new Intent(), "Choose app to share");
Pluralism answered 10/10, 2016 at 4:9 Comment(0)
I
0

After updating targetSdkVersion to 31 the older solution will stop working. This below solution will work for all android version

In Manifest file AndroidManidest.xml

(In Android api 31 by default queryIntentActivities() will return empty list to get the desired result from queryIntentActivities you need to add the below query parameter in manifest file.)

<manifest>
   <queries>
      <intent>
         <!--Change the action and data depending on you share intent-->
         <action android:name="android.intent.action.SEND" /> 
         <data android:mimeType="text/*"/>

      </intent>
   </queries>
</manifest>

In the activity file share function

Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.setType("text/plain");

shareIntent.putExtra(Intent.EXTRA_TEXT, "Link");
shareIntent.putExtra(Intent.EXTRA_SUBJECT,"Description")

ArrayList<ComponentName> excludedComponents = new ArrayList<ComponentName>();
PackageManager packageManager = context.getPackageManager();
for (ResolveInfo resolveInfo : packageManager.queryIntentActivities(shareIntent, 0)){
String packageName = resolveInfo.activityInfo.packageName;
//change facebook with whichever app you want to exclude or you can directly search for the specific package name
   if (packageName.contains("facebook")){
   excludedComponents.add(new 
   ComponentName(packageName,resolveInfo.activityInfo.name));
   }
}

Intent intentChooser = Intent.createChooser(shareIntent, "Share");
intentChooser.putExtra(Intent.EXTRA_EXCLUDE_COMPONENTS, excludedComponents.toArray(new Parcelable[]{}));
startActivity(intentChooser);
Indevout answered 19/10, 2022 at 20:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.