Archive

Archive for 4月, 2010

着信音アプリ、簡単とはいえやはりいろいろありますね・・

4月 30th, 2010

先日、Android向け着信音集アプリをリリースしました。
簡単だよなあと思ったのですが、何点か結構かかってしまった点があるので、
メモ代わりに残します。


■後方互換(1.6と2.1への両対応)
基本的に、1.6向けのプログラムは2.1で動くのですが、
一点だけ、アドレス帳の1人1人に着信音を設定出来るのですが、
それが2.1では貼り付けることが出来ませんでした。
(音自体は、リストには入るのですが)

それで、2.1向けに書くと、

Cursor c = mAdapter.getCursor();
int dataIndex = c.getColumnIndexOrThrow(People._ID);
String contactId = c.getString(dataIndex);

Uri uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI, contactId);

ArrayList ops = new ArrayList();
ContentProviderOperation.Builder builder = ContentProviderOperation.newUpdate(uri);
builder.withValue(ContactsContract.Contacts.CUSTOM_RINGTONE, newRingtoneUri.toString());
ops.add(builder.build());

try{
getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
} catch(Exception e) { }

という様に変えることで動作するようになったものの、
2.1向けのapiを使っている部分があり、このままでは1.6では動かないことに。

こういう場合、

http://www.textdrop.net/soft/android-backword-compatibility/

にあるように、1.6設定で、2.1向けの部分のみ、
if(Integer.valueOf(Build.VERSION.SDK) >= 5)
で分離させ、reflectionを駆使して
以下のように書き換える必要がありました。


ArrayList ops = new ArrayList();

Class contentProviderOperation = Class.forName(“android.content.ContentProviderOperation”);
Method newUpdate = contentProviderOperation.getMethod(“newUpdate”, new Class[] { Uri.class } );

Class contentProviderOperation_Builder = Class.forName(“android.content.ContentProviderOperation$Builder”);
Method build = contentProviderOperation_Builder.getMethod(“build”, null );
Method withValue = contentProviderOperation_Builder.getMethod(“withValue”, new Class[] { String.class , Object.class } );

Class ContactsContract_Contacts = Class.forName(“android.provider.ContactsContract$Contacts”);
Uri CONTENT_URI = (Uri)ContactsContract_Contacts.getField(“CONTENT_URI”).get(ContactsContract_Contacts);
Uri uri = Uri.withAppendedPath(CONTENT_URI, contactId);

String customRingTone = (String)ContactsContract_Contacts.getField(“CUSTOM_RINGTONE”).get(ContactsContract_Contacts);

Object builderObject = ((Object) newUpdate.invoke(null, uri));
withValue.invoke(builderObject, customRingTone, newUri.toString());

ops.add(build.invoke(builderObject, null));

Class ContactsContract = Class.forName(“android.provider.ContactsContract”);
String AUTHORITY = (String)ContactsContract.getField(“AUTHORITY”).get(ContactsContract);

Method applyBatch = ContentResolver.class.getMethod(“applyBatch”, new Class[] { String.class , ArrayList.class});
applyBatch.invoke(mainContext.getContentResolver(), AUTHORITY, ops);

全くreflectionなど使ったこと無かったので、
java的に、書いていくのが大変でした。



■HT-03Aで・・
着信音を登録していくと、どんどん着信音リストに貯まって行ってしまうので、
端末にある着信音のリストを見て、もし既にあればそのUriから設定するようにしたところ、
HT-03Aでは「アプリが停止しています 強制終了しますか、待機しますか」
というような”待ち”ウインドウが出てしまいました。
(他の端末や、エミュレーションでは問題なし。)

ちなみにリストからのチェックは、以下のような関数を実行していて、
音は30個とか40個とかしかなくとも、もうその数だけでも”待ち”状態になってしまいました。

public static Uri ringtoneExsistUri(Context mainContext , String soundName , int RingToneType){

RingtoneManager rm = new RingtoneManager(mainContext);
rm.setType(RingToneType);

Cursor cursor = rm.getCursor();

if (cursor != null) {
int repeatCount = cursor.getCount();
for(int i = 0 ; i < repeatCount ; i++){
Ringtone ringtone = rm.getRingtone(i);

String currentTitle = ringtone.getTitle(mainContext);
if(currentTitle.equals(soundName)){
return rm.getRingtoneUri(i);
}

}
}

return null;
}

登録までには、
上記の既にあるかチェック→リソースから音ファイルに変換(ファイル化してどこかに置かないと着信音として設定出来ないので)→設定
という流れがあるのですが、それらを全てバックグラウンド動作に書き換えることで、
この現象は回避出来ました。

(バックグラウンド動作は、

http://wikiwiki.jp/android/?AsyncTask%A4%C7%A5%D0%A5%C3%A5%AF%A5%B0%A5%E9%A5%A6%A5%F3%A5%C9%BD%E8%CD%FD%A4%F2%B9%D4%A4%A6

を参考にさせていただきました。)

やはり「1本ちゃんと出す」と言うことは
結構いろいろありますが、すごく勉強になりました。


ちなみに、アプリは「着信音~日本の音
http://www.zerohachi.jp/ringtone01/index_jp.html
QRcode_ringtone_jp
という、そのままの名前で99円でマーケットで販売しております、
もしよければご購入いただければありがたいです。


※その他、参考にさせていただいたサイト

http://d.hatena.ne.jp/tomorrowkey/20090826/1251294895


http://code.google.com/p/ringdroid/


http://clipboard.blog.so-net.ne.jp/2010-05-01

kuni android, プログラム

Androidのライブ壁紙のタッチイベント

4月 30th, 2010

public void onTouchEvent(MotionEvent event)
でタッチを拾うと、Homeのメニューを開くボタンや、
そのメニューのアイコンをクリックしたときなどにもタッチを拾ってしまう。

そこで、

http://developer.android.com/intl/ja/resources/articles/live-wallpapers.html

にも載っているが、onCommandを書き、
setTouchEventsEnabled(false);
を入れonTouchEventへ渡らないようにすることで、
壁紙へのタッチのみを拾うことが出来るようになる。

@Override
public Bundle onCommand(String action, int x, int y, int z,
Bundle extras, boolean resultRequested) {
if (“android.wallpaper.tap”.equals(action)) {
//action
}

return super.onCommand(action, x, y, z, extras, resultRequested);
}

ただ、なぜかエミュレーターでは動作せず、実機(Desire)では動作するという、
変な状況になってしまっている。

kuni android, プログラム

エラー:NSUnknownKeyException

4月 10th, 2010

NSUnknownKeyExceptionというエラーが出てアプリが落ちることがあり、調べてみると、
InterfaceBuilderから、既に削除してしまっていたclassを参照してしまっていたため、起こっていました。
また、この様な状態だと、アウトレット接続が残ってしまう
(controlクリックで接続状態を見ると、黄色の文字で警告っぽくなっている)
事があるので、これもちゃんと外さないと、エラーが出続けてしまってました。

kuni ソフトウェア