Bubbles make it easy for users to see and participate in conversations.
Bubbles are built into the Notification system. They float on top of other app content and follow the user wherever they go. Bubbles can be expanded to reveal app functionality and information, and can be collapsed when not being used.
When the device is locked or the always-on-display is active, bubbles appear just as a notification normally would.
Bubbles are an opt-out feature. When an app presents its first bubble, a permission dialog is shown that offers two choices:
- Block all bubbles from your app - notifications are not blocked, but they will never appear as bubbles
- Allow all bubbles from your app - all notifications sent with
BubbleMetaDatawill appear as bubbles
The Bubble API
Bubbles are created via the Notification API, so you send your notification as normal. If you want your notification to display as a bubble, you need to attach some extra data to it.
The expanded view of a bubble is created from an activity that you choose. The Activity needs to be configured to display properly as a bubble. The activity must be resizeable and embedded. If it lacks either of these requirements it displays as a notification instead.
The following code demonstrates how to implement a simple bubble:
<activity android:name=".bubbles.BubbleActivity" android:theme="@style/AppTheme.NoActionBar" android:label="@string/title_activity_bubble" android:allowEmbedded="true" android:resizeableActivity="true" />
If your app shows
multiple bubbles of the same type, like multiple chat conversations with
different contacts, the activity must be able to launch
multiple instances. On devices running Android 10, notifications are
not shown as bubbles unless you explicitly set
"always". Beginning with Android 11, you do not need to explicitly
set this value, as the system automatically sets all conversations'
To send a bubble, follow these steps:
- Create a notification as you normally would.
BubbleMetadata.Builder(String)to create a BubbleMetadata object.
setBubbleMetadata()to add the metadata to the notification.
- If targeting Android 11 or higher, the bubble metadata or notification must reference a sharing shortcut.
// Create bubble intent val target = Intent(context, BubbleActivity::class.java) val bubbleIntent = PendingIntent.getActivity(context, 0, target, 0 /* flags */) val category = "com.example.category.IMG_SHARE_TARGET" val chatPartner = Person.Builder() .setName("Chat partner") .setImportant(true) .build() // Create sharing shortcut val shortcutId = generateShortcutId() val shortcut = ShortcutInfo.Builder(mContext, shortcutId) .setCategories(setOf(category)) .setIntent(Intent(Intent.ACTION_DEFAULT)) .setLongLived(true) .setShortLabel(chatPartner.name) .build() // Create bubble metadata val bubbleData = Notification.BubbleMetadata.Builder(bubbleIntent, Icon.createWithResource(context, R.drawable.icon)) .setDesiredHeight(600) .build() // Create notification, referencing the sharing shortcut val builder = Notification.Builder(context, CHANNEL_ID) .setContentIntent(contentIntent) .setSmallIcon(smallIcon) .setBubbleMetadata(bubbleData) .setShortcutId(shortcutId) .addPerson(chatPartner)
// Create bubble intent Intent target = new Intent(mContext, BubbleActivity.class); PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, target, 0 /* flags */); private val CATEGORY_TEXT_SHARE_TARGET = "com.example.category.IMG_SHARE_TARGET" Person chatPartner = new Person.Builder() .setName("Chat partner") .setImportant(true) .build(); // Create sharing shortcut private String shortcutId = generateShortcutId(); ShortcutInfo shortcut = new ShortcutInfo.Builder(mContext, shortcutId) .setCategories(Collections.singleton(CATEGORY_TEXT_SHARE_TARGET)) .setIntent(Intent(Intent.ACTION_DEFAULT)) .setLongLived(true) .setShortLabel(chatPartner.getName()) .build(); // Create bubble metadata Notification.BubbleMetadata bubbleData = new Notification.BubbleMetadata.Builder(bubbleIntent, Icon.createWithResource(context, R.drawable.icon)) .setDesiredHeight(600) .build(); // Create notification, referencing the sharing shortcut Notification.Builder builder = new Notification.Builder(mContext, CHANNEL_ID) .setContentIntent(contentIntent) .setSmallIcon(smallIcon) .setBubbleMetadata(bubbleData) .setShortcutId(shortcutId) .addPerson(chatPartner);
If your app is in the foreground when a bubble is sent, importance is ignored and your bubble will always be shown (unless the user has blocked bubbles or notifications from your app).
Creating an expanded bubble
You can configure your bubble to present it in expanded state automatically. We recommend only using this functionality if the user performs an action that would result in a bubble, like tapping on a button to start a new chat. In this case, it also makes sense to suppress the initial notification sent when a bubble is created.
There are methods you can use to set flags that enable these behaviours:
val bubbleMetadata = Notification.BubbleMetadata.Builder() .setDesiredHeight(600) .setIntent(bubbleIntent) .setAutoExpandBubble(true) .setSuppressNotification(true) .build()
Notification.BubbleMetadata bubbleData = new Notification.BubbleMetadata.Builder() .setDesiredHeight(600) .setIntent(bubbleIntent) .setAutoExpandBubble(true) .setSuppressNotification(true) .build();
Bubble content lifecycle
When a bubble is expanded, the content activity goes through the normal process lifecycle, resulting in the application becoming a foreground process (if not already).
When the bubble is collapsed or dismissed the activity will be destroyed. This may result in the process being cached and later killed, depending on whether the app has any other foreground components running.
When bubbles appear
To reduce the number of interruptions for the user, bubbles only appear under certain circumstances.
If an app targets Android 11 or higher, a notification doesn't appear as a bubble unless it meets the conversation requirements. If an app targets Android 10, the notification appears as a bubble only if one or more of these conditions are met:
- The notification uses MessagingStyle, and has a Person added.
- The notification is from a call to Service.startForeground, has a category of CATEGORY_CALL, and has a Person added.
- The app is in the foreground when the notification is sent.
If none of those conditions are met, the notification is shown instead of a bubble.
- Bubbles take up screen real estate and cover other app content. You should only send a notification as a bubble if it is important enough such as ongoing communications, or if the user has explicitly requested a bubble for some content.
- Note that the bubble can be disabled by the user. In that case, a bubble notification is shown as a normal notification. You should always make sure your bubble notification works as a normal notification as well.
- Processes that are launched from a bubble (such as activities and dialogs) appear within the bubble container. This means a bubble can have a task stack. Things can get complicated if there is a lot of functionality or navigation within your bubble. We recommend keeping the functionality as specific and light-weight as possible.
- Make sure to call super.onBackPressed when overriding onBackPressed in the Bubble activity, otherwise your bubble may not behave correctly.
- When a collapsed bubble receives an updated message, the bubble shows a badge icon
to indicate an unread message. When the user opens the message in the associated app,
follow these steps:
BubbleMetadatato suppress the notification. Call
BubbleMetadata.Builder.setSupressNotification(). This removes the badge icon to indicate the user acted on the message.
Notification.Builder.setOnlyAlertOnce()to true to suppress the sound or vibration that accompanies the
- Update the
The People sample app is a simple conversation app that uses bubbles. For demonstration purposes, this app uses chat bots. In real-world applications, bubbles should only be used for messages by humans, not by bots.