Mar 28, 2012

CountDownTimer

The android.os.CountDownTimer class schedule a countdown until a time in the future, with regular notifications on intervals along the way.

CountDownTimer

The Constructor CountDownTimer(long millisInFuture, long countDownInterval) call with the number of millis in the future from the call to start() until the countdown is done and onFinish() is called(millisInFuture) and The interval along the way to receive onTick(long) callbacks(countDownInterval).

package com.CountDownTimer;

import android.app.Activity;
import android.graphics.Typeface;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.view.Gravity;
import android.widget.TextView;

public class AnCountDownTimerActivity extends Activity {
public class MyCounter extends CountDownTimer {

public MyCounter(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
// TODO Auto-generated constructor stub
}

@Override
public void onFinish() {
// TODO Auto-generated method stub
myCounterPanel.setText("DONE");
}

@Override
public void onTick(long millisUntilFinished) {

long minutes = millisUntilFinished/60000;
long rSeconds = millisUntilFinished%60000;
long seconds = rSeconds/1000;
long millisonds = rSeconds%1000;

myCounterPanel.setText(minutes + ":" + seconds + ":" + millisonds);

}

}

MyCounter myCounter;
TextView myCounterPanel;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

myCounterPanel = new TextView(this);
myCounterPanel.setTextSize(40);
myCounterPanel.setTypeface(Typeface.SANS_SERIF, Typeface.BOLD);
myCounterPanel.setGravity(Gravity.CENTER);
setContentView(myCounterPanel);

myCounter = new MyCounter(3000000, 500);
myCounter.start();
}

}

Mar 26, 2012

Unzip zip file using java.util.zip

Example to unzip /mnt/sdcard/test/test.zip file to /mnt/sdcard/test/unzip/ folder.

Unzip zip file using java.util.zip

package com.AndroidUnZip;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.widget.Toast;

public class AndroidUnZipActivity extends Activity {

String extStorageDirectory;
final String testDir = "/test";
final String unzipDir = "/unzip/";
final String orgZipFile = "test.zip";
String srcFile;
String targetDir;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

CheckExtStorageDirectory();
unzip();
Toast.makeText(AndroidUnZipActivity.this,
"Unzip finished!",
Toast.LENGTH_LONG).show();


}

private void CheckExtStorageDirectory(){
extStorageDirectory = Environment.getExternalStorageDirectory().toString();
srcFile = extStorageDirectory + testDir + "/" + orgZipFile;
targetDir = extStorageDirectory + testDir + unzipDir;
Toast.makeText(AndroidUnZipActivity.this,
srcFile + "\n\n" + targetDir,
Toast.LENGTH_LONG).show();

}

private void unzip(){

final int BUFFER_SIZE = 4096;
BufferedOutputStream bufferedOutputStream = null;
FileInputStream fileInputStream;

try {
fileInputStream = new FileInputStream(srcFile);

ZipInputStream zipInputStream = new ZipInputStream(new BufferedInputStream(fileInputStream));
ZipEntry zipEntry;

while ((zipEntry = zipInputStream.getNextEntry()) != null){
String zipEntryName = zipEntry.getName();
File file = new File(targetDir + zipEntryName);

if (file.exists()){

}else{
if(zipEntry.isDirectory()){
file.mkdirs();
}else{
byte buffer[] = new byte[BUFFER_SIZE];

FileOutputStream fileOutputStream = new FileOutputStream(file);
bufferedOutputStream
= new BufferedOutputStream(fileOutputStream, BUFFER_SIZE);
int count;

while ((count = zipInputStream.read(buffer, 0, BUFFER_SIZE)) != -1) {
bufferedOutputStream.write(buffer, 0, count);
}

bufferedOutputStream.flush();
bufferedOutputStream.close();
}
}
}
zipInputStream.close();

} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

}



To create folder and save unzipped files in sdcard, AndroidManifest.xml have to be modified to add permission of "android.permission.WRITE_EXTERNAL_STORAGE".
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.AndroidUnZip"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk android:minSdkVersion="10" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:name=".AndroidUnZipActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>

Mar 23, 2012

Gestures detection and canvas scale, translate and rotate.

Further works on previous SurfaceView Game step-by-step: react device movement/orientation using accelerometer; in this article we are going to implement GestureOverlayView to detect gestures input, and apply scale, translate and rotate on canvas accordingly.

Gestures detection and canvas scale, translate and rotate.

- In order to make it simple, disable Sensor function, comment the myAccelerometer related code in MyGameActivity.java.

- Create gestures of up/down/left/right, clockwise/anti-clockwise, enlarge/reduce, refer to the article Gestures Builder: create your gestures library. And copy the generated file to /res/raw folder.
(May be I build the Gestures too simple, the detection is not accurate. You are advised to create your own.)

Gestures Builder

- Modify main.xml to add android.gesture.GestureOverlayView.
<?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:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello" />
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>

<com.MyGame.MyGameSurfaceView
android:id="@+id/myview1"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<com.MyGame.MyForeground
android:id="@+id/myforeground"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />

<android.gesture.GestureOverlayView
android:id="@+id/gestures"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gestureStrokeType="multiple"
android:eventsInterceptionEnabled="true"/>

</FrameLayout>
</LinearLayout>


- Modify MyGameActivity.java to handle Gesture.
package com.MyGame;

import java.util.ArrayList;

import android.app.Activity;
import android.gesture.Gesture;
import android.gesture.GestureLibraries;
import android.gesture.GestureLibrary;
import android.gesture.GestureOverlayView;
import android.gesture.GestureOverlayView.OnGesturePerformedListener;
import android.gesture.Prediction;
import android.graphics.PixelFormat;
import android.os.Bundle;
import android.view.SurfaceView;
import android.widget.Toast;

public class MyGameActivity extends Activity {

MyGameSurfaceView myGameSurfaceView1;
MyForeground myForeground;

//MyAccelerometer myAccelerometer;

GestureLibrary gestureLibrary = null;
GestureOverlayView gestureOverlayView;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
myGameSurfaceView1 = (MyGameSurfaceView)findViewById(R.id.myview1);
myForeground = (MyForeground)findViewById(R.id.myforeground);

//Set myForeground using transparent background
myForeground.setZOrderOnTop(true);
myForeground.getHolder().setFormat(PixelFormat.TRANSPARENT);

//myAccelerometer = new MyAccelerometer(this);

gestureOverlayView = (GestureOverlayView)findViewById(R.id.gestures);
gestureLibrary = GestureLibraries.fromRawResource(this, R.raw.gestures);
gestureLibrary.load();
gestureOverlayView.addOnGesturePerformedListener(gesturePerformedListener);

}

OnGesturePerformedListener gesturePerformedListener
= new OnGesturePerformedListener(){

@Override
public void onGesturePerformed(GestureOverlayView view, Gesture gesture) {
ArrayList<Prediction> prediction = gestureLibrary.recognize(gesture);

if(prediction.size() > 0){
String gesturePerformed = prediction.get(0).name;
if(gesturePerformed.equals("up")){
myForeground.canvasUp();
Toast.makeText(MyGameActivity.this,
"up", Toast.LENGTH_LONG).show();
}else if(gesturePerformed.equals("down")){
myForeground.canvasDown();
Toast.makeText(MyGameActivity.this,
"down", Toast.LENGTH_LONG).show();
}else if(gesturePerformed.equals("left")){
myForeground.canvasLeft();
Toast.makeText(MyGameActivity.this,
"left", Toast.LENGTH_LONG).show();
}else if(gesturePerformed.equals("right")){
myForeground.canvasRight();
Toast.makeText(MyGameActivity.this,
"right", Toast.LENGTH_LONG).show();
}else if(gesturePerformed.equals("clockwise")){
myForeground.canvasClockwise();
Toast.makeText(MyGameActivity.this,
"clockwise", Toast.LENGTH_LONG).show();
}else if(gesturePerformed.equals("anti-clockwise")){
myForeground.canvasAntiClockwise();
Toast.makeText(MyGameActivity.this,
"anti-clockwise", Toast.LENGTH_LONG).show();
}else if(gesturePerformed.equals("enlarge")){
myForeground.canvasEnlarge();
Toast.makeText(MyGameActivity.this,
"enlarge", Toast.LENGTH_LONG).show();
}else if(gesturePerformed.equals("reduce")){
myForeground.canvasReduce();
Toast.makeText(MyGameActivity.this,
"reduce", Toast.LENGTH_LONG).show();
}
}

}

};

@Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
myGameSurfaceView1.MyGameSurfaceView_OnResume();
myForeground.MyGameSurfaceView_OnResume();

//myAccelerometer.registerListener();

}

@Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
myGameSurfaceView1.MyGameSurfaceView_OnPause();
myForeground.MyGameSurfaceView_OnPause();

//myAccelerometer.unregisterListener();
}

void updateAccelerometer(float tx, float ty){
int w = myForeground.getWidth();
int h = myForeground.getHeight();

float x = ((w/2) * tx) + (w/2);
float y = ((h/2) * ty) + (h/2);
myForeground.updateAccelerometer(x, y);
}

}


- Modify MyForeground.java to handle canvas scale, translate and rotate.
package com.MyGame;

import android.content.Context;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PorterDuff.Mode;
import android.util.AttributeSet;

public class MyForeground extends MyGameSurfaceView {

Sprite mySprite;

float canvasScaleX = 1.0f;
float canvasScaleY = 1.0f;
float canvasTranslateX = 0.0f;
float canvasTranslateY = 0.0f;
float canvasRotate = 0.0f;

public MyForeground(Context context) {
super(context);
init();
}

public MyForeground(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}

public MyForeground(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}

private void init(){
mySprite = new Sprite(
BitmapFactory.decodeResource(getResources(), R.drawable.icon_me),
100, 100);
}

@Override
protected void onDraw(Canvas canvas) {
//Clear Canvas with transparent background
canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);

canvas.scale(canvasScaleX, canvasScaleY);
canvas.translate(canvasTranslateX, canvasTranslateY);
canvas.rotate(canvasRotate, mySprite.getX(), mySprite.getY());
mySprite.draw(canvas);

}

@Override
public void updateStates() {
// TODO Auto-generated method stub
mySprite.update();
}

void updateAccelerometer(float tx, float ty){
mySprite.setX((int)tx);
mySprite.setY((int)ty);
}

public void canvasUp(){
canvasTranslateY -= 10.0f;
}

public void canvasDown(){
canvasTranslateY += 10.0f;
}

public void canvasLeft(){
canvasTranslateX -= 10.0f;
}

public void canvasRight(){
canvasTranslateX += 10.0f;
}

public void canvasClockwise(){
canvasRotate += 10.0f;
}

public void canvasAntiClockwise(){
canvasRotate -= 10.0f;
}

public void canvasEnlarge(){
canvasScaleX *= 2.0f;
canvasScaleY *= 2.0f;
}

public void canvasReduce(){
canvasScaleX /= 2.0f;
canvasScaleY /= 2.0f;
}

}



The code can be download here:
https://sites.google.com/site/helloandroidingcoding/download/MyGame_20120324.zip?attredirects=0&d=1

Mar 19, 2012

Touch to move Bitmap inside a custom View

Refer to the article Detect Touch Event, test on Custom View. Modify to add a Bitmap in the custom view, if user touch the View over the bitmap, it will be moved accordingly.

Touch to move Bitmap inside a custom View
package com.TestSingleTouch;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;

public class TestSingleTouch extends Activity {


public class TouchView extends View {

private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
private float x, y;
boolean touching = false;

Bitmap bm = BitmapFactory.decodeResource(
getResources(),
R.drawable.ic_launcher);
int bm_x = 0;
int bm_y = 0;
int bm_w = bm.getWidth();
int bm_h = bm.getHeight();
int bm_offsetx;
int bm_offsety;
boolean dm_touched = false;


public TouchView(Context context) {

super(context);
// TODO Auto-generated constructor stub

}

@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(1);
paint.setColor(Color.WHITE);

if(touching){
canvas.drawRect(x, y, x+bm_w, y+bm_h, paint);
}

canvas.drawBitmap(bm, bm_x, bm_y, paint);
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec),
MeasureSpec.getSize(heightMeasureSpec));
}

@Override

public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
int action = event.getAction();
switch(action){
case MotionEvent.ACTION_MOVE:
x = event.getX();
y = event.getY();
touching = true;

if(dm_touched){
bm_x = (int)x - bm_offsetx;
bm_y = (int)y - bm_offsety;
}

break;
case MotionEvent.ACTION_DOWN:
x = event.getX();
y = event.getY();
touching = true;

//check if bm touched
if((x > bm_x)
&& (x < bm_x+bm_w)
&& (y > bm_y)
&& (y < bm_y+bm_h)){
bm_offsetx = (int)x - bm_x;
bm_offsety = (int)y - bm_y;
dm_touched = true;
}

break;
case MotionEvent.ACTION_UP:
default:
dm_touched = false;
touching = false;
}

invalidate();
return true;
}
}

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new TouchView(this));

}
}

Mar 15, 2012

Implement Horizontal ListView using android.widget.Gallery, with custom BaseAdapter.

Refer to the article Implement a photo bar using android.widget.Gallery, with custom BaseAdapter, and custom object. It can be modify to implement a Horizontal ListView, like this:

Our Horizontal ListView

Modify the main java code to implement our custom BaseAdapter for Gallery.
package com.AnHorizontalListView;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.Gallery;
import android.widget.TextView;
import android.widget.Toast;

public class AnHorizontalListViewActivity extends Activity {

Gallery myHorizontalListView;
MyAdapter myAdapter;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
myHorizontalListView = (Gallery)findViewById(R.id.horizontallistview);

myAdapter = new MyAdapter(this);
myHorizontalListView.setAdapter(myAdapter);

myHorizontalListView.setOnItemClickListener(new OnItemClickListener(){

@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
Toast.makeText(
AnHorizontalListViewActivity.this,
parent.getItemAtPosition(position).toString() + " Clicked",
Toast.LENGTH_LONG)
.show();

}});

}

public class MyAdapter extends BaseAdapter {

Context context;

String[] itemsArray = {
"SUN","MON", "TUS", "WED", "THU", "FRI", "SAT"};

MyAdapter(Context c){
context = c;
}

@Override
public int getCount() {
// TODO Auto-generated method stub
return itemsArray.length;
}

@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return itemsArray[position];
}

@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub

View rowView = LayoutInflater
.from(parent.getContext())
.inflate(R.layout.row, null);
TextView listTextView = (TextView)rowView.findViewById(R.id.itemtext);
listTextView.setText(itemsArray[position]);

return rowView;
}


}
}


Create /res/layout/row.xml to define the layout of individual items in Gallery.
<?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/itemtext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:textColor="@android:color/white"
android:textStyle="bold"
android:textSize="30sp"/>

</LinearLayout>


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:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello" />
<Gallery
android:id="@+id/horizontallistview"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />

</LinearLayout>


Dual VideoView to play 3gp from YouTube

It's a simple example to include two VideoView in layout to play differnece 3gp from YouTube at the same time.

Reference: A simple example using VideoView to play 3gp from YouTube.

Dual VideoView to play 3gp from YouTube

Main Layout:
<?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:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello" />
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="match_parent">
<VideoView
android:id="@+id/myvideoview"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<VideoView
android:id="@+id/myvideoview2"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>


Main Code:
package com.AnVideoView;

import android.app.Activity;
import android.net.Uri;
import android.os.Bundle;
import android.widget.MediaController;
import android.widget.VideoView;

public class AnVideoView extends Activity {

String SrcPath = "rtsp://v5.cache1.c.youtube.com/CjYLENy73wIaLQnhycnrJQ8qmRMYESARFEIJbXYtZ29vZ2xlSARSBXdhdGNoYPj_hYjnq6uUTQw=/0/0/0/video.3gp";
String SrcPath2 = "rtsp://v2.cache7.c.youtube.com/CjYLENy73wIaLQk4RDShYkdS1BMYJCAkFEIJbXYtZ29vZ2xlSARSBXdhdGNoYKjR78WV1ZH5Tgw=/0/0/0/video.3gp";

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
VideoView myVideoView = (VideoView)findViewById(R.id.myvideoview);
myVideoView.setVideoURI(Uri.parse(SrcPath));
myVideoView.setMediaController(new MediaController(this));
myVideoView.requestFocus();
myVideoView.start();

VideoView myVideoView2 = (VideoView)findViewById(R.id.myvideoview2);
myVideoView2.setVideoURI(Uri.parse(SrcPath2));
myVideoView2.setMediaController(new MediaController(this));
myVideoView2.requestFocus();
myVideoView2.start();
}
}


Mar 12, 2012

Create our Android Compass

Base on last post "Detect Orientation using Accelerometer and Magnetic Field sensors", a Android compass is implemented here. In the implementation, the final result (base on Accelerometer and Magnetic Field sensors) is show in RED, point to the north.

our Android Compass

Create a custom View, Compass, extends View. The method update() is called from onSensorChanged() of main activity, with the updated direction.
package com.AndroidDetOrientation;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;

public class Compass extends View {

private float direction;

public Compass(Context context) {
super(context);
// TODO Auto-generated constructor stub
}

public Compass(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}

public Compass(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(
MeasureSpec.getSize(widthMeasureSpec),
MeasureSpec.getSize(heightMeasureSpec));
}

@Override
protected void onDraw(Canvas canvas) {

int w = getMeasuredWidth();
int h = getMeasuredHeight();
int r;
if(w > h){
r = h/2;
}else{
r = w/2;
}

Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(5);
paint.setColor(Color.WHITE);

canvas.drawCircle(w/2, h/2, r, paint);

paint.setColor(Color.RED);
canvas.drawLine(
w/2,
h/2,
(float)(w/2 + r * Math.sin(-direction)),
(float)(h/2 - r * Math.cos(-direction)),
paint);

}

public void update(float dir){
direction = dir;
invalidate();
}

}


Modify main activity, AndroidDetOrientationActivity, to update Compass.
package com.AndroidDetOrientation;

import android.app.Activity;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.widget.TextView;

public class AndroidDetOrientationActivity extends Activity
implements SensorEventListener{

SensorManager sensorManager;
private Sensor sensorAccelerometer;
private Sensor sensorMagneticField;

private float[] valuesAccelerometer;
private float[] valuesMagneticField;

private float[] matrixR;
private float[] matrixI;
private float[] matrixValues;

TextView readingAzimuth, readingPitch, readingRoll;
Compass myCompass;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
readingAzimuth = (TextView)findViewById(R.id.azimuth);
readingPitch = (TextView)findViewById(R.id.pitch);
readingRoll = (TextView)findViewById(R.id.roll);

myCompass = (Compass)findViewById(R.id.mycompass);

sensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
sensorAccelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
sensorMagneticField = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);

valuesAccelerometer = new float[3];
valuesMagneticField = new float[3];

matrixR = new float[9];
matrixI = new float[9];
matrixValues = new float[3];
}

@Override
protected void onResume() {

sensorManager.registerListener(this,
sensorAccelerometer,
SensorManager.SENSOR_DELAY_NORMAL);
sensorManager.registerListener(this,
sensorMagneticField,
SensorManager.SENSOR_DELAY_NORMAL);
super.onResume();
}

@Override
protected void onPause() {

sensorManager.unregisterListener(this,
sensorAccelerometer);
sensorManager.unregisterListener(this,
sensorMagneticField);
super.onPause();
}

@Override
public void onAccuracyChanged(Sensor arg0, int arg1) {
// TODO Auto-generated method stub

}

@Override
public void onSensorChanged(SensorEvent event) {
// TODO Auto-generated method stub

switch(event.sensor.getType()){
case Sensor.TYPE_ACCELEROMETER:
for(int i =0; i < 3; i++){
valuesAccelerometer[i] = event.values[i];
}
break;
case Sensor.TYPE_MAGNETIC_FIELD:
for(int i =0; i < 3; i++){
valuesMagneticField[i] = event.values[i];
}
break;
}

boolean success = SensorManager.getRotationMatrix(
matrixR,
matrixI,
valuesAccelerometer,
valuesMagneticField);

if(success){
SensorManager.getOrientation(matrixR, matrixValues);

double azimuth = Math.toDegrees(matrixValues[0]);
double pitch = Math.toDegrees(matrixValues[1]);
double roll = Math.toDegrees(matrixValues[2]);

readingAzimuth.setText("Azimuth: " + String.valueOf(azimuth));
readingPitch.setText("Pitch: " + String.valueOf(pitch));
readingRoll.setText("Roll: " + String.valueOf(roll));

myCompass.update(matrixValues[0]);
}

}
}


Modify main.xml to add a View of Compass.
<?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:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello" />
<TextView
android:id="@+id/azimuth"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/pitch"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/roll"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<view
class="com.AndroidDetOrientation.Compass"
android:id="@+id/mycompass"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>

</LinearLayout>

Mar 11, 2012

Detect Orientation using Accelerometer and Magnetic Field sensors

The post Detect Android device rotation, using Accelerometer sensor base on accelerometer only. It is another method to obtain it using both Accelerometer and Magnetic Field sensors together.

Example:

Detect Orientation using Accelerometer and Magnetic Field sensors

package com.AndroidDetOrientation;

import android.app.Activity;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.widget.TextView;

public class AndroidDetOrientationActivity extends Activity
implements SensorEventListener{

SensorManager sensorManager;
private Sensor sensorAccelerometer;
private Sensor sensorMagneticField;

private float[] valuesAccelerometer;
private float[] valuesMagneticField;

private float[] matrixR;
private float[] matrixI;
private float[] matrixValues;

TextView readingAzimuth, readingPitch, readingRoll;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
readingAzimuth = (TextView)findViewById(R.id.azimuth);
readingPitch = (TextView)findViewById(R.id.pitch);
readingRoll = (TextView)findViewById(R.id.roll);

sensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
sensorAccelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
sensorMagneticField = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);

valuesAccelerometer = new float[3];
valuesMagneticField = new float[3];

matrixR = new float[9];
matrixI = new float[9];
matrixValues = new float[3];
}

@Override
protected void onResume() {

sensorManager.registerListener(this,
sensorAccelerometer,
SensorManager.SENSOR_DELAY_NORMAL);
sensorManager.registerListener(this,
sensorMagneticField,
SensorManager.SENSOR_DELAY_NORMAL);
super.onResume();
}

@Override
protected void onPause() {

sensorManager.unregisterListener(this,
sensorAccelerometer);
sensorManager.unregisterListener(this,
sensorMagneticField);
super.onPause();
}

@Override
public void onAccuracyChanged(Sensor arg0, int arg1) {
// TODO Auto-generated method stub

}

@Override
public void onSensorChanged(SensorEvent event) {
// TODO Auto-generated method stub

switch(event.sensor.getType()){
case Sensor.TYPE_ACCELEROMETER:
for(int i =0; i < 3; i++){
valuesAccelerometer[i] = event.values[i];
}
break;
case Sensor.TYPE_MAGNETIC_FIELD:
for(int i =0; i < 3; i++){
valuesMagneticField[i] = event.values[i];
}
break;
}

boolean success = SensorManager.getRotationMatrix(
matrixR,
matrixI,
valuesAccelerometer,
valuesMagneticField);

if(success){
SensorManager.getOrientation(matrixR, matrixValues);

double azimuth = Math.toDegrees(matrixValues[0]);
double pitch = Math.toDegrees(matrixValues[1]);
double roll = Math.toDegrees(matrixValues[2]);

readingAzimuth.setText("Azimuth: " + String.valueOf(azimuth));
readingPitch.setText("Pitch: " + String.valueOf(pitch));
readingRoll.setText("Roll: " + String.valueOf(roll));
}

}
}


<?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:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello" />
<TextView
android:id="@+id/azimuth"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/pitch"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/roll"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>

</LinearLayout>



Next
- Create our Android Compass

Mar 7, 2012

SurfaceView Game step-by-step: react device movement/orientation using accelerometer

With the help of accelerometer on Android device(Get detail info of Accelerometer), we can react device movement/orientation for our SurfaceView Game(Implement onTouchEvent() to handle user touch on SurfaceView). After finished, the the Sprite will move once user move the device.

SurfaceView Game step-by-step: react device movement/orientation using accelerometer
Implement new class - MyAccelerometer.java.
package com.MyGame;

import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;

public class MyAccelerometer implements SensorEventListener{

private SensorManager sensorManager;
private Sensor sensorAccelerometer;
private MyGameActivity parent;

private float maximumRange;

public MyAccelerometer(Context c) {
parent = (MyGameActivity)c;
}

void registerListener(){
sensorManager = (SensorManager)parent.getSystemService(Context.SENSOR_SERVICE);
sensorAccelerometer = sensorManager.getDefaultSensor(
Sensor.TYPE_ACCELEROMETER);

maximumRange = sensorAccelerometer.getMaximumRange();

sensorManager.registerListener(this,
sensorAccelerometer,
SensorManager.SENSOR_DELAY_NORMAL);
}

void unregisterListener(){
sensorManager.unregisterListener(this);
}

@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub

}

@Override
public void onSensorChanged(SensorEvent event) {
// TODO Auto-generated method stub
/*
* event.values[0]: azimuth, rotation around the Z axis.
* event.values[1]: pitch, rotation around the X axis.
* event.values[2]: roll, rotation around the Y axis.
*/

float valueAzimuth = event.values[0];
float valuePitch = event.values[1];

parent.updateAccelerometer(
valueAzimuth/maximumRange, -valuePitch/maximumRange);

}

}


Modify MyGameActivity.java to instance MyAccelerometer object in onCreate(), init it in onResume(), unregisterListener it in onPause(), and also implement updateAccelerometer().
package com.MyGame;

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

public class MyGameActivity extends Activity {

MyGameSurfaceView myGameSurfaceView1;
MyForeground myForeground;

MyAccelerometer myAccelerometer;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
myGameSurfaceView1 = (MyGameSurfaceView)findViewById(R.id.myview1);
myForeground = (MyForeground)findViewById(R.id.myforeground);

//Set myForeground using transparent background
myForeground.setZOrderOnTop(true);
myForeground.getHolder().setFormat(PixelFormat.TRANSPARENT);

myAccelerometer = new MyAccelerometer(this);

}

@Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
myGameSurfaceView1.MyGameSurfaceView_OnResume();
myForeground.MyGameSurfaceView_OnResume();

myAccelerometer.registerListener();

}

@Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
myGameSurfaceView1.MyGameSurfaceView_OnPause();
myForeground.MyGameSurfaceView_OnPause();

myAccelerometer.unregisterListener();
}

void updateAccelerometer(float tx, float ty){
int w = myForeground.getWidth();
int h = myForeground.getHeight();

float x = ((w/2) * tx) + (w/2);
float y = ((h/2) * ty) + (h/2);
myForeground.updateAccelerometer(x, y);
}

}


Update MyForeground.java.
package com.MyGame;

import android.content.Context;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PorterDuff.Mode;
import android.util.AttributeSet;

public class MyForeground extends MyGameSurfaceView {

Sprite mySprite;

public MyForeground(Context context) {
super(context);
init();
}

public MyForeground(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}

public MyForeground(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}

private void init(){
mySprite = new Sprite(
BitmapFactory.decodeResource(getResources(), R.drawable.icon_me),
100, 100);
}

@Override
protected void onDraw(Canvas canvas) {
//Clear Canvas with transparent background
canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);

mySprite.draw(canvas);
}

@Override
public void updateStates() {
// TODO Auto-generated method stub
mySprite.update();
}

void updateAccelerometer(float tx, float ty){
mySprite.setX((int)tx);
mySprite.setY((int)ty);
}

}


Update Sprite.java to remove un-used code.
package com.MyGame;

import android.graphics.Bitmap;
import android.graphics.Canvas;

public class Sprite {
private Bitmap bitmap;
private int x;
private int y;
float bitmap_halfWidth, bitmap_halfHeight;

public Sprite(Bitmap bm, int tx, int ty){
bitmap = bm;
x = tx;
y = ty;
bitmap_halfWidth = bitmap.getWidth()/2;
bitmap_halfHeight = bitmap.getHeight()/2;
}

public void setX(int tx){
x = tx;
}

public void setY(int ty){
y = ty;
}

public int getX(){
return x;
}

public int getY(){
return y;
}

public void draw(Canvas canvas){
canvas.drawBitmap(bitmap, x-bitmap_halfWidth, y-bitmap_halfHeight, null);
}

public void update(){

}

}


The code can be download here: https://sites.google.com/site/helloandroidingcoding/download/MyGame_20120307.zip?attredirects=0&d=1

Mar 5, 2012

Get detail info of Accelerometer

detail info of Accelerometer

package com.exercise.AndroidAccelerometer;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;

public class AndroidAccelerometerActivity extends Activity
implements SensorEventListener{

private SensorManager sensorManager;
private Sensor sensorAccelerometer;

TextView readingAzimuth, readingPitch, readingRoll;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

sensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
sensorAccelerometer = sensorManager.getDefaultSensor(
Sensor.TYPE_ACCELEROMETER);

readingAzimuth = (TextView)findViewById(R.id.azimuth);
readingPitch = (TextView)findViewById(R.id.pitch);
readingRoll = (TextView)findViewById(R.id.roll);
TextView info = (TextView)findViewById(R.id.info);

String stringInfo = "\n"
+ "Name: " + sensorAccelerometer.getName() + "\n"
+ "Type: " + sensorAccelerometer.getType() + "\n"
+ "Vendor: " + sensorAccelerometer.getVendor() + "\n"
+ "Version: " + sensorAccelerometer.getVersion() + "\n"
+ "Class: " + sensorAccelerometer.getClass() + "\n"
+ "Resolution: " + sensorAccelerometer.getResolution() + "\n"
+ "MaximumRange: " + sensorAccelerometer.getMaximumRange() + "\n"
+ "Power: " + sensorAccelerometer.getPower() + "\n";

info.setText(stringInfo);

}

@Override
protected void onPause() {
super.onPause();
sensorManager.unregisterListener(this);
}

@Override
protected void onResume() {
super.onResume();
sensorManager.registerListener(this,
sensorAccelerometer,
SensorManager.SENSOR_DELAY_NORMAL);
}

@Override
public void onAccuracyChanged(Sensor arg0, int arg1) {
// TODO Auto-generated method stub

}

@Override
public void onSensorChanged(SensorEvent event) {

/*
* event.values[0]: azimuth, rotation around the Z axis.
* event.values[1]: pitch, rotation around the X axis.
* event.values[2]: roll, rotation around the Y axis.
*/

float valueAzimuth = event.values[0];
float valuePitch = event.values[1];
float valueRoll = event.values[2];

readingAzimuth.setText("Azimuth: " + String.valueOf(valueAzimuth));
readingPitch.setText("Pitch: " + String.valueOf(valuePitch));
readingRoll.setText("Roll: " + String.valueOf(valueRoll));


}
}


<?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:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello" />
<TextView
android:id="@+id/info"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/azimuth"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/pitch"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/roll"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>

</LinearLayout>



Related:
- SurfaceView Game step-by-step: react device movement/orientation using accelerometer

Infolinks In Text Ads