(2011-02の一覧)
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28

2011-02-24 Thu (他の年の同じ日: 2005 2006)

SQLiteのデータベースファイルをSDカードに保存
2011-02-24-1 / カテゴリ: [SQL][Android] / [permlink]

というのを年末調べてたけどまだまとめてなかったので。
内蔵ストレージに作られたファイルをコピーじゃなくて、最初からSD保存する構成。
大容量のデータを扱いたいとかデバッグ時とか。

というか、書籍やネットで「ファイル名を指定」している箇所をフルパスで指定(してandroid.permission.WRITE_EXTERNAL_STORAGEを付加)すればOK

SDK付属サンプルのNotePadであれば、
--- src/com/example/android/notepad/NotePadProvider.java.org	2011-01-20 16:43:58.312750000 +0900
+++ src/com/example/android/notepad/NotePadProvider.java	2011-02-24 21:06:29.551900000 +0900
@@ -30,6 +30,7 @@
 import android.database.sqlite.SQLiteOpenHelper;
 import android.database.sqlite.SQLiteQueryBuilder;
 import android.net.Uri;
+import android.os.Environment;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -43,7 +44,7 @@
 
     private static final String TAG = "NotePadProvider";
 
-    private static final String DATABASE_NAME = "note_pad.db";
+    private static final String DATABASE_NAME = Environment.getExternalStorageDirectory() + "/note_pad.db";
     private static final int DATABASE_VERSION = 2;
     private static final String NOTES_TABLE_NAME = "notes";
 
するとこんな感じ。(DesireIIで確認)
% adb shell ls -l /mnt/sdcard/note_pad.db
----rwxr-x system   sdcard_rw     4096 2011-02-24 11:50 note_pad.db

あとはファイルの暗号化機能とかあればなぁ…
2011-02-22 Tue (他の年の同じ日: 2007 2008)

nkfでエンコード変更して上書き保存
2011-02-22-2 / カテゴリ: [win][cygwin] / [permlink]

--overwrite または --in-place する。
% find . -name "*.java" | xargs nkf -w --overwrite
デフォルトだと標準出力へエンコード変更結果を出力するけど、find|xargsと組み合わせて複数ファイル一気に変更、なとき。
--overwrite はタイムスタンプを変更しない。
--in-place はタイムスタンプが更新される。
-w は utf-8 へ変更

ソースからnkfインストール
2011-02-22-1 / カテゴリ: [win][cygwin] / [permlink]

[2005-12-21-3]の日記だと、http://cygwin-je.sourceforge.jp/cygwin_je/ からパッケージインストールしてたみたいだけど、今試したら setup.bz2.sig がないなどエラーになってインストールできなかったので結局makeした。

ソースは http://sourceforge.jp/projects/nkf/ から。
今日の時点で ver 2.1.1 (2010-09-13版)
wget すると、すでにMakefileはあるので
% make
% make test
% make install
で /usr/local 以下にインストールされる。
インストール先を変えたければ Makefile の prefix をイジればいいはず(未確認)
2011-02-17 Thu (他の年の同じ日: 2005 2006)

ボリューム変更ハードキーのハンドリング
2011-02-17-2 / カテゴリ: [Android] / [permlink]

動作確認用アプリなんかで手抜きをしたい^a^k上下スクロールとかズームイン/アウトなんかにキー操作を割り当てしたい場合に。
標準だと「押す:ボリューム変更&UI表示 / 離す:通知音を鳴らす」という動作のため、KEYCODE_VOLUME_UPとKEYCODE_VOLUME_DOWNの両方をフックする必要がある。

というわけで、こんな感じ。
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
	switch (event.getAction()) {
	case KeyEvent.ACTION_DOWN:
		switch (event.getKeyCode()) {
		case KeyEvent.KEYCODE_VOLUME_UP:
			// ここにボリュームupが押されたときに走らせたい処理
			return true;
			
		case KeyEvent.KEYCODE_VOLUME_DOWN:
			// ここにボリュームdownが押されたときに走らせたい処理
			return true;
			
		default:
			break;
		}
		break;
		
	case KeyEvent.ACTION_UP:
		switch (event.getKeyCode()) {
		case KeyEvent.KEYCODE_VOLUME_UP:
		case KeyEvent.KEYCODE_VOLUME_DOWN:
			// キーが離された場合はイベントを捨てる
			return true;
		default:
			break;
		}
		break;
		
	default:
		break;
	}
	return super.dispatchKeyEvent(event);
}

Androidでキー長押しはACTION_DOWNがコールバックされまくるんだな。

参考
キーイベントに応答するには - 逆引きAndroid入門
ハードキーフックの方法 - 明日の鍵

find|xargsでスペース込みのパスが有る場合
2011-02-17-1 / カテゴリ: [linux][command] / [permlink]

$ find path [opt] -print0 | xargs -0 command
でGo

これで、findの結果が\0区切りになり、xargsのデリミタの扱いが\0になる。
http://linuxjm.sourceforge.jp/html/GNU_findutils/man1/xargs.1.html

例: "a b.txt" がある場合
zaki@salva% find . -name "*txt"                                    [~/tmp/path]
./a b.txt
./a.txt
./b.txt
./sub/a b.txt
./sub/a.txt
./sub/b.txt
こんなディレクトリ構成の場合("a b.txt"がある)
zaki@salva% find . -name "*txt" | xargs file                       [~/tmp/path]
./a:         ERROR: cannot open `./a' (No such file or directory)
b.txt:       empty
./a.txt:     empty
./b.txt:     empty
./sub/a:     ERROR: cannot open `./sub/a' (No such file or directory)
b.txt:       empty
./sub/a.txt: empty
./sub/b.txt: empty
"a"とか"b.txt"なんかねーよといわれる。

これは、findの結果が改行区切りで出力されるためで、更にxargsが改行とスペースを区切りとみなしているため。
zaki@salva% find . -name "*txt" | od -c                            [~/tmp/path]
0000000   .   /   a       b   .   t   x   t  \n   .   /   a   .   t   x
0000020   t  \n   .   /   b   .   t   x   t  \n   .   /   s   u   b   /
0000040   a       b   .   t   x   t  \n   .   /   s   u   b   /   a   .
0000060   t   x   t  \n   .   /   s   u   b   /   b   .   t   x   t  \n
0000100
んで、-print0を付加してやると
zaki@salva% find . -name "*txt" -print0 | od -c                    [~/tmp/path]
0000000   .   /   a       b   .   t   x   t  \0   .   /   a   .   t   x
0000020   t  \0   .   /   b   .   t   x   t  \0   .   /   s   u   b   /
0000040   a       b   .   t   x   t  \0   .   /   s   u   b   /   a   .
0000060   t   x   t  \0   .   /   s   u   b   /   b   .   t   x   t  \0
0000100
区切りが\0に変わる。

で、xargs -0 で本来「スペース/改行区切りで」ファイル名を拾う動作が、\0区切りになる、と。
zaki@salva% find . -name "*txt" -print0 | xargs -0 file            [~/tmp/path]
./a b.txt:     empty
./a.txt:       empty
./b.txt:       empty
./sub/a b.txt: empty
./sub/a.txt:   empty
./sub/b.txt:   empty

そもそもスペース込みのファイル名やディレクトリ名をつけるな、という話。

xargs(1)
find(1)
2011-02-06 Sun (他の年の同じ日: 2006)

前のエントリ/次のエントリにタイトル付加
2011-02-06-3 / カテゴリ: [perl][chalow] / [permlink]

アイテム毎ページの次へ/前へに、そのタイトルをつける。
--- chalow.20110206	2011-01-23 16:42:29.715835927 +0900
+++ chalow	2011-02-06 03:59:16.342571765 +0900
@@ -763,15 +763,21 @@
    my $ymdi_before;
    my $ymdi_after;
+	    my $before_title;
+	    my $after_title;
    if ($i > 1) {
	$ymdi_before = $ymd."-".($i-1);
+		$before_title = $ent->{$i-1}->{ho};
    } elsif ($idx < @day_list - 1) {
	my $day_b = $day_list[$idx + 1];
	$ymdi_before = $day_b."-".$cl->{all}->{$day_b}{curid};
+		$before_title = $cl->{all}->{$day_b}->{$cl->{all}->{$day_b}{curid}}->{ho};
    }
    if ($i != $ent->{curid}) {
	$ymdi_after = $ymd."-".($i+1);
+		$after_title = $ent->{$i+1}->{ho};
    } elsif ($idx > 0) {
	my $day_a = $day_list[$idx - 1];
	$ymdi_after = $day_a."-1";
+		$after_title = $cl->{all}->{$day_a}->{1}->{ho};
    }
 
@@ -794,4 +800,6 @@
    $t->param(back => $ymdi_before);
    $t->param(next => $ymdi_after);
+	    $t->param(back_title => $before_title);
+	    $t->param(next_title => $after_title);
 
    my $ccc = $item->{c}; $ccc =~ s!^<br />!!g;# ad hoc
現在の処理対象アイテムのタイトル取得は
$t->param(header_text => $item->{ho};
にあるので、特定のアイテムのタイトルは
$cl->{all}->{"YYYYmmdd"}->{x}->{ho};
で取れる。

テンプレ例
--- cl.conf.20110206	2011-01-23 16:42:37.523566691 +0900
+++ cl.conf	2011-02-06 03:58:01.367043689 +0900
@@ -362,6 +362,6 @@
 <div id="content">
 <p class="calendar"><a href="<TMPL_VAR name=ym>.html"><TMPL_VAR name=ym></a> / <a href="<TMPL_VAR name=ymd>.html"><TMPL_VAR name=ymd></a></p>
-<TMPL_IF name=back><a href="<TMPL_VAR name=back>.html">前のエントリ</a> / </TMPL_IF>
-<TMPL_IF name=next><a href="<TMPL_VAR name=next>.html">次のエントリ</a></TMPL_IF>
+<TMPL_IF name=back><a href="<TMPL_VAR name=back>.html">前のエントリ(<TMPL_VAR name=back_title>)</a> / </TMPL_IF>
+<TMPL_IF name=next><a href="<TMPL_VAR name=next>.html">次のエントリ(<TMPL_VAR name=next_title>)</a></TMPL_IF>
 <!-- start:<TMPL_VAR name=ymdi> -->
 <div class="day">

AlarmManagerで単純にブロードキャストを投げるだけ
2011-02-06-2 / カテゴリ: [Java][Android] / [permlink]

__軽く__ググってみても、「指定Activityを起動」「BroadcastReceiverをextendsした自前レシーバで受ける」しか見つけられなかったので「特定Activityが生きてれば受ける、なければ無視」をお試し。

ちなみに、定期/定時処理の実装は以下の方法がある(ほかにも有るかも。知らないだけで)
Timerアプリで管理
AlarmManagerシステム(android)で管理
するようなイメージみたい。(thanks! @amay077さん)
AlarmManagerはシステムレベルで動作するので、アプリの寿命と独立してるのがポイント。

public final static String INTENT_ACTION = "alarmmgr_broadcast";
:
:
	AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);

	Intent intent = new Intent(INTENT_ACTION);
	PendingIntent pending = PendingIntent.getBroadcast(this, 0, intent, 0);

	long current = SystemClock.elapsedRealtime();
	// 5秒後(current + 5*1000)にpending発動(1回きり)
	am.set(AlarmManager.ELAPSED_REALTIME, current + 5*1000, pending);
このBroadcastを受けるには[2011-02-06-1]の例で。

指定時間にブロードキャストでなく、単にActivityを起動するだけなら、
Intent intent = new Intent(this, FooBar.class);
PendingIntent pending = PendingIntent.getActivity(this, 0, intent, 0);
こんな感じで。サービス起動もいけそう(getService()で)。

AlarmManager.ELAPSED_REALTIME で「○msec後」に起動設定になる。
「Y年m月d日H時M分S秒に」の場合は、AlarmManager.RTC を使う
			Calendar cal = Calendar.getInstance();
			cal.set(2011, 1, 6, 3, 0, 0);	// 2011-02-06 03:00:00 の場合。monthは0オリジン(-1する)
			long next = cal.getTimeInMillis();
			Log.d(TAG, "current: " + next);
			am.set(AlarmManager.RTC, next, pending);

前記のAlarmManager#setは、指定時間に単に起動するのみ。
定期的に実行するにはAlarmManager#setRepeating()を使う。

キューに入ってるアラームを停止するにはcancel()
am.cancel(pending);
キャンセルは、Intentが同じ(filterEquals()がtrue)ものが対象らしい。
Remove any alarms with a matching Intent. Any alarm, of any type, whose Intent matches this one (as defined by filterEquals(Intent)), will be canceled.

AlarmManager#cancel

参考
Service(サービス)関連 mucchinのAndroid戦記
AlarmManagerで指定した時間に処理させる - Tech Booster
AlarmManager - 愚鈍人
Taosoftware: AlarmManager1 AndroidでCronみたいなことをするには
AlarmManagerの使用 - すにぺっと

レシーバおぼえがき(BroadcastReceiver)
2011-02-06-1 / カテゴリ: [Java][Android] / [permlink]

そのActivityがtopにいる場合にブロードキャストを受けるには。
public class FooBar extends Activity {
:
:
    // スレッドの通知を受けるためのレシーバ
	private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
		@Override
		public void onReceive(Context context, Intent intent) {
			Log.d(TAG, "  onReceive(" + context + ", " + intent + ")");
			if (intent.getAction().equals(Internal.INTENT_ACTION)) {
				Log.d(TAG, "intent val: " + intent.getIntExtra(Internal.INTENT_VAL, 0));
			}
		}
	};
	@Override
	public void onResume() {
		super.onResume();
		Log.d(TAG, "onResume()");
		// レシーバの登録
		registerReceiver(mReceiver, new IntentFilter(Internal.INTENT_ACTION));
	}
	
	@Override
	public void onPause() {
		super.onPause();
		Log.d(TAG, "onPause()");
		// レシーバの解除
		unregisterReceiver(mReceiver);
	}
:
registerReceiver()第2引数でフィルタを設定しているので、onReceive()内でgetAction()でAction名をチェックしてるのはこの例では冗長。
(rergisterReceive()を複数叩いて複数のレシーバを受ける場合は必要)

おまけ
↑のInternalは別クラス(ブロードキャスト元)
投げる部分はこんな感じ。(適当)
public class Internal extends Activity {
	public final static String INTENT_ACTION = "internal_thread_broadcast";
	public final static String INTENT_VAL = "internal_thread_val";
	private int mCount = 0;

// 中略
			Thread thread = new Thread(new Runnable() {

				@Override
				public void run() {
					// TODO 自動生成されたメソッド・スタブ
					try {
						for (;;) {
							Thread.sleep(1000);
							mCount ++;
							Log.d(TAG, "running count("+ mCount + ")");
							Intent intent = new Intent(INTENT_ACTION);
							intent.putExtra(INTENT_VAL, mCount);
							sendBroadcast(intent);
						}
					} catch (InterruptedException e) {
						// TODO 自動生成された catch ブロック
						e.printStackTrace();
					}
				}
				
			});
			thread.start();

// 後略
Referrer (Inside): [2011-02-06-2]
2011-02-01 Tue (他の年の同じ日: 2005 2006 2007 2010)

シェルの起動
2011-02-01-2 / カテゴリ: [shell][Android] / [permlink]

% adb shell
adbはSDK revision7まではtoolsの下にあったけど、revision8からはplatform-tools以下にあるので注意。(6→7だったかも知れん。うろ覚え)
エミュレータと実機、みたいに、複数のデバイスが接続されている場合は
% adb shell
error: more than one device and emulator
となってしまうので、
% adb devices
List of devices attached
emulator-5554   device
HT**********    device
で一覧を出して、
% adb -s emulator-5554 shell
と、シリアルナンバーでデバイスを指定してやる。

詳しくは
% adb -h
で見れる。

なお、シェルコマンドは(sshのリモートコマンド実行の要領で)
% adb [-s serialnumber] shell [command [arg...]]
で、一気に実行できる。

ちなみにシェルはsh(だよな?)。タイムマシンに乗った気分。
環境によって違うと思うけど、エミュレータ(2.2/デフォルトパラメタで作成)だと
# printenv
printenv
ANDROID_ROOT=/system
LD_LIBRARY_PATH=/system/lib
PATH=/sbin:/system/sbin:/system/bin:/system/xbin
ASEC_MOUNTPOINT=/mnt/asec
BOOTCLASSPATH=/system/framework/core.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/android.policy.jar:/system/framework/services.jar
ANDROID_BOOTLOGO=1
ANDROID_ASSETS=/system/app
EXTERNAL_STORAGE=/mnt/sdcard
ANDROID_DATA=/data
ANDROID_PROPERTY_WORKSPACE=9,32768
# cat /proc/cpuinfo
cat /proc/cpuinfo
Processor       : ARM926EJ-S rev 5 (v5l)
BogoMIPS        : 279.34
Features        : swp half thumb fastmult vfp edsp java
CPU implementer : 0x41
CPU architecture: 5TEJ
CPU variant     : 0x0
CPU part        : 0x926
CPU revision    : 5

Hardware        : Goldfish
Revision        : 0000
Serial          : 0000000000000000

desireII(2.2/ドノーマル)だと
$ printenv
printenv
ANDROID_ROOT=/system
LD_LIBRARY_PATH=/system/lib
PATH=/sbin:/system/sbin:/system/bin:/system/xbin
ASEC_MOUNTPOINT=/mnt/asec
BOOTCLASSPATH=/system/framework/core.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/android.policy.jar:/system/framework/services.jar:/system/framework/com.htc.framework.jar:/system/framework/com.htc.android.pimlib.jar:/system/framework/com.htc.android.easopen.jar:/system/framework/com.scalado.util.ScaladoUtil.jar
ANDROID_BOOTLOGO=1
ANDROID_ASSETS=/system/app
EXTERNAL_STORAGE=/mnt/sdcard
ANDROID_DATA=/data
ANDROID_PROPERTY_WORKSPACE=10,65536
$ cat /proc/cpuinfo
cat /proc/cpuinfo
Processor       : ARMv7 Processor rev 2 (v7l)
BogoMIPS        : 162.54
Features        : swp half thumb fastmult vfp edsp thumbee neon
CPU implementer : 0x51
CPU architecture: 7
CPU variant     : 0x0
CPU part        : 0x00f
CPU revision    : 2

Hardware        : bravo
Revision        : 0083
Serial          : 0000000000000000

などなど

エミュレータでパケットキャプチャ
2011-02-01-1 / カテゴリ: [command][network][Android] / [permlink]

ホストPCやサーバ側でキャプチャできない環境の場合、エミュ自身の内蔵tcpdumpでキャプチャ可能。
多分使う機会はホストがwindowsで、ホスト自身で動かしてるサーバへアクセスする際のキャプチャくらいかね。(リモートならEthereal使えば良し)

基本は
# tcpdump -s 0 -X port 80
など。

-s 0 は、未指定だとデフォルトキャプチャサイズが96bytesになり、キャプチャ漏れが発生するので、適当に指定すればよし。0指定だと65535byteになる。
-X は指定なしだと訓練されていないと読めない(笑)

port 80 の部分は、キャプチャのフィルタ条件。指定がないとidleでも結構パケットが飛んでいるので、見たいパケットが見えなくなる。
"port 80" で 80/TCP の全てのパケット
"host jp-z.jp" で、jp-z.jp との全パケット
"port 80 and host jp-z.jp" で↑のand

「コマンドラインじゃわからん!wiershark/etherealで見たいんだ!」な場合は
# tcpdump -s 0 -w /mnt/sdcard/capture.cap port 80
でキャプチャ結果をファイルへ出力できるので、DDMSのファイルエクスプローラで取り出して見ればOK
あとはググッてねん。

ちなみに停止の^Cで、シェルごとなぜか抜けてしまうので、PCのシェル(コマンドライン)上で
% adb -s emulator-5554 shell tcpdump -s 0 -w /mnt/sdcard/capture.cap port 80 and host jp-z.jp
とした方が良いかも知れん。


実機だとpermission deniedになる。うーん、rootな端末もあった方が良いのかも。
2011-02
前の月 / 次の月 / 最新

2013 : 01 02 03 04 05 06 07 08 09 10 11 12
2012 : 01 02 03 04 05 06 07 08 09 10 11 12
2011 : 01 02 03 04 05 06 07 08 09 10 11 12
2010 : 01 02 03 04 05 06 07 08 09 10 11 12
2009 : 01 02 03 04 05 06 07 08 09 10 11 12
2008 : 01 02 03 04 05 06 07 08 09 10 11 12
2007 : 01 02 03 04 05 06 07 08 09 10 11 12
2006 : 01 02 03 04 05 06 07 08 09 10 11 12
2005 : 01 02 03 04 05 06 07 08 09 10 11 12
2004 : 01 02 03 04 05 06 07 08 09 10 11 12

最終更新時間: 2013-05-02 16:12