An Android 7 Notifications Tutorial
Notifications provide a way for an app to convey a message to the user when the app is either not running or is currently in the background. A messaging app might, for example, issue a notification to let the user now that a new message has arrived from a contact. Notifications can be categorized as being either local or remote. A local notification is triggered by the app itself on the device on which it is running. Remote notifications, on the other hand, are initiated by a remote server and delivered to the device for presentation to the user.
Notifications appear in the notification shade that is pulled down from the status bar of the screen and each notification can include actions such as a button to open the app that sent the notification. Android 7 has also introduced Direct Reply, a feature that allows the user to type in and submit a response to a notification from within the notification panel.
The goal of this chapter to outline and demonstrate the implementation of local notifications within an Android app. The next chapter (An Android 7 Direct Reply Notification Tutorial) will cover the implementation of direct reply notifications, while the use of Firebase to initiate and send remote notifications will be covered in the chapter entitled Integrating Firebase Support into an Android Studio Project.
An Overview of Notifications
When a notification is initiated on an Android device, it appears as an icon in the status bar. Figure 51-1, for example, shows a status bar with a number of notification icons:
Figure 51-1
To view the notifications, the user makes a downward swiping motion starting at the status bar to pull down the notification shade as shown in Figure 51-2:
Figure 51-2
A typical notification will simply display a message and, when tapped, launch the app responsible for issuing the notification. Notifications may also contain action buttons which perform a task specific to the corresponding app when tapped. Figure 51 3, for example, shows a notification containing two action buttons allowing the user to either delete or save an incoming message.
Figure 51-3
With Android 7, it is now also possible for the user to enter an inline text reply into the notification and send it to the app, as is the case in Figure 51-4 below. This allows the user to respond to a notification without having to launch the corresponding app into the foreground.
Figure 51-4
An Android 7 Direct Reply Notification Tutorial.Creating the NotifyDemo Project
Start Android Studio and create a new project, entering NotifyDemo into the Application name field and ebookfrenzy.com as the Company Domain setting before clicking on the Next button.
On the form factors screen, enable the Phone and Tablet option and set the minimum SDK setting to API N: Android N (N). Continue through the screens, requesting the creation of an Empty Activity named NotifyDemoActivity with a corresponding layout file named activity_notify_demo.
Designing the User Interface
The main activity will contain a single button, the purpose of which is to create and issue an intent. Locate and load the activity_notify_demo.xml file into the Designer tool and delete the default TextView widget. With autoconnect enabled, drag and drop a Button object from the panel onto the center of the layout canvas as illustrated in Figure 51-5:
Figure 51-5
With the Button widget selected in the layout, use the Properties panel to configure the onClick property to call a method named sendNotification.
Creating the Second Activity
For the purposes of this example, the app will contain a second activity which will be launched by the user from within the notification. Add this new activity to the project by right-clicking on the com.ebookfrenzy.notifydemo package name located in app -> java and select the New -> Activity -> Empty Activity menu option to display the New Android Activity dialog.
Enter ResultActivity into the Activity Name and Title fields and name the layout file activity_result. Since this activity will not be started when the application is launched (it will instead be launched via an intent from within the notification), it is important to make sure that the Launcher Activity option is disabled before clicking on the Finish button.
Open the layout for the second activity (app -> res -> layout -> activity_result.xml) and drag and drop a TextView widget so that it is positioned in the center of the layout. Edit the text of the TextView so that it reads “Result Activity”.
Creating and Issuing a Basic Notification
Notifications are created using the NotificationCompat.Builder class which allows properties such as the icon, title and content of the notification to be specified. Open the NotifyDemoActivity.java file and implement the sendNotification() method as follows to build a basic notification:
package com.ebookfrenzy.notifydemo; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.app.NotificationManager; import android.support.v4.app.NotificationCompat; import android.view.View; import android.content.Intent; import android.app.PendingIntent; public class NotifyDemoActivity extends AppCompatActivity { . . . protected void sendNotification(View view) { NotificationCompat.Builder builder = new NotificationCompat.Builder(this) .setSmallIcon(android.R.drawable.ic_dialog_info) .setContentTitle("A Notification") .setContentText("This is an example notification"); } }
The icon setting in the above code makes use of a built-in Android icon which is displayed both within the status bar and the notification panel when the notification is issued.
Once a notification has been built, it needs to be issued using the notify() method of NotificationManager instance. The NotificationManager, a reference to which can be obtained via a call to the getSystemService() method, is a service that runs on Android devices and is responsible for managing notifications. The code to access the NotificationManager and issue the notification needs to be added to the sendNotification() method as follows:
protected void sendNotification(View view) { NotificationCompat.Builder builder = new NotificationCompat.Builder(this) .setSmallIcon(android.R.drawable.ic_dialog_info) .setContentTitle("A Notification") .setContentText("This is an example notification"); int notificationId = 101; NotificationManager notifyMgr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); notifyMgr.notify(notificationId, builder.build()); }
Note that when the notification is issued, it is assigned a notification ID. This can be any integer and may be used later when updating or deleting the notification.
Figure 51-6
As currently implemented, tapping on the notification has no effect. The next step is to configure the notification to launch an activity when tapped.
Launching an Activity from a Notification
A notification should ideally allow the user to perform some form of action, such as launching the corresponding app, or taking some other form of action in response to the notification. A common requirement is to simply launch an activity belonging to the app when the user taps the notification.
This approach requires an activity to be launched and an Intent configured to launch that activity. Assuming an app that contains an activity named ResultActivity, the intent would be created as follows:
Intent resultIntent = new Intent(this, ResultActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity( this, 0, resultIntent, PendingIntent.FLAG_UPDATE_CURRENT );
All that remains is to assign the PendingIntent object to the notification builder instance created previously:
builder.setContentIntent(pendingIntent);
Bringing these changes together results in a modified sendNotification() method which reads as follows:
protected void sendNotification(View view) { NotificationCompat.Builder builder = new NotificationCompat.Builder(this) .setSmallIcon(android.R.drawable.ic_dialog_info) .setContentTitle("A Notification") .setContentText("This is an example notification"); Intent resultIntent = new Intent(this, ResultActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity( this, 0, resultIntent, PendingIntent.FLAG_UPDATE_CURRENT ); builder.setContentIntent(pendingIntent); int notificationId = 101; NotificationManager notifyMgr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); notifyMgr.notify(notificationId, builder.build()); }
Compile and run the app once again, tap the button and display the notification shade. This time, however, tapping the notification will cause the ResultActivity to launch.
Adding Actions to a Notification
Another way to add interactivity to a notification is to create actions. These appear as buttons beneath the notification message and are programmed to trigger specific intents when tapped by the user. The following code, if added to the sendNotification() method, will add an action button labeled “Open” which launches the referenced pending intent when selected:
NotificationCompat.Action action = new NotificationCompat.Action.Builder( android.R.drawable.sym_action_chat, "Open", pendingIntent) .build(); builder.addAction(action);
Add the above code to the method and run the app. Issue the notification and note the appearance of the Open action within the notification:
Figure 51-7
Tapping the action will trigger the pending intend and launch the ResultActivity.
Bundled Notifications
If an app has a tendency to regularly issue notifications there is a danger that those notifications will rapidly clutter both the status bar and the notification shade providing a less than optimal experience for the user. This can be particularly true of news or messaging apps that send a notification every time there is either a breaking news story or a new message arrives from a contact. Consider, for example, the notifications in Figure 51-8:
Figure 51-8
Now imagine if ten or even twenty new messages had arrived. To avoid this kind of problem Android 7 allows notifications to bundled together into groups.
To bundle notifications, each notification must be designated as belonging to the same group via the setGroup() method, and an additional notification must be issued and configured as being the summary notification. The following code, for example, creates and issues the three notifications shown in Figure 51 8 above, but bundles them into the same group. The code also issues a notification to act as the summary:
final static String GROUP_KEY_NOTIFY = "group_key_notify"; NotificationCompat.Builder builderSummary = new NotificationCompat.Builder(this) .setSmallIcon(android.R.drawable.ic_dialog_info) .setContentTitle("A Bundle Example") .setContentText("You have 3 new messages") .setGroup(GROUP_KEY_NOTIFY) .setGroupSummary(true); NotificationCompat.Builder builder1 = new NotificationCompat.Builder(this) .setSmallIcon(android.R.drawable.ic_dialog_info) .setContentTitle("New Message") .setContentText("You have a new message from Kassidy") .setGroup(GROUP_KEY_NOTIFY); NotificationCompat.Builder builder2 = new NotificationCompat.Builder(this) .setSmallIcon(android.R.drawable.ic_dialog_info) .setContentTitle("New Message") .setContentText("You have a new message from Caitlyn") .setGroup(GROUP_KEY_NOTIFY); NotificationCompat.Builder builder3 = new NotificationCompat.Builder(this) .setSmallIcon(android.R.drawable.ic_dialog_info) .setContentTitle("New Message") .setContentText("You have a new message from Jason") .setGroup(GROUP_KEY_NOTIFY); . . . int notificationId0 = 100; int notificationId1 = 101; int notificationId2 = 102; int notificationId3 = 103; NotificationManager notifyMgr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); notifyMgr.notify(notificationId1, builder1.build()); notifyMgr.notify(notificationId2, builder2.build()); notifyMgr.notify(notificationId3, builder3.build()); notifyMgr.notify(notificationId0, builderSummary.build());
When the code is executed, a single notification icon will appear in the status bar even though four notifications have actually been issued by the app. Within the notification shade, a single summary notification is displayed listing the information in each of the bundled notifications:
Figure 51-9
Pulling further downward on the notification shade expands the panel to show the details of each of the bundled notifications:
Figure 51-10
Summary
Notifications provide a way for an app to deliver a message to the user when the app is not running, or is currently in the background. Notifications appear in the status bar and notification shade. Local notifications are triggered on the device by the running app while remote notifications are initiated by a remote server and delivered to the device. Local notifications are created using the NotificationCompat.Builder class and issued using the NotificationManager service.
As demonstrated in this chapter, notifications can be configured to provide the user with options (such as launching an activity or saving a message) by making use of actions, intents and the PendingIntent class. Notification bundling provides a mechanism for grouping together notifications to provide an improved experience for apps that issue a greater number of notifications.