Monday, December 5, 2016

Understanding Intent Filter with Examples

This article discusses the rules of intent via a comprehensive list of examples and shows an simple application to test intent filter behavior that readers can try with more interesting cases themselves. At the beginning and the end of the article, it also talks about why intent filter is important, the limitation of it and workarounds.

This article doesn’t address how to design intent filters and use them to construct a well connected application. It instead focuses on the technical details – the rules – of intent filter. If you often get lost wondering why your intent filter doesn’t work the way you think it should, then it’s likely this article can answer your question.

This article is useful to you, if you

  • Can write basic intent filters but often run into cases where the actual behavior of the intent filter is different from what is originally intended.
  • Understanding the basic rules of intent filter but want to know the most subtle details and exceptions.

This article is not for useful to you, if you

  • Don’t know the basics of intent filter yet. Please refer to the Android documentation before reading ahead.
  • Want to know how to design a well connected application or suites of application using intent and intent filters.

Also, since intent filter only works with implicit intent, all intent mentioned in the examples are assumed to be implicit by default unless otherwise noted. There is little discussion about explicit intent in this article. For difference between implicit and explicit and which to choose in different scenario, refer to the Android documentation.

A Simple Intent Test App

To facilitate creating examples and testing various cases quickly, I’ll first introduce a simple app that I wrote. This app consists of two Activities

  • An IntentTestActivity that is a simple dialog for specifying an arbitrary intent and send it. IntentTestActivity can specify the action, category and data of an intent, but not any intent extras. However, intent extras plays no role during intent resolution so we really don’t care about it.
  • An IntentTargetActivity that indicates whether the intent has came through. The Activity display nothing more than a string of Hello, you reached it here!. What is more interesting is that this Activity defines an intent filter.

By changing the intent filter of IntentTargetActivity and altering the input to IntentTestActivity, we can quickly tests and examine various examples.

IntentTestActivity

Here is the class definition and layout of IntentTestActivity

public class IntentTestActivity extends AppCompatActivity {
  private static String TAG =
      IntentTestActivity.class.getSimpleName();

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_intent_test);

    configViews();
  }

  private void configViews() {
    Button sendButton = (Button) findViewById(R.id.btnSend);
    sendButton.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        Intent intent = getIntentFromInput();
        Log.e(TAG, "Intent: \n" + intent.toString());

        ComponentName resolvedComponentName =
            intent.resolveActivity(getPackageManager());
        if (resolvedComponentName != null) {
          Toast.makeText(
              IntentTestActivity.this,
              "Intent resolved to " + resolvedComponentName,
              Toast.LENGTH_LONG).show();
          startActivity(intent);
        } else {
          Toast.makeText(
              IntentTestActivity.this,
              "Intent can't resolve.",
              Toast.LENGTH_LONG).show();
        }
      }
    });
  }

  private Intent getIntentFromInput() {
    String action = getActionString();
    List<String> categories = getCategories();
    String dataType = getDataType();
    Uri uri = getDataUri();

    Intent intent = new Intent();
    if (action != null) {
      intent.setAction(action);
    }
    for (String category : categories) {
      intent.addCategory(category);
    }
    if (dataType != null && uri != null) {
      intent.setDataAndType(uri, dataType);
    } else if (uri != null) {
      intent.setData(uri);
    } else if (dataType != null) {
      intent.setType(dataType);
    }

    return intent;
  }

  private String getActionString() {
    String action = ((EditText)findViewById(R.id.etAction))
        .getText().toString();
    return action.isEmpty() ? null : "android.intent.action."
        + action.toUpperCase();
  }

  private List<String> getCategories() {
    String categoriesList = ((EditText)findViewById(R.id.etCategory))
        .getText().toString();

    if (categoriesList.isEmpty()) {
      return new ArrayList<>();
    }

    String[] categories = categoriesList.split(",");

    List<String> ret = new ArrayList<>();
    for (String category : categories) {
      ret.add("android.intent.category." + category.toUpperCase());
    }
    return ret;
  }

  private String getDataType() {
    String type = ((EditText) findViewById(R.id.etType))
        .getText().toString();
    return type.isEmpty() ? null : type;
  }

  private Uri getDataUri() {
    String uri = ((EditText) findViewById(R.id.etUri))
        .getText().toString();
    return uri.isEmpty() ? null : Uri.parse(uri);
  }
}
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.xiaolong.intenttest.IntentTestActivity">

    <TableLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentTop="true"
        android:layout_alignParentStart="true">

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent">
            <TextView
                android:text="Action"
                android:textAppearance="?android:attr/textAppearanceLarge"
                android:scrollHorizontally="true" />
            <EditText
                android:id="@+id/etAction"
                android:layout_width="200dp"/>
        </TableRow>

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent">
            <TextView
                android:text="Category"
                android:textAppearance="?android:attr/textAppearanceLarge"
                android:scrollHorizontally="true" />
            <EditText
                android:id="@+id/etCategory"/>
        </TableRow>

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent">
            <TextView
                android:text="Date Type"
                android:textAppearance="?android:attr/textAppearanceLarge"
                android:scrollHorizontally="true" />
            <EditText
                android:id="@+id/etType"/>
        </TableRow>

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent">
            <TextView
                android:text="Date URI"
                android:textAppearance="?android:attr/textAppearanceLarge"
                android:scrollHorizontally="true" />
            <EditText
                android:id="@+id/etUri"/>
        </TableRow>

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent">
            <Button
                android:id="@+id/btnSend"
                android:text="Send Intent"/>
        </TableRow>
    </TableLayout>
</RelativeLayout>

The Activity is simply a dialog of 4 input fields (action, category, data type and data URL), plus a send button. When send button is hit, an Intent is assembled according to the given input and is sent to the Android system via a call to startActivity(). If the intent resolves to IntentTargetActivity, then that will be started.

Below is a screenshot of the IntentTestActivity. As you can see, the intent action is VIEW. The intent data MIME type is application/test-type1, which is obviously a contrived type. The intent data URI is http://www.test.com/intenttesting, which is obviously a contrived URI.

Imgur

In the examples later, instead of using a screenshot of the IntentTestActivity to show the configuration of an intent, it’s much more concise to just show the string representation of the intent constructed, i.e. the output of calling Intent.toString(). For the same intent as in the above screenshot, the string representation of the intent is:

Intent { act=android.intent.action.VIEW dat=http://www.test.com/intenttesting typ=application/test-type1 }

It’s not hard to see how parts of the string representation maps to components of the intent. Notice that in this example the category is note specified. If one or more categories is specified for the intent, it will shows as a list with the key cat in the string output.

IntentTargetActivity

The IntentTargetActivity is a dummy Activity whose sole purpose is to verify whether the intent send from IntentTestActivity can resolves to it or not. The only thing relevant is the Activity’s definition in the manifest file, which is shown below:

<activity android:name=".IntentTargetActivity">
    <intent-filter>
        <action android:name="android.intent.action.VIEW"/>

        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.TEST1" />

        <data android:mimeType="application/test-type1" />
        <data android:scheme="http" android:host="www.test.com" android:pathPattern="/.*intent.*" />
        <data android:scheme="ftp" android:host="www.test1.com" />
    </intent-filter>
</activity>

Don’t worry if the syntax doesn’t make sense now. The different sub-tags are dissected later with concrete examples.

Examples

Action Test

Intent filter consists of three parts, action, category and data. The definition of each part defines a corresponding test, which an incoming intent as tested against. It’s worth to note that an intent must pass ALL three tests in order to pass the filter.

The first and simplest test is action test. An intent can specify zero or one action by callingIntent.setAction() or via constructor. An intent filter can specify zero or more actions via <action> tag. In the most common case, the incoming intent specifies one action and the intent filter specifies a list of – one or more – actions. In this case, the intent passes the filter if and only if the actions it specifies is in the list the filter specifies.

Example 1: Action Test Pass, Common Case
Intent filter:

<activity android:name=".IntentTargetActivity">
    <intent-filter>
        <action android:name="android.intent.action.TEST1"/>
        <action android:name="android.intent.action.TEST2"/>

        <category android:name="android.intent.category.DEFAULT"/>
    </intent-filter>
</activity>

Intent:

Intent { act=android.intent.action.TEST1 }

Result: Pass Imgur


Example 2: Action Test Fail, Common Case
Intent filter:

<activity android:name=".IntentTargetActivity">
    <intent-filter>
        <action android:name="android.intent.action.TEST1"/>
        <action android:name="android.intent.action.TEST2"/>

        <category android:name="android.intent.category.DEFAULT"/>
    </intent-filter>
</activity>

Intent:

Intent { act=android.intent.action.TEST3 }

Result: Fail Imgur


It’s legal for an intent filter to specify no action at all, but all intent fails the test with such a filter. For obvious reasons, an always-fail filter is hardly useful. However, in a remotely possible scenario, one can read the manifest at runtime including an always-fail intent filter. The following example shows this corner case.

Example 3: Always Fail Action Test
Intent filter:

<activity android:name=".IntentTargetActivity">
    <intent-filter>
        <category android:name="android.intent.category.DEFAULT"/>
    </intent-filter>
</activity>

Intent:

Intent { act=android.intent.action.TEST1 }

Result: Fail Imgur


On the contrary, if the intent doesn’t specify an action, then it always passes the action test, as long as the intent filter specifies any action at all. The following example shows this case. Notice that the data type is also specified both in the intent and the intent filter. This is the minimal requirement for the case to work, since the intent will be entirely empty otherwise and such an empty intent can’t pass any filter

Example 4: Always Pass Action Test
Intent filter:

<activity android:name=".IntentTargetActivity">
    <intent-filter>
        <action android:name="android.intent.action.TEST1"/>

        <category android:name="android.intent.category.DEFAULT"/>

        <data android:mimeType="application/test-type1" />
    </intent-filter>
</activity>

Intent:

Intent { typ=application/test-type1 }

Result: Pass Imgur

Category Test

The second test is category test. An intent can specify one or more categories by calling Intent.addCategory(). The system automatically add the DEFAULT category to an intent during intent resolution, so even if Intent.addCategory() is never called when building the intent, there is still at least one category, which is DEFAULT. The intent filter can specifies zero or more categories via <category> tag. For an intent to pass an intent filter, each category it specifies must also be specified by the filter, i.e. a is subset of check. This implies that if the filter doesn’t specify DEFAULT category, any intent will fail. So an Activity willing to accept implicit intent should always specify DEFAULT category.

Example 5: Category Test Pass, Common Case
Intent filter:

<activity android:name=".IntentTargetActivity">
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />

                <category android:name="android.intent.category.DEFAULT"/>
                <category android:name="android.intent.category.TEST1"/>
                <category android:name="android.intent.category.TEST2"/>
            </intent-filter>
        </activity>

Intent:

Intent { act=android.intent.action.VIEW }

Result: Pass Imgur

Intent:

Intent { act=android.intent.action.VIEW cat=[android.intent.category.TEST1] }

Result: Pass Imgur

Intent:

Intent { act=android.intent.action.VIEW cat=[android.intent.category.TEST1,android.intent.category.TEST2] }

Result: Pass Imgur


Example 6: Category Test Fail, Common Case
Intent filter:

<activity android:name=".IntentTargetActivity">
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />

                <category android:name="android.intent.category.DEFAULT"/>
                <category android:name="android.intent.category.TEST1"/>
                <category android:name="android.intent.category.TEST2"/>
            </intent-filter>
        </activity>

Intent:

Intent { act=android.intent.action.VIEW cat=android.intent.category.TEST1, android.intent.category.TEST2, android.intent.category.TEST3] }

Result: Fail Imgur


The following example show that if DEFAULT category is missing from the intent filter, then no intent will pass, as explained above.

Example 7: Category Test Fail, Missing DEFAULT Category
Intent filter:

<activity android:name=".IntentTargetActivity">
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />

                <category android:name="android.intent.category.TEST1"/>
                <category android:name="android.intent.category.TEST2"/>
            </intent-filter>
        </activity>

Intent:

Intent { act=android.intent.action.VIEW cat=[android.intent.category.TEST1] }

Result: Fail Imgur

Data Test

The last and most complicated test is data test. The complexity comes from the fact that the data part of an intent consists of a data type and and a data URI, where the URI is further divided into several parts: scheme, host, port and path. And to make thing even worse, the path part of the URI can be specified in three different – and increasingly more general – ways: path, pathPrefix or pathPattern.

Due to the complexity, it’s useful to first understand how those different parts are composed to form a single, congruent test. First of all, data test is passed if and only if each part of data of the intent matched that of the intent filter, i.e. this is an AND relationship. For example, if the data type and data URI scheme matches but the URI host doesn’t, then the test still fail. Secondly, for each part of data, the intent filter can specify it more than once, and an intent matches if it matches any of the specification in the intent filter, i.e. this is an OR relationship.

It’s much easier to explain with a concrete example. Considering only the data part of the following intent filter:

<activity android:name=".IntentTargetActivity">
    <intent-filter>
        <action android:name="android.intent.action.VIEW"/>

        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.TEST1" />

        <data android:mimeType="application/test-type1" />
        <data android:scheme="http" />
        <data android:scheme="https" />
        <data android:host="www.test.com" />
        <data android:host="www.test1.com" />
        <data android:pathPattern="/.*intent.*" />
    </intent-filter>
</activity>

An intent passes the data test if and only if

  • its data type is application/test-type1
  • AND its data URI scheme is http OR https
  • AND its data URI host is www.test.com OR www.test1.com
  • AND its data URI path matches the pattern /.*intent.*

Notice that it’s permitted to combine the data tags when they define different attributes. So the above filter can be equivalently written as:

<activity android:name=".IntentTargetActivity">
    <intent-filter>
        <action android:name="android.intent.action.VIEW"/>

        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.TEST1" />

        <data android:mimeType="application/test-type1" />
        <data android:scheme="http" android:host="www.test.com" />
        <data android:scheme="https" android:host="www.test1.com" />
        <data android:pathPattern="/.*intent.*" />
    </intent-filter>
</activity>

However, when the intent filter is written this way, it seems to suggest that for the URI to match, it should either be http://www.test.com/.*intent.* or https://www.test1.com/.*intent.*. However, in reality, both http://www.test1.com/.*intent.* or https://www.test.com/.*intent.* matches too. To avoid such confusion, one should always write each attribute in a separate data tag, or only combine attributes that occur once. In all the following examples, I’ll stick to the convention to put each data attribute in its own data tag.

The next example shows that the location where a <data> tag attribute appears doesn’t matter. More specifically, even though the matching scheme, http and the matching host www.test1.com are in separate data tags, the match happens regardless.

Example 8: Data Test Success
Intent filter:

<activity android:name=".IntentTargetActivity">
    <intent-filter>
        <action android:name="android.intent.action.VIEW"/>

        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.TEST1" />

        <data android:mimeType="application/test-type1" />
        <data android:scheme="http" android:host="www.test.com" />
        <data android:scheme="ftp" android:host="www.test1.com" />
        <data android:pathPattern="/.*intent.*" />
    </intent-filter>
</activity>

Intent:

Intent { act=android.intent.action.VIEW cat=[android.intent.category.TEST1] dat=http://www.test1.com/intensttest typ=application/test-type1 }

Result: Pass Imgur

Example 9: Data Test Fail, Data Type Mismatch
Intent filter:

<activity android:name=".IntentTargetActivity">
    <intent-filter>
        <action android:name="android.intent.action.VIEW"/>

        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.TEST1" />

        <data android:mimeType="application/test-type1" />
        <data android:scheme="http" android:host="www.test.com" />
        <data android:scheme="ftp" android:host="www.test1.com" />
        <data android:pathPattern="/.*intent.*" />
    </intent-filter>
</activity>

Intent:

Intent { act=android.intent.action.VIEW cat=[android.intent.category.TEST1] dat=http://www.test1.com/intensttest typ=application/test-another-type }

Result: Fail Imgur

Example 10: Data Test Fail, Scheme Mismatch
Intent filter:

<activity android:name=".IntentTargetActivity">
    <intent-filter>
        <action android:name="android.intent.action.VIEW"/>

        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.TEST1" />

        <data android:mimeType="application/test-type1" />
        <data android:scheme="http" android:host="www.test.com" />
        <data android:scheme="ftp" android:host="www.test1.com" />
        <data android:pathPattern="/.*intent.*" />
    </intent-filter>
</activity>

Intent:

Intent { act=android.intent.action.VIEW cat=[android.intent.category.TEST1] dat=https://www.test1.com/intenttest typ=application/test-type1 }

Result: Fail Imgur

Example 11: Data Test Fail, Host Mismatch
Intent filter:

<activity android:name=".IntentTargetActivity">
    <intent-filter>
        <action android:name="android.intent.action.VIEW"/>

        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.TEST1" />

        <data android:mimeType="application/test-type1" />
        <data android:scheme="http" android:host="www.test.com" />
        <data android:scheme="ftp" android:host="www.test1.com" />
        <data android:pathPattern="/.*intent.*" />
    </intent-filter>
</activity>

Intent:

Intent { act=android.intent.action.VIEW cat=[android.intent.category.TEST1] dat=https://www.test2.com/intenttest typ=application/test-type1 }

Result: Fail Imgur

Example 12: Data Test Fail, Path Mismatch
Intent filter:

<activity android:name=".IntentTargetActivity">
    <intent-filter>
        <action android:name="android.intent.action.VIEW"/>

        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.TEST1" />

        <data android:mimeType="application/test-type1" />
        <data android:scheme="http" android:host="www.test.com" />
        <data android:scheme="ftp" android:host="www.test1.com" />
        <data android:pathPattern="/.*intent.*" />
    </intent-filter>
</activity>

Intent:

Intent { act=android.intent.action.VIEW cat=[android.intent.category.TEST1] dat=http://www.test1.com/test typ=application/test-type1 }

Result: Fail Imgur

The example for port mismatch is not listed, but one can easily come up with the example on his own.


We just visited the most common case of data test, in which both data type and data URI are specified. However, there are quite a few special cases when either type, or URI, or both are absent. The following examples shows these special rules.

In the intent filter specifies only the data URI but no type, then an intent passes the data test only if its URI matches and it doesn’t specifies data type too. If the intent specifies data type, then it always fails.

Example 13: Data Test without Type Filter, Pass
Intent filter:

<activity android:name=".IntentTargetActivity">
    <intent-filter>
        <action android:name="android.intent.action.VIEW"/>

        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.TEST1" />

        <data android:scheme="http" android:host="www.test.com" />
        <data android:scheme="ftp" android:host="www.test1.com" />
        <data android:pathPattern="/.*intent.*" />
    </intent-filter>
</activity>

Intent:

Intent { act=android.intent.action.VIEW cat=[android.intent.category.TEST1] dat=http://www.test.com/intenttest }

Result: Pass Imgur

Example 14: Data Test without Type Filter, Fail
Intent filter:

<activity android:name=".IntentTargetActivity">
    <intent-filter>
        <action android:name="android.intent.action.VIEW"/>

        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.TEST1" />

        <data android:scheme="http" android:host="www.test.com" />
        <data android:scheme="ftp" android:host="www.test1.com" />
        <data android:pathPattern="/.*intent.*" />
    </intent-filter>
</activity>

Intent:

Intent { act=android.intent.action.VIEW cat=[android.intent.category.TEST1] dat=http://www.test.com/intenttest typ=image/png }

Result: Fail Imgur

If the intent filter specifies data type but no URI, then an intent passes the data test if it’s type matches and it doesn’t specify URI also. The interesting special rule here is that if the intent specifies a file: or content: URI, it passes the test too. In other words, This rule reflects the expectation that components are able to get local data from a file or content provider.

Example 15: Data Test without URI Filter , Pass
Intent filter:

<activity android:name=".IntentTargetActivity">
    <intent-filter>
        <action android:name="android.intent.action.VIEW"/>

        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.TEST1" />

        <data android:mimeType="application/test-type1" />
    </intent-filter>
</activity>

Intent:

Intent { act=android.intent.action.VIEW cat=[android.intent.category.TEST1] typ=application/test-type1 }

Result: Pass Imgur

Example 16: Data Test without URI Filter , Pass with file: URI
Intent filter:

<activity android:name=".IntentTargetActivity">
    <intent-filter>
        <action android:name="android.intent.action.VIEW"/>

        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.TEST1" />

        <data android:mimeType="application/test-type1" />
    </intent-filter>
</activity>

Intent:

Intent { act=android.intent.action.VIEW cat=[android.intent.category.TEST1] dat=file:///Document/resume typ=application/test-type1 }

Result: Pass Imgur

Example 17: Data Test without URI Filter , Fail with http: URI
Intent filter:

<activity android:name=".IntentTargetActivity">
    <intent-filter>
        <action android:name="android.intent.action.VIEW"/>

        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.TEST1" />

        <data android:mimeType="application/test-type1" />
    </intent-filter>
</activity>

Intent:

Intent { act=android.intent.action.VIEW cat=[android.intent.category.TEST1] dat=http://www.test.com/intenttest typ=application/test-type1 }

Result: Fail Imgur

One may conclude that omitting data URI filter has the same effect as defining scheme filter as file: or content:. This is not entirely true because when scheme filter is explicitly defined, the data URI of incoming intent can’t be null in order to pass. Since an intent without URI is not usually desired, it makes sense to always define the URI filter explicitly. Compare the following example with example 15 above.

Example 18: Comparison to Example 15, but Fail
Intent filter:

<activity android:name=".IntentTargetActivity">
    <intent-filter>
        <action android:name="android.intent.action.VIEW"/>

        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.TEST1" />

        <data android:mimeType="application/test-type1" />
        <data android:scheme="file" />
        <data android:scheme="content" />
    </intent-filter>
</activity>

Intent:

Intent { act=android.intent.action.VIEW cat=[android.intent.category.TEST1] typ=application/test-type1 }

Result: Fail Imgur

Multiple Intent Filters

Rather complex intent filters can be constructed by above rules, but it doesn’t yet cover all useful cases. When an app looks for intent with specific action, category combinations, one intent filter is often not enough. Consider an image viewer app that can both view and edit png but can only view gif. This can not be specified with one intent filter: there is no way to specify, within a single intent filter, that it should accept EDIT of png but not gif.

That’s why it’s allowed for an app component to specify multiple intent filters. When multiple intent filters present, an intent passes the filter of that component if and only if it passes any one of the filters specified. For the image viewer app example, the intent filter should be the following:

<activity android:name=".IntentTargetActivity">
    <intent-filter>
        <action android:name="android.intent.action.VIEW"/>
        <action android:name="android.intent.action.EDIT"/>

        <category android:name="android.intent.category.DEFAULT"/>

        <data android:mimeType="image/png" />
    </intent-filter>
    <intent-filter>
        <action android:name="android.intent.action.VIEW"/>

        <category android:name="android.intent.category.DEFAULT"/>

        <data android:mimeType="image/gif" />
    </intent-filter>
</activity>

Example 19: Multiple Filters, Pass
Intent filter:

<activity android:name=".IntentTargetActivity">
    <intent-filter>
        <action android:name="android.intent.action.VIEW"/>
        <action android:name="android.intent.action.EDIT"/>

        <category android:name="android.intent.category.DEFAULT"/>

        <data android:mimeType="image/png" />
    </intent-filter>
    <intent-filter>
        <action android:name="android.intent.action.VIEW"/>

        <category android:name="android.intent.category.DEFAULT"/>

        <data android:mimeType="image/gif" />
    </intent-filter>
</activity>

Intent:

Intent { act=android.intent.action.EDIT dat=file:///Picture/image.png typ=image/png }

Result: Pass Imgur

Example 20: Multiple Filters, Fail
Intent filter:

<activity android:name=".IntentTargetActivity">
    <intent-filter>
        <action android:name="android.intent.action.VIEW"/>
        <action android:name="android.intent.action.EDIT"/>

        <category android:name="android.intent.category.DEFAULT"/>

        <data android:mimeType="image/png" />
    </intent-filter>
    <intent-filter>
        <action android:name="android.intent.action.VIEW"/>

        <category android:name="android.intent.category.DEFAULT"/>

        <data android:mimeType="image/gif" />
    </intent-filter>
</activity>

Intent:

Intent { act=android.intent.action.EDIT dat=file:///Picture/image.gif typ=image/gif }

Result: Fail Imgur

That’s all the examples! If you followed all the way here, congratulations and hope you now have a better understanding of intent filters and some technical details.

No comments:

Post a Comment