How are Intent-Categories matched? - android

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.

Related

Android Custom Explicit Intent

Hi every body I just wanna ask a question, when you define some thing like this in your android manifest file :
<activity android:name= "com.example.myapp.ExampleActivity">
<intent-filter>
<action android:name= "some.custom.action" />
<category android:name= "android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
and you gonna start it by this way :
val intent = Intent()
intent.action = "some.custom.action"
startActivity(intent)
so is it implicit calling activity?
Yes, this is an implicit intent. An explicit intent specifies the exact component that it calls. Because this doesn't, it's implicit (and therefore might resolve to multiple components if more than one matches).

What is the meaning of android.intent.action.MAIN?

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

can not understand intent filter

I was reading intent & intent filter. i got the below code:
In activity:
Intent i = new Intent(android.content.Intent.ACTION_VIEW, Uri.parse("http://www.example.com"));
startActivity(i);
In Manifest:
<activity android:name="com.example.intentdemo.CustomActivity"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<action android:name="com.example.intentdemo.LAUNCH" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="http" />
</intent-filter>
</activity>
My question is that- am i not supposed to declare android.Intent.ACTION_VIEW , instead of android.content.Intent.ACTION_VIEW inside the intent?
android.content.Intent.ACTION_VIEW refers to the name of the constant ACTION_VIEW in the class android.content.Intent. The value of this constant is "android.intent.action.VIEW". Hence the difference.
If you see the source code of Intent class, ACTION_VIEW is a String constant whose value is "android.intent.action.VIEW"...
public static final String ACTION_VIEW = "android.intent.action.VIEW";
so both refers to the same value which is "android.intent.action.VIEW"...
You are getting confused in android.intent.action.VIEW and android.Intent.ACTION_VIEW. They both are totally different.
The way which you are using is IMPLICIT INTENT
These intents do not name a target and the field for the component name is left blank. Implicit intents are often used to activate components in other applications.
Intent i = new Intent(android.content.Intent.ACTION_VIEW, Uri.parse("http://www.example.com"));
startActivity(i);
ACTION
Intent object and is a string naming the action to be performed — or, in the case of broadcast intents, the action that took place and is being reported. The action largely determines how the rest of the intent object is structured . The Intent class defines a number of action constants corresponding to different intents. Check out list of Android Intent Standard Actions
The action in an Intent object can be set by the setAction() method and read by getAction().
Check More for Intent and Intent-Filter

More than one intent-filter with category DEFAULT

Read the documentation but unclear as to the purpose of the DEAFAULT category in the manifest. Is it possible to have more than 1 intent-filter with the DEFAULT category attribute in the same manifest?
Yes it is possible to have more than one. From the documentation here is why you would need the default category:
*Note: In order to receive implicit intents, you must include the CATEGORY_DEFAULT category in the intent filter. The methods startActivity() and startActivityForResult() treat all intents as if they declared the CATEGORY_DEFAULT category. If you do not declare this category in your intent filter, no implicit intents will resolve to your activity.* - http://developer.android.com/guide/components/intents-filters.html
Example of having more than one intent filter with default category:
<intent-filter>
<action android:name="android.intent.action.CREATE_SHORTCUT"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="myscheme"/>
</intent-filter>
Is it possible to have more than 1 intent-filter with the DEFAULT category attribute in the same manifest?
Sure. Most activities that have an <intent-filter> will support the DEFAULT category, as that category is automatically added to an Intent used with startActivity() if there is no other category on the Intent already.
For example, in the manifest for the AOSP Music app, you can see a variety of <activity> elements, with and without <intent-filter> elements. Those that have <intent-filter> may or may not use DEFAULT.

Intent object not triggering intent-filter

Perhaps I'm misunderstanding how Intents and intent-filters work, but it seems to me that this should be a straight-forward case. However, it's not working.
Here is the Intent I'm sending:
Intent i = new Intent(Intent.ACTION_VIEW);
i.setType("vnd.android.cursor.item/vnd.connectsy.event");
startActivity(i);
And here is the intent-filter:
<activity android:name=".events.EventView">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<data android:mimeType="vnd.android.cursor.item/vnd.connectsy.event" />
</intent-filter>
</activity>
And finally, the error I'm recieving:
android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.VIEW typ=vnd.android.cursor.item/vnd.connectsy.event }
Here's the answer:
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.
Add
<category android:name="android.intent.category.DEFAULT" />
to your intent filter in AndroidManifest.xml

Categories

Resources