0

Androidのギャラリーの「共有」メニューから呼び出せるアプリを作る

Androidのカメラで撮影した画像はギャラリーに保存される。そこで画像を選んで共有またはshareなどを選択すると、暗黙的Intent呼び出しで画像を別アプリに渡せる。
Flickrアップローダとか、EvernoteとかDropboxのアプリに写真を渡しているのはこのしくみを使っている。


まずManifest.xmlにintent-filterを追加する。
image/*でもいいが、それだと動画も渡せてしまうので手当たり次第mimeTypeを指定してみる。

<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="image/jpeg"/>
<data android:mimeType="image/jpg"/>
<data android:mimeType="image/png"/>
<data android:mimeType="image/bmp"/>
<data android:mimeType="image/bitmap"/>
</intent-filter>
ようするに、アプリに「私はimageをSENDするというアクションを受け取って適当に処理できますよ」と宣言させておくと、
他のアプリが「誰でもいいからSENDしたimageを受け取ってくれる人いませんか」と呼び出したときに連携できるようになる。


で、このintent-filterと関連付けられているクラス(普通なら一番最初に生成したjavaクラス)の
onCreate()内でintentを受け取る。
あらかじめ、受け取った画像を表示するためのImageViewを配置しておく。
private ImageView imageView;
this.imageView = (ImageView)this.findViewById(R.id.ImageView01);


暗黙的Intentで呼び出されたのか、普通のIntent呼び出しで起動したのか(つまりホーム画面からアプリのアイコンを押して起動したのか)を判別して処理する。
呼び出し元の名前だけで判別してる
Uri imageUri = null;
try{
imageUri = Uri.parse(getIntent().getExtras().get("android.intent.extra.STREAM").toString());
}
catch(Exception e){
e.printStackTrace();
}
if (imageUri != null) {
Log.v("ImageIntent", "暗黙的intentから起動");
Bitmap bmp = null;
try {
bmp = Media.getBitmap(getContentResolver(), imageUri);
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
if (bmp != null) {
this.imageView.setImageBitmap(bmp);
}
}
else{
Log.v("ImageIntent", "普通に起動");
}
imageUriにはcontent://media〜〜というパスが入る。これはAndroid内のファイルシステムのパスではないが、Media.getBitmapに渡すとデータを読み出せる。
とりあえずImageViewに表示だけしておく。


あとEclipseだと日本語が化けるのでterminalからadb logcatしてる。


Bitmapを受け取ったら、後は適当に処理すれば良い。
リサイズとか
public Bitmap resize(Bitmap bmp, float scale){
Matrix matrix = new Matrix();
matrix.postScale(scale, scale);
return Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), matrix, true);
}



form/multipart-dataでgyazo.comにアップロードするとか、色々できる。
Manifest.xmlにpermissionを追加
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
public void upload(Bitmap bmp) throws ParseException, IOException{
File dataDir = new File(Environment.getExternalStorageDirectory(), this.getPackageName());
dataDir.mkdirs();
FileOutputStream tmp = new FileOutputStream(new File(dataDir, "tmp.png"));
bmp.compress(Bitmap.CompressFormat.PNG, 80, tmp);
tmp.close();

HttpClient httpClient = new DefaultHttpClient();
HttpPost post = new HttpPost("http://gyazo.com/upload.cgi");
MultipartEntity entity = new MultipartEntity();

entity.addPart("id", new StringBody("your-gyazo-id"));
entity.addPart("imagedata", new FileBody(new File(dataDir, "tmp.png"), "image/png"));
post.setEntity(entity);
post.setHeader("User-Agent", "TestAndroidApp/0.1");

httpClient.execute(post);
}
httpでform/multipart-dataでアップロードするには
の2つが必要。


■参考
このへんが参考になった

0

mbedで取得したセンサーの値をsinatra+tokyocabinetで保存する

まずセンサーのデータを時系列で溜めたり、取り出したりするためのwebサービスをsinatra+TokyoCabinetで作っておいた。


そこにmbedのADコンバータでCdSの明るさを計測、LEDを点灯/消灯mbedにEthernetを接続しtwitterにpostするを合体させ、約10秒間隔でセンサーの値をhttp-postしまくった。

一度web APIが出ている場所にマイコンの情報も保存しておけば、あとでマッシュアップできて便利になる。このAPIの下にmbedでもgreasemonkeyスクリプトでも何個でもぶら下げられる。
mbedからwedataに保存しても良かったんだけど、あえて自分で作ってみた。



■mbedで明るさを計測してhttp-postする
作った回路。CdSで明るさを取得し、LEDで明るさを表示する。mbedのRD+,RD-,TD+,TD-ピンにトランス入りEthernetジャックを接続し、LANケーブルを刺した。
mbed ethernet


プログラム。CdSに入る光量が少なくなると緑色のLEDが光る。http-postはTickerで定期的に呼び出したかったが、Ticker内でHTTPClient.hの関数を使うとmainに戻ってこなくなるので仕方なくmain内で20ループ毎(約10秒毎)にHTTPClient.post()するようにした。stdは使えるけど、pthread等のスレッド機能は無いみたいなのでこれは痛い。
sensor_http_post | mbed
#include "mbed.h"
#include "HTTPClient.h"
#include <string>
using namespace std;

Serial pc(USBTX, USBRX);

DigitalOut led1(LED1); // blink
DigitalOut led2(LED2); // blink when http-post
DigitalOut led3(p11); // represent ADC value

AnalogIn adc(p15);
float ain;

HTTPClient http; // use DHCP

const string api_uri = "http://shokai.mag.keio.ac.jp/sensor-storage/shokai/cds/";
const string mbed_name = "shokai-mbed01";
const string sensor_name = "CdS";

void blink_led(DigitalOut led, int num){
    for(int i=0; i < num*2; i++){
        led = !led;
        wait(0.1);
    }
}

void post_sensor_value(){
    blink_led(led2, 2);
    char query[256] = "";
    char result[4096] = ""; // 4kb
    sprintf(query, "name=%s&%s=%f", mbed_name.c_str(), sensor_name.c_str(), (float)ain);
    pc.printf("post:%s => %s\n", query, api_uri.c_str());
    http.post(api_uri.c_str(), query, result, 4096);
    pc.printf("%s\n", result);
    blink_led(led2, 2);
}

int main(void){
    led1 = 1;
    int count = 0;
    while(1) {
        ain = adc;
        pc.printf("sensor:%f\n", float(ain));
        led1 = !led1; // blink LED
        if(ain > 0.1) led3 = 0; // represent CdS value
        else led3 = 1;
        if(count > 20){
            post_sensor_value();
            count = 0;
        }
        count++;
        wait(0.5);
    }
}
せっかくC++が使えて、mbed.hのAPIはC++っぽいのに、HTTPClient.hはそうでもないみたいだ。
mbedのローカルのストレージがfopenで読めるので、そこに設定ファイルを置けるようにしたい。yamlやjsonをparseするライブラリを作りたい。



動作はシリアル通信で見れる。表示にはserialterm.rbを使った。
postすると返り値がjsonで来る。
mbed http-post



■tokyocabinetとsinatraでデータを溜めるAPIを作る
できたもの
sensor-storage API


githubでソースを全部公開しておいた。
shokai's sensor-storage at master – GitHub


http://shokai.mag.keio.ac.jp/sensor-storage/ にhttp-postした内容を、json stringにエンコードして時刻_マイクロ秒をキーにしてTokyoCabinetに保存する。
keyの _ の左側が時刻になっているので後で使う時に便利。

http://shokai.mag.keio.ac.jp/sensor-storage/keys で保存されているkeyの一覧がJSON形式で見れる。
http://shokai.mag.keio.ac.jp/sensor-storage/recentで最近10件のkeyとvalueが取れる。他にもrecent/件数や、last(最後に入れたデータ)、count(データ件数)などのAPIがある。


今回のmbedでCdSの値を保存しているのは http://shokai.mag.keio.ac.jp/sensor-storage/shokai/cds/recent になる。shokai/cds/last , shokai/cds/recent , shokai/cds/count などで色々データが取り出せる。

/ 以下に適当に文字列を付けると新しくDBを作るようになっている。もしデータをpostしてみたいなら、mbedの方のコードは/shokai/cds/をハードコーディングしているので、そこを適当に変えてから使ってくれるとうれしい
あまりにも大きいデータは入らない。


スクリプト自体はわりとシンプル。sinatra使って1ファイルに書いてある。
server/main.rb at master from shokai's sensor-storage – GitHub
#!/usr/bin/env ruby
# -*- coding: utf-8 -*-
require 'rubygems'
require 'sinatra'
require 'sinatra/reloader' if development?
require 'rack'
require 'json'
require 'tokyocabinet'
include TokyoCabinet

@@dbdir = 'db'

def db_open(dbname='/')
  dbname = dbname.to_s.gsub(/\//, '_')
  @hdb = HDB.new
  Dir.mkdir(@@dbdir) if !File.exists?(@@dbdir)
  @hdb.open("#{@@dbdir}/_#{dbname}.tch", HDB::OWRITER|HDB::OCREAT)  
end

after do
  @hdb.close if @hdb
end

get '*/' do
  path = "../" * params[:splat].first.count('/')
  redirect "#{path}./readme"
end

get '*/keys' do
  db_open(params[:splat])
  @hdb.keys.reverse[0...10000].to_json
end

get '/dbs' do
  Dir::glob("#{@@dbdir}/*.tch").map{|i|
    name = i.to_s.scan(/.*\/(.+)\.tch/).first.to_s.gsub(/_/,'/')
    tmp = name.split(//u)
    tmp.shift
    tmp.to_s + "/"
  }.uniq.delete_if{|i|
    i =~ /\/\//
  }.sort.to_json
end

get '*/count' do
  db_open(params[:splat])
  {"count", @hdb.rnum}.to_json
end

get '*/last' do
  db_open(params[:splat])
  key = @hdb.keys.last
  {key, @hdb[key]}.to_json
end

get '*/recent' do
  db_open(params[:splat])
  @hdb.keys.reverse[0...10].map{|k| {k, @hdb[k]} }.to_json
end

get '*/recent/:num' do
  db_open(params[:splat])
  num = [params[:num].to_i, 1000].min
  @hdb.keys.reverse[0...num].map{|k| {k, @hdb[k]}}.to_json
end

get '*/:tc_key' do
  db_open(params[:splat])
  key = params[:tc_key]
  {key, @hdb[key]}.to_json
end

post '*/' do
  db_open(params[:splat])
  now = Time.now
  key = "#{now.to_i}_#{now.usec}"
  params.delete(:splat.to_s)
  @hdb.put(key, params.to_json)
  {key, @hdb[key]}.to_json
end

delete '*/:tc_key' do
key = params[:tc_key]
  v = @hdb[params[:tc_key]]
  @hdb.out(params[:tc_key])
  {key,v}.to_json
end


githubのmiscディレクトリ以下にテスト用にhttp postしたりするためのスクリプトがある。mbedが無い時の動作チェックにどうぞ。


サーバーはthinで10個preforkさせておいて、それぞれ別のportで起動させてある。apache2のmod_proxy_balancerでそこにproxyして、80番ポートのサブディレクトリ下にあるように見せている。



0

mbedにEthernetを接続しtwitterにpostする

@1VQ9の助力を得てmbedがethernetにつながった。1VQ9はパルストランスも通さず、分解したLANケーブルをmbedに直接差し込んで動かしてたけど、俺はmbed Ethernet Testingに従ってパルストランス入りのEthernet jackを使った。



ethernetにつないだところ
mbed + ethernet
mbedとethernet jackは
  • mbed p1 = Ethernet RD+
  • p2 = RD-
  • p7 = TD-
  • p8 = TD+
という風に接続した。こっちでは別のつなぎ方をしているが、この配置だと動かなかったのでjack毎に違うのかもしれない。よくわからない。


配線はこっちの方が見やすいかも
mbed + ethernet


裏のピン配置がブレッドボードに刺せるピッチ幅ではなかったので、秋月で100円で売ってる両面ガラススルーホール基盤の切れ端とピンヘッダを駆使してピン配置を変更した。
ethernet jack for breadboard
ethernet jack for breadboard


mbedにはHTTPClientというDNSやDHCPやHTTPを適当に解決してくれるモジュールがある。
ほぼmbed EMAC/HTTPClientのまま動いた。
HTTPClientを使うために、
http://mbed.org/projects/cookbook/svn/EMAC/lwip/trunk
をprojectにimportする必要があった。mbedのエディタのGUIからimportできた。

tweet_test | mbed
#include "mbed.h"
#include "HTTPClient.h"
using namespace std;

DigitalOut led(LED1);

HTTPClient http; // use DHCP

/* // use static IP
HTTPClient http("mbed", // hostname.
                IPv4(192,168,1,39), // IPv4 address
                IPv4(255,255,255,0), // netmask
                IPv4(192,168,1,1), // default gateway
                IPv4(192,168,1,1)); // dns server
/**/

const char msg[] = "status=mbed test";

int main(void) {
    http.auth("username", "password");
    http.post("http://twitter.com/statuses/update.xml", msg);
  
    while(1) {
        led = !led;
        wait(0.2);
    }
}
twitter APIにbasic認証を通ってhttp-postし、成功するとLED点滅のループに入る。

twitter APIは同じtweetを連続で受け取らないようになっているので、このプログラムだと一度tweetした後はmsgを別の文字列に変えないと再確認できない。後ろに乱数とか時刻とかをつける必要がある。

0

RailsにFlashからpostしたり取り出したりする

Railsのscaffoldでさくっと作ったインタフェースって、HTTP-POSTからSQLに保存したり取り出したりもできて色々プロトタイプを作るのに便利なのでまとめておく。

ためたデータの管理もできるし。

■Rails側の準備

まずrailsを入れる。

Macの人は既に入っているはず。Windowsなら、ActiveScriptRubyを入れてパス通すと、gemコマンドが入るのでgem install railsすればrailsコマンドが使えるようになる。DBはSQLiteのdll版をc:\windows\system32に入れればできる様になるはず。

railsでtestbbsというプロジェクトを作って、そこにscaffoldでentry(投稿)というmodelを作る。entryには、name(投稿者)とmessage(本文)が入る。

rails testbbs

cd testbbs

ruby script/generate scaffold entry name:string message:text

rake db:migrate

(単数形に注意)

webサーバーを立ち上げる

ruby script/server

http://localhost:3000/entriesから見れるようになっている。はず。(複数形に注意)

こんなページができている。ここからentryを増やしたり消したりもできる。

post from flash to rails

ここまでで、http://localhost:3000/entries/newから投稿できるのと、http://localhost:3000/entries.xmlから一覧を取得できるようになった。

Source Code (Ruby on Rails 2.0.2)

■Flashから投稿する

HTTP POSTで行う。

今回作ったもの(動きます)

Source Code (AS3 / Flash CS3 + Flashdevelop)

今回もFlashDevelop上でAS3書いて、FlashCS3オーサリング/コンパイルした。

こいつでPOSTすると、http://localhost:3000/entriesに結果が出るようになる。

post from flash to rails

どうやってるかというとまず

http://localhost:3000/entries/newを見ると



Name




Message






という風にPOSTしているので、entry[name]とentry[message]をパラメータで渡せばいいとわかる。

Read more