2010年12月1日水曜日

android.permission.INJECT_EVENTS



androidに外部からイベントを流せたら面白いな。
とか思っていて、Event周りを調べていたけど、
よくよく考えると、Androidのテストフレームワークって
テスト用のパッケージ作って、ソコからUI操作するし、
Monkeyとか言うテストツールも外部からイベント流しているな。
とか思ったので、Monkeyのソースを見てみたら、
injectKeyEventとかがあった。
Serviceの口として
// These can only be called when injecting events to your own window,
// or by holding the INJECT_EVENTS permission.
boolean injectKeyEvent(in KeyEvent ev, boolean sync);
boolean injectPointerEvent(in MotionEvent ev, boolean sync);
boolean injectTrackballEvent(in MotionEvent ev, boolean sync);
見たいにIWindowManager.aidlに定義してある。
なんか、外部からいじれるっぽいな。
INJECT_EVENTS
にもマニフェストの説明として普通にINJECT_EVENTSについて説明あるし。
最初からデベロッパーサイトのManifestのpermissionについての説明
を読んどけば、Androidで何が可能なのか解ってたかも。。。

2010年11月29日月曜日

hardwareのeventを拡張しようと思ったら



まだ、メモ書き程度だけど、調べたことを忘れるのもイヤなのでメモしておく。
動かしたわけではなく、あくまで読んでみた結果だけど。
EventLoopの肝は、
eclair/frameworks/base/services/java/com/android/server/KeyInputQueue.java
の Thread mThread = new Thread("InputDeviceReader") {
の部分。
ここで、hardwareからイベントを取得している。
具体的には、readEventで、こいつの実態はJNIを利用して、
android_server_KeyInputQueue_readEvent()
といった関数として定義されている。
この関数の中でさらにEventHub::getEventをコールすることで
/dev/からいろんなデバイスのイベントを取得している。
EventHub::getEventのなかで、イベントのcodeやscancodeを作ったりしている。
それを上のmThreadで読んでいるわけだ。
で、ここからイベント配信をしている。
詳しい仕組みは、今後読み解いていく。

もし、ハードウェア的にデバイスを足したいときは、
JNI層から手を入れる必要があり、
擬似的にイベントを発行するデバイスをJava層で作ろうとしたら、
readEventあたりを書き換えることになりそう。
もしくは、別スレッドを作って、ソコからイベントキューに勝手にイベントを足すとか。

2010年11月24日水曜日

Xacti買った

スノーボードのシーズンがやってきました。
今年は、ボードやっているときにビデオでもとろうかと思って
Xacti買いました。
HTC DesireのカメラもHD動画対応なので、
両方を持って撮影して、比較してみた。

まずDesire


んで、こっちがXacti


当然だけどXactiの方がいいですね。

2010年10月31日日曜日

AndroidのCameraアプリ


Androidのカメラアプリだけど、
思いの他はまりました。。。なのでメモとっておきます。
HTC Desire(2.2)で動作確認したアプリを貼り付けときます。
SampleUseCamera.tar.gz
写真とって、保存するだけです。

中身ですが、
デベロッパーサイトには書いてあるんだけど、
意外と他のサイトやサンプルでは違うことが書いてあったりしたのがManifest

uses-permission android:name="android.permission.CAMERA"
uses-feature android:name="android.hardware.camera"
uses-feature android:name="android.hardware.camera.autofocus"
が必要なのと、以下の二つも念のため追加しました。
uses-feature android:name="android.hardware.camera.flash"
uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"


で、一番ハマッたのがシャッターの処理だ。
Webや本にあるサンプルだと
シャッターを切ったときにアプリが落ちる。。。だけじゃなく
端末のリソースを解放せずに落ちるので、端末全体でカメラが使えなくなったり。。。
Camera.autoFocusで設定するコールバックの中で、
Camera.takePictureを実行するのが一般的のようだが、
TakePicture後にすぐにもう一度Camera.autoFocusが実行されると落ちるし、
他のActivityを立ち上げようとすると落ちるし。。。
根本的な原因はわからないですが、
画面をタッチしてシャッターを切るようにしてあるコードで、
DOWNで切って、UPでも切ってしまっているのが問題の模様。
なので、


void takePictureAutoFocus(ShutterCallback shutter, PictureCallback raw, PictureCallback jpeg) {
_shutter = shutter;
_raw = raw;
_jpeg = jpeg;

synchronized (lockObject) {
if (takingpicture != false) {
return;
}
takingpicture = true;
}

camera.autoFocus(new AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, final Camera camera) {
camera.takePicture(_shutter, _raw, _jpeg);

new Thread() {
@Override
public void run() {
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
}
synchronized (lockObject) {
takingpicture = false;
}
if (_auto_focus_listener != null) {
_auto_focus_listener.onTakenPicture();
}
camera.startPreview();
}
}.start();
}
});
}

みたいにして、ちょっと時間がたつまで待ってます。
本当は、もっとちゃんとタイミング計りたいけど、
コードが結合する。。。ので、まあいいか。
CameraPreviewに書いてありますが、

private static final int PREVIEW_WIDTH = 800;
private static final int PREVIEW_HEIGHT = 480; // 800x480 = WVGA
private static final int PICTURE_WIDTH = 1280;
private static final int PICTURE_HEIGHT = 768;

みたいに、端末の画面サイズ(コード的にはカメラのpreviewのサイズ)がWVGA
保存する写真のサイズが1280x768にしてあります。

Java自体なれてないので、変なとこあるとは思いますが、
とりあえずは動くサンプルということで。

2010年10月25日月曜日

dispatchKeyEventについて


androidのkeyイベントについて調べたので、
忘れないようにメモしとく。

結論から書くと、androidのキーイベントの
イベント配信の方法は、GTKと同じで、
親から順番にイベントが通知されていき
最終的にフォーカスが当たっている
もしくは当たっていたアイテムにキーイベントが通知される。
といったものだ。
うーん。子供からキーイベントが通知されて、
親にバブルアップしていったほうが拡張性が高いんだがな。。。


アプリを作る人に最初に見えるのは、
ActivityのdispatchKeyEventで、
そこからGroupView->View->ユーザ定義のView
といった具合だ。
なので、
上下キーをこっちのViewに通知して
左右キーはあっちのViewに通知する
みたいな処理をしようと思ったら、
ActivityでdispatchKeyEventをOverrideして、
そこでイベント処理をしてやらなければいけない。
しかもフォーカス依存になっているから、
そのたびにフォーカスの移動しなければいけないのでは。。。
やっぱandroidって、タッチパネル前提のプラットフォームだなぁと
改めて感じた。

ちなみに、確認のために書いてみたのは
下のようなコードです。


HelloAndroid.java

package com.example.helloandroid;

import java.util.Random;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnKeyListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.content.Intent;


public class HelloAndroid extends Activity{

@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_UP) {
switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_0:
Log.v("HelloAndroid","Activity KEYCODE_0");
return true;
default:
}
}
Log.v("HelloAndroid","Activity");
return super.dispatchKeyEvent(event);
}

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);


Button b_true = (Button)findViewById(R.id.button_true);
b_true.setOnKeyListener(new OnKeyListener(){
public boolean onKey(View v, int keyCode, KeyEvent event){
if (event.getAction() == KeyEvent.ACTION_DOWN) {
Log.v("HelloAndroid","button true");
return true;
}
return false;
}
});

Button b_false = (Button)findViewById(R.id.button_false);
b_false.setOnKeyListener(new OnKeyListener(){
public boolean onKey(View v, int keyCode, KeyEvent event){
if (event.getAction() == KeyEvent.ACTION_DOWN) {
Log.v("HelloAndroid","button false");
}
return false;
}
});

ListView listView = (ListView) findViewById(R.id.listview);
String[] items = new String[] {"First", "Second", "Third", "Fourth"};

ArrayAdapter adapter = new ArrayAdapter (this,
android.R.layout.simple_list_item_1,
items);

listView.setAdapter(adapter);
listView.setOnKeyListener(new OnKeyListener() {
public boolean onKey(View v, int keyCode, KeyEvent event){
if (event.getAction() == KeyEvent.ACTION_DOWN) {
Log.v("HelloAndroid","listView false");
}
return false;
}
});

LinearLayout linear = (LinearLayout)findViewById(R.id.parent);
linear.setOnKeyListener(new OnKeyListener() {
public boolean onKey(View v, int keyCode, KeyEvent event){
if (event.getAction() == KeyEvent.ACTION_DOWN) {
Log.v("HelloAndroid","linear false"); // これは永久に出ません。なぜならLinearLayoutではdispatchしているだけだから。
}
return false;
}
});
}
}


ほかにも色々書いてあったコードから、
抜き取ったので、きちんと動くかはナゾ。

いかは、コールバック

HelloAndroid [Android Application]
HelloAndroid [Android Application]
DalvikVM[localhost:8617]
Thread [<3> main] (Suspended (breakpoint at line 97 in HelloAndroid$5))
HelloAndroid$5.onKey(View, int, KeyEvent) line: 97
ListView(View).dispatchKeyEvent(KeyEvent) line: 3678
ListView(ViewGroup).dispatchKeyEvent(KeyEvent) line: 746
ListView.dispatchKeyEvent(KeyEvent) line: 1943
LinearLayout(ViewGroup).dispatchKeyEvent(KeyEvent) line: 748
FrameLayout(ViewGroup).dispatchKeyEvent(KeyEvent) line: 748
LinearLayout(ViewGroup).dispatchKeyEvent(KeyEvent) line: 748
PhoneWindow$DecorView(ViewGroup).dispatchKeyEvent(KeyEvent) line: 748
PhoneWindow$DecorView.superDispatchKeyEvent(KeyEvent) line: 1655
PhoneWindow.superDispatchKeyEvent(KeyEvent) line: 1102
HelloAndroid(Activity).dispatchKeyEvent(KeyEvent) line: 2038
HelloAndroid.dispatchKeyEvent(KeyEvent) line: 40
PhoneWindow$DecorView.dispatchKeyEvent(KeyEvent) line: 1631
ViewRoot.deliverKeyEventToViewHierarchy(KeyEvent, boolean) line: 2368
ViewRoot.handleFinishedEvent(int, boolean) line: 2338
ViewRoot.handleMessage(Message) line: 1641
ViewRoot(Handler).dispatchMessage(Message) line: 99
Looper.loop() line: 123
ActivityThread.main(String[]) line: 4363
Method.invokeNative(Object, Object[], Class, Class[], Class, int, boolean) line: not available [native method]
Method.invoke(Object, Object...) line: 521
ZygoteInit$MethodAndArgsCaller.run() line: 860
ZygoteInit.main(String[]) line: 618
NativeStart.main(String[]) line: not available [native method]
Thread [<13> Binder Thread #2] (Running)
Thread [<11> Binder Thread #1] (Running)
Thread [<15> Binder Thread #3] (Running)

2010年10月8日金曜日

HTC Desire(X06HT)でCloud to Device Messaging

10月8日にHTC Desire(H06HT)がandroid 2.2にアップデートされて、
HD動画が撮影できるようになったり、
標準のブラウザのWLAN切り替え時の動作の不具合が改修されていたり、
microSDからアプリを起動できるようになったり、
追加された機能はいろいろあったけど、
個人的に一番気になっていたのは、
Cloud to Device Messaging
簡単にいうと端末側に対してリモートからintentを発行する仕組みだ。
このAPIに対応したアプリを作るには、サーバも用意しなければいけないが、
今すぐ利用できるものとして、
chrometophone
があるので試してみた。

以下試した動画

ちょっと解りにくいけど、
画面右上のchrometophoneのアイコンをクリックすると
「端末に転送しました」のポップアップが出て
chromeで開いているページのURL(動画ではyahoo)をandroid端末に送って、
intentを発行してブラウザを立ち上げている。
スゲー。
この仕組みを使えば、android搭載の携帯端末からintentを発行して、
android搭載のテレビやSTBをコントロールするといったことが可能そう。

ついでにHD動画もアップしてみる。
撮影するときにコマが飛ぶことがあるみたいです。

あんまりいい動画じゃないですね。。。そのうち清流での動画でもとりたいです。

2010年9月24日金曜日

androidのタイトルバーにプログレスバー



androidのアプリケーションのタイトルバーに
プログレスバーを表示する方法についてメモを取っておく。
基本的に、画面描画はメインスレッドに処理をさせなければいけないので、
mHandler.postを利用している。


import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.Window;
import android.widget.ProgressBar;

public class MainActivity extends Activity {
private Handler mHandler = new Handler();
private int mTotal;
private int mRemain;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_PROGRESS);
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setContentView(R.layout.main);

/* showProgressはButton */
findViewById(R.id.showProgress).setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
start();
}
});
start();
}

private void start() {
setProgressBarIndeterminate(false);
setProgressBarVisibility(true);
setProgressBarIndeterminateVisibility(true);

new Thread(new Runnable() {
public void run() {
mTotal = 100;
mRemain = mTotal;
do {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
mRemain--;

mHandler.post(new Runnable() {
public void run() {
setProgress((mTotal-mRemain)*100);
}
});

} while (mRemain> 0);
}
}).start();
}
}



別スレッドで、50msec寝て画面描画要求をメインスレッドのハンドラー経由で
行っているだけ。
ボールドさせているところが、プログレスバーの表示部分で
イタリックになっているところが、メインスレッドに描画処理をさせているところ。

2010年9月22日水曜日

大事故ですよ

用事があって行けなかったのは残念だったな~。
youtubeでも一日中ランキングのトップだったww

2010年9月7日火曜日

androidではまった


しばらくandroidのSDKをいじっていなかったら、
eclipseからemulatorが起動しなくなってた。。。
エラーメッセージ(Error generating final archive: Debug certificate expired)
でググって見たら、情報が出てきた。
どうやら証明書関連らしい
1.~/./androidにあるdebug.keystoreを削除
2.Project メニューの Clean... を実行
これだけで直った。
ちょっぴりはまってしまった。。。

2010年8月14日土曜日

ジェフ・ショーリ


久々にフクアリに行ってジェフが勝った~。
倉田(僕の中ではファンタジスタ)が活躍しなかったのは
残念だけど、勝ったからいっか!!

2010年8月9日月曜日

TVPlayerと「SEG CLIP」 GV-SC310とandroid(X06HT)

PCで録画したワンセグのコンテンツをAndroidにインストールした
TVPlayerで見たいと思ったのだけど、
だいぶ苦労したので、方法を書いておきます。

まず、GV-SC310について、
これ自体は、インストールも簡単でワンセグを見るのも簡単でした。
ただ、私の家では電波状況が悪かったので、付属のアンテナだけでは視聴できませんでした。
ただ、我が家にはアンテナの線が2本引かれていたので、
優先でケーブルテレビの電波を拾っています。

TVPlayerをインストールして起動したら、こんな画面


サーバを検索したら、見つからなかった。。。


うーん何でだろ。てことで
IPを入れてみたけどやっぱり見つからない。。。

Nortonのファイアーウォールで、TCPポート8278を開くも成功せず。
何が問題か解らず、
ルータをブリッジ接続にしてくださいとか
いろいろ書いてあるのを読んでルータの設定を変えてみたりしたけど、
結局はルータのファームウェアの更新をすることで解決した。
ココまで来るのに、数時間かかってしまった。
私が利用しているのはWZR2-G300Nで、ファームウェアにバグがあったらしく
iphoneやandroidからWiFiでつながらないとか何とか。。。
で、WZR2-G300N Ver.1.55にルータのファームウェアをアップデータしたら、


こんな画面、どう考えてもPCにインストールした
GV-SC310のバージョンが古そう。
ということでI/Oデータのサポートページから最新のソフトをダウンロードしてインストール。


やっと見えたー。あーつかれた。

ここからは順調で














わーい。みれた。


androidでワンセグ視聴をするための手順をまとめると
1.GV-SC310のソフトをインストール
2.GV-SC310のソフトを最新にアップデート
3.無線LANルータのファームウェアを最新にアップデート(ルータの設定はルータモード。AndroidがIPを割り当ててもらえなくなります。)
4.PCのファイアーウォールの設定でTCP ポート8278を開く
5.Androidで、TVPlayerをインストール
6.TVPlayerを起動する。

ちなみに私はHTC Desire(X06HT)で成功しました。
42分9秒(2529秒)のコンテンツを3分9秒(189秒)でダビングできました。
REGZAでmicroSDにワンセグコンテンツをコピーするより断然速い!

2010年8月7日土曜日

いろいろ



会社の同期の人が結婚したり、
仲の良かった同期が退職したり、
いろいろあるけど、人生は人それぞれですよね。

自分が最近仕事に対して、ヤル気が抜けているのもあって、
妙に考え込んでしまいました。

2010年8月1日日曜日

ワンピース祭り


マンガの方のワンピースのことです。

フットサルを水道橋でやったので、
その足で神保町でやっていたワンピース祭りに行ってみた。

神保町でスノボーのズボンを買いに行くついでに
チラッ見ていくだけのつもりだったけど、
予想外にいい感じだった。
グッズが適当に打ってるだけかと思ったら、
原画がいっぱい!!
昔のジャンプの表紙とかもあって、結構楽しめました。

一番印象に残ったこと。
神保町には、エッチな本とかが売ってる店とかもあるわけですが、
のれんの様な目隠しがあるわけではなく、
フツーに外からでも店内が見えます。
普段は女性がいっぱいということは、ほとんどない神保町ですが、
ワンピース祭りでは女性が多かったです。
女性が多い中でも普段と変わらず、エッチな本屋に堂々と入っている方々に
「漢」を感じました。

写真は、靖国通りと白山通りが交わる場所にあったチョッパーと一緒にとったもの。
満面の笑顔。。。スゲー楽しそうですね。