In the previous entries, I have managed to display a notification and make it sticky. Now, since the app I'm developing is supposed to be visible mainly through this notification, I wanted to see if I can customise the actual content. Yes, I know there are options by default, like:

  • Small and large notifications
  • Add some buttons to perform actions

However, I wanted to see if I can, for example, add some icons and buttons like Sonos notification does:

sonos-notification

It turns out that, with a bit of work and an OS Jelly Bean or better, anything is possible!

Preparation

Most for the NotificationBuilder code for custom notification is the same as the other ones:

NotificationCompat.Builder builder = new NotificationCompat.Builder(getContext())
    // Set Icon
    .setSmallIcon(R.drawable.ic_launcher)
      // Set Ticker Message
    .setTicker(getContext().getString(R.string.customnotificationticker))
    // Dismiss Notification
    .setAutoCancel(true)
    // Set PendingIntent into Notification
    .setContentIntent(pIntent);

Now, the builder is prepared to receive the custom layout. To make it compatible with devices pre-JellyBean, you need to do something like this:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
    // build a complex notification, with buttons and such
    //
    builder = builder.setContent(getComplexNotificationView());
} else {
    // Build a simpler notification, without buttons
    //
    builder = builder.setContentTitle(getTitle())
        .setContentText(getText())
        .setSmallIcon(android.R.drawable.ic_menu_gallery);
}

The custom content is set (as seen above) with builder.setContent(RemoteViews views). Now all we have to do is to build the remote view.

For the purpose of this exercise, custom layout is designed to have an image, a larger and a smaller text underneath, just like the default notification:

custom-layout

The RemoteViews creation code is:

private RemoteViews getComplexNotificationView() {
  // Using RemoteViews to bind custom layouts into Notification
  RemoteViews notificationView = new RemoteViews(
      getContext().getPackageName(),
      R.layout.activity_custom_notification
  );

Once the view object is created, we can set the various components programmatically (e.g. content from an Intent):

    // Locate and set the Image into customnotificationtext.xml ImageViews
    notificationView.setImageViewResource(R.id.imagenotileft, R.drawable.ic_launcher);

    // Locate and set the Text into customnotificationtext.xml TextViews
    notificationView.setTextViewText(R.id.title, getTitle());
    notificationView.setTextViewText(R.id.text, getText());

    return notificationView;
}

Voila! the builder is now complete and we can show the notification as in the previous posts.

Code

Notification Layout

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

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    style="@android:style/TextAppearance.StatusBar.EventContent"
    >

    <ImageView
        android:id="@+id/imagenotileft"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_margin="8dp"
        android:contentDescription="@string/app_name"
        android:src="@drawable/ic_launcher" />


    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_alignParentBottom="false"
        android:layout_margin="8dp"
        android:layout_toRightOf="@+id/imagenotileft"
        android:gravity="center_vertical"
        android:orientation="vertical">

        <TextView
            android:id="@+id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/customnotificationtitle"
            android:textStyle="bold"
            />

        <TextView
            android:id="@+id/text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/customnotificationtext"
            />
    </LinearLayout>

</RelativeLayout>

buildNotification Method

For the lazy:

protected NotificationCompat.Builder buildNotification() {

    // Open NotificationView.java Activity
    PendingIntent pIntent = PendingIntent.getActivity(
        getContext(),
        NOTIFICATION_ID,
        getIntent(),
        PendingIntent.FLAG_UPDATE_CURRENT);

    NotificationCompat.Builder builder = new NotificationCompat.Builder(getContext())
        // Set Icon
        .setSmallIcon(R.drawable.ic_launcher)
          // Set Ticker Message
        .setTicker(getContext().getString(R.string.customnotificationticker))
        // Dismiss Notification
        .setAutoCancel(true)
        // Set PendingIntent into Notification
        .setContentIntent(pIntent);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
        // build a complex notification, with buttons and such
        //
        builder = builder.setContent(getComplexNotificationView());
    } else {
        // Build a simpler notification, without buttons
        //
        builder = builder.setContentTitle(getTitle())
            .setContentText(getText())
            .setSmallIcon(android.R.drawable.ic_menu_gallery);
    }
    return builder;
}

getComplexNotificationView()

private RemoteViews getComplexNotificationView() {
    // Using RemoteViews to bind custom layouts into Notification
    RemoteViews notificationView = new RemoteViews(
        getContext().getPackageName(),
        R.layout.activity_custom_notification
    );

    // Locate and set the Image into customnotificationtext.xml ImageViews
    notificationView.setImageViewResource(
        R.id.imagenotileft,
        R.drawable.ic_launcher);

    // Locate and set the Text into customnotificationtext.xml TextViews
    notificationView.setTextViewText(R.id.title, getTitle());
    notificationView.setTextViewText(R.id.text, getText());

    return notificationView;
}

HTH,