Taste of Android :: Part-11


Bhaskar S 07/20/2013


Android Application Development - X

In Part-10, we demostrated a simple alarm application using the Android Service. We had to use an AsyncTask to avoid blocking the main UI Thread and cancel the AsyncTask and stop the Service once the alarm was trigger at the desired time (hour and minute). A simpler and easier way to acheive the same would be to use the Android framework class android.app.IntentService. The reason IntentService is simpler and easier is because it automatically creates a background processing thread to handle the alarm task and stops the service once the alarm is triggered.

In order to use IntentService, we need to extend the android.app.IntentService class and override the following method:

We will now demonstrate this concept of using IntentService by creating a new Android application named DroidAlarmService2.

This application is essentially similar to DroidAlarmService except that it uses IntentService and we will use Notification instead of the Toast to alert the user when the alarm is triggered.

Let us create a new Android application named DroidAlarmService2 to illustrate the concept of using Android IntentService and Notification to build our own custom alarm clock application.

We will not go step-by-step to show the various screens since we already did that in Part-2 for the DroidTipCalculator application.

Modify the contents of the dimens.xml file to look like the one shown in the listing 11.1 below:

Listing-11.1
<?xml version="1.0" encoding="utf-8"?>
<resources>

<dimen name="title_size">26sp</dimen>
<dimen name="margin_size">26dp</dimen>

</resources>

Next, modify the contents of the strings.xml file to look like the one shown in the listing 11.2 below:

Listing-11.2
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- id references -->

<string name="textview">textview</string>
<string name="timepicker">timepicker</string>
<string name="button1">button1</string>
<string name="button2">button2</string>

<!-- Text references -->

<string name="app_name">DroidAlarmService2</string>
<string name="simple_alarm">Simple Alarm</string>
<string name="set_alarm">Set Alarm</string>
<string name="cancel_alarm">Cancel Alarm</string>

</resources>

The contents of the activity_time_pick.xml layout file will look like the one shown in the listing 11.3 below:

Listing-11.3
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:gravity="center_horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >

<TextView
android:id="@+id/textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="@dimen/margin_size"
android:paddingBottom="@dimen/margin_size"
android:text="@string/simple_alarm"
android:textColor="#cc3300"
android:textSize="@dimen/title_size"
android:textStyle="bold"
android:typeface="sans" />

<TimePicker
android:id="@+id/timepicker"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/margin_size" />

<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/set_alarm" />

<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/cancel_alarm" />

</LinearLayout>

Previewing the activity_time_pick.xml layout file in the Graphical Mode in Eclipse will look like the one shown in the figure 11.1 below:

Activity Time Picker Image
Figure-11.1

The contents of the java source file TimePickActivity2.java will look like the one shown in the listing 11.4 below:

Listing-11.4
package com.polarsparc.android.droidalarmservice2;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Messenger;
import android.view.View;
import android.widget.Button;
import android.widget.TimePicker;

public class TimePickActivity2 extends Activity {

private int pickedHour;
private int pickedMinute;

private Handler handler;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

setContentView(R.layout.activity_time_pick);

handler = new Handler() {
@Override
public void handleMessage(Message msg) {
Button set = (Button) findViewById(R.id.button1);
set.setEnabled(true);

Button cancel = (Button) findViewById(R.id.button2);
cancel.setEnabled(false);
}
};

TimePicker picker = (TimePicker) findViewById(R.id.timepicker);
pickedHour = picker.getCurrentHour();
pickedMinute = picker.getCurrentMinute();
picker.setOnTimeChangedListener(new TimePicker.OnTimeChangedListener() {
@Override
public void onTimeChanged(TimePicker view, int hour, int minute) {
pickedHour = hour;
pickedMinute = minute;
}
});

final Button set = (Button) findViewById(R.id.button1);
set.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
set.setEnabled(false);

Button cancel = (Button) findViewById(R.id.button2);
cancel.setEnabled(true);

Intent intent = new Intent(getBaseContext(), MyAlarmService2.class);
intent.putExtra("pickedHour", pickedHour);
intent.putExtra("pickedMinute", pickedMinute);
intent.putExtra("Messenger", new Messenger(handler));

startService(intent);
}
});

final Button cancel = (Button) findViewById(R.id.button2);
cancel.setEnabled(false);
cancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
cancel.setEnabled(false);

Button set = (Button) findViewById(R.id.button1);
set.setEnabled(true);

stopService(new Intent(getBaseContext(), MyAlarmService2.class));
}
});
}

}

The contents of the java source file MyAlarmService2.java will look like the one shown in the listing 11.5 below:

Listing-11.5
package com.polarsparc.android.droidalarmservice2;

import android.app.IntentService;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Message;
import android.os.Messenger;
import android.util.Log;

import java.util.Calendar;

public class MyAlarmService2 extends IntentService {

private static String TAG = "MyAlarmService2";

private boolean loop = true;

private NotificationManager notificationManager = null;

private Messenger messenger = null;

public MyAlarmService2() {
super("MyAlarmService2");
}

@Override
protected void onHandleIntent(Intent intent) {
final int REQUEST_CODE = 0;
final int NOTIFICATION_ID = 1;

final String TITLE = "Wake Up Alarm @ %02d:%02d";
final String TEXT = "Alarm Service!";

int pickedHour = intent.getIntExtra("pickedHour", -1);
int pickedMinute = intent.getIntExtra("pickedMinute", -1);

Bundle extras = intent.getExtras();

messenger = (Messenger) extras.get("Messenger");

notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);

Log.i(TAG, "MyAlarmService2 - onHandleIntent() :: pickedHour = " +
pickedHour + ", pickedMinute = " + pickedMinute);

if (pickedHour >= 0 && pickedMinute >= 0 && notificationManager != null && messenger != null) {
while (loop) {
try {
// Sleep for 1 second
Thread.sleep(1000);

if (! loop) {
break;
}

Calendar cal = Calendar.getInstance();

int curHour = cal.get(Calendar.HOUR_OF_DAY);
int curMinute = cal.get(Calendar.MINUTE);

if (curHour == pickedHour && curMinute == pickedMinute) {
Log.i(TAG, "MyAlarmService2 - onHandleIntent() :: Alarm triggered !!!");

sendHandlerMessage();

Context context = getApplicationContext();

Intent notifyIntent = new Intent(this, TimePickActivity2.class);

PendingIntent pendingIntent = PendingIntent.getActivity(context, REQUEST_CODE,
notifyIntent, Intent.FLAG_ACTIVITY_NEW_TASK);

Notification notification = new Notification.Builder(context)
.setContentTitle(String.format(TITLE, pickedHour, pickedMinute))
.setContentText(TEXT)
.setSmallIcon(R.drawable.my_alarm)
.setContentIntent(pendingIntent)
.getNotification();
notification.defaults |= Notification.DEFAULT_SOUND;
notification.flags |= Notification.FLAG_AUTO_CANCEL;

notificationManager.notify(NOTIFICATION_ID, notification);

break;
}
}
catch (Throwable t) {
Log.e(TAG, "MyAlarmService2 - onHandleIntent() :: exception !!!", t);
}
}
}
}

@Override
public void onDestroy() {
loop = false;

Log.i(TAG, "MyAlarmService2 - onDestroy() called !!!");
}

private void sendHandlerMessage() {
Message msg = Message.obtain();

try {
messenger.send(msg);
}
catch (Throwable t) {
Log.e(TAG, "MyAlarmService2 - sendHandlerMessage() :: exception !!!", t);
}
}

}

Here is how this custom alarm timer will work:

Finally, modify the contents of the AndroidManifest.xml file to look like the one shown in the listing 11.6 below:

Listing-11.6
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.polarsparc.android.droidalarmservice2"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="14" />

<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >

<activity
android:name="com.polarsparc.android.droidalarmservice2.TimePickActivity2"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />

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

<service android:name=".MyAlarmService2" />

</application>

</manifest>

We are now ready to test our DroidAlarmService2 application on the virtual Android device we created in Part-1. We will create a Run Configuration for DroidAlarmService2 as we did in Part-2 for DroidTipCalculator.

Once the run configuration for DroidAlarmService2 is ready, we will Run the application and the application will come to life as shown in the following figure 11.2 below:

Alarm Time Picker Image
Figure-11.2

Pick the desired alarm time (hour and minute) and click on the Set Alarm button. This will launch the background service MyAlarmService2 resulting in the following figure 11.3 below:

Alarm Service Image
Figure-11.3

When the alarm goes off at the desired time (hour and minute), it will display a Notification icon on the status or notification bar as shown in the following figure 11.4 below:

Alarm Notification Image
Figure-11.4

Drag the Notification icon downwards with the computer mouse (to simulate the swipe down on the device) and it will reveal the alarm alert as shown in the following figure 11.5 below:

Alarm Notification Image
Figure-11.5

References

Taste of Android :: Part-1

Taste of Android :: Part-2

Taste of Android :: Part-3

Taste of Android :: Part-4

Taste of Android :: Part-5

Taste of Android :: Part-6

Taste of Android :: Part-7

Taste of Android :: Part-8

Taste of Android :: Part-9

Taste of Android :: Part-10