Chapter    23

Communicating with Notifications

One of the enduring features of all operating systems is their ability to seek your attention, calling you to action for some form of notification. Whether it is the arrival of a new email or an SMS message from a friend, a low battery warning, the confirmation of a purchase, or traffic alerts, notifications in Android are all about trying to get your attention.

Android devices have a range of ways to notify you that we explore in this chapter. The familiar tray icons that appear at the top of the Android launcher are likely familiar to you. After the examples of using dialog boxes earlier in the book, you should know all about pop-up style messages, and you might even have seen their downside—applications that get “pop-up happy” and insist on responses again and again.

Android also supports some hardware that, among other things, lends a hand on the notifications front. The vibration and haptic feedback mechanisms of a phone or tablet help you feel notifications, and phones, including ones as old as the original Dream/G1, incorporate a pulsing light in the trackwheel or a set of buttons that provide a visual clue to the user that notifications are waiting.

To make all of this work well for the user, and to make it all so it can be easily incorporated into applications by developers, it will not surprise you to learn that Android includes a complete framework as part of the SDK to help bring notifications to your applications.

Configuring Notifications

Applications have lots of ways of grabbing a user’s attention when something interesting happens. But an application can also be paused, in the background, and frankly forgotten by the user when an event happens. Services do not even have a user interface through which they catch the user’s eye. Applications and services also need ways to direct the user to the relevant activity in response to an event.

All of these requirements are handled in Android by the NotificationManager system service. To gain access to the NotificationManager, you need to pass the appropriate parameter to the getSystemService() method from your activity or your own service logic. In practice, this is as simple as creating an object with a call like this:

getSystemService(NOTIFICATION_SERVICE)

With the resulting NotificationManager object, you then have access to the main notification management methods. These are the typical methods with which you will normally control your notifications:

  • notify(): This is the main method you would use to raise notifications according to your desired triggers and events. This takes a Notification object as a parameter, which is the main data structure that carries the payload of your notification—text, images, and so on—as well as the way or ways in which you would like to catch the user’s attention.
  • cancel(): To dismiss a notification, you use the cancel() method. Android is also able to cancel notification in response to certain user actions, such as swipe-to-dismiss gestures.
  • cancelAll(): Use this method when you just want to get rid of all the notifications that a NotificationManager object has active.

Customizing the Notification Object

Out of the box, notifications are quite functional and include a bunch of sensible defaults to help catch the user’s attention. But sometimes you want to up the ante and make your notification irresistable. The Notification object has methods to enhance and customize your notification.

Note  Some of the following methods are from the original methods and data members available for the Notification object. Starting in API level 11, several of these methods—in particular the constructor—were deprecated in favor of a slightly different approach. I cover all of the original ways of configuring a notification since this allows you to understand individual configuration options one at a time. At the end of the chapter, I demonstrate how to use the newer builder option to perform all the configurations using the new approach.

The good news is the older approach may be deprecated, but it is still available all the way up to and including Android version 6.0 Marshmallow.

Adding Sounds to Your Notification

Android supports the notion of default sounds for many different types of notifications, all of which can be configured by the device user. This means that you can avoid having to manually specify sounds if you do not want to go to that effort and simply tell your Notification object to use the default sound by invoking its .defaults() method as follows:

Notification myNotification = new Notification(...);
myNotification.defaults = Notification.DEFAULT_SOUND;

Where you do wish to provide your own sounds, it is as simple as providing the Uri reference to a sound file resource. This can be a sound file of your own that you have added to your raw project resources, or a Uri reference to one of the many sounds that come prepackaged with Android.

For instance, to use the Kalimba sound that ships as part of stock Android, you can source the Uri for this resource using the ContentResolver class, and assign the sound accordingly:

Notification myNotification = new Notificiation(...);
myNotification.sound = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE +
                                                     "://" +
                                                     getPackageName() +
                                                     "/raw/kalimba");

One very important aspect to remember with notification sounds (and several other notification attributes we discuss shortly) is that if you assign a sound via .sound() and set .defaults() to include the flag DEFAULTS_SOUND, then the default always overrides the custom sound, regardless of the order in which you call the methods on your Notification object.

Shining a Light for Your Notification

Almost all phone and tablet-format Android devices come with a built-in LED light below the main screen. This has several uses, but the primary one is to aid in notifying users of events like notifications. You can control this LED in various ways by configuring your Notification object.

  • Set the .lights() method to true, which activates the LED.
  • Where color is supported, use ledARGB and your desired hex code for the RGB-based color you wish to use to have a device change the color of the LED.
  • Control blinking speed and spacing using the ledOnMS and ledOffMS values, which express on and off times in milliseconds.

Whatever customization you wish to perform, you should also make sure you set the Notification.flags field to include the Notification.FLASH_SHOW_LIGHTS flag. On devices with simpler LEDs, your choice of color might be ignored and replaced with a different brightness of the fixed color the LED supports. Also, a handful of devices have color-variable LEDs, but their manufacturers haven’t included the necessary support for the Notification class so that you are able to control color.

This raises a larger point that you should keep in mind. Your application can also run on devices that do not have a notification LED, such as an Android TV or an in-car system. It is best to think of your LED customization as a useful extra, rather than the only tool for gaining the user’s attention.

Vibrating to Shake Things Up

If lights and sounds are not enough to get your user’s attention, try shocking them into action with a little vibration. Another default flag exists to allow use of the device-wide default.

myNotification.defaults = Notifcation.DEFAULT_VIBRATE;

Note that in order for your application to be permitted to make a device vibrate, you must ask for <uses-permission android:name="android.permission.VIBRATE" /> in your application manifest. You can also perform custom vibration via .vibrate(), providing a long[] of the duration of on/off timing for the vibration, with values in milliseconds. For example, new long[] {1000, 500, 1000, 500, 1000} makes your notification vibrate three times for a second each, with a half-second pause between vibrations.

Adding Icons for Notifications

So far, each of the notification customizations has aimed to catch the user’s attention. Icons differ in that they attempt to provide more information to the user regarding what the notification is about once they have actually noticed it.

In addition to providing the drawables that convey more meaning to your user, you also need to provide a contentIntent value,PendingIntent, which should be raised when the user decides to touch the icon in your notification. As you saw in earlier chapters, a PendingIntent acts as a wrapper and a “snooze” function allowing you to ready an Intent to later trigger some activity, service, or what have you.

One more flourish is available when you are adding an icon and contentIntent to your notification. You are also allowed to add a short piece of text to include via the tickerText attribute. This is where you can put the most important part of the notification text, such as the name of a person sending a message in a messaging app, the subject of an email, the caption of a photo, and so on. If you want to save coding effort and you plan on including all three of the icons, contentIntent and tickerText, the setLatestEventInfo() method allows you to specify all three in a single call.

Icon Sizes for Old and New Android Versions

If you like the notion of adding icons to your notifications, then consider what kind of fidelity you would like your icons to have across older and newer Android versions and different screen densities.

To support all of Android’s recommended notification styles and sizes, you need to provide four or more different drawables that represent your icon:

  • A 25-pixel square for all Android versions prior to 2.3 (and regardless of actual screen density on those old devices). This is placed in the res/drawable resource folder.
  • A 24-pixel by 38-pixel bounding box, housing a 24-pixel square icon, for use on high-density, extra-high-density, and extra-extra-high-density screens. This icon is placed in the res/drawable-hdpi-v9, res/drawable-xhdpi-v9, and res/drawable-xxhdpi-v9 folders.
  • A 16-pixel by 25-pixel bounding box, housing a 16-pixel square icon, for use on medium-density screens. This icon is placed in the res/drawable-mdpi folder.
  • A 12-pixel by 19-pixel bounding box, housing a 12-pixed square icon, for use on low-density screens. This icon is placed in the res/drawable-ldpi-v9 project folder.

More details on icon styling and use are available in the design section of the Android developer site. This includes some useful information on up-scaling and down-scaling drawables where you decide not to include one or more of the size-and-density-specific icons for your application. It is not the end of the world to omit one of these icons, but you should at least be aware of the possible poor onscreen look of your notification if you choose to skip one.

Floating Numbers for Added Information

One type of flourish on notifications you may have already seen, and have come to appreciate, is the extra floating “number” that can appear over an icon to summarize either the count of similar notifications, or unread/unresponded notifications.

The Notification object includes a public member named number that you can set directly with the number you wish to have appear in the top-right or top-left corner of the icon (depending on locale and right-to-left or left-to-right convention on the device). By default this value is not set, and in the unset state, Android simply ignores it and does not attempt to show any number as an icon overlay.

Notifications in Action

Now that you are familiar with the concepts and customizable features of notifications with Android, let’s take a look at the first example application that shows a bunch of these features in action. The NotificationExample sample is provided in the ch23/NotificationExample folder.

The layout is very similar to some of the two-button test layouts you have already seen for other examples in the book. Figure 23-1 shows the layout with the two buttons: one to fire the notification, and another to clear it.

9781430246862_Fig23-01.jpg

Figure 23-1. The basic NotificationExample layout, with no notifications showing

There are no particularly noteworthy features to the layout XML, so I will omit it to save space—feel free to browse the XML in the ch23/NotificationExample project.

Coding Notification Behavior

The code for NotificationExample, shown in Listing 23-1, is interesting.

Although there is a reasonable amount of code here, and in the companion NotifcationFollowon class, much of it should already be familiar to you. Setting up the activity in onCreate() does the normal task of restoring or creating state and inflating the layout, in addition to the work of creating the myNotifyMgr object to bind to the system notification infrastructure. The NotificationExample class itself also sets up a ficticious ID for the notification and a counter to track how many pending notifications there are. Note that you can easily decide to have multiple different types of notifications from your application. If you decide to do this, be sure to use a different ID to distinguish each type.

Employing the onClick() method establishes the familiar pattern I use to group button-click handling together—though, again, in this example, you can just as easily have each button call the relevant raiseNotification() and dismissNotification() methods directly. It is the implementation of these methods that houses our interesting notification logic.

Within the raiseNotification() method, we perform almost all of the optional configuration and customization I described at the start of the chapter. First, we create the Notification object and assign the wavinghand.png icon and the status text to use on versions of Android that support showing status text at the time of notification.

Next, we create a PendingIntent that points at the NotificationFollowon activity. This is triggered if a user decides to click on the wavinghand.png icon in the notification drawer. The PendingIntent is then bundled with a notification title and an additional notification message using the setLatestEventInfo() method, and it is ready for deployment into the notification drawer.

Lastly, we go to town using all of the extra notification bells and whistles for the Notification object:

  • .sound() is called and given the pop.mp3 sound as a resource from the raw folder.
  • .vibrate() is called with a cadence of one second on, half a second off of vibration.
  • .number() is called to increment the number of times the notification has been raised.
  • .flags() is called to include the FLAG_AUTO_CANCEL option in the flags field.

With all of the options configured, we finally pass the Notification object and the NOTIFICATION_ID to the NotificationManager for presentation to the user.

Notifications as the User Experiences Them

Running the NotificationExample application in a virtual device provides most of the experience of notifications. Figure 23-2 shows the notification appearing in the icon bar of the home screen.

9781430246862_Fig23-02.jpg

Figure 23-2. Notification triggered in top-left corner—the small waving hand icon

The little waving hand icon can be a bit hard to make out on the printed page, so definitely try running the example for yourself to see it appear in your own virtual device. Depending on the API levels supported by your AVD, you may or may not see the additional status text associated with the Notification object.

Clicking the Clear Notification button makes the icon disappear, and if you are fast enough to click it while the pop sound is still playing or a real device is still vibrating, those additional customizations also stop.

The notification stays in place throughout the lifecycle of the activity, and even after you have gone off to other applications or have returned to the launcher home screen. Try it for yourself, and you should still see the notificication icon, as in Figure 23-3.

9781430246862_Fig23-03.jpg

Figure 23-3. Notification icon persists even after leaving activity

At any point after the notification has fired, the device user can access the notification drawer that collects all the notifications from all the applications on the device. They do this by grabbing the bar at the top of the screen and dragging all the way to the bottom. Figure 23-4 shows our example notification with many of the additional details we added, including the notification title and additional text.

9781430246862_Fig23-04.jpg

Figure 23-4. The notifications drawer open, showing our notification

What you see in the notification drawer is heavily dependent on the release of Android you are using. The most modern Lollipop and Marshmallow approach is shown in Figure 23-4, with our icon chosen from the appropriate screen density resource or scaled from the nearest available resource packaged within the application. Our 25-by-25 pixel waving hand is far more recognizable in the notification drawer. The title and additional text are shown, along with the timestamp passed to the Notification object at creation time.

You will also notice that the number value is presented in the notification drawer of newer Android releases, instead of as an overlay on the icon in the icon bar. This change was largely driven by the tendency of the icons to become crowded and overwhelmed on phone-sized screens, so it was moved to the drawer, which made it more likely that it wouldn’t be lost in the noise.

The user can click the icon to trigger the follow-on activity, or they can simply dismiss the notification—just as if they had hit the Clear Notification button on the activity home screen. In Android version 4.0 (Ice Cream Sandwich) and later, you also see the three slightly offset horizontal bars below the notifications; this is the dismiss all option. This triggers the cancelAll() method on all active NotificationManager objects, which completely clears the notification drawer.

A completely clear notification drawer looks like the depiction in Figure 23-5.

9781430246862_Fig23-05.jpg

Figure 23-5. All notifications have been cleared from the device

Note that clearing notifications in this fashion does not necessarily clear the notification count you may have been tracking in your application. Remember, just because you have switched away from the application, doesn’t mean Android has necessarily triggered onDestroy() or reaped the application for its resources.

Using the Builder Approach to Notifications

At the beginning of the chapter, I pointed out that there were newer approaches to creating your Notification objects that were introduced from API level 11 on. The main change to be aware of is the preference for using a NotificationBuilder object to handle all of the configuration and customization for your notification.

This means that the followingaspects of the original Notifcation class are flagged as deprecated, though support is still provided in the most recent Android version 6.0 Marshmallow release.

  • Overloaded options for the constructor are deprecated.
  • The setLatestEventInfo() method is deprecated.

The Notification.Builder allows you to stack method calls for all the components of the Notification you wish to customize. This means that in the NotificationExample sample application, we can replace our constructor call and our subsequent call to setLatestEventInfo() with the following use of the builder:

Notification myNotification = new Notification.Builder(context)
    .setContentTitle("Notice this")
    .setContentText("Notification content")
    .setSmallIcon(R.drawable.wavinghand)
    .setLargeIcon(R.drawable.wavinghand)
    .setContentIntent(myPendingI)
    .setWhen(System.currentTimeMillis())
    .build();

Note that we need to move the declaration of the contentIntent’s PendingIntent object so it falls before we use the builder so it is in scope for the .setContentIntent() call. In most other respects, you can see the equivalent aspects of the traditional notification constructor and other calls in the builder approach.

Other Uses and Extensions to Notifications

Notifications have enjoyed almost constant enhancement since Android was released, and I touch on more advanced uses next. There is a great deal more to the advanced features that are beyond the scope of this book, but you can read about them online at the Android developer site.

Notifications and Services

In Chapter 22, we discussed services and their traditional nature of staying in the background and being invisible to the user, while, at the same time, performing useful tasks or actions for the user. Remember that services can also be subject to Android’s need to reclaim resources, and so they can be killed off when memory is heavily constrained. Although you know about the “stickiness” and out-of-memory controls for services, there is another approach to keeping services around when they otherwise might be subject to termination, and this method involves using notifications.

A service can declare that it should be considered at the priority level of foreground, which gives it the same chance of surviving as the applications that are currently in onCreate()/onResume() parts of their lifecycle. The cost to you as a developer is that you must implement a user notification that flags to the device user that your service has taken on foreground priority.

You achieve the move to foreground by calling the startForeground() method in your service’s onCreate() logic. The startForeground() method takes a Notification object as a parameter, and it takes a unique ID, just as the .notify() method for NotificationManager does. You can guess what startForeground() does with those parameters. If you need or want to move the service to the background priority level, you call stopForeground() and this also uses the cancel() method under the hood with the relevant NotificationManager object to clear the related notification.

More Advanced Notification Features

Although this chapter has focused on the fundamentals of notifications, you should at least be aware of the many types of advanced notification features Google has added in recent releases. Many of these styles of notifications were tailored to suit particular derivations of Android, such as Google Glass, Android Wear, and the TV and in-car modificaitons to Android. I could fill a book that just deals with all of the nuances and possibilities of advanced notification features, but we just do not have the page count to spare.

Instead, here is an overview of some of the more interesting new-style notifications; the Android developer documentation can help you learn more.

Timeline Notifications

This is more of a formatting approach than a leap in functionality. With the introduction of Google Glass, Google created a larger notification canvas with options for much larger images. Figure 23-6 shows the classic Timeline Notification teaser.

9781430246862_Fig23-06.jpg

Figure 23-6. A notification formatted for Google Glass’s timeline format

Bundled Notifications

Bundled notifications take the idea of the number attribute that counts multiple notifications and turns it on its head. Instead of just presenting a count, a bundled notification presents a “top” notification and visual cues allow the user to open the bundle and see all the related notifications. Figure 23-7 shows a top-level notification for a bundled notification.

9781430246862_Fig23-07.jpg

Figure 23-7. The top notification in a bundle of notifications

The key visual cue that this is a bundle is the folded corner motif in the top-right. The user can actually swipe that part of the notification to reveal all of the notifications that constitute the bundle. Figure 23-8 shows a sample of notifications in a bundle.

9781430246862_Fig23-08.jpg

Figure 23-8. The notifications within a bundle

The one additional UI feature here is the subtle white bar at the bottom of the bundled notifications. The bar is divided into a number of sections equal to the number of notifications in the bundle. The highlighted part of the footer bar changes to represent which notification in the bundle the user is viewing.

Expanding Notifications

From Android version 4.1 Jelly Bean on, Google added support for expanding notifications that do not trigger an activity when the notification is clicked. Instead, expandable notifications can increase their size within the notifications drawer and show additional content as well as one or more embedded actions (I will discuss embedded actions momentarily). This allows the user to make much more use of larger screens like tablets and phablets, as well as move straight to the desired response action rather than having to navigate to the contentIntent-triggered activity and then chose an action.

Figure 23-9 shows a notification that has expanded to a much larger size, using a background image, and with two embedded actions for the user to quickly use.

9781430246862_Fig23-09.jpg

Figure 23-9. Expanding notification with multiple embedded actions

More Embedded Actions in Notifications

One particular set of new features promoted by Google across all the variants of the Android platform is the ability to add direct actions to the notification. Whereas the traditional notification can use the contentIntent member of the Notification object to trigger a specific activity, embedded actions provide more context and the abililty to label the tasks (multiple!) that can be performed. This, in effect, gives you capabilities like a mini embedded menu of actions inside the notification. Figure 23-10 shows a simple reply function surfaced within a message notification.

9781430246862_Fig23-10.jpg

Figure 23-10. Actions within a timeline notification

Notifications Tailored for Wear

With the recent rapid growth in the wearable Android space, it will come as no surprise that specific wearable-tailored notification styles exist in Android version 4.3 KitKat and later versions. The main options available cover the aesthetics of text sizing and placement with images, as shown in Figure 23-11, plus full support for square and round screen displays translating into appropriately shaped notifications.

9781430246862_Fig23-11.jpg

Figure 23-11. Circular notifications for Android Wear

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

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