Add chat-related features to an Android app with the Messaging and People APIs

1. Before you begin

It's challenging to create a messaging app. Though the overall user experience is subjective, Android provides the Messaging and People APIs, which improve and streamline the chat experience.

In this codelab, you learn how to use these APIs to create a compelling ecosystem for chat apps on Android. You extend the JetChat app, a bare-bones and non-functional chat app that uses Jetpack compose.

Prerequisites

  • Basic knowledge of Android development
  • Basic knowledge of notifications

What you'll build

An extended JetChat app that does the following:

  • Surfaces notifications that represent conversations in the reserved conversation section of the notification drawer.
  • References share targets in these notifications that let you share into your app's conversations.
  • Enforces best practices for creation of these objects to take advantage of the default experiences provided by the system that enhance your app.

What you'll learn

  • How to surface conversation-related notifications in the reserved conversation section of the notification drawer.
  • How to understand the various experiences enabled by the Messaging and People APIs.

What you'll need

  • Git
  • Android Studio
  • A GitHub account

2. Get set up

The starting point is based on the JetChat app. The starter code extends the JetChat app to better showcase the Messaging and People APIs.

Get the starter code

To get the starter code for this codelab, follow these steps:

  1. From your command line, clone the following GitHub repository:
git clone –branch starter-code \
https://github.com/android/people-messaging-codelab.git
  1. Open the project in Android Studio and then click a1bbb9d97659a043.png Run app. The Emulator pane appears and displays the app.

Explore the extended JetChat app

  1. In the app's Message #composers text box, enter a message and then tap Send.
  2. Navigate away from the app. After a few seconds, you receive a push notification that contains a response from somebody in the chat.

3. Create conversation notifications

Android 11 introduced APIs that allow chat-related notifications to appear in a designated section in the notification drawer, which is strictly for conversations.

The notification drawer that appears when swipe down from the status bar

The notification must be of the Notification.MessagingStyle class and reference a long-lived sharing shortcut. In this section, you learn how to fulfill these API requirements to surface these notifications that represent conversations in the conversation section.

To make notifications of the NotificationCompat.MessagingStyle class, follow these steps:

  1. In the Project tab of Android Studio, click app > java > com.example.compose.jetchat > conversation and then double-click ConversationFragment.
  2. In the ConversationFragment.kt file, find the ConversationFragment class, and then find the createNotification function's Notification code block where the notification is created.
  3. Replace the setContentText method with a setStyle method that sets the style of the notification to the NotificationCompat.MessagingStyle class. This helper class adds the message that was set with the setContextText method with additional context relevant to the message, such as the time that it was sent and the person who sent it.

ConversationFragment.kt

private fun createNotification(
   notificationId: Int,
   message: Message,
   person: Person,
   shortcut: ShortcutInfoCompat,
   time: Long
): Notification? {
    ...
    .setStyle(NotificationCompat.MessagingStyle(person).addMessage(
                      NotificationCompat.MessagingStyle.Message(
                          message.content,
                          time,
                          person
                      )
    )
    )
    ...
    .build()
}

Run the app

  1. Run the app.
  2. In the app's Message #composers text box, enter a message and then tap Send.
  3. Navigate away from the app. You receive a push notification again, but it's styled differently. It includes an avatar and distinct style for the message. However, there's more work to do before your notifications appear where they should.

4. Create share targets for conversations

You need to reference a sharing shortcut or share target in the notification. Share targets are defined in the shortcuts.xml file and are the entry points to handling shortcuts that are programmatically defined. The shortcuts that you create represent the conversations in the app, and let you share content in your conversations.

Define share targets

  1. In the Project tab, right-click the res directory and then select New > Directory.
  2. In the text box, enter xml and then press Enter (or return on macOS).
  3. Right-click the xml directory and then select File.
  4. In the text box, enter shortcuts.xml and then press Enter (or return on macOS).
  5. In the shortcuts.xml file, declare the share target that handles the sharing of data of text/plain type:

shortcuts.xml

<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
  <share-target android:targetClass="com.example.compose.jetchat.NavActivity">
   <data android:mimeType="text/plain" />
   <category android:name="com.example.compose.jetchat.share.TEXT_SHARE_TARGET" />
 </share-target>
</shortcuts>
  1. In the Project tab, click manifests and then double-click AndroidManifest.xml.
  2. In the AndroidManifest.xml file, define the shortcuts.xml file:

AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.compose.jetchat">

   <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/Theme.Jetchat.NoActionBar">
...
 <meta-data android:name="android.app.shortcuts"
            android:resource="@xml/shortcuts" />

    </application>
</manifest>
  1. In the AndroidManifest.xml file's activity component, define the intent filter that contains the sharing logic:

AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
   package="com.example.compose.jetchat">

   ...
       <activity
           ...
           <intent-filter>
               <action android:name="android.intent.action.SEND" />
               <category android:name="android.intent.category.DEFAULT" />
               <data android:mimeType="text/plain" />
           </intent-filter>
...

Define shortcuts

For every notification, you need to associate the relevant shortcut. You define only one unique shortcut per conversation because the unique shortcut represents the one contact with which to share.

To generate a shortcut, follow these steps:

  1. In the Project tab, click app > java > com.example.compose.jetchat > conversation > util and then double-click ConversationUtil.
  2. In the ConversationUtil.kt file, add a generateShortcut function:

ConversationUtil.kt

import android.content.Intent
import androidx.core.content.pm.ShortcutInfoCompat
import com.example.compose.jetchat.NavActivity

class ConversationUtil {

   companion object {
...
fun generateShortcut(context: Context, shortcutId: String): ShortcutInfoCompat {
   return ShortcutInfoCompat.Builder(context, shortcutId)
   .setCategories(setOf(CATEGORY_SHARE))
   .setLongLived(true)
   .setShortLabel(shortcutId)
   .setLongLabel(shortcutId)
   .setIntent(
       Intent(context, NavActivity::class.java)
           .setAction(Intent.ACTION_VIEW)
   )
   .build()
}

This function contains the setPerson and setLongLived methods required for conversation. The person is the contact associated with the shortcut, and setting long-lived to a true value ensures that this shortcut is cached by the system and surfaced in various surfaces in the UI.

Reference the shortcut in the notification

You need to reference the sharing shortcut in the notification. However, you must create the shortcut before you push the notification.

To do so, follow these steps:

  1. In the ConversationFragment.kt file, find the ConversationFragment class.
  2. Before the call to the notification variable, create a shortcut variable that references the shortcut generated from ConversationUtil.generateShortcut.
  3. In the notification variable's createNotification method, replace null with the shortcut variable as a parameter.

ConversationFragment.kt

private fun simulateResponseAsANotification() {
   ...
   if (message.author != "me") {
       ...
       val shortcut = ConversationUtil.generateShortcut(context!!, message.author)
       val notification = createNotification(notificationId, message, person, shortcut, time)
       ...
   }
}
  1. In the createNotification method, add the NotificationCompat.Builder#setShortcutInfo method, and then pass in the shortcut variable as a parameter.

ConversationFragment.kt

private fun createNotification(
  notificatoinIf: Int,
  messagin: Message,
  person: Person,
  shortcut: ShortcutInfoCompat?,
  time: Long
): Notification {
...
return NotificationCompat.Builder(context!!,  ConversationUtil.CHANNEL_MESSAGES)
   ...
   .setShortcutInfo(shortcut)
   .build()
}

Publish the shortcut

  • To publish the shortcut, in the simulateResponseAsANotification function before the notificationManager.notify method, call the pushDynamicShortcut method:

ConversationFragment.kt

import androidx.core.content.pm.ShortcutManagerCompat

...private fun simulateResponseAsANotification() {
   ...
   if (message.author != "me") {
       ...
       ShortcutManagerCompat.pushDynamicShortcut(context!!, shortcut)
       ...
   }
}

Run the app

  1. Run the app.
  2. In the app's Message #composers text box, enter a message and then tap Send.
  3. Navigate away from the app. You receive a push notification again, but it's more distinctly styled as a conversation-related notification. The avatar icon is more pronounced and integrates the app icon. The sender, time, and text are also more streamlined.

5. Optional: Enable bubbles

Bubbles were introduced in Android 9, and improved and repurposed for usage in the context of conversations in Android 11. Bubbles are circular overlays that are avatars to your conversations. They appear in the app launcher, and let you easily respond to conversations in an expanded bubble. Even when implemented, bubbles are optional depending on the user's preference.

To enable bubbles, follow these steps:

  1. In the AndroidManifest.xml file, add the allowEmbedded and resizeableActivity attributes, and then set each to a true value:

AndroidManifest.xml

<activity
  ...
  android:allowEmbedded="true"
  android:resizeableActivity="true"
  ...
</activity>
  1. In the ConversationUtil.kt file's ConversationUtil class, add the bubble metadata:

ConversationUtil.kt

import androidx.core.app.NotificationCompat
import androidx.core.graphics.drawable.IconCompat


fun createBubbleMetadata(context: Context, icon: IconCompat): NotificationCompat.BubbleMetadata {
        // Create bubble intent
        val target = Intent(context, NavActivity::class.java)
        val bubbleIntent = PendingIntent.getActivity(context, REQUEST_BUBBLE, target, flagUpdateCurrent(mutable = true))

        // Create bubble metadata
        return NotificationCompat.BubbleMetadata.Builder(bubbleIntent, icon)
            .setDesiredHeight(400)
            .setSuppressNotification(true)
            .build()
    }
  1. In the ConversationFragment.kt file, create and reference the bubble metadata on the notification:

ConversationFragment.kt

private fun createNotification(
  notificatoinIf: Int,
  messagin: Message,
  person: Person,
  shortcut: ShortcutInfoCompat?,
  time: Long
): Notification {
...
// Reference the bubble metadata in the notification.
  return NotificationCompat.Builder(context!!,     ConversationUtil.CHANNEL_MESSAGES)
    ...
     .setBubbleMetadata(ConversationUtil.createBubbleMetadata(context!!, person.icon!!))
...
    .build()
}

Run the app

  1. Run the app.
  2. In the app's Message #composers text box, enter a message and then tap Send.
  3. Navigate away from the app. After a few seconds, you receive a notification from the chat in the form of a bubble.
  4. Tap the bubble. The conversation opens from the bubble.

A conversation bubble

6. Optional: Share a link

You declared share targets and referenced them in your notifications, which also enabled the surfacing of your contact in the Sharesheet, a bottom-up component that appears when an ACTION intent is sent. Share targets appear at the top of the Sharesheet, and let you share rich content in your conversations.

To invoke the Sharesheet, follow these steps:

  1. On your device, open Google Chrome, and then navigate to a web page of your choice, such as developer.android.com.
  2. If necessary, click 2fdbaccda71bc5f0.png More vert.
  3. Click 771b0be21764f6b6.png Share. The Sharesheet appears at the bottom of the screen.

The Sharesheet

  1. If possible, click 468248e6b8a84bb3.png JetChat. The URL is shared in the chat.
  2. If you don't see 468248e6b8a84bb3.png JetChat, click 145399af71577431.png More to invoke the system sharesheet, and then swipe up on the ShareSheet and click 468248e6b8a84bb3.png JetChat. The URL is shared into the chat.

This is a simple example. There are richer content types to share. For more information, see Retrieving simple data from other apps.

7. Congratulations

Congratulations! Now you know how to add chat-related features to an Android app with the Messaging and People APIs. Happy messaging!

Learn more