Archive for November, 2011

[JavaScript] Observer pattern like EventDispatcher in AS3

Tuesday, November 29th, 2011

I made Observer pattern classes in JavaScript.
Here is code.

var kinkuma = {}; //package name
(function(pkg){
	pkg.Event = function(){
		this.target;
		this.context;
	};
	pkg.Observer = function(){
		this.listeners = {};
	};
	pkg.Observer.prototype = {
		addObserver:function(type, listener, context){
			var listeners = this.listeners;
			if(!listeners[type]){
				listeners[type] = [];
			}
			listeners[type].push([listener, context]);
		},
		removeObserver:function(type, listener){
			var listeners = this.listeners;
			if(listeners[type]){
				var i;
				var len = listeners[type].length;
				for(i = len - 1; i >= 0; i--){
					var arr = listeners[type][i];
					if(arr[0] == listener){
						listeners[type].splice(i, 1);
					}
				}
			}
		},
		notify:function(type){
			var listeners = this.listeners;
			var e = new pkg.Event();
			e.target = this;
			if(listeners[type]){
				var i;
				var len = listeners[type].length;
				for(i = 0; i < len; i++){
					var arr = listeners[type][i];
					e.context = arr[1];
					arr[0](e);
				}
			}
		}
	}
})(kinkuma);

Usage 1 simple

I made simple class.

var MyData = function(){
	this.change = function(){
		this.notify("CHANGE"); //trigger
	};
};
MyData.prototype = new kinkuma.Observer(); //extends Observer

function hello(){
	alert('hello');
}

var d = new MyData();
d.addObserver("CHANGE", hello); //linkage with hello function
d.change(); //let's try

Usage 2 With MVC pattern like in AS3

>> Would you try to do this page.

If you push button, mycar moves to right.
But if it is over 200px, it stops to move.

I used MVC pattern.

The code is here.

<html>
<head>
<meta charset="UTF-8" />
<script type="text/javascript" src="jquery-1.6.2.min.js"></script>
<script type="text/javascript">

var kinkuma = {}; //package name
(function(pkg){
	pkg.Event = function(){
		this.target;
		this.context;
	};
	pkg.Observer = function(){
		this.listeners = {};
	};
	pkg.Observer.prototype = {
		addObserver:function(type, listener, context){
			var listeners = this.listeners;
			if(!listeners[type]){
				listeners[type] = [];
			}
			listeners[type].push([listener, context]);
		},
		removeObserver:function(type, listener){
			var listeners = this.listeners;
			if(listeners[type]){
				var i;
				var len = listeners[type].length;
				for(i = len - 1; i >= 0; i--){
					var arr = listeners[type][i];
					if(arr[0] == listener){
						listeners[type].splice(i, 1);
					}
				}
			}
		},
		notify:function(type){
			var listeners = this.listeners;
			var e = new pkg.Event();
			e.target = this;
			if(listeners[type]){
				var i;
				var len = listeners[type].length;
				for(i = 0; i < len; i++){
					var arr = listeners[type][i];
					e.context = arr[1];
					arr[0](e);
				}
			}
		}
	}
})(kinkuma);

function trace(str){
	console.log(str);
}

var DataEvent = {
	CHANGE:"change"
}

//Model
var CarData = function(){
	this.posX = 0;
};
CarData.prototype = new kinkuma.Observer();
CarData.prototype.setPosX = function(aPosX){
	this.posX = aPosX;
	this.notify(DataEvent.CHANGE);
};

//View
var CarView = function(data){
	this.cardata = data;
	this.view;
	this.cardata.addObserver(DataEvent.CHANGE, this.onCardataChange, this);
	this.createView();
};
CarView.prototype.createView = function(){
	$('body').append('<div id="carview" style="width:60px;height:30px;background-color:#aaa;position:absolute;top:100px;left:0px;font-size:12px;text-align:center;font-family:sans-serif">mycar</div>');
	this.view = $('#carview');
};
CarView.prototype.onCardataChange = function(e){
	var self = e.context; //CarView instance
	var data = e.target; //observer instance
	self.view.css({left:data.posX + 'px'});
	if(data.posX > 200){
		self.cardata.removeObserver(DataEvent.CHANGE, self.onCardataChange);
	}
};

//Main
var Main = function(){
	this.cardata;
	this.carView;
};
Main.prototype = {
	init:function(){
		var self = this;
		this.cardata = new CarData();
		this.carView = new CarView(this.cardata);
		$('#pushBtn').click(function(){
			self.cardata.setPosX(self.cardata.posX + 20);
		});
	}
}

$(function(){
	var m = new Main();
	m.init();
});

</script>
</head>
<body>

<input id="pushBtn" type="button" value="pushme" />
</body>
</html>

[Android] Async download file from network and save it in external SD card

Tuesday, November 15th, 2011

I created Async download class.

This usage app is..

Push download button. Then it starts downloading file from network.

When downloading is completed, it saves file in external sd card.

Add user permission in AndroidManifest.xml

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.INTERNET"/>

main.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:orientation="vertical" >

    <Button
        android:id="@+id/loadStartButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Download" />

</LinearLayout>

AsyncFileLoader.java

I used AsyncTask.
And I read input file little by little and write output file with InputStream and OutputStream.


package com.kinkuma.util;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;

import android.os.AsyncTask;
import android.util.Log;

public class AsyncFileLoader extends AsyncTask<Void, Void, Boolean> {
	private final String TAG = "AsyncFileLoader";
	private String _urlStr;
	private URL _url;
	private URLConnection _urlConnection;
	private final int TIMEOUT_READ = 5000;
	private final int TIMEOUT_CONNECT = 30000;
	private InputStream _inputStream;
	private BufferedInputStream _bufferedInputStream;
	private FileOutputStream _fileOutputStream;
	private File _outputFile;
	private byte[] buff = new byte[5 * 1024];
	
	private int _totalByte = 0;
	private int _currentByte = 0;
	
	public AsyncFileLoader(String urlStr, File outputFile){
		this._urlStr = urlStr;
		this._outputFile = outputFile;
	}
	
	@Override
	protected Boolean doInBackground(Void... params) {
		
		if(isCancelled()){
			return false;
		}
		
		try{
			int len;
			while((len = _bufferedInputStream.read(buff)) != -1){
				_fileOutputStream.write(buff, 0, len);
				_currentByte += len;
				//publishProgress();
				if(isCancelled()){
					break;
				}
			}
	
		}catch(IOException e){
			Log.d(TAG, "error on read file:" + e.toString());
			return false;
		}
		return true;
	}
	
	@Override
	protected void onPreExecute(){
		try{
			connect();
		}catch(IOException e){
			Log.d(TAG, "error on preExecute:" + e.toString());
			cancel(true);
		}
	}
	/*
	@Override
	protected void onProgressUpdate(Void... progress){
		
	}
	*/
	@Override
	protected void onPostExecute(Boolean result){
		if(result == true){
			try{
				close();
			}catch(IOException e){
				Log.d(TAG, "error on postExecute:" + e.toString());
			}
		}else{
			Log.d(TAG, "result: load error");
		}
	}
	
	private void connect() throws IOException
	{
		_url = new URL(_urlStr);
		_urlConnection = _url.openConnection();
		_urlConnection.setReadTimeout(TIMEOUT_READ);
		_urlConnection.setConnectTimeout(TIMEOUT_CONNECT);
		_inputStream = _urlConnection.getInputStream();
		_bufferedInputStream = new BufferedInputStream(_inputStream, 1024 * 5);
		_fileOutputStream = new FileOutputStream(_outputFile);
		
		//_totalByte = _bufferedInputStream.available(); //this is not work
		_totalByte = _urlConnection.getContentLength();
		_currentByte = 0;
	}
	
	private void close() throws IOException
	{
		_fileOutputStream.flush();
		_fileOutputStream.close();
		_bufferedInputStream.close();
	}
	
	public int getLoadedBytePercent()
	{
		if(_totalByte <= 0){
			return 0;
		}
		//Log.d(TAG, Integer.toString(_currentByte) + ":" + Integer.toString(_totalByte));
		return (int)Math.floor(100 * _currentByte/_totalByte);
	}
}

main activity

To get the external sd card path, I used Environment.getExternalStorageDirectory().

package com.myprogress;

import java.io.File;

import android.app.Activity;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Button;

import com.kinkuma.util.AsyncFileLoader;

public class DownloadingAndProgressbarActivity extends Activity {
    private final String TAG = "DownloadSample";
	private Button _loadStartButton;
	private ProgressDialog _progressDialog;
	private Handler _progressHandler;
	private final String VIDEO_URL = "http://192.168.1.0/video/sample_movie.mp4";
	private AsyncFileLoader _fileLoader;
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        _loadStartButton = (Button)findViewById(R.id.loadStartButton);
        _loadStartButton.setOnClickListener(new View.OnClickListener() {
		
			@Override
			public void onClick(View v) {
				initFileLoader();
				showDialog(0);
				_progressDialog.setProgress(0);
				_progressHandler.sendEmptyMessage(0);
			}
		});
        
        _progressHandler = new Handler(){
        	public void handleMessage(Message msg){
        		super.handleMessage(msg);
        		if(_fileLoader.isCancelled()){
        			_progressDialog.dismiss();
        			Log.d(TAG, "load canceled");
        		}
        		else if(_fileLoader.getStatus() == AsyncTask.Status.FINISHED){
        			_progressDialog.dismiss();
        		}else{
        			_progressDialog.setProgress(_fileLoader.getLoadedBytePercent());
        			_progressHandler.sendEmptyMessageDelayed(0, 100);
        		}
        	}
        };
    }
    
    @Override
    protected void onPause(){
    	Log.d(TAG, "onPause");
    	super.onPause();
    	cancelLoad();
    }
    
    @Override
    protected void onStop(){
    	Log.d(TAG, "onStop");
    	super.onStop();
    	cancelLoad();
    }
    
    private void cancelLoad()
    {
    	if(_fileLoader != null){
    		_fileLoader.cancel(true);
    	}
    }
    
    private void initFileLoader()
    {
    	File sdCard = Environment.getExternalStorageDirectory();
    	File directory = new File(sdCard.getAbsolutePath() + "/SampleFolder");
    	if(directory.exists() == false){
    		directory.mkdir();
    	}
    	File outputFile = new File(directory, "myvideo.mp4");
    	_fileLoader = new AsyncFileLoader(VIDEO_URL, outputFile);
    	_fileLoader.execute();
    }
    
    @Override
    protected Dialog onCreateDialog(int id){
    	switch(id){
    		case 0:
    			_progressDialog = new ProgressDialog(this);
    			_progressDialog.setIcon(R.drawable.ic_launcher);
    			_progressDialog.setTitle("Downloading files..");
    			_progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
    			_progressDialog.setButton(DialogInterface.BUTTON_POSITIVE, "Hide", new DialogInterface.OnClickListener() {
					
				@Override
				public void onClick(DialogInterface dialog, int which) {
						Log.d(TAG, "hide");
					}
				});
    			_progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, "Cancel", new DialogInterface.OnClickListener() {
					
					@Override
					public void onClick(DialogInterface dialog, int which) {
						Log.d(TAG, "cancel");
						cancelLoad();
					}
				});
    	}
		return _progressDialog;
    }
}

[Android] Simple repeat timer count

Tuesday, November 15th, 2011

I practiced to make timer base app.

When start button is pushed, it starts to count up and shows counted value in the label.
When stop button is pushed, it stops to count up.

main.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:orientation="vertical" >

    <TextView
        android:id="@+id/currentTimeLabel"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/hello" />

    <LinearLayout
        android:id="@+id/linearLayout1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <Button
            android:id="@+id/startButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Start" />

        <Button
            android:id="@+id/stopButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Stop" />

    </LinearLayout>

</LinearLayout>

TimerSampleActivity.java

package com.mytimer;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class TimerSampleActivity extends Activity implements View.OnClickListener{
    private final String TAG = "TimerSample";  
	
	private Button mStartButton;
	private Button mStopButton;
	public int currentTime;
	private Handler _myHandler;
	private TextView mCurrentTimeLabel;
	private Runnable _myTask;
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        currentTime = 0;
        mStartButton = (Button)findViewById(R.id.startButton);
        mStopButton = (Button)findViewById(R.id.stopButton);
        mCurrentTimeLabel = (TextView)findViewById(R.id.currentTimeLabel);
        mStartButton.setOnClickListener(this);
        mStopButton.setOnClickListener(this);
    }

	@Override
	public void onClick(View v) {
		if(v.getId() == R.id.startButton){
			Log.d(TAG, "start");
			cancelTimer();
			_myTask = new MyTimerTask();
			_myHandler = new Handler();
			_myHandler.postDelayed(_myTask, 100);
		}
		else if(v.getId() == R.id.stopButton){
			Log.d(TAG, "stop");
			mCurrentTimeLabel.setText("stop");
			cancelTimer();
		}
		
	}
	
	private void cancelTimer()
	{
		if(_myHandler != null){
			_myHandler.removeCallbacks(_myTask);
		}
	}
	
	private class MyTimerTask implements Runnable
	{
		@Override
		public void run() {
			currentTime++;
			mCurrentTimeLabel.setText(Integer.toString(currentTime));
			
			_myHandler.postDelayed(this, 100);
		}
	}
}

Below page is original source code page.
Updating the UI from a Timer

[Android] How to access media data in assets and res/raw folder

Monday, November 14th, 2011

To make custom media player, I tried to use MediaPlayer.
But when I set datasource, it could not work well.

I placed video files in assets/ or res/raw.
I didn’t know how to access.

I googled.
Then I found the solution.

If you placed in assets/video_file.mp4

_player = new MediaPlayer();
AssetFileDescriptor afd = getAssets().openFd("video_file.mp4");
_player.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
    		
_player.setDisplay(_holder); //_holder is SurfaceHolder of SurfaceView
_player.prepare();

Or if you placed in res/raw/video_file.mp4

_player = new MediaPlayer();
 String fileName = "android.resource://" + getPackageName() + "/" + R.raw.video_file;
_player.setDataSource(this, Uri.parse(fileName));
    		
_player.setDisplay(_holder); //_holder is SurfaceHolder of SurfaceView
_player.prepare();

These pages have some very useful information.
Thanks.

Discovering Android – Embedding Video in an Android Application
Play audio file from the assets directory

[Android] how to make display to fullscreen

Monday, November 14th, 2011

There are several way to make display to fullscreen.

method 1)
this method’s point is placing requestWindowFeature between onCreate and setContentView.

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE); // to fullscreen
        setContentView(R.layout.main);
    }

method 2)
add theme property application or activity xml tag in AndroidManifest.xml.


or


see this page
http://developer.android.com/guide/topics/ui/themes.html#ApplyATheme

[Android] Honeycomb Android 3 system bar height is 48px

Monday, November 14th, 2011

Honeycomb Android 3 system bar height is 48px.

If your device display size is WXGA (1280 x 800), your content height is 752px.