when using startActivity() to open a share dialog, but content was less than what i see in log. Can anyone explain this phenomenon?
private static final String TAG = "MainActivity";
private void testShare() {
List<Intent> intentList = new ArrayList<>();
PackageManager pm = getPackageManager();//get PackageManager
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("text/plain");
shareIntent.putExtra(Intent.EXTRA_SUBJECT, "title");
shareIntent.putExtra(Intent.EXTRA_TEXT, "text");
List<ResolveInfo> resInfo = pm.queryIntentActivities(shareIntent, 0);
Log.d(TAG, "testShare: resInfo.size = "+resInfo.size());
for (int i = 0; i < resInfo.size(); i++) {
//I will screen some apps here in the future
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND);
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_SUBJECT, "title");
intent.putExtra(Intent.EXTRA_TEXT, "text");
ResolveInfo ri = resInfo.get(i);//get intent resolveInfo data
String packageName = ri.activityInfo.packageName;
intent.setComponent(new ComponentName(packageName, ri.activityInfo.name));//finish init
intentList.add(new LabeledIntent(intent, packageName, ri.loadLabel(pm), ri.icon));
}
//use createChooser to pack a share intent list
Intent chooserIntent = Intent.createChooser(intentList.remove(0), "Share to...");
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentList.toArray(new Parcelable[]{}));
startActivity(chooserIntent);
}
this is what the log shows:
the log shows here can see 28 apps
and this is the effect of running:
is the effect of running but here just only show 5 apps
by the way, i'm using android12 RedmiK40, so i have already add queries Tag in AndroidManifest.xml
<queries>
<intent>
<action android:name="android.intent.action.SEND" />
<data android:mimeType="text/plain"/>
</intent>
</queries>
Can anyone tell me what I did wrong?
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 ?
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.
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
}
}
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
Android N (API 24) introduces blacklist Intent.EXTRA_EXCLUDE_COMPONENTS, which is better and simpler than whitelist Intent.EXTRA_INITIAL_INTENTS.
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)
}
}
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");
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);
I've successfully created an intent chooser which lists Gallery, Documents and Camera. But when I try to select Camera from the chooser, nothing happens on clicking it.
I tried creating a chooser with just Camera Intent, even then the result was the same.
This exact code was working before the Marshmallow update. I suspect it has something to do with it. Have you come across a similar problem? And How did you solve it?
Following is my code to create an intent chooser.
public Intent getPickImageChooserIntent() {
// Determine Uri of camera image to save.
fileUri = getCaptureImageOutputUri();
List<Intent> allIntents = new ArrayList<>();
PackageManager packageManager = getPackageManager();
// collect all camera intents
Intent captureIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
List<ResolveInfo> listCam = packageManager.queryIntentActivities(captureIntent, 0);
for (ResolveInfo res : listCam) {
Intent intent = new Intent(captureIntent);
intent.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));
intent.setPackage(res.activityInfo.packageName);
if (fileUri != null) {
intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
}
allIntents.add(intent);
}
// collect all gallery intents
Intent galleryIntent = new Intent(Intent.ACTION_GET_CONTENT);
galleryIntent.setType("image/*");
List<ResolveInfo> listGallery = packageManager.queryIntentActivities(galleryIntent, 0);
for (ResolveInfo res : listGallery) {
Intent intent = new Intent(galleryIntent);
intent.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));
intent.setPackage(res.activityInfo.packageName);
allIntents.add(intent);
}
// the main intent is the last in the list (fucking android) so pickup the useless one
Intent mainIntent = allIntents.get(allIntents.size() - 1);
for (Intent intent : allIntents) {
if (intent.getComponent().getClassName().equals("com.android.documentsui.DocumentsActivity")) {
mainIntent = intent;
break;
}
}
allIntents.remove(mainIntent);
// Create a chooser from the main intent
Intent chooserIntent = Intent.createChooser(mainIntent, "Select source");
// Add all other intents
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, allIntents.toArray(new Parcelable[allIntents.size()]));
return chooserIntent;
}
As #Tynn pointed out, The problem is because of the new Permission Model. I had to setup runtime checks for the permission status for each of the permissions.
How can i remove Google+ from the intent?
Intent intent = new Intent(Intent.ACTION_SEND);
...
// Always use string resources for UI text.
// This says something like "Share this photo with"
String title = getResources().getString(R.string.chooser_title);
// Create intent to show chooser
Intent chooser = Intent.createChooser(intent, title);
// Verify the intent will resolve to at least one activity
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(chooser);
}
How can i remove Google+ from the intent?
List<Intent> targetIntents = new ArrayList<Intent>();
Intent templateIntent = new Intent(Intent.ACTION_SEND);
templateIntent.setType("text/plain");
List<ResolveInfo> packages = this.getPackageManager().
queryIntentActivities(templateIntent, 0);
// remove desired package
for (ResolveInfo candidate : packages) {
String packageName = candidate.activityInfo.packageName;
if (!packageName.equals("com.google.android.apps.plus")) { //GooglePlus Package name
Intent target = new Intent(android.content.Intent.ACTION_SEND);
target.setType("text/plain");
target.putExtra(Intent.EXTRA_TEXT, "Your Text Here");
target.setPackage(packageName);
targetIntents.add(target);
}
}
Intent chooserIntent = Intent.createChooser(targetIntents.remove(0), "Share.");
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetIntents.toArray(new Parcelable[]{}));
startActivity(chooserIntent);
In my project I need to share some information into Just Facebook and Twitter. Currently when you use following codes, android offers list of all social networks that you have in your mobile phone.
public void share(String subject,String text) {
final Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_SUBJECT, subject);
intent.putExtra(Intent.EXTRA_TEXT, text);
startActivity(Intent.createChooser(intent, "Share with:"));
}
The requirement is just showing Facebook and Twitter in this list. Is it possible to filter this list in order to have these two?
Button btnshare=(Button)rootView.findViewById(R.id.btnshare);
btnshare.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Share(getShareApplication(),"Hello Text Share");
}
});
private List<String> getShareApplication(){
List<String> mList=new ArrayList<String>();
mList.add("com.facebook.katana");
mList.add("com.twitter.android");
mList.add("com.google.android.gm");
return mList;
}
private void Share(List<String> PackageName,String Text) {
try
{
List<Intent> targetedShareIntents = new ArrayList<Intent>();
Intent share = new Intent(android.content.Intent.ACTION_SEND);
share.setType("text/plain");
List<ResolveInfo> resInfo = getActivity().getPackageManager().queryIntentActivities(share, 0);
if (!resInfo.isEmpty()){
for (ResolveInfo info : resInfo) {
Intent targetedShare = new Intent(android.content.Intent.ACTION_SEND);
targetedShare.setType("text/plain"); // put here your mime type
if (PackageName.contains(info.activityInfo.packageName.toLowerCase())) {
targetedShare.putExtra(Intent.EXTRA_TEXT,Text);
targetedShare.setPackage(info.activityInfo.packageName.toLowerCase());
targetedShareIntents.add(targetedShare);
}
}
Intent chooserIntent = Intent.createChooser(targetedShareIntents.remove(0), "Share");
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetedShareIntents.toArray(new Parcelable[]{}));
startActivity(chooserIntent);
}
}
catch(Exception e){
e.printStackTrace();
}
}
You could query for the activities that match the intent and then filter for the package names of the Twitter and Facebook apps since the package name of an app never changes. Then put these results in a custom dialog.
Using something like this you could filter the results by package name:
final PackageManager pm = context.getPackageManager();
final Intent intent = new Intent(Intent.ACTION_SEND);
List<ResolveInfo> riList = pm.queryIntentActivities(intent, 0);
for (ResolveInfo ri : riList) {
ActivityInfo ai = ri.activityInfo;
String pkg = ai.packageName;
if (pkg.equals("com.facebook.katana") || pkg.equals("com.twitter.android")) {
// Add to the list of accepted activities.
// There's a lot of info available in the
// ResolveInfo and ActivityInfo objects: the name, the icon, etc.
// You could get a component name like this:
ComponentName cmp = new ComponentName(ai.packageName, ai.name);
}
}
I don't know if that's what you mean but you can use the Android built-in sharing menu...
You can share a URL to Facebook, Twitter, Gmail and more (as long as the apps are installed on your device) using Intents:
Intent i = new Intent(Intent.ACTION_SEND);
i.setType("text/plain");
i.putExtra(Intent.EXTRA_SUBJECT, "Sharing URL");
i.putExtra(Intent.EXTRA_TEXT, "http://www.url.com");
startActivity(Intent.createChooser(i, "Share URL"));
Don't forget to insert this to the Manifest.xml:
<activity android:name="ShareLink">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
<meta-data/>
</activity>
Hope this helps!