Вы находитесь на странице: 1из 77

Android Application Development Training Tutorial

For more info visit http://www.zybotech.in

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

Creating Lists Using The Android ListActivity


Introduction
ListViews are used to create views with lists of data in Android applications. Lists can be populated with data from android data sources with cursors or with simple arrays. Custom views can be applied to Lists applying formatting including checkboxes and icons. Create new project called TestListActivities.

Basic ListActivity Usage


Layout
To create a visible list there are some specific elements that need to exist in the layout. The first is a ListView node with the android:id of "@android:id/list". This will be where the list is displayed in the view. The second one is a TextView with the android:id of "@android:id/empty". This second one will be displayed if the list is empty.
<?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" > <ListView android:id="@android:id/list" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <TextView android:id="@android:id/empty" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Empty set" /> </LinearLayout>

Here we just contain the list in a simple LinearLayout.

Java
package com.higherpass.android.widgets.test; import android.app.ListActivity; import android.os.Bundle; import android.widget.ArrayAdapter; public class TestListActivities extends ListActivity { String[] listItems = {"exploring", "android", "list", "activities"}; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main);

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

setListAdapter(new ArrayAdapter(this, android.R.layout.simple_list_item_1, listItems)); } }

Instead of using an Activity we use a ListActivity to extend our main class from. The string array listItems contain the text that will populate the list. As with other activities the onCreate() method is used and the first thing that should be done is call super.onCreate. Next set the main.xml file as the layout to display with setContentView(R.layout.main). The last thing to do is to populate the list. To populate the list you need to create an ArrayAdapter and pass it to setListAdapter(). ArrayAdapters manage the ListView objects managed by an internal array. The ArrayAdapter constructor expects 3 parameters, the current class instance (this), The display layout to use for each list item, and the array of items respectively. Android comes with a few built-in layouts available under android.R.layout. We used android.R.layout.simple_list_item_1 which displays a single string.

Attaching a Cursor
The CursorAdapter class allows standard Android cursors to be used to populate a ListView. This provides a simple interface to present database data to the user. See the Android cursor tutorial for more information on cursors. Android comes with a bundled ListAdapter for cursors called BasicCursorAdapter To demonstrate using cursors with lists we're going to query the browser bookmarks. For this example we need to grant access to the browser bookmarks in the AndroidManifest.xml file by adding the following line after the uses-sdk statement.
<uses-permission android:name="com.android.browser.permission.READ_HISTORY_BOOKMARKS" /> <uses-permission android:name="com.android.broswer.permission.WRITE_HISTORY_BOOKMARKS" />

This simply grants read and write access to the browser bookmarks and history.
package com.higherpass.android.widgets.test; import import import import import import android.app.ListActivity; android.database.Cursor; android.media.MediaPlayer; android.os.Bundle; android.provider.Browser; android.provider.Settings;

import android.provider.MediaStore.Audio.Media; import android.widget.SimpleCursorAdapter; public class TestListActivities extends ListActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); String[] projection = new String[] {Browser.BookmarkColumns._ID, Browser.BookmarkColumns.TITLE, Browser.BookmarkColumns.URL};

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

String[] displayFields = new String[] {Browser.BookmarkColumns.TITLE, Browser.BookmarkColumns.URL}; int[] displayViews = new int[] { android.R.id.text1, android.R.id.text2 }; Cursor cur = managedQuery(android.provider.Browser.BOOKMARKS_URI, projection, null, null, null); setListAdapter(new SimpleCursorAdapter(this, android.R.layout.simple_list_item_2, cur, displayFields, displayViews)); } }

Basing a List off a cursor is very similar to using an array as before. A few things do need to be setup though. First create a string array called projection populated with Android SDK constants for the database columns that we want to retrieve. Next create a string array called displayFields which holds the fields that will be displayed in the view. The displayFields works with the displayColumns integer array that will tell the view where to place the data from the cursor. The order of the displayFields and displayColumns arrays are important. The positions of each array relate what data gets placed into each view element. In this case the bookmark title goes into the text1 field and the URL goes into the text2 field. Next create the cursor. For simplicity we're just going to pass the URI of the database and the fields we want to retrieve to the managedQuery that creates the cursor. See cursor article for more information on cursors. Finally create a SimpleCursorAdapter. Similar to the ArayAdapter the first parameter is the current class instance (this). Now pass the autogenerated R variable that corresponds to the view for the row. In this example we used android.R.layout.simple_list_item_2. This is a small preview to the next thing we're going to cover, Customizing the list item display. The android.R.layout.simple_list_item_2 layout is built in to the Android SDK. It has 2 internal TextViews one with large text, followed by one with smaller text below. The third parameter to the SimpleCursorAdapter constructor is the cursor itself. Fourth pass the displayFields string array and finally pass the displayViews.

Creating Lists Using The Android ListActivity


Introduction
ListViews are used to create views with lists of data in Android applications. Lists can be populated with data from android data sources with cursors or with simple arrays. Custom views can be applied to Lists applying formatting including checkboxes and icons. Create new project called TestListActivities.

Basic ListActivity Usage


Layout
To create a visible list there are some specific elements that need to exist in the layout. The first is a ListView node with the android:id of "@android:id/list". This will be where the list is displayed in the view. The second one is a TextView with the android:id of "@android:id/empty". This second one will be displayed if the list is empty.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <ListView android:id="@android:id/list" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <TextView android:id="@android:id/empty" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Empty set" /> </LinearLayout>

Here we just contain the list in a simple LinearLayout.

Java
package com.higherpass.android.widgets.test; import android.app.ListActivity; import android.os.Bundle; import android.widget.ArrayAdapter; public class TestListActivities extends ListActivity { String[] listItems = {"exploring", "android", "list", "activities"}; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); setListAdapter(new ArrayAdapter(this, android.R.layout.simple_list_item_1, listItems)); } }

Instead of using an Activity we use a ListActivity to extend our main class from. The string array listItems contain the text that will populate the list. As with other activities the onCreate() method is used and the first thing that should be done is call super.onCreate. Next set the main.xml file as the layout to display with setContentView(R.layout.main). The last thing to do is to populate the list. To populate the list you need to create an ArrayAdapter and pass it to setListAdapter(). ArrayAdapters manage the ListView objects managed by an internal array. The ArrayAdapter constructor expects 3 parameters, the current class instance (this), The display layout to use for each list item, and the array of items respectively. Android comes with a few built-in layouts available under android.R.layout. We used android.R.layout.simple_list_item_1 which displays a single string.

Attaching a Cursor
The CursorAdapter class allows standard Android cursors to be used to populate a ListView. This provides a simple interface to present database data to the user. See the Android cursor tutorial for more information on
A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

cursors. Android comes with a bundled ListAdapter for cursors called BasicCursorAdapter To demonstrate using cursors with lists we're going to query the browser bookmarks. For this example we need to grant access to the browser bookmarks in the AndroidManifest.xml file by adding the following line after the uses-sdk statement.
<uses-permission android:name="com.android.browser.permission.READ_HISTORY_BOOKMARKS" /> <uses-permission android:name="com.android.broswer.permission.WRITE_HISTORY_BOOKMARKS" />

This simply grants read and write access to the browser bookmarks and history.
package com.higherpass.android.widgets.test; import import import import import import android.app.ListActivity; android.database.Cursor; android.media.MediaPlayer; android.os.Bundle; android.provider.Browser; android.provider.Settings;

import android.provider.MediaStore.Audio.Media; import android.widget.SimpleCursorAdapter; public class TestListActivities extends ListActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); String[] projection = new String[] {Browser.BookmarkColumns._ID, Browser.BookmarkColumns.TITLE, Browser.BookmarkColumns.URL}; String[] displayFields = new String[] {Browser.BookmarkColumns.TITLE, Browser.BookmarkColumns.URL}; int[] displayViews = new int[] { android.R.id.text1, android.R.id.text2 }; Cursor cur = managedQuery(android.provider.Browser.BOOKMARKS_URI, projection, null, null, null); setListAdapter(new SimpleCursorAdapter(this, android.R.layout.simple_list_item_2, cur, displayFields, displayViews)); } }

Basing a List off a cursor is very similar to using an array as before. A few things do need to be setup though. First create a string array called projection populated with Android SDK constants for the database columns that we want to retrieve. Next create a string array called displayFields which holds the fields that will be displayed in the view. The displayFields works with the displayColumns integer array that will tell the view where to place the data from the cursor. The order of the displayFields and displayColumns arrays are important. The positions of each array relate what data gets placed into each view element. In this case the bookmark title goes into the text1 field and the URL goes into the text2 field.

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

Next create the cursor. For simplicity we're just going to pass the URI of the database and the fields we want to retrieve to the managedQuery that creates the cursor. See cursor article for more information on cursors. Finally create a SimpleCursorAdapter. Similar to the ArayAdapter the first parameter is the current class instance (this). Now pass the autogenerated R variable that corresponds to the view for the row. In this example we used android.R.layout.simple_list_item_2. This is a small preview to the next thing we're going to cover, Customizing the list item display. The android.R.layout.simple_list_item_2 layout is built in to the Android SDK. It has 2 internal TextViews one with large text, followed by one with smaller text below. The third parameter to the SimpleCursorAdapter constructor is the cursor itself. Fourth pass the displayFields string array and finally pass the displayViews.

Creating Lists Using The Android ListActivity


Custom Row elements
As you just saw in the cursor example the list items can be customized. Some of the common customizations are formatting text display, adding icons, and checkboxes. To customize text layout we'll simply create a new layout, but adding custom icons and checkboxes require more work.

Formatting and arranging text


Right click on res/layouts/ select New > android XML file. Set the file name to text_list.xml then select the root element as a LinearLayout and click finish.
<?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" > <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent"*** android:orientation="horizontal" > <TextView android:id="@+id/bmark_visits" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:id="@+id/bmark_title" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout> <TextView android:id="@+id/bmark_url" android:layout_width="fill_parent" android:layout_height="wrap_content" /> </LinearLayout>

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

This nested LinearLayout creates a base to create a list that displays bookmark information. The outer LinearLayout is set to a vertical orientation and has a nested LinearLayout element that stores the top line followed by a TextView containing the URL. The nested LinearLayout contains the top line of the list element that contains the number of visits to the URL and the bookmark title. Now we need to go back and edit the java in TestListActivities.java.
package com.higherpass.android.widgets.test; import import import import import android.app.ListActivity; android.database.Cursor; android.os.Bundle; android.provider.Browser; android.widget.SimpleCursorAdapter;

public class TestListActivities extends ListActivity { String[] listItems = {"exploring", "android", "list", "activities"}; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); String[] projection = new String[] {Browser.BookmarkColumns._ID, Browser.BookmarkColumns.TITLE, Browser.BookmarkColumns.URL, Browser.BookmarkColumns.VISITS}; String[] displayFields = new String[] {Browser.BookmarkColumns.VISITS, Browser.BookmarkColumns.TITLE, Browser.BookmarkColumns.URL}; int[] displayViews = new int[] { R.id.bmark_visits, R.id.bmark_title, R.id.bmark_url}; Cursor cur = managedQuery(android.provider.Browser.BOOKMARKS_URI, projection, null, null, null); setListAdapter(new SimpleCursorAdapter(this, R.layout.text_list, cur, displayFields, displayViews )); } }

There are a few key changes we make to the earlier code. First add the Browser.BookmarkColumns.VISITS to the projection field and adjust the displayFields and displayViews string arrays as shown. This will set the SimpleCursorAdapter to map the data to the new layout. Next adjust the layout that is passed into the SimpleCursorAdapter to the one we just created, R.layout.text_list. Now the list will be displayed with the custom view applied.

Creating Lists Using The Android ListActivity


Iconifying the list
Pictures and other graphics can also be added to the list items. This takes even more work though. We will need to extend the SimpleCursorAdapter so that the getView method can be overridden. First though, create a new
A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

android xml file in res/layouts/ called image_list.xml with a root element of LinearLayout to hold the list item 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="wrap_content" android:orientation="horizontal"> <ImageView android:id="@+id/bimage" android:layout_height="22px" android:layout_width="22px" android:src="@drawable/icon" /> <TextView android:id="@+id/btitle" android:layout_width="fill_parent" android:layout_height="wrap_content"/> </LinearLayout>

This simple linear layout will be used to display each list element. The ImageView element will be used to display the favicon for the bookmark if one is stored. If one isn't stored the default application icon will be displayed. The src component was set to the icon. In the code below we'll change the image to the favicon if one exists. The TextView component will be used to hold the title of the bookmark. Now we need to extend SimpleCursorAdapter. Create a new class called ImageCursorAdapter in the same source package as TestListActivities.java. The new class should extend android.widget.SimpleCursorAdapter.
package com.higherpass.android.widgets.test; import import import import import import import import import import android.content.Context; android.database.Cursor; android.graphics.BitmapFactory; android.provider.Browser; android.view.LayoutInflater; android.view.View; android.view.ViewGroup; android.widget.ImageView; android.widget.SimpleCursorAdapter; android.widget.TextView;

public class ImageCursorAdapter extends SimpleCursorAdapter { private Cursor c; private Context context; public ImageCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to) { super(context, layout, c, from, to); this.c = c; this.context = context; } public View getView(int pos, View inView, ViewGroup parent) { View v = inView; if (v == null) {

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); v = inflater.inflate(R.layout.image_list, null); } this.c.moveToPosition(pos); String bookmark = this.c.getString(this.c.getColumnIndex(Browser.BookmarkColumns.TITLE)); byte[] favicon = this.c.getBlob(this.c.getColumnIndex(Browser.BookmarkColumns.FAVICON)); if (favicon != null) { ImageView iv = (ImageView) v.findViewById(R.id.bimage); iv.setImageBitmap(BitmapFactory.decodeByteArray(favicon, 0, favicon.length)); } TextView bTitle = (TextView) v.findViewById(R.id.btitle); bTitle.setText(bookmark); return(v); } }

The ImageCursorAdapter class extends the SimpleCursorAdapter class so that we can override the getView() method. This will allow us to customize the ListView rows. First though we need to create the constructor. The constructor, public ImageCursorAdapter(), expects 5 paramters. They are the context, the layout resource to use, the cursor with the data, and field to view element mapping arrays respectively in 4 and 5. The cursor will then pass the parameters to the constructor for SimpleCursorAdapter with the super() method. Now override the getView() method from SimpleCursorAdapter. The getView() method expects 3 parameters, the position in the list/cursor, the view, and the parent. If a view wasn't provided to the getView() method use the LayoutInflater to create the view from the layout. Next move the cursor pointer to the correct position. For more information about using cursors see Using Cursors In Android Tutorial. Get the title of the bookmark and store it in the string bookmark. The favicon is stored as a blob in the SQLite database. The cursor function getBlob() will properly retrieve the data from the cursor and return it as a byte array. This is good because we can use the byte array to create our bitmap for the image. If the favicon value isn't null then there was an icon stored in the database. Extract the ImageView component from the view. Now use the BitmapFactory to create a bitmap from the byte array and set it as the ImageView image with setImageBitmap. For more information on images see the Android Image Tutorial. Finally set the title TextView and return the view.

Creating Lists Using The Android ListActivity


Using Checkboxes
Creating checked lists is similar to creating the image list on the previous page. A custom layout will need to be created and the SimpleCursorAdapter class will need to be extended to override getView(). Create a new xml file in res/layout/ called check_list.xml. This will hold the checked list layout.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent"

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

android:layout_height="wrap_content" android:orientation="horizontal"> <CheckBox android:id="@+id/bcheck" android:layout_height="wrap_content" android:layout_width="wrap_content" /> </LinearLayout>

This is a simple LinearLayout although the only component is the CheckBox element with the id of bcheck. CheckBox elements are really a view themselves. They consist of the checkbox and a TextView component to the right. This makes using checkboxes very easy as the code below will show. Create a new class in the project called CheckboxCursorAdapter that extends android.widget.SimpleCursorAdapter.
package com.higherpass.android.widgets.test; import java.util.ArrayList; import import import import import import import import import import android.content.Context; android.database.Cursor; android.provider.Browser; android.view.LayoutInflater; android.view.View; android.view.View.OnClickListener; android.view.ViewGroup; android.widget.CheckBox; android.widget.SimpleCursorAdapter; android.widget.TextView;

public class CheckboxCursorAdapter extends SimpleCursorAdapter { private Cursor c; private Context context; private ArrayList<Integer> checkList = new ArrayList<Integer>(); public CheckboxCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to) { super(context, layout, c, from, to); this.c = c; this.context = context; } public View getView(int pos, View inView, ViewGroup parent) { View v = inView; if (v == null) { LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); v = inflater.inflate(R.layout.check_list, null); } this.c.moveToPosition(pos); String bookmark = this.c.getString(this.c.getColumnIndex(Browser.BookmarkColumns.TITLE)); CheckBox cBox = (CheckBox) v.findViewById(R.id.bcheck); cBox.setTag(Integer.parseInt(this.c.getString(this.c.getColumnIndex(Browser.Bookma rkColumns._ID))));

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

cBox.setText(bookmark); if (Integer.parseInt(this.c.getString(this.c.getColumnIndex(Browser.BookmarkColumns._ID))) % 2 != 0) { cBox.setChecked(true); } return(v); } }

The CheckboxCursorAdapter class has a simple constructor just like the ImageCursorAdapter. The constructor just needs to pass the data into the SimpleCursorAdapter constructor. The getView() method is very similar to before as well. If the passed view is null we need to use the LayoutInflater to create a view from the layout we created in check_list.xml. Then move the cursor to the correct position in the list and populate the data into the correct parts of the view. Use the cBox.setText() method to set the text of the checkbox. To check the checkbox by default use the setChecked() function to set the checked state. In this example the checkbox defaults as checked to all items with an odd database ID in the list. A few modifications are needed to TestListActivities to reflect the checked list.
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); String[] projection = new String[] {Browser.BookmarkColumns._ID, Browser.BookmarkColumns.TITLE}; String[] displayFields = new String[] {Browser.BookmarkColumns.TITLE}; int[] displayViews = new int[] {R.id.btitle}; Cursor cur = managedQuery(android.provider.Browser.BOOKMARKS_URI, projection, null, null, null); setListAdapter(new CheckboxCursorAdapter(this, R.layout.check_list, cur, displayFields, displayViews )); }

Creating Lists Using The Android ListActivity


Adding Actions
To demonstrate actions we're going to add the capability to manage a list of checked items to CheckboxCursorAdapter. Actions are handled with listeners, we're going to use an onClickListener. The onClickListener should be attached to the checkbox in getView(). All that's needed is creating a creating an ArrayList to hold the checked list, create the onClickListener() to manage the list, and set the list position into the checkbox tag field for use in the list. The list needs a unique ID for each element in the list that we can store in the ArrayList to manage what is checked. To do this we store the list position into the checkbox tag with setTag(). In getView() create and
A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

attach an onClickListener() to the checkbox element, cBox. The onClickListener() expects a class that contains public void method onClick(). The onClickListener() will pass the View element that was clicked into the onClick() method. The onClick() function needs to get the value from the checkbox tag with getTag(). Then if the checkbox was clicked add the position stored in the tag into the ArrayList. And if the checkbox was unchecked remove the tag from the ArrayList.
package com.higherpass.android.widgets.test; import java.util.ArrayList; import import import import import import import import import import android.content.Context; android.database.Cursor; android.provider.Browser; android.view.LayoutInflater; android.view.View; android.view.View.OnClickListener; android.view.ViewGroup; android.widget.CheckBox; android.widget.SimpleCursorAdapter; android.widget.TextView;

public class CheckboxCursorAdapter extends SimpleCursorAdapter { private Cursor c; private Context context; private ArrayList<String> checkList = new ArrayList<String>(); public CheckboxCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to) { super(context, layout, c, from, to); this.c = c; this.context = context; } public View getView(int pos, View inView, ViewGroup parent) { View v = inView; if (v == null) { LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); v = inflater.inflate(R.layout.check_list, null); } this.c.moveToPosition(pos); String bookmark = this.c.getString(this.c.getColumnIndex(Browser.BookmarkColumns.TITLE)); CheckBox cBox = (CheckBox) v.findViewById(R.id.bcheck); cBox.setTag(pos); cBox.setText(bookmark); if (Integer.parseInt(this.c.getString(this.c.getColumnIndex(Browser.BookmarkColumns._ID))) % 2 != 0) { cBox.setChecked(true); checkList.add((String) cBox.getTag()); } cBox.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { CheckBox cBox = (CheckBox) v.findViewById(R.id.bcheck); if (cBox.isChecked()) { //cBox.setChecked(false); checkList.add((String) cBox.getTag());

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

} else if (!cBox.isChecked()) { //cBox.setChecked(true); checkList.remove(cBox.getTag()); } } }); return(v); } }

No other changes are required other than the additions to CheckboxCursorAdapter to enable the onClickListener. This should be enough to get you started building and presenting lists in Android applications.

Working With Android Contacts


Introduction To Android Contacts
Learn to work with the Android contacts database. Basic knowledge of accessing SQLite in Android along with using Cursors is expected. See the Android SQLite and Cursor Article for more information. Google changed the contacts database moving from 1.x to 2.0 versions of Android. This tutorial will be broken into 3 sections. First covering accessing contacts in Android 2.0. The second page will deal with accessing the contacts in Android 1.6 and before. Third we'll glue it all together with a class that abstracts specific classes for each version and a set of classes to manage the data from the contact records. Create a new project called TestContacts in Eclipse setup for Android 2.0.

Android Contact API For 2.0

Granting Access
Before an application can query the contact records access must be granted through the AndroidManifest.xml file stored in the root of the project. Add the following uses-permission belows the uses-sdk statement.
<uses-permission android:name="android.permission.READ_CONTACTS" />

Querying The Android Contact Database


Retrieving Contact Details

Basic contact information stored in Contacts table with detailed information stored in individual tables for normalization. In Android 2.0 to query the base contact records the URI to query is stored in ContactsContract.Contacts.CONTENT_URI.
package higherpass.TestContacts; import android.app.Activity; import android.content.ContentResolver; import android.database.Cursor;

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

import android.os.Bundle; import android.provider.ContactsContract; public class TestContacts extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); ContentResolver cr = getContentResolver(); Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null); if (cur.getCount() > 0) { while (cur.moveToNext()) { String id = cur.getString( cur.getColumnIndex(ContactsContract.Contacts._ID)); String name = cur.getString( cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)); if (Integer.parseInt(cur.getString(cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NU MBER))) > 0) { //Query phone here. Covered next } } } } }

This application starts off as any other Android application. First create a ContentResolver isntance in cr. Then use the ContentResolver instance to query the database and return a Cursor with the contacts list. The query is perofrmed against the URI stored in ContactsContract.Contacts.CONTENT_URI. Next check if the cursor contains records and if so loop through them. The record ID field is stored in the id variable. This will be used as a where parameter later. Also the display name field is stored in the string name. For more details about working with cursors see Android Cursors Tutorial.
Phone Numbers

Phone numbers are stored in their own table and need to be queried separately. To query the phone number table use the URI stored in the SDK variable ContactsContract.CommonDataKinds.Phone.CONTENT_URI. Use a WHERE conditional to get the phone numbers for the specified contact.
if (Integer.parseInt(cur.getString( cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))) > 0) { Cursor pCur = cr.query( ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = ?", new String[]{id}, null); while (pCur.moveToNext()) { // Do something with phones } pCur.close(); }

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

Perform a second query against the Android contacts SQLite database. The phone numbers are queried against the URI stored in ContactsContract.CommonDataKinds.Phone.CONTENT_URI. The contact ID is stored in the phone table as ContactsContract.CommonDataKinds.Phone.CONTACT_ID and the WHERE clause is used to limit the data returned.
Email Addresses

Querying email addresses is similar to phone numbers. A query must be performed to get email addresses from the database. Query the URI stored in ContactsContract.CommonDataKinds.Email.CONTENT_URI to query the email address table.
Cursor emailCur = cr.query( ContactsContract.CommonDataKinds.Email.CONTENT_URI, null, ContactsContract.CommonDataKinds.Email.CONTACT_ID + " = ?", new String[]{id}, null); while (emailCur.moveToNext()) { // This would allow you get several email addresses // if the email addresses were stored in an array String email = emailCur.getString( emailCur.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA)); String emailType = emailCur.getString( emailCur.getColumnIndex(ContactsContract.CommonDataKinds.Email.TYPE)); } emailCur.close();

As with the phone query the field names for the email table are also stored under ContactsContract.CommonDataKinds. The email query is performed on the URI in ContactsContract.CommonDataKinds.Email.CONTENT_URI and the WHERE clause has to match the ContactsContract.CommonDataKinds.Email.CONTACT_ID field. Since multiple email addresses can be stored loop through the records returned in the Cursor.
Notes

Custom notes can be attached to each contact record. As before these are stored in a separate table and are related based on the contact ID.
String noteWhere = ContactsContract.Data.CONTACT_ID + " = ? AND " + ContactsContract.Data.MIMETYPE + " = ?"; String[] noteWhereParams = new String[]{id, ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE}; Cursor noteCur = cr.query(ContactsContract.Data.CONTENT_URI, null, noteWhere, noteWhereParams, null); if (noteCur.moveToFirst()) { String note = noteCur.getString(noteCur.getColumnIndex(ContactsContract.CommonDataKinds.Note.NOTE)); } noteCur.close();

Notes are stored in the Android Contacts generic data table. When accessing specific data the WHERE clause will need 2 conditionals. First the standard contact ID, second a MIMETYPE for the data that is being
A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

requested. The Android SDK comes with a series of auto-generated variables that take care of this. Use the ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE variable to limit the query to note records. The data table URI is stored at ContactsContract.Data.CONTENT_URI. Finally the note field name is stored in ContactsContract.CommonDataKinds.Note.NOTE.
Postal Addresses

Android can store multiple postal addresses per contact. Addresses are also stored in the data table like notes and queried via the URI stored in ContactsContract.Data.CONTENT_URI. Similar to the notes query a MIMETYPE must be added to the WHERE conditional. Also in Android 2.0 the Address record was split into multiple fields containing different parts of the address (PO-Box, stree, city, region, postal code). In earlier versions of the Android SDK this was a free-form string storage.
String addrWhere = ContactsContract.Data.CONTACT_ID + " = ? AND " + ContactsContract.Data.MIMETYPE + " = ?"; String[] addrWhereParams = new String[]{id, ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE}; Cursor addrCur = cr.query(ContactsContract.Data.CONTENT_URI, null, where, whereParameters, null); while(addrCur.moveToNext()) { String poBox = addrCur.getString( addrCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.POBOX)); String street = addrCur.getString( addrCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.STREET)); String city = addrCur.getString( addrCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.CITY)); String state = addrCur.getString( addrCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.REGION)); String postalCode = addrCur.getString( addrCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.POSTCODE)); String country = addrCur.getString( addrCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY)); String type = addrCur.getString( addrCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.TYPE)); } addrCur.close();

This code is similar to the previous example. Notice the field names for the address pieces are stored in ContactsContract.CommonDataKinds.StructuredPostal.
Instant Messenger (IM)

The instant messenger query performs just as the notes and address queries. Important field names for IM related data are stored in ContactsContract.CommonDataKinds.Im.
String imWhere = ContactsContract.Data.CONTACT_ID + " = ? AND " + ContactsContract.Data.MIMETYPE + " = ?"; String[] imWhereParams = new String[]{id,

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE}; Cursor imCur = cr.query(ContactsContract.Data.CONTENT_URI, null, imWhere, imWhereParams, null); if (imCur.moveToFirst()) { String imName = imCur.getString( imCur.getColumnIndex(ContactsContract.CommonDataKinds.Im.DATA)); String imType; imType = imCur.getString( imCur.getColumnIndex(ContactsContract.CommonDataKinds.Im.TYPE)); } imCur.close();

Organizations

The last part of the contact record to be covered is the Organizations data. The Android contact record can contain information about Employment, professional, and social memberships as well as roles and titles. These records are queried from the URI stored in ContactsContract.Data.CONTENT_URI. Important field names for the organization data are stored in ContactsContract.CommonDataKinds.Organization.
String orgWhere = ContactsContract.Data.CONTACT_ID + " = ? AND " + ContactsContract.Data.MIMETYPE + " = ?"; String[] orgWhereParams = new String[]{id, ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE}; Cursor orgCur = cr.query(ContactsContract.Data.CONTENT_URI, null, orgWhere, orgWhereParams, null); if (orgCur.moveToFirst()) { String orgName = orgCur.getString(orgCur.getColumnIndex(ContactsContract.CommonDataKinds.Organization.DATA )); String title = orgCur.getString(orgCur.getColumnIndex(ContactsContract.CommonDataKinds.Organization.TITL E)); } orgCur.close();

Working With Android Contacts


Introduction To Android Contacts
Learn to work with the Android contacts database. Basic knowledge of accessing SQLite in Android along with using Cursors is expected. See the Android SQLite and Cursor Article for more information. Google changed the contacts database moving from 1.x to 2.0 versions of Android. This tutorial will be broken into 3 sections. First covering accessing contacts in Android 2.0. The second page will deal with accessing the contacts in Android 1.6 and before. Third we'll glue it all together with a class that abstracts specific classes for each version and a set of classes to manage the data from the contact records. Create a new project called TestContacts in Eclipse setup for Android 2.0.

Android Contact API For 2.0

Granting Access

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

Before an application can query the contact records access must be granted through the AndroidManifest.xml file stored in the root of the project. Add the following uses-permission belows the uses-sdk statement.
<uses-permission android:name="android.permission.READ_CONTACTS" />

Querying The Android Contact Database


Retrieving Contact Details

Basic contact information stored in Contacts table with detailed information stored in individual tables for normalization. In Android 2.0 to query the base contact records the URI to query is stored in ContactsContract.Contacts.CONTENT_URI.
package higherpass.TestContacts; import import import import import android.app.Activity; android.content.ContentResolver; android.database.Cursor; android.os.Bundle; android.provider.ContactsContract;

public class TestContacts extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); ContentResolver cr = getContentResolver(); Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null); if (cur.getCount() > 0) { while (cur.moveToNext()) { String id = cur.getString( cur.getColumnIndex(ContactsContract.Contacts._ID)); String name = cur.getString( cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)); if (Integer.parseInt(cur.getString(cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NU MBER))) > 0) { //Query phone here. Covered next } } } } }

This application starts off as any other Android application. First create a ContentResolver isntance in cr. Then use the ContentResolver instance to query the database and return a Cursor with the contacts list. The query is perofrmed against the URI stored in ContactsContract.Contacts.CONTENT_URI. Next check if the cursor contains records and if so loop through them. The record ID field is stored in the id variable. This will be used as a where parameter later. Also the display name field is stored in the string name. For more details about working with cursors see Android Cursors Tutorial.

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

Phone Numbers

Phone numbers are stored in their own table and need to be queried separately. To query the phone number table use the URI stored in the SDK variable ContactsContract.CommonDataKinds.Phone.CONTENT_URI. Use a WHERE conditional to get the phone numbers for the specified contact.
if (Integer.parseInt(cur.getString( cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))) > 0) { Cursor pCur = cr.query( ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = ?", new String[]{id}, null); while (pCur.moveToNext()) { // Do something with phones } pCur.close(); }

Perform a second query against the Android contacts SQLite database. The phone numbers are queried against the URI stored in ContactsContract.CommonDataKinds.Phone.CONTENT_URI. The contact ID is stored in the phone table as ContactsContract.CommonDataKinds.Phone.CONTACT_ID and the WHERE clause is used to limit the data returned.
Email Addresses

Querying email addresses is similar to phone numbers. A query must be performed to get email addresses from the database. Query the URI stored in ContactsContract.CommonDataKinds.Email.CONTENT_URI to query the email address table.
Cursor emailCur = cr.query( ContactsContract.CommonDataKinds.Email.CONTENT_URI, null, ContactsContract.CommonDataKinds.Email.CONTACT_ID + " = ?", new String[]{id}, null); while (emailCur.moveToNext()) { // This would allow you get several email addresses // if the email addresses were stored in an array String email = emailCur.getString( emailCur.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA)); String emailType = emailCur.getString( emailCur.getColumnIndex(ContactsContract.CommonDataKinds.Email.TYPE)); } emailCur.close();

As with the phone query the field names for the email table are also stored under ContactsContract.CommonDataKinds. The email query is performed on the URI in ContactsContract.CommonDataKinds.Email.CONTENT_URI and the WHERE clause has to match the ContactsContract.CommonDataKinds.Email.CONTACT_ID field. Since multiple email addresses can be stored loop through the records returned in the Cursor.
A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

Notes

Custom notes can be attached to each contact record. As before these are stored in a separate table and are related based on the contact ID.
String noteWhere = ContactsContract.Data.CONTACT_ID + " = ? AND " + ContactsContract.Data.MIMETYPE + " = ?"; String[] noteWhereParams = new String[]{id, ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE}; Cursor noteCur = cr.query(ContactsContract.Data.CONTENT_URI, null, noteWhere, noteWhereParams, null); if (noteCur.moveToFirst()) { String note = noteCur.getString(noteCur.getColumnIndex(ContactsContract.CommonDataKinds.Note.NOTE)); } noteCur.close();

Notes are stored in the Android Contacts generic data table. When accessing specific data the WHERE clause will need 2 conditionals. First the standard contact ID, second a MIMETYPE for the data that is being requested. The Android SDK comes with a series of auto-generated variables that take care of this. Use the ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE variable to limit the query to note records. The data table URI is stored at ContactsContract.Data.CONTENT_URI. Finally the note field name is stored in ContactsContract.CommonDataKinds.Note.NOTE.
Postal Addresses

Android can store multiple postal addresses per contact. Addresses are also stored in the data table like notes and queried via the URI stored in ContactsContract.Data.CONTENT_URI. Similar to the notes query a MIMETYPE must be added to the WHERE conditional. Also in Android 2.0 the Address record was split into multiple fields containing different parts of the address (PO-Box, stree, city, region, postal code). In earlier versions of the Android SDK this was a free-form string storage.
String addrWhere = ContactsContract.Data.CONTACT_ID + " = ? AND " + ContactsContract.Data.MIMETYPE + " = ?"; String[] addrWhereParams = new String[]{id, ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE}; Cursor addrCur = cr.query(ContactsContract.Data.CONTENT_URI, null, where, whereParameters, null); while(addrCur.moveToNext()) { String poBox = addrCur.getString( addrCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.POBOX)); String street = addrCur.getString( addrCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.STREET)); String city = addrCur.getString( addrCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.CITY)); String state = addrCur.getString( addrCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.REGION)); String postalCode = addrCur.getString( addrCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.POSTCODE)); String country = addrCur.getString(

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

addrCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY)); String type = addrCur.getString( addrCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.TYPE)); } addrCur.close();

This code is similar to the previous example. Notice the field names for the address pieces are stored in ContactsContract.CommonDataKinds.StructuredPostal.
Instant Messenger (IM)

The instant messenger query performs just as the notes and address queries. Important field names for IM related data are stored in ContactsContract.CommonDataKinds.Im.
String imWhere = ContactsContract.Data.CONTACT_ID + " = ? AND " + ContactsContract.Data.MIMETYPE + " = ?"; String[] imWhereParams = new String[]{id, ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE}; Cursor imCur = cr.query(ContactsContract.Data.CONTENT_URI, null, imWhere, imWhereParams, null); if (imCur.moveToFirst()) { String imName = imCur.getString( imCur.getColumnIndex(ContactsContract.CommonDataKinds.Im.DATA)); String imType; imType = imCur.getString( imCur.getColumnIndex(ContactsContract.CommonDataKinds.Im.TYPE)); } imCur.close();

Organizations

The last part of the contact record to be covered is the Organizations data. The Android contact record can contain information about Employment, professional, and social memberships as well as roles and titles. These records are queried from the URI stored in ContactsContract.Data.CONTENT_URI. Important field names for the organization data are stored in ContactsContract.CommonDataKinds.Organization.
String orgWhere = ContactsContract.Data.CONTACT_ID + " = ? AND " + ContactsContract.Data.MIMETYPE + " = ?"; String[] orgWhereParams = new String[]{id, ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE}; Cursor orgCur = cr.query(ContactsContract.Data.CONTENT_URI, null, orgWhere, orgWhereParams, null); if (orgCur.moveToFirst()) { String orgName = orgCur.getString(orgCur.getColumnIndex(ContactsContract.CommonDataKinds.Organization.DATA )); String title = orgCur.getString(orgCur.getColumnIndex(ContactsContract.CommonDataKinds.Organization.TITL E)); } orgCur.close();

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

Working With Android Contacts


API For 1.6 and Before
If you just read the begining of this article the first bit of this page is going to look familiar. This page is designed to act as a standalone guide to working with the contacts API in Android 1.6 and before.

Granting Access
Before an application can query the contact records access must be granted through the AndroidManifest.xml file stored in the root of the project. Add the following uses-permission belows the uses-sdk statement.
<uses-permission android:name="android.permission.READ_CONTACTS" />

Querying the contact database


Retrieving Contact Details

Basic contact information stored in Contacts table with detailed information stored in individual tables for normalization. In Android 1.x to query the base contact records the URI to query is stored in People.CONTENT_URI.
package higherpass.TestContacts; import import import import import import android.app.Activity; android.content.ContentResolver; android.database.Cursor; android.os.Bundle; android.provider.Contacts; android.provider.Contacts.People;

public class TestContacts extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); ContentResolver cr = getContentResolver(); Cursor cur = cr.query(People.CONTENT_URI, null, null, null, null); if (cur.getCount() > 0) { while (cur.moveToNext()) { String id = cur.getString(cur.getColumnIndex(People._ID)); String name = cur.getString(cur.getColumnIndex(People.DISPLAY_NAME)); } } } }

Start off with the standard view loading. Then we create a ContentResolver instance that will be used to query the SQLite database that stores the contacts. The ContentResolver query returns a Cursor instance that holds the contact records queried from the database. Then take the ID field from the contact record and store it in the

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

string id and take the DISPLAY_NAME field and place it in the string name. For more information about cursors see the Android Cursor Tutorial.
Phone Numbers

Phone numbers are stored in their own table and need to be queried separately. To query the phone number table use the URI stored in the SDK variable Contacts.Phones.CONTENT_URI. Use a WHERE conditional to get the phone numbers for the specified contact.
if (Integer.parseInt(cur.getString( cur.getColumnIndex(People.PRIMARY_PHONE_ID))) > 0) { Cursor pCur = cr.query( Contacts.Phones.CONTENT_URI, null, Contacts.Phones.PERSON_ID +" = ?", new String[]{id}, null); int i=0; int pCount = pCur.getCount(); String[] phoneNum = new String[pCount]; String[] phoneType = new String[pCount]; while (pCur.moveToNext()) { phoneNum[i] = pCur.getString( pCur.getColumnIndex(Contacts.Phones.NUMBER)); phoneType[i] = pCur.getString( pCur.getColumnIndex(Contacts.Phones.TYPE)); i++; } }

Query the phones table and get a Cursor stored in pCur. Since the Android contacts database can store multiple phone numbers per contact we need to loop through the returned results. In addition to returning the phone number the query also returned the type of number (home, work, mobile, etc).
Email Addresses

Querying email addresses is similar to phone numbers. A special query must be performed to get email addresses from the database. Query the URI stored in Contacts.ContactMethods.CONTENT_EMAIL_URI to query the email addresses.
Cursor emailCur = cr.query( Contacts.ContactMethods.CONTENT_EMAIL_URI, null, Contacts.ContactMethods.PERSON_ID + " = ?", new String[]{id}, null); while (emailCur.moveToNext()) { // This would allow you get several email addresses } emailCur.close();

Simple query Contacts.ContactMethods.CONTENT_EMAIL_URI with a conditional limiting the results to numbers that match the ID of the contact record matches the value in the field Contacts.ContactMethods.PERSON_ID. As with phone numbers each contact can contain multiple email addresses so we need to loop through the Cursor records.
A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

Notes

Custom notes can be attached to each contact record. Notes though are stored in the main contact record and are simply accessed through the data stored in People.NOTES.
cur.getString(cur.getColumnIndex(People.NOTES));

Postal Addresses

Android can store multiple postal addresses per contact. Addresses are stored in the contact methods table and need to have a second conditional added to retrieve the data. Add a conditional Contacts.ContactMethods.KIND that matches Contacts.ContactMethods.CONTENT_POSTAL_ITEM_TYPE to only query postal addresses from Contacts.ContactMethods.CONTENT_URI.
String addrWhere = Contacts.ContactMethods.PERSON_ID + " = ? AND " + Contacts.ContactMethods.KIND + " = ?"; String[] addrWhereParams = new String[]{id, Contacts.ContactMethods.CONTENT_POSTAL_ITEM_TYPE}; Cursor addrCur = cr.query(Contacts.ContactMethods.CONTENT_URI, null, addrWhere, addrWhereParams, null); while(addrCur.moveToNext()) { String addr = addrCur.getString( addrCur.getColumnIndex(Contacts.ContactMethodsColumns.DATA)); String type = addrCur.getString( addrCur.getColumnIndex(Contacts.ContactMethodsColumns.TYPE)); } addrCur.close();

Query Contacts.ContactMethods.CONTENT_URI with 2 conditionals, one limiting the contact ID and the second Contacts.ContactMethods.KIND matching Contacts.ContactMethods.CONTENT_POSTAL_ITEM_TYPE to only query postall addresses. Android can store multiple postal addresses so loop through the list of returned results. Android also stores a type record for the address. In Android 1.6 and before the address is stored as a free-form string containing the data. In Android 2.0 and later this has changed to being a series of fields containing parts of the address.
Instant Messenger (IM)

The instant messenger query works just like the previous 2. The data is queried from Contacts.ContactMethods.CONTENT_URI and needs conditionals for the contact ID and Contacts.ContactMethods.KIND matching Contacts.ContactMethods.CONTENT_IM_ITEM_TYPE.
String imWhere = Contacts.ContactMethods.PERSON_ID + " = ? AND " + Contacts.ContactMethods.KIND + " = ?"; String[] imWhereParams = new String[]{id, Contacts.ContactMethods.CONTENT_IM_ITEM_TYPE}; Cursor imCur = cr.query(Contacts.ContactMethods.CONTENT_URI, null, imWhere, imWhereParams, null); if (imCur.moveToFirst()) { String imName = imCur.getString( imCur.getColumnIndex(Contacts.ContactMethodsColumns.DATA)); String imType = imCur.getString( imCur.getColumnIndex(Contacts.ContactMethodsColumns.TYPE)); } imCur.close();

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

Organizations

The last part of the contact record to be covered is the Organizations data. The Android contact record can contain information about Employment, professional, and social memberships as well as roles and titles. These records are queried from the URI stored in Contacts.Organizations.CONTENT_URI.
String orgWhere = Contacts.ContactMethods.PERSON_ID + " = ?"; String[] orgWhereParams = new String[]{id}; Cursor orgCur = cr.query(Contacts.Organizations.CONTENT_URI, null, orgWhere, orgWhereParams, null); if (orgCur.moveToFirst()) { String orgName = orgCur.getString( orgCur.getColumnIndex(Contacts.Organizations.COMPANY)); String title = orgCur.getString( orgCur.getColumnIndex(Contacts.Organizations.TITLE)); } orgCur.close();

Working With Android Contacts


Gluing it together
To put this together into an application there are a few glue pieces that need to be setup along with creating classes to manage accessing the data. First we need to create a set of classes to hold the data. Also we'll create a class to handle 2.0 API calls and a class to handle 1.6 and earlier API calls. There's also a wrapper class that determines and loads the proper class.

Contact Data Classes


The contact classes are a series of classes to hold a list of contacts. The list is stored in the class ContactList that maintains an ArrayList of Contacts. The Contact objects are represented in the Contact class. The contact class stores all the data from the Android contact record. In addition to the ContactList and Contact classes there are specialized classes to represent some of the record data. We will create classes to represent the address, email, instant messenger, phone number, and organization(s). Most of these classes are mere data storage classes with variables and getter/setters.

ContactList
The ContactList class is a very basic class designed to hold an ArrayList of instances of the Contact class below. We've left this class very plain and ready to be expanded to suit your needs.
package com.higherpass.android.ContactAPI.objects; import java.util.ArrayList; public class ContactList { private ArrayList<Contact> contacts = new ArrayList<Contact>(); public ArrayList<Contact> getContacts() { return contacts;

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

} public void setContacts(ArrayList<Contact> contacts) { this.contacts = contacts; } public void addContact(Contact contact) { this.contacts.add(contact); } public ContactList() { } }

Contact
The Contact class is used to store the details about each contact. There are a series of private class variables to hold this data. Singular data such as name and database ID are stored as strings. Complex data is stored either as an instance or ArrayList of data specific classes. This class is mainly getters and setters with a few methods to add to the internal ArrayLists.
package com.higherpass.android.ContactAPI.objects; import java.util.ArrayList; public class Contact { private String id; private String displayName; private ArrayList<Phone> phone; private ArrayList<Email> email; private ArrayList<String> notes; private ArrayList<Address> addresses = new ArrayList<Address>(); private ArrayList<IM> imAddresses; private Organization organization; public Organization getOrganization() { return organization; } public void setOrganization(Organization organization) { this.organization = organization; } public ArrayList<IM> getImAddresses() { return imAddresses; } public void setImAddresses(ArrayList<IM> imAddresses) { this.imAddresses = imAddresses; } public void addImAddresses(IM imAddr) { this.imAddresses.add(imAddr); } public ArrayList<String> getNotes() { return notes; } public void setNotes(ArrayList<String> notes) { this.notes = notes; }

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

public void addNote(String note) { this.notes.add(note); } public ArrayList<Address> getAddresses() { return addresses; } public void setAddresses(ArrayList<Address> addresses) { this.addresses = addresses; } public void addAddress(Address address) { this.addresses.add(address); } public ArrayList<Email> getEmail() { return email; } public void setEmail(ArrayList<Email> email) { this.email = email; } public void addEmail(Email e) { this.email.add(e); } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getDisplayName() { return displayName; } public void setDisplayName(String dName) { this.displayName = dName; } public ArrayList<Phone> getPhone() { return phone; } public void setPhone(ArrayList<Phone> phone) { this.phone = phone; } public void addPhone(Phone phone) { this.phone.add(phone); } }

Address
The Address class is the only class in the ContactList framework that actually does any work. Due to differences in data storage between 1.x and 2.0 versions of Android the Address class has to determine if the input address is free-form from 1.x or was input from the formatted data structure from 2.0. Android 2.0 has individual data columns for PO-Box, street, city, region, postal code, country while 1.x was just a text field with the entire address. This is handled in the toString() method that returns a free-form address from either input type. Unfortunately when using Android 1.x all the individual address getters will return null.
package com.higherpass.android.ContactAPI.objects; public class Address { private String poBox; private String street; private String city;

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

private private private private private

String String String String String

state; postalCode; country; type; asString = "";

public String getType() { return type; } public void setType(String type) { this.type = type; } public String getPoBox() { return poBox; } public void setPoBox(String poBox) { this.poBox = poBox; } public String getStreet() { return street; } public void setStreet(String street) { this.street = street; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } public String getState() { return state; } public void setState(String state) { this.state = state; } public String getPostalCode() { return postalCode; } public void setPostalCode(String postalCode) { this.postalCode = postalCode; } public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } public String toString() { if (this.asString.length() > 0) { return(this.asString); } else { String addr = ""; if (this.getPoBox() != null) { addr = addr + this.getPoBox() + "n"; } if (this.getStreet() != null) { addr = addr + this.getStreet() + "n"; } if (this.getCity() != null) { addr = addr + this.getCity() + ", ";

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

} if (this.getState() != null) { addr = addr + this.getState() + " "; } if (this.getPostalCode() != null) { addr = addr + this.getPostalCode() + " "; } if (this.getCountry() != null) { addr = addr + this.getCountry(); } return(addr); } } public Address(String asString, String type) { this.asString = asString; this.type = type; } public Address(String poBox, String street, String city, String state, String postal, String country, String type) { this.setPoBox(poBox); this.setStreet(street); this.setCity(city); this.setState(state); this.setPostalCode(postal); this.setCountry(country); this.setType(type); } }

Email
Another getter/setter and data storage class. The email class stores the email address and address type (work, home, etc).
package com.higherpass.android.ContactAPI.objects; public class Email { private String address; private String type; public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public String getType() { return type; } public void setType(String t) { this.type = t; } public Email(String a, String t) { this.address = a; this.type = t; } }

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

IM
Class to hold instant messenger data.
package com.higherpass.android.ContactAPI.objects; public class IM { private String name; private String type; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getType() { return type; } public void setType(String type) { this.type = type; } public IM(String name, String type) { this.name = name; this.type = type; } }

Organization
Class to hold the contacts organizational data.
package com.higherpass.android.ContactAPI.objects; public class Organization { private String organization = ""; private String title = ""; public String getOrganization() { return organization; } public void setOrganization(String organization) { this.organization = organization; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public Organization() { } public Organization(String org, String title) { this.organization = org; this.title = title; } }

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

Phone
Class to hold the phone records.
package com.higherpass.android.ContactAPI.objects; public class Phone { private String number; private String type; public String getNumber() { return number; } public void setNumber(String number) { this.number = number; } public String getType() { return type; } public void setType(String type) { this.type = type; } public Phone(String n, String t) { this.number = n; this.type = t; } }

Working With Android Contacts


Wrapper class
The wrapper class below is what will be invoked by applications. This class will determine the API level running on the device/emulator and load the correct class created on the next pages. To determine the correct Android API running the Build.VERSION.SDK variable is queried. This version code is then compared against the Eclair (2.0) version code stored in Build.VERSION_CODES.ECLAIR. Finally the proper API class is loaded.
package com.higherpass.android.ContactAPI; import import import import import android.os.Build; android.content.ContentResolver; android.content.Intent; android.database.Cursor; android.net.Uri;

import com.highercollaboration.android.ContactAPI.objects.*; public abstract class ContactAPI { private static ContactAPI api; private Cursor cur;

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

private ContentResolver cr; public static ContactAPI getAPI() { if (api == null) { String apiClass; if (Integer.parseInt(Build.VERSION.SDK) >= Build.VERSION_CODES.ECLAIR) { apiClass = "com.highercollaboration.android.ContactAPI.ContactAPISdk5"; } else { apiClass = "com.highercollaboration.android.ContactAPI.ContactAPISdk3"; } try { Class<? extends ContactAPI> realClass = Class.forName(apiClass).asSubclass(ContactAPI.class); api = realClass.newInstance(); } catch (Exception e) { throw new IllegalStateException(e); } } return api; } public abstract Intent getContactIntent(); public abstract ContactList newContactList(); public abstract Cursor getCur(); public abstract void setCur(Cursor cur); public abstract ContentResolver getCr(); public abstract void setCr(ContentResolver cr); }

2.0 Data access class


This class takes what was covered on page 1 of the tutorial about the Android 2.0 Contact API and turns it into a class. This class extends and will be invoked by the wrapper class created previously.
package com.higherpass.android.ContactAPI; import java.util.ArrayList; import com.highercollaboration.android.ContactAPI.objects.*; import import import import android.content.Intent; android.database.Cursor; android.provider.ContactsContract; android.content.ContentResolver;

public class ContactAPISdk5 extends ContactAPI { private Cursor cur; private ContentResolver cr;

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

public Cursor getCur() { return cur; } public void setCur(Cursor cur) { this.cur = cur; } public ContentResolver getCr() { return cr; } public void setCr(ContentResolver cr) { this.cr = cr; } public Intent getContactIntent() { return(new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI)); } public ContactList newContactList() { ContactList contacts = new ContactList(); String id; this.cur = this.cr.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null); if (this.cur.getCount() > 0) { while (cur.moveToNext()) { Contact c = new Contact(); id = cur.getString(cur.getColumnIndex(ContactsContract.Contacts._ID)); c.setId(id); c.setDisplayName(cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLA Y_NAME))); if (Integer.parseInt(cur.getString(cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NU MBER))) > 0) { c.setPhone(this.getPhoneNumbers(id)); } c.setEmail(this.getEmailAddresses(id)); c.setNotes(this.getContactNotes(id)); c.setAddresses(this.getContactAddresses(id)); c.setImAddresses(this.getIM(id)); c.setOrganization(this.getContactOrg(id)); contacts.addContact(c); } } return(contacts); } public ArrayList<Phone> getPhoneNumbers(String id) { ArrayList<Phone> phones = new ArrayList<Phone>(); Cursor pCur = this.cr.query( ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = ?", new String[]{id}, null); while (pCur.moveToNext()) {

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

phones.add(new Phone( pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)) , pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE)) )); } pCur.close(); return(phones); } public ArrayList<Email> getEmailAddresses(String id) { ArrayList<Email> emails = new ArrayList<Email>(); Cursor emailCur = this.cr.query( ContactsContract.CommonDataKinds.Email.CONTENT_URI, null, ContactsContract.CommonDataKinds.Email.CONTACT_ID + " = ?", new String[]{id}, null); while (emailCur.moveToNext()) { // This would allow you get several email addresses Email e = new Email(emailCur.getString(emailCur.getColumnIndex(ContactsContract.CommonDataKinds.Email.D ATA)) ,emailCur.getString(emailCur.getColumnIndex(ContactsContract.CommonDataKinds.Email .TYPE)) ); emails.add(e); } emailCur.close(); return(emails); } public ArrayList<String> getContactNotes(String id) { ArrayList<String> notes = new ArrayList<String>(); String where = ContactsContract.Data.CONTACT_ID + " = ? AND " + ContactsContract.Data.MIMETYPE + " = ?"; String[] whereParameters = new String[]{id, ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE}; Cursor noteCur = this.cr.query(ContactsContract.Data.CONTENT_URI, null, where, whereParameters, null); if (noteCur.moveToFirst()) { String note = noteCur.getString(noteCur.getColumnIndex(ContactsContract.CommonDataKinds.Note.NOTE)); if (note.length() > 0) { notes.add(note); } } noteCur.close(); return(notes); } public ArrayList<Address> getContactAddresses(String id) { ArrayList<Address> addrList = new ArrayList<Address>(); String where = ContactsContract.Data.CONTACT_ID + " = ? AND " + ContactsContract.Data.MIMETYPE + " = ?"; String[] whereParameters = new String[]{id,

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE}; Cursor addrCur = this.cr.query(ContactsContract.Data.CONTENT_URI, null, where, whereParameters, null); while(addrCur.moveToNext()) { String poBox = addrCur.getString(addrCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPosta l.POBOX)); String street = addrCur.getString(addrCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPosta l.STREET)); String city = addrCur.getString(addrCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPosta l.CITY)); String state = addrCur.getString(addrCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPosta l.REGION)); String postalCode = addrCur.getString(addrCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPosta l.POSTCODE)); String country = addrCur.getString(addrCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPosta l.COUNTRY)); String type = addrCur.getString(addrCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPosta l.TYPE)); Address a = new Address(poBox, street, city, state, postalCode, country, type); addrList.add(a); } addrCur.close(); return(addrList); } public ArrayList<IM> getIM(String id) { ArrayList<IM> imList = new ArrayList<IM>(); String where = ContactsContract.Data.CONTACT_ID + " = ? AND " + ContactsContract.Data.MIMETYPE + " = ?"; String[] whereParameters = new String[]{id, ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE}; Cursor imCur = this.cr.query(ContactsContract.Data.CONTENT_URI, null, where, whereParameters, null); if (imCur.moveToFirst()) { String imName = imCur.getString(imCur.getColumnIndex(ContactsContract.CommonDataKinds.Im.DATA)); String imType; imType = imCur.getString(imCur.getColumnIndex(ContactsContract.CommonDataKinds.Im.TYPE)); if (imName.length() > 0) { IM im = new IM(imName, imType); imList.add(im); } } imCur.close(); return(imList); } public Organization getContactOrg(String id) { Organization org = new Organization();

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

String where = ContactsContract.Data.CONTACT_ID + " = ? AND " + ContactsContract.Data.MIMETYPE + " = ?"; String[] whereParameters = new String[]{id, ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE}; Cursor orgCur = this.cr.query(ContactsContract.Data.CONTENT_URI, null, where, whereParameters, null); if (orgCur.moveToFirst()) { String orgName = orgCur.getString(orgCur.getColumnIndex(ContactsContract.CommonDataKinds.Organization.DATA )); String title = orgCur.getString(orgCur.getColumnIndex(ContactsContract.CommonDataKinds.Organization.TITL E)); if (orgName.length() > 0) { org.setOrganization(orgName); org.setTitle(title); } } orgCur.close(); return(org); } }

Working With Android Contacts


1.x Data access class
This class is made up of the code explained covering version 1.x of the Android contact API. As with the 2.0 class this class extends the ContactAPI wrapper class and will be invoked by it if the 1.x version of Android is in use.
package com.higherpass.android.ContactAPI; import java.util.ArrayList; import import import import import import import import import import import import com.higherpass.android.ContactAPI.objects.Address; com.higherpass.android.ContactAPI.objects.Contact; com.higherpass.android.ContactAPI.objects.ContactList; com.higherpass.android.ContactAPI.objects.Email; com.higherpass.android.ContactAPI.objects.IM; com.higherpass.android.ContactAPI.objects.Organization; com.higherpass.android.ContactAPI.objects.Phone; android.content.ContentResolver; android.content.Intent; android.database.Cursor; android.provider.Contacts; android.provider.Contacts.People;

public class ContactAPISdk3 extends ContactAPI { private Cursor cur; private ContentResolver cr;

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

public Cursor getCur() { return cur; } public void setCur(Cursor cur) { this.cur = cur; } public ContentResolver getCr() { return cr; } public void setCr(ContentResolver cr) { this.cr = cr; } public Intent getContactIntent() { return(new Intent(Intent.ACTION_PICK, People.CONTENT_URI)); } public ContactList newContactList() { ContactList contacts = new ContactList(); String id; this.cur = this.cr.query(People.CONTENT_URI, null, null, null, null); if (this.cur.getCount() > 0) { while (cur.moveToNext()) { Contact c = new Contact(); id = cur.getString(cur.getColumnIndex(People._ID)); c.setId(id); c.setDisplayName(cur.getString(cur.getColumnIndex(People.DISPLAY_NAME))); if (Integer.parseInt(cur.getString(cur.getColumnIndex(People.PRIMARY_PHONE_ID))) > 0) { c.setPhone(this.getPhoneNumbers(id)); } c.setEmail(this.getEmailAddresses(id)); ArrayList<String> notes = new ArrayList<String>(); notes.add(cur.getString(cur.getColumnIndex(People.NOTES))); c.setNotes(notes); c.setAddresses(this.getContactAddresses(id)); c.setImAddresses(this.getIM(id)); c.setOrganization(this.getContactOrg(id)); contacts.addContact(c); } } return(contacts); } public ArrayList<Phone> getPhoneNumbers(String id) { ArrayList<Phone> phones = new ArrayList<Phone>(); Cursor pCur = this.cr.query( Contacts.Phones.CONTENT_URI, null, Contacts.Phones.PERSON_ID +" = ?", new String[]{id}, null); while (pCur.moveToNext()) { phones.add(new Phone(

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

pCur.getString(pCur.getColumnIndex(Contacts.Phones.NUMBER)) , pCur.getString(pCur.getColumnIndex(Contacts.Phones.TYPE)) )); } pCur.close(); return(phones); } public ArrayList<Email> getEmailAddresses(String id) { ArrayList<Email> emails = new ArrayList<Email>(); Cursor emailCur = this.cr.query( Contacts.ContactMethods.CONTENT_EMAIL_URI, null, Contacts.ContactMethods.PERSON_ID + " = ?", new String[]{id}, null); while (emailCur.moveToNext()) { // This would allow you get several email addresses Email e = new Email(emailCur.getString(emailCur.getColumnIndex(Contacts.ContactMethods.DATA)) ,emailCur.getString(emailCur.getColumnIndex(Contacts.ContactMethods.CONTENT_EMAIL_ TYPE)) ); emails.add(e); } emailCur.close(); return(emails); } public ArrayList<Address> getContactAddresses(String id) { ArrayList<Address> addrList = new ArrayList<Address>(); String where = Contacts.ContactMethods.PERSON_ID + " = ? AND " + Contacts.ContactMethods.KIND + " = ?"; String[] whereParameters = new String[]{id, Contacts.ContactMethods.CONTENT_POSTAL_ITEM_TYPE}; Cursor addrCur = this.cr.query(Contacts.ContactMethods.CONTENT_URI, null, where, whereParameters, null); while(addrCur.moveToNext()) { String addr = addrCur.getString(addrCur.getColumnIndex(Contacts.ContactMethodsColumns.DATA)); String type = addrCur.getString(addrCur.getColumnIndex(Contacts.ContactMethodsColumns.TYPE)); Address a = new Address(addr, type); addrList.add(a); } addrCur.close(); return(addrList); } public ArrayList<IM> getIM(String id) { ArrayList<IM> imList = new ArrayList<IM>(); String where = Contacts.ContactMethods.PERSON_ID + " = ? AND " + Contacts.ContactMethods.KIND + " = ?"; String[] whereParameters = new String[]{id, Contacts.ContactMethods.CONTENT_IM_ITEM_TYPE};

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

Cursor imCur = this.cr.query(Contacts.ContactMethods.CONTENT_URI, null, where, whereParameters, null); if (imCur.moveToFirst()) { String imName = imCur.getString(imCur.getColumnIndex(Contacts.ContactMethodsColumns.DATA)); String imType = imCur.getString(imCur.getColumnIndex(Contacts.ContactMethodsColumns.TYPE)); if (imName.length() > 0) { IM im = new IM(imName, imType); imList.add(im); } } imCur.close(); return(imList); } public Organization getContactOrg(String id) { Organization org = new Organization(); String where = Contacts.ContactMethods.PERSON_ID + " = ?"; String[] whereParameters = new String[]{id}; Cursor orgCur = this.cr.query(Contacts.Organizations.CONTENT_URI, null, where, whereParameters, null); if (orgCur.moveToFirst()) { String orgName = orgCur.getString(orgCur.getColumnIndex(Contacts.Organizations.COMPANY)); String title = orgCur.getString(orgCur.getColumnIndex(Contacts.Organizations.TITLE)); if (orgName.length() > 0) { org.setOrganization(orgName); org.setTitle(title); } } orgCur.close(); return(org); } }

Accessing Data With Android Cursors


What is SQLite
SQLite is an open-source server-less database engine. SQLite supports transacations and has no configuration required. SQLite adds powerful data storage to mobile and embedded apps without a large footprint.

Creating and connecting to a database


First import android.databse.sqlite.SQLiteDatabase into your application. Then use the openOrCreateDatabase() method to create or connect to a database. Create a new project in Eclipse called TestingData and select the API version of your choice. Use the package name higherpass.TestingData with an activity TestingData and click finish.
package higherpass.TestingData;

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

import android.app.Activity; import android.os.Bundle; import android.database.sqlite.SQLiteDatabase; public class TestingData extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); SQLiteDatabase db; db = openOrCreateDatabase( "TestingData.db" , SQLiteDatabase.CREATE_IF_NECESSARY , null ); } }

Add the android.database.sqlite.SQLiteDatabase to the standard imports from the new project. After the standard layout setup initialize a SQLiteDatabase variable to hold the database instance. Next use the openOrCreateDatabase() method to open the database. The openOrCreateDatabase() method expects the database file first, followed by the permissions to open the database with, and an optional cursor factory builder.
Where does Android store SQLite databases?

Android stores SQLite databases in /data/data/[application package name]/databases.

sqlite3 from adb shell


bash-3.1$ /usr/local/android-sdk-linux/tools/adb devices List of devices attached emulator-5554 device bash-3.1$ /usr/local/android-sdk-linux/tools/adb -s emulator-5554 shell # ls /data/data/higherpass.TestingData/databases TestingData.db # sqlite3 /data/data/higherpass.TestingData/databases/TestingData.db SQLite version 3.5.9 Enter ".help" for instructions sqlite> .tables android_metadata tbl_countries tbl_states

The Google Android SDK comes with a utility adb. The adb tool can be used to browse and modify the filesystem of attached emulators and physical devices. This example is a bit ahead of where we are as we haven't created the databases yet.

Setting database properties

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

There are a few database properties that should be set after connecting to the database. Use the setVersion(), setLocale(), and setLockingEnabled() methods to set these properties. These will be demonstrated in the creating tables example.

Creating Tables
Tables are created by executing statements on the database. The queries should be executed with the execSQL() statement.
package higherpass.TestingData; import java.util.Locale; import android.app.Activity; import android.os.Bundle; import android.database.sqlite.SQLiteDatabase; public class TestingData extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); SQLiteDatabase db; db = openOrCreateDatabase( "TestingData.db" , SQLiteDatabase.CREATE_IF_NECESSARY , null ); db.setVersion(1); db.setLocale(Locale.getDefault()); db.setLockingEnabled(true); final String CREATE_TABLE_COUNTRIES = "CREATE TABLE tbl_countries (" + "id INTEGER PRIMARY KEY AUTOINCREMENT," + "country_name TEXT);"; final String CREATE_TABLE_STATES = "CREATE TABLE tbl_states (" + "id INTEGER PRIMARY KEY AUTOINCREMENT," + "state_name TEXT," + "country_id INTEGER NOT NULL CONSTRAINT " + "contry_id REFERENCES tbl_contries(id) " + "ON DELETE CASCADE);"; db.execSQL(CREATE_TABLE_COUNTRIES); db.execSQL(CREATE_TABLE_STATES); final String CREATE_TRIGGER_STATES = "CREATE TRIGGER fk_insert_state BEFORE " + "INSERT on tbl_states" + "FOR EACH ROW " + "BEGIN " + "SELECT RAISE(ROLLBACK, 'insert on table " + ""tbl_states" voilates foreign key constraint " + ""fk_insert_state"') WHERE (SELECT id FROM " + "tbl_countries WHERE id = NEW.country_id) IS NULL; " + "END;"; db.execSQL(CREATE_TRIGGER_STATES);

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

} }

As before open the database with openOrCreateDatabase(). Now configure the database connection with setVersion to set the database version. The setLocale method sets the default locale for the database and setLockingEnabled enables locking on the database. Next we setup final String variables to hold the SQLite table creation statements and execute them with execSQL. Additionally we manually have to create triggers to handle the foreign key relationships between the table. In a production application there would also need to be foreign key triggers to handle row updates and deletes. The foreign key triggers are executed with execSQL just like the table creation.

Inserting records
Android comes with a series of classes that simplify database usage. Use a ContentValues instance to create a series of table field to data matchings that will be passed into an insert() method. Android has created similar methods for updating and deleting records.
ContentValues values = new ContentValues(); values.put("country_name", "US"); long countryId = db.insert("tbl_countries", null, values); ContentValues stateValues = new ContentValues(); stateValues.put("state_name", "Texas"); stateValues.put("country_id", Long.toString(countryId)); try { db.insertOrThrow("tbl_states", null, stateValues); } catch (Exception e) { //catch code }

Append this code to the previous example. First create a ContentValues object to store the data to insert and use the put method to load the data. Then use the insert() method to perform the insert query into SQLite. The insert() function expects three parameters, the table name, null, and the ContentValues pairs. Also a long is returned by the insert() function. This long will hold the primary key of the inserted row. Next we create a new ContentValues pair for the state and perform a second insert using the insertOrThrow() method. Using insertOrThrow() will throw an exception if the insert isn't successful and must be surrounded by a try/catch block. You'll notice that currently the application dies with an unhandled exception because the tables we're trying to create already exist. Go back into the adb shell and attach to the SQLite database for the application and drop the tables.
sqlite> drop table tbl_countries; sqlite> drop table tbl_states;

Updating data
Updating records is handled with the update() method. The update() function supports WHERE syntax similar to other SQL engines. The update() method expects the table name, a ContentValues instance similar to insert with the fields to update. Also allowed are optional WHERE syntax, add a String containing the WHERE

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

statement as parameter 3. Use the ? to designate an argument replacement in the WHERE clause with the replacements passed as an array in parameter 4 to update.
ContentValues updateCountry = new ContentValues(); updateCountry.put("country_name", "United States"); db.update("tbl_countries", updateCountry, "id=?", new String[] {Long.toString(countryId)});

First remove the table create statements from the code. We don't need to keep creating and dropping tables. Now create a new ContentValues instance, updateCountry, to hold the data to be updated. Then use the update() method to update the table. The where clause in parameter 3 uses replacement of the ? with the values stored in parameter 4. If multiple ? existed in the where statement they would be replaced in order by the values of the array.

From the adb shell attach to the database and execute select * FROM tbl_countries; inside sqlite3.
bash-3.1$ /usr/local/android-sdk-linux/tools/adb -s emulator-5554 shell # sqlite3 /data/data/higherpass.TestingData/databases/TestingData.db SQLite version 3.5.9 Enter ".help" for instructions sqlite> select * FROM tbl_countries; 1|United States

Deleting data
Once data is no longer needed it can be removed from the database with the delete() method. The delete() method expects 3 parameters, the database name, a WHERE clause, and an argument array for the WHERE clause. To delete all records from a table pass null for the WHERE clause and WHERE clause argument array.
db.delete("tbl_states", "id=?", new String[] {Long.toString(countryId)});

Simply call the delete() method to remove records from the SQLite database. The delete method expects, the table name, and optionally a where clause and where clause argument replacement arrays as parameters. The where clause and argument replacement array work just as with update where ? is replaced by the values in the array.

Accessing Data With Android Cursors


Retrieving data
Retrieving data from SQLite databases in Android is done using Cursors. The Android SQLite query method returns a Cursor object containing the results of the query. To use Cursors android.database.Cursor must be imported.

About Cursors
Cursors store query result records in rows and grant many methods to access and iterate through the records. Cursors should be closed when no longer used, and will be deactivated with a call to Cursor.deactivate() when the application pauses or exists. On resume the Cursor.requery() statement is executed to re-enable the Cursor with fresh data. These functions can be managed by the parent Activity by calling startManagingCursor().
A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

package higherpass.TestingData; import java.util.Locale; import import import import import android.app.Activity; android.os.Bundle; android.content.ContentValues; android.database.Cursor; android.database.sqlite.SQLiteDatabase;

public class TestingData extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); SQLiteDatabase db; db = openOrCreateDatabase( "TestingData.db" , SQLiteDatabase.CREATE_IF_NECESSARY , null ); db.setVersion(1); db.setLocale(Locale.getDefault()); db.setLockingEnabled(true); Cursor cur = db.query("tbl_countries", null, null, null, null, null, null); cur.close(); } }

Open the database as before. The query performed will return all records from the table tbl_countries. Next we'll look at how to access the data returned.

Iterating through records


The Cursor class provides a couple of simple methods to allow iterating through Cursor data easily. Use moveToFirst() to position the Cursor pointer at the first record then use the moveToNext() function to iterate through the records. The isAfterLast() method performs a check to see if the cursor is pointed after the last record. When looping through records break the loop when this becomes false. First add the following attribute to the TextView element in the main layout. The main layout is the xml file located at res/layouts/main.xml. We need to give this TextView element an ID that we can reference to update the view.
android:id="@+id/hello"

Java code to iterate through entries in a cursor:


package higherpass.TestingData;

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

import java.util.Locale; import import import import import android.app.Activity; android.os.Bundle; android.widget.TextView; android.database.Cursor; android.database.sqlite.SQLiteDatabase;

public class TestingData extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); TextView view = (TextView) findViewById(R.id.hello); SQLiteDatabase db; db = openOrCreateDatabase( "TestingData.db" , SQLiteDatabase.CREATE_IF_NECESSARY , null ); db.setVersion(1); db.setLocale(Locale.getDefault()); db.setLockingEnabled(true); Cursor cur = db.query("tbl_countries", null, null, null, null, null, null); cur.moveToFirst(); while (cur.isAfterLast() == false) { view.append("n" + cur.getString(1)); cur.moveToNext(); } cur.close(); } }

This code simply creates a cursor querying all the records of the table tbl_countries. The moveToFirst() method is used to position the cursor pointer at the beginning of the data set. Then loop through the records in the cursor. The method isAfterLast() returns a boolean if the pointer is past the last record in the cursor. Use the moveToNext() method to traverse through the records in the cursor.

Retrieving a specific record


The cursor also allows direct access to specific records.
Cursor cur = db.query("tbl_countries", null, null, null, null, null, null); cur.moveToPosition(0); view.append("n" + cur.getString(1)); cur.close();

Accessing Data With Android Cursors


A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

Transactions
SQLite also supports transactions when you need to perform a series of queries that either all complete or all fail. When a SQLite transaction fails an exception will be thrown. The transaction methods are all part of the database object. Start a transaction by calling the beginTransaction() method. Perform the queries and then call the setTransactionSuccessful() when you wish to commit the transaction. Once the transaction is complete call the endTransaction() function.
db.beginTransaction(); Cursor cur = null; try { cur = db.query("tbl_countries", null, null, null, null, null, null); cur.moveToPosition(0); ContentValues values = new ContentValues(); values.put("state_name", "Georgia"); values.put("country_id", cur.getString(0)); long stateId = db.insert("tbl_states", null, values); db.setTransactionSuccessful(); view.append("n" + Long.toString(stateId)); } catch (Exception e) { Log.e("Error in transaction", e.toString()); } finally { db.endTransaction(); cur.close(); }

Start off with a call to beginTransaction() to tell SQLite to perform the queries in transaction mode. Initiate a try/catch block to handle exceptions thrown by a transaction failure. Perform the queries and then call setTransactionSuccessful() to tell SQLite that our transaction is complete. If an error isn't thrown then endTransaction() can be called to commit the transaction. Finally close the cursor when we're finished with it.

Built in android databases


The Android Operating-System provides several built-in databases to store and manage core phone application data. Before external applications may access some of these data sources access must be granted in the AndroidManifest.xml file in the root of the project. Some of the data applications can access are the bookmarks, media player data, call log, and contact data. Contact data not covered due to changes in the API between 1.x and 2.0 version of Android. See the Android Working With Contacts Tutorial. Android provides built in variables to make working with the internal SQLite databases easy.

Access permissions
Before a program accesses any of the internal Android databases the application must be granted access. This access is granted in the AndroidManifest.xml file. Before the application is installed from the market the user will be prompted to allow the program to access this data.
<uses-permission android:name="com.android.browser.permission.READ_HISTORY_BOOKMARKS" /> <uses-permission android:name="com.android.broswer.permission.WRITE_HISTORY_BOOKMARKS" /> <uses-permission android:name="android.permission.READ_CONTACTS" />

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

These are some sample uses-permission statements to grant access to internal Android databases. These are normally placed below the uses-sdk statement in the AndroidManifest.xml file. The first 2 grant read and write access to the browser history and bookmarks. The third grants read access to the contacts. We'll need to grant READ access to the bookmarks and contacts for the rest of the code samples to work.

Managed Query
Managed queries delegate control of the Cursor to the parent activity automatically. This is handy as it allows the activity to control when to destroy and recreate the Cursor as the application changes state.
package higherpass.TestingData; import import import import import android.app.Activity; android.os.Bundle; android.provider.Browser; android.widget.TextView; android.database.Cursor;

public class TestingData extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); TextView view = (TextView) findViewById(R.id.hello); Cursor mCur = managedQuery(android.provider.Browser.BOOKMARKS_URI, null, null, null, null ); mCur.moveToFirst(); int index = mCur.getColumnIndex(Browser.BookmarkColumns.TITLE); while (mCur.isAfterLast() == false) { view.append("n" + mCur.getString(index)); mCur.moveToNext(); } } }

The managed query functions very similar to the query function we used before. When accessing Android built in databases you should reference them by calling the associated SDK variable containing the correct database URI. In this case the browser bookmarks are being accessed by pointing the managedQuery() statement at android.provider.Browser.BOOKMARKS_URI. We left the rest of the parameters null to pull all results from the table. Then we iterate through the cursor records. Each time through the loop we append the title of the bookmark to the TextView element. If you know the name of a column, but not it's index in the results use the getColumnIndex() method to get the correct index. To get the value of a field use the getString() method passing the index of the field to return.

Bookmarks
The first Android database we're going to explore is the browser bookmarks. When accessing the internal Android databases use the managedQuery() method. Android includes some helper variables in Browser.BookmarkColumns to designate column names. They are Browser.BookmarkColumns.TITLE,

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

BOOKMARK, FAVICON, CREATED, URL, DATE, VISITS. These contain the table column names for the bookmarks SQLite table.
package higherpass.TestingData; import import import import import android.app.Activity; android.os.Bundle; android.provider.Browser; android.widget.TextView; android.database.Cursor;

public class TestingData extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); TextView view = (TextView) findViewById(R.id.hello); String[] projection = new String[] { Browser.BookmarkColumns.TITLE , Browser.BookmarkColumns.URL }; Cursor mCur = managedQuery(android.provider.Browser.BOOKMARKS_URI, projection, null, null, null ); mCur.moveToFirst(); int titleIdx = mCur.getColumnIndex(Browser.BookmarkColumns.TITLE); int urlIdx = mCur.getColumnIndex(Browser.BookmarkColumns.URL); while (mCur.isAfterLast() == false) { view.append("n" + mCur.getString(titleIdx)); view.append("n" + mCur.getString(urlIdx)); mCur.moveToNext(); } } }

This code works as before, with the addition of limiting return columns with a projection. The projection is a string array that holds a list of the columns to return. In this example we limited the columns to the bookmark title (Browser.BookmarkColumns.TITLE) and URL (Browser.BookmarkColumns.URL). The projection array is then passed into managedQuery as the second parameter.

Accessing Data With Android Cursors


Media Player
The Android Media-player also uses SQLite to store the media information. Use this database to find media stored on the device. Available fields are DATE_ADDED, DATE_MODIFIED, DISPLAY_NAME, MIME_TYPE, SIZE, and TITLE.
package higherpass.TestingData; import android.app.Activity; import android.os.Bundle; import android.provider.MediaStore;

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

import android.provider.MediaStore.Audio.Media; import android.widget.TextView; import android.database.Cursor; public class TestingData extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); TextView view = (TextView) findViewById(R.id.hello); String[] projection = new String[] { MediaStore.MediaColumns.DISPLAY_NAME , MediaStore.MediaColumns.DATE_ADDED , MediaStore.MediaColumns.MIME_TYPE }; Cursor mCur = managedQuery(Media.EXTERNAL_CONTENT_URI, projection, null, null, null ); mCur.moveToFirst(); while (mCur.isAfterLast() == false) { for (int i=0; i<mCur.getColumnCount(); i++) { view.append("n" + mCur.getString(i)); } mCur.moveToNext(); } } }

The only differences here is that we use getColumnCount() to determine the number of columns in the returned records and loop through displaying each column.

Call Log
If granted permission Android applications can access the call log. The call log is accessed like other datastores.
package higherpass.TestingData; import import import import import import android.app.Activity; android.os.Bundle; android.provider.CallLog; android.provider.CallLog.Calls; android.widget.TextView; android.database.Cursor;

public class TestingData extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); TextView view = (TextView) findViewById(R.id.hello); String[] projection = new String[] { Calls.DATE , Calls.NUMBER

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

, Calls.DURATION }; Cursor mCur = managedQuery(CallLog.Calls.CONTENT_URI, projection, Calls.DURATION +"<?", new String[] {"60"}, Calls.DURATION + " ASC"); mCur.moveToFirst(); while (mCur.isAfterLast() == false) { for (int i=0; i<mCur.getColumnCount(); i++) { view.append("n" + mCur.getString(i)); } mCur.moveToNext(); } } }

This final example introduces the rest of the managedQuery() parameters. After the projection we pass a WHERE clause in the same way they were crafted in the update and delete sections earlier. After the where clause comes the array of replacement arguments. Finally we pass in an order by clause to tell SQLite how to sort the results. This query only retrieves records for phone calls lasting less than 60 seconds and sorts them by duration ascending.

Android 9 Patch Scaled PNG Image Guide


About 9 Patch PNG Images
9 patch scalable graphics are PNG based images that have 9 areas, called patches, that scale separately. This is handy for mobile devices that have smaller screens with differing resolutions and aspect ratios. The Android SDK comes with a utility called draw9patch to create 9 patch images from PNG files. The draw9patch utility is located in the tools/ directory of the SDK. The easiest way to think of a 9 patch image is to lay a tic-tac-toe board over the image. The grid from the tictac-toe board can then be moved across the image to fit the correct scaling zones. The 4 corner scaling zones don't scale. These are fixed size blocks. The top and bottom center column blocks only scale horizontally. The left and right edge boxes on row 2 only scale vertically. Finally the center scales both vertically and horizontally.

Creating 9 Patch Images


This is the image we're going to work with.

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

Right click on the image and save it. Next launch draw9patch from the tools directory of the SDK and open the image. The left pane of draw9patch shows the images and allows you to set the patch boundaries. To the right is a preview pane that shows the results of the defined patches. To set a patch boundary click along the edge of the image. Clicking on the top or bottom will create a vertical patch boundary. Clicking on the left or right will create a horizontal patch boundary. Right click to remove a patch boundary. Setup the image so that the colored bars create an even border around the image. Download patched example here. This allows for the creation of custom button and other graphic elements that can be scaled and re-sized minimizing the amount of work to keep a consistent look and feel across multiple devices.

Basic application use


9 patch images are included no differently than standard images. See the Android Image Tutorial tutorial for detailed information about using images. Here we're just going to show basic usage and 9 patch specific actions.

Layout
To include a 9 patch image via a layout use an ImageView
<ImageView android:id="@+id/test_image" android:src="@drawable/test_9patch_patched" android:layout_width="fill_parent" android:layout_height="fill_parent" />

Insert this ImageView component into res/layout/main.xml below the TextView. For the code it's just as with any other Android image. Create an ImageView to work with. Read the Android Image Tutorial article for more information about working with images.
package higherpass.Test9Patch; import android.app.Activity; import android.os.Bundle;

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

import android.widget.ImageView; public class Test9Patch extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); ImageView patch = (ImageView) findViewById(R.id.test_image); } }

Working With Images In Android


Basic Android Image Information
Android supports 3 common image formats PNG, JPG, GIF, along with 9 patch PNG images. Images are stored in the directory res/layout/drawable. As of version 1.6 of the Android SDK multiple drawable directories exist for different screen resolutions. There are low, medium, and high DPI specific directories, drawable-ldpi, drawable-mdpi, drawable-hdpi respectively. This allows you to create images at different DPI to enhance the appearance of your application. All image filenames should be lowercase and only contain letters, numbers, and underscores. Create a new project in Eclipse called TestImages.

Displaying An Image
The ImageView layout component is the base element used for displaying images in Android. Download this image and copy it into res/layout/drawable-mdpi in your project. We're simply going to use a screenshot of the emulator.
<ImageView android:id="@+id/test_image" android:src="@drawable/test" android:layout_width="wrap_content" android:layout_height="wrap_content" />

This ImageView loads the image test that you downloaded. Add this to the res/layout/main.xml file below the TextView.
package higherpass.TestImages; import android.app.Activity; public class TestImages extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); ImageView image = (ImageView) findViewById(R.id.test_image);

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

} }

All that was added to the default code is how to get the ImageView component from the layout and store it in a variable. We'll do more with this in the next examples.

Changing The Image


Changing the image done by creating an ImageView object for the image component to change and calling the setImageResource() method. Instead of using resources a custom bitmap can also be used by invoking setImageBitmap(). We'll get to bitmaps next. Download this second image and store it as test2.png in res/layout/drawable-mdpi.
package higherpass.TestImages; import android.app.Activity; import android.os.Bundle; import android.widget.ImageView; public class TestImages extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); ImageView image = (ImageView) findViewById(R.id.test_image); image.setImageResource(R.drawable.test2); } }

Here simply store the ImageView into the image variable and use the setImageResource() method to point the ImageView at the second image.

Working With Images In Android


Using BitmapDrawable To Create Bitmaps
BitmapDrawables are simply Drawable objects that wrap a bitmap and can be created from file path, input stream, XML inflation from a layout, and bitmaps.

Building Bitmap Objects


File

Use the adb tool with push option to copy test2.png onto the sdcard.
bash-3.1$ /usr/local/android-sdk-linux/tools/adb push test2.png /sdcard/

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

This is the easiest way to load bitmaps from the sdcard. Simply pass the path to the image to BitmapFactory.decodeFile() and let the Android SDK do the rest.
package higherpass.TestImages; import import import import import android.app.Activity; android.graphics.Bitmap; android.graphics.BitmapFactory; android.os.Bundle; android.widget.ImageView;

public class TestImages extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); ImageView image = (ImageView) findViewById(R.id.test_image); Bitmap bMap = BitmapFactory.decodeFile("/sdcard/test2.png"); image.setImageBitmap(bMap); } }

All this code does is load the image test2.png that we previously copied to the sdcard. The BitmapFactory creates a bitmap object with this image and we use the ImageView.setImageBitmap() method to update the ImageView component.
Input stream

Use BitmapFactory.decodeStream() to convert a BufferedInputStream into a bitmap object.


package higherpass.TestImages; import java.io.BufferedInputStream; import java.io.FileInputStream; import import import import import import android.app.Activity; android.graphics.Bitmap; android.graphics.BitmapFactory; android.os.Bundle; android.util.Log; android.widget.ImageView;

public class TestImages extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); ImageView image = (ImageView) findViewById(R.id.test_image); FileInputStream in; BufferedInputStream buf; try { in = new FileInputStream("/sdcard/test2.png"); buf = new BufferedInputStream(in); Bitmap bMap = BitmapFactory.decodeStream(buf); image.setImageBitmap(bMap);

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

if (in != null) { in.close(); } if (buf != null) { buf.close(); } } catch (Exception e) { Log.e("Error reading file", e.toString()); } } }

This code uses the basic Java FileInputStream and BufferedInputStream to create the input stream for BitmapFactory.decodeStream(). The file access code should be surrounded by a try/catch block to catch any exceptions thrown by FileInputStream or BufferedInputStream. Also when you're finished with the stream handles they should be closed.
XML inflation

Bitmaps can be extracted from layouts and views with inflation. Use BitmapFactory.decodeResource(res, id) to get a bitmap from an Android resource.
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); ImageView image = (ImageView) findViewById(R.id.test_image); Bitmap bMap = BitmapFactory.decodeResource(getResources(), R.drawable.icon); image.setImageBitmap(bMap); }

First create an ImageView instance containing the ImageView from the layout. Then create a bitmap from the application icon (R.drawable.icon) with BitmapFactory.decodeResource(). Finally set the new bitmap to be the image displayed in the ImageView component of the layout.
Bitmaps

The BitmapFactory.decodeByteArray() method of creating bitmaps creates a bitmap from an array of bytes. This is useful when a bitmap has been loaded for another purpose or has been created by the application or other external source.
package higherpass.TestImages; import java.io.BufferedInputStream; import java.io.FileInputStream; import import import import import import android.app.Activity; android.graphics.Bitmap; android.graphics.BitmapFactory; android.os.Bundle; android.util.Log; android.widget.ImageView;

public class TestImages extends Activity { /** Called when the activity is first created. */

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); ImageView image = (ImageView) findViewById(R.id.test_image); FileInputStream in; BufferedInputStream buf; try { in = new FileInputStream("/sdcard/test2.png"); buf = new BufferedInputStream(in); byte[] bMapArray= new byte[buf.available()]; buf.read(bMapArray); Bitmap bMap = BitmapFactory.decodeByteArray(bMapArray, 0, bMapArray.length); image.setImageBitmap(bMap); if (in != null) { in.close(); } if (buf != null) { buf.close(); } } catch (Exception e) { Log.e("Error reading file", e.toString()); } } }

As with the decodeStream() example we open the file in an input stream. This time though we go the extra mile and manually read the file into a byte array. This isn't the best way to do this if you haven't noticed, but it's a simple way to show the functionality. Use the BitmapFactory.decodeByteArray() method to create the bitmap. This function expects 3 parameters, the byte array, the array offset to start from, and the array offset to stop at.

Working With Images In Android


Image attributes
The bitmap classes provide access to the image attributes as well as perform some image manipulation.

Dimensions (width/height)
package higherpass.TestImages; import import import import import android.app.Activity; android.graphics.Bitmap; android.graphics.BitmapFactory; android.os.Bundle; android.widget.TextView;

public class TestImages extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); TextView text = (TextView) findViewById(R.id.hello);

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

Bitmap bMap = BitmapFactory.decodeResource(getResources(), R.drawable.test); text.setText(Integer.toString(bMap.getWidth()) + " x " + Integer.toString(bMap.getHeight())); } }

Scaling an image
Done by creating a bitmap of the scaled size.
public class TestImages extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); ImageView image = (ImageView) findViewById(R.id.test_image); Bitmap bMap = BitmapFactory.decodeResource(getResources(), R.drawable.test); Bitmap bMapScaled = Bitmap.createScaledBitmap(bMap, 150, 100, true); image.setImageBitmap(bMapScaled); } }

Load the original bitmap resource. Then use Bitmap.createScaledBitmap(originalBitmap, newX, newY, true) with the original bitmap resource, the new X dimension, new Y dimension, and true to enable filter respectively.

Rotating images
Use an instance of the Matrix class from the SDK to apply rotation properties to an image. The rotate properties work rotating the image clockwise.
package higherpass.TestImages; import import import import import import android.app.Activity; android.graphics.Bitmap; android.graphics.BitmapFactory; android.graphics.Matrix; android.os.Bundle; android.widget.ImageView;

public class TestImages extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); ImageView image = (ImageView) findViewById(R.id.test_image); Bitmap bMap = BitmapFactory.decodeResource(getResources(), R.drawable.test); Matrix mat = new Matrix(); mat.postRotate(90); Bitmap bMapRotate = Bitmap.createBitmap(bMap, 0, 0, bMap.getWidth(), bMap.getHeight(), mat, true); image.setImageBitmap(bMapRotate); } }

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

Create a bitmap resource, bMap, containing the original bitmap. Create a new instance of the Matrix class. Use the postRotate() method of the Matrix instance to set the amount of rotation in degrees. Use the Bitmap.createBitmap() method to create a new rotated bitmap. This instance of createBitmap() expects the original bitmap, starting X, starting Y, ending X, ending Y, Matrix translation, true to enable filters as arguments.

Exploring Android LinearLayout And RelativeLayout


LinearLayout
The LinearLayout is the most simple layout available in Android. A LinearLayout organizes layout components in a linear fashion horizontally or vertically. Create a new Android project TestBasicLayout in Eclipse to develop in.

Setup of Layout XML file


Android stores layouts in XML files located in the res/layouts/ directory of the project. All projects come with a default LinearLayout that displays a simple hello world message.
<?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" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" /> <TextView android:id="@+id/black_on_red" android:layout_width="fill_parent" android:layout_height="wrap_content" android:background="#ff0000" android:textColor="#000000" android:text="black on red" /> <TextView android:id="@+id/update_me" android:layout_width="fill_parent" android:layout_height="wrap_content" android:background="#00ff00" android:textColor="#000000" android:text="@string/update_text" /> </LinearLayout>

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

This is a simple Android LinearLayout. This layout specifies a vertical orientation. The orientation attribute of the LinearLayout tag references the arrangement of layout components not the direction of the screen. The width and height components are set to fill_parent which tells the layout to use all available screen space. The other available option for the width and height attributes is wrap_content, which tells the component to only use the required space for the contained component. Nested inside the LinearLayout are the view components. These specify what is displayed onto the screen. In this layout we simply use 3 TextView elements. The first elements is the default hello world created with the project. Next we added 2 new TextView components. The first specifies a red background with black text. If you wish to access a view component from the application an id must be assigned. The java code below will access the third TextView. Android uses the hex #RRGGBB red, green, blue format similar to HTML to represent color codes. A static text value was also used in the layout. This is a suboptimal way of displaying text. The third TextView component displays this properly. Use value from the strings.xml file to store the text. The strings.xml file is a configuration file that the SDK autogenerates code from. The strings.xml file is stored in res/values in the project. Here is what should be added to res/values/strings.xml.
<string name="update_text">this should be updated</string>

At this point run the project. We'll cover some Java in a second. Adjust the values of the layout_width and layout_height and see the results. If the last TextView height is changed to fill_parent the green background fills the pane. Also notice that if the first or second TextView elements height are changed to fill_pane the elements of the layout below that are off screen.

Loading the layout


Layouts are loaded by calling the setContentView() method from the SDK.
package higherpass.TestBasicLayout; import android.app.Activity; import android.os.Bundle; import android.widget.TextView; public class TestBasicLayout extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); TextView updateView = (TextView) findViewById(R.id.update_me); updateView.setText("New updated text here"); } }

This is a simple Android application that simply loads the LinearLayout we just created and changes the value of the last TextView. Use the findViewById() function to get the appropriate view element from the application. The findViewById() method expects an integer parameter from the auto-generated variable R representing the view. This variable, R.id.update_me, was set in the TextView element of the LinearLayout.
A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

RelativeLayout
The RelativeLayout Organizes layout components in relation to each other. This provides more flexibility of component positioning than LinearLayouts.

Setup Of The Layout main.xml File


The layout of the RelativeLayout XML file is very similar to LinearLayouts and all other layouts. Start with a RelativeLayout tag and nest the needed components.
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:id="@+id/hello" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" /> <TextView android:id="@+id/black_on_red" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_below="@id/hello" android:background="#ff0000" android:textColor="#000000" android:text="black on red" /> <TextView android:id="@+id/update_me" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_below="@id/black_on_red" android:background="#00ff00" android:textColor="#000000" android:text="@string/update_text" /> <TextView android:id="@+id/left_wrap" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/update_me" android:background="#0000ff" android:textColor="#000000" android:text="wrap" /> <TextView android:id="@+id/right_fill" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_below="@id/update_me" android:layout_toRightOf="@id/left_wrap" android:background="#ff0000" android:textColor="#000000" android:text="fill" />

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

</RelativeLayout>

Other than changing the LinearLayout to RelativeLayout there isn't much change to the beginning of the layout. Notice the RelativeLayout doesn't need the orientation attribute. When using a RelativeLayout all elements should have an ID. This ID will be referenced in the placement attributes. See how the black_on_red TextView the attribute android:layout_below is used to specify that the component should be placed below the hello component. On the last component, right_fill, it's placed under update_me and to the right of left_wrap TextViews. The java code doesn't need to change to load the RelativeLayout. Run the program and see what it does or use the layout viewer in eclipse.

Nesting Layouts
Sometimes there's a need to insert a layout inside a layout, to do that simply nest one layout inside another.
<?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/hello" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" /> <TextView android:id="@+id/black_on_red" android:layout_width="fill_parent" android:layout_height="wrap_content" android:background="#ff0000" android:textColor="#000000" android:text="black on red" /> <TextView android:id="@+id/update_me" android:layout_width="fill_parent" android:layout_height="wrap_content" android:background="#00ff00" android:textColor="#000000" android:text="@string/update_text" /> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:id="@+id/left_wrap" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/update_me" android:background="#0000ff" android:textColor="#000000" android:text="wrap"

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

/> <TextView android:id="@+id/right_fill" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_below="@id/update_me" android:layout_toRightOf="@id/left_wrap" android:background="#ff0000" android:textColor="#000000" android:text="fill" /> </RelativeLayout> </LinearLayout>

Here we changed the main layout back to a LinearLayout and removed the layout positioning attributes from the first 2 TextViews. To position the 2 TextViews horizontally in a vertical LinearLayout we must nest another view. Here we chose to use a RelativeLayout. A horizontally orientied LinearLayout would've worked as well.

Writing A Basic Android Application


Introduction
This tutorial assumes you have a decent knowledge of Java, and have already installed the Android SDK and Eclipse Plugin. Visit the Installing Android SDK tutorial to get the Android SDK and Eclipse plugin installed. The application built in this tutorial will demonstrate how to do various tasks in Android over making a truly productive application. The tutorial starts slow with creating a project.

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

Create A New Android Project


Open Eclipse and go to New Project > Android Project. Enter the following information to create the project.

The base project created for Android is a hello world implementation.

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

Setup Application Resources


Google did an excellent job creating a project layout that allows you to easily separate data from code. The res/ directory in the project stores layout, images, and application data. Localization data is also stored in this directory, but that's beyond the scope of this tutorial.

Strings
Now Open res/values/strings.xml Since the application is going to demonstrate how to use different features, change the hello string value to instruct the user to push one of the below buttons. Next add a string named button_dialog_text by clicking add then select string and press OK. A new String will appear in the list and the input fields to the right should be blank. Enter "button_dialog_text" in the name and "Show Dialog Box" in the value fields both without quotes and click the new String resource on the left side. Do the same for button_sound_text with the value "Play Sound".

At the bottom of the pane there are 2 tabs, resources and strings.xml. Click the strings.xml tag to view the raw XML of the file. Manually add a new string with a name of "button_relative_text" and a value of "Show Relative Layout". The XML tag should look like Show Relative Layout. Before we move on to setting up layouts add the following strings to the XML file. We'll use these later.
<string <string <string <string <string <string name="button_update_text">Update</string> name="dialog_title">Dialog Box Title</string> name="dialog_text">Click OK or Cancel to close</string> name="dialog_ok">OK</string> name="dialog_cancel">Cancel</string> name="sound_file">/sdcard/moonbeam.ogg</string>

Writing A Basic Android Application

Android Layouts
Android builds display components out of views. The views are built from XML files that tell android how to build the display. These layouts are stored in res/layout/. Open the res/layout/main.xml layout file. The Eclipse SDK includes a visual layout tool that should have come up. Similar to the strings.xml file edited earlier there is another tab at the bottom of the pane to display the raw XML file, but we're going to explore the visual editor
A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

first. Remember the visual editor is no substitute to checking how the display looks in the emulator and on a physical device. First change the orientation to portrait with the config dropdown at the top of the pane. Click on the button to the left side and drag it into the view below the string. Notice the bottom pane changed over to the properties tag and now shows the properties for the button. Find the field "text" it should currently have a value of @id/Button01. Change the value to @string/button_dialog_text. Using stored strings and not hard coding values in layouts will be important if you ever try to localize your application to different regions and languages. Now add a second button and change the text value to @string/button_sound_text. Next click over to the main.xml tab at the bottom and lets explore the XML. As with other XML files this one opens with the standard XML tag.

LinearLayout
Next the LinearLayout tag opens to declare the layout style. The LinearLayout is a simple layout where each View component is placed directly after the previous element. The first element inside the linear layout is our hello object that was created with the project. Next are the two buttons we created. Now lets add the show relative layout button manually. Usually you want to give your buttons and other objects descriptive ID tags, but for simplicity just give this button the ID of Button03. Copy and paste Button02 and change the android:id value to "@+id/Button03" and the android:text value to "@string/button_relative_text". Then click back to the layout tab and the new button should be shown.

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

Next we need to create the relative layout.

RelativeLayout
The RelativeLayout is another simple Android layout. RelativeLayouts allows you to position objects relative to other objects on the page. Right click on res/layouts/ and select New > Android XML file. In the dialog box enter relative.xml for the File. The type of resource is layout and at the bottom select RelativeLayout for the root element. Click finish to create and open the file. Again change the config to portrait for consistency. The RelativeView is going to display a number of different components that can be placed in a view. First add an EditText by finding it under views to the left and dragging it into the layout. Next click the relative.xml tab at the bottom of the pane. From here out we're going to adjust this layout by hand. Notice that the root tag for this is RelativeLayout compared to the LinearLayout of the main.xml file. Relative layouts allow you to locate elements relative to previously declared elements in the layout with simple keywords. Change the android:layout_width value for the EditText from wrap_content to fill_parent. This will expand the text box to fill the screen. Now add a button to the layout by creating a new Button tag below the EditText.
<Button android:id="@+id/button_update" android:text="@string/button_update_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/EditText01" android:layout_alignParentRight="true" />

The Button tag simply creates a button. We assigned the ID button_update and the text value button_update_text from res/values/strings.xml. The android:layout_width and layout_height fields are required for the element to be displayed. They can be set to either wrap_content or fill_parent. To position the element in the view the android:layout_below and android:layout_alignParentRight are used. This sets the button to be below the EditText01 element with the android:layout_below attribute. The android:layout_alignParentRight boolean being set to true right aligns the element to the right edge of the parent element. Next lets add a Spinner element to the layout. This element is similar to a dropdown on a webpage. They are best used to display a list. This tutorial isn't going to elaborate on usage of the spinner, just display one.
<Spinner android:id="@+id/spinner_names" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_below="@id/button_update" />

Spinner elements are declared with the Spinner tag. Give the spinner an id of @+id/spinner_names. Notice that for the android:layout_width we expanded it out to fill the window with fill_parent. Simply position the Spinner below the update button.

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

Writing A Basic Android Application


Working with the AndroidManifest.xml File
Now that we've added a new view we need to create an associated activity. Activities need to be registered in the AndroidManifest.xml file. When the project was created we defined an activity TestApp. This was setup as an activity for the application in the AndroidManifest.xml file when the project was created. Bring up the XML by clicking the AndroidManifest.xml tab at the bottom of the main pane.
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.higherpass.testapp" android:versionCode="1" android:versionName="1.0"> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".TestApp" 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> <uses-sdk android:minSdkVersion="5" /> </manifest>

Notice the manifest starts with the standard xml tag. Then there is a manifest tag that links to the schema and defines the package, versionCode, and versionName attributes. Nested inside the manifest tag is an application tag. The application tag has the attributes android:icon and android:label that define the applications icon and the label respectively. The application tag contains the activity nodes that define the accessible activities of the application. When the project was created the first activity for TestApp was pre-populated into the file. Notice the android:name value starts with a "." this is because it's the class that's appended to the package name. The label for the activity is set to the app_name string from strings.xml. The intent-filter tag is used to declare the intents for the activity. An intent is simply a tag defining an attributes of the activity. The action tag with a name of "android.intent.action.MAIN" will declare the activity as the initial activity. The category tag with a name of "android.intent.category.LAUNCHER" allows the activity to be an initial activity and will list the activity in the Android application launcher. We need to declare a second activity. Click on the Application tab at the bottom of the pane. Scroll to the bottom of the page to expose all of the Application Nodes and Attributes for Activity sections. Click Add under Applicaton Nodes. In the dialog select Activity and click OK. Now select the new activity and update the section under Attributes. First set the name to Relative then the label to @string/app_name. Click on the

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

activity and save the file.

There will be an error in the file until we create the Relative activity class in a minute. Before creating the Relative activity class take a second to explore the XML created by adding the new activity. Click back to the AndroidManifest.xml tab at the bottom of the main pane. You should see a new activity tag that looks like the following.
<activity android:name="Relative" android:label="@string/app_name"> </activity>

The activity tag simply gives the activity a name and declares a label for the window.

Writing A Basic Android Application


Building The Android Code
Now that the foundation for the application has been created it's lets start building the Java. First create the Relative class to clear the error. Right click on com.higherpass.testapp in the left pane and select New > Class.

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

Enter Relative for the name and android.app.Activity for the superclass.

We are going to leave the Relative class for later though, but as long as the class exists the error from AndroidManifest.xml will be cleared. Now open the TestApp.java file in src/com.higherpass.testapp in the package explorer. This is the default activity for our application and what will be executed when the program is launched. This class was pre-filled with code to load any saved running instance data and to build the layout from main.xml. The variable R is a special object that is built by the SDK in auto generated code. The setContentView method displays the view.
package com.higherpass.testapp; import android.app.Activity; import android.os.Bundle; public class TestApp extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } }

At this point the application will launch and display the buttons we created in main.xml. The next thing we need to do is to create our dialog box.
final Builder dialog = new AlertDialog.Builder(this); dialog.setTitle(R.string.dialog_title); dialog.setMessage(R.string.dialog_text); dialog.setPositiveButton(R.string.dialog_ok, null); dialog.setNegativeButton(R.string.dialog_cancel, null);

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

Place this code in the onCreate function in TestApp.java below the setContentView statement. The code first creates the builder that will deploy the dialog box. Next set the title and body of the dialog box with the setTitle and setMessage methods respectively. The OK/Cancel buttons are created with the setPositiveButton and setNegativeButton functions. Notice that we use the R variable to pass the int value of the ID of the string values from strings.xml. Now we need to attach an on-click listeners to the first button.
Button btnDialog = (Button) findViewById(R.id.Button01); btnDialog.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { dialog.show(); } });

To create the on-click listener the first thing to do is create a Button object representing the button in the layout. Use findViewById to retrieve the Button. Since buttons are superclassed from a TextView which is superclassed from View it's easy to cast findViewById back to a Button object. Most view components are built from the View class which allows easy casting to the proper type from findViewById. Next call the setOnClickListener and pass a new anonymous OnClickListener() instance. Finally set the action in the onClick method to dialog.show() to make the dialog visible with focus. Next create the on-click listener for the play sound button. This is the same procedure as before except that instead of initializing a dialog box we start the music player. Notification sounds are usually stored in /system/media/audio/notifications, but unfortunately the emulators don't have them installed so you'll need to copy a music file into the virtual SD card.
$ adb push /local/path/to/sound/file /sdcard/file

The adb push command is used to send files to the device (physical or emulator) connected to adb. The first argument is the path to the file on local disk and the second argument is the path on the device to store the file. /sdcard is normally the path to the SD card (physical or virtual). Now for the code to use the built in music player to play the file. The path to the file was set in strings.xml earlier. The file, moonbeam.ogg, listed in strings.xml was copied from a physical phone with the adb pull command.
Button btnSound = (Button) findViewById(R.id.Button02); btnSound.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { MediaPlayer player = new MediaPlayer(); try { player.setDataSource(getString(R.string.sound_file)); player.prepare(); player.start(); } catch (Exception e) { e.printStackTrace(); } } });

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

Attach an on-click listener to Button02 that launches the music player. Initialize a MediaPlayer object as player. Open a try/catch block to catch exceptions from the MediaPlayer object. Then set the file to play from the value of the sound_file string in strings.xml. Use the prepare statement to ready the MediaPlayer for use. Then use the start method to play the file. Finally if an exception is caught print the stack trace.

Writing A Basic Android Application


Launching the RelativeLayout
The third button actually launches a new view. This is done with an on-click listener as before, but this time we launch a new view.
Button btnRelative = (Button) findViewById(R.id.Button03); btnRelative.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Intent i = new Intent(TestApp.this, Relative.class); startActivity(i); finish(); } });

Just as with the previous buttons we need to get the button and create an object with it. Then create an OnClickListener. This time the listener starts a new intent passing the current Class.this followed by the activity to launch. In this case Relative.class is the parameter. Then call startActivity passing the new intent to launch the activity. Finally call finish to complete the activity. Now lets look at the Relative.java file that contains the new activity. This activity simply displays the view from relative.xml. This is a simple Activity that just overrides the onCreate function. All we do is have to call the setContentView to the relative layout by passing the ID to the layout stored in the auto-generated R variable.
package com.higherpass.testapp; import android.app.Activity; import android.os.Bundle; public class Relative extends Activity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.relative); } }

This wraps up writing a basic Android application and should get you started developing on your own.

Installing The Android SDK In Eclipse


A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

Introduction
The Android SDK is a development kit created by Google for developing on the Android platform. Google also released an Eclipse plugin that allows for Android SDK integration in the Eclipse IDE. Also an emulator is included to ease development and debugging. The development kit is modular allowing for only certain components or Android SDK versions to be installed.

Downloading and installing the Android SDK


Download the Android SDK from Google http://developer.android.com/sdk/index.html. Uncompress the downloaded archive and copy the package to a suitable location. Take note of this location you'll need to put it into the Eclipse plugin later.
$ tar -zxvf android-sdk_r3-linux.tgz # cp -a android-sdk-linux /usr/local

Installing the Eclipse plugin

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

Open Eclipse and go to Help > Install New Software. Then click add button to add a new site.

Give the new site a descriptive name such as Google Android Dev and use eclipse update site https://dlssl.google.com/android/eclipse/ to install the Android ADT eclipse plugin. Click ok and eclipse will download the information about available packages from the new site.

Check developer tools and click next.

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

Click next again confirming the list to install including any dependancies. Accept the license agreement and click finish. Eclipse will download and install the plugins. Accept any warnings about an unsigned application being installed. Finally Restart Eclipse when prompted

Configure The Android Eclipse Plugin


Go to Window > Preferences and open the android preferences. Set the location of the Android SDK to where you installed it earlier. Now it's time to install the plugin packages.

Install SDK Packages


Once the SDK has been installed there are associated packages that need to be downloaded through the SDK. Go to Window > Android AVD and SDK Manager. Notice the phone icon next to the option. That also appears in the toolbar as a shortcut to the Android AVD & SDK manager.

Click available packages in the left pane and expand the predefined Google source. Select the SDK platforms and APIs for the desired platforms and click install selected. It's probably best just to install all the packages as applications should be tested on multiple platforms and Android revisions. Accept the license agreement and click install. This is a lot of data so expect it to take a while depending on your internet speed. Finally restart adb when prompted. The packages should now be listed under the installed packages pane.

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

Installing The Android SDK In Eclipse


Building an emulator
In the Android SDK and AVD Manager click virtual devices in the left pane and click new. Give the Emulator a familiar name. Next select the proper target android level. This is the version of Android the emulator will run. Then enter the size of the virtual SD Card to be created for the emulator. There are also a number of device functionality emulators included that can be added. These provide mock versions of the camera, gps, etc to be developed against. Finally Click create AVD. Once the AVD has been created a dialog box will inform you.

Attaching a physical device


Physical devices can also be used to develop applications against. They are faster and less resource intensive than running the emulator. Once a device has been properly configured and is attached to the system they will appear in the Android SDK and AVD Manager. In Linux udev must be setup for the phone to be properly detected.

Android Device udev Rules


This is a simple addition to /etc/udev/rules.d. Create a new file /etc/udev/rules.d/51-android.rules containing one of the following lines. The SYSFS{idVentor}== value needs to be adjusted to the correct USB ID for your device. Depending on your linux distro one of the following 2 lines:
SUBSYSTEM=="usb_device", SYSFS{idVendor}=="22b8", MODE="0666"

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi

OR
SUBSYSTEM=="usb", SYSFS{idVendor}=="22b8", MODE="0666"

Android USB Device Chart HTC - 0bb4 Motorola - 22b8 Samsung - 04e8 Acer - 0502 Sony Ericsson - 0fce

A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi