Bubbles & Conversations in Android 11: Getting Started
Learn how to use Bubbles in Android to add notifications and create conversational shortcuts for Direct Share. By Jenn Bailey.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Bubbles & Conversations in Android 11: Getting Started
20 mins
- Getting Started
- Showing Notifications in the Conversations Section
- Adding a Person to the Conversation
- Understanding Fallback Behavior
- Creating Conversation Shortcuts
- Dynamically Updating the Shortcuts
- Testing the Shortcuts
- Allowing Direct Sharing Through Shortcuts
- Notification Bubbles
- Adding BubbleMetadata
- Making Your Activities Bubble
- Detecting Bubble User Permissions
- Background Bubbles
- Where to Go From Here?
The most important thing an Android phone does is connect people. Wouldn’t it be nice if you could feel like the people you want to talk to are right there with you?
Android 11 has spectacular new features to help developers and users do just that. These features allow quick access to conversations with conversation shortcuts and adds a new Conversations section in the notification shade. Bubbles also gives you sophisticated sharing and ranking capabilities, as well as improved multitasking.
These changes reflect the goal of the platform: It will continue to evolve to focus on people and conversations as part of a multi-year Android initiative.
In this tutorial, you’ll learn how to add these features to an app called Bubble Affirmations, which simulates chats with inspirational characters who provide a quick fix of ongoing encouragement at your fingertips.
In the process, you’ll learn how to:
- Make notifications appear in the Conversations section
- Create conversation shortcuts
- Allow direct share through the shortcuts
- Add metadata to bubbles
- Detect user permission for bubbles
Perhaps you know Android but are unfamiliar with Kotlin. If that’s the case, take a look at Kotlin For Android: An Introduction.
Just in case you’d like a quick primer on notifications, take a peek at Android Notifications Tutorial: Getting Started.
Perhaps you know Android but are unfamiliar with Kotlin. If that’s the case, take a look at Kotlin For Android: An Introduction.
Just in case you’d like a quick primer on notifications, take a peek at Android Notifications Tutorial: Getting Started.
Now, it’s time to dive in!
Getting Started
Download the project materials by using the Download Materials button at the top or bottom of this tutorial. Open the Starter project in Android Studio. After the project finishes loading, build and run.
Select a category of affirmations to see a random quote from that category:
Tap the bell icon in the top-right corner, and your selected quote will appear as a notification:
This notification could be more inspiring. In the next step, you’ll promote it to the Conversations section of the drawer.
Showing Notifications in the Conversations Section
Many phones have a reserved section at the top of the notification shade for real-time conversations. Notifications that appear in this section have a stronger visual emphasis on the avatar, highlighting who the conversation is with. Long-pressing notifications in this area shows you conversation-specific actions you can take.
To appear in this section, the notification must use MessagingStyle
and associate the message with a Person. You’ll see how to do this next.
Adding a Person to the Conversation
Open NotificationHelper.kt and add the method below inside NotificationHelper
:
private fun createPerson(icon: Icon, category: Category): Person {
return Person.Builder()
.setName(category.name)
.setIcon(icon)
.build()
}
This code generates a person to associate with the notification, making it a Person Notification.
Now, in showNotification
, add the following above the line of code that creates the notification:
val person = createPerson(icon, quoteAndCategory.category)
The code above creates the person
. Now, update the line of code that creates the notification to:
val notification = createNotification(quoteAndCategory, icon, person)
This passes the person
to createNotification
.
Then, replace createNotification
with:
private fun createNotification(
quoteAndCategory: QuoteAndCategory,
icon: Icon,
person: Person
): Notification.Builder {
return Notification.Builder(context, CHANNEL_QUOTES)
// 1
.setContentTitle(quoteAndCategory.category.name)
.setSmallIcon(icon)
// 2
.setShortcutId(quoteAndCategory.category.shortcutId)
.setLocusId(LocusId(quoteAndCategory.category.shortcutId))
.setCategory(Notification.CATEGORY_MESSAGE)
// 3
.setStyle(Notification.MessagingStyle(person)
.setGroupConversation(false)
.addMessage(quoteAndCategory.quote.quoteText,
currentTimeMillis(), person)
)
// 4
.setShowWhen(true)
.setContentIntent(createPendingMainIntent(
REQUEST_CONTENT,
quoteAndCategory.category)
)
}
createNotification
configures and returns Notification.Builder to send the notification. Here’s what’s going on inside:
- First, you set the title and icon for the notification.
- Then you use
setShortcutId
orsetShortcutInfo
to associate the notification with a long-lived dynamic or cached sharing shortcut when targeting Android 11. You also set theLocusId
to improve ranking accuracy. - In Android 11, a conversation notification must use
MessagingStyle
. - Finally, you include the time of the notification and set an intent to open when the user taps the notification.
For better ranking, a messaging app can include a URI to a contact.
LocusId
helps the on-device intelligence figure out which conversations interest the user most. Ranking is based on how recent and how frequent the conversations are.
For better ranking, a messaging app can include a URI to a contact.
Understanding Fallback Behavior
If you want a conversation to appear in the Conversations section in Android 11, you must associate it with a valid, long-lived, dynamic or cached sharing shortcut and use MessagingStyle
. The user can demote the conversation by altering the notification channel settings.
Apps that target Android 10 can make messages appear in the notification space, but the requirements are different. If the app uses MessagingStyle
, it isn’t necessary to provide a shortcut in Android 10. However, if you don’t provide a shortcut, users won’t be able to see conversation-specific functions inline by long-pressing the notification.
If you set the category to CATEGORY_MESSAGE
and the platform recognizes the app as a messaging app, it will still show in the Conversations section, but it will be in the pre-Android 11 style with no conversation-specific functions.
Now that you’ve associated the notification with a person
, build and run:
The notification looks better now, and the sender’s avatar is more visible. For the notification to show up in the conversation area, however, you have to associate it with a valid shortcut. You’ll create the shortcuts next.
Creating Conversation Shortcuts
When targeting Android 11 or higher, you have to give a shortcut to any notification you want to show in the conversation space. Shortcuts are a handy way for a user to jump right into a conversation. Be sure to use AdaptiveIconDrawable
for your shortcut icons. Otherwise, the avatar might not look as intended.
Add the following function inside NotificationHelper.kt:
private fun createShortcutIcon(category: Category): Icon {
return Icon.createWithAdaptiveBitmap(
context.resources.assets.open(
"${category.name.toLowerCase(Locale.ROOT)}.png").use {
input ->
BitmapFactory.decodeStream(input)
})
}
This code provides an adaptive bitmap so you can add the shortcuts. To do this, first add a new Android resource file to res called shortcuts.xml. Type shortcuts as the root element and select XML as the resource type and xml as the directory name.
In shortcuts.xml, inside the shortcut
tag, add the following code:
<share-target android:targetClass=
"com.raywenderlich.android.bubblesaffirmations.ui.main.MainActivity">
<data android:mimeType="text/plain" />
<category android:name=
"com.example.android.bubbles.category.TEXT_SHARE_TARGET" />
</share-target>
The share-target
element holds information about which class will handle the intent, the type of data it can accept from sharing and the category that the direct share target uses.
Next, open AndroidManifest.xml and add the following code above the closing activity
tag for MainActivity
:
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/shortcuts" />
The code above associates MainActivity
with the dynamic shortcut’s share-target
in shortcuts.xml.
Next, open NotificationHelper.kt and add the following inside NotificationHelper
:
private fun createDynamicShortcutIntent(category: Category): Intent =
Intent(context, MainActivity::class.java)
.setAction(Intent.ACTION_VIEW)
.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
.setData(
Uri.parse(
"https://raywenderlich.android.bubblesaffirmations.com"
+ "/quote/${category.categoryId}"
)
)
createDynamicShortcutIntent
creates the intent to launch from this shortcut. It uses a URI that passes categoryId
to link directly to a specific conversation in the app via the shortcut.
Still in NotificationHelper.kt, add:
private fun createShortcuts() = categories.map { category ->
ShortcutInfo.Builder(context, category.shortcutId)
// 1
.setLocusId(LocusId(category.shortcutId))
.setActivity(ComponentName(context, MainActivity::class.java))
.setShortLabel(category.name)
.setIcon(createShortcutIcon(category))
// 2
.setLongLived(true)
// 3
.setCategories(
setOf("com.example.android.bubbles.category.TEXT_SHARE_TARGET")
)
.setIntent(createDynamicShortcutIntent(category))
// 4
.setPerson(createPerson(createIcon(category), category)
).build()
}
Here’s what the code above does:
-
LocusId
helps the system accurately rank the conversation based on app usage. - Conversation shortcuts must be long-lived. If the conversation no longer exists, the app can delete the shortcut with
removeLongLivedShortcuts
. Don’t remove shortcuts unless absolutely necessary — for example, when the user blocks a contact. - Sets the category to the
share-target
defined in shortcuts.xml. Categories describe what type of data the user can share to the shortcut. - Creates a person with an avatar and associates the person with the shortcut. Conversational shortcuts always have an associated person object.