Archive

Posts Tagged ‘tutorials’

Create and use a Compound Control

July 9, 2011 11 comments

What is Compound Control?

Basically, it is a widget/control that containing a group of other controls, something like: an ImageView and a TextView can be used as one instead of two separate controls….

Today, I will guide you on creating a Compound Control like below (one part in my next release Android Application)

Compound Control: HeroInfo Control

Compound Control: HeroInfo Control

I named it HeroInfoControl. As you see on the screenshot, there are three same compound controls I created.

Each HeroInfoControl will display information of one hero in DotA :D, my favorite game!

A – Design the layout

The control contains:

+ a hero icon on the very left of the layout, I define all image displayed here with size 48×48 in pixels.

+ on the top right is also one image that displays hero title

+ on the bottom right is a text which displays hero name.

Generally, a parent ViewGroup appropriate for this one is LinearLayout and a sub LinearLayout to contain the part on the right.

There should a space between the left and the right of the main layout, so a marginRight needs to defined, I guess “5-10dip” is good enough.

The hero name needs to be bold somehow.

The hero name and hero title somehow need to be padded on top and bottom to make it a little center horizontal aligning to the hero icon. It looks a bit nicer then.

That’s all I have for sketching the layout, let’s define it into XML:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:orientation="horizontal"
	android:layout_width="fill_parent"
	android:layout_height="wrap_content">

	<ImageView
		android:id="@+id/ivIcon"
		android:layout_width="wrap_content"
		android:layout_height="wrap_content"
		android:scaleType="fitCenter"
		android:layout_marginRight="5dip"
	/>

	<LinearLayout
		android:orientation="vertical"
		android:layout_width="fill_parent"
		android:layout_height="fill_parent"
	>

		<ImageView
			android:id="@+id/ivTitle"
			android:layout_width="fill_parent"
			android:layout_height="wrap_content"
			android:scaleType="fitStart"
			android:paddingTop="5dip"
			android:paddingLeft="10dip"
		/>

		<TextView
			android:id="@+id/tvName"
			android:layout_width="fill_parent"
			android:layout_height="wrap_content"
			android:layout_weight="1"
			android:gravity="left|bottom"
			android:paddingBottom="5dip"
			android:paddingLeft="10dip"
			android:textStyle="bold"
			android:textSize="15sp"
		/>

	</LinearLayout>

</LinearLayout>

B – Code for Layout

The next part is to define the layout and create the real control to use.

Since the parent layout used is LinearLayout, I will extend my compound control to LinearLayout class.

package pete.android.study;

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

public class HeroInfoControl extends LinearLayout {

	private ImageView mHeroIcon;
	private ImageView mHeroTitle;
	private TextView mHeroName;

	public HeroInfoControl(Context context) {
		super(context);

		loadViews();
	}

	public HeroInfoControl(Context context, AttributeSet attrs) {
		super(context, attrs);

		LayoutInflater inflater = LayoutInflater.from(context);
		inflater.inflate(R.layout.hero_info, this);

		loadViews();
	}

	private void loadViews() {
		mHeroIcon = (ImageView)findViewById(R.id.ivIcon);
		mHeroTitle = (ImageView)findViewById(R.id.ivTitle);
		mHeroName = (TextView)findViewById(R.id.tvName);
	}

	public void setHeroIcon(Drawable icon) {
		mHeroIcon.setImageDrawable(icon);
	}

	public void setHeroTitle(Drawable title) {
		mHeroTitle.setImageDrawable(title);
	}

	public void setHeroName(String name) {
		mHeroName.setText("::" + name + "::");
	}

}

You need the constructor with AttributeSet in order to use it in XML layout. Well, it’s quite simple, I guess no need to explain the above code.

So, we’ve done creating our control, it’s time to use it!

C – Use the Control

As sample, I will put three controls in layout:

<?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"
    >

	<pete.android.study.HeroInfoControl
		android:id="@+id/heroLuna"
		android:layout_width="fill_parent"
		android:layout_height="wrap_content"
		android:layout_marginTop="5dip"
		android:layout_marginBottom="5dip"
	>
	</pete.android.study.HeroInfoControl>

	<pete.android.study.HeroInfoControl
		android:id="@+id/heroTiny"
		android:layout_width="fill_parent"
		android:layout_height="wrap_content"
		android:layout_marginTop="5dip"
		android:layout_marginBottom="5dip"
	>
	</pete.android.study.HeroInfoControl>

	<pete.android.study.HeroInfoControl
		android:id="@+id/heroKael"
		android:layout_width="fill_parent"
		android:layout_height="wrap_content"
		android:layout_marginTop="5dip"
		android:layout_marginBottom="5dip"
	>
	</pete.android.study.HeroInfoControl>

</LinearLayout>

You probably need to put all images into resources folder.

Remember to use your control with fully qualified tag like above, otherwise, it won’t work.

Make code and set their values:

package pete.android.study;

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

public class MainActivity extends Activity {
    HeroInfoControl heroLuna;
    HeroInfoControl heroTiny;
    HeroInfoControl heroKael;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        heroLuna = (HeroInfoControl)findViewById(R.id.heroLuna);
        heroLuna.setHeroIcon(getResources().getDrawable(R.drawable.luna));
        heroLuna.setHeroTitle(getResources().getDrawable(R.drawable.luna_title));
        heroLuna.setHeroName("Luna Moonfang");

        heroTiny = (HeroInfoControl)findViewById(R.id.heroTiny);
        heroTiny.setHeroIcon(getResources().getDrawable(R.drawable.tiny));
        heroTiny.setHeroTitle(getResources().getDrawable(R.drawable.tiny_title));
        heroTiny.setHeroName("Tiny");

        heroKael = (HeroInfoControl)findViewById(R.id.heroKael);
        heroKael.setHeroIcon(getResources().getDrawable(R.drawable.kael));
        heroKael.setHeroTitle(getResources().getDrawable(R.drawable.kael_title));
        heroKael.setHeroName("Kael");
    }
}

There you go, your compound control is done with the sample.
You can make any kind of control you want 🙂
Hope you like it!

Cheers,
Pete Houston

Advertisements

Parsing MP3 Basic Info manually

June 28, 2011 1 comment

Let’s continue from my previous article on MP3 file structure.

We’re going into practice to parse MP3 basic info: Title, Artist, Year, Album. These are the most basic ones and we can achieve by reading the very last 128 bytes at the end of file.

First you need to put the file into Emulator, in my case, I put into “/sdcard/music.mp3“. After parsing just display it to screen:

MP3 Info Parsing

MP3 Info Parsing

Think it simple, just Java, no Android thought here!

This is how I did it 🙂

package pete.android.study;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Calendar;
import java.util.HashMap;

public class MP3HeaderInfo {

	// --- { constants } --- >>>
	// ID3 tag value
	public static final String ID3_TAG = "TAG";
	public static final int BYTE_128 = 128;
	public static final int[] OFFSET_TAG = new int[] { 0, 3 };
	public static final int[] OFFSET_TITLE = new int[] { 3, 33 };
	public static final int[] OFFSET_ARTIST = new int[] { 33, 63 };
	public static final int[] OFFSET_YEAR = new int[] { 93, 97 };
	public static final int[] OFFSET_ALBUM = new int[] { 63, 93 };

	// indexer
	public static final int FROM = 0;
	public static final int TO = 1;

	// key attribute
	public static final String TITLE = "Title";
	public static final String ARTIST = "Artist";
	public static final String YEAR = "Year";
	public static final String ALBUM = "Album";

	// default values for each key value
	public static final String DEFAULT_TITLE = "Unknown Title";
	public static final String DEFAULT_ARTIST = "Unknown Artist";
	public static final String DEFAULT_YEAR = String.valueOf(Calendar.getInstance().get(Calendar.YEAR));
	public static final String DEFAULT_ALBUM = "Unknown Album";
	// --- { constants } --- <<<

	// --- { fields } --- >>>
	private String mFile;
	private String mTitle = DEFAULT_TITLE;
	private String mArtist = DEFAULT_ARTIST;
	private String mYear = DEFAULT_YEAR;
	private String mAlbum = DEFAULT_ALBUM;
	private String mErrorLog; // for error information
	// --- { fields } --- <<<

	// --- { constructor } --- >>>
	public MP3HeaderInfo(String file) {
		mFile = file;
		// auto parse file, only once
		parseAudio();
	}
	// --- { constructor } --- <<<

	// --- { properties } --- >>>
	public String getTitle() {
		return !mTitle.equals("") ? mTitle.trim() : DEFAULT_TITLE;
	}

	public String getArtist() {
		return !mArtist.equals("") ? mArtist.trim() : DEFAULT_ARTIST;
	}

	public String getYear() {
		return !mYear.equals("") ? mYear.trim() : DEFAULT_YEAR;
	}

	public String getAlbum() {
		return !mAlbum.equals("") ? mAlbum.trim() : DEFAULT_ALBUM;
	}

	public String getErrorLog() {
		return mErrorLog;
	}
	// --- { properties } --- <<<

	// --- { private methods } --- >>>
	private boolean parseAudio() {
		// create MP3 File object
		File mp3 = new File(mFile);
		FileInputStream fis;
		try {
			// create new file stream for parsing file in binary
			fis = new FileInputStream(mp3);
			// get file size
			int size = (int) mp3.length();
			// offset to the first byte of the last 128 bytes
			fis.skip(size - BYTE_128);
			// read chunk of 128 bytes
			byte[] chunk = new byte[BYTE_128];
			fis.read(chunk);
			// convert chunk to string
			String id3 = new String(chunk);
			// get first 3 byte
			String tag = id3.substring(OFFSET_TAG[FROM], OFFSET_TAG[TO]);
			// if equals to "TAG" meaning a valid readable one
			if(tag.equals(ID3_TAG)) {
				mTitle = id3.substring(OFFSET_TITLE[FROM], OFFSET_TITLE[TO]);
				mArtist = id3.substring(OFFSET_ARTIST[FROM], OFFSET_ARTIST[TO]);
				mYear = id3.substring(OFFSET_YEAR[FROM], OFFSET_YEAR[TO]);
				mAlbum = id3.substring(OFFSET_ALBUM[FROM], OFFSET_ALBUM[TO]);
			}

			// close stream after done
			fis.close();
			// return complete
			return true;
		} catch (FileNotFoundException e) {
			// log error
			mErrorLog = e.getMessage();
			return false;
		} catch (IOException e) {
			// log error
			mErrorLog = e.getMessage();
			return false;
		}
	}

	// --- { private methods } --- <<<

	// --- { public methods } --- >>>
	public static HashMap<String, String> getInfo(String file) {
		HashMap<String, String> result = new HashMap<String, String>();
		MP3HeaderInfo info = new MP3HeaderInfo(file);
		result.put(ARTIST, info.getArtist());
		result.put(TITLE, info.getTitle());
		result.put(YEAR, info.getYear());
		result.put(ALBUM, info.getAlbum());

		return result;
	}
	// --- { public methods } --- <<<

}

For MainActivity, just input file name to parse and display:

package pete.android.study;

import java.util.HashMap;

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

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);

        TextView tvMain = (TextView)findViewById(R.id.tvMain);

        HashMap<String, String> info = MP3HeaderInfo.getInfo("/sdcard/music.mp3");

        String out = "";
        out += info.get("Title") + " - " + info.get("Year") + "\n";
        out += info.get("Album") + "\n" + info.get("Artist") + "\n";
        tvMain.setText(out);
    }
}

Very very basic of Java file handling, isn’t it?
Talking about MP3 Song Duration or Bit-rate, well, it’s quite complicated … I’m still not good enough at parsing them at the moment, it would take some more time to study about.
However, I guess those above info is enough to display to users. Or you can even achieve reading more metadata on MP3 file by using third-party libraries for your applications.
Have fun!

Cheers,
Pete Houston

Categories: Tutorials Tags: , , ,

A Quick Study on MP3 file structure

June 28, 2011 1 comment

Just had a little time playing around with MP3 file and found it quite interesting.

Do you like “New Divide” by Linkin Park, which is the Original Sound Track on Transformer 2: The Revenge of the Fallen? I personally like it very much. Ah right, Transformer 3 – Dark of the Moon is coming tomorrow, certainly I’ll watch it :D.

If you have the MP3 file of the song, on Windows Explorer right click on it and select Properties, open tab Details:

Windows Explorer: MP3 File Properties

Windows Explorer: MP3 File Properties

You can see its information like: Title, Artists, Album, Year, Genre, Length ….

Ok, try to open it using Mp3tag (v2.49):

MP3Tag - File Info View

MP3Tag - File Info View

The tag version of MP3 file is: ID3v2.3, which is basically derived from v1 and v2.3. Let’s have a look at the internal structure of ID3v1:

Internal layout of an ID3v1 tagged file.

Internal layout of an ID3v1 tagged file.

At the description at original page about ID3v1,

Song Title 30 characters
Artist 30 characters
Album 30 characters
Year 4 characters
Comment 30 characters
Genre 1 byte

If you one sum the the size of all these fields we see that 30+30+30+4+30+1 equals 125 bytes and not 128 bytes. The missing three bytes can be found at the very beginning of the tag, before the song title. These three bytes are always “TAG” and is the identification that this is indeed a ID3 tag. The easiest way to find a ID3v1/1.1 tag is to look for the word “TAG” 128 bytes from the end of a file. ” – Quoted from ID3.org

Another pages on MP3 internal:

+ http://www.multiweb.cz/twoinches/mp3inside.htm

+ http://www.fortunecity.com/underworld/sonic/3/id3tag.html

So we can easily extract any MP3 file tag information by parsing its very last 128 bytes (128 bytes at the end).

Once again, I open the song in a hex editor:

Hex Editor: MP3 Binary Format

Hex Editor: MP3 Binary Format

That’s right, the info is there!

Generally, instead of reading MP3 file header structure at beginning, we can use the very last 128 bytes to extract its basic info. Interesting, isn’t it?

We’re gonna make a library to query MP3 basic info using Java on Android in next article 🙂

Just take a cup of coffee and enjoy the song “….give me reason …. connect the space between …” , lol :))

 

Cheers,

Pete Houston

 

Categories: Tutorials Tags: , , , , ,

Image Processing – Image Flipping / Mirroring

June 26, 2011 4 comments

This technique is basically same as rotation, however, it transforms rotation with a reverse direction.

– For vertical flipping: [ x = x, y = y * -1 ]

– For horizontal flipping: [ x = x * -1, y = y ]

By using matrix transformation, we’ll get nice results:

Original Image

Original Image

Vertical Flipping

Vertical Flipping

Horizontal Flipping

Horizontal Flipping

Here the implementation:

	// type definition
	public static final int FLIP_VERTICAL = 1;
	public static final int FLIP_HORIZONTAL = 2;

	public static Bitmap flip(Bitmap src, int type) {
		// create new matrix for transformation
		Matrix matrix = new Matrix();
		// if vertical
		if(type == FLIP_VERTICAL) {
			// y = y * -1
			matrix.preScale(1.0f, -1.0f);
		}
		// if horizonal
		else if(type == FLIP_HORIZONTAL) {
			// x = x * -1
			matrix.preScale(-1.0f, 1.0f);
		// unknown type
		} else {
			return null;
		}

		// return transformed image
		return Bitmap.createBitmap(src, 0, 0, src.getWidth(), src.getHeight(), matrix, true);
	}

Hope you like it!

Cheers,
Pete Houston

Create and use emulated SD Card

June 26, 2011 16 comments

SD card is an external storage for mobile device, by default, it is not available in Android Emulator. What you need  to do is to create an emulated SD card for your Android Emulator.

1. Creating SD Card

Access to your Android SDK Tools folder and use command “mksdcard” in order to create one.

By default installation on Windows, the Tools folder should be here:

C:\Program Files\Android\android-sdk\tools

Using following syntax to create your desired SD Card

mksdcard [memory size] [output file]

For example, I’d like to create a SD card with 256 MB in memory and put the files in C:\Personel\AndroidNewbie\SDCard with file named “sdcard_dev.iso“, I do like this:

mksdcard 256M C:\Personel\AndroidNewbie\SDCard\sdcard_dev.iso

2. Using SD Card

You’ve done creating your desired SD Card, now you need it to be used by Android emulator. Open Eclipse, access to your project.

On menu Run -> Run Configurations, click on Android Configuration on the left tree menu, click on tab Target on the right pane. You will see at the bottom: “Additional Emulator Commandline Options” and an Input/Edit box below:

Just type your input sdcard following syntax

-sdcard [sdcard location]

For example, with the SD Card I’ve created above, I type:

-sdcard C:\Personel\AndroidNewbie\SDCard\sdcard_dev.iso

 

SD Card Settings

SD Card Settings

Now just run your emulator, you can access to your created SD Card.

 

Another way to run your Emulator with SDCard:

+ Open AVD Manager, click on the device you want to run with SDCard automatically, click on button Edit on the right menu. A setting dialog appears and just browse to your desired SDCard image:

SD Card Settings

SD Card Settings

 

3. Browse SD Card

There are many ways to browse SD Card, however, I will just tell you two common ways:

a. In Eclipse, open DDMS Perspective, and open File Explorer view, you can browse /sdcard directory.

In this mode, you can drag and drop files.

b. Using commandline, go to adb shell by typing:

adb -e shell

Then access to /sdcard directory by typing:

# cd /sdcard

You can use push/pull from adb shell to put files into sdcard or get files from it.

It’s quite handy-some, isn’t it?

Happy Android!

Cheers,

Pete Houston

Categories: Tutorials Tags: , ,

Insert image to database

June 25, 2011 7 comments

In order to insert an image into SQLite database, you might need to use BLOB type, which stores binary data (it is, byte array).

Creating a database table:

CREATE TABLE tbl_image (
    _id INTEGER PRIMARY KEY AUTOINCREMENT,
    image_data BLOB
);

– Before inserting into database, you need to convert your BItmap image into byte array first then apply it using database query.

Please look at my previous post on “SQLite on Android” and “Create and Use custom Content Provider” for references.

For example, when I insert image using Database adapter:

	public long insert(byte[] image) {
		return mDb.insert(TABLE_NAME, null, createContentValues(image));
	}

	private ContentValues createContentValues(byte[] image) {
		ContentValues cv = new ContentValues();
		cv.put(COL_DATA, image);
		return cv;
	}

– When retrieving from database, you certainly have a byte array of image, what you need to do is to convert byte array back to original image. So, you have to make use of BitmapFactory to decode.

This is how I do encoding and decoding between byte array and bitmap:

package pete.android.study;

import java.io.ByteArrayOutputStream;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Bitmap.CompressFormat;

public class Utilities {

	// convert from bitmap to byte array
	public static byte[] getBytes(Bitmap bitmap) {
		ByteArrayOutputStream stream = new ByteArrayOutputStream();
		bitmap.compress(CompressFormat.PNG, 0, stream);
		return stream.toByteArray();
	}

	// convert from byte array to bitmap
	public static Bitmap getImage(byte[] image) {
		return BitmapFactory.decodeByteArray(image, 0, image.length);
	}
}

This is the sample project in which will insert an image to database and display to screen after querying it.

Sample Project

Sample Project

Get project here: Browse Sample Project

Well, hope you like it!

 

Cheers,

Pete Houston

Categories: Tutorials Tags: , , ,

Image Processing – Watermarking On The Fly

June 23, 2011 13 comments

Having a little free time, I’ve just been digging on this technique. A little trick with canvas and drawing, I’ve got an image with watermark, so cool!!!

This is how it looks:

Image w/ Watermark

Image w/ Watermark

Here the implementation:

	public static Bitmap mark(Bitmap src, String watermark, Point location, Color color, int alpha, int size, boolean underline) {
		int w = src.getWidth();
		int h = src.getHeight();
		Bitmap result = Bitmap.createBitmap(w, h, src.getConfig());

		Canvas canvas = new Canvas(result);
		canvas.drawBitmap(src, 0, 0, null);

		Paint paint = new Paint();
		paint.setColor(color);
		paint.setAlpha(alpha);
		paint.setTextSize(size);
		paint.setAntiAlias(true);
		paint.setUnderlineText(underline);
		canvas.drawText(watermark, location.x, location.y, paint);

		return result;
	}

Hope you like it!

Cheers,
Pete Houston