Yolp Android SDKを使ってみる

最近Android SDKを触っています。

http://developer.yahoo.co.jp/webapi/map/openlocalplatform/v1/androidsdk/

こちらのYOLP Android Map SDKでサンプル。

手順は簡単。
http://developer.yahoo.co.jp/webapi/map/openlocalplatform/v1/androidsdk/tutorial1.html



ここに沿って作成。
とりあえずorg.codehaus.jacksonだけでなく、ダウンロードした、ymap.jarも
Androidプロジェクト直下のassetsフォルダーに配置し、
Build Pathに追加。


webのgoogle placeみたいなmapとlistが表示される画面を作る。
地図をロングタップすれば、その地点周辺のドトールコーヒーを検索し、ピンをプロット。listにも店名を表示。
といったアプリを作ります。


layout.xmlは以下。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:id="@+id/mainLayout"
    android:orientation="vertical" >
       
       <FrameLayout 
           android:id="@+id/mapContainer"
           android:layout_width="match_parent"
           android:layout_height="0px"
           android:layout_weight="7" />
       
       <ListView
           android:id="@+id/listView"
           android:layout_width="match_parent"
           android:layout_height="0px"
           android:layout_weight="3"
            />

</LinearLayout>

FrameLayoutの子供に、ソース内からMapViewを割り当てる。



MapView生成

        mapView = new MapView(this,getResources().getString(R.string.yolp_appid));
        mapView.setBuiltInZoomControls(true);
        mapView.setLongPress(true);
        MapController c = mapView.getMapController();
        c.setCenter(new GeoPoint(35665721, 139731006)); //初期表示の地図を指定
        c.setZoom(3); 				  //初期表示の縮尺を指定
        
        FrameLayout mainLayout = (FrameLayout)findViewById(R.id.mapContainer);
       mainLayout.addView(mapView);

これだけでmapが表示される。



mapにタッチイベント割り当て。

mapView.setMapTouchListener(new MapTouchListener() {
			
			@Override
			public boolean onLongPress(MapView arg0, Object arg1, PinOverlay arg2,
					GeoPoint arg3) {
				// TODO Auto-generated method stub
				
				ArrayList<Overlay> overlays = (ArrayList<Overlay>) arg0.getOverlays();
				overlays.clear();
				arg2.clearPoint();
				PinOverlay pinOverlay = new PinOverlay(PinOverlay.PIN_VIOLET);
				  mapView.getOverlays().add(pinOverlay);
				  pinOverlay.addPoint(arg3,null);
				

				StringBuilder url = new StringBuilder("http://search.olp.yahooapis.jp/OpenLocalPlatform/V1/localSearch?output=json");
				url.append("&appid=");
				url.append(getResources().getString(R.string.yolp_appid));
				url.append("&cid=6e6c4795b23a5e45540addb5ff6f0d00");
				url.append("&dist=1&sort=dist");
				url.append("&lat=");
				url.append(""+(float)(arg3.getLatitudeE6()/1000000.f));
				url.append("&lon=");
				url.append(""+(float)(arg3.getLongitudeE6()/1000000.f));
				
				HttpAsyncTask httpClient = new HttpAsyncTask();
				httpClient.execute(url.toString());
				
				return false;
			}
		});

onLongPressイベントの中でyolp APIにアクセス。
緯度経度を割るのを忘れずに。



返ってきた値を

mapView.getOverlays().add(new YDFOverlay(result));

これだけで地図にピンが描画され、クリックすると店名が表示される。



AsyncTaskを使っているのでソースが前後していますが、
主な流れとしては上記の感じ。



すべてのソースはこちら
https://github.com/tegut/Android_YolpMapSample/blob/master/src/info/tteguri/yolpmapsample/YolpMapSampleActivity.java



これで喫煙者がタバコ吸いたくなって、ドトールなら吸えるだろう。サクっとアプリでドトール検索するかができちゃう。



感想
apiの結果パースせなアカンかーとかって思ったけど、そこはydfフォーマット。
サクっとAPIのレスポンスを食ってくれます。
楽チン。


チュートリアルではsetContentViewにmapViewをそのまま渡してるけど、地図以外も設置したいので、いつもどおりsetContentViewにはlayout.xmlを渡しました。


layoutは出来る限り、ソースの中には記述したくない派です。
しかしMapViewの第二引数がAttributeSetではなく、String appIdなので
MapViewを継承したカスタムビュー作成を試みたが、
MapViewがコンストラクタの第一引数にContent型ではなく、
Activity型になっており、うまくいかなかった。


欲を言えば、第一引数がContentで、
第二引数がAttributeSetのコンストラクタが用意されており、
appIdはattributeで渡すって感じになっていれば、layout.xmlに記述できたり、
カスタムビューが作成できたり、
ソース内でインスタンス生成しなくても済むので、今後そう改善されることを期待。



まだまださわりの機能しかつかっておらず、ルート検索や、目玉のARナビとか、いろんな機能が満載なSDK
やはり日本語ドキュメントという点もわかりやすいですしね。



参考文献
ListView
http://www.adakoda.com/android/000077.html

HttpClient
http://techbooster.org/android/application/1801/
http://d.hatena.ne.jp/terurou/20110702/1309541200

AsyncTask(非同期リクエスト)
http://android.keicode.com/basics/async-asynctask.php

プログラミングAndroid

プログラミングAndroid

ios5 safariでhtml5のinput type numberの仕様変更

iphone3GSやiphone4でosアップデートしたユーザや
iphone4Sならデフォルトでios5だと思うのですが、
スマフォサイト開発者にとっては少々厄介なことが。

というのも
html5によってinput typeの属性がemailやnumberが増えて
スマフォだとソフトウェアキーボードがそのtypeに応じて
変更されて便利なんですが、
input type="number"だと
0052などの
0始まりの数字は0が消されて52になるようです。

テストした限りではios5で仕様変更されたようです。

まあnumberなんだから当たり前かという気もしますが
その仕様変更知らねえよっていうね。

そして大概問題なさそうですが、郵便番号が問題。

フォームが
3桁 - 4桁
って形になってたら
下4桁がアウトになってしまう。

"107" - "0052"
ってフォームに入力すると

"107" - "52"
とサーバに飛んでくる。

バリデートでもアウトでしょうし、
郵便番号の存在チェックなんてかけてたら
存在しない郵便番号ですと。。。

気づかないとios5ユーザはformのpostができない状態に。

心当たりのある方は
お気をつけ下さい。

perl利用してマルチスレッドしながらポート監視

意味があるかは別にして実験。

スレッドにして
メインの処理をさせながら
サブでポートを監視し
特定のメッセージの場合、応答する。

ファイヤーウォール内の想定なので
ポートをたたくのに認証等は考えない。

perlは5.12.3

参考にさせていただいたサイトは以下。
echo サーバを作ってみよう (2)
ソケットによる通信を行う - Perl入門ゼミ
Perlでマルチスレッド

あんまりperlわかってないですし
すごく即興なので
多々いけてないところあるかもしれませんが、ご容赦を。

use strict;
use warnings;

use Socket;
use threads;
use Thread::Queue;

$| = 1;
my $queue = new Thread::Queue;
my $mainTask = threads->new(\&echoA);
my $subTask = threads->new(\&listenPorter);

$mainTask->join; 
$subTask->join; 

print "\n";
print "done.\n";

sub echoA {
    while(1) {
        print "A\n";
        sleep(2);
    }
}
sub listenPorter {

    socket(CLIENT_WAITING, PF_INET, SOCK_STREAM, 0)
        or die "Cannot create socket: $!";

    setsockopt(CLIENT_WAITING, SOL_SOCKET, SO_REUSEADDR, 1)
        or die "Cannot set socket: $!";

    my $local_port = 9000;

    my $pack_addr = sockaddr_in( $local_port, INADDR_ANY );

    bind( CLIENT_WAITING, $pack_addr )
        or die "Cannot bind: $!";

    listen( CLIENT_WAITING, SOMAXCONN )
        or die "Cannot listen: $!";


    while( accept( CLIENT, CLIENT_WAITING ) ){
        select(CLIENT); $|=1; select(STDOUT);
        my $content;

        while( my $line = <CLIENT> ){
            chomp($line);
            if ( $line =~ /ruok/ ) {
                print CLIENT 'imok' . "\n";
            }
        }

        close(CLIENT);
    }
}


プログラムを実行させながら、telnetで9000ポートにメッセージおくるとかえってくる。

ffmpeg一括エンコードのバッチ作成

ffmpeg
がさっとエンコードしてしまいたい。

find . -name '*.m4a' -type f > filelist.log

一旦ファイルリストを作成。


そして

#!/bin/sh

while read -r FILE
do
    OUTPUT=`echo $FILE | perl -pe 's/m4a$/mp3/'`

    ffmpeg -y -i "$FILE" -ab 160 "$OUTPUT" 

done < filelist.log

これでいけるかと思いきや、先頭のファイルしか変換されない。
やたらdebug=512って感じの出力がされ、終わる。
おかしい。ファイル名がマルチバイト文字列だしスペースあるし、そういうのが原因なのか。。。


サクっと終わるかと思ってたら、結局これで半日潰れました。
なんでうまくいかないのかはわかりません。


もう手でやったらいいやんっていう。


なんか他の言語でシステム関数たたいてなんとかしてしまおうと。
phpでやろうかと思いましたが、open_basedirとか、もうって思って、

#!/usr/bin/php -d 'open_basedir=/Users'

かなと思いましたが、
勉強もかねて、pythonでやってみました。
カッコとか行末のセミコロンとか書かなくてもインデントでスコープが決まるのはやっぱり楽ちんですね。

#!/usr/bin/env python
import re
import commands

for file in open('filelist.log','r'):
    output = re.sub(r'\.m4a$','.mp3',file)
    c = 'ffmpeg -y -i "'+ file.strip()+'" -ab 160 ' +' "' + output.strip() + '"'
    result = commands.getoutput(c)
    print result 


これでうまくいきました。
もうさっきまでの時間はなんだったんだろうかと。

ffmpeg使ってみました

AACをMP3に変換しようと
itunesでやるのもいいけど
いったんライブラリに複数フォーマットできて
うにゃむにゃ・・・というのはめんどくさいからいっそコマンドラインやりたい。

そこでFFmpeg

環境はmac上で。
落としてきてコンパイル

The Yasm Modular Assembler Project
yasmがないのでこれもコンパイル

再度ffmpegコンパイル

http://www.ecoop.net/memo/2007-07-19-1.html
このサイトに記述されてるコマンドを参考に

ffmpeg -i $INPUT -ab 160 $OUTPUT

実行したが0kbのファイルしか生成されない。

LAME MP3 Encoder
lameがない。。。

lameコンパイル、インストール。

ffmpegのconfigureやり直し。

./configure --enable-libmp3lame

ffmpegコンパイル、インストール。

無事aacをmp3に変換できました。

apacheのmod_envとmod_rewriteの環境変数の扱い

apache 1.3系で、

SetEnv FOO BAR

RewriteRule .* - [E=FOO:BAR]

は等価のように見える。

たしかにphp内でアクセスする分には変わらないです。

しかし
以下のようにすると

SetEnv FOO BAR

RewriteRule /path/to   /index.php?module=path&action=to&env=%{ENV:FOO}
RewriteRule .* - [E=FOO:BAR]

RewriteRule /path/to   /index.php?module=path&action=to&env=%{ENV:FOO}

前者はenvは空で、後者にはちゃんとenv=BARとなる。

という不思議。

おそらくmod_envとmod_rewriteモジュールの読み込まれる順番が違うから?という推測。
apacheに精通されてる方なら周知の事実かもしれません。

そして、上記のような設定例はあり得ないとは思いますが、いいサンプルが思いつかず、
でも、こんな現象がおこったので書き留めておきます。

webサイトからiphone twitter公式アプリで投稿

iphone用webサイトを構築してると
最近はtwitterへの投稿リンクも要件として入ってくることがあります。

それは

http://twitter.com/home/?status=hogehoge

な感じでリンクを投稿リンクを作成できるのはご存知かと思います。

でも普段iphoneではなんらかの
twitterクライアントアプリを使って投稿している方が大半なのに、
このときだけiphone safariからっていう。

やっぱり、twitterアプリから投稿させれるようにできないの?
っていう要望がでてくるかと思います。

今までいやそれはできないですねなんてお断りしていたんですが、
まあiphoneのお持ちの方で、とりあえずtwitterをってなったときに
twitter公式アプリをいれてない人は少ないでしょう。

twitter公式アプリはtweetieって特殊リンクで開けるようなので(公式ブックマークレットより)

javascript:window.location='tweetie:'+window.location

じゃこれにさ、タイトルとかいれれるようにしたら
twitter公式アプリ入れてる人はアプリのほうで投稿できるやんっておもって調べてみたら
書いてくださってる人いました。

試してみました。
結果macのtweetie(twitter公式アプリの前の名前)なら上記のサイトの内容はいけました。

しかしiphoneではどうやっても無理な様子。
結局URL以外はいれれない。

投稿画面にならないパターン

javascript:window.location='tweetie:'+document.title+window.location
javascript:window.location='tweetie:'+document.title+' '+window.location
javascript:window.location='tweetie:'+document.title+'%20'+window.location
javascript:window.location='tweetie:'+'aaaaa'

httpが先頭にないとだめっぽい。

投稿画面になるがこれじゃつかえないパターン

javascript:window.location='tweetie:'+window.location+' '+document.title
javascript:window.location='tweetie:'+window.location+'%20'+document.title

エンコードされます。
デコードして渡してもデコードされているのでwindow.location変数に入ったときにエンコードされているのでしょう。


ということでサイトのURLだけって仕様ならいけますよってことになるのかな。