Hatena::ブログ(Diary)

natu_nの日記 このページをアンテナに追加 RSSフィード

2009-08-22

[][][][]Java初心者が携帯百景投稿用クライアントを作る その3

とりあえずコマンド行編集と投稿用アドレスの自動設定の機能のみの実装版ですがAndroid Marketに登録しましたので携帯百景のアカウントをお持ちの方は試してみてはいかがでしょうか。

http://image.movapic.com/pic/m_200908220857234a8f346371740.jpeg

こんな感じで表示されるはずですが、後ろの方に流されているかもしれませんね

http://jp.androlib.com/android.application.com-natu-android-movapichelper-qzxx.aspxにアクセスしてQRコードで直接、マーケットを開いてしまうのが早いかもしれません。

    • コンタクトリストを見に行くのでインストールの時に注意が表示されます
  • 無事インストールが終わったら投稿用アドレスを自分のAndroid携帯に登録しましょう
    • 一旦PCのgmailから携帯百景から投稿した後、Android携帯の連絡先を同期させてAndroid携帯に投稿用アドレスを登録します
  • 次からは通常の投稿パターン

カメラアプリギャラリーから投稿したい画像を選んで共有をクリック

f:id:natu_n:20090816212944p:image

f:id:natu_n:20090816212947p:image

  • アプリが起動しますのでドロップダウンリストやチェックボックスで文字の色や表示位置を調整します

f:id:natu_n:20090816212943p:image:leftf:id:natu_n:20090816212942p:image

  • 設定したら「送る」ボタンでメーラーを起動します

f:id:natu_n:20090816212945p:image

  • 本文を入力したら投稿しましょう
    • ね、(ちまちま手入力するよりは)簡単でしょ。

追記(重要)

「送る」を押した後、メーラーの一覧が表示されますので使いたいメーラーを選んでください

2009-08-16

[][][][]Java初心者が携帯百景投稿用クライアントを作る その2

前回の多量のボタンのアクションの記述を簡単にしたい・・・のある程度の対応が出来たのでメモ

  • strings.xmlにボタンに貼付ける文字列を記述
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="hello">Hello World, mainActivity!</string>
    <string name="app_name">testEdit</string>
    <string-array name="array01">
    	<item>[[</item>
    	<item></item>
    	<item></item>
    	<item></item>
    	<item></item>
    	<item></item>
    	<item></item>
    	<item></item>
    	<item></item>
    	<item></item>
    	<item></item>
    	<item>]]</item>
</string-array>
</resources>
<?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">
	<EditText android:text="EditText01" android:id="@+id/EditText01"
		android:layout_width="fill_parent" android:layout_height="wrap_content"></EditText>
	<LinearLayout android:id="@+id/LinearLayout01"
		android:layout_width="fill_parent" android:layout_height="wrap_content">
		<Button android:text="Button02" android:id="@+id/B0"
			android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
		<Button android:text="Button03" android:id="@+id/B1"
			android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
		<Button android:text="Button04" android:id="@+id/B2"
			android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
		<Button android:text="Button05" android:id="@+id/B3"
			android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
		<Button android:text="Button06" android:id="@+id/B4"
			android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
		<Button android:text="Button07" android:id="@+id/B5"
			android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
		<Button android:text="Button08" android:id="@+id/B6"
			android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
		<Button android:text="Button09" android:id="@+id/B7"
			android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
		<Button android:text="Button10" android:id="@+id/B8"
			android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
	</LinearLayout>
	<LinearLayout android:id="@+id/LinearLayout02"
		android:layout_width="fill_parent" android:layout_height="wrap_content">
		<Button android:text="Button11" android:id="@+id/B9"
			android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
		<Button android:text="Button12" android:id="@+id/B10"
			android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
		<Button android:text="Button13" android:id="@+id/B11"
			android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
	</LinearLayout>
</LinearLayout>
  • メインとなるmainActivity.java
package com.natu.testedit;

import java.util.ArrayList;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

public class mainActivity extends Activity {
	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		// コマンドボタン創成
		int len = getResources().getStringArray(R.array.array01).length;
		ArrayList<Button> btns = new ArrayList<Button>();
		for (int i = 0; i < len; i++) {
			int wId = getResources().getIdentifier("B" + String.valueOf(i),
					"id", "com.natu.testedit");
			final Button btn = (Button) findViewById(wId);
			btn.setText(getResources().getStringArray(R.array.array01)[i]);
			btn.setOnClickListener(new View.OnClickListener() {

				public void onClick(View view) {
					EditText txt = (EditText) findViewById(R.id.EditText01);
					int loc = txt.getSelectionStart();
					String ttxt = txt.getText().toString();
					// カーソル位置にボタンの文字を挿入
					String prefix = ttxt.substring(0, loc);
					String suffix = loc < ttxt.length() ? ttxt.substring(loc,
							ttxt.length()) : "";
					txt.setText(prefix + btn.getText() + suffix);
					txt.setSelection(loc + btn.getText().length());
				}
			});
			btns.add(btn);
		}
	}
}

今回の肝はgetIdentifierというメソッド、これを使うことにより指定した条件でコンポーネントを検索してIdを返してくれる

つまり変数でIdを指定できるということ

public int getIdentifier (String name, String defType, String defPackage)

Return a resource identifier for the given resource name. A fully qualified resource name is of the form "package:type/entry". The first two components (package and type) are optional if defType and defPackage, respectively, are specified here.

Note: use of this function is discouraged. It is much more efficient to retrieve resources by identifier than by name.

Parameters

name The name of the desired resource.

defType Optional default resource type to find, if "type/" is not included in the name. Can be null to require an explicit type.

defPackage Optional default package to find, if "package:" is not included in the name. Can be null to require an explicit package.

Returns

* int The associated resource identifier. Returns 0 if no such resource was found. (0 is not a valid resource ID.)

で、このような画面が出来上がる

f:id:natu_n:20090816212946p:image

あとは絵文字の対応が済めばいよいよリリースだが、情報が一画面に納まらないため機能毎にタブで分けたり絵文字ボタンの見せかたをどうするか等の問題が山積みである

今まで出来ているところ

f:id:natu_n:20090816212944p:image:leftf:id:natu_n:20090816212947p:image

  • ローカルのコンタクトリストから投稿用アドレスの取得、文字位置等のコマンドをドロップダウンリストで指定

f:id:natu_n:20090816212943p:image:leftf:id:natu_n:20090816212942p:image

  • 送るボタン押下でメーラアプリが起動

f:id:natu_n:20090816212945p:image

という部分は完成済みでDeveloper Registration Feeも支払い済みだったりはしているので近いうちβ版として登録しても良いかもしれない

*1:本当はこれも省きたい

2009-08-14

[][][][]Java初心者が携帯百景投稿用クライアントを作る その1

HT-03Aで撮影した写真を携帯百景に投稿する時に文字の表示位置や色をソフトキーボードで入力するのも大変だなと思い、Javaの勉強を兼ねて入力ヘルパーを作ってみる実験

やりたいこと

    1. カメラアプリギャラリーの共有メニューに入力ヘルパーアプリを追加する
    2. ヘルパーアプリではコンタクトリストから投稿用メールアドレスを取得、文字色や文字位置、サイズをドロップダウンリストから選択出来るようにする
    3. 投稿ボタンをクリックで予め送信先アドレス、タイトル(表示コマンド)がセットされた状態でメーラーアプリを起動する
    4. メールを送信後にカメラアプリまたはギャラリーへ戻る

Androidの場合ゴリゴリとすべて作り込まなくてもIntentという仕組みを使って、こういうデータでこういうことがしたいと投げることによりその処理が可能なアプリがある場合にそのアプリが出来ますよと手を挙げてくれる仕組み(かなりの意訳ですが)があるので、今回は画像データを受けてメーラーに投げるところまでが範囲

    • カメラアプリやギャラリーの共有メニューに入力ヘルパーアプリを追加する

AndroidManifest.xmlにintent-filterを追加

<intent-filter>
    <action android:name="android.intent.action.MAIN"/>
    <action android:name="android.intent.action.SEND"/> 
    <category android:name="android.intent.category.DEFAULT"/> 
    <data android:mimeType="image/jpeg"/> 
</intent-filter>

jpegデータが投げられたら受けます(起動)

はまったところ

  • メールアドレスを指定してもメーラーのto欄に設定されない
Intent it = new Intent(Intent.ACTION_SEND);
it.putExtra(Intent.EXTRA_EMAIL, "foo@bar.com");
it.putExtra(Intent.EXTRA_SUBJECT, title);
it.setType("image/jpeg");
it.putExtra(Intent.EXTRA_STREAM, Uri.parse(String.valueOf(uri)));
it.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
startActivity(it);

なんて固定で書いても空っぽになる。

String[] adrs = {
  "foo@bar.com",
};
it.putExtra(Intent.EXTRA_EMAIL, adrs);

配列でセットしてあげればOK

  • SQLのWHERE句はWHEREは書かなくて良い

どのサンプルを見ても実際にWHERE句を書いてある例がなくて四苦八苦*1

/*		携帯百景投稿用アドレス取得	*/        
String[] projection = new String[] {
		android.provider.Contacts.ContactMethodsColumns.DATA
};

final Cursor cur = managedQuery(android.provider.Contacts.ContactMethods.CONTENT_EMAIL_URI,
                                     projection,
                                     android.provider.Contacts.ContactMethodsColumns.DATA + " LIKE '%movapic.com'",
                                     null,
                                     android.provider.Contacts.ContactMethodsColumns.DATA + " ASC");
int emailColumn = cur.getColumnIndex(android.provider.Contacts.ContactMethodsColumns.DATA);

spinner_mail = (Spinner) findViewById(R.id.Spinner01);
ArrayAdapter<String> adapter1 = new ArrayAdapter<String>(
		this, 
    	android.R.layout.simple_spinner_item);
adapter1.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
while (cur.moveToNext()){
        adapter1.add(cur.getString(emailColumn));
}
spinner_mail.setAdapter(adapter1);

これで(ローカルの)コンタクトリストからドメインがmovapic.comのメールアドレスのみを抽出してドロップダウンリストにセット出来た

はまっているところ

大量のボタンのアクションを登録するのにいちいち全部の項目に対して記述していったら無駄なので配列の数分ループさせてボタンのテキストとかだけを変えたいが、どのIdに対してイベント等を登録するかというやり方しか調べられていない。

Button button1 = (Button) findViewById(R.id.Button01);
button1.setOnClickListener(new View.OnClickListener() {

        public void onClick(View view) {
         //  処理
        }
);

ようはbutton1とかButton01と固定で書いているところを変数にしたい

メモ

EditTextのカーソル位置はgetSelectionStart()で取得出来るので、getText().toString()でEditTextのテキストを取得してカーソル位置に特定の文字列(タグとか)を挿入すればOK

*1:全部必要なのでnullとか

2009-01-18

[][][]ISBNをハイフン編集してJSONPで返すサービスを最新化してみた

Business::ISBNのデータを自分で更新出来たらなとモジュールを眺めるとデータはData.pmにあるらしい

use Business::ISBN::Data 20081208; # now a separate module

で、Data.pmでどのように持っているかというと

%country_data = (
0     => ['English speaking area' =>   ['00' => '19', '200' => '699', '7000' => '8499', '85000' => '89999', '900000' => '949999', '9500000' => '9999999'] ],
1     => ['English speaking area' =>   ['00' => '09', '100' => '399', '4000' => '5499', '55000' => '86979', '869800' => '998999'] ],
2     => ['French speaking area' =>   ['00' => '19', '200' => '349', '35000' => '39999', '400' => '699', '7000' => '8399', '84000' => '89999', '900000' => '949999', '9500000' => '9999999'] ],

Page not found | International ISBN Agencyで使っているhttp://www.isbn-international.org/converter/ranges.jsをごにょるスクリプトを書きながら出版社コードの上限下限をセットで苦戦

Data.pmのコメントを眺めると

This module lives in the Github repository with Business::ISBN:

	git://github.com/briandfoy/business--isbn.git

Github見たら最新情報があるかなと見に行くと最新バージョンは20081208版で変わりないけど、make_data.plなんてのを発見、そのものズバリのPerlスクリプトが本家にあるとは・・・

早速うごかしたいところであるけどPerlのバージョンが5.010以上じゃないと動かない、次のあたりを5.8で書くには面倒だ

my @keys = qw(text ranges);
my %data;

while( $js_data =~
    /
        ^gi\.area(?<group>\d+)\.text \s* = \s* "(?<text>.*?)" ;?  [\r\n]+
        ^gi\.area(\1)\.pubrange \s* = \s* "(?<ranges>.*?)"    ;?  [\r\n]+
    /gmx
    )
    {
    @{ $data{ $+{group} } }{ @keys } = @+{ @keys };
    }

#名前付きキャプチャバッファすごいな

こんなきれいに書く自信が無いのでMacBookにPerl5.010をインストール(別ディレクトリで)して実行、サーバのData.pmを最新化した

これで次のあたりも対応できました

09.12.2008; Affed Mongolia (99962) "0-4;50-79;800-999"

24.11.2008; Added El Salvador (99961) "0-3;40-89;900-999"

20.11.2008; Changed Benin (99919) to include "300-399" (previously undefined)

24.10.2008: Define India (93)"00-09;100-499;5000-7999;80000-94999;950000-999999"

20.10.2008; Changed Kenya (9966) "00-19" becomes "000-199"

05.10.2008; Addec Ukraine (611)"00-49;500-699;7000-8999;90000-99999"

29.09.2008; Added Syria (9933) "0-0;10-39;400-899;9000-9999"

2009-01-10

[][][]ハイフン無しのISBNを渡すとハイフン付きのJSONPを返すサービスを作ってみた

中身的にはno titleを呼んでJSONPにして返すだけですが、ニッチな需要があるのでw

2008年10月ぐらい?のデータを元にしているので全部のパターンには対応出来ていないのが残念ではありますが

サンプル画面

404 エラー : @niftyホームページサービスにアクセス

    • 入力エリアにISBNを入力(ISBN-10またはISBN-13)

http://img.skitch.com/20090110-8s4hmrtr1fq2q22xuwi82rmtch.png

http://img.skitch.com/20090110-c2h6gpen4eybigfbruanxi65ce.png

    • 桁数が合ってないとエラーになる

http://img.skitch.com/20090110-m23crmjhkiat216gtgqc3aj4n4.png

    • 99945(Namibia)以降が対応されてない

http://img.skitch.com/20090110-kxqmen69155s77pt9inyie4itg.png

JSONPのURL

http://natu-n.com/cgi/ISBN.cgi?isbn=ISBN-13(10)&callback=コールバック名
ただしcallbackはオプション

レスポンス例

  • ISBN(10桁または13桁)を渡して取得する
callback({
   "isbn10" : "4150116784",
   "isbn10e" : "4-15-011678-4",
   "isbn13" : "9784150116781",
   "isbn13e" : "978-4-15-011678-1",
   "success" : true
})
  • 与えたISBNが正しくない(桁数)とfalseで帰る
callback({
   "success" : false
})
  • callback=コールバック名で任意のコールバック名で取得出来る
callbacks({
   "isbn10" : "4150400083",
   "isbn10e" : "4-15-040008-3",
   "isbn13" : "9784150400088",
   "isbn13e" : "978-4-15-040008-8",
   "success" : true
})

サンプルソース(HTML+JS)

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="ja">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <script type="text/javascript" src="lib/jquery-1.2.6.pack.js"></script>
    <title>TEST</title>
    <script type="text/javascript">
        /* <![CDATA[ */
$(document).ready(function() {
    $("#isbn").keydown(function(e) {
        if (e.which == 13) {
            return false;
        }
    });
    $("#btn").click(function() {
        $("#success").text("");
        $("#isbn10").text("");
        $("#isbn10e").text("");
        $("#isbn13").text("");
        $("#isbn13e").text("");
        $.ajax({
            url : "http://natu-n.com/cgi/ISBN.cgi",
            dataType : "jsonp",
            data : {
                isbn : $("#isbn").val()
            },
            success : function(json){
                // ロード完了時にここが呼ばれる
                $("#success").text(json.success);
                if ( json.success == true ) {
                    $("#isbn10").text(json.isbn10);
                    $("#isbn10e").text(json.isbn10e);
                    $("#isbn13").text(json.isbn13);
                    $("#isbn13e").text(json.isbn13e);
                }
            },
            error : function(){
                alert('error');
            }
        });
    });
});
        /* ]]> */
    </script>

</head>
<body>
<h2>ISBNを入力(10または13桁)</h2>
<form id="iform" name="iform">
    <input type="text" id="isbn" name="isbn" size="13">
    <input type="button" id="btn" value="変換">
</form>
<table>
    <tdoby>
        <tr><td>status</td><td>:</td><td id="success"></td></tr>
        <tr><td>isbn10</td><td>:</td><td id="isbn10" ></td></tr>
        <tr><td>isbn10e</td><td>:</td><td id="isbn10e"></td></tr>
        <tr><td>isbn13</td><td>:</td><td id="isbn13" ></td></tr>
        <tr><td>isbn13e</td><td>:</td><td id="isbn13e"></td></tr>
    </tbody>
</table>
</td>
</body>
</html>