暗黙的インテントに設定するACTION_*

暗黙的インテントがアプリ内部から発行されると、そのアクションに対応できるアクティビティをもつアプリが選択されて、それが一つの場合は起動、複数の場合は選択ダイアログが表示される。

ACTION_*の種類

  • ACTION_CALL
  • ACTION_VIEW
  • ACTION_SEND
  • ACTION_SET_WALLPAPER
  • ACTION_WEB_SEARCH

など多数の種類がある。
http://developer.android.com/intl/ja/reference/android/content/Intent.html

メーラを起動させる場合

Intent it = new Intent();
it.setAction(Intent.ACTION_SENDTO);
it.setData(Uri.parse("mailto:[email protected]"));
it.putExtra(Intent.EXTRA_SUBJECT, "サンプルコードの件");
it.putExtra(intent.EXTRA_TEXT, "あけましておめでとうございます。");
startActivity(it);

メーラが、ACTION_SENDTO に対応できるアクティビティをもっていれば、そのメーラアプリが起動または選択肢の一つとして表示される。

ブラウザを起動させる場合

String text = inputText.getText().toString();
Uri url = Uri.parse(text);
Intent it = new Intent();
it.setAction(Intent.ACTION_VIEW);
it.setData(url);
startActivity(it);

ブラウザが、ACTION_VIEW に対応できるアクティビティをもっていれば、そのブラウザアプリが起動または選択肢の一つとして表示される。

起動されるアプリ側ではどんな記述をされているか。


「あなたは、ACTION_VIEWが暗黙的インテントで発行されたら反応しなさい。」

アプリから発行された「暗黙的インテント」のACTION_*の種類は、起動される(受け取る)アプリ内ではどう記述されているか。

AndroidManifest.xml

        <activity android:name=".ReceiveApplication"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

             <intent-filter android:label="@string/app_name">
                 <action android:name="android.intent.action.SEND" />
                 <data android:mimeType="text/plain" />
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>

        </activity>

ACTION_SENDに対応して反応するように該当アクティビティにインテントフィルターを記述しておく。
また、受け取るインテントのアクション以外の情報

  • Data
  • Category
  • Flags
  • Extra
  • Type

は、反応する/しないに関係してくるのだろう。
また、すでにインストールしているアプリがそれぞれ「どんな暗黙的インテントに対して反応するか」を調べてみようかと。

インテントフィルターの記述の例

思ったより記述が複雑な気がするので、どんな記述をしているのか集める。

http://www.techdoctranslator.com/android/guide/manifest/data-element

http://mindia.jp/book/dobby/keyword/Intent+Filter

ブラウザの「ページの共有」から起動

<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />

ブラウザでリンク遷移しようとしたときに起動

<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="http" />

明示的インテント・暗黙的インテントの使用例
http://thinkit.jp/article/921/1/

 Intent intent = new Intent();
 intent.setAction(Intent.ACTION_SEND);
 intent.setType("image/jpeg");
 intent.putExtra(Intent.EXTRA_STREAM, Uri.parse("jpegファイルの場所"));
 startActivity(intent);
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="image/jpeg" />
</intent-filter>

逆に、Twidroidから、ホットペッパーのURLを開いたときに、ホットペッパーアプリが呼ばれるような仕組みも実装しています。
http://mtl.recruit.co.jp/blog/2010/01/android.html

        <activity android:name=".RwsHotpepperShopActivity"
           android:label="@string/app_name" android:screenOrientation="portrait">
           <intent-filter>
               <action android:name="android.intent.action.VIEW" />
              <category android:name="android.intent.category.DEFAULT" />
               <data android:scheme="http" />
            <data android:host="www.hotpepper.jp" />
              <data android:pathPrefix="/str" />
        </intent-filter>
      </activity>


http://lab.r246.jp/twicca/twicca_plugin.pdf

<intent-filter android:icon="@drawable/plugin_icon" android:label="@string/plugin_name">
<action android:name="jp.r246.twicca.ACTION_UPLOAD" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="image/*" /> …画像をアップロードする場合
<data android:mimeType="video/*" />
</intent-filter>
<intent-filter android:icon="@drawable/plugin_icon" android:label="@string/plugin_name">
<action android:name="jp.r246.twicca.ACTION_PLUGIN_SETTINGS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
Quick Bookmark のことを知らないアプリからでもURLを保存したい場合は、ブラウザを開くIntentを横取りすればいいはずです。以下を Manifest に追加すれば、http:// と https:// を開く Intent が Activity に届くようになります。

<intent-filter>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="http" />
<data android:scheme="https" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>

ただ、このままだと、URLをデータベースに保存してすぐ終了する Activity であっても、一瞬画面に表示されてしまいます。これを防ぐために、Activity を透明化します。

<activity android:name=".AddActivity"
android:label="@string/app_name"
android:theme="@android:style/Theme.Translucent.NoTitleBar">

あとは、Activity の onCreate() で getIntent().getData().toString() して URL を文字列として取り出して、DBに保存、即 finish() で終了です

いろんな ACTION_* を発行してみる

上のアクションの種類以外の情報に関しては、無限なパターンが存在することになりそうなので、とりあえずは、アクションの種類のみで発行してみようかと。

Intents and Intent Filters


アクションの種類のみの発行でインストールされているアクティビティの反応をみるアプリがマーケットにある。
http://jp.androlib.com/android.application.yanzm-example-getintentlist-AqtF.aspx


その他の情報を追加しての発行からの反応をみるアプリもある。
http://jp.androlib.com/android.application.com-codtech-android-intentplayground-qBq.aspx


コマンドラインで反応をみるには、

$ adb shell
$ am        
usage: am [start|broadcast|instrument|profile]
       am start [-D] INTENT
       am broadcast INTENT
       am instrument [-r] [-e <ARG_NAME> <ARG_VALUE>] [-p <PROF_FILE>]
                [-w] <COMPONENT> 
       am profile <PROCESS> [start <PROF_FILE>|stop]

       INTENT is described with:
                [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]
                [-c <CATEGORY> [-c <CATEGORY>] ...]
                [-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...]
                [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]
                [-e|--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]
                [-n <COMPONENT>] [-f <FLAGS>] [<URI>]

なので

$ am start -a android.intent.action.VIEW http://www.google.com


ログの書式を確認してみる。

I/ActivityManager(   79): Starting activity: Intent { act=android.intent.action.CHOOSER cmp=android/com.android.internal.app.ChooserActivity (has extras) }
I/ActivityManager(   79): Starting activity: Intent { act=android.intent.action.SEND typ=text/plain flg=0x3000000 cmp=com.threebanana.notes/.NoteEditor (has extras) }
I/ActivityManager(   79): Starting activity: Intent { act=android.intent.action.CHOOSER cmp=android/com.android.internal.app.ChooserActivity (has extras) }
I/ActivityManager(   79): Starting activity: Intent { act=android.intent.action.CHOOSER cmp=android/com.android.internal.app.ChooserActivity (has extras) }
I/ActivityManager(   79): Starting activity: Intent { act=android.intent.action.SEND typ=text/plain flg=0x3000000 cmp=jp.tomorrowkey.android.hatenabookmark/.PageInfoActivity (has extras) }
I/ActivityManager(   79): Starting activity: Intent { act=android.intent.action.CHOOSER cmp=android/com.android.internal.app.ChooserActivity (has extras) }
I/ActivityManager(   79): Starting activity: Intent { act=android.intent.action.SEND typ=text/plain flg=0x3000000 cmp=com.mgeek.android.DolphinBrowser.Browser/.PostToDelicious (has extras) }
I/ActivityManager(   79): Starting activity: Intent { cmp=com.mgeek.android.DolphinBrowser.Browser/.ModifyDeliciousAccount }
I/ActivityManager(   79): Starting activity: Intent { act=android.intent.action.VIEW dat=http://www.google.com flg=0x10000000 cmp=android/com.android.internal.app.ResolverActivity }
I/ActivityManager(   79): Starting activity: Intent { act=android.intent.action.VIEW dat=http://www.google.com flg=0x10000000 cmp=android/com.android.internal.app.ResolverActivity }
I/ActivityManager(   79): Starting activity: Intent { act=android.intent.action.VIEW cat=[android.intent.category.BROWSABLE] dat=http://www.google.co.jp/ cmp=android/com.android.internal.app.ResolverActivity }
I/ActivityManager(   79): Starting activity: Intent { act=android.intent.action.VIEW cat=[android.intent.category.BROWSABLE] dat=http://www.google.co.jp/ flg=0x3800000 cmp=com.mgeek.android.DolphinBrowser.Browser/.BrowserActivity }

am start -a android.intent.action.VIEW http://www.google.com
am start -a android.intent.action.VIEW -t plain/text http://www.google.com x
am start -a android.intent.action.SEND http://www.google.com x
am start -a android.intent.action.SEND -t plain/text http://www.google.com

インテントフィルタの解釈のルール

簡単なように見えるが、複雑だ。

  1. スキームが指定され、型が指定されていなければ、どのような型のIntentともマッチする。
  2. 型が指定され、スキームが指定されていなければ、どのようなスキームのIntentともマッチする。
  3. スキームも型も指定されていなければ、スキームも型も指定されていないIntentのみとマッチする。
  4. オーソリティが指定されていれば、スキームも指定されていなければならない。
  5. パスが指定されていれば、スキームとオーソリティも指定されていなければならない。