ZOFTINO.COM android and web dev tutorials

How to Implement Android Notifications

Android notification feature provides a way for apps to let users know about an event when applications are active, inactive or closed. Android notifications are displayed as icons in notification area. Users can view details of notification by opening notification drawer.

Notifications can be simple text messages or complex with layouts to let users perform some action by providing actionable buttons in the notification view.

Table of Contents

Creating Notifications

To create a notification in Android, first you need to use NotificationCompat.Builder class provided by Android notification frame work. NotificationCompat.Builder has flag methods using which you can define Notification object. Notification object should at least contain small icon, content title and content text information. If you are building an app to run on Android 8.0 (API level 26) and higher, you must add channel Id to NotificationCompat.Builder, check next section for more information on notification channels.

Then using NotificationManager system service, you can make the notification appear in notification area for user to view by calling notify method on it.

android notification example
 int mNotificationId = 23;
NotificationCompat.Builder mBuilder =
        new NotificationCompat.Builder(this, null)
                .setSmallIcon(R.drawable.zoftino)
                .setContentTitle("Z Latest Coupons")
                .setContentText("Latest coupons from top retailers.");
NotificationManager mNotificationManager =
        (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

mNotificationManager.notify(mNotificationId, mBuilder.build()); 

Notification Channel

Notification channels, introduced in Android 8.0 API level 26, allow you to categorize notifications and give control to user in terms of settings of each notification channel. If your app is targeted to run on API level 26 and higher, you must use channels in order for the notifications to work.

Below screen shows notification channel or category of an app. You can get this screen on long pressing a notification.

android notification channel example

To view all the categories or channels belong to the app, click all categories and below is the screen with list of channels for our example app.

android notification channel example

To view channel settings, click a channel on the screen which shows channels of an app. As shown in the below screen, for each channel, user can change settings such as importance, sound, lights, vibration, show on lockscreen and override do not disturb. Once channel has been created, these settings can’t be changed programmatically as it’ll override user selections.

List of apps, channels and channel settings can be accessed from setting also.

android notification channel settings

Creating Notification Channel

To create notification channel, first you need to instantiate NotificationChannel object passing channel id, channel name and channel description to its constructor. Then configure NotificationChannel using various methods it offers.

Below are some of the important methods used to configure notification channel.

  • Passing boolean value of true to enableLights() method makes notification lights show up when a notification is sent to this channel if device supports the feature.
  • Passing boolean value of true to enableVibration () method makes the device vibrate when a notification is sent to the channel.
  • Passing boolean value of true to setBypassDnd method makes the notifications to the channel by pass do-not-disturb mode which is set to priority only.
  • You can set priority of notifications sent to the channel using setImportance method. Possible values are IMPORTANCE_UNSPECIFIED, IMPORTANCE_NONE, IMPORTANCE_MIN, IMPORTANCE_LOW, IMPORTANCE_DEFAULT and IMPORTANCE_HIGH.
  • Method setLightColor allows you to set light color.
  • Method setLockscreenVisibility indicates whether notifications to the channel can be seen on lock screen. Possible values are Notification.VISIBILITY_PRIVATE, Notification.VISIBILITY_PUBLIC and Notification.VISIBILITY_SECRET.
  • Passing true to setShowBadge method makes badge appear on the launch icon of the app when notification is sent to the channel.
  • Method setGroup associates the channel to the channel group passed to it. Channel groups allow you to use same channel name within the app. You can create same channel name in different channel groups. To create channel group, you need to pass group id and group name to createNotificationChannelGroup method of NotificationManager object.

Below code shows how to create notification channel.

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

String channelId = "zlcb";
String channelName = "z latest cashback";
String channelDesc = "latest cashback from top retailers";

NotificationChannel channel =
        new NotificationChannel(channelId, channelName, 
                NotificationManager.IMPORTANCE_DEFAULT);
channel.setDescription(channelDesc);
channel.enableLights(true);
channel.setLightColor(Color.RED);
channel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
channel.enableVibration(true);
channel.setVibrationPattern(new long[]{100, 200, 400, 400, 500, 400, 400, 200, 500});

notificationManager.createNotificationChannel(channel);
 

You can manage notification channels and channel groups by using getNotificationChannel, deleteNotificationChannel, getNotificationChannelGroups and deleteNotificationChannelGroup methods of NotificationManager.

Notification Actions

You can add actions to notifications which will start activities in your app. You need to create activities for each action added to notifications. To add an action to notification content, meaning to start an activity when notification is clicked, content action needs to be added to notification builder while creating notification.

To make notification content clickable, you need to add PendingIntent to notification builder using setContentIntent method. For more information about pending intent, please see PendingIntent tutorial.

To start an activity when user clears notifications, create pending intent and add it to notification builder by using setDeleteIntent method.

Intent intent = new Intent(this, Coupons.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
mBuilder.setContentIntent(pendingIntent);

To add actions to notifications, you can either create NotificationCompat.Action object, then add it to notification builder by calling addAction method or pass icon, title and pending intent to notification builder by calling addAction method.

android notification example
 Intent intent = new Intent(this, CouponsActivity.class);

TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addParentStack(CouponsActivity.class);
stackBuilder.addNextIntent(intent);

PendingIntent pendingIntent =
        stackBuilder.getPendingIntent(
                0,
                PendingIntent.FLAG_UPDATE_CURRENT
        );
NotificationCompat.Action.Builder actionBuilder =
        new NotificationCompat.Action.Builder(R.drawable.view,
                "View Offers", pendingIntent);
mBuilder.addAction(actionBuilder.build()); 

Expanded Layout or Notification Styles

Notification can be shown in expanded layout by creating different style objects such as NotificationCompat.BigPictureStyle, NotificationCompat.BigTextStyle, NotificationCompat.DecoratedCustomViewStyle, NotificationCompat.InboxStyle, NotificationCompat.MediaStyle and NotificationCompat.MessagingStyle and adding the style object to notification builder by calling setStyle.

Displaying Notification with Lot of Text Using BigTextStyle

To post notification with lot of text, you can use BigTextStyle as shown below.

 NotificationCompat.BigTextStyle bigTextStyle = 
	new NotificationCompat.BigTextStyle();
bigTextStyle.bigText(offers);

builder.setStyle(bigTextStyle);
notificationManager.notify(notificationId, builder.build());

Notification Inbox Style

Below screen shot shows notification in inbox style. To create inbox style notification, we need to use NotificationCompat.InboxStyle object and call setBigContentTitle, setSummaryText and addLine to configure it. Then add it to NotificationCompat.Builder object by calling setStyle method.

android notification expanded layout inboxstyle
NotificationCompat.InboxStyle inboxStyle =
new NotificationCompat.InboxStyle();

inboxStyle.setBigContentTitle("Deals from top electronics retailers");
inboxStyle.setSummaryText("Excellent deals on mobiles, laptops, desktops,"
		+ "tablets and others.");
inboxStyle.addLine("Mobile 50% off");
inboxStyle.addLine("Laptops 20% off");
inboxStyle.addLine("Desktops 30% off");
inboxStyle.addLine("Tablets 22% off");
inboxStyle.addLine("Others 10% off");

builder.setStyle(inboxStyle);

mNotificationManager.notify(mNotificationId, builder.build());

Displaying Image in Notification or BigPictureStyle

To display large content with large image, you can use BigPictureStyle object. An image can be added to BigPictureStyle object by calling bigPicture method and passing bitmap to it as shown below.

android notification expanded layout with image bigpicturestyle
 Bitmap bitmap = BitmapFactory.decodeResource(getResources(),
        R.drawable.electronics);

NotificationCompat.BigPictureStyle bigPictureStyle =
        new NotificationCompat.BigPictureStyle();
bigPictureStyle.setSummaryText("Best deals in all categories of electronics");
bigPictureStyle.bigPicture(bitmap);
builder.setStyle(bigPictureStyle);

mNotificationManager.notify(mNotificationId, builder.build());

Messaging Style Notification

To create notification with content containing messages between two or more people, we can use NotificationCompat.MessagingStyle object and add messages to it by using addMessage method and passing message, time and sender name to it, as shown below.

android notification expanded layout messagestyle
 NotificationCompat.MessagingStyle messageStyle =
new NotificationCompat.MessagingStyle("Android Dev");

messageStyle.setConversationTitle("Notification Issue");
messageStyle.addMessage("Hi, we have an issue with notification.",
		System.currentTimeMillis(), null);
messageStyle.addMessage("What's the issue$", System.currentTimeMillis(),
		"Android Dev2");
messageStyle.addMessage("Notification functionality broke",
		System.currentTimeMillis(), null);
messageStyle.addMessage("When did it start happening, is root cause identified?",
		System.currentTimeMillis(), "Android Dev2");
NotificationCompat.Builder builder =
new NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.drawable.zoftino)
.setContentTitle("Android Dev")
.setContentText("Dev issues.")
.setStyle(messageStyle);

NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(mNotificationId, builder.build());

Custom Notification

You can define xml layout and use it as notification layout using RemoteViews. First inflate the layout using RemoteViews, set values and add it to NotificationCompat.Builder by calling setContent() method, below code shows how to create custom notification. To create custom notification with expanded layout, you will have to use DecoratedCustomViewStyle.

android custom notification custom layout
 NotificationCompat.Builder mBuilder =
	new NotificationCompat.Builder(this, channelId)
	.setSmallIcon(R.drawable.zoftino);

RemoteViews notificationContent = new RemoteViews("com.zoftino.notification",
		R.layout.custom_notification);
notificationContent.setImageViewResource(R.id.store, R.drawable.amazon);
notificationContent.setTextViewText(R.id.coupon_one, "BIG SALE");

mBuilder.setContent(notificationContent);

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

mNotificationManager.notify(mNotificationId, mBuilder.build());

Below is the custom notification layout.

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_marginTop="2dp"
    android:layout_margin="2dp"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <ImageView
        android:id="@+id/store"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
    <TextView
        android:id="@+id/coupon_one"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="4dp"/>
</LinearLayout>

Notification Badges

Notification badges, introduced in API level 26, display a dot or badge on the app launcher icon to indicate that notifications associated with the app exist and allow user to glance notifications. Long pressing launch icon displays notifications in a menu allowing user to either dismiss or take action.

Notification badges feature can be turned off by users using settings. Programmatically, badges can be turned off when a channel is created using setShowBadge method on NotificationManager object. Below screen shows badge on app launch icon.

android notification badge

Below screen shows long press menu.

android notification badges long press menu

Best Practices for Notification Implementation

  1. Since not all notification features are available in previous android versions, create notifications with NotificationCompat.Builder to achieve compatibility.
  2. Implement activities for all actions defined in notification.
  3. Update previous notification by using notification id instead of creating new notification if the notification is for same type of event as the issued notification.
  4. In certain situations where issued notification is not acted on by user and becomes irrelevant, you can clear the notification by calling cancel passing the notification id.
  5. It is good practice to bundle similar notifications, a feature introduced in API level 24.
  6. If user starts an activity by clicking actions on notification, you need to make sure that back navigation works properly.

Posting Notifications when App is not Running

Notifications can be posted to notification service when your app is not active meaning when user is not using your app or app is closed. To send notifications when your app is closed, you need to rely on alarm.

You can set a repeating alarm with pending intent which fires as per the configured frequency setting. The pending intent, which alarm sends, would start a service which intern sends notifications and the notifications can also be associated with pending intents which are triggered based on the user actions on notification and can start activities in your app for further user interactions.

Now, let’s see how to implement posting notifications from closed apps. First, we need to identify event on occurrence of which alarm can be registered with the system. We can use system events or broadcasts for registering alarm. Android system sends a broadcast once after booting is complete. We can use this system broadcast to register an alarm which would frequently fire notification intents. To receive ACTION_BOOT_COMPLETED broadcast, you need to request RECEIVE_BOOT_COMPLETED permission from users.

Alarm registration is one time activity. Once alarm is set, it starts sending intents frequently as per configuration. Below is the code.

The best way to push notifications is using Firebase cloud messaging, please see Firebase cloud messaging tutorial

Broadcast receiver starts alarm on receiving boot complete broadcast and sends service intent

package com.zoftino.notifications;


import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

public class MyAppBootReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) {
            AlarmManager alarmManger = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);

            Intent nAlarmIntent = new Intent(context, NotificationSenderService.class);
            PendingIntent nAlarmPenginIntent = PendingIntent.getBroadcast(context, 0, nAlarmIntent, 0);

            alarmManger.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                    AlarmManager.INTERVAL_FIFTEEN_MINUTES,
                    AlarmManager.INTERVAL_FIFTEEN_MINUTES, nAlarmPenginIntent);
        }
    }
}

Service, which is started by alarm, sends notification

package com.zoftino.notifications;


import android.app.IntentService;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.support.v7.app.NotificationCompat;

public class NotificationSenderService  extends IntentService {

    public NotificationSenderService() {
        super("NotificationSenderService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {

        Context context = getApplicationContext();
        NotificationCompat.Builder notificationBuilder =
                new NotificationCompat.Builder(this);

        notificationBuilder.setSmallIcon(R.drawable.notification);
        notificationBuilder.setContentTitle("Latest Coupon");
        notificationBuilder.setContentText("Get Upto 10% Off on Mobiles");

        Intent notificationClickIntent = new Intent(this, NotificationActionActivity.class);
        PendingIntent notificationPendingIntent = 
PendingIntent.getActivity(context, 0, notificationClickIntent, 0);

        notificationBuilder.setContentIntent(notificationPendingIntent);
        NotificationManager mNotificationManager =
                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        mNotificationManager.notify(1, notificationBuilder.build());
    }
}

Activity which gets started when user click notification

package com.zoftino.notifications;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

public class NotificationActionActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.notification_action);
    }
}

AndoridManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.zoftino.notifications">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <receiver android:name=".MyAppBootReceiver">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED"></action>
            </intent-filter>
        </receiver>
        <activity android:name=".NotificationActionActivity">
        </activity>
        <service android:name=".NotificationSenderService">
        </service>
        <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
    </application>

</manifest>