2013/03/29

[android]mozcが動かんかったのはzipalign忘れだった

mozcのビルド説明にいろいろ追記されていた。

でも、特に違いはないな・・・・あっ。
jarsignerはやったけど、zipalignしてない!

やると・・・動きました。
ごめんなさいごめんなさい。


まあ、そういうこともあるわな。
あまり細かいことは気にしない私であった。

[android]mozcエラーログ

zinniaをapt-get libzinnia-devにしてみたが、やっぱり設定画面が立ち上がらない。
えーい、わからん。
logcatの出力を取っておくことにした。

http://pastebin.com/hVAauFTq

出力されるタイミングは、設定アプリの「言語と入力」の「キーボードと入力方法」の項目にある「Mozc for Android」の右側にある設定アイコンをタッチしたときだ。
一瞬画面が黒くなって、また戻ってしまう(初回は「入力方法をMozcにしなさい」と出てくる)。

 

エラー原因はL.27に出ている「SIGBUS」だろう。
アラインメントがよろしくないことまでは書いてあるのだが、これからどう調べていいかわからない。。。。

[android]Mozcはビルドできたが、うちでは動かなかった

Mozcをビルドした。
ビルドしたら、インストールして動かしたくなるではないか。

ビルドしたapkはunsignedなので、符号無し・・・ではなく署名されてない。
jarsignerはどうやって使うんだったっけ、とAndroid Developerを参照した。

$ jarsigner -verbose -sigalg MD5withRSA -digestalg SHA1 -keystore my-release-key.keystore my_application.apk alias_name

こんなに長かったっけ?
と思いつつも、昔作ったkeystoreファイルを指定すると怒られた。
signature algorithmが違う、と。

keytoolで確認できるようなので、見てみた。
すると「SHA1withDSA」というやつになっていた。

うーん、あまり記憶は無いが、確か当時はサイトを見ながらkeystoreファイルを作ったはず。。。
ということは、時代が新しくなったので、アルゴリズムも新しくなったということか。


keystoreファイルを作り直すのはやめて、SHA1withDSAにするとうまくいった。
Nexus7へも、adb installでうまくいった。
設定アプリの「言語と入力」にも「Mozc for Android」が出てくるし、選択できる。

が・・・設定ができない・・・。
logcatで見ると、SIGBUSってなってるから、Bus Errorが起きているようだ。
libmozc.soらしい。
「RUN EMOJI PROVIDER DETECTION: null」というところかね。
これはandroid/inputmethod/japanese/emoji/EmojiProviderType.javaが出しているようだ。

では、Google Playにある方もだめなのかと思ってインストールしてみたが、こっちは問題ないようだ。
EMOJIのログもINFOだから致命的ではないのだろう。

ならば「Ignoring setInputMethod of uid 10111 token: null」の方が問題なのかもしれん。
バスエラーだからNULL参照とかそんなとこだと思うが、Javaだったらthrowするだろうから、原因はNDKの部分か。

む、BUS_ADRALNとある。
アラインメント不正か。アドレスが奇数になってるな・・・。
Thumb命令のベクタアドレスは奇数にするとかいう決まりがあったような気がするが、そういうのじゃないんだろうな。
addr2lineとかで追うしかないのか。。。

backtraceに出てくる最後は、これだった。

#00  pc 000cbab6  /data/app-lib/org.mozc.android.inputmethod.japanese-1/libmozc.so

では、これをaddr2lineしてみる。

[android/obj/local/armeabi]$ addr2line -e libmozc.so 0x000cbab6
/mnt/android/mozc/mozc/src/./storage/louds/simple_succinct_bit_vector_index.cc:47

ふむ。
ソースを見ておこう。

// TODO(hidehiko): Support XMM and 64-bits popcount for 64bits architectures.
inline int BitCount1(uint32 x) {
  return __builtin_popcount(x);
}

__builtin_popcount()はgccの組み込み関数で、ビットが立ってる数を求めてくれるらしい。
組み込み関数だからまずいのか?と思って、そうじゃない方の関数を呼ばせるようにしてみた。
が、これはこれでやはりだめだった。

 

報告は、こういう状況。

signal 7 (SIGBUS), code 1 (BUS_ADRALN), fault addr 69bcd243

バックトレースは、こう。

backtrace:
    #00  pc 000cbaf6  /data/app-lib/org.mozc.android.inputmethod.japanese-1/libmozc.so
    #01  pc 000cb4cb  /data/app-lib/org.mozc.android.inputmethod.japanese-1/libmozc.so
    #02  pc 000b504d  /data/app-lib/org.mozc.android.inputmethod.japanese-1/libmozc.so
    #03  pc 000b528d  /data/app-lib/org.mozc.android.inputmethod.japanese-1/libmozc.so

スタックトレースは、こう。

stack:
         69915940  00000000 
         69915944  63097b64 
         69915948  00000000 
         6991594c  6a90ba43  /data/app-lib/org.mozc.android.inputmethod.japanese-1/libmozc.so
         69915950  00000d88 
         69915954  0000ead8 
         69915958  59ae3b20 
         6991595c  63097b64 
         69915960  0003ab44 
         69915964  63117818 
         69915968  69bcd243  /data/app/org.mozc.android.inputmethod.japanese-1.apk
         6991596c  00075688 
         69915970  0003ab44 
         69915974  63117818 
         69915978  df0027ad 
         6991597c  00000000 
    #00  69915980  699159b4 
         69915984  6a91a053  /data/app-lib/org.mozc.android.inputmethod.japanese-1/libmozc.so

もっとログは出ているのだが、紙面の都合で省略した。

不正アドレスになっているのはわかるけど、それはapkが元になっていることになってる。
soファイルならaddr2lineすればいいけど、apkはどうしたらいいんだろうね?

2013/03/28

[android]mozcのビルド

http://googledevjp.blogspot.jp/2013/03/google-android.html
Google日本語入力Android番がオープンソースになりました。

 

ほほぅ。
せっかくなので、やってみることにした。
まあ、ビルドするだけなんだけどね。


うちは、Windows 7(64bit)上にVirtualBoxでxubuntu12.10が動くようになっている。
ビルドの説明では12.04となっているので、まあそんなに悪くないだろう。

自慢にはならないが、書いてある通りにやってみるだけだ。
独自に機能を追加してやれ、とかは思ってない。

 

まず、apt-get installでg++, python, subversionをインストール。
なお、Android SDKとNDKはインストール済みだ。
Androidのplatformもrepoでダウンロードしてビルドまでできている。
パスも、SDKのplatform-toolsとtools、NDKに通している。

あとはサイトに書いてある通り、svnでdepot_toolsをcheckout。
gclient syncで取ってくる。

 

詰まったのは、"Compilation"のgyp。

% python build_mozc.py gyp --target_platform=Android
これがエラーになった。RunOrDieという、なんか物騒なエラーだ。
よくわからないが「zinniaパッケージがない」みたいなことをいわれているようだ。
zinnniaはオンライン手書き文字認識エンジンらしい。
よくわからないなりに、zinnia-0.06.tar.gzをダウンロードし、解凍して、makeして、sudo make install。
そしたら、進むようになった。
が、最後でこけた。
% python build_mozc.py build android/android.gyp:apk -c Release_Android
まず、antがインストールされてなかった。
apt-get installしたら、状況が変わった。
BUILD FAILED
xxx/build.xml:76: sdk.dir is missing.
よくわからなくなったので、cleanしてやり直すことにした。
そうすると、ここでエラーが出てることに気付いてなかった。
% android update project -s -p android
targetを指定しなさい、みたいなエラーだった。
Nexus7しかないから、API17ってやればいいのかな?
% android update project --target android-17 -s -p android
こうやると、エラーも出なくなった。
そして最後のandroid.gypもうまくいきましたとさ。
めでたしめでたし。
 
さて・・・私は一体なにをビルドできたんでしょうかね・・・。
ビルドしたものは、src/android/bin/MozcForAndroid-release-unsigned.apk、らしい。
手動でサインしてね、ってログが出てた。

[android]getSystemService()はいつやるとよい?

NFCを使うときだけじゃないが、getSystemService()を使うときは多い。
システムサービス、というくらいだから、onCreate()で取得しておいて、あとは使い回せばいいだろうと何となく思っているのだが、本当だろうか?

心配になってきたので、調べよう。
うぅ、身近にAndroidの先生がほしい・・・。


まず、Context#getSystemService()を見る。
・・・abstructだから、実装は派生クラスが持っているのか。
そういえば、未だにabstructとinterfaceの違いがわかってないな。
C++だと、

class Context {
public:
  Object getSystemService(String name) = 0;

となっているイメージだけど、あってるのかな。まあ、後で調べよう。


次は、Activity#getSystemService()を見る。
普段呼び出しているのが、ここ経由だからだ。

  1. Contextがなければ、エラー
  2. WindowServiceを要求しているなら、mWindowManagerを返す。
    mWindowManagerは、attach()ってところで設定されている。誰が呼ぶかは知らない・・・。
  3. SearchServiceを要求しているなら、mSearchManagerを返す。
    もしmSearchManagerがnullだったら、この時点でnewして返す。
  4. それ以外なら、super.getSystemService()を呼び出す。

Contextは後から変化することはなさそうだから、使い回してもよさそうだ(根拠無し)。
WindowServiceも、最初に作るだけだろうから、使い回してもよいだろう。
SearchServiceも、その場で作るくらいだし、newするときの引数もthisだから使い回してもよいだろう。

また、特に重たそうな処理もないので、毎回取得しても悪いことはないかな、という気分になった。


では、Activityの上。ContextThemeWrapper#getSystemService()を見る。

  1. LayoutInflaterServiceを要求しているなら、mInflaterを返す。
    もしmInflaterがnullだったら、この時点でLayoutInflaterを作って(cloneして)返す。
  2. それ以外なら、mBase.getSystemService()を呼び出す。

LayoutInflaterは、レイアウトXMLからViewを作るときに使うものらしい。
"inflate"は「膨張させる」という意味らしい。インフレってやつか。

まあ、ここもcloneInContext()するときにthisを使うくらいだから、使い回してもよさそうだ。
取得にも時間はかからないだろう。

Activityと違うのは、次に呼び出すgetSystemService()が、superではなくてmBaseになっていることだ。
mBaseはContextのインスタンスで、コンストラクタで指定するようになっている。
足跡が途切れてしまった・・・。


仕方ないので、デバッガで探すことにした。
さっき作ったアプリでは、app.ContextImpl#getSystemService()が呼ばれるようだった。

  1. SYSTEM_SERVICE_MAPから、サービス名に合うServiceFetcherを取得
  2. ServiceFetcherがnullなら、nullを返す。
    そうでなければ、fetcher.getService()を返す。

SYSTEM_SERVICE_MAPは、HashMap<String, ServiceFetcher>となっている。
ServiceFetcherはこのContextImpl内にあるstatic classである。

 

・・・static class ?
またよくわからないものが出てきた。。。
調べたが、こちらがわかりよかった。
 Java static クラス - グロブ

わざわざそげんことせんでも、staticメソッドかなんか作りゃいいやん、と思ったが、ServiceFetcherを継承したStaticServiceFetcherクラスもあるので、classにしたかったのだろう。
この辺りの実装感覚が、全然ないんだな。。。

 

ともかく、ServiceFetcherやStaticServiceFetcherのインスタンスは、ContextImplが読み込まれたときにnewするようだ。
static{}の中に書いてあるから、そうなのだろう。

ただ、WallPaperServiceだけは別物らしく、static{}外に書いてある。
これは、getWallpaperManager()で再利用できるようにするためと、HashMapの検索対象外にするため、らしい。
うーむ・・・意味がわからないな。

fetcher.getService()では、既にサービスのインスタンスがあるならそれを返し、なければ生成して返すようになっているみたいだ。


見て回った感触からすると、システムサービスはonCreate()で保持しててもいいかな、という気がする。
毎回取得してもいいのだろうけど、HashMapを検索するコストが重たいのかどうかがよくわからない。
けど、インスタンスは既にあるのだから、保持することでそんなにメモリを食ってしまうということもなさそうだ。
まあ、個人の感想に過ぎないがね。

ただ、WallpaperServiceだけは別物のような気がしている。
WallpaperService自身は小さくて、WallpaperService.Engineを生成するためだけのものらしい。
ライブ壁紙を作る方法を読むと「WallpaperServiceとそのEngineを継承したクラスを作る」とあるので、動的に変化するように思うのだ。
onResume()で取得するようにした方が無難なのかな。

そういう解釈でいいのかね?

2013/03/27

[android]音を鳴らす練習

そういえば、Androidで音を鳴らすアプリを作ったことがなかった。
やってみよう。

https://github.com/hirokuma/AndroidCoinThrow

https://github.com/hirokuma/AndroidCoinThrow/blob/master/bin/CoinThrow.apk

apkのリンクをクリックすると、「raw view」というリンクがあるので、それもクリックするとダウンロードできる。
ダウンロードした後は、インストールするだけ。
NFCを使うだけで、ネットとかGPSとかは無い。
APIレベルは17なので、Nexus7くらいしか動かないかも。

 

NDEF TEXTで「OK」となったタグをかざすと、OKっぽい音が鳴る。
それ以外のNDEFだと、NGっぽい音が鳴る。
NDEFじゃなかったら、失敗っぽい音が鳴る。
ただ・・・それだけ・・・・。

NDEFタグは、自分で用意するよう。
NXP TagWriterなどを使ってPlain Textを書き込むだけでよい。

音は、魔王魂さんからいただいた。


私にも学生の時があって、学園祭にも参加したことがある。
そのときに出店で「コイン投げ」ってのをやったことがある。

スロットで使うようなコイン(メダルというのか)を投げ、離れた位置にあるプラスチックの板の上に載せる、というゲームだ。
板はつるつるなので、ほぼ垂直にコインが落ちるようにしないと、すべって落ちてしまうのだ。
私は客引きとして「誰でもできますよ」みたいな感じで、何気なくやって載せることができるよう、かなり練習した。
あこぎなもんだ。

image

当時は単にコインを渡して、載ったかどうかを目で見るだけだった。
しかし今なら、コインの両面にNDEFタグを貼って、当たり判定ができるんじゃなかろうか、と思ったのである。

Nexus7を裏返しにしてやってみると・・・そもそもリーダライタの範囲が狭すぎて、音すら鳴らないことがあった。
そうだよな・・・狭いのは当たり前だし、なかなか載らないようにしてるんだから、音すらしないよな・・・。

 

投げるのではなく、シールタイプのやつにして、そのままひらひらと舞い散るように落とした。
うん、その方がまだゲームっぽい感じがした。
しかし、やはりリーダライタの部分に載せるのは至難の業だ。

 

NFCアンテナの延長キットみたいなものがあったが、面積を広くすることはできるんだろうか。
あるいは、そこまでいったらアクティブタグの方が向いてるかもしれない。
でも、リーダライタが高いっていってたよな・・・。


 

普段、ツールしか作らないんだけど、たまには違うものを作るとおもしろいですな。

MIFARE ClassicはType 7 Tagとなるのか?

昨日コメントで、OpenNFCのドキュメント[PDF]を教えてもらった。

Type 1~4 Tagはいいとして、5とか6とか7とか書いてある・・・。
OpenNFCはInside Secure社が中心となって行っているプロジェクト(だと思っている)で、NFC ForumのPrincipal Memberでもある。
Principal Memberがどういう位置にいるかは知らないが、NFC Forumで決めようとしていることを先に知っていてもおかしくない。


Type 5[PDF](NXP Type Vとなってる)は、"NXP"と書いてあるので、別なのかもしれない。

Type 6 Tag[PDF]は、ICODEと書いてある。
日本で製品にしているところがあったが、ISO/IEC 15963らしい。NFC-Vってやつですか。
ということは「Type V」は「5」じゃなくて「vicinity」の方なのか?
いや、「5」でいいようだ。ドキュメント名が5になってる。

Type 7 Tagは、MIFARE 1K/4KやPlusとなっている。
ここでようやく標準に取り込むということなのかな。
であれば、AndroidのMifareClassicクラスもBroadcomチップを含むNCIで対応することになるのかもしれん。

 

(OpenNFCのSDKリリースノートより[PDF])

  • Type 5 Tagは、PicoPass(ISO 14443B/15693[PDF])
  • Type 7 Tagは、MIFARE Classic

こうやって見ると、NXPがんばってるなー、と思う。
FeliCaもこうやって表にばんばん出てくるとうれしいのだが、やはり戦略が違うから出てこないのだろうか。

と思ったが、あんまり製品がばんばん出てきても対応する方はめんどくさいな・・・。
願わくは、FeliCa LiteをNDEF対応するところまで含めて規格になってくれれば・・・。

[nfc]Type 3 Tagのちょっとした説明

月刊NDEF 2013年3月号は、NDEFのことをまったく書かないという斬新さだったが、さすがにいかんだろうと思った。
差分だけ置いた。

PDF

見る

自分でアクセスするときは、WriteFは操作していないし、チェックもしていない。
めんどくさいからだ。

春休みの宿題(追記)

そうそう、書き忘れたことがあった。
LEDは、アノードとカソードのどっちをどっちの電極につけても、点灯した。
つまり、交流というか、行ったり来たりしてるということだな。
NFCタグで能動的な部品は、剥いだチップだけのようだ。
Nexus7にかざしても、うんともすんとも言わない。
あんな小さな部品が、搬送波の中からコマンドを見つけ出して、それに応じて返事をしたり、自分宛じゃなかったら無視したりする上、データの保存までやるのか?
信じられん・・・。
世の中って進歩してるんだなあ、と感心した。

こういうときにオシロスコープがあれば観測できるんだろうが、うちにはそういうものがない。
ハードウェアのことはよくわからないから、持ってなくてもいいのだけど、ちょっと残念。
測ったことある人によると、Nexusなんかは定期的に変化しているという話だった。
私が興味を持ったのは、電流がプラスマイナスと変化するけど、どうやってチップが動いてるのだろう?というところだ。
でも、デジタルチップじゃなくてアナログチップなのだろうね。
よくわかんないけど、アナログだったらありだ。うんうん。

2013/03/26

春休みの宿題

At Japanese school, there is some homework in spring holiday.
・・・なんかちょっと書きたいことと違うような気がする。
「日本の学校では、春休みに宿題があります」と書きたかったのだが。
そもそも「春休み」ということばが、うまく訳せていないように思う。
学年が変わる前に2週間ほどある休みの期間、なのだが。

そういうのはどうでもよく、私ももうすぐ春休みが終わるので、宿題を終わらせなくては。
日本の長期休暇にある宿題と言えば「自由研究」だろう。
特に課題も無く、「何かしてきなさいね」というやつだ。
私はさっき思い出して、「搬送波でLEDを点灯させる」をやることにした。

思いつきだけでやるはずもなく、勝算はあった。
これだ。
ハンドメイドNFCワークショップ - slideshare
これを見ると、非常に簡単そうに書かれているので、やってみることにした。
いや、私だって少しは調べたことがあるのだ
5.5メートルの導線を買ってくるのもちょっと面倒だなぁ、と思ったのである。
スライドでは導線(エナメル線かな?)をぐるぐる巻いているが、私はNFCタグのアンテナを使うことにした。
image
わかりにくいが、「UPM」の下の「T」が指している当たりにあるチップを、カッターで剥いでいる。
剥いだチップは・・・ゴミにしか見えない。
ゴミというか、黒コショウの黒いやつだ。
これを剥がすと、2つの電極が切り離されるので、その間にLEDの端子を置けば導通するはずだ。
今回は、PaSoRi RC-S380をWindows7機に接続し、FeliCaランチャーを起動させて搬送波を出し続けてもらうことにした。
image

結果

LEDちかりちかり
うん、素直にうれしいですな。
指でしっかり押さえている様子がわかると思うが、上から薬瓶を置いたくらいでも大丈夫だった。
image
LEDは25年くらい前にジャンク品で買ったやつだと思う(私は物持ちがよいのだ)。

さて、初めてのYouTubeアップもやったことだし、もういいですかね?

[整理]Windows8とRC-S380

何度も書いているが、だんだんわからなくなってきたので、また整理する。

Windows8とRC-S380の組み合わせの場合に、どういう使い方をするのがよいか、ということについてだ。


毎回同じことを書いているような気がするが、これでいいのかな。

image

NFP(Near Field Proximity)を有効にしている場合、NDEFタグをかざすとNFPに持って行かれる。
NDEFタグでない場合は、デスクトップアプリであればPC/SCでアクセスが可能。
(ストアアプリではPC/SCのためのwinscardが使えないようだ。)

デスクトップアプリでPC/SCを使ったとしても、NDEFタグをかざすとPC/SCアプリじゃなくてストアアプリに持って行かれたり、ストアアプリからPC/SCを使うのに失敗したのは、以前実践済みだ
ただ「ストアアプリに持って行かれてる」のか「NFPに持って行かれてる」のかまでは確認していない。
NFPはストアアプリ専用だろうと思い込んでいるが、デスクトップアプリからWinRT APIを使うこともできるようなので、やればわかるのかもしれんな。

 

あとで検索したが、この説明がわかりやすいかな。
http://www.facebook.com/FeliCa.Japan/posts/355164961233975

 - DeskTop UI : PC/SC API(業界標準), FeliCa Library API(Sony独自)
 - Windows8 Style UI(旧Metro) : NFP API(Microsoft独自)

MIFARE ClassicのNDEF

Twitterを見ていると、Nexus4とNexus10はMIFARE Classic (MIFARE Standard)に対応してない、とのことだった。
AndroidのNDEF Formattableを調べているときにも書いたが、最近のAndroidはNFCライブラリへのアクセス方法を、従来のlibnfc-nxpを使うか、NFC Forumが策定したNCI(NFC Controller Interface)を使うかに分かれている。

今までのAndroid製品でNFC対応のものは、たぶんNXPのチップを使ったものがほとんどだったのだろう(PN544とか65Nとか)。
が、そういうチップ依存の状況を嫌ったのか、早く一般的な手法にあわせようとしたのかは知らないが、とにかくそうなっている。
Nexus4や10はBroadcom社のチップを使っているそうだ。
Broadcom社はNCIで機能提供している(のだと思う)から、AndroidでもNCIを使うようになっている。


MIFARE Classicは、NFC Forumが規格としているType 1 Tag~Type 4 Tagにあてはまらない。
libnfc-nxpがMIFARE ClassicをNDEF対応しているのは、NXP社の独自NDEFフォーマットに対応しているからだ(PDF)。
NCIでは義理がないせいかもしれないが、とにかく対応してないのだろう。
そういう意味では、FeliCa LiteがNDEF Formattableじゃないのと似てる。

ファイルだけ見ると、externals/libnfc-nxpと、externals/libnfc-nciがある。
だから、NCIのライブラリはlibnfc-nciなのだろう。
その中に「bcm2079x」というフォルダがあるので、これがBroadcom社のチップ用なのかな。
だが、Type 2 TagのNDEF判定はlibnfc-nci/src/nfc/tags/rw_t2t_ndef.cで行っているようだ(T2T_CC0_NMN)。
だからチップに依存せず、NCIを使っているならMIFARE ClassicはNDEFとみなさないだろう。

一番下のライブラリはexternals/libnfc-nciとして、その上はpackages/apps/Nfc/nciを含むNfcServiceになるだろう。
jni/NfcTags.cppにdiscoverTechnologies()があるが、そこではTechListになるものがMIFARE Ultralightしかなさそうだ。
(SEL_RESとUIDを見ているようだ。)
MIFARE Ultralight以外は、TARGET_TYPE_ISO14443_3A扱いになるみたい。
cppでのTARGET_TYPE_xxxxは、javaのTagTechnology.xxxxに対応している。

  • TARGET_TYPE_ISO14443_3A ==> NFC_A
  • TARGET_TYPE_ISO14443_3B ==> NFC_B
  • TARGET_TYPE_ISO14443_4 ==> ISO_DEP
  • TARGET_TYPE_FELICA ==> NFC_F
  • TARGET_TYPE_ISO15693 ==> NFC_V
  • TARGET_TYPE_NDEF ==> NDEF
  • TARGET_TYPE_NDEF_FORMATABLE ==> NDEF_FORMATABLE
  • TARGET_TYPE_MIFARE_CLASSIC ==> MIFARE_CLASSIC
  • TARGET_TYPE_MIFARE_UL ==> MIFARE_ULTRALIGHT
  • (?) ==> NFC_BARCODE

ざっと検索した限りでは、NCI側ではTARGET_TYPE_MIFARE_CLASSIC を使っているところがない。
だから、やっぱり対応していないのだろうね。

どうでもいいが、NFC_BARCODEも対応してないみたい。
まあ、たしかにNFC Forumの対象外なのだろうけど、突然AndroidでAPIを追加したわりには扱いが冷たいなあ。
それならFelicaLiteクラスだって追加していいじゃないか、ぶぅぶぅ。


が、これはもちろん、素のAndroidを使ったらそうなるだろうというだけで、組み込んだ会社が対応してしまえば、対応できる。
Nexusは、なんとなく素のAndroidを使うようなイメージがあるけど、メーカーが出すときには互換性とかあるだろうから各自でがんばるのかなあ。

MIFARE ClassicがNFC Forumの対象外になっている理由は知らないが、メモリが連続していないとか、アクセスするのに認証が必要になるとか、そういうところだろうか。
安価で大量に出回っているので、すぱっと切り捨てるのも難しいと思う。
NFC Forumで認証関係が落ち着いたら、Type 5 Tagとかになって現れたりするのかねぇ。

Bluetooth 4.0は、それまでと互換性がない

あと一週間でこの優雅な生活が終わる。
休みが始まったときには「毎日どうしよう・・・」などと思っていたものだが、始まってしまえばあっという間だった。
うぅ、もったいない過ごし方をしたような気もする。

優雅な時間の終わりは、とてもブルーだ・・・。
4番目の馬だっけ、青ざめているのは。乗っているものは「死」だ。
いや、そこまでブルーではないものの、それなりにブルーだ。

そんなわけで、今回はBluetooth 4.0の話だ。


ブルーなのは本当だが、実はそれはどうでもよく、今月発売のInterface誌の特集がBluetoothだったのだ。
ちょうどペアリングなどを見ていたこともあり、興味深く読んだ。

繰り返し書かれているのは、Bluetooth 4.0は従来の規格と互換性はない、ということだった。
4.0対応製品でも3.0のプロファイルが使えるようになっているが、それはそういう製品に仕立てているからできるのであり、純粋な4.0しか搭載していない製品だったら、3.0のプロファイルなどは使えないとのこと。

どうやって見分けたらいいんじゃい、と思ったら、それが「SMART」やら「SMART READY」マークらしい。
世の中について行ってないなあ。。。


うーん、やはりBluetoothのことを調べても、ブルーな気分が直るわけではないようだ。

2013/03/20

NDEF Formatter

NDEFタグをフォーマットするだけのアプリを置きました。
署名はしてますが、野良です。

https://sites.google.com/site/hiro99ma/home/files/freeapk/FLFMT.apk?attredirects=0&d=1

Android 4.2.2のみ対応してます(たぶん、APIとしてはもっと下でも動くはず)。

NDEF Formatと、UnNDEF Fomratの2つがあります。

 

NDEF Format

タグがどうなっているかで、動作が変わります。
下の処理を、上から順に見ていって、最初に引っかかった処理を行います。

  • NDEFフォーマット済みの場合(android.nfc.tech.Ndef)
    AndroidのNDEF書き込み機能で、TNFがEmptyのNDEF Messageを書き込む。
  • NDEFフォーマットが可能な場合(android.nfc.tech.NdefFormatable)
    AndroidのNDEFフォーマット処理で、TNFがEmptyのNDEF Messageを書き込む。
  • NFC-Fの場合(android.nfc.tech.NfcF)
    MCレジスタを操作してType 3 Tagとして扱えるようにしたあと、TNFがEmptyのNDEF Messageを書き込む。
    それ以降のユーザ領域は、0x00でクリアします。
  • それ以外
    何もしない

MIFARE Ultralightは、NDEFフォーマット済みか、NDEFフォーマット可能のどちらかになると思ってます。
それ以外でも、Androidが対処してくれそうなものであれば、上の処理2つのどちらかになるでしょう。
FeliCa Liteは、未フォーマット状態があり得るので、MCレジスタ操作を加えています(1次発行まではしない)。

 

UnNDEF Format

MIFARE UltralightとFeliCa Liteだけしか対応してません(たぶん)。

  • NFC-Fの場合(android.nfc.tech.NfcF)
    MCレジスタを操作してFeliCa Liteのみにしたあと、ユーザ領域を0x00でクリアします。
  • MIFARE Ultralightの場合(android.nfc.tech.MifareUltraligh)
    ユーザ領域に、サイズ0のNDEF TLVと、Terminator TLVを書き込んだ後、残りを0x00でクリアします。
  • それ以外
    何もしない

MIFARE Ultralightは、NDEF化すると元に戻れません(OTPという1回しか書き込めない領域を使うため)。
NDEF化したあとでユーザ領域を0x00でクリアしてしまうと、AndroidがNdefFormatableとみなさないようになってしまいました。
どうやら、NDEF TLVがないとダメなようでした。
仕方なく、NDEF Messageとしては何も書き込まないNDEF TLVだけを書き込むようにして逃げました。

 

使い方

アプリを起動すると「NDEF Formatてr」という画面が表示されますが、ここでNDEFタグにタッチしても何もしません。
一度画面をタッチすると、上にアプリ名と、下に切り替え用のボタンが表示されます。
これが表示されている間にタッチすると、確認無しでフォーマットします。
フォーマット後は確認ダイアログが表示され、OKしないとフォーマットしないようにしています。

通常は1秒くらいで元に戻るのですが、うまく行かないときもあるようです。
あまり気にしていません。

今さら気づいたんですが、NDEF Formatterの方はアプリ名なしのフルスクリーンなのに、UnNDEF Formatterの方はアプリ名が表示されているんですね・・・。
あまり気にしないことにします。

 

Nexus7でしか動作確認していません。
なにかあったら、ごめんなさい。。。

2013/03/18

[android]OTPがNDEFになると、NdefFormatable#format()に失敗することがある?

こんな時間まで何やってるんだか・・・。

FeliCa Liteのフォーマッタを作っていた。
しかし、それだけだと寂しいので、NDEFフォーマットするやつと、非NDEFフォーマットするやつを作った。
もちろん1次発行済みのFeliCa Liteであればできないのだが、MC[3]に書き込みができるなら元に戻せるのだ。

 

では、とMIFARE Ultralightにも対応しようと考えた。

 

まず考えたのは、かざし終わったNDEFタグを、そのまままた読み込むような動作ができるかどうかであった。
というのも、NFC-Fが非NDEFフォーマットしているとき、それをフォーマットしてNDEFタグにしたとしても、AndroidとしてはNDEFと思っていないので、せっかくのNdefクラスが使えないからだ。

これはあきらめて、NdefFormatable#format()と同じように、引数にNdefMessageを渡したら書き込むようにした。

 

あとはそこまで難しくない。
Ndefとして検出したなら、TNF_EMPTYを書き込む。
NdefFormatableとして検出したなら、TNF_EMPTYでformat()する。


じゃあせっかくなので、非NDEFにも対応しようと考えた。
対応は、MIFARE Ultralightだけ。
やることは簡単で、データ領域を0x00で埋めるだけだ。

そうすると、NDEFタグとして認識しなくなった(NXP TagInfoで確認)。

最後にNDEFフォーマットして寝るか、と思ったら・・・失敗する。
NdefFormatable#format()を呼び出すのだが、IOExceptionが発生するのだ。
これは困った。

 

まずは書き込みができなくなったのかもしれない、と思って、データ領域を0xFFで埋めた。
そしたら・・・0xFFで埋まった。
書き込みはできる。
うん、でも埋めた領域はデータ領域を超え、Lock領域にも及んでいたようだ。。。
おかげで、そのタグは後半が0xFFのまま書き込み禁止になってしまった。。。
まあ、前半は生きているからいいだろう。

私のフォーマット方法が悪いのかと思い、NXP TagWriterを使ってみた。
同じく失敗。
Tag Lostになる。

腹が立ったので、他の生きているデータ領域の5byteをまねして書き込んだ。
そうすると、format()できるようになった。


推測だが、OTP領域(NFC ForumのT2T資料でいうCC)にNDEFのマジックナンバーを書き込むと、Android側が「これはNDEFタグだから、データ領域の先頭はこれこれこうなっていないといけない」と判断してしまっているのだろう。
Nexus7(4.2.2)の動作なので、libnfc-nxpだろうか。
Broadcomのチップを使っている端末で起きないなら、libnfc-nxpかな。そうでなければOS部分か。

まあ、NdefFormatableの定義もちょっと曖昧な気がするので、バグと呼ぶのは悪い気がするな。

2013/03/17

[android]IntentFilterのマッチング(注:2年半前)

2年半くらい前に作っていた、AndroidのIntentFilterマッチング処理の資料が出てきた。
もったいないので、置いておく(astah* communityで作成)。
https://sites.google.com/site/hiro99ma/home/files/other/intent-filter.asta?attredirects=0&d=1

さて・・・2年半前って、OSのバージョンは何だったんだろうね。


IntentFilter.match()は、おおざっぱに書くと、こうだ。

if (action文字列がnullではない) {
  if (action文字列が一致しない) {
    return アクション不一致;
  }
}
dataMatch = dataマッチング(type, scheme, data);
if (マッチングしない) {
  return マッチングしない;
}
categoryMatch = categoryマッチング(categories);
if (マッチングしない) {
  return categoryがマッチングしない;
}
return dataMatch;

typeは、Intent.resolveType()だということだ。

IntentFilterの書き方がわからなくて調べたんだったと思う。
今だと簡単に説明しているサイトがありそうだなあ。

  • <intent-filter>の比較は、<intent-filter>ごとに行われる。
  • actionのみのintentを受け付けるのであれば、同じ<intent-filter>にまとめてよい
  • actionとschemeがあるintentを受け付けるのであれば、同じ<intent-filter>にまとめてよい
  • categoryを含む場合は完全一致となるので、同じ<intent-filter>にするかどうかには注意すべし

と自分では思っているが、そんなにintent-filter自体を書いたことがないので、あやしいかも。

[android]画面遷移を学ぼうとするも、難しいことに気付く

Annotationの調べを進めていて気付いたが・・・私はそれよりも先にやるべきことがあるはずだ、と思うようになった。
今は亡き(と思う)、Personal Java時代にちょろっとかじったくらいの私には、Javaがまだわかっていないのだ。
そんな私がAnnotationを見ようなんて、庭のビニールプールで遊んでいる子供がいきなり荒海の小島を目指して泳ぐようなものだ。
順番にやっていこう。

最初に選んだのは、画面遷移だ。
Javaじゃないんだけど、そもそもJavaを全部把握するなんて、私には無理だ。
実際に使うところから学んでいこう。


Androidの画面遷移について説明してあるサイトは、非常に多い。
それだけ重要なのだろう。

まずは練習として、1つのアプリに2つのActivityを作り、ボタンを押すとstartActivity()で切り替わる、ということをやった。
うん、これは動く。

ただ、BACKキーを押すと、ひたすらスタックに積まれた前のActivityに戻ってしまう。
startActivity()するだけだと、新たにインスタンスを作っていくようだ。

では、BACKキーを押したらもう戻らないようにしよう。
調べると、startActivity()したいインテントにフラグを設定すればよいらしい。

intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

やってみたのだが、私のイメージとちょっと違っていた。
ActivityのAとBがあるとして、

ランチャー→A→B→A→B→A→(BACK)

とするとホーム画面に戻るのだが、

ランチャー→A→B→A→B→(BACK)

とすると、Aに戻るのだ。次にBACKを押すと、ホーム画面に戻る。
AndroidManifest.xmsで<activity>のlaunchModeを変更したが、どれも同じ動きだ。


別の設定がないか探すと、noHistoryというものがあった。
これを使うと、launchModeがstandardだろうとsingleTopだろうと、BACKキーでホーム画面に戻った。
(その代わり、アクティビティBでホーム画面に戻ってから再度アプリを立ち上げても、アクティビティAになる。)

launchModeがstandardだと、毎回アクティビティのインスタンスを作成するのにうまくいくのは、noHistoryがtrueだと「見えなくなったアクティビティは終了する」という動作になるからだろう。
見た目は同じだけど、毎回生まれ変わっているので、注意がいる。
たぶん今回の私が期待する動作はsingleTopだろう。

 

と思ったが、noHistoryが裏に回ったアクティビティを終了させるのなら、singleTopにしていたとしても同じではないか。
そんな心配をするくらいだったら、アクティビティ間で共通するデータは別に持つようにした方がよさそうだ。

また、ツールのdumpsys activityを使って見てみると、noHistoryにしていたとしてもA→BとしたときにAはヒストリーに残っているようなのだ。
見方が悪いのかな?

 

などなど、一筋縄でいかないことがわかってきた。
ネットで調べるのもめんどうなので本を買いたいところだが、手持ちの本はそこら辺が書いてないので、また買っても同じかも・・・という気もしている。

まあ、見に行くか。

2013/03/16

[java]Aptina Unitを使ってみたが、正しい使い方かわからん

JavaのAnnotation。
Pluggable Annotation Processing APIというらしいのだが、動いているかどうかがわからん。。。

見ていくと、Aptina Unitを使うのがよい、と書いているところが多かった。
よくわからないなりに、人々のサイトを参考にしながらやってみた。

こちらが、一番参考にさせていただいたサイト。
 Aptinaを利用するとAPTのテストが簡単に書けたよ - kurukuru-papaの日記

ここまで解説があってもわからないのが初心者の哀しいところよ。。。
使っているのは、ADT Build v21.1.0-569685。
JUNOベースらしい。

なお、動かしてみただけなので、やりかたが正しいかどうかはわからんです。


まず、Java Projectを作る。
ここでは「Java_Test6Unit」という名前で進める(なんて適当な名前なんだ・・・)。

srcフォルダの下に、自作Annotation一式のソースファイルを置く。
「下に」といっても、Javaファイルをそのまま置くのではなく、ちゃんとフォルダを掘るのだ。
私は「com.blogpost.hiro99ma.anno」というパッケージ名だったので、そう掘った。

image

 

名前はGetSetだが、中身はgetterとかsetterとは関係が無い。
あとでがんばろう。。

GetSet.java

package com.blogpost.hiro99ma.anno;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.TYPE)
public @interface GetSet {
	boolean setter() default true;
	boolean getter() default true;
	String prop();
}

 

GetSetProcessor.java

package com.blogpost.hiro99ma.anno;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.Messager;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic.Kind;
import javax.tools.FileObject;
import javax.tools.StandardLocation;
@SupportedSourceVersion(SourceVersion.RELEASE_6)
@SupportedAnnotationTypes("com.blogpost.hiro99ma.anno.GetSet")
public class GetSetProcessor extends AbstractProcessor {
	@Override
	public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
		if (annotations.size() == 0) {
			//annotation処理済み
			return true;
		}
		Messager messager = processingEnv.getMessager();
		Filer filer = processingEnv.getFiler();
		try {
			FileObject file = filer.createResource(StandardLocation.SOURCE_OUTPUT, "", "hiro99ma.txt", (Element)null);
			PrintWriter writer = new PrintWriter(file.openWriter(), true);
			//annotationが使用されている要素
			for (TypeElement anno : annotations) {
				for (Element elem : roundEnv.getElementsAnnotatedWith(anno)) {
					GetSet getset = elem.getAnnotation(GetSet.class);
					//propに設定されている文字列が"hiro99ma"だったらメッセージを出す
					if (getset.prop().equals("hiro99ma")) {
						writer.println("おう : " + elem);
						messager.printMessage(Kind.NOTE, "You must be HIRO99MA.", elem);
					}
				}
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return true;
	}
}

 

自作Annotationを使うJavaファイルを作る。
場所はどこでもいいのだろうが、同じパッケージにした。
名前も何でもよさそうなので、「Foo」にした。

package com.blogpost.hiro99ma.anno;
@GetSet(prop = "hiro99ma")
public class Foo {}

 

AptinaTestCaseをextendsしたclassを作る。
これが、Foo.javaをコンパイルして、実行までやってくれるようだ。

package com.blogpost.hiro99ma.anno;
import java.nio.charset.Charset;
import java.util.Locale;
import org.seasar.aptina.unit.AptinaTestCase;
public class TestProcessorTest extends AptinaTestCase {
	public TestProcessorTest(String name) {
		super(name);
	}
	@Override
	protected void setUp() throws Exception {
		super.setUp();
		setLocale(Locale.JAPANESE);
		setCharset(Charset.forName("UTF-8"));
		addSourcePath("src");
	}
	public void test() throws Exception {
		GetSetProcessor processor = new GetSetProcessor();
		addProcessor(processor);
		addCompilationUnit(Foo.class);
		compile();
		assertEqualsGeneratedSourceWithFile(
						"oops.txt",
						"com");
	}
}

サイトの方も書かれているが、setUp()でsetLocale()などをやらないと、addCompilationUnit()がエラーになってしまった。

あと、addSourcePath()で追加するのは、いわゆる「ソースフォルダ」の先頭みたいだ。
「src/com/・・・」と指定してたが、だめだったのだ。

 

ここまで追加すると、Eclipseがエラーをあれこれ出しているので、プロジェクトの設定をする。
もちろん、最初にやっててもよい。

まず、Aptina UnitのJARファイルを追加する。
ここからダウンロードし(今はAptina-1.0.0.zipだった)、解凍する。
中に「lib」フォルダがあり、その中に「aptina-unit-x.x.x.jarが入っている(私はaptina-unit-1.0.0.jar)。
これを適当にコピーして、プロジェクトの設定でLibrariesに追加。

image

これでよいかと思ったが「junit.frameworkがない」みたいなことを言われる。。。
よくわからんので、JUnit4をダウンロードして同じように追加した。
したのだが、もっと普通の方法があった。

上の画面で「Add Library ...」を押すと、JUnitが選択できる。
image

JUnit3かJUnit4かを迫られるので、新しい方がいいんじゃないの、と思ってJUnit4にした。

 

ここまでやると、Eclipseのエラーが出なくなった。
なお、プロジェクト設定でAnnotation Processingの設定は不要だ。


では、実際に動かしてみよう。

動いたかどうかがわからないというレベルなので、まずは自作のProcessorクラスのprocess()先頭にブレークポイントを設定。

そして、プロジェクト名で右クリックし、「Debug As > JUnit Test」を選択。
「Use configuration specific settings」にチェックし「Eclipse JUnit Launcher」を選択。
ここで「Java Application」を選択しても、ダメですぞ(それで悩んでた)。

 

そうすると、ブレークポイントのところで止まるんじゃないかね。
私のところは止まったよ。

2013/03/15

[java]Annotation Factoryのjarにはclassを入れる

Androidでボタンを追加するたびに、いつも同じようなことを書く。
ひどくめんどくさいし、覚えてないので腹立たしい。

そう思っていると「android annotationがある」という話を教えてもらった。
便利そうなものは使ってみよう!


と思ったが、なんだかわからないまま使うのも悪いので、このAnnotationのしくみを動かすサンプルぐらいやってみるか、と試すことにした。

参考にしたのは、こちら
Javaのpackage名以外は、そのままやったのだが・・・できたJarを設定してもEclipseが「unable to load annotation processor factory」みたいなことを言う。
パスがおかしいのか? package名がまずいのか? どこか書き間違えたか?
いろいろ見たのだが、わからん。
他のサイトも見たが、わからん。

2時間くらい悩んで、AndroidAnnotationsのJarを見てみることにした。
image

えー、classファイルを置くの??
みんな説明に「srcの下にMETA-INFを作って・・・」って書いてるから、JARにするときも*.javaファイルをやるものとばかり思ってたよ・・・。

classにすると、あっさりできた。


悔しいので、初心者なりに説明を(設定の)。

 

まず、Annotation Processorというやつは、Androidのプロジェクトとは一緒にできない。
新たに普通のJavaのプロジェクトを作ってやる。
Androidでは、それで作ったJARファイルだけを参照させることになる。

 

実装の仕方は、よくわからん。
他の人参照。
プロジェクトの構成は、特にこだわらないようだが、srcの下にMETA-INFを作成し、その下にservicesを作成し、その下に「javax.annotation.processing.Processor」という名前のテキストファイルを作る。
テキストファイルをエディタか何かで開いて、自作したProcessorのclass名をフルで書く。
私だと「com.blogpost.hiro99ma.anno.SampleAnnoProcessor」だった。
「extern」というフォルダは、JARの出力先として私が勝手に決めただけだ。

 

image

JARファイルを作る。
プロジェクト名で右クリックし「Export...」を選択。

「JAR file」を選択して、次へ。
image

JARにまとめたいファイルを決める。
.classpathと.projectはいらんだろう。
自分で作っていた「extern」もいらん。
下のチェックは「class files and resources」。
JARファイルの出力先や名前も適当に決める。
image

あんまり見てない。次へ。
image

ここもあんまり見てない。Finish。
image

JARファイルができた。

 

では、Annotationを追加する方。
プロジェクト名で右クリックし「Properties」を選択。

「Java Compiler > Annotation Processing」で、いろいろ有効にする。
生成場所は「gen」らしい。
image

Factory Pathに、さっきのJARを追加する。
私は「Add External JARs..」で追加したが、追加できればいいらしい。
image

 

ビルドパスも通すらしい。classがあるからか?
ないと、importするときに見つからんと言われるようだ。
同じようにLibrariesに「Add External JARs...」で追加した。
image

 

このくらいやると、使えるみたいだ。
私がAnnotationを調べ始めた理由を忘れてしまったが、まあいいや。

[android]やはりNfcFと互換を持たせよう

一晩寝て、気分が変わった。
[android]覚えているものを忘れるしくみ
やっぱり、NfcFクラスと互換性を持たせるようにしよう。
めんどくさいといっても、そんなにAPIは多くないから、我慢するのだ。
Eclipseとかだと、簡単にやる手段があるのかもしれんが、わからんので手書きだ。

FelicaLite.java

これならstaticのメンバ変数・・・じゃなくてプロパティというのか、がないので、忘れる忘れないも従来と同じレベルになったんじゃないだろうか。

 

本物のNfcFはBasicTagTechnologyをextendsしてるのだが、こっちはやってない。
なので、完全に互換があるわけじゃないけど・・・せっかく継承させてないのだから、断ち切った方がいいんじゃないかなと思った(というのは、後付けの理由だ)。

[android]最近のAndroidアプリの作り方を知らねば (6)

Type 3 Tagのフォーマッタを作って少し安心したが、実はあれは大したことをしていない。
特に画面周りなんかは、文言を変更したくらいしかやってないのだ。。。
もうちょっと、画面周りを調べておこう。

どうでもいいが、Type 3 Tagは「T3T」と略すことが多いのだけど、顔文字っぽいな。
(T 3 T) みたいな、口をとんがらせて涙を流しているようなイメージだ。


画面周りと言えば、まずはリソースだろう。
resフォルダを見ると、なんかいろいろあった。

  • drawable-hdpi
  • drawable-ldpi
  • drawable-mdpi
  • drawable-xhdpi
  • drawable-xxhdpi

画像だけで、これだ。
幸い、画像ファイルが少ない(ic_launcher.pngだけ)ので、原寸で載せていこう。

drawable-hdpi
image 72x72

drawable-ldpi
画像無し

drawable-mdpi
image 48x48

drawable-xhdpi
image 96x96

drawable-xxhdpi
image 144x144

以上だ。

48x48~144x144まである。
Androidのマルチスクリーン対応には、まだxxhdpiは載ってなかった。

2013/03/14

ucode

「ポストにNFCタグをつける」という記事があったが、もう少し詳細が出てきた。
NFCタグを丸の内エリアの郵便ポストに取り 付け情報配信(KDDI等) - payment navi

ucodeNFC ?
また新しいやつの登場か・・・。


と思ったが、調べていくとそうではなかった。
「ucode」という情報を書き込んだNFCタグを「ucodeNFCタグ」と呼ぶようだ。
同様に、QRコードも「ucodeQR」らしい。
(NXPにUHF帯のUCODEというものもあるようだが、これは別だろう。)

ucodeについては、こちら。
第604回:「ucode」 とは[2013/03/12] - ケータイWatch

  • 国際標準規格 ITU H.642.1
  • ものや場所に付けられる番号
  • 番号は消滅させることができ、そのときは欠番になる(再利用しない)
  • 128bitを基本とした識別番号

では、H.642.1で検索して・・・・。
Multimedia information access triggered by tag-based identification - Identification scheme
あれ・・ucodeとか単語が出てこないけど、間違ったのかしら。

いや、いいらしい。
ucodeをベースに確立したH.642(pdf)、という記載があった。
マルチメディア、というと音楽とか画像とかをイメージしてしまうが、文字通りマルチなメディアということで「なんでもかんでも」ということになっているのかな。


128bitの内訳は、H642では1LC(Level Code)~4LCという分け方らしい。

  • 1LC : 4bit。バージョン情報?
  • 2LC : 16bit。ITUメンバー状態(H.642.2)
  • CLASS : 4bit。Class9~14があり、3LCと4LCのビット比率を決めている。
  • 3LC/4LC : 104bit。
    3LC ... RA(Registration Authority)。
    4LC ... 個別に番号を振るための連番

ちょっと広すぎて、私の手に負えない。。。。

ともかく、調べるとっかかりくらいになればいいや、ということで。

[android]覚えているものを忘れるしくみ

Androidというか、Javaだ。

FeliCa Liteを操作するclassを作った(前から作ってたやつだが)。
最初は、MifareUltralightみたいに、NfcFに毛が生えたような操作だけ追加しようと考えていた。
が、

public final class NfcF extends BasicTagTechnology {

と、finalになってた。
じゃあ継承できんので所有させようかと思ったのだが、NfcF互換にするならメソッドを全部呼べるようにせんといかん。

うーん、それはめんどくさい。
ということで、NfcF互換は諦め、別のものにした。

https://github.com/hirokuma/FLFMT/blob/master/src/com/blogpost/hiro99ma/nfc/FelicaLite.java

static classだ。
どうせ同時に扱うNFCタグはたかだか1つなので、もういいだろうと思ったのである。
毎回引数でTagをもらうようにすればいいけど、それはそれでめんどうなので、最初にもらったら終わるまでFelicaLite内で保持するようにしている。

 

気にしているのは、この「保持する」のところ。
static classだから、保持するのもstatic。
明示的に忘れさせてもらわないといかんのだ。
自分で作ってる分にはそれでもいいけど、なんか他にいい手段はなかろうか。
enableForegroundDispatch()なんかも、同じといえば同じなので、もうメソッドのコメントでやーやー言うしかないのかね。

C++だと、スコープ外になるときにデストラクタが呼ばれるから、そのしくみを使うようにしてもらえばいいのだけど、これも結局はメンバ変数なんかで保持されたら同じなのだ。
Cでやってるとそれが普通なので、使う側の責任にはなる(そして忘れてバグる)のだけど、それだったらそもそもそういう実装をした方が悪い、という考え方もある(まあ、メモリが足りなくてそうせざるをえんことも多いのだが)。

Androidはメモリが多いんだから、static classとかしないでインスタンスをばしばし作ればいいやん、という気もするのだが、やっぱりもったいないという気もしてしまう。

うーん、悩ましいですわ。

[android]フォーマッタ

FeliCa Liteをかざすと、NDEFフォーマットするアプリを作った。

https://github.com/hirokuma/FLFMT

 

ユーザへの確認も何もなく、フォーマットする。
既存データも含めて消すので、危険だ。
消したいときに使おう。

なんで作ったかというと、フォーマッタがほしかったからだ。
データを書くツールはあるけど、消すのがなかったんでね。

[android]どれだけnullチェックする?

お勉強がてら、Androidアプリを作っている。
がてら、というか、お勉強だ。

onCreate()にこんなコードを追加した。

mAdapter = ((NfcManager)this.getSystemService(Context.NFC_SERVICE)).getDefaultAdapter();
mPendingIntent = PendingIntent.getActivity(
				this,
				0,		//request code
				new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP),
				0);		//flagなし
mFilters = new IntentFilter[] {
				new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED)
};
mTechLists = new String[][] {
				new String[] { NfcA.class.getName(), NdefFormatable.class.getName() },
				new String[] { NfcA.class.getName(), Ndef.class.getName() },
				new String[] { NfcF.class.getName(), NdefFormatable.class.getName() },
				new String[] { NfcF.class.getName(), Ndef.class.getName() },
};

さて、このうちどれをnullチェックすべきなのだろうか?

全部やればいいのはいいのだろうけど、実装量が多くなるし、そうなるとバイナリサイズも大きくなるし、動作も遅くなる。
それよりなにより、めんどくさい。

C++だと、例えばgetSystemService()がNULLポインタでないことを確認してからgetDefaultAdapter()を呼ばないと、不正メモリアクセスということでMMUとかから怒られ、try-catchも効かないだろう(getSystemService()が例外を出せばいいんだけど)。
Javaは幸い、nullポインタ参照や0除算とかは例外で扱えるので、try-catchで囲んでおけばいいだろう(nullチェックした方がきれいな気はするがね)。

でも、mFiltersは、IntentFilter[]のnewで失敗するかもしれないし(newの失敗は例外を出すのかな?)、中のIntentFilterのnewで失敗するかもしれない。
例外が出ないのだったら、自分でforでぐるぐるとnullチェックをすることになるだろう。
他のだって、String[]のnewに失敗するかもしれんしね。

 

ただ・・・そこまでせんでもよいのでは、という気がなんとなくしている。
OS積んでるんだから、なんかうまいことやってよ、というお祈りのような気分だ。
この程度のnewで失敗するようなら、アプリ自体起動できないのでは、とか。

こういうお作法的なものは、どうやって身につけるものか。
誰をどの程度信用するか、とかかねぇ。。。

[android]NdefFormatable

android.nfc.tech.Ndefandroid.nfc.tech.NdefFormatableがある。
自分で試してないけど、こちらによるとNDEFを書き込む前はNdefFormatableで、NDEFを書き込んだらNdefになるそうだ。
つまり、NdefFormatableに反応するということは、NDEFが書き込まれていないということだろう。
そしてNdefFormatableの場合には、formatすることができるそうだ。
それはいいのだが、どこかで「FeliCa LiteはNdefFormatableにならない」ということを聞いたような気がする。
私も以前調べたことがあるが、もう一度調べ直そう。

最初にNFC-FとType 3 Tagについて簡単に書こう。
私が知っている範囲でだが、NFC-FのタグはFeliCaしかないと思っている。

FeliCaのタグ製品としては、FeliCa StandardとFeliCa Lite / Lite-Sがある。
これらは、どちらもNFC-Fと考えてよいと思う。
 
しかしType 3 Tagとなると、これはFeliCa Lite / Lite-Sしかないと思われる。
それも、条件付きでの対応になる。
FeliCa Standardはなぜ除外するかというと、これは「私が知らないから」というだけだ。
一般に使われているFeliCa Standardのタグは、nimocaやSuicaのようなものだ。
FeliCaには「システム」という考え方があり、普通のタグは1枚1システムだ(ったと思う)。
Type 3 Tagは「0x12FC」という番号のシステム(以下、システムコード)を使うようになっているが、
そういうタグが作れるのかどうか知らない、というところである。
まあ、作ることができてもおかしくはないがね。
FeliCa Liteが条件付きなのも、そのシステムのせいである。
作られたばかりのFeliCa Lite(0次発行、という)のシステムコードは「0x88B4」である。
0x12FCではないので、Type 3 Tagではないのだ。
じゃあ、FeliCa LiteがType 3 Tagとして使えるのはどうしてかというと、FeliCa Liteの設定によって
0x12FCというシステムコードにも応答するようにできるからだ(設定して状態を確定させることを、1次発行、という)。
このシステム設定は、NFC Forumなどとは関係が無い、FeliCa Lite製品の動作である。
そういった個別製品の動作を製品に組み込みたいかというと、あんまり入れたくはないだろうな。
AndroidでFeliCa LiteのNDEFフォーマットができないのは、たぶんそういう事情からだろう。
もし純粋なType 3 Tagの製品があるならばNdefFormatableになるかもしれんね。

では、さっさとNdefFormatableの決め方を調べておこう。
ソースしか追わないので、間違ってたら済まん。
最近のAndroidソース一式を持ってきた。たぶん4.2.2くらいだろう。
4.0.3くらいのときは、NXPのNFCチップを使うようになっていた。
今では、NCI(NFC Control Interface)へも対応ができているようだ。
NXPのソースも共存しているのは、まだNXPの部分はNCI対応していないからだろう。
AndroidにNFCが搭載されていた頃はPN544が、Nexus7ではPN65が載っていたと思うが、最近はNXPではなく
Broadcomのチップを使っているという話を読んだことがある。
BroadcomのチップはNCI対応しているのだろうし、今後は全部NCIで統一するのだろうね。
そんなわけで、NXPとNCIで多少動きが異なる。
NXPの場合、NativeNfcTag#isNdefFormatable()でやっている。
  • MIFARE Classic : OK
  • MIFARE Ultralight : OK
  • NFC-V : UID依存でOK
  • ISO-DEP : NFC-AならOK?
  • それ以外 : NG
libnfc-nxpが対応しているかどうかで決めているように見える。
 
NCI版も同じ関数はあるのだが、呼びだすのはJNIの方になっている。
  • Type 1 Tag : OK
  • ISO-15693(NFC-Vね) : OK
  • Type 2 Tag : MIFARE UltralightならOK
  • それ以外 : NG

MIFARE Classicが除外されてたのは、もともとMIFARE ClassicはNFC Forumの対象外だからだろう。
NXP自社だから優遇されていたのだろうな(Androidのクラスには残ってるけど)。

今度はType 1 Tagが優遇されたように見えるが、これはBroadcomがTopaz/Jewelを持っているからだろう。
こういうのを見ると、SONYさんにがんばってもらわんとな、と思ってしまいますな。


FeliCa LiteをNDEF Formattableにするなら、まずこの辺をいじることになるんだろうね。
もちろん、実際にformatするところも作らないかんだろう。
NCIがその辺をどうサポートしているのかは、まだ全然見ていない。。。

2013/03/13

[n7]Windows7でNexus7がMTPとして認識してなかった

以前、似たようなことがあった。
あのときはXP(32bit)で、Nexus7をUSBに挿すとデバイスマネージャでMTPがエラーになっていたのだ。

今回はWindows7(64bit)で、デバイスマネージャーにはMTPすら出てこない。
USBデバッグの有効/無効には関係ない。
カメラとしては認識できるのだが・・・

http://android.stackexchange.com/questions/26689/problem-connecting-nexus-7-as-mass-storage-device-on-windows-7

これに書いてある通りにやると、できた。

2013/03/12

Bluetooth 2.0では、まだペアリングが簡易になっていない

BTでStatic Handoverがうまくいかんかった件についてコメントをいただいた。
「Bluetoothのバージョンは?」

えっっ。
Bluetoothのバージョン??
まったく考えてなかった・・・。
デスクトップPCの方は、2.1+EDR。
ノートPCの方は、2.0+EDR。
なんでも、2.1になってから自動PINコード入力が実装されたのだとか。
ならば、うまくいかなかったのはOSやペアリング経験済みとかではなく、単にノートPCのBluetoothバージョンが2.0だったためだということか・・・。

Wikipediaの説明によると、2.1からペアリングが簡略化されたとのこと(ケータイWatchがわかりやすいか)。
これが、2007年3月のこと。
うちのノートPC(ThinkPad T61)はBluetooth内蔵なのだが、発売が2007年5月。
まだ2.1が普及していなかったのだろうな。
そういえば、NFC ForumのBTペアリングも、2.1+EDRのドキュメント参照になっていたな。
うぅ、なんたる失態よ・・・。

この汚名を返上するためには、ノートPCに2.1のドングルをつけてペアリングさせるしかあるまい!
幸い、プリンタ用のBluetoothドングルがあるので、それをつなぎさえすれば・・・・。
・・・・。
・・だめだ、やっぱりペアキー入力画面が出てくる。
そういう問題じゃないのか?
あ、このBluetoothドングルも2.0だった・・・。
うちにある2.1以上のBluetoothは、Nexus7とデスクトップPCで使っているやつだけみたいだ。
全然気にしてなかったわ・・・。

デスクトップPCで使っているドングルを使うと、ペアキーを求められるのではなく、「このペアキーでよい?」という確認画面になった。
これでよいということか。

しかし、ちょっと不満がある。
PCのBluetoothを「私を見つけて!」にしないといけないところだ。
だって、Static HandoverのデータとしてBTのMACアドレスを記載しているのだ。
それなら、PC側は何もせずに見つけてほしいと思ったのだ。
これだったら、AndroidのBluetooth設定画面を開いて、周囲の検索をタッチして、出てきた端末をタッチすれば、同じようにペアキー確認画面が出るからなあ。
・・・まあ、この手間が面倒といえば、面倒だな。
かざすだけだと、ステータスバーみたいなところに「ペアリング要求があります」みたいなのが出るまで待てばいいわけだ。
今回はノートPCとかでやったから、PC側も認証画面が出てきたけれども、これが専用機器(スピーカとか)だったらその操作もいらないので、もうちょっと簡単に思えることだろう。

こんだけのためにBT2.1以上の機器を買い直すつもりはないのだが、注意しとかんとな。

NDEFを書くときは、空いたところも消した方がよいと思った

これは、自分の反省というか、注意すべきところということで書き残しておく。

私がNDEFのタグを作るとき、必要最低限のブロックしか更新しない。
特に理由はなく、わざわざ消さんでいいだろう、くらいのものだ。

でも、前のに上書きすると、そういう書き方だと前のデータが残ってしまうのだ。
消してないのだから当たり前なのだけど、上書きした人からすれば「前のは消えただろう」と思うはずだ。
だから、消すべきだ、と思った。

 

仕様としては、そのブロックの終わりまでは0x00で埋めること、くらいだったような気がする。
読み飛ばしているだけかもしれんがね。

NDEFフォーマットされたタグであれば、データ領域のサイズがわかるはずなので、その分だけ消せばよいだろう。
フォーマットするソフトは、なんとかしてタグのサイズを調べんといかんので、ちょっとめんどうだろうな。

2013/03/11

[android]最近のAndroidアプリの作り方を知らねば (5)

テーマは、4つあった。

  • なし
  • 全体的に暗め
  • 全体的に明るめ
  • 全体的に明るめ(暗めのアクションバーあり)

アクションバー(action bar)?
どうやら、アプリの上などにある、ツールバーというか何というか、そんなやつみたいだ。
HTML5でいう、<nav>のところになるんだろうか。
http://www.androidpatterns.com/uap_pattern/action-bar

 

まあ、それはいいとしよう。
気になるのは、なんでそんなものが現れたか、だ。
おそらく、似たような機能は以前のAndroidでも実現できたのだと思う。
それを標準的な機能としたということは、何らかの意図があると考えるべきだろう。

こういう記事があった。
http://yuki312.blogspot.jp/2012/07/androidmenuactionbar.html

Android3.0までは、ハードウェアキーとしてMENUキーを用意することがしばしばだったのだが、だんだんとMENUキーをなくしてしまって、ソフトウェアキーで済ませるようになってきたそうだ。
ソフトウェアキーなので、画面に表示しないといけない。
でもどこに? ということで、そういった動作を配置するための場所が必要になったということか。

http://developer.android.com/design/patterns/actionbar.html
Androidのデザインとしては「そのアプリを動かしている間は(だいたい)変更せずに画面の一番上にある専用の場所」ということにしたいらしい(real estate、だし)。

 

やっぱり、いろいろ覚えることがあるねぇ。

[android]最近のAndroidアプリの作り方を知らねば (4)

アプリプロジェクトを作るウィザードの最初に「Theme」がある。
デフォルトは「Holo Light with Dark Action Bar」となっている。

image

テーマ別の画像は、ここにあった。
http://developer.android.com/design/style/themes.html

以前からテーマという設定はあったが、ウィザードでは設定できなかったように思う。
WindowsやFirefoxのテーマと同じような、全体の根底に流れる雰囲気、みたいなものだろうか。

 

ソフト開発というか、製品開発にあたっては「テーマ」が不可欠だ。
「この製品は、こういう風にありたい」という指標がないと、ただでさえ開発者は自分の好きな方向に解釈しがちなので、迷走しがちになるのだ。
「好きな方向に解釈」は怠慢ではなく、どちらかといえば気を遣ったために起こることが多いように思う。「訊きたいけど、忙しそうだから後にしよう」とか「さっきも訊いたばかりだから、また訊くと迷惑だろう」とか。

管理側としては、そういう風に思われないように注意しないといかんだろう。勝ち負けではないのだが、そう思われたら管理側の負けであるし、それはプロジェクトが終わるまで引きずってしまうように思う。
精神的な余裕を作るためでもあり、周囲にそれを知らせるためにも、管理者は基本的に現場作業を持たない方がいいと思っている。
まあ、そうもいかないことが多いけどね・・・。

 

いかんいかん、いろいろ考えてしまった。
Androidでいうテーマは、もちろん見栄え上のテーマである。
「Holo」がなんかわからないけど、"holo-"は「全体の」というような意味だった。
つまり「全体的に明るめ」とか、「全体的に暗め」とかなんだろう。

[android]最近のAndroidアプリの作り方を知らねば (3)

Androidの今までを全部を把握しようとか、最近のものだけでも把握しようとかするのは、とても無理だということがわかっているので、あきらめて開発をやろう。

今回はAndroid SDKを使う。
NDKという日本電波工業がリリースした・・・じゃなく、Native Development Kitもあるが、こっちはやらない。

最近はeclipseを拡張したADTというツールがリリースされているので、それを使えばよい。
設定は他のサイトの方が親切に説明していると思うので、やらない。


さて、ADTを使うと、アプリのテンプレートを作ってくれる。
楽だ。

ただ・・・「com.example.」がデフォルトになるのは、変更できるとうれしい。
確かに、最初の1回しかやらないんだけど、なんか、こう、ねぇ。
忘れてしまって、そのままパッケージを作ってしまうこともあるやん。
うん、忘れなければいいんだけどね。
TABでテキストボックスを移動させると「com.example」だけが選択状態になるから、ちゃんとわかってるのよ。
そうだよね、そうだよね。。。

 

・・・いや、そうじゃない。
探してみるんだ!
探せば、きっと何かが・・・・何かが・・・

出てこなかった。
"example"で全文検索する、というめんどくさいことまでやったのだが、それっぽい箇所を見つけられなかった。
plugin_customization.iniがそれか、とも思ったのだが・・・

力尽きた。

[android]最近のAndroidアプリの作り方を知らねば (2)

「最近の」って書いたが、いったい何がどうなったら最近なんだろう・・・。
Androidのことをよく知らないことに気付いた。
「敵を知り、己を知れば・・・」という言葉があるが、Androidが敵か味方かはわからん。
わからんが、どっちにせよ知らんと負けるということだけはわかる。

では、2013年3月11日現在の状況を調べておこう。

 

http://developer.android.com/about/dashboards/index.html
世に出ているバージョンの最新は、4.2らしい。
4.2はAPIレベル 17。その前の4.1は、APIレベル 16。
repoのmasterは、4.2.2_r1が番号からすると一番新しそうだ(うちのNexus7も4.2.2)。
4.2も4.1も、コードネームは"Jelly Bean"。バーバパパみたいなやつだな。

しかし、世に出回っているという意味では2.3~2.3.7の"Gingerbread"。
開発する側からすると、せっかくOSが無料だから採用したのに、ばんばんバージョンアップしたらそっちの方で金がかかってしまうよ、ということなのかね。


バージョンによって何が違うか、少し見ておこう。

→4.0になったとき(2011年10月19日)
http://gigazine.net/news/20111019_android_4_ice_cream_sandwich/

→4.1になったとき(2012年6月28日)
http://gigazine.net/news/20120628-google-android-jelly-bean/

4.2は、探し疲れたので、無し。。。

あっさり言えば「いろいろ変わった」ということだ。


調べていてわかったのは、いろいろ大変そうだ、ということだった・・・。
画面サイズが1つで、搭載されている機能が固定されていた時代は終わったのだ。

まあ、携帯電話じゃない仕事になるかもしれないじゃないか。
私はそう考え、ひそかに涙をぬぐった。

[android]最近のAndroidアプリの作り方を知らねば (1)

そういえば、内定が出ました。
みなさま、ご心配をお掛けしました。。。
4月から、また仕事に復帰します(今も就職してるのはしてるが、お休み中)。
次になにやるかは不明(かつ秘密)だ。

 

が、下調べをするなら、やっぱり携帯電話関係だろう。
となると、筆頭はAndroidか。
しかし最近だと、TizenとかFirefoxOSとかUbuntuとか、そっち側も捨てがたい。

TizenとFirefoxOSは、HTML5を使うところもあるだろうってことで、先週はちょっとだけやってた。
まあ、まったく知らないのはまずい、という程度しかやっていない。
Tizenはネイティブアプリもやっておきたいし、せっかくNexus7があるんだから動かしてもみたい。


が、やっぱりAndroidはやっておかんとなー、と思っている。
私がソースを見ていた頃は、2.2くらいだったので、今とはずいぶん変わっていると思う。
それに、Androidがメジャーになってから、私は携帯電話の仕事をしてないのだな・・・。
TizenやFirefoxOSだったら「いやあ、まだ情報が少なくて」でごまかせるかもしれんが、Androidはさすがに何も知りませんじゃ済まんだろう。

私が担当するのは、たぶんAndroidだったとしてもアプリではないだろう。
けっこう下回りだと思う。
とはいえ、アプリを作ることもできんのに下回りを任せられるかというと、そういうもんでもあるまい。
私の上司がよく言ってたが「飛行機の操縦ができない人に飛行機のソフト開発を任せられるか?」ということだ。
まあ、全員が全員操縦できないとしても、中心メンバーは操縦できる人じゃないと心配だろう。

そんな訳で、下回りをやるためにも、アプリは少しくらい作れた方がよかろうとは思うのだが、とてもではないがまんべんなくやっておこう、なんてことは無理だ!
アプリはそんなに甘くない(下回りより大変だと思う)。

なので今回は消極的に「最近のアプリの作り方を調べて、それに沿ってやってみよう」ということにした。
・・・目標が低く見えるが、許してくれ。
せっかくNexus7があるので、NFCアプリにしておこう。
あまり使ったことがない、サービスとかインテントとか非同期とかもやっておきたい(非同期関連は難しいというイメージがあるため)。

まあ、何を作るのかは決めてないけど、宣言だけでもしておかないと目標がぶれそうでね。


では、実際に入社して、仕事が携帯電話じゃなかったら、どうしよう?

どうしようもない。
だって、そんなの現場に行かないとわからんし。
だから、そこは心配しても仕方ないので、忘れてしまえ。

[nfc]Static HandoverではBTのペアキー入力を回避できない?

※後日談あり (2013/03/12)

昨日、Bluetooth用のStatic Handover NFCタグを作り、ペアキーを求められたことを書いた。
その後、NXP社のアプリ「NFC TagWriter by NXP」でもタグを作ることができるということだったので、試してみた。
結果としては、私のタグと同じ動作をした。ペアキーを求められたのだ。

TagWriterで作られたタグを確認したが、まあ私のとだいたい同じ。
私の方が多いくらいだ。
Static Handoverだと、書く内容ってあんまり変わらないのだな。

 

しかし、市販のNFC対応の機器はペアリングでそんなのを求められるとは書いていない。
ということは、Static HandoverではBluetoothのペアキー入力を避けることができないのだろう。
そうしたいのであれば、Negotiated Handoverになるんだと思う。

Negotiated Handoverか・・・。
やるなら、NFC Forumのドキュメントだけじゃなくて、Bluetoothのドキュメントも見らないかん。
時間があるように見える私だが、そこまでの時間があるのだろうか・・・。

2013/03/10

[n7]Bluetoothのペアリング

Bluetooth機器は、ペアリングというものをしないと使えない。
そこまではわかるのだが、いつも何となくペアリングを行い、何となく失敗したり成功したりしている。
これは、理屈がわかっていないからそうなるのだ。

わからないものは、調べるしかない。

なお、うちにあるBluetooth機器は3つ。

  • デスクトップPC (Windows7 64bit) + USBドングル
  • ノートPC (Windows8 32bit) + 内蔵
  • Nexus7 (Android 4.2.2) + 内蔵

PC側のBluetoothはMicrosoftが提供しているドライバを使っている。
BUFFALOのBluetoothドングルで、東芝のドライバがついていたのだが、Windows7をインストールするときには何もしていない。

image


Microsoftの説明
http://windows.microsoft.com/ja-jp/windows7/add-a-bluetooth-enabled-device-to-your-computer

片方を「私を見つけて!」の状態にして、もう片方が「私が見つけてあげよう」という状態にしてやればいいようだ。

 

これは、周囲にBluetoothデバイスがなくて、Nexus7も見つけられないようにしている状態。

image

 

ここで、デスクトップPCを「私を見つけて!」にする。
SHIRANAMI、というのがデスクトップPCだ(うちのPC名は、焼酎銘柄)。

image

なお、使用可能なデバイスが更新されるタイミングは、AndroidのBluetoothをOFFからONにしたときや、右上にある「デバイスの検索」を押したときのようだ。
では、ノートPCも「私を見つけて!」にしてみよう。

image

どっちかといえば、Windows側の設定をやる方がわかりづらそうだ。

image

この「発見」はデフォルトでチェックされていない。知らないうちに知らない人に見つけられたらいかん、というわけだ。
じゃあ、PCを2台ともチェックを外して、Nexus7でデバイスの検索をするとどうなるかというと、しばらく探しに行くものの、一覧から消えはしなかった。
一度Bluetooth自体をOFFにして、またONにすると一覧から消えた。
そういうものらしい。


では、Nexus7をPCに見つけてもらいたい場合はどうするかというと、「他のBluetoothには非表示」というところをタッチする。
そうすると、2分のカウントダウンが始まり、その間は検索できるようになっている。

その間に、PC側で「デバイスの追加」を選ぶ。
image


image

Nexus7を選択すると、次に進むようになる。

image

 

次に進むと、画面が出てきた。

image

と同時に、Nexus7側にも画面が!

image

 

どど、どっちを先に処理したらいいんだ??

Nexus7を「ペア設定」を先にやったが、それだけではAndroid側にはまだSHIRANAMIが追加されず、PC側を次に進めると「ペアリングされたデバイス」としてSHIRANAMIが出てきた。

Android側
image

 

PC側
image

 

PC側の「デバイスとプリンター」
image

 

なお、PC側の設定を先に次に進めても、Android側の設定も進めない限りは追加されないようだった。
つまり「どっちを先に処理してもよい」ということだ。


デバイスの削除は、PCだと右クリックして「デバイスの削除」でよい。

image

PCだけ削除してもAndroid側には残っている。
こっちは、ペアリングしたデバイス名の右側にあるアイコン(たぶん、スライドさせるつまみが3つ並んだ絵なのだろう)をタッチする。

image

こんな画面が出てくるので「ペアを解除」をタッチすると、「ペアリングされたデバイス」から「使用可能なデバイス」に格下げ(?)となる。

この状態で、Androidの「SHIRANAMI」をタッチすると、ペアリングを使用とし始める。

image

クリックすると、また「ペアリングコードの比較」ダイアログが出てくるので、あとは好きにすればよい。
この場合は「私を見つけて!」としなくても、よいようだ。
一度通路が開いたから、直接やりとりできるのだろう。

それが嫌だったら、AndroidのBluetoothを一端OFFにすればよい。


では、PC側を「私を見つけて!」にすると、どうなるだろうか。

Microsoftドライバの場合は、発見してもらうための時間制限はないようだ。
東芝のはあったような気がするが・・・忘れた。

image

そうしておいてからAndroidで「デバイスの検索」をやると、「使用可能なデバイス」としてPC名が出てくる。
そのPC名をタッチするとペアリングしようとするのだが、一度ペアリングしたことがあるデバイスと、そうでないデバイスとで、ちょっと動きが違うみたいだ。

一度ペアリングしたデバイスだと、「xxxxというパスキーが相手にも表示されてますか?」みたいな問い合わせと、PC側にもパスキーの設定要求が出てくる。
それ以降は、PCからデバイス検索した場合と同じだ。

 

はじめての場合、パスキーを入力する画面がAndroid側に表示された。

image

入力してOKとすると、KIRISHIMA側にトーストが出てきた。
Windows8だからトースト表示だったが、Windows7とかならタスクトレイ表示なのだろう。

image

タッチすると、Windowsストアアプリのデバイス設定画面が開いた。
画面が大きいので、スクリーンショットは無しだ。

Windows7の場合は、一度ペアリングしていると「私を見つけて!」としていなくてもペアリングを再開できたのだが、Windows8の場合にはだめなようだ。
そして、Androidでペアキーを入力させる画面も毎回表示されるようだ。
まあ、それはそれでいいと思う。


さて、ここまでわかったところで、ようやく本番だ。

やり方はわかったが、やっぱり面倒なので、NFCタグを作ってしまいたい。
Androidとスピーカーがペアリングする、という商品があるくらいだから、なんかできるんだろう。

 

まずは、NFC ForumのBluetooth Handoverに関する資料を読む。
NegotiatedとStaticの2種類がある。
今回の用途なら、Static Handoverでいいんじゃなかろうか。

そうなると、やることはWi-FiのStatic Handoverで作ったのとあまり変わらない中身になる。
OOB (Out-of Band) Dataの中身が違うくらいだ。

BluetoothのOOB Dataは、BluetoothのMAC値と、EIRという値(Extended Inquiry Response)がBluetooth SIGによって決められているデータ組だけである。

  • Local Name
  • Simple Pairing Hash C
  • Simple Paring Randomizer R
  • Service Class UUID
  • Class of Device

Static Handoverでは、青文字にした3タイプだけ使うみたいである。

以前SDK for NFC Starter Kitで作ったWi-Fi用データを書き込むソフトを改造して、Bluetooth用のデータを書き込むようにした。
Androidでやってしまえるようになりたいが、まあそれは今週の課題だ。
PCを「私を見つけて!」状態にしてから書き込んだNDEFのタグをAndroidにかざすと・・・ペアリングするかどうかの画面が出てきた。

image

やった!と思ったのもここまで。
あとは、やっぱりペアキーを入力する画面が出てきた。。。
(ちなみに、Windows7でやると、何も聞かれなかった。やっぱりOSの違い?)


今日はここまでだ。

AndroidではHandoverManager.javaあたりでOOBをさばいているようだけど、パスキーがどういう扱いなのかまだわかっていないので、調べんといかんのだろうな。