SoftBank MobileのMMSはUserAgentによるアクセス制限がかかっており、HTC One Vに標準搭載のMessageアプリではプッシュ通知は受け取れますが、本文を受信できません。
他の通知手段が充実してきたので、個人的にはキャリアメールはどうでも良くなってきているのですが、諸々の理由でsoftbank.ne.jpドメインのメールを受け取る必要が僅かながらあるので、対応することにしました。
MMSのUserAgent変更
HTCの場合は、/system/customize/MNS/default.xmlにてMMSのユーザエージェントを変更することができます。
<module=”MMS”>のあたりを見ると、「HTC_One_V/1.0」が指定されています。実際にメッセージ受信を試みてadb logcat すると、
% adb logcat | grep HttpUtils ... snipped ... V/HttpUtils( 2165): key=ua_string, value=HTC_One_V/1.0 D/HttpUtils( 2165): [HttpUtils] createHttpClient w/ socket timeout 60000 ms, UA=HTC_One_V/1.0 V/HttpUtils( 2165): key=ua_profile, value=http://www.htcmms.com.tw/Android/Common/PK76/ua-profile.xml W/System.err( 2165): at com.android.mms.transport.HttpUtils.httpConnection(HttpUtils.java:502) D/HttpUtils( 2165): Catched unexcepted http-error exception D/HttpUtils( 2165): com.htc.messaging.util.HtcHttpTransportError: HTTP error: Forbidden D/HttpUtils( 2165): at com.android.mms.transport.HttpUtils.httpConnection(HttpUtils.java:502) ...
確かにUAとして「HTC_One_V/1.0」が使用され、見事に「HTTP error: Forbidden」と言われているのがわかります。
よって、適当な場所にdefault.xmlのバックアップを取った上で、直接sedで置換してしまいます。置換後のユーザエージェントは、SoftBankメールアプリで使用されている「SoftBank/1.0/Smart/MyrMMS」を採用することにしました。
% adb shell $ su # mount -o rw,remount /system # cp /system/customize/MNS/default.xml /sdcard/mns_default.xml.org # sed -i 's/HTC_One_V\/1\.0/SoftBank\/1\.0\/Smart\/MyrMMS/' /system/customize/MNS/default.xml # exit $ exit
念のため、diffをとって変更点を確認しておきます。
2つ目の変更は単にファイル末尾に改行コードがあるかないかの違いですので、スルーでOKです。
# diff /sdcard/mns_default.xml.org /system/customize/MNS/default.xml
--- /sdcard/mns_default.xml.org
+++ /system/customize/MNS/default.xml
@@ -947,7 +947,7 @@
<module name="MMS">
<function name="ua_string">
<set name="single">
- <item name="value">HTC_One_V/1.0</item>
+ <item name="value">SoftBank/1.0/Smart/MyrMMS</item>
</set>
</function>
</module>
@@ -958,4 +958,4 @@
</function>
</module>
</category>
-</customization_form>
\ No newline at end of file
+</customization_form>
これで、工場出荷状態に初期化(wipe)すれば、変更したユーザエージェントが使用されるようになります。
wipeをせずに反映させる方法
一度端末の初期設定をしてしまうと、/system/customize/MNS/default.xmlをベースとして設定情報がdataパーティション内にDB保存されてしまうので、xmlを書き換えてもDB保存された設定が優先されてしまい、修正を反映させるためには「工場出荷状態に初期化(wipe)」が必要となります。
ただ、いろいろ環境構築してしまって今更wipeなんてありえない、というケースもありますので、xmlに加えてDB修正する方法も示しておきます。
修正するDBの場所は、/data/data/com.htc.provider.CustomizationSettings/databases/customization_settings.dbとなります。
一旦sdcardに複製し、ローカルに持ってきてから編集を行います。
% adb shell $ su # cp /data/data/com.htc.provider.CustomizationSettings/databases/customization_settings.db /sdcard/customization_settings.db.org # exit $ exit % adb pull /sdcard/customization_settings.db.org customization_settings.db
SQLite3のDBを扱えるツールもしくはsqlite3コマンドが使用可能な環境を整えておきましょう。以下では、コマンドラインベースで進めます。
sqlite3コマンドは、Android SDK内のtools以下にもあります。
sqlite3コマンドで以下のUPDATE文を実行します。
% sqlite3 customization_settings.db sqlite> update SettingTable set value=X'80000000424e444c010000000000000009000000750061005f0073007400720069006e00670000000300000054000000424e444c010000000000000005000000760061006c00750065000000000000001900000053006f0066007400420061006e006b002f0031002e0030002f0053006d006100720074002f004d00790072004d004d0053000000' where key='force_change_MMS'; sqlite> .quit
更新したDBファイルを元の場所に書き戻します。
% adb push customization_settings.db /sdcard/ % adb shell $ su # cd /data/data/com.htc.provider.CustomizationSettings/databases # ls -l customization_settings.db -rw-rw---- app_14 app_14 50176 2012-05-09 17:03 customization_settings.db # cp /sdcard/customization_settings.db . # chmod 660 customization_settings.db # chown app_14.app14 customization_settings.db # exit $ exit
これで、MMSが無事受信できるようになるはずです。念のため「adb logcat | grep HttpUtils」してMMSを受信し、UAが変わっていることを確認しておきましょう。
補足:UPDATE文の中身について
このDB内にはSettingTableというテーブルがあり、_id,key,valueというフィールド構成になっています。
% sqlite3 customization_settings.db SQLite version 3.7.10 2012-01-16 13:28:40 Enter ".help" for instructions Enter SQL statements terminated with a ";" sqlite> .tables SettingTable android_metadata sqlite> .schema SettingTable CREATE TABLE SettingTable (_id INTEGER primary key autoincrement,key TEXT NOT NULL,value BLOB);
その中のレコードでkeyがforce_change_MMSのものが今回の修正対象になりますので、まずはデータを抜いてきます。
valueがBLOBデータとなっているため、insertモードにして16進データで出力しています。
sqlite> .mode insert sqlite> select * from SettingTable where key='force_change_MMS'; INSERT INTO table VALUES(30,'force_change_MMS',X'68000000424e444c010000000000000009000000750061005f0073007400720069006e0067000000030000003c000000424e444c010000000000000005000000760061006c00750065000000000000000d0000004800540043005f004f006e0065005f0056002f0031002e0030000000'); sqlite> .quit
この16進データをバイナリエディタに貼り付けて閲覧すると、なにやら見えてきます。
このデータはBundleクラスのデータをParcel化したもので、
- データ長(青枠部分、0x68 = 104byte)
- “BNDL”(緑枠部分、固定文字列)
- データ部(赤枠部分、104byte分のデータ)
となっています。 ※ core/java/android/os/Bundle.javaのwriteToParcelメソッドを参照。
データ部の構造は、key-valueペアの集合になっており、
- key-valueペアの個数(青枠部分、0x01 = 1組)
- 1組目のkeyデータ(緑枠部分)
- 1組目のvalueデータ(赤枠部分)
- …(2組以上ある場合はこれの繰り返し、今回は1組のみなので終了)
となっています。 ※ core/java/android/os/Parcel.javaのwriteMapInternalメソッドを参照。
keyやvalueの各データは、先頭4byteがデータ種別を表しており、
- 0 → VAL_STRING、文字列データ
- 3 → VAL_BUNDLE、Bundleデータ
となります。 ※ core/java/android/os/Parcel.java#L193あたりを参照。
文字列データは、
- 文字数(青枠部分、0x09 = 9文字)
- 文字列「ua_string」(緑枠部分、UTF-16LEで9文字分、18byteのデータ)
- 文字列終端子(橙枠部分、2byteのデータ)
Bundleデータは、前述した構造の通り、
- データ長(青枠部分、0x3C = 60byte)
- “BNDL”(緑枠部分、固定文字列)
- データ部(赤枠部分、60byteのデータ)
となり、同様に解析していくことができます。最終的に、このデータはJSONで例えるなら、
{
"ua_string" : {
"value" : "HTC_One_V/1.0"
}
}
といった感じになり、「HTC_One_V/1.0」を「SoftBank/1.0/Smart/MyrMMS」と置き換えるので、結果として編集箇所は、
- UA文字列データ(赤枠部分) → 「SoftBank/1.0/Smart/MyrMMS」+終端子をUTF-16LEで表記(25文字 – 13文字 = 12文字増加 = 24byte増加)
- UA文字列の文字数(緑枠部分) → 25文字 = 0x19
- key「ua_string」に対するvalueのBundleデータ長(橙枠部分) → 60byte + 増加分24byte = 84byte = 0x54
- 全体のBundleデータ長(青枠部分) → 104byte + 増加分24byte = 128byte = 0x80
の4箇所になります。
最終的には、以下の様なデータになります。

このデータ列を、UPDATE文に指定すればOKです。
BLOBにデータを入れるときは「field_name = X’16進のバイト列’」という表記になるため、上記のようなUPDATE文になっています。
HTC One VでSoftBankのSIMを利用する場合、初期設定ではAPNがandglobalとなっており、銀SIM等では正しく接続できません。そこでAPN情報を手動設定するのですが、GingerbreadやFroyo時代には使えたはずの/system/etc/apns-conf.xmlがなぜか反応してくれませんでした。※何かミスしているだけの可能性もありますが。
wipeを繰り返していると毎回手動設定するのがいいかげん面倒&設定し忘れでハマるのを避けるために、デフォルトのAPN設定自体を書き換えてしまい、安心・快適環境を目指します。
失敗すると起動しなくなりますので、作業の前にRUUの準備もしくはCWM Recoveryを導入してバックアップしておくことを推奨します。
現時点でHTC One Vは技適証明を取得していないので、以下の内容はあくまで参考情報となります。一応。
デフォルトのAPN設定は、framework-res.apk内のres/xml/apns.xmlに記載されていますので、これを修正します。
作業にはapktool 1.4.3が必要ですので、事前に入手し設定しておきます。
framework-res.apkのデコードとapns.xmlの修正
まずは、framework-res.apkを取得し、apktoolを使ってリソースをデコードします。
% adb pull /system/framework/framework-res.apk . % apktool d framework-res.apk I: Loading resource table... I: Loaded. I: Decoding file-resources... I: Decoding values*/* XMLs... I: Done. I: Copying assets and libs...
無事apkのデコードが完了すると、framework-resというディレクトリが生成されていますので、この中のres/xml/apns.xmlを修正します。
「SoftBank」を検索すると、中盤ぐらいにandglobalのAPN設定が存在しますので、お好みのAPNに書き換えます。
銀SIMであれば、apn=”open.softbank.ne.jp”、user=”opensoftbank”…が有名ですね。以下のような感じで。
<apn carrier="SoftBank Internet" apn="open.softbank.ne.jp" user="opensoftbank" password="********" mmsc="http://mms/" mmsproxy="mmsopen.softbank.ne.jp" mmsport="8080" mcc="440" mnc="20" type="default,supl,mms" />
X06HTからの移行派はuser=”softbankX06HT”、mmsproxy=”andmms.softbank.ne.jp”もいいかも。passwordは上記と同様の手順でX06HTのapns.xmlから抜いてきましょう。
framework-res.apkのリビルド
apns.xmlの修正が完了したら、framework-res.apkを再生成します。ただし、そのままビルドすると大量のエラーが発生してビルド失敗になるので、いくつかのxmlファイルを書き換える必要があります。
- res/values/anims.xml
- <anim name=”…”>…</anim> を <item type=”anim” name=”…”>…</item> に修正します。
- res/values/layouts.xml
- <layout name=”…”>…</layout> を <item type=”layout” name=”…”>…</item> に修正します。
- res/values/raws.xml
- <raw name=”…”>…</raw> を <item type=”raw” name=”…”>…</item> に修正します。
- res/values/plurals.xml
- 79行目の 「%d of %d」 を 「%1$d of %2$d」 に修正します。各言語用のファイル res/values-**/plurals.xml も同様に修正します。
GNU sedが使える人は、次のように一発置換でもOKです。
% cd framework-res/res % sed -i 's/<\(anim\|layout\|raw\)/<item type="\1"/;s/<\/\(anim\|layout\|raw\)>/<\/item>/;s/%d\(.*\)%d/%1$d\1%2$d/' values/anims.xml values/layouts.xml values/raws.xml values*/plurals.xml % cd ../..
その後、apktoolでビルドします。
% apktool b framework-res framework-res.new.apk W: Could not find sources I: Checking whether resources has changed... I: Building resources... I: Building apk file...
framework-res.new.apkが生成されていれば成功です。
新apk内のapns.xmlを旧apkに移植する
framework-res.apk内部のresources.arscや画像ファイルは無圧縮にする必要があるので、生成したapkはそのままでは問題があります。無圧縮にすべきファイルが多すぎるため、生成したapkからres/xml/apns.xmlを取り出し、既存のframework-res.apkに追記保存することにします。
事前にオリジナルのapkをコピーして保存しておきましょう。
追記後は念のためzipalignも行なっておきます。
zipalignはAndroid SDKのtools以下にありますので必要に応じてパスを通しておきます。
% cp framework-res.apk framework-res.org.apk % unzip framework-res.new.apk res/xml/apns.xml % zip framework-res.apk res/xml/apns.xml % zipalign -f -v 4 framework-res.apk framework-res2.apk
生成したapkを上書きする
最後に、生成したapkを/system/framework以下に書き戻します。
まだadbがrootで動作していないためsdcard経由で転送し、rwモードでsystemパーティションをremount、上書きしてパーミッションを修正します。
% adb push framework-res2.apk /sdcard/ % adb shell shell@android:/ $ su shell@android:/ # mount -o rw,remount /system shell@android:/ # cp /sdcard/framework-res2.apk /system/framework/framework-res.apk shell@android:/ # chmod 644 /system/framework/framework-res.apk shell@android:/ # exit shell@android:/ $ exit
最後にrebootして確認しましょう。
% adb reboot
先日、台北にてHTC One V(Asia TW版)を入手してきましたが、例によって日本語フォントがない状態ですので、早速root取得、フォント導入してみます。
bootloaderのunlockからsu導入まで
HTCは、無保証になる代わりにbootloaderのunlock手順をwebで提供しています。HTCdevに行き、Developer Center、Unlock Bootloaderから手順通りに進めれば、簡単にunlockできます。
xda developersのこことかに、bootloaderのunlockからsuperbootを使ったsu導入の手順があるので、ここでは省略します。
まだテストビルドですが、CWM RecoveryのOne V版ができたようなので、こちらの手順でもいいかもしれません。
日本語フォントのインストール
Desire X06HT – Gingerbread(2.3)の導入 その2でも使用していたモトヤLマルベリ3(MTLmr3m.ttf)を使います。モトヤLシーダ3やDroidSansJapaneseを使う場合は適宜読み替えてください。フォントはgithubのplatform_framework_baseから取得しておきます。
busyboxのインストール
cpコマンドが存在しないので、事前にPlayストアからbusyboxをインストールして各種コマンドを使えるようにしておきます。
フォントファイルの設置
フォントファイルは/system/fonts以下に設置しますが、systemパーティションはread onlyになっており、かつro.secure=1なので直接adb pushで置くことができません。SD Card経由で書き込むことにします。
まずは、フォントファイルを/sdcardに転送し、systemパーティションをrwモードでremount。/sdcardから/system/fontsにファイルをコピーします。
% adb push MTLmr3m.ttf /system % adb shell shell@android:/ $ su shell@android:/ # mount -o rw,remount /system shell@android:/ # cp /sdcard/MTLmr3m.ttf /system/fonts shell@android:/ # chmod 644 /system/fonts/MTLmr3m.ttf shell@android:/ # exit shell@android:/ $ exit
fallbackフォント設定の追記
GBではフォントファイルを置くだけで有効になりましたが、ICSではさらに設定ファイルに追記が必要です。
/system/etc/system_fonts.xmlに記載のフォントで処理できなかった文字は、/system/etc/fallback_fonts.xmlに記載された順序でフォントを検索し、処理されます。
ですので、fallback_fonts.xmlの先頭(<familyset>の次)に以下の内容を記載することで、日本語フォントが使用されるようになります。
<family>
<fileset>
<file>MTLmr3m.ttf</file>
</fileset>
</family>
このファイルも直接書き込み不可ですので、取得・編集後、/sdcard経由で書き戻します。
busyboxを入れたことでviが使用可能ですので、使える人はremount後に直接編集してもOKです。
% adb pull /system/etc/fallback_fonts.xml 上記内容を追記 % adb push fallback_fonts.xml /sdcard/ % adb shell shell@android:/ $ su shell@android:/ # mount -o rw,remount /system shell@android:/ # cp /sdcard/fallback_fonts.xml /system/etc shell@android:/ # chmod 644 /system/etc/fallback_fonts.xml shell@android:/ # exit shell@android:/ $ exit
最後に、再起動します。正しく設定されていればフォントが変更されているはずです。
% adb reboot
これで違和感なく使えるようになりました。
Banshee 2.2.0の時点で、ローカルにある楽曲に関しては、ID3タグに埋め込んであるカバーアート(アルバムアートワーク)を取得するようになっています。
しかし、DAAP共有でmt-daapd等のDAAPサーバ上の曲を表示する場合、カバーアートはネットワークダウンロードのみとなってしまいます。
ネットワークからダウンロードされるカバーアートは、質が低かったり国内アーティストのものが少なかったりと、あまり満足できるものではありません。
自分自身は、ほとんどの楽曲に対してID3タグにカバーアートを埋め込み済みなので、DAAP経由での再生でも埋め込みカバーアートが表示されるように手を入れてみました。
作成したパッチはこちら。
banshee_daap_embedded_coverart_fix.patch
変更点の概要は、以下の通りです。
- カバーアート取得時のファイルURI条件がローカルファイルのみになっていたのを、DAAP配信のファイル(HTTP)も通るように修正。
- DAAPプロキシ用のファイルURI生成時に拡張子を付加するよう修正。
- DAAPプロキシ側のリクエスト処理時に拡張子を除外するよう修正。
2および3は、ID3タグの処理に用いているtaglib-sharpがファイルのフォーマットを判別する際に拡張子を利用しているためです。
パッチの適用は、Banshee 2.2.0をアルバムアーティスト対応にするのパッチ適用手順と同様の流れで、以下のような形で。
% cd ~/work/banshee/banshee-2.2.0 % quilt new xx_daap_embedded_coverart_fix.patch % curl -L 'http://media.st/blog/wp-content/uploads/2011/11/banshee_daap_embedded_coverart_fix.patch_.txt' | quilt fold -f -p1 % quilt refresh
後は普通にビルドでOKです。
DAAPでの再生はHTTP経由ですので、初回のカバーアートの表示はローカルファイルに比べると遅いですが、焦らず待ちましょう。
もちろん、一度取得するとBanshee側でカバーアートのキャッシュが生成されますので、2回目以降はスムーズに表示されます。
曲のカバーアートを更新してもキャッシュがある場合は反映されませんが、そこはご愛嬌ということで。
手動で更新する場は、キャッシュは ~/.cache/media-art 以下に保管されていますので、該当の画像を削除すれば再作成されます。
Banshee 2.2.0をアルバムアーティスト対応にするに記載した方法で、Bansheeローカルにある楽曲はアルバムアーティストでの絞り込みに対応しました。
しかしDAAPでの楽曲共有の場合、そもそもmt-daapd側がアルバムアーティストに非対応だったため、Firefly(mt-daapd)をアルバムアーティスト対応にするに記載した方法でmt-daapdを改修、DAAP経由でアルバムアーティスト情報が送出されるようにしました。
これで万事OKと思われたのですが、まだBanshee側で表示されません。
DAAP的にはmt-daapd側から正しく送出されているので、問題があるとすればBansheeのほうです。そこでBansheeのソースコードに目を通してみると、案の定拡張機能のDAAP共有が原因でした。
作ったパッチはこちら。
banshee_daap_albumartist_compilation_fix.patch
変更点は、大まかに以下の通りです。
- DAAP通信時のリクエストクエリに、アルバムアーティスト情報(daap.songalbumartist)を追加。
- DAAPで取得した曲データにおいて、アルバムアーティスト情報を保持するよう修正。
- DAAPで取得した曲データにおいて、コンピレーションアルバムかどうかのフラグを保持するよう修正。
- 曲一覧のアルバムアーティスト取得部分の判定方法を修正。
コンピレーションについては、DAAP通信では取得しているものの、なぜか保持していなかったので追加で入れてあります。
また、曲一覧の表示で、
- コンピレーションである場合、アルバムアーティストがあればそれを返し、なければVarious Artistsを返す
- コンピレーションでない場合、アーティスト名を返す
という、よくわからない判定になっていて、このままだとコンピレーションがtrueでない限り、曲一覧でアルバムアーティスト=アーティストになってしまうため、
- アルバムアーティストがある場合、それを返す
- アルバムアーティストがない場合、コンピレーションであればVarious Artistsを返し、なければアーティスト名を返す
と判定方法を修正しています。
パッチの適用は、Banshee 2.2.0をアルバムアーティスト対応にするでのパッチ適用手順の最後に行います。
% cd ~/work/banshee/banshee-2.2.0 % quilt new xx_daap_albumartist_compilation_fix.patch % curl -L 'http://media.st/blog/wp-content/uploads/2011/10/banshee_daap_albumartist_compilation_fix.patch_.txt' | quilt fold -f -p1 % quilt refresh
changelogも適当に追加して、ビルドしましょう。
できたパッケージをインストールし、DAAP経由でアルバムアーティストが表示されればOKです。








