2011年12月9日金曜日

PhoneGap入門

PhoneGapとは

  • HTMLとJavaScriptだけでAndroidアプリを作成できるフレームワーク。
  • カメラなどのデバイスのAPIを使用できる。
  • HTML5、JQueryMobileを組み合わせるといろいろできそう。


  1. まずはEclipseでAndroidProjectの作成
  2. PhoneGapフレームワークの設定
    公式ページからダウンロードして配置する。

  3. Activityの修正
    import android.os.Bundle;
    import com.phonegap.*;
    public class TestPhoneGapActivity extends DroidGap {
        /** Called when the activity is first created. */
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            super.loadUrl("file:///android_asset/www/index.html");
        }
    }
  4. AndroidManifestの修正
    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.utsugen"
        android:versionCode="1"
        android:versionName="1.0" >
        
        <supports-screens
    android:largeScreens="true"

    android:normalScreens="true"android:smallScreens="true"android:resizeable="true"android:anyDensity="true"/>

    <uses-permission android:name="android.permission.CAMERA" /><uses-permission android:name="android.permission.VIBRATE" /><uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /><uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /><uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" /><uses-permission android:name="android.permission.READ_PHONE_STATE" /><uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.RECEIVE_SMS" /><uses-permission android:name="android.permission.RECORD_AUDIO" /><uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /><uses-permission android:name="android.permission.READ_CONTACTS" /><uses-permission android:name="android.permission.WRITE_CONTACTS" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />


        <uses-sdk android:minSdkVersion="10" />

        <application
            android:icon="@drawable/ic_launcher"
            android:label="@string/app_name" >
            <activity
                android:label="@string/app_name"
                android:name=".TestPhoneGapActivity"
                android:configChanges="orientation|keyboardHidden" >
                <intent-filter >
                    <action android:name="android.intent.action.MAIN" />

                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>

    </manifest>



  5. レイアウトの作成
    assets/www/index.htmlを作成
    <!DOCTYPE HTML>

    <html>
    <head>
    <title>TestPhoneGap</title>
    <script type="text/javascript" charset="utf-8" src="phonegap-1.2.0.js"></script>
    <script type="text/javascript" charset="utf-8">
    <!--
    document.addEventListener("deviceready", onDeviceReady, false);
    function onDeviceReady() {
    document.getElementById('myDevice').innerHTML = "PhoneGap on " + device.platform;
    document.getElementById('ready').innerHTML =
    "<ul><li>device name : " + device.name + "</li>" +
    "<li>devie version : " + device.version + "</li></ul>";
    }
    -->
    </script>

    </head>

    <body>
    <h1>Hello world!</h1>
    <h2 id="myDevice"></h2>
    <p id="ready">デバイス情報取得中...</p>

    </body>
    </html>

完成!




2011年12月4日日曜日

Ajax入門

Ajaxの初歩的なまとめ。



  1. XMLHttpRequest
    ・JavaScriptのオブジェクト。
     ページ遷移なしでHTTPリクエストを送る事が出来る。
     Ajaxの根幹となる部分。
    ドメインが違うサイトのデータは取得できない。
     このためPHPやJavaなどのサーバサイドのプログラムを
     間にかます必要がある。
    <script type="text/javascript">
    httpRequest = false;
    if(window.XMLHttpRequest) {
        // Firefox, Opera など
        httpRequest = new XMLHttpRequest();
        httpRequest.overrideMimeType('text/xml');
    } else if(window.ActiveXObject) {
        // IE
        try {
            httpRequest = new ActiveXObject('Msxml2.XMLHTTP');
        } catch (e) {
            httpRequest = new ActiveXObject('Microsoft.XMLHTTP');
        }
    }
    function request() {
        httpRequest.abort();
        httpRequest.open('GET', 'url', true);
        httpRequest.onreadystatechange = function() { // コールバック関数
            if(httpRequest.readyState == 4) {
                if(httpRequest.status == 200) {
                    // 処理
                }
            }
        }
        httpRequest.send(null);
    }
    </script>
  2. XAMPP
    ・MySQLやPHPを含んだApacheディストリビューション。
     簡単インストールですぐに使える。
     開発用のローカル環境にとても便利。
     本番用にもセキュリティの設定を変えれば使えるそう。
    ・MAC OS X版に含まれるソフト
     Apache, MySQL, PHP & PEAR, SQLite, Perl, ProFTPD, phpMyAdmin, OpenSSL,
     GD, Freetype2, libjpeg, libpng, zlib, Ming, Webalizer, mod_perl.

  3. Prototype.js
    ・多彩なJavaScriptライブラリ。
     ブラウザの差異も吸収してくれる。
    new Ajax.Request( 'url', {method:'get',
                  onSuccess:getData,    // 成功時コールバック関数
                  onFailure:showErrMsg, // エラー時コールバック関数
                  parameters:''} );
    
    function getData(data) {
         var rdf ="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
         var response;
         if(document.all){
              response = data.responseXML.getElementsByTagName('rdf:RDF');
         }else{
              response = data.responseXML.getElementsByTagNameNS(rdf,'RDF');
         }
         var item = response[0].getElementsByTagName('item');
         for(i = 0; i < item.length; i++){
              // 処理
         }
    }
    function showErrMsg() {
         // エラー処理
    }
    
  4. DOM (Document Object Model)
    ・HTMLやXMLを操作する為のAPI。
    // selectボックスの作成
    var selectDOM = document.createElement('select');
    selectDOM.setAttribute( 'id', 'data_select' );
    
    var optionDOM = document.createElement('option');
    optionDOM.setAttribute( 'value', '0' );
    optionDOM.appendChild( document.createTextNode( '選択してください' ) );
    selectDOM.appendChild( optionDOM );
    
    result.appendChild( selectDOM );

2011年12月2日金曜日

ADKアプリの作成 ースケッチー


 AndroidAccessory acc("Utsugen",
                                     "TestADK",
                                     "TestADK by Utsugen",
                                     "1.0",
                                     "http://utsugen.blogspot.com/",
                                     "0000000012345678");

void setup() { pinMode( LED, OUTPUT ); acc.powerOn(); }


Arduinoを接続したときに立ち上げるAndroidアプリを指定する。


void loop() { if (acc.isConnected()) { // INPUT from Android int len = acc.read(msg, sizeof(msg), 1); if( len == 3 ){ if( msg[0] == 0x2 ){ if( msg[1] == 0x0 ){ analogWrite( LED, msg[2] ); } } } // OUTPUT to Android data = analogRead( IR ); msg[0] = 0x1; msg[1] = ((int)voltage2distance( (double)data / 1024.0 * 5.0 )) & 0xf; msg[2] = 0xff; acc.write(msg, 3); } delay(100); }


①Androidからの入力を受け取る。
3byteが種別/対象/値で並んでいる。
Android側と示し合わせておく。
②voltage2distance関数は、赤外線測距モジュールGP2Y0A21YKからの
 電圧を距離に変換している。この方が作成された。
③Androidに値を渡す。

2011年11月20日日曜日

ADKアプリの作成 ーActivityー

今回のアプリは勉強の為に
ActivityはTestADKActivityクラス1つだけで作る事にする。

ADKのDemoKitの実装箇所を参考にする。

onCreate()
public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
     mUsbManager = UsbManager.getInstance(this);
     mPermissionIntent = PendingIntent.getBroadcast(this0,  new Intent(ACTION_USB_PERMISSION),  0);
        IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
        filter.addAction(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
      registerReceiver(mUsbReceiver, filter);
    if(getLastNonConfigurationInstance() != null){
        mAccessory = (UsbAccessory)getLastNonConfigurationInstance();
        openAccessory(mAccessory);
        }
    setContentView(R.layout.main);
        mSlider = (Slider)findViewById(R.id.LedSlider);
        mSlider.setPositionListener(this);
        mLed = (TextView)findViewById(R.id.Led);
        mLed.setOnClickListener(this);
        mLed.setText("0");
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
①UsbManagerの生成
②USB Accessory通信のパーミッションを取得するための
BroadcastReceiverを登録する。
BroadcastReceiver:PendingIntentを登録しておくとこでイベント発生時に呼び出す事が出来る。
③UsbAccessoryがキャッシュに無ければ通信を確立する。
キャッシュ登録:onRetainNonConfigurationInstance
  キャッシュ取得:getLastNonConfigurationInstance
④USB AccessoryとのIOストリームを生成する自作関数。
⑤レイアウトとのひもづけ
SliderレイアウトはDemokitの自作View。
⑥ADKはスリープ状態になると切断されてしまうのでスリープ防止。

onResume()
 protected void onResume() { super.onResume(); Intent intent = getIntent(); if (mInputStream != null && mOutputStream != null) { return; } UsbAccessory[] accessories = mUsbManager.getAccessoryList(); UsbAccessory accessory = (accessories == null ? null : accessories[0]); if (accessory != null) { if (mUsbManager.hasPermission(accessory)) { openAccessory(accessory); } else { synchronized (mUsbReceiver) { if (!mPermissionRequestPending) { mUsbManager.requestPermission(accessory, mPermissionIntent) mPermissionRequestPending = true; } } } } else { Log.d(TAG, "mAccessory is null"); setContentView(R.layout.no_device); } }
①通信確立済みなら何もしない。
②UsbManagerオブジェクトからUsbAccessoryのリストを取得する。
リストの先頭を決め打ち使用(将来の拡張用らしい)
③通信許可を取得済みならIOストリームの生成。
④BroadcastReceiverに同期してユーザに通信許可の問い合わせ。
⑤USBAccessory未接続の場合のView表示。

BroadcastReceiver
 private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (ACTION_USB_PERMISSION.equals(action)) {
synchronized (this) {
UsbAccessory accessory = UsbManager.getAccessory(intent);
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
openAccessory(accessory);
} else {
Log.d(TAG, "permission denied for accessory " + accessory);
}
mPermissionRequestPending = false;
}
} else if (UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action)) {
UsbAccessory accessory = UsbManager.getAccessory(intent);
if (accessory != null && accessory.equals(mAccessory)) {
closeAccessory();
}
} }
};


①onCreate()で指定したBroadcastReceiver
②受け取ったイベントがUSB通信許可だった。
③受け取ったイベントがUSBAccessory切断だった。
openAccessory()
private void openAccessory(UsbAccessory accessory){
mFileDescriptor = mUsbManager.openAccessory(accessory);
if (mFileDescriptor != null) {
mAccessory = accessory;

FileDescriptor fd = mFileDescriptor.getFileDescriptor();
mInputStream = new FileInputStream(fd);
mOutputStream = new FileOutputStream(fd);

Thread thread = new Thread(null, this, "TestADK");
thread.start();

Log.d(TAG, "accessory opened");
} else {
Log.d(TAG, "accessory open fail");
}
}

①IOストリームの生成
②入力受付用のスレッド生成


run()
public void run() {
    int ret = 0;
    byte[] buffer = new byte[16384];
    int i;

    while (ret >= 0) {
        try {
          ret = mInputStream.read(buffer);
        } catch (IOException e) {
            break;
        }

        i = 0;
        while (i < ret) {
            int len = ret - i;

            switch (buffer[i]) {
         case 0x1:
                if (len >= 3) {
                 Message m = Message.obtain(mHandler, MESSAGE_DISTANCE);
                    m.obj = new DistanceMsg(buffer[i + 1]);
                    mHandler.sendMessage(m);
                }
                i += 3;
                break;

            default:
                Log.d(TAG, "unknown msg: " + buffer[i]);
                i = len;
                break;
            }
        }
    }
}
①Arduinoからの入力を受け取る
②1byte目が入力種別(ここでは赤外線測距のcm)
これはArduinoと示し合わせておく
③MessageクラスはHandlerへ値を渡す為の器。
Handler:UIスレッドはシングルスレッドであるため、
この入力信号待ちスレッド等の別スレッドからアクセスすると
例外が発生する。
Handlerを使うとUIスレッドが実行するキューに登録できる。


Handler
Handler mHandler = new Handler() {
    @Override
 public void handleMessage(Message msg) {
        switch (msg.what) {
        case MESSAGE_DISTANCE:
         DistanceMsg o = (DistanceMsg) msg.obj;
            mDistance.setText(String.valueOf(o.getDistance()) + "cm");
            break;
        }
    }
};
①HandlerのsendMessageを受け取る。
②Messageクラスから値を取り出してViewに反映。


onPause()
通信切断

onDestroy()
BroadcastReceiverを登録削除

onPositionChange()
public void onPositionChange(double value) {
int v = (int) (255 * value);
mLed.setText(String.valueOf(v));
sendCommand(LED_SERVO_COMMAND, (byte)LED_RED, (byte) v);
}
①onCreate()で登録したスライダViewのリスナー
②出力用自作関数

sendCommand()
public void sendCommand(byte command, byte target, int value) {
  byte[] buffer = new byte[3];
if (value > 255)
value = 255;
buffer[0] = command;
buffer[1] = target;
buffer[2] = (byte) value;
if (mOutputStream != null && buffer[1] != -1) {
try {
mOutputStream.write(buffer);
} catch (IOException e) {
Log.e(TAG, "write failed", e);
}
}
}
①3byteで「コマンド/対象/値」を表している。
Arduino側の処理と示し合わせておく。