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.
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.
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 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.
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.
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.
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.
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.
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.
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());
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.
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());
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.
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());
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.
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());
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.
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());
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.
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, 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.
Below screen shows long press menu.
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
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);
}
}
}
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());
}
}
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);
}
}
<?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>