Reputation: 358
I've been reading through the documentation on CATEGORY_ALTERNATIVE and I'm wondering what exactly is meant by "an alternative action to the data the user is currently viewing".
Could someone provide more examples of how this category is used?
I've found only some information about creating Menus and also some quote "When the system offers the user a choice of activities to do a job, the system lists activities with filters possessing this category". But then again, in the 2nd case - how does this work if we need to include CATEGORY_DEFAULT in order for an activity to receive implicit intents.
Upvotes: 0
Views: 746
Reputation: 13019
Suppose you're using some messenger app and a friend sent you an interesting link. Then there are several things you could do with it:
If you take the link as "data you are currently viewing" then it would be nice if the messenger offered you an option to select the appropriate action from a bundle of alternative actions which are currently available on your device.
With Intent.CATEGORY_ALTERNATIVE
and Menu.addIntentOptions()
, the framework has a way for the app which is the initital "owner" of some type of data to offer the user access to further actions. These actions can be implemented by any app which is running on the device and which announced its capability of handling this specific data type by an entry in the Manifest.xml
, more specifically in the <intent-filter>
tag.
Let's consider a very simple - if not very realistic - example:
My app has some String
value which it displays to the users. Alternative actions could be
String
based on some regex String
String
, e.g. to upper case lettersMy app will have its Activity
or Fragment
override onCreateOptionsMenu()
as follows (code snippet for a Fragment
)
@Override
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.home_menu, menu);
// Create an Intent that describes the requirements to fulfill, to be included
// in our menu. The offering app must include a category value of Intent.CATEGORY_ALTERNATIVE.
Intent intent = new Intent();
intent.putExtra(Intent.EXTRA_TEXT, "Lorem ipsum");
intent.setType("text/plain");
intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
// Search and populate the menu with acceptable offering applications.
menu.addIntentOptions(
R.id.intent_group, // Menu group to which new items will be added
0, // Unique item ID (none)
0, // Order for the items (none)
this.getActivity().getComponentName(), // The current activity name
null, // Specific items to place first (none)
intent, // Intent created above that describes our requirements
0, // Additional flags to control items (none)
null); // Array of MenuItems that correlate to specific items (none)
}
The Activity
s which are able to handle the given String
will declare an IntentFilter
as child tag of their tag in the Manifest.xml
:
<activity android:name=".ToUpperCaseActivity">
<intent-filter android:label="@string/label_action_text_to_uppercase">
<action android:name="de.ddvsidedown.alternativeoptionsapp.action.ALL_CAPS" />
<category android:name="android.intent.category.ALTERNATIVE" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
or
<activity android:name=".SortActivity">
<intent-filter android:label="@string/label_action_sort_text">
<action android:name="de.ddvsidedown.alternativeoptionsapp.action.SORT" />
<category android:name="android.intent.category.ALTERNATIVE" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
Then my app will show the following popup menu when the user taps the overflow icon...
... and the runtime will navigate directly to the chosen Activity
. There, the text can be retrieved as follows:
if(getIntent().hasExtra(Intent.EXTRA_TEXT)) {
char[] ca = getIntent().getCharSequenceExtra(Intent.EXTRA_TEXT).toString().toCharArray();
Arrays.sort(ca);
String message = buildString(ca);
Log.d(TAG, "onCreate: " + message);
TextView textView = findViewById(R.id.tvResult);
textView.setText(message);
}
Please note that the exact code for retrieving the data depends on the data type, just like with "normal" Intent
s with no <category>
tag at all or with <category android:name="android.intent.category.DEFAULT" />
in the <intent-filter>
.
how does this work if we need to include CATEGORY_DEFAULT in order for an activity to receive implicit intents
You need <category android:name="android.intent.category.DEFAULT"/>
in the <intent-filter>
of an Activity
if you want it to appear in a chooser dialog. By the way, an Activity
can have multiple <intent-filter>
tags
Let's modify the example: my app also has "SHARE" Button
. If it is clicked, the following piece of code is executed:
/**
* Will only work with <category android:name="android.intent.category.DEFAULT" />
*/
private void shareText() {
// Create the text message with a string
Intent sendIntent = new Intent();
//sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, "Lorem ipsum");
sendIntent.setType("text/plain");
// Verify that the intent will resolve to an activity
if (sendIntent.resolveActivity(getActivity().getPackageManager()) != null) {
startActivity(sendIntent);
}
}
The runtime will show a chooser dialog to the user. Each Activity
with an <intent-filter>
with <category android:name="android.intent.category.DEFAULT"/>
will be shown with the app title and the app's launcher icon. (While it is possible to have two Activity
s with CATEGORY_DEFAULT
in the same app, it is clear that this does not look good - it may be possible to tweak the text and/ or icon but that's definitely out of the scope of this question)
If I comment out the ACTION_SEND
then the chooser dialog has the title "Complete action using" whereas if I set ACTION_SEND
, the title is "Share with".
how [does] the system decide[...] about handling many apps with 'alternative' category especially without knowing the action name
My app configures its Intent
by setting (or omitting) the action, the categories as well as the data type. The runtime always chooses Activity
s which match all requirements of my Intent
. This means, the other Activity
may offer to handle data type "text/*" instead of just "text/plain" but if it only offers "image/*" then it won't be shown to the user.
Upvotes: 3