Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make an intent with multiple actions

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.

like image 653
Ken Avatar asked Jun 13 '12 18:06

Ken


1 Answers

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

enter image description here

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

like image 50
Ken Avatar answered Sep 24 '22 16:09

Ken