Show a message reply Notification in android

Sadman Sarar
3 min readDec 22, 2020

Creating a notification that can reply to a message is one of the newest addition to the android platform. It can easily be achieved by using remote input. With no further delay, let’s get into it.

First, a few things we need to create a notification channel. The following function achieves that.

private fun createNotificationChannel(id: String, name: String, description: String) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
val importance = NotificationManager.IMPORTANCE_HIGH
val channel = NotificationChannel(id, name, importance)
channel.description = description
channel.enableLights(true)
channel.lightColor = Color.RED
channel.enableVibration(true)

notificationManager.createNotificationChannel(channel)
}
}

Also, let’s add a button that will trigger a notification as we don’t have any messaging mechanism on our hands. Add a button and add this line to out onCreate of activity. sendNotification() function is where we build out notification.

findViewById<View>(R.id.btnShowNotification).setOnClickListener {
sendNotification()
}

For building the message notification, we must define a Remote Input which should take a string(KEY_TEXT_REPLY) by which we would be able to identify input later.

val remoteInput: RemoteInput = RemoteInput.Builder(KEY_TEXT_REPLY)
.setLabel(replyLabel)
.build()

The next step is to create a pending with an intent that would trigger a service. We will create a RemoteInputSerivice for handling the intent from our remote input.

val resultIntent = Intent(this, RemoteInputService::class.java)

val resultPendingIntent = PendingIntent.getService(
this,
0,
resultIntent,
PendingIntent.FLAG_UPDATE_CURRENT
)

Now, we should create a Notification action with the remote input.

val replyAction: NotificationCompat.Action = NotificationCompat.Action.Builder(
IconCompat.createWithResource(this, android.R.drawable.ic_dialog_info), "Reply",
resultPendingIntent)
.addRemoteInput(remoteInput)
.build()

Now we have enough things for creating our desired notification. Let’s build one:

val newMessageNotification = NotificationCompat.Builder(this, CHANNEL_ID)
.setColor(ContextCompat.getColor(this, R.color.purple_200))
.setSmallIcon(android.R.drawable.ic_dialog_info)
.setContentTitle("You received a new message")
.setContentText(receivedMessage)
.addAction(replyAction).build()

The last step is to show the notification using our notification manager

notificationManager.notify(MESSAGE_NOTIFICATION_ID, newMessageNotification)

As mentioned earlier, we need to create a RemoteInputService that will handle our intent from the RemoteInput. The onStartCommand of the service will be called with our intent. Here we can use the intent to get the input string.

val remoteInput = RemoteInput.getResultsFromIntent(intent)
if (remoteInput != null) {
val inputString = remoteInput.getCharSequence(KEY_TEXT_REPLY).toString()
}

If you observe the UI, the send button is showing an indicator. It’s waiting for an update in response to the pending intent. We should update the notification.

val repliedNotification: Notification = NotificationCompat.Builder(this,CHANNEL_ID)
.setSmallIcon(android.R.drawable.ic_dialog_info)
.setContentText(inputString)
.build()

val notificationManager = getSystemService(
Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.notify(MainActivity.MESSAGE_NOTIFICATION_ID, repliedNotification)

To receive the callback to our activity we can use a Broadcast receiver. Let’s create a RemoteInputBroadcastReceiver.

inner class RemoteInputBroadcastReceiver : BroadcastReceiver() {


override fun onReceive(context: Context, intent: Intent) {
val myTextView = this@MainActivity.findViewById<TextView>(R.id.txtMessage)
val inputString = intent.getStringExtra(EXTRA_REPLY_MESSAGE)
myTextView.text = inputString
}
}

Let’s register and unregister the broadcast receiver instance onStart and onStop of our activity.

override fun onStart() {
super.onStart()
registerReciver()
}

override fun onStop() {
super.onStop()
unregisterReceiver(remoteInputBroadcastReceiver)
}
private fun registerReciver() {
val filter = IntentFilter(REPLY_BROADCAST_ACTION)
registerReceiver(remoteInputBroadcastReceiver, filter)
}

Now we are listening to the sent message, but our service still does not send any. So, let’s modify our service to send the broadcast. Add this line to our service’s onStartCommand.

sendBroadcast(
Intent(REPLY_BROADCAST_ACTION).apply {
putExtra(EXTRA_REPLY_MESSAGE, inputString)
}
)

Now, if you trigger a notification, you should see a reply button. If you reply to the notification, the UI on the main activity should be updated.

The whole demo project can be found here.

If you think that was helpful, share the article with others.

--

--