A message from space: create Bundled Notifications for Android N

Blobpostheaders androidstackednotificationsedit

Informing your users about you posting a new picture of your cat, or your new product finally going on sale, is a cumbersome task seldom dealt with ease. Let's take a look at building an Android app that automatically notifies users about the changes of your content.

This series consists of two posts: the first one (the one you are reading right now) will cover building Android N notifications, including how to stack multiple notifications on top of each other in so-called Bundled Notifications, and how to add images, texts and colors to customize them.

The second post will cover how to get the data to fill these notifications. In an attempt to introduce you to the webhooks in Contentful, we will quickly go through the setup and configuration of a content space and explain how to use Heroku to transform those webhooks into data which are readable by the Google Cloud Messaging service — to send them to your phone afterwards.

For now let's see how four fellow imaginary friends are using and implementing bundled notifications on Android N.

Notifications from the user perspective

Let us assume (by maybe following the second post) we have a blog space on Contentful, full of stories we and our co-authors wrote, pictures of our cats and, last but not least, all the content we need. Lewis, one of our imaginary authors, just finished his story about a rabbit hole, publishes it, and hopes everyone will read it.

Our reader and imaginary friend Mary sees a notification on her phone and wearable. It is telling her about Lewis's new and wonderful story, encouraging her to read it on her phone.

notification-lewis-publish

If now Steve from Imaginary Marketing Inc. also changes a drawing, this additional notification can get added to the already existing notifications. Mary will see something like this:

notification-stack

Let's follow Ada, our imaginary developer, to see how to implement all of the above. She already has a Google Cloud Messaging (GCM) connection established (either by sheer awesomeness, or by reading our upcoming post), and we only need to follow her to see how to use Notifications on Android.

Building notifications

First of all we notice that she has the Android 'N' preview on her phone (or an emulator) and the Android Studio installed. We should probably do the same.

To configure her build, she only needed to use a current appcompat library, changing her build.gradle file to include:

1
2
3
4
dependencies {
  /// [other dependencies]
  compile 'com.android.support:appcompat-v7:23.3.0'
}

Now she can use the NotificationManager to build notifications. Mary will be able to see three kind of notifications: 1) a header notification, to summarize stacks of notifications, 2) a notification with an external image (of the author's face, maybe Lewis'?), and 3) a simple notification without any image to be downloaded.

Header notification

Android Notifications - Header

The Header notification consists of a logo (here the 'C', which should only have white and transparent colors), the tint (green in this case), a text to be displayed, and the time. Android sets the time automatically — the rest Ada needs to provide manually. For a general style guide, please take a look at the design specification.

She created a new project and writes the followings in her launcher Activity:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
NotificationManager notificationManager;
    
@Override public void onCreate() {
  super.onCreate();
  // store the notification manager in a field, since we need it later on 
  notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
  // send a notification. Notice, that the id (the first parameter) is 0,
  // so we always change the same notification
  notificationManager.notify(0, createHeaderBuilder().build());
}
    
private NotificationCompat.Builder createHeaderBuilder() {
  return new NotificationCompat.Builder(this)
    .setColor(Color.GREEN) // use the green color (a value is needed! Not a resource)
    .setContentTitle(getString(R.string.app_name)) // 'GCM Webhooks' in the example text    
    .setSmallIcon(R.mipmap.ic_simple_contentful) // white and transparent logo (the 'C')
    .setGroupSummary(true) // important: This is a summary, aka header
    .setGroup(NOTIFICATION_GROUP); // important: Always use the same group,
                                       // otherwise you'll get multiple notifications
}

Now, if she starts the app, it will generate a notification without any content or interaction capabilities. She'll need to change that to add some actual notifications.

Simple notification

Ada starts with a simple notification without an image:

Android Notifications - Simple

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// call this method from onCreate()
private void sendNotification(Bundle data) {
  final NotificationCompat.Builder builder = createBuilder(data);
  notificationManager.notify(createNotificationId(), builder.build());
}
    
private NotificationCompat.Builder createBuilder(Bundle data) {
  final String action = // retrieve action somehow
  final String title = // retrieve title somehow
  final int icon = // retrieve icon somehow, based on action, maybe?
  
  // createIntent() creates a pending Intent, starting a new Activity from this app
  final PendingIntent pendingIntent = createIntent(data);
  return new NotificationCompat.Builder(this)
    .setContentTitle(title) // 'Alice in Wonderland'
    .setContentText(makeHumanReadable(action)) // 'auto save'
    .setSmallIcon(icon) // the 'floppy disk' symbol
    .setContentIntent(pendingIntent) // what happens if you touch the notification?
    .setAutoCancel(true) // touching the notification closes this notification
    .setGroup(NOTIFICATION_GROUP); // again, use the same ID for this group
}

By calling the sendNotification(...) method from above in onCreate(), for example, she creates two new notifications: one for the header, and one for the simple content — to be able to touch it. This way she just implemented the first interaction with notifications.

Notification with a remote image

Android Notifications - Simple Notification

The last type of notification is essentially the same as the simple one, except for the big image at the end of it. Ada retrieves this image, using the Universal Image Loader like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
imageLoader = ImageLoader.getInstance();
if (!imageLoader.isInited()) {
  // change this configuration for cache and other strategies, depending on your usecase
  final ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(this)
  .build();

  imageLoader.init(config);
}
    
// url for the image
String url = "https://images.contentful.com/gtsje21w5geo/2ReMHJhXoAcy4AyamgsgwQ/2eefbeef2bf3f285858122911a5ce74a/lewis-carroll-1.jpg";

imageLoader.loadImage(url, new ImageLoadingListener() {
  @Override public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
  // use same builder as for the simple notification, but add a large image.
  NotificationCompat.Builder builder = createBuilder(data)
    .setLargeIcon(loadedImage);
    notificationManager.notify(createNotificationId(), builder.build());
  }
    
  @Override public void onLoadingStarted(String imageUri, View view) {
    // ignored
  }
      
  @Override public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
    // inform user about message, or silently ignore complete notification
  }
      
  @Override public void onLoadingCancelled(String imageUri, View view) {
    // ignored
  }
});

That's all she wrote. With this configuration she can send notifications full of information and interaction capabilities on Android Wear and Android phones. Taking a look at Marie's other phones, we can see that the notifications are looking good there, according to their design specifications:

notification-all-os

Troubleshooting

On some configurations Ada saw some weird java.lang.RuntimeException: bad array lengths or java.lang.RuntimeException: out of memory. That happened because the downloaded image was too large. Adjusting the Universal Image Loader configuration helped her:

1
2
3
// 256 is the desired image size
final ImageSize size = new ImageSize(256, 256);
imageLoader.loadImage(uri, size, new ImageLoadingListener() {  });

Conclusion

Today we followed Lewis, Steve, Mary and Ada through their adventures of showing and seeing the notifications on Android. They interacted with Contentful, triggering different notifications, and we followed Ada's journey of developing the Notification part.

Tell us what other adventures you would like to read about, and which notifications you would like them to use.

Blog posts in your inbox

Subscribe to receive most important updates. We send emails once a month.