mrnobody
mrnobody

Reputation: 419

How to exclude a specific application from ACTION_SEND Intent?

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 ?

Upvotes: 12

Views: 11258

Answers (7)

Priyankchoudhary
Priyankchoudhary

Reputation: 826

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);

Upvotes: 0

Richard Muvirimi
Richard Muvirimi

Reputation: 844

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

Upvotes: 7

android developer
android developer

Reputation: 116332

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
    }
}

Upvotes: 6

T. Colligan
T. Colligan

Reputation: 171

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)
        }
    }

Upvotes: 2

liudongmiao
liudongmiao

Reputation: 454

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

Upvotes: 5

空気嫁
空気嫁

Reputation: 186

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");

Upvotes: 0

Swaminathan V
Swaminathan V

Reputation: 4781

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.

Upvotes: 16

Related Questions