2011/08/07

[widget]AppWidgetProvider

過去記事:2010/08/20 21:00
AppWidgetProviderは、BroadcastReceiverをextendsしている。
コンストラクタもからっぽ。
特徴としては、onReceive()をオーバーライドして、onUpdate(), onDeleted(), onEnabled(), onDisabled()を呼び出せるようにしているところ。
なので、onReceive()を自分でオーバーライドした場合には、superを呼び出すタイミングを考えないと、うまく動かないことがあるかもしれない。
まあ、onUpdate()だけ派生している分には影響ないのだが。
BroadcastReceiverを派生しているので、普通のブロードキャストも受信できる。
そうなると、onReceive()を派生させないと意味がない。
onReceive()内でintent.getAction()によってswitch ...はできないので、if-elseifしき、どこにも引っかからなかったらsuperに処理させる、ということになるか。

私が処理したかったのは、
  • アイコンのタップ
  • マウント通知
  • アンマウント通知
なので、
  • ACTION_WIDGET_CONTROL (自前で定義)
  • Intent.ACTION_MEDIA_MOUNTED
  • Intent.ACTION_MEDIA_UNMOUNTED
を処理した。それ以外は、super.onReceive()にお任せ。
ソースに書くだけでは受け取ってくれないので、AndroidManifest.xmlに追記。
<receiver android:name=".EjectSD">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="jp.typepad.hirokumaEjectSD.WIDGET_CONTROL"/>
</intent-filter>
<meta-data android:name="android.appwidget.provider" android:resource="@xml/app_widget"/>
</receiver>

<receiver android:name=".EjectSD">
<intent-filter>
<action android:name="android.intent.action.MEDIA_UNMOUNTED"/>
<action android:name="android.intent.action.MEDIA_EJECT"/>
<action android:name="android.intent.action.MEDIA_REMOVED"/>
<action android:name="android.intent.action.MEDIA_UNMOUNTABLE"/>
<action android:name="android.intent.action.MEDIA_MOUNTED"/>
<data android:scheme="file" />
</intent-filter>
</receiver>


前半は、ウィジェット更新とタップを受けるintent-filter、後半は、SDカード関連のintent-filter。
receiverは同じだから、まとめていいのだろうか?
分け方がよくわかっていない。

以下、Android Documentの訳も含めて書いておく。
intent-filterには、action, category, nameの3つのIntent特性(Intent characteristics)がある。
これらは文字列だ。
メソッドでは、setAction(), のような「set」ではなく、addAction(), のような「add」になっている。
つまり、追加していくしくみなのだ。
となると、intent-filterをまとめていいのかどうかは、intent-filterがどのようにintentをマッチさせるかのしくみによることになる。
actionとcategoryはマッチしなくてはならない。
そしてdata(data typeとdata scheme+authority+path)はマッチしなくてはならない。
なら、全部やん。
まあ上記は基本ルールらしいので、もう少し見ていこう。
actionは、Intent actionにマッチする。 "if any of the given values match XXX"とあるので、「もしXXXと一致するなら」くらいの意味になるのだろうか。
それが嫌なら、actionは書くな。
「嫌なら」とは書いてないけど、そんな意味でよかろうか。
次は、Data Type, Data Scheme, Data Authority, Data Pathと続く。
Dataシリーズだろうか。
これらにはそれぞれ、addDataType()やaddDataScheme()のようなメソッドがある。

Data Type。Intent typeにマッチする。MIMEっぽいワイルドカードが使えるらしい。"audio/*"とすると、"audio/mpeg"とか"audio/aiff"などに対応できるとか。大文字・小文字は関係するのだと。小文字使っとけ、と。actionは関係しないのか?

Data Scheme。Intent data's schemeにマッチする。これも大文字・小文字があるので、小文字使っとけ、と。

Data Authority。data authorityと schemeの1つとマッチするか、書かないでおくか。
ならschemeは必ず書く必要があるのかというと、実際はそんなこともない。いるのかいらんのか、表にまとめられんのか、君らは!
これも大文字・小文字あり、と。以下省略。

Data Path。Intentのdata pathと、schemeとauthorityの両方にマッチする。か、書かないでおくか。
そしてCategory。
・・・訳せんかった。

Extra categories in the filter that are not in the Intent will not cause the match to fail.
Intentにないintent-filterの余計なカテゴリーはマッチしない、ということ?
つまり、カテゴリーは完全一致でしか引っかからないということだろうか。
actionがない場合、カテゴリーのないintent-filterは、カテゴリーのないintentしかマッチできない、とある。
悔しいが、よくわからん。

では、intentをマッチさせているソースを見てみたいものだ。
あんまり見てないけど、IntentFilter::match()だろう。
引数が長い方のmatchね。
戻り値は、
  • MATCH_CATEGORY_MASK : 0xfff0000
  • MATCH_ADJUSTMENT_MASK : 0x000ffff
  • MATCH_ADJUSTMENT_NORMAL : 0x8000
  • MATCH_CATEGORY_EMPTY : 0x0100000
  • MATCH_CATEGORY_SCHEME : 0x0200000
  • MATCH_CATEGORY_HOST : 0x0300000
  • MATCH_CATEGORY_PORT : 0x0400000
  • MATCH_CATEGORY_PATH : 0x0500000
  • MATCH_CATEGORY_TYPE : 0x0600000
  • NO_MATCH_TYPE : -1
  • NO_MATCH_DATA : -2
  • NO_MATCH_ACTION : -3
  • NO_MATCH_CATEGORY : -1
とのこと。
actionがある場合には、matchAction()を呼び出し、マッチしなければ終了。
次にmatchData()。戻りが0未満なら、終了。
次にmatchCategories()。非nullなら、終了。
ここまでくぐり抜けたら、matchData()の値を返して終了。
では、順に見ていこう。

matchAction(action)
まず、引数action(おそらくintent.getAction()と同じものが来るだろう)がnullか、mActionsすなわちaddAction()していないか、mActionsの大きさが0の場合は、falseを返す。
そうでなければ、actionがmActionsに含まれればtrue、含まれなければfalseを返す。
実にシンプルだ。
actionに相当するものがあれば比較し、なければ比較しない。
呼び出し元では、引数actionが非nullであることが条件になっている。
つまりIntentにactionがなければ、ここは通らないことになる。
actionがあるならば、!matchAction()なので、trueを返さないとマッチ失敗となる。

matchDAta(type, scheme, data)
ここは処理が長い。ループはないので、上から下に流れるだけなのだが、長いな。
まず、addDataType()とaddDataScheme()をしてない場合。
typeもdataもnullなら、マッチしたことになる。
MATCH_CATEGORY_EMPTY+MATCH_ADJUSTMENT_NORMAL = 0x108000
そうでなければ、NO_MATCH_DATA。
addDataScheme()していた場合・・・・

と書いていこうとしたが、文章ではわかりにくいことがわかった。
図にしよう。
今回は、メインの流れのみ。
(紛失)
他もアクティビティ図にしたので、見たい人は持っていってくだされ(紛失)

0 件のコメント:

コメントを投稿

コメントありがとうございます。
スパムかもしれない、と私が思ったら、
申し訳ないですが勝手に削除することもあります。

注: コメントを投稿できるのは、このブログのメンバーだけです。