mozcのビルド説明にいろいろ追記されていた。
でも、特に違いはないな・・・・あっ。
jarsignerはやったけど、zipalignしてない!
やると・・・動きました。
ごめんなさいごめんなさい。
まあ、そういうこともあるわな。
あまり細かいことは気にしない私であった。
mozcのビルド説明にいろいろ追記されていた。
でも、特に違いはないな・・・・あっ。
jarsignerはやったけど、zipalignしてない!
やると・・・動きました。
ごめんなさいごめんなさい。
まあ、そういうこともあるわな。
あまり細かいことは気にしない私であった。
zinniaをapt-get libzinnia-devにしてみたが、やっぱり設定画面が立ち上がらない。
えーい、わからん。
logcatの出力を取っておくことにした。
出力されるタイミングは、設定アプリの「言語と入力」の「キーボードと入力方法」の項目にある「Mozc for Android」の右側にある設定アイコンをタッチしたときだ。
一瞬画面が黒くなって、また戻ってしまう(初回は「入力方法をMozcにしなさい」と出てくる)。
エラー原因はL.27に出ている「SIGBUS」だろう。
アラインメントがよろしくないことまでは書いてあるのだが、これからどう調べていいかわからない。。。。
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はどうしたらいいんだろうね?
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、らしい。
手動でサインしてね、ってログが出てた。
NFCを使うときだけじゃないが、getSystemService()を使うときは多い。
システムサービス、というくらいだから、onCreate()で取得しておいて、あとは使い回せばいいだろうと何となく思っているのだが、本当だろうか?
心配になってきたので、調べよう。
うぅ、身近にAndroidの先生がほしい・・・。
まず、Context#getSystemService()を見る。
・・・abstructだから、実装は派生クラスが持っているのか。
そういえば、未だにabstructとinterfaceの違いがわかってないな。
C++だと、
class Context {
public:
Object getSystemService(String name) = 0;
となっているイメージだけど、あってるのかな。まあ、後で調べよう。
次は、Activity#getSystemService()を見る。
普段呼び出しているのが、ここ経由だからだ。
Contextは後から変化することはなさそうだから、使い回してもよさそうだ(根拠無し)。
WindowServiceも、最初に作るだけだろうから、使い回してもよいだろう。
SearchServiceも、その場で作るくらいだし、newするときの引数もthisだから使い回してもよいだろう。
また、特に重たそうな処理もないので、毎回取得しても悪いことはないかな、という気分になった。
では、Activityの上。ContextThemeWrapper#getSystemService()を見る。
LayoutInflaterは、レイアウトXMLからViewを作るときに使うものらしい。
"inflate"は「膨張させる」という意味らしい。インフレってやつか。
まあ、ここもcloneInContext()するときにthisを使うくらいだから、使い回してもよさそうだ。
取得にも時間はかからないだろう。
Activityと違うのは、次に呼び出すgetSystemService()が、superではなくてmBaseになっていることだ。
mBaseはContextのインスタンスで、コンストラクタで指定するようになっている。
足跡が途切れてしまった・・・。
仕方ないので、デバッガで探すことにした。
さっき作ったアプリでは、app.ContextImpl#getSystemService()が呼ばれるようだった。
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()で取得するようにした方が無難なのかな。
そういう解釈でいいのかね?
そういえば、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を書き込むだけでよい。
音は、魔王魂さんからいただいた。
私にも学生の時があって、学園祭にも参加したことがある。
そのときに出店で「コイン投げ」ってのをやったことがある。
スロットで使うようなコイン(メダルというのか)を投げ、離れた位置にあるプラスチックの板の上に載せる、というゲームだ。
板はつるつるなので、ほぼ垂直にコインが落ちるようにしないと、すべって落ちてしまうのだ。
私は客引きとして「誰でもできますよ」みたいな感じで、何気なくやって載せることができるよう、かなり練習した。
あこぎなもんだ。
当時は単にコインを渡して、載ったかどうかを目で見るだけだった。
しかし今なら、コインの両面にNDEFタグを貼って、当たり判定ができるんじゃなかろうか、と思ったのである。
Nexus7を裏返しにしてやってみると・・・そもそもリーダライタの範囲が狭すぎて、音すら鳴らないことがあった。
そうだよな・・・狭いのは当たり前だし、なかなか載らないようにしてるんだから、音すらしないよな・・・。
投げるのではなく、シールタイプのやつにして、そのままひらひらと舞い散るように落とした。
うん、その方がまだゲームっぽい感じがした。
しかし、やはりリーダライタの部分に載せるのは至難の業だ。
NFCアンテナの延長キットみたいなものがあったが、面積を広くすることはできるんだろうか。
あるいは、そこまでいったらアクティブタグの方が向いてるかもしれない。
でも、リーダライタが高いっていってたよな・・・。
普段、ツールしか作らないんだけど、たまには違うものを作るとおもしろいですな。
昨日コメントで、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])
こうやって見ると、NXPがんばってるなー、と思う。
FeliCaもこうやって表にばんばん出てくるとうれしいのだが、やはり戦略が違うから出てこないのだろうか。
と思ったが、あんまり製品がばんばん出てきても対応する方はめんどくさいな・・・。
願わくは、FeliCa LiteをNDEF対応するところまで含めて規格になってくれれば・・・。
何度も書いているが、だんだんわからなくなってきたので、また整理する。
Windows8とRC-S380の組み合わせの場合に、どういう使い方をするのがよいか、ということについてだ。
毎回同じことを書いているような気がするが、これでいいのかな。
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独自)
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に対応している。
ざっと検索した限りでは、NCI側ではTARGET_TYPE_MIFARE_CLASSIC を使っているところがない。
だから、やっぱり対応していないのだろうね。
どうでもいいが、NFC_BARCODEも対応してないみたい。
まあ、たしかにNFC Forumの対象外なのだろうけど、突然AndroidでAPIを追加したわりには扱いが冷たいなあ。
それならFelicaLiteクラスだって追加していいじゃないか、ぶぅぶぅ。
が、これはもちろん、素のAndroidを使ったらそうなるだろうというだけで、組み込んだ会社が対応してしまえば、対応できる。
Nexusは、なんとなく素のAndroidを使うようなイメージがあるけど、メーカーが出すときには互換性とかあるだろうから各自でがんばるのかなあ。
MIFARE ClassicがNFC Forumの対象外になっている理由は知らないが、メモリが連続していないとか、アクセスするのに認証が必要になるとか、そういうところだろうか。
安価で大量に出回っているので、すぱっと切り捨てるのも難しいと思う。
NFC Forumで認証関係が落ち着いたら、Type 5 Tagとかになって現れたりするのかねぇ。
あと一週間でこの優雅な生活が終わる。
休みが始まったときには「毎日どうしよう・・・」などと思っていたものだが、始まってしまえばあっという間だった。
うぅ、もったいない過ごし方をしたような気もする。
優雅な時間の終わりは、とてもブルーだ・・・。
4番目の馬だっけ、青ざめているのは。乗っているものは「死」だ。
いや、そこまでブルーではないものの、それなりにブルーだ。
そんなわけで、今回はBluetooth 4.0の話だ。
ブルーなのは本当だが、実はそれはどうでもよく、今月発売のInterface誌の特集がBluetoothだったのだ。
ちょうどペアリングなどを見ていたこともあり、興味深く読んだ。
繰り返し書かれているのは、Bluetooth 4.0は従来の規格と互換性はない、ということだった。
4.0対応製品でも3.0のプロファイルが使えるようになっているが、それはそういう製品に仕立てているからできるのであり、純粋な4.0しか搭載していない製品だったら、3.0のプロファイルなどは使えないとのこと。
どうやって見分けたらいいんじゃい、と思ったら、それが「SMART」やら「SMART READY」マークらしい。
世の中について行ってないなあ。。。
うーん、やはりBluetoothのことを調べても、ブルーな気分が直るわけではないようだ。
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つがあります。
タグがどうなっているかで、動作が変わります。
下の処理を、上から順に見ていって、最初に引っかかった処理を行います。
MIFARE Ultralightは、NDEFフォーマット済みか、NDEFフォーマット可能のどちらかになると思ってます。
それ以外でも、Androidが対処してくれそうなものであれば、上の処理2つのどちらかになるでしょう。
FeliCa Liteは、未フォーマット状態があり得るので、MCレジスタ操作を加えています(1次発行まではしない)。
MIFARE UltralightとFeliCa Liteだけしか対応してません(たぶん)。
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でしか動作確認していません。
なにかあったら、ごめんなさい。。。
こんな時間まで何やってるんだか・・・。
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の定義もちょっと曖昧な気がするので、バグと呼ぶのは悪い気がするな。
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自体を書いたことがないので、あやしいかも。
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はヒストリーに残っているようなのだ。
見方が悪いのかな?
などなど、一筋縄でいかないことがわかってきた。
ネットで調べるのもめんどうなので本を買いたいところだが、手持ちの本はそこら辺が書いてないので、また買っても同じかも・・・という気もしている。
まあ、見に行くか。
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」というパッケージ名だったので、そう掘った。
名前は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 {@Overridepublic 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);
}@Overrideprotected 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に追加。
これでよいかと思ったが「junit.frameworkがない」みたいなことを言われる。。。
よくわからんので、JUnit4をダウンロードして同じように追加した。
したのだが、もっと普通の方法があった。
上の画面で「Add Library ...」を押すと、JUnitが選択できる。
JUnit3かJUnit4かを迫られるので、新しい方がいいんじゃないの、と思ってJUnit4にした。
ここまでやると、Eclipseのエラーが出なくなった。
なお、プロジェクト設定でAnnotation Processingの設定は不要だ。
では、実際に動かしてみよう。
動いたかどうかがわからないというレベルなので、まずは自作のProcessorクラスのprocess()先頭にブレークポイントを設定。
そして、プロジェクト名で右クリックし、「Debug As > JUnit Test」を選択。
「Use configuration specific settings」にチェックし「Eclipse JUnit Launcher」を選択。
ここで「Java Application」を選択しても、ダメですぞ(それで悩んでた)。
そうすると、ブレークポイントのところで止まるんじゃないかね。
私のところは止まったよ。
Androidでボタンを追加するたびに、いつも同じようなことを書く。
ひどくめんどくさいし、覚えてないので腹立たしい。
そう思っていると「android annotationがある」という話を教えてもらった。
便利そうなものは使ってみよう!
と思ったが、なんだかわからないまま使うのも悪いので、このAnnotationのしくみを動かすサンプルぐらいやってみるか、と試すことにした。
参考にしたのは、こちら。
Javaのpackage名以外は、そのままやったのだが・・・できたJarを設定してもEclipseが「unable to load annotation processor factory」みたいなことを言う。
パスがおかしいのか? package名がまずいのか? どこか書き間違えたか?
いろいろ見たのだが、わからん。
他のサイトも見たが、わからん。
2時間くらい悩んで、AndroidAnnotationsのJarを見てみることにした。
えー、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の出力先として私が勝手に決めただけだ。
JARファイルを作る。
プロジェクト名で右クリックし「Export...」を選択。
JARにまとめたいファイルを決める。
.classpathと.projectはいらんだろう。
自分で作っていた「extern」もいらん。
下のチェックは「class files and resources」。
JARファイルの出力先や名前も適当に決める。
JARファイルができた。
では、Annotationを追加する方。
プロジェクト名で右クリックし「Properties」を選択。
「Java Compiler > Annotation Processing」で、いろいろ有効にする。
生成場所は「gen」らしい。
Factory Pathに、さっきのJARを追加する。
私は「Add External JARs..」で追加したが、追加できればいいらしい。
ビルドパスも通すらしい。classがあるからか?
ないと、importするときに見つからんと言われるようだ。
同じようにLibrariesに「Add External JARs...」で追加した。
このくらいやると、使えるみたいだ。
私がAnnotationを調べ始めた理由を忘れてしまったが、まあいいや。
一晩寝て、気分が変わった。
[android]覚えているものを忘れるしくみ
やっぱり、NfcFクラスと互換性を持たせるようにしよう。
めんどくさいといっても、そんなにAPIは多くないから、我慢するのだ。
Eclipseとかだと、簡単にやる手段があるのかもしれんが、わからんので手書きだ。
これならstaticのメンバ変数・・・じゃなくてプロパティというのか、がないので、忘れる忘れないも従来と同じレベルになったんじゃないだろうか。
本物のNfcFはBasicTagTechnologyをextendsしてるのだが、こっちはやってない。
なので、完全に互換があるわけじゃないけど・・・せっかく継承させてないのだから、断ち切った方がいいんじゃないかなと思った(というのは、後付けの理由だ)。
Type 3 Tagのフォーマッタを作って少し安心したが、実はあれは大したことをしていない。
特に画面周りなんかは、文言を変更したくらいしかやってないのだ。。。
もうちょっと、画面周りを調べておこう。
どうでもいいが、Type 3 Tagは「T3T」と略すことが多いのだけど、顔文字っぽいな。
(T 3 T) みたいな、口をとんがらせて涙を流しているようなイメージだ。
画面周りと言えば、まずはリソースだろう。
resフォルダを見ると、なんかいろいろあった。
画像だけで、これだ。
幸い、画像ファイルが少ない(ic_launcher.pngだけ)ので、原寸で載せていこう。
drawable-ldpi
画像無し
以上だ。
48x48~144x144まである。
Androidのマルチスクリーン対応には、まだxxhdpiは載ってなかった。
「ポストにNFCタグをつける」という記事があったが、もう少し詳細が出てきた。
NFCタグを丸の内エリアの郵便ポストに取り 付け情報配信(KDDI等) - payment navi
ucodeNFC ?
また新しいやつの登場か・・・。
と思ったが、調べていくとそうではなかった。
「ucode」という情報を書き込んだNFCタグを「ucodeNFCタグ」と呼ぶようだ。
同様に、QRコードも「ucodeQR」らしい。
(NXPにUHF帯のUCODEというものもあるようだが、これは別だろう。)
ucodeについては、こちら。
第604回:「ucode」 とは[2013/03/12] - ケータイWatch
では、H.642.1で検索して・・・・。
Multimedia information access triggered by tag-based identification - Identification scheme
あれ・・ucodeとか単語が出てこないけど、間違ったのかしら。
いや、いいらしい。
ucodeをベースに確立したH.642(pdf)、という記載があった。
マルチメディア、というと音楽とか画像とかをイメージしてしまうが、文字通りマルチなメディアということで「なんでもかんでも」ということになっているのかな。
128bitの内訳は、H642では1LC(Level Code)~4LCという分け方らしい。
ちょっと広すぎて、私の手に負えない。。。。
ともかく、調べるとっかかりくらいになればいいや、ということで。
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とかしないでインスタンスをばしばし作ればいいやん、という気もするのだが、やっぱりもったいないという気もしてしまう。
うーん、悩ましいですわ。
FeliCa Liteをかざすと、NDEFフォーマットするアプリを作った。
https://github.com/hirokuma/FLFMT
ユーザへの確認も何もなく、フォーマットする。
既存データも含めて消すので、危険だ。
消したいときに使おう。
なんで作ったかというと、フォーマッタがほしかったからだ。
データを書くツールはあるけど、消すのがなかったんでね。
お勉強がてら、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.nfc.tech.Ndefとandroid.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()でやっている。
libnfc-nxpが対応しているかどうかで決めているように見える。
NCI版も同じ関数はあるのだが、呼びだすのはJNIの方になっている。
MIFARE Classicが除外されてたのは、もともとMIFARE ClassicはNFC Forumの対象外だからだろう。
NXP自社だから優遇されていたのだろうな(Androidのクラスには残ってるけど)。
今度はType 1 Tagが優遇されたように見えるが、これはBroadcomがTopaz/Jewelを持っているからだろう。
こういうのを見ると、SONYさんにがんばってもらわんとな、と思ってしまいますな。
FeliCa LiteをNDEF Formattableにするなら、まずこの辺をいじることになるんだろうね。
もちろん、実際にformatするところも作らないかんだろう。
NCIがその辺をどうサポートしているのかは、まだ全然見ていない。。。
以前、似たようなことがあった。
あのときはXP(32bit)で、Nexus7をUSBに挿すとデバイスマネージャでMTPがエラーになっていたのだ。
今回はWindows7(64bit)で、デバイスマネージャーにはMTPすら出てこない。
USBデバッグの有効/無効には関係ない。
カメラとしては認識できるのだが・・・
これに書いてある通りにやると、できた。
これは、自分の反省というか、注意すべきところということで書き残しておく。
私がNDEFのタグを作るとき、必要最低限のブロックしか更新しない。
特に理由はなく、わざわざ消さんでいいだろう、くらいのものだ。
でも、前のに上書きすると、そういう書き方だと前のデータが残ってしまうのだ。
消してないのだから当たり前なのだけど、上書きした人からすれば「前のは消えただろう」と思うはずだ。
だから、消すべきだ、と思った。
仕様としては、そのブロックの終わりまでは0x00で埋めること、くらいだったような気がする。
読み飛ばしているだけかもしれんがね。
NDEFフォーマットされたタグであれば、データ領域のサイズがわかるはずなので、その分だけ消せばよいだろう。
フォーマットするソフトは、なんとかしてタグのサイズを調べんといかんので、ちょっとめんどうだろうな。
テーマは、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、だし)。
やっぱり、いろいろ覚えることがあるねぇ。
アプリプロジェクトを作るウィザードの最初に「Theme」がある。
デフォルトは「Holo Light with Dark Action Bar」となっている。
テーマ別の画像は、ここにあった。
http://developer.android.com/design/style/themes.html
以前からテーマという設定はあったが、ウィザードでは設定できなかったように思う。
WindowsやFirefoxのテーマと同じような、全体の根底に流れる雰囲気、みたいなものだろうか。
ソフト開発というか、製品開発にあたっては「テーマ」が不可欠だ。
「この製品は、こういう風にありたい」という指標がないと、ただでさえ開発者は自分の好きな方向に解釈しがちなので、迷走しがちになるのだ。
「好きな方向に解釈」は怠慢ではなく、どちらかといえば気を遣ったために起こることが多いように思う。「訊きたいけど、忙しそうだから後にしよう」とか「さっきも訊いたばかりだから、また訊くと迷惑だろう」とか。
管理側としては、そういう風に思われないように注意しないといかんだろう。勝ち負けではないのだが、そう思われたら管理側の負けであるし、それはプロジェクトが終わるまで引きずってしまうように思う。
精神的な余裕を作るためでもあり、周囲にそれを知らせるためにも、管理者は基本的に現場作業を持たない方がいいと思っている。
まあ、そうもいかないことが多いけどね・・・。
いかんいかん、いろいろ考えてしまった。
Androidでいうテーマは、もちろん見栄え上のテーマである。
「Holo」がなんかわからないけど、"holo-"は「全体の」というような意味だった。
つまり「全体的に明るめ」とか、「全体的に暗め」とかなんだろう。
Androidの今までを全部を把握しようとか、最近のものだけでも把握しようとかするのは、とても無理だということがわかっているので、あきらめて開発をやろう。
今回はAndroid SDKを使う。
NDKという日本電波工業がリリースした・・・じゃなく、Native Development Kitもあるが、こっちはやらない。
最近はeclipseを拡張したADTというツールがリリースされているので、それを使えばよい。
設定は他のサイトの方が親切に説明していると思うので、やらない。
さて、ADTを使うと、アプリのテンプレートを作ってくれる。
楽だ。
ただ・・・「com.example.」がデフォルトになるのは、変更できるとうれしい。
確かに、最初の1回しかやらないんだけど、なんか、こう、ねぇ。
忘れてしまって、そのままパッケージを作ってしまうこともあるやん。
うん、忘れなければいいんだけどね。
TABでテキストボックスを移動させると「com.example」だけが選択状態になるから、ちゃんとわかってるのよ。
そうだよね、そうだよね。。。
・・・いや、そうじゃない。
探してみるんだ!
探せば、きっと何かが・・・・何かが・・・
出てこなかった。
"example"で全文検索する、というめんどくさいことまでやったのだが、それっぽい箇所を見つけられなかった。
plugin_customization.iniがそれか、とも思ったのだが・・・
力尽きた。
「最近の」って書いたが、いったい何がどうなったら最近なんだろう・・・。
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つで、搭載されている機能が固定されていた時代は終わったのだ。
まあ、携帯電話じゃない仕事になるかもしれないじゃないか。
私はそう考え、ひそかに涙をぬぐった。
そういえば、内定が出ました。
みなさま、ご心配をお掛けしました。。。
4月から、また仕事に復帰します(今も就職してるのはしてるが、お休み中)。
次になにやるかは不明(かつ秘密)だ。
が、下調べをするなら、やっぱり携帯電話関係だろう。
となると、筆頭はAndroidか。
しかし最近だと、TizenとかFirefoxOSとかUbuntuとか、そっち側も捨てがたい。
TizenとFirefoxOSは、HTML5を使うところもあるだろうってことで、先週はちょっとだけやってた。
まあ、まったく知らないのはまずい、という程度しかやっていない。
Tizenはネイティブアプリもやっておきたいし、せっかくNexus7があるんだから動かしてもみたい。
が、やっぱりAndroidはやっておかんとなー、と思っている。
私がソースを見ていた頃は、2.2くらいだったので、今とはずいぶん変わっていると思う。
それに、Androidがメジャーになってから、私は携帯電話の仕事をしてないのだな・・・。
TizenやFirefoxOSだったら「いやあ、まだ情報が少なくて」でごまかせるかもしれんが、Androidはさすがに何も知りませんじゃ済まんだろう。
私が担当するのは、たぶんAndroidだったとしてもアプリではないだろう。
けっこう下回りだと思う。
とはいえ、アプリを作ることもできんのに下回りを任せられるかというと、そういうもんでもあるまい。
私の上司がよく言ってたが「飛行機の操縦ができない人に飛行機のソフト開発を任せられるか?」ということだ。
まあ、全員が全員操縦できないとしても、中心メンバーは操縦できる人じゃないと心配だろう。
そんな訳で、下回りをやるためにも、アプリは少しくらい作れた方がよかろうとは思うのだが、とてもではないがまんべんなくやっておこう、なんてことは無理だ!
アプリはそんなに甘くない(下回りより大変だと思う)。
なので今回は消極的に「最近のアプリの作り方を調べて、それに沿ってやってみよう」ということにした。
・・・目標が低く見えるが、許してくれ。
せっかくNexus7があるので、NFCアプリにしておこう。
あまり使ったことがない、サービスとかインテントとか非同期とかもやっておきたい(非同期関連は難しいというイメージがあるため)。
まあ、何を作るのかは決めてないけど、宣言だけでもしておかないと目標がぶれそうでね。
では、実際に入社して、仕事が携帯電話じゃなかったら、どうしよう?
どうしようもない。
だって、そんなの現場に行かないとわからんし。
だから、そこは心配しても仕方ないので、忘れてしまえ。
※後日談あり (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のドキュメントも見らないかん。
時間があるように見える私だが、そこまでの時間があるのだろうか・・・。
Bluetooth機器は、ペアリングというものをしないと使えない。
そこまではわかるのだが、いつも何となくペアリングを行い、何となく失敗したり成功したりしている。
これは、理屈がわかっていないからそうなるのだ。
わからないものは、調べるしかない。
なお、うちにあるBluetooth機器は3つ。
PC側のBluetoothはMicrosoftが提供しているドライバを使っている。
BUFFALOのBluetoothドングルで、東芝のドライバがついていたのだが、Windows7をインストールするときには何もしていない。
Microsoftの説明
http://windows.microsoft.com/ja-jp/windows7/add-a-bluetooth-enabled-device-to-your-computer
片方を「私を見つけて!」の状態にして、もう片方が「私が見つけてあげよう」という状態にしてやればいいようだ。
これは、周囲にBluetoothデバイスがなくて、Nexus7も見つけられないようにしている状態。
ここで、デスクトップPCを「私を見つけて!」にする。
SHIRANAMI、というのがデスクトップPCだ(うちのPC名は、焼酎銘柄)。
なお、使用可能なデバイスが更新されるタイミングは、AndroidのBluetoothをOFFからONにしたときや、右上にある「デバイスの検索」を押したときのようだ。
では、ノートPCも「私を見つけて!」にしてみよう。
どっちかといえば、Windows側の設定をやる方がわかりづらそうだ。
この「発見」はデフォルトでチェックされていない。知らないうちに知らない人に見つけられたらいかん、というわけだ。
じゃあ、PCを2台ともチェックを外して、Nexus7でデバイスの検索をするとどうなるかというと、しばらく探しに行くものの、一覧から消えはしなかった。
一度Bluetooth自体をOFFにして、またONにすると一覧から消えた。
そういうものらしい。
では、Nexus7をPCに見つけてもらいたい場合はどうするかというと、「他のBluetoothには非表示」というところをタッチする。
そうすると、2分のカウントダウンが始まり、その間は検索できるようになっている。
Nexus7を選択すると、次に進むようになる。
次に進むと、画面が出てきた。
と同時に、Nexus7側にも画面が!
どど、どっちを先に処理したらいいんだ??
Nexus7を「ペア設定」を先にやったが、それだけではAndroid側にはまだSHIRANAMIが追加されず、PC側を次に進めると「ペアリングされたデバイス」としてSHIRANAMIが出てきた。
なお、PC側の設定を先に次に進めても、Android側の設定も進めない限りは追加されないようだった。
つまり「どっちを先に処理してもよい」ということだ。
デバイスの削除は、PCだと右クリックして「デバイスの削除」でよい。
PCだけ削除してもAndroid側には残っている。
こっちは、ペアリングしたデバイス名の右側にあるアイコン(たぶん、スライドさせるつまみが3つ並んだ絵なのだろう)をタッチする。
こんな画面が出てくるので「ペアを解除」をタッチすると、「ペアリングされたデバイス」から「使用可能なデバイス」に格下げ(?)となる。
この状態で、Androidの「SHIRANAMI」をタッチすると、ペアリングを使用とし始める。
クリックすると、また「ペアリングコードの比較」ダイアログが出てくるので、あとは好きにすればよい。
この場合は「私を見つけて!」としなくても、よいようだ。
一度通路が開いたから、直接やりとりできるのだろう。
それが嫌だったら、AndroidのBluetoothを一端OFFにすればよい。
では、PC側を「私を見つけて!」にすると、どうなるだろうか。
Microsoftドライバの場合は、発見してもらうための時間制限はないようだ。
東芝のはあったような気がするが・・・忘れた。
そうしておいてからAndroidで「デバイスの検索」をやると、「使用可能なデバイス」としてPC名が出てくる。
そのPC名をタッチするとペアリングしようとするのだが、一度ペアリングしたことがあるデバイスと、そうでないデバイスとで、ちょっと動きが違うみたいだ。
一度ペアリングしたデバイスだと、「xxxxというパスキーが相手にも表示されてますか?」みたいな問い合わせと、PC側にもパスキーの設定要求が出てくる。
それ以降は、PCからデバイス検索した場合と同じだ。
はじめての場合、パスキーを入力する画面がAndroid側に表示された。
入力してOKとすると、KIRISHIMA側にトーストが出てきた。
Windows8だからトースト表示だったが、Windows7とかならタスクトレイ表示なのだろう。
タッチすると、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によって決められているデータ組だけである。
Static Handoverでは、青文字にした3タイプだけ使うみたいである。
以前SDK for NFC Starter Kitで作ったWi-Fi用データを書き込むソフトを改造して、Bluetooth用のデータを書き込むようにした。
Androidでやってしまえるようになりたいが、まあそれは今週の課題だ。
PCを「私を見つけて!」状態にしてから書き込んだNDEFのタグをAndroidにかざすと・・・ペアリングするかどうかの画面が出てきた。
やった!と思ったのもここまで。
あとは、やっぱりペアキーを入力する画面が出てきた。。。
(ちなみに、Windows7でやると、何も聞かれなかった。やっぱりOSの違い?)
今日はここまでだ。
AndroidではHandoverManager.javaあたりでOOBをさばいているようだけど、パスキーがどういう扱いなのかまだわかっていないので、調べんといかんのだろうな。