シャカシャカシェイクリスナー

Standard
シャカシャカシェイクリスナー

「Android端末をフンッ!って振ったら、今いる場所の住所をtwitterでつぶやく」っていう機能を実装したときのメモ。GPSから逆ジオコーディングとかjavaのtwitterライブラリ、twitter4jの使い方とかはサンプルがたくさんあるので他を参照。SensorEventListenerを使った、「端末がシェイクされた」っていうのの検知部分をメモっとくばいー
 
 
物理わからん
 
「android 加速度センサー シェイク」とかでググって出てきたのがここらへん。
http://www.grandnature.net/blog/archives/2009/02/android_2.html
http://andronavi.com/2010/03/15069
 
ハイカットとローカットとかCONVERSEしか思いつかないので、先人の知恵をほぼ流用させてもらうことにした。あと、いい歳した大人が夜な夜な携帯を振りまくって得たという謎の計算式も使っちゃう。Sensor.TYPE_ACCELEROMETER使って取得したx,y,zそれぞれの軸に対する端末の傾き具合座標のイベント発生前後の差がある一定の値を超えたら、「振られた」って判断してるってことだと思う。
 
ということで「振られた」を判断するためのクラスを↓みたいに書いた。
ShakeDeterminator.java

package com.bugcloud.android.touchme.util;

import android.hardware.SensorEvent;

public class ShakeDeterminator {

    private float[] currentOrientationValues = {0.0f, 0.0f, 0.0f};
    private float[] currentAccelerationValues = {0.0f, 0.0f, 0.0f};
    private static final int LEVEL = 2;

    public boolean isShake(SensorEvent event) {
        float shakeLevel = 30 + (8 * (float)LEVEL);
        boolean result = false;

        float values[] = event.values;
        currentOrientationValues[0] = values[0] * 0.1f + currentOrientationValues[0] * (1.0f - 0.1f);
        currentOrientationValues[1] = values[1] * 0.1f + currentOrientationValues[1] * (1.0f - 0.1f);
        currentOrientationValues[2] = values[2] * 0.1f + currentOrientationValues[2] * (1.0f - 0.1f);
        currentAccelerationValues[0] = values[0] - currentOrientationValues[0];
        currentAccelerationValues[1] = values[1] - currentOrientationValues[1];
        currentAccelerationValues[2] = values[2] - currentOrientationValues[2];

        float targetValue = Math.abs(currentAccelerationValues[0]) + 
                                    Math.abs(currentAccelerationValues[1]) +
                                    Math.abs(currentAccelerationValues[2]);
        if (targetValue > shakeLevel) {
            result = true;
        }
        return result;
    }
}

 
ただコレだと、端末の傾きしか見てないので正確には「振る」を検知できない気がする。端末の傾きを変えないまま上下に動かすときとか。端末の直線的な動きしか見てないので正確には「振る」を検知できない気がする。端末の位置を変えないままブンブンやるときとか。「Androidって振るときにコツがいるんですよー」で逃げれそうな気配しかしないので今回は深追いしません。。。。。。
 
上のクラスを使ったActivityが↓な感じ
 

package com.bugcloud.android.touchme;

import java.util.List;

import com.bugcloud.android.touchme.util.ShakeDeterminator;

import android.app.Activity;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.widget.Toast;

public class TouchMe extends Activity implements SensorEventListener {
    
    private boolean registeredSensor;
    private SensorManager sensorManager;
    
    private ShakeDeterminator shakeDeterminator;
    
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        registeredSensor = false;
        sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
        shakeDeterminator = new ShakeDeterminator();
    }
    
    @Override
    protected void onResume()
    {
        super.onResume();
        
        List<Sensor> sensors = sensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER);
        if (sensors.size() > 0) {
            Sensor sensor = sensors.get(0);
            registeredSensor = sensorManager.registerListener(this,
                                                                sensor,
                                                                SensorManager.SENSOR_DELAY_NORMAL);
        }
    }

    
    @Override
    protected void onPause()
    {
        if (registeredSensor) {
            sensorManager.unregisterListener(this);
            registeredSensor = false;
        }
        
        super.onPause();
    }

    // Show Toast Message
    private void show(String message)
    {
        Toast.makeText(
            this,
            message,
            Toast.LENGTH_SHORT
        ).show();
    }

    public void onAccuracyChanged(Sensor arg0, int arg1) {
        // TODO Auto-generated method stub
        
    }

    public void onSensorChanged(SensorEvent event) {
        if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
            if(shakeDeterminator.isShake(event)) {
                show("加速度センサーが反応した");
            }
        }
    }
}

 
shakeDeterminator.isShake(event)の戻り値がTRUEだったときにやる処理を別スレッドでやったりするときは、クラス変数にそのスレッドが動いてるかどうかのフラグでも持っといてやんないとスレッドめっちゃ立っちゃう気がします。
ShakeDeterminator.javaのLEVELはセンサーの感度、sensorManager.registerListener()の第3引数はセンサーイベントの検知頻度。実機で試した結果、LEVEL=2で、頻度はSensorManager.SENSOR_DELAY_NORMALっていうが今回の場合はちょうどよかった。
 
 
Activity殺害事件
 
Androidは画面の縦/横でレイアウトを変えたりできるわけですが、この時にActivityは一回死んでもっかいonCreate()が走る。らしい。ので、この「振る」ときにActivityがぶっ生き返しまくる。これを回避するには画面の方向を固定してやればよかと。AndroidManifest.xmlのactivityにandroid:screenOrientation属性を追加してやる。
 
AndroidManifest.xml

< ?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.bugcloud.android.touchme"
      android:versionCode="1"
      android:versionName="1.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".TouchMe"
                  android:label="@string/app_name"
                   android:screenOrientation="nosensor">
            <intent -filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent>
        </activity>
    </application>
    <uses -sdk android:minSdkVersion="4" />
</manifest> 

 
 
振ると揺れるおっぱいシミュレータをtechnohippyさんより先に作ろうと思う。

早起きしすぎた

Standard
早起きしすぎた

ちょっと昼寝のつもりが12時間ぐらい爆睡してしまったので、今日は4時すぎから起きとります。
 
せっかく早起きしたので、こないだ寝る寸前に思いついたAndroidアプリを作ってみました。Androidケータイ持ってないので実機でテストできません。ヒマな人、貸してください。あとデザイン変えたいのでムフフな絵を描いてくれる人いませんか?Android Marketで公開できたあかつきには、売上の半分を渡します。ちなみにアプリは50円にする予定です。開発中のベータ版アプリはこれです。XperiaとかDesireとか持ってる人はインストールしてみてください。そしてキャプチャを送ってください。背景が伸びまくってる予感しかしません。 → あぽり
以下がいよー
 
 
アプリ名:考え中
アプリ説明:カラダを触るといろんな声を出すよ。触る場所と触り方で声の種類も変わるよ。
カテゴリ:foolish
アプリキャプチャ:
screenshot

CAP 001

screenshot

CAP 002

備考:
   Picture from テケ
   Sounds from あみたろ
 
 
 
「こする」の検知がよくわからん
 
「カラダが触られた」っていうのは、透明のボタンを配置しておいて、そのボタンにリスナーを設定してます。「タッチされた」っていうのはOnClickListenerで

((Button)findViewById(R.id.btn)).setOnClickListener(new OnClickListener() {
    public void onClick(View v) {
        show("どんたっちみー");
    }
});

みたいなことをやればいいと思うんだけど、「こすられた」っていうのはどう判断すればいいのかよくわからんです。いまはOnTouchListenerを設定しといて、android.view.MotionEvent.getAction() で「タッチされた部分が動かされたら」みたいなことをやってます。ただこれをエミュレータ上で試すと何回もイベントが発生してるような。。実機でやってみたら違ったりする系のノリですか?

((Button)findViewById(R.id.btn)).setOnTouchListener(new OnTouchListener() {
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                break;
            case MotionEvent.ACTION_UP:
                break;
            case MotionEvent.ACTION_MOVE:
                show("こすってんじゃないわよ");
                break;
            case MotionEvent.ACTION_CANCEL:
                break;
        }
    return false;
    }
});

 
 
 
先週から仕事でも軽いAndroidアプリを作ってるんですが、学んだ教訓がひとつ。
安易な気持ちでTableLayoutを使わない
です。
htmlと同じ勢いでテーブル使ってるとレイアウトの調整に苦しむ気がしました。LinearLayout使って、横に並べたいときはandroid:orientation=”horizontal”、縦はandroid:orientation=”vertical”を組み合わせてったほうが楽に調整できる気がします。あと、android:layout_widthとandroid:layout_heightにはwrap_contentとかfill_parentじゃなくて”?px”とか”?sp”が使えることに気づくとグッと調整が早くなりました。
上の開発中アプリで使ってるレイアウトのxmlは↓な感じです。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="#fefefe"
    android:scrollbars="vertical"
    android:scrollbarSize="18px"
    android:scrollbarStyle="outsideInset">
<ScrollView android:layout_width="fill_parent" android:layout_height="wrap_content">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@drawable/back001">
    <Button android:text=""
            android:id="@+id/head_move"
            android:layout_height="26px"
            android:layout_width="wrap_content"
            android:layout_marginTop="60sp"
            android:layout_gravity="center"
            android:gravity="center"
            android:minWidth="200sp"
            android:background="@drawable/alpha"/>
    <Button android:text=""
            android:id="@+id/head"
            android:layout_height="50sp"
            android:layout_width="50sp"
            android:layout_marginTop="0sp"
            android:layout_gravity="center"
            android:gravity="center"
            android:background="@drawable/alpha"/>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_marginTop="140sp"
    android:gravity="center">
    <Button android:text=""
            android:id="@+id/beachLeft"
            android:layout_height="50px"
            android:layout_width="50px"
            android:layout_gravity="left"
            android:layout_marginRight="25sp"
            android:gravity="center"
            android:background="@drawable/alpha"/>
    <Button android:text=""
            android:id="@+id/beachRight"
            android:layout_height="50px"
            android:layout_width="50px"
            android:layout_gravity="left"
            android:gravity="center"
            android:background="@drawable/alpha"/>
</LinearLayout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_marginTop="50sp"
    android:gravity="center">
    <Button android:text=""
            android:id="@+id/heso"
            android:layout_height="50px"
            android:layout_width="30px"
            android:layout_gravity="center"
            android:gravity="center"
            android:background="@drawable/alpha"/>
</LinearLayout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_marginTop="10sp"
    android:gravity="center">
    <Button android:text=""
            android:id="@+id/xxx"
            android:layout_height="50px"
            android:layout_width="30px"
            android:layout_gravity="center"
            android:gravity="center"
            android:background="@drawable/alpha"/>
</LinearLayout>
</LinearLayout>
</ScrollView>
</LinearLayout>

 
 
 
もう少しタッチできる部分を増やしたらいったん公開して、Version2.0とかで音を設定できるようにすればいいかなーと思ってます。
 
追記
会社の人に教えてもらったけど、MotionEvent.ACTION_MOVEのところは、OnTouchListenerが動くたびに反応してるので上だと反応しまくってると。なので、別に「こする」検知用のクラスを用意して、eventを渡すメソッド作ればよいみたいです。受けとった側でしきい値を超えたら、「こすられた」って判断してやればいいと。数学とかもうすっかり忘れたけど、ピタゴラスの定理とか使えばいんじゃね?
 
 

Cover image is not found
amazon.co.jpで詳細情報を見る


my job’s memo

Standard
my job's memo

Webサービスクライアントの開発でつまずいたのでメモ。
知識がないって悔しい上に恥ずかしいね。
 
 

DataSetオブジェクト

 
 
Webサービスサーバ側のシステムプラットフォームはASP.NET
クライアント側はJava2EE
で、今回の開発はクライアント側の開発
 
 
要件の時点で相手側(サービス側システム)の主管からは
「こっちで用意してる既存のWebサービスを利用してもらえばデータのやりとりはOKだから全部あわせてね」
って感じで言われていた。(実際は向こうのシステムも開発中)
 
 
I/Fの設計書とかをもらって、とりあえず初体験のWebサービスの概要設計書を書いてみる。
(いま思えば、ここでちゃんと勉強しとけばよかったわけですけども)設計終わって
じゃーそろそろ製造したいからWDSLファイルくださいよっつって、相手側の開発担当者と
打ち合せしてるときに言われたのが、
 
「ちなみにそちらの言語はなんですか?」
「Javaですが」
「Javaかー。既存のクライアントの中にjavaのシステムが1つあるんですけど、DataSet型がうまく扱えないみたいな話がでてるんですよねー。」
「ん?」
 
 
んで、まーちょっと調べてみました。DataSetって?
http://www.atmarkit.co.jp/fdotnet/basics/adonet04/adonet04_01.html
 
javaと.NETでWebサービス
http://blogs.sqlpassj.org/akiraonishi/articles/4244.aspx
http://d.hatena.ne.jp/kkamegawa/20080926/p1
 
 
何その「いや普通に使えないよ」的な空気!なんで知らないんだろうなオレのあほーっ
結局むこうが対応してくれるわけもなく、こっちで解決策を考えないといけないっすよね
いやーしかし、調べてみるとつくづく常識みたいな感じですね。
今回は複雑なデータもらうわけじゃないので、XMLからDOMを利用して必要な情報だけとればいいのかな。
 
http://yamarou.at.infoseek.co.jp/javanawake/002.html
 
中国人プログラマに聞いたら、WDSLファイルをどの言語でも使えるように記述し直して、もっかいweblogicでクラスファイル生成すればうまいこといくアルよって言われたけど、どうなの?wできなそうな気がするけども?????
 
 
相手側のシステムの人からは↓の利用を検討してくださいっていう感じでメールがきたけれども
http://kickjava.com/src/groovy/sql/DataSet.java.htm
 
↑使ったら、相手からもらったDataSetオブジェクトがJavaで扱えるってこと?
仕組みがわからぬよいろいろと。ふごーふごー
 
 
 

Cover image is not found
amazon.co.jpで詳細情報を見る



 

Technorati Tags: , ,