6. Working with Notifications

Applications often need to communicate with users, even when the applications aren’t actively running. Applications can alert users with text notifications, vibration, blinking lights, and even audio. In this chapter, you will learn how to build different kinds of notifications into your Android applications using modern APIs, while keeping them compatible with devices running Android versions all the way back to API Level 4.

Notifying the User

Applications can use notifications to greatly improve the user’s experience. For example:

Image An email application might notify a user when new messages arrive. A newsreader application might notify a user when there are new articles to read.

Image A game might notify a user when a friend has signed in, or sent an invitation to play, or beaten a high score.

Image A weather application might notify a user of special weather alerts.

Image A stock market application might notify the user when certain stock price targets are met. (Sell now before it’s too late!)

Users appreciate these notifications because they help drive application workflow, reminding the users when they need to launch the application. However, there is a fine line between just enough and too many notifications. Application designers need to consider carefully how they use notifications so as not to annoy users or interrupt them without good reason. Each notification should be appropriate for the specific application and the event the user is being notified of. For example, an application should not put out an emergency-style notification (think flashing lights, ringing noises, and generally making a “to-do”) simply to notify the user that his or her picture has been uploaded to a website or that new content has been downloaded.

The Android platform provides a number of different ways of notifying the user. Notifications are often displayed on the status bar at the top of the screen. They may involve:

Image Textual information

Image Graphical indicators

Image Action indicators

Image Sound indicators

Image Vibration of the device

Image Control of the indicator light


Image Warning

Although the Android SDK provides APIs for creating a variety of notifications, not all notifications are supported by all devices. For example, the BigTextStyle and BigPictureStyle are not available on all Android devices. There is also a degree of variation in how different devices handle notifications. Always test any notification implementations on target devices.


Now let’s look at how to use these different kinds of notifications in your applications. But first, let’s talk a little about compatibility.

A Word on Compatibility

Notifications have been around since the beginning of the Android platform. They have undergone some changes, but the basics have pretty much stayed the same. However, over time, some areas have changed enough that they no longer work the way they originally did. While we’re not attempting to cover every single type of notification or option allowed for notifications in this book, even this overview covers at least one area that behaves differently on different versions of Android. We point out these areas as we come across them.

Additionally, a new method of creating notifications was introduced in API Level 11. This method involves using the Notification.Builder() class, but in this book we describe how to maintain compatibility with devices that are running Android API versions older than API Level 11. To do so, we use the NotificationCompat library and the NotificationCompat.Builder() class, rather than the standard API Level 11 and Notification.Builder() class, so if you are developing only for devices at API Level 11 and higher, feel free to use the later class, as these two different approaches are easily interchangeable.

Notifying with the Status Bar

The standard location for displaying notifications and indicators on an Android device is the status bar that runs along the top of the screen. Typically, the status bar shows information such as the current date and time. It also displays notifications (such as incoming SMS messages) as they arrive—in short form along the bar and in full if the user pulls down the status bar to see the notification list. The user can clear certain notifications by pulling down the status bar and hitting the Clear button. Other notifications are intended to be ongoing, not dismissible by the user, and cleared only by the calling application or Service.

Developers can enhance their applications by using notifications from their applications to inform the user of important events. For example, an application might want to send a simple notification to the user whenever new content has been downloaded. A simple notification has a number of important components:

Image An icon (appears on the status bar and the full notification)

Image Ticker text (appears on the status bar)

Image Notification title text (appears in the full notification)

Image Notification body text (appears in the full notification)

Image An Intent (launches if the user clicks on the full notification)

In this section, you will learn how to create this basic kind of notification.


Image Tip

Many of the code examples provided in this chapter are taken from the SimpleNotifications application. The source code for this application is provided for download on the book’s website.


Using the NotificationManager Service

All notifications are created with the help of the NotificationManager. The NotificationManager (in the android.app package) is a system Service that must be requested. The following code demonstrates how to obtain a valid NotificationManager object using the getSystemService() method:

NotificationManager notifier = (NotificationManager)
    getSystemService(Context.NOTIFICATION_SERVICE);

The NotificationManager is not useful without having a valid Notification object to use with the notify() method. The Notification object defines what information displays to the user when the Notification is triggered. This includes text that displays on the status bar, a couple of lines of text that display on the expanded status bar, an icon displayed in both places, a count of the number of times this Notification has been triggered, and a time for when the last event that caused this Notification took place.

Creating a Simple Text Notification with an Icon

To remain backward compatible, first you must construct a NotificationCompat.Builder object, passing in the application Context as a parameter, like so:

NotificationCompat.Builder notifyBuilder = new
        NotificationCompat.Builder(getApplicationContext());

You can then set the icon, ticker text, and notification timestamp, each of which displays on the status bar, through the notifyBuilder variable, using the available methods of the object, as follows:

notifyBuilder.setSmallIcon(R.drawable.ic_launcher);
notifyBuilder.setTicker("Hello!");
notifyBuilder.setWhen(System.currentTimeMillis());

You need to set a couple more pieces of information before the call to the notify() method takes place. First, you need to make a call to the setContentTitle() method and the setContentText() method, which configure a View that displays in the expanded status bar. Here is an example:

Intent toLaunch = new Intent(SimpleNotificationsActivity.this,
        SimpleNotificationsActivity.class);
notifyBuilder.setContentIntent(PendingIntent.getActivity(
        SimpleNotificationsActivity.this, 0, toLaunch, 0));
notifyBuilder.setContentTitle("Hi there!");
notifyBuilder.setContentText("This is even more text.");

Next, you must create the Notification object using the build() method, then call the notify() method of the notification to supply the notification’s title and body text as well as the Intent triggered when the user clicks on the notification. In this case, we’re using our own Activity so that when the user clicks on the notification, our Activity launches again.


Image Note

When the expanded status bar is pulled down, the current Activity lifecycle is still treated as if it were the top (displayed) Activity. Triggering system notifications while running in the foreground, though, isn’t particularly useful. For an application that is in the foreground, it is better to use a Dialog or Toast to notify the user, not a Notification.


Working with the Notification Queue

Now the application is ready to actually notify the user of the event. All that is needed is a call to the notify() method of the NotificationManager with an identifier and the Notification we configured using the Notification.Builder. This is demonstrated with the following code:

private static final int NOTIFY_1 = 0x1001;
// ...
notifier.notify(NOTIFY_1, notify);

The identifier matches up a Notification with any previous Notification instances of that type. When the identifiers match, the old Notification is updated instead of a new one being created. You might have a Notification that some file is being downloaded. You can update the Notification when the download is complete, instead of filling the notification queue with a separate Notification, which quickly becomes obsolete. This Notification identifier needs to be unique only in your application.

The Notification displays as an icon and ticker text on the status bar. This is shown at the top of Figure 6.1.

Image

Figure 6.1 Status bar notification showing an icon and ticker text.

Shortly after the ticker text displays, the status bar returns to normal with each notification icon shown. If the users expand the status bar, they see something like what is shown in Figure 6.2.

Image

Figure 6.2 Expanded status bar showing the icon, both text fields, and the time of the notification.

Updating Notifications

You don’t want your application’s notifications to pile up in the status bar. Therefore, you might want to reuse or update notifications to keep the notification list manageable. For example, there is no reason to keep a notification informing the user that the application is downloading File X when you now want to send another notification saying File X has finished downloading. Instead, you can simply update the first notification with new information.

When the notification identifiers match, the old notification is updated. When a notification with a matching identifier is posted, the ticker text does not draw a second time. To show the user that something has changed, you can use a counter. The value of the number member variable of the NotificationCompat.Builder() object tracks and displays this. For instance, we can set it to the number 4, as shown here:

notifyBuilder.setNumber(4);

Figure 6.3 shows how this might look.

Image

Figure 6.3 Status bar notification with the count of 4 showing in the pull-down area.

Clearing Notifications

When a user clicks on the notification, the Intent assigned is triggered. At some point after this, the application might want to clear the notification from the system notifications queue. This is done through a call to the cancel() method of the NotificationManager object. For instance, the notification we created earlier can be canceled with the following call:

notifier.cancel(NOTIFY_1);

This cancels the notification that has the same identifier. However, if the application doesn’t care what the user does after clicking on the notification, there is an easier way to cancel notifications. Simply set a flag to do so, as shown here:

notifyBuilder.setAutoCancel(true);

Setting the setAutoCancel() method to true causes notifications to be canceled when the user clicks on them. This is convenient and easy for the application when just launching the Intent is good enough.

Vibrating the Phone

Vibration is a great way to enable notifications to catch the attention of a user in noisy environments or alert the user when visible and audible alerts are not appropriate (though a vibrating phone is often noisy on a hard surface). Android notifications give a fine level of control over how vibration is performed. However, before the application can use vibration with a notification, an explicit permission is needed. The following XML in your application’s AndroidManifest.xml file is required to use vibration:

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


Image Warning

The vibrate feature must be tested on the device. The emulator does not indicate vibration in any way. Also, some Android devices do not support vibration.


Without this permission, the vibrate functionality does not work, nor are there any errors. With this permission enabled, the application is free to vibrate the phone however it wants. This is accomplished by describing the vibrate member variable using the setVibrate() method, which determines the vibration pattern. An array of long values describes the different vibration durations for turning the vibrator on and off. Thus, the following line of code enables a simple vibration pattern that occurs whenever the notification is triggered:

notifyBuilder.setVibrate(new long[] {0, 200, 200, 600, 600});

This pattern causes the device to vibrate for 200 milliseconds and then stop for 200 milliseconds. After that, it vibrates for 600 milliseconds and then stops for that long.

An application can use different patterns of vibrations to alert the user to different types of events or even present counts. For instance, think about a grandfather clock with which you can deduce the time based on the tones that are played.


Image Tip

Using short, unique patterns of vibration can be useful, and users become accustomed to them.


Blinking the Lights

Blinking lights are a great way to pass information silently to the user when other forms of alert are not appropriate. The Android SDK provides reasonable control over a multicolored indicator light, when such a light is available on the device. Users might recognize this light as a Service indicator or battery level warning. An application can also take advantage of this light by changing its blinking rate or color.


Image Warning

Indicator lights are not available on all Android devices. Also, the emulator does not display the light’s state. Use of the indicator light mandates testing on actual hardware.


You must call methods on the NotificationCompat.Builder() object to use the indicator light. Then, the color of the light must be set as well as information about how it should blink. The following code configures the indicator light to shine green and blink at a rate of 1 second on and 1 second off:

notifyBuilder.setLights(Color.GREEN, 1000, 1000);

Although you can set arbitrary color values, a typical physical implementation of the indicator light has three small LEDs in red, green, and blue. Although the colors blend reasonably well, they won’t be as accurate as the colors on the screen.


Image Warning

On some devices, certain notifications appear to take precedence when it comes to using the indicator light. For instance, the light on certain devices is always solid green when the device is plugged into a USB port, regardless of whether other applications are trying to use the indicator light. Additionally, on other devices, the color trackball is not lit unless the screen is off. You must unplug the phone from the USB port for the color to change.


An application can use different colors and different blinking rates to indicate different information to the user. For instance, the more times an event occurs, the more urgent the indicator light could be. The following block of code shows changing the light based on the number of notifications that have been triggered, and the blinking light continues until the notification is cleared by the user:

if (counterNotify3.getCount() < 2) {
    argb = Color.GREEN;
    onMs = 1000;
    offMs = 1000;
} else if (counterNotify3.getCount() < 3) {
    argb = Color.BLUE;
    onMs = 750;
    offMs = 750;
} else if (counterNotify3.getCount() < 4) {
    argb = Color.WHITE;
    onMs = 500;
    offMs = 500;
} else {
    argb = Color.RED;
    onMs = 50;
    offMs = 50;
}
counterNotify3.increment();
notifyBuilder.setLights(argb, onMs, offMs);

Color and blinking rates can also be used to indicate other information. For instance, temperature from a weather service can be indicated with red and blue plus a blink rate. Use of such colors for passive data indication can be useful even when other forms would work. It is far less intrusive than annoying, loud rings or harsh, vibrating phone noises. For instance, a simple glance at the device can tell the user some useful piece of information without the need to launch any applications or change what he or she is doing.

Making Noise

Sometimes, the device has to make noise to get the user’s attention. Luckily, the Android SDK provides a means for doing this using the NotificationCompat.Builder object. Begin by calling the setSound() method and setting the URI of the sound, and also set the audio stream type to use when playing a sound. Generally, the most useful stream type is STREAM_NOTIFICATION. The following code demonstrates how to play a sound that is included as a project resource:

notifyBuilder.setSound(Uri.parse(
        "android.resource://com.advancedandroidbook.simplenotifications/"
        + R.raw.fallbackring),
        AudioManager.STREAM_NOTIFICATION);

By default, the audio file is played once. No specific permissions are needed for this form of notification.


Image Note

The sound file used in this example is included in the project as a raw resource. However, you can use any sound file on the device. Keep in mind that the sound files available on different Android devices may vary.


Customizing the Notification

Although the default notification behavior in the expanded status bar tray is sufficient for most purposes, developers can customize how notifications are displayed if they so choose. To do so, developers can use the RemoteViews object to customize the look and feel of a notification.

The following code demonstrates how to create a RemoteViews object and assign custom text to it:

RemoteViews remote = new RemoteViews(getPackageName(), R.layout.remote);

remote.setTextViewText(R.id.text1, "Big text here!");
remote.setTextViewText(R.id.text2, "Red text down here!");
notifyBuilder.setContent(remote);

To better understand this, here is the layout file remote.xml referenced by the preceding code:

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:id="@+id/text1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="31sp"
        android:textColor="#ddd" />
    <TextView
        android:id="@+id/text2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="18sp"
        android:textColor="#f00" />
</LinearLayout>

This particular example is similar to the default notification but does not contain an icon. The setContentTitle() and setContentText() methods are normally used to assign the text to the default layout. In this example, we use our custom layout instead. The Intent still needs to be assigned, though, as follows:

Intent toLaunch = new Intent(SimpleNotificationsActivity.this,
        SimpleNotificationsActivity.class);
notifyBuilder.setContentIntent(PendingIntent.getActivity(
        SimpleNotificationsActivity.this, 0, toLaunch, 0));
Notification notify = notifyBuilder.build();
notifier.notify(NOTIFY_5, notify);

The end result looks something like Figure 6.4.

Image

Figure 6.4 Custom notification showing just two lines of text.

Using a custom notification layout can provide better control over the information on the expanded status bar. Additionally, it can help differentiate your application’s notifications from those of other applications by providing a themed or branded appearance.


Image Note

The size of the area that a layout can use on the expanded status bar is fixed for a given device. However, the exact details might change from device to device. Keep this in mind when designing a custom notification layout. Additionally, be sure to test the layout on all target devices in all modes of screen operation so that you can be sure the notification layout draws properly.


The default layout includes two fields of text: an icon and a time field for when the notification was triggered. Users are accustomed to this information. An application, where feasible and where it makes sense, should try to conform to at least this level of information when using custom notifications.

Expandable and Contractible Notifications

Android 4.1 (API Level 17) introduced the ability to create notifications that either expand or contract, depending on their order in the notification queue. Expanded notifications are the most recent notifications displayed in the status bar; are larger than contracted ones, as they provide more screen real estate for displaying notification content; and provide the option to include action buttons.

There are many different notification style types that allow you to include large image previews as an attachment using the Notification.BigPictureStyle class, larger amounts of text such as the contents of a long article using the Notification.BigTextStyle class, or multiple text snippets such as multiple unread messages from an email inbox using the Notification.InboxStyle class.

To create one of these Notification style types, use the setStyle() method of the NotificationCompat.Builder class. The setStyle() method requires passing in a Style, which is done as follows:

notifyBuilder.setStyle(new NotificationCompat.BigTextStyle()
            .bigText("This is a really long message that is used "
            + "for expanded notifications in the status bar"));

In this code sample, we call the bigText() method on our BigTextStyle class and include the text that we want displayed when the notification is expanded.

It is also possible to include action buttons in our Notification. To do so, we need to create a PendingIntent for each action that we include. The screen size of the device should determine how many action buttons you include, but we have found that more than two actions is usually too many. Figure 6.5 shows what our notification looks like when expanded, including two action buttons.

Image

Figure 6.5 An expandable, big-view-style notification that is expanded, showing an icon, multiple lines of text, a timestamp, and two actions, each action accompanied by an icon.

You should also include the setContentTitle() and setContentText() methods as we have demonstrated in past examples, to ensure that your notification displays properly when it is contracted; otherwise the notification content area will be empty if in the contracted state. Figure 6.6 shows what the same notification looks like when contracted.

Image

Figure 6.6 An expandable, big-view-style notification that is contracted (second notification from the top), showing an icon, a title, a line of text, and a timestamp.

Notification Priority

Starting with Android 4.1 (API Level 17), notifications include the ability to set a priority. The priority allows the system to determine the order of importance in which to display an application’s activity to the device user. Here is a list of priorities you are able to set for your notifications:

Image Min: Notifications do not show in the status bar when triggered, only when the user expands the notification tray.

Image Low: Notifications show in the status bar with a low priority.

Image Default: Notifications default to this when not specifically configured.

Image High: Notifications for including messages such as, SMS, emails, etc.

Image Max: Notifications for missed calls, voicemails, etc.

Introducing the Notification Listener

Android 4.3 (API Level 18) introduced the NotificationListenerService, and Android 4.4 (API Level 19) quickly released enhancements to this new Service class. The class is designed so that you can configure your application to listen for notifications as the system triggers responses to them. The Android 4.4 updates include special metadata with the notification messages sent by the system, allowing your application to learn more about the information included, such as the picture or title of a notification. This metadata is included as a Bundle, and Android 4.4 also includes a Notification.Action class that is useful for learning information about the actions posted by the notifications. You must include the BIND_NOTIFICATION_LISTENER_SERVICE permission on the NotificationListenerService class registered in your manifest, in addition to including an <intent-filter> action with a constant value of android.service.notification.NotificationListenerService.

Designing Useful Notifications

As you can see, the notification capabilities on the Android platform are quite robust—so robust that it is easy to overdo it and make your application tiresome for the user. Here are some tips for designing useful notifications:

Image Use notifications only when your application is not in the foreground. When the application is in the foreground, use Toast or Dialog controls.

Image Allow users to determine what types (text, lights, sound, and vibration) and frequency of notifications they receive, as well as what events to trigger notifications for.

Image Whenever possible, update and reuse an existing notification instead of creating a new one.

Image Clear notifications regularly so as not to overwhelm the user with dated information.

Image When in doubt, generate “polite” notifications (read as quiet).

Image Make sure your notifications contain useful information in the ticker, title, and body text fields and launch sensible intents.

The notification framework is lightweight yet powerful. However, some applications such as alarm clocks or stock market monitors might also need to implement their own alert windows above and beyond the notification framework provided. In this case, they may use a background Service and launch full Activity windows when certain events occur. In Android 2.0 and later, developers can use the WindowManager.LayoutParams class to enable Activity windows to display, even when the screen is locked with a keyguard.

Summary

Applications can interact with their users outside the normal activity boundaries by using notifications. Notifications can be visual, auditory, or sensory, using the vibrate feature of the device. Various methods can customize these notifications to provide rich information to the user. Special care must be taken to provide the right amount of appropriate information to the user without the application becoming a nuisance or the application being installed and forgotten about.

Quiz Questions

1. What method do you call to retrieve a NotificationManager object?

2. True or false: You should use the setTicker() method to set the ticker text of a Notification.

3. True or false: The notify() method is used to broadcast the Notification.

4. What method should you set on the Notification.Builder object to display a count of notifications?

5. What does the setAutoCancel() method cause?

Exercises

1. Add an InboxStyle Notification to the SimpleNotifications application included with this chapter.

2. Add a Notification that displays a progress indicator to the SimpleNotifications application included with this chapter.

3. Create a new Android application demonstrating how to use the NotificationListenerService class.

References and More Information

Android Design: “Notifications”:

http://d.android.com/design/patterns/notifications.html

Android Training: “Notifying the User”:

http://developer.android.com/training/notify-user/index.html

Android API Guides: “Notifications”:

http://d.android.com/guide/topics/ui/notifiers/notifications.html

Android Reference documentation for the Notification class:

http://d.android.com/reference/android/app/Notification.html

Android SDK Reference documentation for the NotificationListenerService class:

http://d.android.com/reference/android/service/notification/NotificationListenerService.html

Android SDK Reference documentation for the StatusBarNotification class:

http://d.android.com/reference/android/service/notification/StatusBarNotification.html

Android SDK Reference documentation for the NotificationManager class:

http://d.android.com/reference/android/app/NotificationManager.html

Android SDK Reference documentation for the Notification.Builder class:

http://d.android.com/reference/android/app/Notification.Builder.html

Android SDK Reference documentation for the NotificationCompat class:

http://d.android.com/reference/android/support/v4/app/NotificationCompat.html

YouTube Android Developers Channel: “Android Design in Action: Notifications and Design Process with Alex Faaborg”:

http://www.youtube.com/watch?v=FaW8PwhU_BY

YouTube Android Developers Channel: “2012-10-18 Android Developer Lab+ - Notifications”:

http://www.youtube.com/watch?v=s61Rbk3ynXQ

YouTube Android Developers Channel: “Android Design in Action: Local Video and Rich Notifications”:

http://www.youtube.com/watch?v=2YeTxWtxgPQ

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.116.21.109