Android's documentation says:
http://developer.android.com/reference/android/content/IntentFilter.html
"Action matches if any of the given values match the Intent action, or if no actions were specified in the filter."
I just tried to test it. In my test application I set such filter for one of activities:
<intent-filter>
<action android:name="ma" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="mk1" />
</intent-filter>
I try to send such intent:
Intent i = new Intent();
i.setAction("ma");
i.addCategory("mk1");
startActivity(i);
It works - my activity gets started.
Then I comment out action in filter:
<intent-filter>
<!-- <action android:name="ma" /> -->
<category android:name="android.intent.category.DEFAULT" />
<category android:name="mk1" />
</intent-filter>
Again I send the very same intent. Now my activity doesn't start.
Why? According to documentation, when my filter has no actions specified, intent with some actions should fullfill it.
Refer to the documentation on IntentFilters especially the following description of the action test in the section on Intent Resolution:
As the example shows, while an Intent object names just a single
action, a filter may list more than one. The list cannot be empty; a
filter must contain at least one element, or it will block
all intents.
To pass this test, the action specified in the Intent object must
match one of the actions listed in the filter. If the object or the
filter does not specify an action, the results are as follows:
If the filter fails to list any actions, there is nothing for an intent to match, so all intents fail the test. No intents can get
through the filter.
On the other hand, an Intent object that doesn't specify an action automatically passes the test — as long as the filter contains at
least one action.
It is pretty clear from this that an IntentFilter that contains no actions will not match any Intent objects. Which is what you are seeing.
On the other hand, I absolutely agree with you that the documentation is inconsistent. Even the section I copied here is inconsistent, as it states both "a filter must contain at least one element, or it will block all intents" and also "an Intent object that doesn't specify an action automatically passes the test — as long as the filter contains at least one action."
You should also comment i.setAction("ma"); in your source.
Related
I have seen so many different confusing explenations..
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
What is the meaning of
<action android:name="android.intent.action.MAIN" />
and
<category android:name="android.intent.category.LAUNCHER" />
and
<category android:name="android.intent.category.DEFAULT" />
ACTION_MAIN is considered an entry point for the application. Usually, it combines with CATEGORY_LAUNCHER in an <intent-filter> to indicate an activity that should appear in the home screen's launcher, or in anything else that considers itself to be a launcher. Such "launchers" can query PackageManager, using queryIntentActivities(), to find such activities and display them to the user.
However, ACTION_MAIN can be used in combination with other categories for other specialized purposes. For example, CATEGORY_CAR_DOCK with ACTION_MAIN indicates an activity that should be considered a candidate to be shown when the user drops their phone into a manufacturer-supplied car dock.
When an Intent is used with startActivity(), if the Intent is not already placed into a category, it is placed into CATEGORY_DEFAULT. Hence, an <activity> <intent-filter> needs to specify some <category>, using <category android:name="android.intent.category.DEFAULT" /> if nothing else.
android.intent.action.MAIN means that this activity is the entry point of the application, i.e. when you launch the application, this activity is created.
From the docs
ACTION_MAIN with category CATEGORY_HOME -- Launch the home screen.
Also,from here
Activity Action Start as a main entry point, does not expect to
receive data.
android.intent.category.DEFAULT is mainly used for implicit intents. If your activity wishes to be started by an implicit intent it should include this catetory in its filter.
If your Activity might be started by an implicit Intent when no specific category is assigned to it, its Intent filter should include this category.
android.intent.category.LAUNCHER
category -- Gives additional information about the action to execute.
CATEGORY_LAUNCHER means it should appear in the Launcher as a top-level application
See the docs..
http://developer.android.com/reference/android/content/Intent.html
http://developer.android.com/guide/topics/manifest/action-element.html
<action android:name="android.intent.action.MAIN"/>
Is the main activity for this application
<category android:name="android.intent.category.LAUNCHER" />
It is in the LAUNCHER category, meaning it gets an icon in anything
that thinks of itself as a “launcher”, such as the home screen
<category android:name="android.intent.category.DEFAULT" />
The call to startActivity() will always add the DEFAULT category if
no other category is specified.
Generally just add android.intent.category.DEFAULT even if you have other Categories. This will guarantee that if Requesting Intent doesn't provide any Categories while starting the intent using startActivity(intent), then your Receiving Activity can also receive those Intents..
Source: The Busy Coders Guide to Android Development
https://commonsware.com/Android/
The answers above are pretty good, so I will just fill in some of the blanks.
<action / > element
So we all know that when the android system opens our app, it will send out an Implicit Intent and as the documentation states:
the Android system finds the appropriate component to start by comparing the contents of the intent to the intent filters declared in the manifest file of other apps on the device. If the intent matches an intent filter, the system starts that component and delivers it the Intent object.
Now each intent-filter specifies the type of intents it accepts based on the intent's based on the intent's <action>, <category/> and <data/>
So with <action>and <category/> we are defining the name and category of the intent our activity can accept
I looked up intent filters and found that they will be used when "Android finds the appropriate component to start by comparing the contents of the intent to the intent filters declared in the manifest file of other apps on the device"(http://developer.android.com/guide/components/intents-filters.html#Building)
In my manifest file, I have
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
which from reading that guide means that this activity can handle an implicit intent with action of main and category of launcher.
However what if i have multiple applications with the same intent filter in the manifest file. I know that some implicit intent will be called with action of main and category of launcher. How does the Android O.S know to choose this application?
when you have multiple activities defined with same intent filter(action=main and category=launcher), then android takes the first activity defined in the hierarchy with that intent filter (action=main and category=launcher) and will launch it when user clicks on app icon.
I have two apps where the second one has a broadcast receiver declared in its manifest.xml
<receiver android:name="com.company.app2.MyBroadcastReceiver" >
<intent-filter>
<action android:name="com.company.ACTION_CUSTOM" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
From the other app I send broadcast this way
Intent intent = new Intent();
intent.setAction("com.company.ACTION_CUSTOM");
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
//if I decomment the next line the BroadcastReceiver will not receive the broadcast
//intent.setData(fileUri);
Please guys tell me why I can't receive broadcasts when I setData ...Thanks!
When finding a matching component for an implicit intent, both the action, category, data and type are used, i.e., all of them must match.
This means that an intent with only an action will match a receiver with only an action, while an intent with an action and data will only match a receiver with that action and a <data> element matching the data URI.
Note that extras are never used for matching, which is why when you put your data as an extra instead of using setData(), you did match your action-only receiver.
Example:
Intent intent = new Intent();
intent.setAction("com.company.ACTION_CUSTOM");
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setData(Uri.parse("file://somefile.jpg"));
This will for example match a receiver with the following intent filter:
<receiver android:name="com.company.app2.MyBroadcastReceiver" >
<intent-filter>
<action android:name="com.company.ACTION_CUSTOM" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="file" />
</intent-filter>
</receiver>
...because the action, category and data all match.
If the intent filter were to not have any <data> element, it would only match intents also not having any data.
It's quite common to skip the data for intents using custom actions, especially if used only internally within an app. However, for intents using standard actions such as android.intent.action.VIEW, data (or type) is critical to make any sensible matching (imagine the chaos if an android.intent.action.VIEW intent with an image URI as the data would be matched by all components supporting android.intent.action.VIEW regardless of the type of data!)
From the documentation:
The type of data supplied is generally dictated by the intent's action. For example, if the action is ACTION_EDIT, the data should contain the URI of the document to edit.
So in your case you can simply pass the uri with intent extras.
I don't get the Android Intent matching concept! I must be missing something, but I read and re-read the docs and don't get it. Maybe some kind soul can shed some light on this?
I am able to start an Activity if I specify a Category filter android.intent.category.DEFAULT in the manifest:
...
<activity
android:name="mmmo.android.test.ItemDetails"
<intent-filter>
<action android:name="android.intent.action.INSERT" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
...
and if I then don't add any Category to the Intent object:
...
Intent intent = new Intent(Intent.ACTION_INSERT);
startActivity(intent);
...
That works. However, as soon as I define any other category than android.intent.category.DEFAULT I am only getting ActivityNotFoundExceptions. E.g. if I specify:
...
<activity
android:name="mmmo.android.test.ItemDetails"
<intent-filter>
<action android:name="android.intent.action.INSERT" />
<category android:name="foo.bar" />
</intent-filter>
</activity>
...
and then try to start that Activity using:
...
Intent intent = new Intent(Intent.ACTION_INSERT);
intent.addCategory("foo.bar");
startActivity(intent);
...
this does not work. The doc reads "... every category in the Intent object must match a category in the filter. ...". The category name I add to the Intent matches the category I specified in the filter. So why does this not match up and just throws an exception???
Michael
You must also add
<category android:name="android.intent.category.DEFAULT"></category>
to the intent filter for the intent to be resolved.
See Intent:
Activities will very often need to support the CATEGORY_DEFAULT so that they can be found by Context.startActivity().
From the documentation:
In principle, therefore, an Intent object with no categories should
always pass this test, regardless of what's in the filter. That's
mostly true. However, with one exception, Android treats all implicit
intents passed to startActivity() as if they contained at least one
category: "android.intent.category.DEFAULT" (the CATEGORY_DEFAULT
constant). Therefore, activities that are willing to receive implicit
intents must include "android.intent.category.DEFAULT" in their intent
filters
A "bug" is present if the observable behaviour does not match its documented one. This one does not a bug make.
Trying to grok intents and actions in android and looking through the documentation.
But one thing I keep seeing is an intent filter with multiple actions defined. Like this, from the above link:
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.EDIT" />
<action android:name="android.intent.action.PICK" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.cursor.dir/vnd.google.note" />
</intent-filter>
But, if you call that activity, how does it choose which action is chosen?
For that matter, that linked to example has multiple activities that all contain the same actions, "android.intent.action.VIEW" for example. When calling this with something like content://com.google.provider.NotePad/notes how does it even know which activity to use?
But, if you call that activity, how
does it choose which action is chosen?
The Intent has an action. If that action matches one of the three in the Intent filter, and matches on the category, and matches on the MIME type, then it will match the Intent filter overall and will start the activity.
In other words, multiple actions (or any other element) are a logical OR.
For that matter, that linked to
example has multiple activities that
all contain the same actions,
"android.intent.action.VIEW" for
example.
And generally there is stuff in the Intent filters to distinguish one from the next.
When calling this with something like
content://com.google.provider.NotePad/notes
how does it even know which activity
to use?
It asks the content provider, "yo, dawg -- what's the MIME type for this, yo?". Given the MIME type from the content provider, it can find any matching Intent filters.