Archive

Posts Tagged ‘Android API’

Android Basics – Dialogs and Floating Activities

January 23rd, 2009

As we know android provide Activity class for developing application screens. But many a time application needs to show Dialog boxes or floating screen to do simple tasks likes taking input from user or ask for confirmation etc.

In android Dialogs can be created in following 2 ways:

1. Creating a dialog with the help of android Dialog class or its subclass like AlertDialog.
2. Using dialog theme for the activity.

Using android Dialog class:
Let see how we can create a dialog with the help of Dialog class. To define a dialog the dialog class has to extend the android Dialog class.

class MyDialog extends Dialog {
/**
* @param context
*/
public MyDialog(Context context) {
super(context);
}
}

Define a layout for our dialog. Here is the xml file for of the layout that asks for user’s name.

<?xml version=”1.0″ encoding=”utf-8″?>


<LinearLayout
android:id="@+id/widget28"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android"
>
<TextView
android:id="@+id/nameMessage"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Enter Name:"
>
</TextView>
<EditText
android:id="@+id/nameEditText"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="18sp"
>
</EditText>
<LinearLayout
android:id="@+id/buttonLayout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
>
<Button
android:id="@+id/okButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="OK"
>
</Button>
<Button
android:id="@+id/cancelButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Cancel"
>
</Button>
</LinearLayout>
</LinearLayout>

Use the above layout for our dialog

class MyDialog extends Dialog {
....

/** * @see android.app.Dialog#onCreate(android.os.Bundle) */ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.d("TestApp", "Dialog created"); setContentView(R.layout.mydialog); } }

Now the dialog can be shown by calling the show method like this

MyDialog dialog = new MyDialog(context);
dialog.show();

Event handling for the Dialog controls are same as in case of the activity. Modify the dialog code to handle the onclick event on the ok and cancel button.

class MyDialog extends Dialog implements OnClickListener {

private Button           okButton;

private Button           cancelButton;

private EditText         nameEditText;

protected void onCreate(Bundle savedInstanceState) { okButton = (Button) findViewById(R.id.okButton); cancelButton = (Button) findViewById(R.id.cancelButton);

nameEditText = (EditText) findViewById(R.id.nameEditText);

okButton.setOnClickListener(this); cancelButton.setOnClickListener(this); }

public void onClick(View view) { switch (view.getId()) { case R.id.okButton: dismiss(); break; case R.id.cancelButton: cancel(); break; } } }

To close the dialog the dismiss() method can be called. The dialog can call the dismiss method itself or some other code can also close the dialog by calling dismiss().

The dialog also supports cancel. Canceling means the dialog action is canceled and does not need to perform any operation. Dialog can be canceled by calling cancel() method. Canceling the dialog also dismisses the dialog.

When user clicks the phones BACK button the dialog gets canceled. If you do not want to cancel the dialog on BACK button you can set cancelable to false as

setCancelable(false);

Note that the cancel() method call till be able to cancel the dialog (which is the desirable functionality in most cases). The dialog’s cancel and dismiss events can be listened with the help of OnCancelListener and OnDismissListener.

Returning information from dialog:
Now our dialog can take the name from the user. We need to pass that name to the calling activity. Dialog class does not provide any direct method for returning values. But our own Listener can be created as follows:

public interface MyDialogListener {

public void onOkClick(String name); // User name is provided here.

public void onCancelClick(); }

The dialog’s constructor has to be modified to take the object of the listener:

public MyDialog(Context context, MyDialogListener listener) {
super(context);
this.listener = listener;
}

Now the calling activity needs to provide the object of the class that implements the MyDialogListener which will gets called on ok or cancel button clicks.

Now we need update the onclick method to return the user name.

public void onClick(View view) {
switch (view.getId()) {
case R.id.okButton:
listener.onOkClick(nameEditText.getText().toString()); // returning the user's name.
dismiss();
break;
case R.id.cancelButton:
cancel();
break;
}
}

Using AlertDialog:

AlertDialog is the subclass of the Dialog. It by default provide 3 buttons and text message. The buttons can be made visible as required. Following code creates an AlertDialog that ask user a question and provide Yes, No option.

AlertDialog dialog = new AlertDialog.Builder(context).create();

dialog.setMessage("Do you play cricket?"); dialog.setButton("Yes", myOnClickListener); dialog.setButton2("No", myOnClickListener);

dialog.show();

The onClick method code for the button listener myOnClickListener will be like this:

public void onClick(DialogInterface dialog, int i) {
switch (i) {
case AlertDialog.BUTTON1:
/* Button1 is clicked. Do something */
break;
case AlertDialog.BUTTON2:
/* Button2 is clicked. Do something */
break;
}
}

AlertDialog.Builder:
AlertDialog has a nested class called ‘Builder’. Builder class provides facility to add multichoice or single choice lists. The class also provides methods to set the appropriate Adaptors for the lists, set event handlers for the list events etc. The Builder button calls the Button1, Button2, Button3 as PositiveButton, NeutralButton, NegativeButton.

Here is an example of dialog box with Multichoice list

new AlertDialog.Builder(context)
.setIcon(R.drawable.icon)
.setTitle(R.string.alert_dialog_multi_choice)
.setMultiChoiceItems(R.array.select_dialog_items,
new boolean[]{false, true, false, true, false},
new DialogInterface.OnMultiChoiceClickListener() {
public void onClick(DialogInterface dialog, int whichButton, boolean isChecked) {
/* Something on click of the check box */
}
})
.setPositiveButton(R.string.alert_dialog_ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {

/* User clicked Yes so do some stuff */ } }) .setNegativeButton(R.string.alert_dialog_cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) {

/* User clicked No so do some stuff */ } }) .create();

Activity Managed Dialog:

Android also provide facility to create dialogs. Activity created dialog can be managed by Activity methods like showDialog(), onCreateDialog(), onPrepareDialog(), dismissDialog(), removeDialog().
The onCreateDialog create the dialog that needs to be shown, for example

/**
* @see android.app.Activity#onCreateDialog(int)
*/
@Override
protected Dialog onCreateDialog(int id) {
return new AlertDialog.Builder(this).setMessage("How are you?").setPositiveButton("Fine", new DialogInterface.OnClickListener() {

public void onClick(DialogInterface dialog, int which) { /* Do something here */ } }).setNegativeButton("Not so good", new DialogInterface.OnClickListener() {

public void onClick(DialogInterface dialog, int which) { /* Do something here */ } }).create(); }

You can create multiple dialog boxes and differentiate them with the id parameter. The dialog can be shown with the help of showDialog(id) method. The onCreateDialog method gets called for the first time when showDialog method is called. For subsequent calls to the showDialog() the dialog is not created but shown directly.
If you need to update the dialog before it is getting shown then you can do that in onPrepareDialog() method. The methods get called just before the dialog is shown to the user.
To close the dialog you can call dismissDialog() method. Generally you will dismiss the dialogs in the click handles of the dialog buttons.
The removeDialog() method will remove the dialog from the activity management and if showDialog is again called for that dialog, the dialog needs to be created.

Using android Dialog theme for activity:
Another simple way to show the dialog is to make the Activity to work as a Dialog (floating activity). This can be done by applying dialog Theme while defining the activity entry in the AndroidManifest.xml

<activity android:name=”.DialogActivity” android:label=”@string/activity_dialog” android:theme=”@android:style/Theme.Dialog”>

</activity>

The activity will be shown as a dialog as the activity is using ‘Theme.Dialog’ as theme.

Android Basics , , , , , , ,

Android Application Lifecycle

January 14th, 2009

In Android, the applications are run as a separate Linux process. So the application lifecycle is closely related to the process lifecycle. The application process lifecycle is handled by the system depending on the current system memory state.

In case of low memory, the Android system kills some less important process. The process importance is decided depending on the state of the process components.

The process types depending on the importance are as follows (from most important to least important):

1. Foreground process: A foreground process is the application process with which the user is currently interacting. The process is considered to be foreground if its Activity is at the top of the Activity stack (its onResume() has been called) or BroadcastReceiver is currently running (onReceive() method is currently getting executed) or its Service is executing callback functions like onCreate(), onStart() or onDestroy() methods.

2. Visible Process: A visible process is the process which has an Activity visible to the user (its onPause() method has been called).

3. Service Process: Service process contains a Service for which startService method is called and the service is running.

4. Background Process: The background process does not have any visible activities to the user. (Activity onStop() method has been called).

5. Empty Process: Empty process is the one that does not have any active application components. These processes are kept on for caching purpose.

It is important that application developers understand lifecycle of the application process. Not using these correctly can result in the system killing the application’s process while it is doing important work.

Android Basics , , ,

Basics of Android : Part IV – Android Content Providers

January 9th, 2009

The last post in the series, which talks about basic Android development concepts. Android application can use a file or SqlLite database to store data. Content provider provides the way by which you can share the data between multiple applications. For example contact data is used by multiple applications and must be stored in Content Provider to have common access. A content provider is a class that implements a standard set of methods to let other applications store and retrieve the type of data that is handled by that content provider. If you want your data to be public and handle by many applications create your own content provider. Application can perform following operations on content provider -

  1. Querying data
  2. Modifying records
  3. Adding records
  4. Deleting records

Standard Content Provider: Android provide some standard content provider, which are already implemented in Android e.g. contacts, images on device etc. Using these content providers the application can access contact information, images available on the device etc. Querying data: The query string in content provider is different than standard sql query. For any operation like select, add, delete, modify we required content provider URI. The URI consist of three parts, the string “content://”, segment representing kind of data to retrieve and optional ID of specific item of the specified content provider. Here are some examples of query string:

content://media/internal/images URI return the list of all internal images on the device.

content://contacts/people/ URI return the list of all contact names on the device.

content://contacts/people/45 URI return the single result row, the contact with ID=45.

Although this is the general form of the query, query URIs are somewhat arbitrary and confusing. For this android provide list of helper classes in android.provider package that define these query strings so you should not need to know the actual URI value for different data types. So it will be easy to query data. Above URIs can be represented as:

MediaStore.Images.Media.INTERNAL_CONTENT_URI
Contacts.People.CONTENT_URI

To query about specific record we have to use same CONTENT_URI, but must append specific ID. So third URI becomes

Uri person = ContentUris.withAppendedId(People.CONTENT_URI, 23);

Here is how we can query for data:

Cursor cur = managedQuery(person, null, null, null);

This query returns the cursor which contains the fields, we can iterate through cursor to retrieve all data. Let’s see an example now, which will make concept clearer:

package com.wissen.testApp;

public class ContentProviderDemo extends Activity {

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

    private void displayRecords() {
        // An array specifying which columns to return.

        String columns[] = new String[] { People.NAME, People.NUMBER };
        Uri mContacts = People.CONTENT_URI;
        Cursor cur = managedQuery(mContacts, columns, // Which columns to return
                null, // WHERE clause; which rows to return(all rows)
                null, // WHERE clause selection arguments (none)
                null // Order-by clause (ascending by name)

        );
        if (cur.moveToFirst()) {
            String name = null;
            String phoneNo = null;
            do {
                // Get the field values
                name = cur.getString(cur.getColumnIndex(People.NAME));
                phoneNo = cur.getString(cur.getColumnIndex(People.NUMBER));
                Toast.makeText(this, name + " " + phoneNo, Toast.LENGTH_LONG).show();
            } while (cur.moveToNext());
        }
    }
}

In above example we are retrieving only specific columns contact name, number and displaying the contact records one by one. Modifying Records: To modify the set of records call the method ContentResolver.update() with columns and value to be changed. You can select the columns to be updated in Content query string or in method itself. Here is how it can be done:

private void updateRecord(int recNo, String name) {
        //appending recNo, record to be updated
        Uri uri = ContentUris.withAppendedId(People.CONTENT_URI, recNo);
        ContentValues values = new ContentValues();
        values.put(People.NAME, name);
        getContentResolver().update(uri, values, null, null);
    }

You can call above method to modify any record by specifying record number and name.

updateRecord(10,"XYZ");

This will change the name to “XYZ” of record number 10. Adding Records: To add a new record, call ContentResolver.insert() with the URI of the type of item to add, and a Map of any values you want to set immediately on the new record. This will return the full URI of the new record, including record number, which you can then use to query and get a Cursor over the new record. In above example what we have used is standard Content Provider, Contacts. We can add records in contacts also. Continuing our previous example, let us create insertRecord() method that will do the work of insertion.

private void insertRecords(String name, String phoneNo) {
        ContentValues values = new ContentValues();
        values.put(People.NAME, name);
        Uri uri = getContentResolver().insert(People.CONTENT_URI, values);
        Log.d("ANDROID", uri.toString());
        Uri numberUri = Uri.withAppendedPath(uri, People.Phones.CONTENT_DIRECTORY);
        values.clear();
        values.put(Contacts.Phones.TYPE, People.Phones.TYPE_MOBILE);
        values.put(People.NUMBER, phoneNo);
        getContentResolver().insert(numberUri, values);
    }

To insert record in contacts just call insertRecords(name, phoneNo). Deleting records: To delete record/records from content provider use getContextResolver.delete(). Following example deletes all contacts from device as no where condition is specified.

 private void deleteRecords() {
        Uri uri = People.CONTENT_URI;
        getContentResolver().delete(uri, null, null);
    }

You can delete specific records by specifying where condition in method as parameter. This will give you an idea, how to delete specific records:

getContentResolver().delete(uri, "NAME=" + "'XYZ XYZ'", null);

This will delete records whose name is ‘XYZ XYZ’. Creating Content Provider: We now know how to use the content Provider; let’s now see how to create a content provider. To create own Content Provider in android following steps needs to be followed: 1. Create a class that will extend ContentProvider. 2. Define a public static final Uri named CONTENT_URI. This is the string that represents the full “content://” URI that your content provider handles. You must define a unique string for this value; the best solution is to use the fully-qualified class name of your content provider (lowercase). So, for example:

public static final Uri CONTENT_URI = Uri.parse( "content://com.google.android.MyContentProvider");

3. Create your system for storing data. Most content providers store their data using Android’s file storage methods or SQLite databases, but you can store your data any way you want, so long as you follow the calling and return value conventions. 4. Define column names that you will return to client. If you are using android database the column will be same as database. But you database must include one column call as _id, which identify each record in database uniquely. 5. If you are exposing byte data, such as a bitmap file, the field that stores this data should actually be a string field with a content:// URI for that specific file. This is the field that clients will call to retrieve this data. The content provider for that content type (it can be the same content provider or another content provider – for example, if you’re storing a photo you would use the media content provider) should implement a field named _data for that record. The _data field lists the exact file path on the device for that file. This field is not intended to be read by the client, but by the ContentResolver. The client will call ContentResolver.openOutputStream() on the user-facing field holding the URI for the item (for example, the column named photo might have value content://media/images/4453). The ContentResolver will request the _data field for that record, and because it has higher permissions than a client, it should be able to access that file directly and return a read wrapper for that file to the client. 6. Declare public static String for client to specify which column to return or to specify field value from cursor. 7. Return a Cursor object in response to query. This means write down all the overridden methods such as insert(), update() and delete() those will perform operations on underlying database. We may notify the listeners about updated information by using ContentResover().notifyChange(). 8. Add <provider> tag to AndroidMenifest.xml and set its authorities to define the authority part of the content type it should handle. 9. If you are handling a new data type, you must define a new MIME type to return for your implementation of android.ContentProvider.geType(url). This type corresponds to the content:// URI submitted to getType(), which will be one of the content types handled by the provider. The MIME type for each content type has two forms: one for a specific record, and one for multiple records. Use the Uri methods to help determine what is being requested. Here is the general format for each:

vnd.android.cursor.item/vnd.yourcompanyname.contenttype for a single row.

For example, a request for train record 122 using content://com.example.transportationprovider/trains/122 might return the MIME type vnd.android.cursor.item/vnd.example.rail

vnd.android.cursor.dir/vnd.yourcompanyname.contenttype for multiple rows.

For example, a request for all train records using content://com.example.transportationprovider/trains might return the MIME type vnd.android.cursor.dir/vnd.example.rail Here is the code that creates a content provider. The example just store user name and display the user names of all the users. SQLLite database is used to store the user data.

package com.wissen.testApp;

public class MyUsers {

    public static final String AUTHORITY = "com.wissen.MyContentProvider";

    // BaseColumn contains _id.
    public static final class User implements BaseColumns {

        public static final Uri    CONTENT_URI = Uri.parse("content://com.wissen.MyContentProvider");

        // Table column
        public static final String USER_NAME   = "USER_NAME";
    }
}

The above class defines the CONTENT_URI of the content provider, it also defines the columns of the content provider. Next we will define the actual content provider class that will use the above defined class.

package com.wissen.testApp.android;

public class MyContentProvider extends ContentProvider {

    private SQLiteDatabase      sqlDB;

    private DatabaseHelper      dbHelper;

    private static final String DATABASE_NAME    = "Users.db";

    private static final int    DATABASE_VERSION = 1;

    private static final String TABLE_NAME       = "User";

    private static final String TAG              = "MyContentProvider";

    private static class DatabaseHelper extends SQLiteOpenHelper {

        DatabaseHelper(Context context) {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
        }

        @Override
        public void onCreate(SQLiteDatabase db) {
            //create table to store user names
            db.execSQL("Create table " + TABLE_NAME + "( _id INTEGER PRIMARY KEY AUTOINCREMENT, USER_NAME TEXT);");
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
            onCreate(db);
        }
    }

    @Override
    public int delete(Uri uri, String s, String[] as) {
        return 0;
    }

    @Override
    public String getType(Uri uri) {
        return null;
    }

    @Override
    public Uri insert(Uri uri, ContentValues contentvalues) {
        // get database to insert records
        sqlDB = dbHelper.getWritableDatabase();
        // insert record in user table and get the row number of recently inserted record
        long rowId = sqlDB.insert(TABLE_NAME, "", contentvalues);
        if (rowId > 0) {
            Uri rowUri = ContentUris.appendId(MyUsers.User.CONTENT_URI.buildUpon(), rowId).build();
            getContext().getContentResolver().notifyChange(rowUri, null);
            return rowUri;
        }
        throw new SQLException("Failed to insert row into " + uri);
    }

    @Override
    public boolean onCreate() {
        dbHelper = new DatabaseHelper(getContext());
        return (dbHelper == null) ? false : true;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
        SQLiteDatabase db = dbHelper.getReadableDatabase();
        qb.setTables(TABLE_NAME);
        Cursor c = qb.query(db, projection, selection, null, null, null, sortOrder);
        c.setNotificationUri(getContext().getContentResolver(), uri);
        return c;
    }

    @Override
    public int update(Uri uri, ContentValues contentvalues, String s, String[] as) {
        return 0;
    }
}

So we created a content Provider class as MyContentProvider and wrote code for insertion and retrieving records from Sqlite database. The content provider entry has to be added in the AndroidManifest.xml file as follows:

<provider android:name="MyContentProvider" android:authorities="com.wissen.MyContentProvider" />

Now Lets use the above defined content provider:

package com.wissen.testApp;

public class MyContentDemo extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        insertRecord("MyUser");
        displayRecords();
    }

    private void insertRecord(String userName) {
        ContentValues values = new ContentValues();
        values.put(MyUsers.User.USER_NAME, userName);
        getContentResolver().insert(MyUsers.User.CONTENT_URI, values);
    }

    private void displayRecords() {
        // An array specifying which columns to return.
        String columns[] = new String[] { MyUsers.User._ID, MyUsers.User.USER_NAME };
        Uri myUri = MyUsers.User.CONTENT_URI;
        Cursor cur = managedQuery(myUri, columns, // Which columns to return
                null, // WHERE clause; which rows to return(all rows)
                null, // WHERE clause selection arguments (none)
                null // Order-by clause (ascending by name)
        );
        if (cur.moveToFirst()) {
            String id = null;
            String userName = null;
            do {
                // Get the field values
                id = cur.getString(cur.getColumnIndex(MyUsers.User._ID));
                userName = cur.getString(cur.getColumnIndex(MyUsers.User.USER_NAME));
                Toast.makeText(this, id + " " + userName, Toast.LENGTH_LONG).show();
            } while (cur.moveToNext());
        }
    }
}

The above class first adds a user entry in the database and then displays all the usernames available in the db. So we saw how to user the content providers and how to create our own content provider. From this post on wards we will be diving deep into specific APIs like Android Media API, Android Communications API, Accelarometer and lots of other stuff.

Android Basics , , ,

Basics of Android : Part III – Android Services

January 8th, 2009

Many a times the application needs to do some tasks in the background for which user interventions is not required (or very less intervention is required). These background processes keeps working even if user is using some other application on the phone.

To define such background processes android has a concept of Services. Service in android is long lived application component. Service doesn’t implement any User Interface. Common example of service is Media Player application that keeps playing song in the background, file download application that can download the file in the background.

Let’s see how to create a service.

Creating a service

Android has defined a base class for all services as ‘Service’. All the services have to extend from this Service class. Service class defines service lifecycle methods like onCreate(), onStart(), onDestroy(). Here is the example a service class

package com.wissen.testApp.service;
public class MyService extends Service {
	@Override
	public IBinder onBind(Intent intent) {
		return null;
	}
	@Override
	public void onCreate() {
		super.onCreate();
		Toast.makeText(this, "Service created...", Toast.LENGTH_LONG).show();
	}

	@Override
	public void onDestroy() {
		super.onDestroy();
		Toast.makeText(this, "Service destroyed...", Toast.LENGTH_LONG).show();
	}
}

The above service is notifying the user when the service is created and service is destroyed.

Like every thing else in android, Service in android are also associated with the intents. This intent is required while using the service.

The service entry has to be done in the AndroidManifest.xml file along with the service intent as shown below:

<service class=".service.MyService">
<intent-filter>
<action android:value="com.wissen.testApp.service.MY_SERVICE" />
</intent-filter>
</service>

Now our service is created and can be used by the application code.

Using the service:

The application can start the service with the help of Context.startService method. The method will call the onCreate method of the service if service is not already created; else onStart method will be called. Here is the code to start the MyService

..

Intent serviceIntent = new Intent();
serviceIntent.setAction("com.wissen.testApp.service.MY_SERVICE");
startService(serviceIntent);

The service started with startService method will keep on running until stopService() is called or stopSelf() method is called.

Another way to use service is to bind to the service. The service contented this way will be considered required by the system only for as long as the calling context exists. To bind to the service a service connection object need to be created. The service connection object tell the application when the service is connected or disconnected. Here is how you can bind to the service.

ServiceConnection conn = new ServiceConnection() {
	@Override
	public void onServiceConnected(ComponentName name, IBinder service) {
	Log.i("INFO", "Service bound ");
	@Override
	public void onServiceDisconnected(ComponentName arg0) {
	Log.i("INFO", "Service Unbound ");
	}
	}

	bindService(new Intent("com.wissen.testApp.service.MY_SERVICE"), conn, Context.BIND_AUTO_CREATE);
}

The application can communicate with the service when application is connected with the service. Generally the service communicate is done with the help of Service Interface. Service interface defines methods for which service can provider implementation. For example here is some interface:

package com.wissen.testApp;
public interface IMyService {
public int getStatusCode();
}

Using this interface the application can ask the Service about its status. Lets see how the service can support this interface. Previously we saw a method called onBind which return IBinder object, the method gets called when some client of the service binds to the service. This is the same object that is passed to the onServiceConnected method. The application can communicate with the service using this IBinder object. Here is how this can be done:

 

public class MyService extends Service {
	private int statusCode;
	private MyServiceBinder myServiceBinder = new MyServiceBinder();
	@Override
	public IBinder onBind(Intent intent) {
		return myServiceBinder; // object of the class that implements Service
								// interface.
	}
	public class MyServiceBinder extends Binder implements IMyService {

		public int getStatusCode() {
			return statusCode;
		}
	}
	// .......
}

 

And here is how application can call getStatusCode method:

 

	ServiceConnection conn = new ServiceConnection() {
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			IMyService myService = (IMyService) service;
			statusCode = myService.getStatusCode();
			Log.i("INFO", "Service bound ");
		}
		// ........
	};

You can also define ServiceListener interface which the client of the service has to be implemented to gets update from the service. In that case the service interface will have to define methods to register and unregister the ServiceListener objects.

Communication with Remote Service:

The services that we defined until now run in the application processes, you can define service that can run in their own process. For two processes to communicate with each other they need to marshal the object to sent to other process.

Android provide an AIDL tool (Android Interface definition Language) to handle all marshalling and communication part.

 

The service has to provide the Service interface as an aidl file. The AIDL tool will create a java interface corresponding for the aidl Service Interface. The AIDL tool also defines a stub class in the generated service interface, which implements the Service Interface (as abstract methods) and also provides some other required functionality. The service interface implementation class has to extend this stub class and define the service interface methods. The service onBind method will return object of this implementation class so that the client application can use the service methods. Here is the how the communication can be done:

Create a file as IMyRemoteService.aidl as follows:

 

package com.wissen.testApp;

interface IMyRemoteService {
int getStatusCode();
}

The eclipse android plug-in will create a Java interface for the aidl file created above as the part of build process.

The interface generated above will have a Stub inner class. Define a class that extends this stub class. Here is the code for the RemoteService class:

package com.wissen.testApp;
class RemoteService implements Service {
	int statusCode;

	@Override
	public IBinder onBind(Intent arg0) {
		return myRemoteServiceStub;
	}
	private IMyRemoteService.Stub myRemoteServiceStub = new IMyRemoteService.Stub() {
		public int getStatusCode() throws RemoteException {
			return 0;
		}
	};
	// ........
}

When the client application connect to the service the onServiceConnected method will be called and client will get the IBinder object of the service. The Stub class also provides a method to obtain the Service Interface object from the IBinder object. Here is the client onServiceConnected code

 

	ServiceConnection conn = new ServiceConnection() {
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			IMyRemoteService myRemoteService = IMyRemoteService.Stub
					.asInterface(service);

			try {

				statusCode = myRemoteService.getStatusCode();
			} catch (RemoteException e) {

				// handle exception

			}

			Log.i("INFO", "Service bound ");
		}
		// .........
	};

Permissions:

Service may specify required user permissions in the AndroidManifest.xml in <service> tag like this,

<service class=".service.MyService" android:permission="com.wissen.permission.MY_SERVICE_PERMISSION">
<intent-filter>
<action android:value="com.wissen.testApp.service.MY_SERVICE" />
</intent-filter>
</service>

Then to use above service the application has to ask for permission with the help of <user-permission> tag as follows:

<uses-permission android:name="com.wissen.permission.MY_SERVICE_PERMISSION"></uses-permission>

So in today’s post we saw how to create service and use it. In the next post we will see how to use ContentProviders. 

Android Basics , ,

Basics of Android : Part II – Intent Receivers

January 7th, 2009

In the last post we see about the Android activities and how to use them.

In this post we will see about the IntentReceivers.

Android Intent receivers are part of the event handling mechanism. The intent receiver can handle the broadcaste intents and thus can be used as event handler.

Creating Intent Receivers:

Android has defined a ‘BroadcastReceiver’ class. All the intent receivers have to inherit from this class. Following is the example of the intent receiver

package com.wissen.testApp.receiver;

public class MyIntentReceiver extends BroadcastReceiver {

/**

* @see adroid.content.BroadcastReceiver#onReceive(android.content.Context, android.content.Intent)

*/

@Override

public void onReceive(Context context, Intent intent) {

...

}

}

The intent receiver has to override the method onReceive as shown above. The onReceive method gets called when intent receiver’s intent is broadcasted, and thus onReceive() method is the entry point for the intent receiver.

The intent receiver entry has to be done in the AndroidManifest.xml file. The intent receiver can be defined in manifest xml as follows:

<receiver android:name=”.receiver.MyIntentReceiver” android:enabled=”true”>
<intent-filter>
<action android:name=”com.wissen.testApp.MY_INTENT_RECEIVER” />
</intent-filter>
</receiver>

The intent receiver can also be registered dynamically with the help of Context.registerReceiver() method as follows:

..


MyIntentReceiver intentReceiver = new MyIntentReceiver();

IntentFilter intentFilter = new IntentFilter("com.wissen.testApp.MY_INTENT_RECEIVER");

registerReceiver(intentReceiver, intentFilter);

..

Broadcasting Intent:

The intent can be broadcasted with the help of sendBroadcast() and sendOrderedBroadcast() method of the Context class. The sendBroadcast method will send the broadcast to all the registered Intent Receivers, on the other hand sendOrderedBroadcast() method calls the intent receivers one at a time. This gives the intent receivers ability to exchange result of previous intent receiver or to abort the broadcast. The order of execution is controls by the android:priority attribute defined in the <intent-filter> tag of AndroidManifext.xml file.

Receiver Lifecycle:

There is only one lifecycle method for the intent receiver as onReceive(). The method gets called when intent is broadcasted. The receiver object is only valid for the duration of the onReceive() method, after the method ends the object is considered to be non-active and can be garbage collected. Because of this the intent receiver onReceive() method should not handle any asynchronous operation.

To receiver an intent by the intent receiver the application does not need to be running. When the intent is broadcasted the system will start the application to call the intent receiver.

Permissions:

Sometimes for defining intent receivers for some intent, permissions need to be specified by the intent receiver. The intent receiver can specify the required permission in the AndroidManifest.xml file with the help of <user-permission> tag. While registering the intent receiver dynamically, the permission can be specified as the parameter of the registerReceiver method.

To enforce a permission while broadcasting an intent, a non-null permission argument need to be specified for the sendBroadcast() or sendOrderedBroadcast() method.

This is all on the intent receivers. In next post we will see android services and content providers.

Android Basics ,

Basics of Android : Part I – Android Activities

January 4th, 2009

There are four basic building blocks of an Android Application -

1. Activity

2. Intent Receivers

3. Service

4. Content Providers

In this post we will go in details of the activity. Activities represent the application screens in Android. Android platform define a class ‘Activity’, all the activities have to extend from Activity class.

Android platform is designed in such way that all applications can expose interfaces using above mentioned 4 building blocks through which they can interact with each other. There fore defining screens in XML is major feature required in developing such no-boundary application.

Designing user screen in XML:

The activity (screen) consists of views and viewgroups. Views are the standard screen components like TextView (Label), Buttons, CheckBox, EditText (textbox) etc. The viewgroups are special views that can contain other views and thus viewgroups can be used as panels to arrange the views on the screen. Viewgroups examples are LinearLayout, RelativeLayout, AbsoluteLayout etc.

Android supports XML syntax for designing application screens. Let’s develop an xml layout of screen which takes user’s first name and last name.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:id="@+id/widget28"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android">
<TextView
android:id="@+id/firstNameLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="First Name:">
</TextView>
<EditText
android:id="@+id/firstName"
android:layout_width="319px"
android:layout_height="wrap_content"
android:textSize="18sp">
</EditText>
<TextView
android:id="@+id/lastNameLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Last Name:">
</TextView>
<EditText
android:id="@+id/lastName"
android:layout_width="320px"
android:layout_height="wrap_content"
android:textSize="18sp">
</EditText>
<Button
android:id="@+id/submitButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Submit"
android:layout_gravity="center_horizontal">
</Button>
</LinearLayout>

There are visual tools available for creating android XML screen layout. Try out droiddraw.

The above activity layout shows two textboxes for user’s first Name and last Name. Each view controls is assigned an id to identify and access the control. Activity layouts are stored under resources directory as layouts (in res/layout dir).

Activity intents:

Each activity is associated with intents which specify what the Activity can do. Activity intent consists of action and data required by the activity. The activity intents are specified in the application AndroidManifest.xml file as intent filters. Activity can support multiple actions. See the example below:

<activity class=".SomeActivity" android:label="@string/activityTitle">
<intent-filter>
<action android:value="android.intent.action.VIEW" />
<category android:value="android.intent.category.DEFAULT" />
<type android:value="content://contacts" />
</intent-filter>
</activity>

The above activity supports the view action for contact data. That means the activity display the phone contacts. There are some standard intent actions defined by the android platform like VIEW, EDIT, MAIN etc. But custom intent actions can also be specified as shown below:

<activity class=".TestActivity" android:label="@string/activityTitle">
<intent-filter>
<action android:value="com.wissen.testApp.activities.TEST_ACTIVITY" />
<category android:value="android.intent.category.DEFAULT" />
</intent-filter>
</activity>

This activity can be used by using the TEST_ACTIVITY intent. We will see how to create activity with intents in following part of post.

Application Launcher Activity:

Every android application has a Launcher activity. The launcher activity is the activity that gets control when the application starts.

Launcher activity must support predefined intent ‘android.intent.action.MAIN’ and has category ‘android.intent.category.LAUNCHER’.

The launcher activity can be specified in the AndroidManifest.xml as follows:

<activity class=".WelcomeActivity" android:label="@string/app_name">
<intent-filter>
<action android:value="android.intent.action.MAIN" />
<category android:value="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

Creating an Activity:

All the activity must extend android ‘Activity’ class. onCreate() method gets called when an activity is created.

Let create an activity for the layout we defined earlier. Here is the code…

package com.wissen.testApp;

public class UserInfoActivity extends Activity {

		private EditText firstName;

		private EditText lastName;

		/** Called when the activity is first created. */

		@Override

		public void onCreate(Bundle savedInstanceState) {

		super.onCreate(savedInstanceState);

		setContentView(R.layout.main);

		firstName = (EditText) findViewById(R.id.firstName);<

		lastName = (EditText) findViewById(R.id.lastName);

		submitButton = (Button) findViewById(R.id.saveButton);

		}
	}

The above activity class overrides the onCreate method. The onCreate is the activity lifecycle method and as name suggests it gets call when activity is created. So the onCreate method is the entry point for an activity.

Activity calls the setContentView method to assign the layout that we defined earlier. The Resource class is used to refer to the xml layout main (the xml file name is main.xml).

As we saw in the xml layout all the view controls as assigned id's to them. The activity can refer to the view with the help of these defined ids by using the findViewById method.

So now our activity is using layout that we defined and also has access to the firstName, lastName and button controls.

Lets define an onClick event handler for the submit button. The event handler will just show user provide firstName and LastName in a notification.

public class UserInfoActivity extends Activity implements View.OnClickListener {

		private EditText firstName;

		private EditText lastName;

		/** Called when the activity is first created. */

		@Override

		public void onCreate(Bundle savedInstanceState) {
		 //.......
		}<

		public void onClick(View view) {

		if(view.getId() == R.id.submitButton) {

		Toast.makeText(context, "Hi " + firstName.getText() + " " + lastName.getText().toString(), Toast.LENGTH_LONG).show();

		}
		}
		}

Define the above activity as the launcher activity in the AndroidManifest.xml file and the activity will be called when the application will start.

Activity Lifecycle:

Let see what the lifecycle of the android activity is. Activity class supports following lifecycle methods,

onCreate(): Called when the activity is first created. This is where setting up views is done. This method also provides you with a Bundle containing the activity's previous state (if any).

onRestart(): Called just before activity is being started after it has been stopped.

onStart(): Called when the activity is becoming visible to the user. Followed by onResume() if the activity is at the top of the activity stack.

onResume(): Called when the activity will start interacting with the user, i.e. activity is at the top of the activity stack.

onPause(): Called just before some other activity become active and user start interacting with the new activity. This method can be used to save unsaved changes.

onStop(): Called when the activity is no longer visible to the user. This may happen either because a new activity become visible, or this one is being destroyed.

onDestroy(): This method is called just before the activity is destroyed. The activity can be destroyed by calling finish() method.

Starting an Activity:

We have seen how to create and show a launcher activity. To show other activities in the application the activities has to be started.

Support you have defined an as activity as follows:

package com.wissen.testApp;

public class TestActivity extends Activity {

	@Override
	public void onCreate(Bundle savedInstanceState) {
		// ........
	}
}

AndroidManifest.xml contains:


<activity class=".TestActivity" android:label="@string/activityTitle">

<intent-filter>

<action android:value="com.wissen.testApp.activities.TEST_ACTIVITY" />

<category android:value="android.intent.category.DEFAULT" />

</intent-filter>

</activity>

To show this activity to the user, the activity must be started (this can happen on some event). Here is show the activity can be started

Intent testActivityIntent = new Intent();

testActivityIntent.setAction("com.wissen.testApp.activities.TEST_ACTIVITY");

startActivity(myProfileIntent);

The activity can also be started by setting the Activity class name in the intent. Like

intent.setClass(context, TestActivity.class);

Sometimes the caller activity need some return value from the called activity. In that case the caller will start the activity with the help of startActivityForResult() method. The caller will get the result onActivityResult() method as follows:

public class MyActivity extends Activity {

	// ...

	static final int REQUEST_CODE = 0;

	protected boolean onKeyDown(int keyCode, KeyEvent event) {

		startActivityForResult(

		new Intent("activity.Action"),

		REQUEST_CODE);

		return true;

	}

	protected void onActivityResult(int requestCode, int resultCode, Intent data) {

		if (requestCode == REQUEST_CODE) {

			if (resultCode == RESULT_OK) {

				// .. do something with the result

			}

		}

	}

}

The REQUEST_CODE will be return back by the called activity to identify the request.

This is all on the activities. In subsequent posts we will see other building blocks of the android platform.

Android Basics , , ,

Android API – SMS handling

December 29th, 2008

Many new application will use SMS as data delivery platform. Reality shows, on-demand movies etc request users to send predefined formatted SMS. Similarly some applications are coming up which sends data to user using SMS. Let’s see how such an application can be built using Android platform.

Android API support developing applications that can send and receive SMS messages. The android emulator does not support sending of the SMS currently. But the emulator can receive SMS. Lets explore the android SMS support and develop a small program that listens to the SMSes received on the device (on emulator) and will show that message as notification.

The event handling on Android is done with the help of intents and intent receivers. The intents  announce (or broadcast) the event and intent receivers respond to the event. Intent receivers act as the event handlers.

Let’s define an intent receiver that can handle the SMS received event:

package com.wissen.sms.receiver;
/**
* The class is called when SMS is received.
*/
public class SMSReceiver extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {
// TODO
}
}

We need to configure this intent receiver to receive SMS receive event. For SMS receive event android has defined an intent as ‘ android.provider.Telephony.SMS_RECEIVED ‘. The receiver can be configured in AndroidManifest.xml as follows:

<receiver android:name=".receiver.SMSReceiver" android:enabled="true">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>

To receive SMS, application also needs to specify permission for receiving SMS. The permission can be set in AndroidManifest.xml as follows:

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

Now our intent receiver is all set to be called when the android device will receive SMS. Now we only need to retrieve the received SMS and show the SMS text in a notification.

Here is the code of intent receiver that will read the SMS from intent received and show the first message (pdu).

public void onReceive(Context context, Intent intent) {
		Bundle bundle = intent.getExtras();

		Object messages[] = (Object[]) bundle.get("pdus");
		SmsMessage smsMessage[] = new SmsMessage[messages.length];
		for (int n = 0; n &lt; messages.length; n++) {
		smsMessage[n] = SmsMessage.createFromPdu((byte[]) messages[n]);
		}

		// show first message
		Toast toast = Toast.makeText(context,
		"Received SMS: " + smsMessage[0].getMessageBody(), Toast.LENGTH_LONG);
		toast.show();
		}

The SMS received by the Android device is in the form of pdus (protocol description unit). Class SmsMessage, defined in android.telephony.gsm package, can store information about the SMS. The class can also be used to create SmsMessage object from received pdus. Toast widget is used to show the SMS body as an notification.

Running the Program:
Only remaining thing now is running the application and sending the SMS message to the emulator. An SMS message can be sent to the emulator in the DDMS eclipse perspective (Dalvik Debug Monitor Service). ‘Emulator Control’ window can be used to send SMS message (an incoming number has to be provided which can be anything).

Here is the application screen shot in action,

Android SMS receiver application

Android SMS receiver application

Download the sample code here

Join the forum discussion on this post - (1) Posts

Android API , ,