Android サイリウムアプリ公開

t-kado2011-08-06

久々に、Androidアプリを公開しました


今回も前回と同じように3日で完成
個人的に時間をかけてアプリを作るよりは、さっさと形にして叩きながら機能改善していく方が好きです


カラフル サイリウム
https://market.android.com/details?id=com.ColorfulCyalume


今回のアプリで工夫したところは
・アプリ起動中はスリープに入らないようにする

・画面輝度を最大にする

・メニューアイコンを動的に変化させる

・加速度センサーを使う・ローパス・ハイパスフィルターを使う


仕事ではC++ばっかりなので、久々のJavaでした。
オブジェクト指向がだんだん分かってきたので、コードの書き方も前よりはスマートになったかな
次は何を作ろうかなぁ
あと、Androidの勉強会はどこかのタイミングで出席したい

WebKit GTK版をビルドする

ほとんど↓通り
http://96inu.blogspot.com/2009/09/debiangtkwebkit.html


Subversionのインストールをして
$ sudo apt-get install subversion


ソースをチェックアウト
$ svn co http://svn.webkit.org/repository/webkit/trunk

設定をしてからビルドをする
$ cd trunk
$ WebKitTools/Scripts/update-webkit
$ WebKitTools/Scripts/set-webkit-configuration --release
$ WebKitTools/Scripts/build-webkit --gtk

いろいろとエラーが出てくるので、そのたびに必要なパッケージをインストールする
特にうまく行かなかったのは以下の2点


GLIBではまったときはPATHに/usr/include/glib-2.0を設定したらうまくいった
$ export PATH=$PATH:/usr/include/glib-2.0


libsoupもなかなかうまくいかず、libsoup-2.33.6をダウンロードしてきて(http://ftp.acc.umu.se/pub/gnome/sources/libsoup/2.33/
$ tar zxvf libsoup-2.33.6.tar.gz
$ cd libsoup-2.33.6
$ ./configure
$ make
$ sudo make install
でうまくいった

設定画うまく行けばビルドが始まる
1時間ほどでビルドができた
===========================================================
WebKit is now built (1h:02m:52s).
To run GtkLauncher with this newly-built code, use the
"Tools/Scripts/run-launcher" script.
===========================================================
実行は以下のコマンド
$ WebKitBuild/Release/Programs/GtkLancher


Windowが立ち上がりブラウザ画面が開く
Acid3は99点なのね
Sunspider 0.9の結果
 WebKit        Firefox 3.6.12
432.8ms +/- 4.4% 1035.2ms +/- 2.1%


土日に移植層が作れるかどうか検討してみよう

Androidアプリ2本 マーケットで公開中

先週くらいからAndroidマーケットでアプリを2本公開しています

ガイガーカウンター
http://market.android.com/details?id=com.XmlTest

水の安全
http://market.android.com/details?id=jp.tkada.gaigerwater


今回のアプリ公開で、Androidマーケットの署名やバージョン管理方法なども勉強できました
公開したあとってパッケージ名に変えられないんですね・・・
それにより、ガイガーカウンターの方は「com.XmlTest」なんて名前に…
これらのアプリに関してはこまめにアップデートを行う予定です


アンドロイダーでの紹介記事
http://androider.jp/a/e62d11728cc7c99c/
http://androider.jp/a/c4293b738cc5699d/


Exドロイドでの紹介記事
http://exdroid.jp/d/3626/


アンドロイドスーパーでの紹介記事
http://arar.tk/archives/219

Android ColorPickerDialogの使い方

t-kado2010-12-12

お絵かきアプリを作る際に色選択は必須
カラーパレットを用意してやって・・・ってのもいいけど
Android SDKのサンプルに良いものがあるので流用してみる

1.samples\android-7\ApiDemos\src\com\example\android\apis\graphicsの中にある
 ColorPickerDialog.javaをプロジェクトに組み込む
2.Dialogとして呼び出す

package com.example.android.apis.graphics;

import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;

public class ColorSelect extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        ColorPickerDialog cpd=new ColorPickerDialog(this, new ColorPickerDialog.OnColorChangedListener() {
			
			@Override
			public void colorChanged(int color) {
				// 色が選択されるとcolorに値が入る
				int R=Color.red(color);
				int G=Color.green(color);
				int B=Color.blue(color);
				
				android.util.Log.d("ColorPickerDialog", "(R,G,B)=("+R+","+G+","+B+")");
			}
		},Color.BLACK);
        
        cpd.show();
    }
}

参考:http://y-anz-m.blogspot.com/2010/05/androidcolorpickerdialog.html

シンプルなAndroidカメラアプリ

参考:http://androidlab.blog119.fc2.com/blog-entry-21.html

package com.tkado.SimpleCamera;

import android.app.Activity;
import android.content.Context;
import android.hardware.Camera;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.Window;

import java.io.*;
import java.util.Calendar;

// ----------------------------------------------------------------------

public class Camera_test extends Activity {
    private Preview mPreview;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Hide the window title.
        requestWindowFeature(Window.FEATURE_NO_TITLE);

        // Create our Preview view and set it as the content of our activity.
        mPreview = new Preview(this);
        setContentView(mPreview);
    }

}

// ----------------------------------------------------------------------

class Preview extends SurfaceView implements SurfaceHolder.Callback {
    SurfaceHolder mHolder;
    Camera mCamera;
    String SD="/sdcard/DCIM/102SC/";  //SDカードの保存先フォルダ

    Preview(Context context) {
        super(context);

        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        mHolder = getHolder();
        mHolder.addCallback(this);
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    public void surfaceCreated(SurfaceHolder holder) {
        // The Surface has been created, acquire the camera and tell it where
        // to draw.
        mCamera = Camera.open();
        try {
           mCamera.setPreviewDisplay(holder);
        } catch (IOException exception) {
            mCamera.release();
            mCamera = null;
        }
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        // Surface will be destroyed when we return, so stop the preview.
        // Because the CameraDevice object is not a shared resource, it's very
        // important to release it when the activity is paused.
        mCamera.stopPreview();
        mCamera.release();
        mCamera = null;
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        // Now that the size is known, set up the camera parameters and begin
        // the preview.
        Camera.Parameters parameters = mCamera.getParameters();
        parameters.setPreviewSize(w, h);
        parameters.setPictureSize(w*2, h*2); //プレビューサイズの2倍の大きさで画像を保存する
        mCamera.setParameters(parameters);
        mCamera.startPreview();
    }

    public boolean onTouchEvent(MotionEvent e){
    	if(e.getAction()==MotionEvent.ACTION_DOWN){
    		Log.d("TEST","X:"+e.getX());
    		Log.d("TEST","Y:"+e.getY());
    	}
    	takePicture();
		return false;
    }

    //写真撮影
    public void takePicture() {
        //カメラのスクリーンショットの取得
        mCamera.takePicture(null,null,new Camera.PictureCallback() {
            public void onPictureTaken(byte[] data,Camera camera) {
                try {
                	mCamera.stopPreview();
                    Log.d("Camera","Take picture");
                    File dirs = new File(SD);
                    if (!dirs.exists()) {
                        dirs.mkdirs();    //make folders
                    }

                    String outputfile=Calendar.getInstance().getTimeInMillis()+".jpg";   //ファイル名が被らないように時間で名前を付ける
					String filename=SD+outputfile;
                    Log.d("Camera", "output:"+filename);
					FileOutputStream fos = null;
					try {
						fos = new FileOutputStream(filename);
						fos.write(data);
					} catch (IOException e) {
						e.printStackTrace();
						mCamera.stopPreview();
	                    mCamera.release();
	                    android.util.Log.e("",""+e.toString());
					} finally {
						fos.close();
						Log.d("Camera", "Done:"+filename);
					}
                    mCamera.startPreview();
                } catch (Exception e) {
                	mCamera.stopPreview();
                    mCamera.release();
                    android.util.Log.e("",""+e.toString());
                }
            }
        });
    }
}

あとはカメラを使うためにAndroidManifest.xml

を追加する。
そしてAndroid2.1以下ではカメラが横向き専用のため

と横向き固定にしておく。


カメラで撮って保存するだけなら非常に簡単なのだが
撮ったあとに確認画面を表示したり
プレビュー中の画像に画像処理を加えるのは一癖も二癖もあるみたいで苦戦中

IS03開発用ドライバ

IS03買ってきたのでさっそく自作アプリを動かす

1.ドライバのダウンロード
http://k-tai.sharp.co.jp/support/a/is03/download/usb/index.html
https://sh-dev.sharp.co.jp/android/modules/driver/index.php?/is03_adb/download
2.ドライバのインストール
3.IS03を接続
4.adb devicesでデバイスが見つかればOK


と、流れは簡単なのだが何度やってもうまく行かず
インストール・アンインストールを2回くらい繰り返して
ようやくadb devicesで見つかるようになった
しかし、高速転送モードが使えなくなってしまった


う〜んよくわからん。
直り次第ここに追記しよう


adb devicesで見つかればあとはEclipseから実行してあげれば
自動的にインストールと実行がされる

BitmapのOutOfMemoryErrorと戦った

画像処理はできるようになったので次はSDから画像を読み込んで画像処理をしたいなと思って挑戦


AndroidにはGalleryってのがあって端末に含まれている画像を収集して一覧として表示してくれる機能がある
そこからインテントを受け取ればどの画像が選択されたか簡単に分かるはずなのだが・・・
※Galleryについてはこちら
http://www.conit.co.jp/labs/index.php?e=255

package com.tkado.sdtest;

import java.io.*;
/*省略*/

public class SD_test extends Activity {
	final int REQUEST_PICK_CONTACT=99;
	Bitmap mBitmap;
	ImageView image;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        image=(ImageView)findViewById(R.id.ImageView01);
        String inputname="/sdcard/test2.txt";
        try{
	        byte[] buf = new byte[ (int) new File( inputname ).length() ];
	        BufferedInputStream f = new BufferedInputStream( new FileInputStream( inputname ) );
	        f.read( buf );
	        f.close();
	        TextView txt=(TextView)findViewById(R.id.TextView01);
	        String s=new String(buf, "SJIS");
	        txt.setText(s);
        }
        catch( IOException e){
        	TextView txt=(TextView)findViewById(R.id.TextView01);
			txt.setText("ERROR:"+inputname);
        }
        Button button1=(Button)findViewById(R.id.Button01);
        button1.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				// TODO 自動生成されたメソッド・スタブ
				// インテント設定
				Intent intent = new Intent(Intent.ACTION_PICK);
				// とりあえずストレージ内の全イメージ画像を対象
				intent.setType("image/*");
				// ギャラリー表示
				startActivityForResult(intent, REQUEST_PICK_CONTACT);
			}
		});

    }
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    	// TODO Auto-generated method stub
    	super.onActivityResult(requestCode, resultCode, data);
    	Log.d("tag","onActivity");
    	if(requestCode == REQUEST_PICK_CONTACT){
	    	//Content Providerとは、全てのアプリケーションからデータの読み書きが可能なオブジェクトで、パッケージ間でデータ共有を行う唯一の手段
    		Log.d("tag","inif");
	    	Uri photoUri = data.getData();
	    	ContentResolver cont_reslv = getContentResolver();
	    	if (photoUri != null) {
		    	try {
		    		if(mBitmap!=null){
		    			mBitmap.recycle();
		    			mBitmap=null;
		    		}
		    		mBitmap = MediaStore.Images.Media.getBitmap(cont_reslv, photoUri);

		    		image.setImageBitmap(mBitmap);
		    	} catch (Exception e) {
		    		e.printStackTrace();
		    	}
	    	}
    	}

    }
}


このコードのキモはここ

if(mBitmap!=null){
 	mBitmap.recycle();
	mBitmap=null;
}

これがないとOutOfMemoryErrorが出てきてどうしようもなかった


ここらへんがかなり参考になった
http://groups.google.com/group/android-group-japan/browse_thread/thread/fa40fe4d250541f5
http://mtnk.org/down/PDF/OutOfMemoryError.pdf

なんとか画像の切り替えができるようになったので
次は画像処理をしてSDへの保存、カメラアプリとの連動、メールアプリとの連動辺りをやりたいな
実はOutOfMemoryErrorもネイティブコードを使えば簡単に回避できるらしいね