Wednesday, June 2, 2010

Fix Android MMS more.

Update:CM-5.0.8がでましたが、マージされてませんので作りました。

どうやらAndroidのMMSはもう少し修正が必要だった模様でして。(おそらく自分の調査が甘かった)
純粋なmultipart/alternativeメッセージを受信できません。(multipart/mixedかつmultipart/alternativeは受信できる)

というわけで修正をsubmitしました。Review:14917
(追記 2010/06/15: mergeされました)

CM-5.0.7.1/5.0.8-N1用とCM-5.0.7/5.0.8-DS用のupdate-zipを用意してます。

update-mms-fix-framework-cm-508-N1-signed.zip
(MD5:541d0bc06fc960369d6c4ced1b31aa21)
update-mms-fix-framework-cm-508-DS-signed.zip
(MD5:e11c520cb98445098c3effcb6134273f)
update-mms-fix-framework-cm-5071-N1-signed.zip (MD5:c046768f48cf47dd30c3fe50d42245cb)
update-mms-fix-framework-cm-507-DS-signed.zip (MD5:7be1a11c220d441308870bcbebb58bd7)

frameworkの差し替えになるので初回起動時にえらい時間がかかります(特にDS)。adb logcatでも眺めてましょう。

Tuesday, June 1, 2010

ntpd on CyanogenMod (busybox)

Androidの時刻同期ツールもいろいろとでてきましたが、実はCyanogenMod(5.0.7)にはntpdがはいってます。
といってもbusybox appletなので完璧なntpdではありませんが、複数のntpd serverとpeerして同期するくらいのことはできます。

使い方はadb shellあるいはTerminal Emulatorアプリから起動します。
$ ./adb shell
# ntpd -p ntp.nict.jp -p ntp.ring.gr.jp
# exit
[ENTER]
~.[ENTER]

adbの場合、ntpdがバックグラウンドへいくとshellを終了できなくなるので、強制的に切り離してます。
動いているかどうか確認するには ps ntpd とでもすればわかります。

端末の起動時に自動的に起動する方法はありません。
(/sd-ext/userinit.shから起動すると、その段階ではnetworkが起動してないので失敗します)

GUIもありません。

リソース消費にやさしいくらいしかいいとこないかもしれません。
常に通信を行うので電池の消費が気になったのですが、大したことないようです。

Sunday, May 23, 2010

Softbank MMS on Froyo

Froyoになりましたが、MMSはどうなってるかといえば、標準MMSアプリはUser-Agentを変更できないので受信できません。
Mms.apkを変更するにはrootが必要ですが、一応root奪取はすでにきています。
が、Froyoのソースコードはまだでていないので、Mms.apkのソースを改変してビルドすることはできません。

手っ取り早く、リソースファイルをいじることによりUser-Agentは変更できるので試しました。
とはいえダイナミックに変更できるわけではなく、apkを構築しなおして入れ替える必要があります。
$ adb remount
$ adb push Mms_iPhone.apk /system/app/Mms.apk

※ Mms.odexは消してはいけない。
とりあえずこれでUser-AgentをiPhoneにしたものが使えます。
iPhoneの他、Softbank/X01Tにしたものも作りましたのでお試しください。ダウンロード

黒SIMでためしたところ、Android-2.1(Eclair)にあった受信のバグは期待通りなおっているようです。
Update: 追試でHTMLメールを送信したらやはりだめでした。AOSPへの修正はFroyo(Google)ブランチにはマージされなかったと思われます。

Update 2: 様々な理由により自分はCM-5.0.7-N1-test3に戻しましたので、ひとまずFroyoに関わる調査などはこれ以上いたしません。

I'm just Froyo now


FroyoのOTAが待たれていましたが、OTAが来る前にダウンロードURLがリークされました。(削除されました)

導入手順はひとまずフルリカバリして、2.1-update1を当てる。その後FRF50を同様に当てる。
システムファイルのチェックがあるのでrootを導入してたりしてはいけません。

とりあえず雑感としては
  • フォントは相変わらず
  • ニコニコ動画を完璧に見られる
  • WiFi HotspotはPSPなど、携帯ゲーム機からも接続可能
  • 連絡帳はフリガナ対応になってて日本語環境での問題はなくなった
  • バンドルされているJapanese IMEはWnn(フリックなし)SDKにしかはいってなかったみたい
  • MMSはUserAgentを変更できないのでrootしてのapk入れ替え、あるいはカスタムROMは必須になる
  • マルチタッチの座標入れ替わりバグはなおってるような気がする
  • 11nの5GHzは未対応
  • マルチアカウントでカレンダー同期できるようになった
  • GMailアプリでテキスト選択してコピーが出来るようになった、引用なし返信ができるようになった
  • ホーム長押しのアプリ履歴は8こになった


こんなところですかね。操作が軽くて快適なのはこれまでの情報通り言わずもがな。

Update: root化もきました http://forum.xda-developers.com/showthread.php?t=686627

Update 2: どうやらFRF50は正式なFroyoリリースではないらしく、あくまでプレスレビュー向けの評価リリースというような話を耳にしました。この記事はFRF50の導入を推奨するエントリではございませんので、すべて自己責任で行動してください。

Saturday, May 15, 2010

MMSReq 0.4 for Android

MMSReq 0.4をリリースしました。
些細なバグ修正と失敗時のメッセージを詳細にしました。

smile.world以外での動作確認もできましたので、使い方をgithub wikiにまとめてみました。

ダウンロード

Monday, May 10, 2010

MMSReq for Android - MMS新着受信

どうも。
Nexus OneでのMMSがだいぶ落ち着いてきましたので、MMSの新着をメールセンターに問い合せるアプリを作ってみました。
要するに、iPhoneにある「MMS新着受信」アプリのAndroid版です。


使い方はボタンひとつしかないので説明するまでもないですが、以下の制限があります。
  • 3Gネットワーク必須
  • WiFi環境下で稀に失敗することがある


ダウンロード
(2010/05/12 追記) Version 0.3をリリースしました。銀SIMのMMSで使えるようです。(mmsopenではダメのようです)

Friday, April 23, 2010

Nexus One MMS まとめ

メモ。おもしろくないので興味ある人だけどうぞ。
※(2010/05/05追記) 下記修正はすべてAndroid Open Source Projectにマージしてもらえました。AOSPをベースに開発されているCM-5.0.7にも取り込まれてます。


まず純正ファームウェアでの問題点。

SoftbankのMMSサーバはUser-Agentにより接続を拒否するので、MMS本文のダウンロードができない。
これは、CyanogenMod 5.0.6 (5.0.5以降?)を導入することにより解決する。(User-Agentを変更できる)

さて、以下はAOSP Android2.1,CyanogenModに共通する問題点。

1.WAP DataにMMSの仕様で定められているPduHeaderに準拠しないバイトデータが現われる。
WAPではデータを短く表現するために、ヘッダを1バイトのデータで表現し、続くバイトデータをそのヘッダの仕様に沿って解析する。
が、SBMのMMSサーバはそのヘッダオクテットを付けずにいきなり文字列ヘッダを送ってくる。
その中身は "X-Mms-Vodafone-Notif-Text" であり、続くデータは端末上で通知に使う本文の冒頭部分と思われる。
この冒頭文に、PduHeaderでつかわれるバイトデータと同じものが含まれていると、解析済みのヘッダデータを破壊する。
結果、Content-Locationヘッダ("0x83")のデータを破壊し、本文のダウンロードができなくなる。
あるいはMMSアプリが強制終了したりする。(冒頭文の内容による)

例: logcatしながらMMSを受信すると
D/WAP PUSH(  188): Rx: 0f0603beaf848c82984a42414141473338496f526c59553478675173313868722f47665233416741414141414141414141
008d928914806e756c6c406578616d706c652e636f6d009606ea546573740086818a808f818e019388058103278d008368
7474703a2f2f6d6d732f4a42414141473338496f526c59553478675173313868722f476652334167414141414141414141
4100582d4d6d732d566f6461666f6e652d4e6f7469662d54657874006d65737361676520626f647900582d4d6d732d566f
6461666f6e652d4e6f7469662d454f4c003100

のようなデータを受けとる。
この文字列は次のようなコードと人力でデコードできる。
#!/usr/bin/ruby
WAP =
"0f0603beaf848c82984a42414141473338496f526c59553478675173313868722f476652334"
"16741414141414141414141008d928914806e756c6c406578616d706c652e636f6d009606ea"
"546573740086818a808f818e019388058103278d0083687474703a2f2f6d6d732f4a4241414"
"1473338496f526c59553478675173313868722f476652334167414141414141414141410058"
"2d4d6d732d566f6461666f6e652d4e6f7469662d54657874006d65737361676520626f64790"
"0582d4d6d732d566f6461666f6e652d4e6f7469662d454f4c003100"
char = false
a = WAP.scan(/../).each do |x|
c = x.hex & 0xFF
if c >= 32 && c <= 126
print "%c" % c
char = true
else
print "\n" if char
print "0x%02x\n" % [x.hex & 0xFF]
char = false
end
end
print "\n"

結果と意味(文字列は便宜上quoteした)
0x0f 0x06 0x03 0xbe (SMS header?)
0xaf (START) 0x84 (ShortInt: 0x84 & 0x7F = 4)
0x8c (MESSAGE_TYPE) 0x82 (MESSAGE_TYPE_NOTIFICATION_IND)
0x98 (TRANSACTION_ID) "JBAAAG38IoRlYU4xgQs18hr/GfR3AgAAAAAAAAAA" 0x00 (NULL)
0x8d (MMS_VERSION) 0x92 (ShortInt: 0x92 & 0x7F = 18: (18 >> 4 = 1).(18 & 0x0F = 2) = 1.2 )
0x89 (FROM) 0x12 (Length:18) 0x80 (FROM_ADDRESS_PRESENT_TOKEN) "null@example.com" 0x00 (NULL)
0x96 (SUBJECT) 0x06 (Length:6) 0xea (Charset(ShortInt: 0xEA & 0x7F = 0x6A) = UTF-8) Test 0x00 (NULL)
0x86 (DELIVERY_REPORT) 0x81 (octet)
0x8a (MESSAGE_CLASS) 0x80 (MESSAGE_CLASS_PERSONAL)
0x8f (PRIORITY) 0x81 (PRIORITY_NORMAL)
0x8e (MESSAGE_SIZE) 0x01 (COUNT:1 (next 1byte)) 0x93 (LongInt: 0x93 = 142)
0x88 (EXPIRY) 0x05 (Length: 5) 0x81 (VALUE_RELATIVE_TOKEN) 0x03 (COUNT:3) 0x27 0x8d (((0x27 << 8) + 0x8d) << 8 = 2592000) 0x00 (NULL) (2592000secs = 30days)
0x83 (CONTENT_LOCATION) "http://mms/JBAAAG38IoRlYU4xgQs18hr/GfR3AgAAAAAAAAAA" 0x00 (NULL)
"X-Mms-Vodafone-Notif-Text" 0x00 (NULL)
"message body" 0x00 (NULL)
"X-Mms-Vodafone-Notif-EOL" 0x00 (NULL)
"1" 0x00 (NULL)

という具合になり、ヘッダオクテットなしにテキストデータおくってくる。
これはWAPというかMMSの仕様よく読めばなんかわかりそうだけど。
この"message body"の位置に0x83だとかヘッダ意味をもつオクテットが含まれる文字(日本語によくある)がくると、parserがヘッダだと誤認し、データがぶっこわれる。
ヘッダ部分にUTF-8の1st byte(32-127)がきたらとりあえず文字列として処理することでうまくいく。
というかiPhoneはこんな特殊なケースもちゃんと処理してるのがえらいなぁ。たぶんこの文字つかって通知に本文だしてる。
いろいろためしたが、この修正でたぶんOK. Review:14446


2.マルチパートメッセージの入れ子に対応していない。
これはHTMLメールや携帯のデコレーションメールなどによく見られるのだが、multipart/mixed中にmultipart/alternativeのパートがあり、これによりMMSアプリが本文の解析に失敗する。
つまり
- multipart/mixed
-- multipart/alternative
---- text/plain
---- text/html
-- image/gif
-- image/gif

というような構成になっているメール。
例えば、デコレーションメールは本文をHTMLで表現し、添付している画像をHTML中で参照するという仕組みなのだが、HTMLメールを表示できない端末向けにとりあえず本文だけでも表示できるように、multipart/alternative で text/plain を追加している。(alternativeというのはそういうためのもの)
frameworkのMMS本文解析がこれに対応していない(multipartの入れ子を解析していない)ので受信できても表示できないままとなる。
multipart/alternative があらわれたら中身を再帰的に解析し、1番目のパートを本文として使用することで解決。 Review:14466
ただし、デコメはそもそもMMSアプリでHTMLメールを表示できないので、送信者の意図通りに表示できるわけではない。


3.「"<>'&」を含む添付ファイルがある場合、添付ファイルのパートをescapeXML()した後で探すので、実際のパート名とマッチせず表示できない。
ようするに、<テスト>.gifなんてファイルが添付されいてると、添付ファイルがあるパートデータを&lt;テスト&gt;.gifで探すので表示でない。
明かにバグなのだけど…。どうするのがベストなのかわからないので、とりあえず、findPart()するときにunescapeするようにした。 Review:14523
なんでescapeXML()してるかといえば、表示するためのマークアップ(Smil)がXMLだから。