I'm trying to make a custom Intent chooser for the ACTION_SEND
PackageManager pm = getApplicationContext().getPackageManager();
Intent shareIntent = new Intent(android.content.Intent.ACTION_SEND)
.setType("application/octet-stream");
List<Intent> targetedShareIntents = new ArrayList<Intent>();
List<ResolveInfo> resInfo = pm.queryIntentActivities(shareIntent, 0);
Collections.sort(resInfo, new ResolveInfo.DisplayNameComparator(pm));
for (ResolveInfo resolveInfo : resInfo) {
String packageName = resolveInfo.activityInfo.packageName;
Intent targetedShareIntent = new Intent(android.content.Intent.ACTION_SEND)
.setType("application/octet-stream")
.setPackage(packageName);
targetedShareIntents.add(targetedShareIntent);
}
Intent chooserIntent = Intent.createChooser(targetedShareIntents.remove(0), "Title");
chooserIntent.putExtra( Intent.EXTRA_INITIAL_INTENTS, targetedShareIntents.toArray(new Parcelable[]{}));
startActivity(chooserIntent);
the problem is that for applications that have multiple activities with the same action (Like ES File Explorer), it is listed multiple times as "Android System" Like in Figure 1. http://imgur.com/a/3TYMA
and then if selected it gives you the standard Intent chooser associated with that application Like in Figure 2.
The Question: how can I implement a custom Intent chooser like the build-in one, where each Activity is listed together.
like in Figure 3.
Found something to get rid of the "Android-system" text and now its displaying "ES File Explorer" instead. And an es file explorer icon. I had added these log statements:
Log.d(TAG, packageName );
Log.d(TAG, resolveInfo.activityInfo.name );
and the result for ES File Explores was:
com.estrongs.android.pop
com.estrongs.android.pop.app.ESFileSharingActivity
com.estrongs.android.pop
com.estrongs.android.pop.app.SaveToESActivity
then i added following statement in the loop:
targetedShareIntent.setClassName(packageName, resolveInfo.activityInfo.name);
So now you will see twice ES File Explorer. But unlucky twice the same info. And the same icon.
Think you should mail the guys of es file explorer a link to this post. They are helpfull. They will be interested.
Related
I am working with this code which Ragu Swaminathan helped me with on my original post found at: How to show both texting and dialer apps with a single Intent on Android?.
final List<Intent> finalIntents = new ArrayList<Intent>();
final Intent textIntent = new Intent(Intent.ACTION_VIEW);
textIntent.setType("text/plain");
textIntent.setData(Uri.parse("sms:"));
final PackageManager packageManager = getActivity().getPackageManager();
final List<ResolveInfo> listCam = packageManager.queryIntentActivities(textIntent, 0);
for (ResolveInfo res : listCam) {
final String packageName = res.activityInfo.packageName;
final Intent intent = new Intent(textIntent);
intent.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));
intent.setPackage(packageName);
finalIntents.add(intent);
}
Intent callIntent = new Intent(Intent.ACTION_DIAL);
callIntent.setData(Uri.parse("tel:121"));
Intent chooserIntent = Intent.createChooser(
callIntent, "Select app to share");
chooserIntent.putExtra(
Intent.EXTRA_INITIAL_INTENTS, finalIntents.toArray(new Parcelable[]{}));
startActivity(chooserIntent);
I have this code that brings up snackup separating sms and dialer apps installed on users phone and allows them to pick one to either send a message / call a person.
What I want to know is, is it possbile to add another section on this snackbar that checks if the user has whatsapp installed or another specfic app installed.
Also, being new to android, I have tried playing around with the code but ended up messing it up. another thing that I would like to do is create sections like theses;
Sms apps:
.....
.....
.....
Dialer apps:
.....
.....
.....
Whatsapp:
.....
Any help is welcomed, please let me know if my question is not clear.
Edited;
You can use getPackageInfo method
PackageManager pm = getPackageManager();
PackageInfo pi = pm.getPackageInfo(certainAppPackageName, 0);
if (pi != null) {
//app is installed, do smth
}
Google play links exist package names.
For example:
https://play.google.com/store/apps/details?id=org.telegram.messenger
where org.telegram.messenger is a package name
I use below code to get share applications:
PackageManager packageManager = this.getPackageManager();
Intent sharingIntent = new Intent(Intent.ACTION_SEND);
sharingIntent.setType("image/jpeg");
sharingIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse(PhotoPath));
List<ResolveInfo> resolveInfo = packageManager.queryIntentActivities(sharingIntent, PackageManager.MATCH_DEFAULT_ONLY);
I get all applications chooser as below:
And I use below code to launch application:
"one" means the selected ResolveInfo.
Intent MySharingIntent = new Intent(Intent.ACTION_SEND);
MySharingIntent.setType("image/jpeg");
MySharingIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse(PhotoPath));
MySharingIntent.setPackage(one.activityInfo.packageName);
startActivity(MySharingIntent);
If I select the item "Photo" or "Google+".
It will pop below dialog:
But I want to launch application "Photo" directly.
Without the second select dialog.
How can I do it?
You can do this by adding
intent.setComponent(new ComponentName("packagename of the activity","classname.java"));
But this is not recommended, you'll have to check first that "Photos" are indeed installed on the device.
i've a android app to share message to WeChat(without sdk).
When i directly use the StartChooser method, the display-name 'Send to Moment' and 'Send to Chat' display well.
But when i want to remove the apps i donot need using a intent filter as follows, there's problem that both display-name show 'WeChat' rather than 'Send to Moment' and 'Send to Chat'.But at the same time,their icon are right!
Who can tell me how to get the right display label?? Thank you!
Intent it = new Intent(Intent.ACTION_SEND);
it.setType("image/*");
List<ResolveInfo> resInfo = getPackageManager().queryIntentActivities(it, PackageManager.COMPONENT_ENABLED_STATE_DEFAULT);
if (!resInfo.isEmpty()) {
List<Intent> targetedShareIntents = new ArrayList<Intent>();
for (ResolveInfo info : resInfo)
{
Intent targeted = new Intent(Intent.ACTION_SEND);
targeted.setType("image/*");
ActivityInfo activityInfo = info.activityInfo;
if (activityInfo.packageName.contains("tencent.mm") || etc..)
{
targeted.setClassName(activityInfo.packageName, activityInfo.name);
targeted.setPackage(activityInfo.packageName);
targeted.putExtra(Intent.EXTRA_TEXT, "share text");
targeted.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
targetedShareIntents.add(targeted);
}
}
Intent chooserIntent = Intent.createChooser(targetedShareIntents.remove(0), "Share");
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetedShareIntents.toArray(new Parcelable[] {}));
startActivity(chooserIntent);
}
!!! update !!! :
if the wechat intent being placed in "Intent.createChooser", the label shown is right, but shown wrong label when placed in "EXTRA_INITIAL_INTENTS".
UPDATE2:
I find the answer at How to make an intent with multiple actions. Using LabeledIntent will solve the problem.Over.
Here is how I get it to work.
CharSequence label = info.loadLabel(getPackageManager());
Intent extraIntents = new LabeledIntent(targeted, activityInfo.packageName, label, info.icon);
targetedShareIntents.add(extraIntents);
In my Android App I have an image loaded from Instragram API and I share it via the generic Share Intent like this:
Intent share = new Intent(Intent.ACTION_SEND);
share.setType("image/jpeg");
Uri uri = Uri.fromFile(file);
share.putExtra(Intent.EXTRA_STREAM,uri);
startActivity(Intent.createChooser(share, "Share Image"));
By default it gives a list of all installed apps that handle this intent, including Instagram which is the original source from where the image is coming from. How can I filter this list to exclude only the Instagram App from handling the intent while leaving all the rest?
How can I filter this list to exclude only the Instagram App from handling the intent while leaving all the rest?
You can't, except by creating your own chooser activity, using queryIntentActivities() on PackageManager and somehow filtering out Instagram. Doing that will be unreliable, simply because there are multiple possible Instagram clients, whose package names are not conclusively knowable in advance.
I'd just leave Instagram there as an option.
I used this code to filter the shareintent for instagram.
List<Intent> targets = new ArrayList<Intent>();
Intent template = new Intent(Intent.ACTION_SEND);
template.setType("text/plain");
List<ResolveInfo> candidates = this.getPackageManager().
queryIntentActivities(template, 0);
// remove all intent except instagram in share intent
for (ResolveInfo candidate : candidates) {
String packageName = candidate.activityInfo.packageName;
if (packageName.contains("instagram")) {
Intent target = new Intent(android.content.Intent.ACTION_SEND);
target.setType("text/plain");
target.putExtra(Intent.EXTRA_TEXT, "Text to share"));
target.setPackage(packageName);
targets.add(target);
}
}
Intent chooser = Intent.createChooser(targets.remove(0), translate("Share Via"));
chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, targets.toArray(new Parcelable[]{}));
startActivity(chooser);
I want to display an activity chooser that shows all apps that can VIEW and/or EDIT some data. Is there an easy way to do this, or do I have to implement my own activity chooser dialog? Or maybe I can just subclass Intent? Thanks.
I found a partial solution by using EXTRA_INITIAL_INTENTS:
Intent viewIntent = new Intent(Intent.ACTION_VIEW);
Intent editIntent = new Intent(Intent.ACTION_EDIT);
viewIntent.setDataAndType(uri, type);
editIntent.setDataAndType(uri, type);
Intent chooserIntent = Intent.createChooser(editIntent, "Open in...");
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Intent[] { viewIntent });
startActivity(chooserIntent);
I say partial because if an app supports both ACTION_VIEW and ACTION_EDIT it will show up twice in the list, one of which will open the file for viewing and the other for editing, and you wouldn't necessarily know which is which. I think a complete solution would require a custom app chooser, as Tim suggested.
EDIT (Complete Solution!):
I found a solution that doesn't involving writing a custom app chooser. In order to differentiate ACTION_EDIT apps from ACTION_VIEW apps, I found a way to append a "(for editing)" string to the labels for one of them (in my case, ACTION_EDIT) by using the line of code Tim provided. In addition, to ensure the appended string doesn't appear to be a part of the app name, I changed the color of it to cyan:
PackageManager pm = kyoPrint.getPackageManager();
Intent viewIntent = new Intent(Intent.ACTION_VIEW);
Intent editIntent = new Intent(Intent.ACTION_EDIT);
viewIntent.setDataAndType(uri, type);
editIntent.setDataAndType(uri, type);
Intent openInChooser = Intent.createChooser(viewIntent, "Open in...");
// Append " (for editing)" to applicable apps, otherwise they will show up twice identically
Spannable forEditing = new SpannableString(" (for editing)");
forEditing.setSpan(new ForegroundColorSpan(Color.CYAN), 0, forEditing.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
List<ResolveInfo> resInfo = pm.queryIntentActivities(editIntent, 0);
Intent[] extraIntents = new Intent[resInfo.size()];
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;
Intent intent = new Intent();
intent.setComponent(new ComponentName(packageName, ri.activityInfo.name));
intent.setAction(Intent.ACTION_EDIT);
intent.setDataAndType(uri, type);
CharSequence label = TextUtils.concat(ri.loadLabel(pm), forEditing);
extraIntents[i] = new LabeledIntent(intent, packageName, label, ri.icon);
}
openInChooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, extraIntents);
startActivity(openInChooser);
EDIT 2: BUG
If there are no activities found by the first intent, NO activities will be displayed, including any found by the second intent. I ended up writing my own chooser. I just populated an ExpandableListView with headings for each type of intent with their respective activities as children (stored as individual LabeledIntents).
depends on what your data is. But in general using with ACTION_VIEW and some data attached you can use an IntentChoooser to populate the list of choices to the user.
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_TEXT, "some data");
startActivity(Intent.createChooser(intent, "Open with"));
Be sure to set your type correctly so that applications will know that you are wanting to open something that they may be able to handle.
EDIT: I think you would have to use a package manager query to get your two lists then combine them into one and make your own activity / dialog that will pop-up and get populated with the data contained in your combined list.
Here is an example making the query:
List<ResolveInfo> resInfo = getPackageManager().queryIntentActivities(intent, 0);
so if you make your two Intents and call this twice, passing in each intent you should be able to combine the resulting lists to get your full set of possibilities. Then it is up to to create an activity or dialog to show them with.