You will learn how to make incoming call notifications on Android from basic to advanced layouts from this article. Customize the notification screen with our examples.
Last time, we told you what any Android app with calls should have and promised to show you how to implement it. Today we’ll deal with notifications for incoming calls: we’ll start with the simplest and most minimalistic ones, and end with full-screen notifications with an off-system design. Let’s get started!
Creating a channel(api 26+)
Since Android 8.0, each notification must have a notification channel to which it belongs. Before this version of the system, the user could either allow or disallow the app to show notifications, without being able to turn off only a certain category, which was not very convenient. With channels, on the other hand, the user can turn off annoying notifications from the app, such as ads and unnecessary reminders, while leaving only the ones he needs (new messages, calls, and so on).
If we don’t specify a channel ID, using the Deprecated builder. If we don’t create a channel with such an ID, the notification will not be displayed with the Android 8 or later versions.
We need the androidx.core library which you probably already have hooked up. We write in Kotlin, so we use the version of the library for that language:
All work with notifications is done through the system service NotificationManager. For backward compatibility, it is always better to use the Compat version of Android classes if you have them, so we will use NotificationManagerCompat. To get the instance:
Let’s create our channel. You can set a lot of parameters for the Let’s create our channel. You can set a lot of parameters for the channel, such as a general sound for notifications and a vibration pattern. We will set only the basic ones, and the full list you can find here.
Notification runtime permission (api 33+):
If your app targets Android 13+ you should declare the following permission in AndroidManifest:
You should also request POST_NOTIFICATIONS permission from a user at runtime. Learn more about permission requesting.
Displaying a notification
Now we can start creating the notification itself, let’s start with the simplest example:
The INCOMING_CALL_NOTIFICATION_ID is a notification identifier that can be used to find and interact with an already displayed notification.
For example, the user wasn’t answering the call for a long time, the caller got tired of waiting and canceled the call. Then we can cancel notification:
Or, in the case of a conferencing application, if more than one person has joined the caller, we can update our notification. To do this, just create a new notification and pass the same notification ID in the notify call—then the old notification will just be updated with the data, without animating the appearance of the new notification. To do this, we can reuse the old notificationBuilder by simply replacing the changed part in it:
Button actions upon clicking
A simple notification of an incoming call, after which the user has to find our application himself and accept or reject the call is not a very useful thing. Fortunately, we can add action buttons to our notification!
To do this, we add one or more actions when creating the notification. Creating them will look something like this:
Wait a minute, what does another PendingIntent mean? It’s a very broad topic, worthy of its own article, but simplistically, it’s a description of how to run an element of our application (such as an activity). In its simplest form it goes like this:
Accordingly, we need to handle this action in activity itself
To do this, in `onCreate()` (and in `onNewIntent()` if you use the flag `FLAG_ACTIVITY_SINGLE_TOP` for your activity), take `action` from `intent` and take the action:
Now that we have everything ready for our action, we can add it to our notification via `Builder`:
In addition to the buttons, we can assign an action by clicking on the notification itself, outside of the buttons. Going to the incoming call screen seems like the best solution — to do this, we repeat all the steps of creating an action, but use a different action id instead of `ACTION_ACCEPT_CALL`, and in `MainActivity.onCreate()` handle that `action` with navigation:
Notification.CallStyle (api 31+):
There’s a new call notification style in Android 12, Notification.CallStyle. It helps you distinguish and highlight the call notification among others. In the new OS versions starting from Android 12 you have to use Notification.CallStyle instead of custom call notifications.
Notifications with their own design
Notifications themselves are part of the system interface, so they will be displayed in the same system style. However, if you want to stand out, or if the standard arrangement of buttons and other notification elements don’t suit you, you can give the notifications your own unique style.
DISCLAIMER: Due to the huge variety of Android devices with different screen sizes and aspect ratios, combined with the limited positioning of elements in notifications (relative to regular application screens), Custom Content Notification is much more difficult to support
The notification will still be rendered by the system, that is, outside of our application process, so we need to use RemoteViews instead of the regular View. Note that this mechanism does not support all the familiar elements, in particular, the `ConstraintLayout` is not available.
A simple example is a custom notification with one button for accepting a call:
The layout is ready, now we need to create an instance RemoteViews and pass it to the notification constructor.
Our example is as simplistic as possible and, of course, a bit jarring. Usually, a customized notification is done in a style similar to the system notification, but in a branded color scheme, like the notifications in Skype, for example.
In addition to .setCustomContentView, which is a normal notification, we can separately specify mark-up for the expanded state .setCustomBigContentView and for the head-up state .setCustomHeadsUpContentView
Now our custom notification layouts match the design inside the app, but they’re still small notifications, with small buttons. And what happens when you get a normal incoming call? Our eyes are presented with a beautiful screen that takes up all the available space. Fortunately, this functionality is available to us! And we’re not afraid of any limitations associated with RemoteViews, as we can show the full `activity`.
First of all, we have to add a permission to `AndroidManifest.xml`
After creating an `activity` with the desired design and functionality, we initialize the PendingIntent and add it to the notification:
And that’s it! Despite the fact that this functionality is so easy to add, for some reason not all call-related applications use it. However, giants like Whatsapp and Telegram have implemented notifications of incoming calls in this way!
The incoming call notification on Android is a very important part of the application. There are a lot of requirements: it should be prompt, eye-catching, but not annoying. Today we learned about the tools available to achieve all these goals. Let your notifications be always beautiful!