Introducing notifications

In the previous section we showed how simple it is to create a quick, unobtrusive message to let the user know an SMS message has arrived. In this next section we are going to look at how to create a persistent notification that not only shows up in the status bar but stays in a notification area until the user deletes it. To do that we need to use the class Notification since we want to do something more complex than Toast can offer us.

A notification on Android can be many things, ranging from a pop-up message, a flashing LED, to a vibration, but all of these actions start with and are represented by the Notification class. The Notification class defines how you want to represent a notification to a user and has three constructors, one public method, and a number of fields. Table 8.1 summarizes the class.

Table 8.1 Notification fields

Access

Type

Method

Description

public

int

ledARGB

The color of the LED notification.

public

int

ledOffMS

The number of milliseconds for LED to be off between flashes.

public

int

ledOnMS

The number of milliseconds for LED to be on between flashes.

public

ContentURI

sound

The sound to play.

public

RemoteViews

contentView

View to display when the statusBar-Icon is selected in the status bar.

public

CharSequence

statusBarBalloonText

Text to display when the statusBar-Icon is selected in the status bar.

public

PendingIntent

contentIntent

The Intent to execute when the icon is clicked.

public

int

icon

The resource id of a drawable to use as the icon in the status bar.

public

CharSequence

tickerText

Text to scroll across the screen when this item is added to the status bar.

public

long[]

vibrate

The pattern with which to vibrate.

As you can see, the Notification class has numerous fields since it has to describe every way you can notify a user. Using a Notification is as simple as running this code:

Notification notif = new Notification(

context, // the application context icon, // the icon for the status bar ticketText, // the text to display in the ticker when, // the timestamp for the notification

Title, // the title for the notification

TextBody, // the details to display in the notification contentIntent, // the contentIntent appIntent); // the application intent

To send the Notification all you have to do is enter the following:

nm.notify(String, Notification);

where nm is the reference to the NotificationManager. Now let's take our previous example and edit to change it from a Toast notification to a notification in the status bar. Before we do that, we'll make the application more interesting by adding icons to our resources directory. For this example we're going to use the chat.png icon and the incoming.png icon. You can find these files in the downloaded code for this book, or you can get them from http://www.manning.com/ableson/. Simply drop them in the res/drawable directory to have Eclipse automatically register them for you in the R class.

Now let's edit our code. First we'll edit the SMSNotifyActivity class so that when the Activity is called it can find the Notification passed to it from the Notification-Manager. After the Activity has run, SMSNotifyActivity can cancel it. Listing 8.4 provides the code you need for new SMSNotifyActivity class.

Listing 8.4 A sample SMSNotifyActivity public class SMSNotifyActivity extends Activity {

public void onCreate(Bundle icicle) { super.onCreate(icicle);

setContentView (R. layout. main); ^^ Set up the

NotificationManager nm = (Notif icationManager) <1-1 N°tificati°nManager getSystemService(NOTIFICATION_SERVICE);

nm. cancel (R. string. app_name) ; <1-n Cancel the

© Notification

As you can see, all we did was to use the NotificationManager O to look up the Notification and then used the cancel() © method to cancel it. We could do more here, such as set up a custom view, but for now we will leave it as is.

Next we need to edit the SMSNotifyExample to remove the Toast Notification and support a Notification to the status bar. Listing 8.5 shows the edits we need to make.

Listing 8.5 Updated SMSNotifyExample.java public class SMSNotifyExample extends BroadcastReceiver { private static final String LOG_TAG = "SMSReceiver";

public static final int NOTIFICATION_ID_RECEIVED = 0x1221;

static final String ACTION = "android.provider.Telephony.SMS_RECEIVED";

private CharSequence tickerMessage = null;

public void onReceiveIntent(Context context, Intent intent) { <-

NotificationManager nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); if (intent.getAction().equals(SMSNotifyExample.ACTION)) {

StringBuilder sb = new StringBuilder () ; Create the

Bundle bundle = intent. getExtras () ; Application Intent O

Object [] pdusObj = (Object []) bundle .get ("pdus") ; SmsMessage[] messages = new SmsMessage[pdusObj.length];

for (SmsMessage currentMessage : messages) { sb.append("Received compressed SMS\nFrom: ") ; sb.append(currentMessage.getDisplayOriginatingAddress()); sb. append ("\n----Message----\n") ;

sb.append(currentMessage.getDisplayMessageBody()) ;

Log.i(SMSNotifyExample.LOG_TAG, " [SMSApp] onReceiveIntent: " + sb) ; abortBroadcast();

Intent i = new Intent(context, SMSNotifyActivity.class) ; context.startActivity(i) ;

CharSequence appName = "SMSNotifyExample"; this.tickerMessage = sb.toString(); Long theWhen = System.currentTimeMillis();

PendingIntent.getBroadcast((Context) appName, 0, i, 0)

Notification notif = new Notif ication ( <1-1

R.drawable.incoming, this.tickerMessage, theWhen) ;

, Build the © Notification

nm. notify (R. string. alert_message, notif); <1-n Broadcast the

} Q Notification

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

Notice that the first change we made was to add a called tickerMessage. The tickerMessage will hold the SMS message that we want to scroll in the notification bar. We add these fields right after our Action variable, like this:

private CharSequence tickerMessage = null;

Next we create an Application Intent Q. The Application Intent will be the Intent shown when we click on the SMS inbox. For this example it won't do anything, but it is required for building the Notification. You could have it pop up in an editor or some other screen with a little more effort.

Once the Application Intent is set, we can generate the Notification ©. To make the code easier to understand, we have added some comments next to each attribute of Notification from listing 8.5:

Notification notif = new Notification(

R. drawable . incoming, // the icon for the status bar tickerMessage, // the text to display in the ticker theWhen

nm.notify(R.string.app_name, notif);

On the last line we use the notify() method © from the NotificationManager to broadcast our Notification to the application.

Now if you run the application, then open the DDMS and pass an SMS message as you did earlier, you should see the new Notification appear in the status bar. The message displays each line for a short interval until the message is fully displayed. You should also see a new icon pop up in the status bar indicating a new SMS message, as shown in figure 8.3.

When you have sent the message, you can click the New Messages icon, and a bar should drop down from it. Click on the bar and drag it down to the bottom of the screen. This opens the default view of the SMS inbox for Android, as shown in figure 8.4.

Figure 8.3 Using the Android DDMS to send an SMS message to the application

Figure 8.4 The expanded SMS inbox displaying the contentlntent and appIntent

There is a lot more you could do with this demo, such as creating a better UI or making the SMS inbox more feature rich. You could even have the application play a sound when a message arrives, but for this example we have looked at everything you need to know to start working with notifications. In the next section we are going to look at Notification's close relative, the Alarm.

8.3 Alarms

In Android, alarms allow you to schedule your application to run at some point in the future. Alarms can be used for a wide range of applications, from notifying a user of an appointment to something more sophisticated, such as having an application start up, check for software updates, and then shut down. An Alarm works by registering an Intent with the Alarm, and then at the time scheduled the Alarm will broadcast the Intent. Android will automatically start the targeted application even if the Android handset is asleep.

Android manages all alarms somewhat like the NotificationManager—via an AlarmManager class. The AlarmManager has four methods: cancel, set, setRepeating, and setTimeZone as shown in table 8.2.

Table 8.2 AlarmManager public methods

Returns

Method and description

void

cancel(PendingIntent intent) Remove alarms with matching Intent

void

set(int type, long triggerAtTime, PendingIntent operation) Set an Alarm

void

setRepeating(int type, long triggerAtTime, long interval, PendingIntent operation) Set a repeating Alarm

void

setTimeZone(String TimeZone) Set the time zone for the Alarm

You instantiate the AlarmManager indirectly as you do the NotificationManager by using Context.getSystemService(Context.ALARM_SERVICE).

Setting alarms is very easy, like most things in Android. In the next example we will create a simple application that sets an Alarm when a button is pushed; when the Alarm is triggered, it will pass back a simple Toast to inform us that the Alarm has been fired.

8.3.1 Alarm example

In this next example we are going to create an Android project called SimpleAlarm with the package com.msi.manning.chapter8.simpleAlarm, an application name of SimpleAlarm and an Activity name of GenerateAlarm. In this project we will use another open source icon, which you can find at http://www.manning.com/ableson/ or in the download for this chapter. Change the name of the icon to clock, and add it to the res/drawable directory of the project when you create it.

Next we need to edit the AndroidManifest.xml to have a receiver O, which we will create soon, called AlarmReceiver, as shown in listing 8.6.

Listing 8.6 AndroidManifest.xml

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

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.msi.manning.chapter8.simpleAlarm"> <application android:icon="@drawable/clock"> <activity android:name=".GenerateAlarm" android:label="@string/app_name"> <intent-filter>

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

<receiver android:name=".AlarmReceiver" android:process=":remote" /> </application>

</manifest> Define the receiver

Now we edit the string.xml file in the values directory and add two new strings:

<string name="set_alarm_text">Set Alarm</string> <string name="alarm_message">Alarm Fired</string>

We will use this string as the value of the button in our layout. Next we need to add a new button to our layout, so edit the main.xml file to add a new button, like this:

<Button android:id="@+id/set_alarm_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/set_alarm_text"> <requestFocus /> </Button>

We are ready to create a new class that will act as the Receiver for the Notification the Alarm will generate. In this case we are going to be generating a Toast-style Notification to let the user know that the Alarm has been triggered. Now create a new class as shown in listing 8.7, which waits for the Alarm to broadcast to the AlarmReceiver and will then generate a Toast.

Listing 8.7 AlarmReceiver.java

{Create the onReceivelntent method public void onReceiveIntent(Context context, Intent intent) { <—

Toast. makeText (context, R. string. app_name, Toast. LENGTH_SHORT).show();

Broadcast a Toast when

@Override the Intent is received

public void onReceive(Context context, Intent intent) { }

Next we need to edit the SimpleAlarm class to create a button widget (as discussed in chapter 3) that calls the inner class setAlarm. In setAlarm we create an onClick method that will schedule our Alarm, call our Intent, and fire off our Toast. Listing 8.8 shows what the finished class should look like.

Listing 8.8 SimpleAlarm.java public class GenerateAlarm extends Activity { Toast mToast; @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.main); Button button = (Button)findViewById(R.id.set_alarm_button) button.setOnClickListener(this.mOneShotListener); ■

Set up Button to call A mOneShotListener

private OnClickListener mOneShotListener = new OnClickListener() {

public void onClick (View v) { Create Intent to fire when Alarm goes off Q

Intent intent = new Intent(GenerateAlarm.this, AlarmReceiver.class); PendingIntent appIntent =

PendingIntent.getBroadcast (GenerateAlarm. this, 0, intent, 0); <■-

Calendar calendar = Calendar. getInstance () ; <1-1 Set the time calendar. setTimeInMillis (System. currentTimeMillis ()); for Alarm to calendar. add (Calendar. SECOND, 30); Q go off

AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE) am.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), appIntent) ; <1-1

Q Set the Alarm if (GenerateAlarm.this.mToast != null) { GenerateAlarm.this.mToast.cancel();

Create the AlarmManager Q

GenerateAlarm.this.mToast = Toast.makeText(GenerateAlarm.this, R.string.alarm_message, Toast.LENGTH_LONG); GenerateAlarm.this.mToast.show();

As you can see, this is a pretty simple class. We first create a Button to trigger our Alarm Q. Next we create an inner class for our mOneShotListener. We then create the Intent to be trigged when the Alarm actually goes off ©. In the next section of code we use the Calendar class Q to help us calculate the number of milliseconds from the time the button is pressed, which we will use to set the Alarm.

Now we have done everything necessary beforehand in order to create and set the Alarm. To do this we first create the AlarmManager O and then call its set() method to set the Alarm Q. To see a little more detail of what's going on in the application, take a look at these lines of code:

AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);

am.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), intent);

This is where we actually create and set the Alarm by first using getSystemService to create the AlarmManager. The first parameter we pass to the set() method is RTC_WAKEUP, which is an integer representing the Alarm type we want to set. The AlarmManager currently supports four Alarm types, as shown in table 8.3.

Table 8.3 AlarmManager Alarm types

Type

Description

ELAPSED.

.REALTIME

Alarm time in SystemClock.elapsedRealtime() (time since boot, including sleep)

ELAPSED.

_REALTIME_WAKEUP

Alarm time in SystemClock.elapsedRealtime() (time since boot, including sleep), which will wake up the device when it goes off

RTC

Alarm time in System.currentTimeMillisO (wall clock time in UTC)

RTC_WAKEUP

Alarm time in System.currentTimeMillisO (wall clock time in UTC), which will wake up the device when it goes off

As you can see, there are multiple types of alarms that you can use depending on your requirements. The RTC_WAKEUP, for example, sets the Alarm time in milliseconds, and when the Alarm goes off it will wake up the device from sleep mode for you, as opposed to RTC, which will not.

The next parameter we pass to the method is the amount of time in milliseconds we want to elapse, after which we want the alarm to be triggered. We set this with:

Calendar calendar = Calendar.getInstance();

calendar.setTimeInMillis(System.currentTimeMillis());

calendar.add(Calendar.SECOND, 30) ;

The last parameter is the Intent we want to broadcast to, which is our Intent-Receiver. Now if you build the application and run it in the emulator, you should see something like the screen shown in figure 8.5.

Clicking the Set Alarm button will set the alarm, and after 30 seconds you should see something like figure 8.6, displaying the Toast message.

As you can see, creating an Alarm is pretty easy in Android, but what might make more sense would be for that Alarm to trigger a Notification in the status bar. To do that you would need to add a NotificationManager and generate a Notification. To do this we have created a new method to add to listing 8.8 called showNotification, which takes four parameters and creates our Notification, like this:

Figure 8.5 Example of the SimpleAlarm application running in the emulator

Figure 8.6 After the Alarm runs, the application shows a simple Toast message.

private void showNotification(int statusBarIconID, int statusBarTextID, int detailedTextID, boolean showIconOnly) {

Intent contentIntent = new Intent(this, SetAlarm.class); PendingIntent theappIntent = PendingIntent. getBroadcast(SetAlarm.this,

0, contentIntent, 0); CharSequence from = "Alarm Manager"; CharSequence message = "The Alarm was fired";

String tickerText = showIconOnly ? null : this.getString(statusBarTextID); Notification notif = new Notification( statusBarIconID, tickerText, System.currentTimeMillis());

notif.setLatestEventInfo(this, from, message, theappIntent);

nm.notify(YOURAPP_NOTIFICATION_ID, notif );

Much of this code is very similar to the SMSNotifyExample code. To add it to your SimpleAlarm, edit listing 8.8 to look like listing 8.9, where the only other things we have done are to import the Notification and NotificationManager to the code, add the private variables nm and ApplicationID, and make a call to showNotifica-tion() right after the Toast.

Listing 8.9 SetAlarm.java public class SetAlarm extends Activity {

private NotificationManager nm; Toast mToast;

@Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.main);

this.nm = (NotificationManager)

getSystemService(Context. NOTIFICATION_SERVICE);

Button button = (Button) findViewByld (R. id. set_alarm_button); button.setOnClickListener(this.mOneShotListener) ;

private void showNotification(int statusBarIconID, int statusBarTextID, int detailedTextID, boolean showIconOnly) {

Intent contentIntent = new Intent(this, SetAlarm.class);

PendingIntent theappIntent = PendingIntent.getBroadcast(SetAlarm.this, 0, contentIntent, 0) ; CharSequence from = "Alarm Manager"; CharSequence message = "The Alarm was fired";

String tickerText = showIconOnly ? null : this.getString(statusBarTextID); Notification notif = new Notification(statusBarIconID, tickerText, System.currentTimeMillis());

notif.setLatestEventInfo(this, from, message, theappIntent);

this.nm.notify(this.YOURAPP_NOTIFICATION_ID, notif);

private OnClickListener mOneShotListener = new OnClickListener() {

public void onClick(View v) {

Intent intent = new Intent(SetAlarm.this, AlarmReceiver.class);

PendingIntent appIntent = PendingIntent.getBroadcast(SetAlarm.this, 0, intent, 0) ;

Calendar calendar = Calendar.getInstance();

calendar.setTimeInMillis(System.currentTimeMillis());

calendar.add(Calendar.SECOND, 30) ;

AlarmManager am = (AlarmManager)

getSystemService(Context.ALARM_SERVICE); am. set (AlarmManager .RTC_WAKEUP, calendar.getTimeInMillis () , appIntent);

showNotification(R.drawable.alarm, R.string.alarm_message, R.string.alarm_message, false);

If you run the code and click Set Alarm, you should see the Alarm Notification in the status bar, as in figure 8.7. You could easily edit this code to take in parameters for time and date, have it show different Intents when the icons are clicked, and so on.

As you can see from this example, Android alarms and the AlarmManager are very straightforward, and you should be able to easily integrate them into your applications.

0 0

Post a comment