Notification bubbles make it easier for users to see and participate in
conversations.
**Figure 1.** A chat bubble.

They float on top of other app content and users can expand bubbles to reveal
and interact with the app content, and they can collapse them when they're not
using them.

When the device is locked, or the always-on-display is active, bubbles appear as
notifications normally do.

Notification bubbles are enabled by the user. They can do this by tapping on
the bubble button on notifications that support bubbles. This allows that
specific chat to always bubble. In settings, users can adjust which chats
they've bubbled or modify the settings for the overall app.

Users can do the following:

- Block all notification bubbles from your app. Notifications aren't blocked, but they never appear as bubbles.
- Allow selected notification bubbles from your app. Notifications bubbled using the bubble button are "selected".
- Allow all notification bubbles from your app. All notifications sent with `BubbleMetadata` appear as bubbles.

> [!NOTE]
> **Note:** As of Android 17, bubbles has been formalized as a proper windowing mode, like split screen. This allows users to add any app to the bubble UI along with notification bubbles.

## The Notification Bubble API

Notification bubbles are created using the notification API. If you want your
notification to appear as a bubble, attach extra data to it.

The expanded view of the bubble is created from an activity that you choose.
Configure the activity to appear properly as a bubble. The activity must be
[resizeable](https://developer.android.com/guide/topics/manifest/activity-element.md.txt#resizeableActivity) and [embedded](https://developer.android.com/guide/topics/manifest/activity-element.md.txt#embedded). If it lacks either of these requirements, the
system displays it as a notification instead.

The following code demonstrates how to implement a bubble:

```xml
<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 and lower,
notifications aren't shown as bubbles unless you explicitly set
[`documentLaunchMode`](https://developer.android.com/guide/topics/manifest/activity-element.md.txt#dlmode) to
`"always"`. Beginning with Android 11, you don't need to explicitly
set this value, as the system automatically sets all conversations'
`documentLaunchMode` to `"always"`.

To send a notification bubble, follow these steps:

1. [Create a notification](https://developer.android.com/develop/ui/compose/notifications/create-notification.md.txt) as you normally do.
2. Call [`BubbleMetadata.Builder(PendingIntent, Icon)`](https://developer.android.com/reference/android/app/Notification.BubbleMetadata.Builder.md.txt#Builder(android.app.PendingIntent,%20android.graphics.drawable.Icon)) or [`BubbleMetadata.Builder(String)`](https://developer.android.com/reference/android/app/Notification.BubbleMetadata.Builder.md.txt#Builder(java.lang.String)) to create a `BubbleMetadata` object.
3. Use [`setBubbleMetadata()`](https://developer.android.com/reference/android/app/Notification.Builder.md.txt#setBubbleMetadata(android.app.Notification.BubbleMetadata)) to add the metadata to the notification.
4. If targeting Android 11 (API level 30) or higher, make sure the bubble metadata or notification references a sharing shortcut.
5. Modify your app to **not** cancel notifications that appear as bubbles. Canceling a notification removes the bubble from the screen. Opening a bubble automatically hides the notification associated with it.

These steps are shown in the following example:


```kotlin
// Create a bubble intent.
val target = Intent(context, BubbleActivity::class.java)
val bubbleIntent =
    PendingIntent.getActivity(context, 0, target, PendingIntent.FLAG_IMMUTABLE /* flags */)
val category = "com.example.category.IMG_SHARE_TARGET"

val chatPartner = Person.Builder()
    .setName("Chat partner")
    .setImportant(true)
    .build()

// Create a sharing shortcut.
val shortcutId = generateShortcutId()
val shortcut =
    ShortcutInfoCompat.Builder(context, shortcutId)
        .setCategories(setOf(category))
        .setIntent(Intent(Intent.ACTION_DEFAULT))
        .setLongLived(true)
        .setShortLabel("Chat partner name")
        .build()
// Publish the shortcut, otherwise the bubble metadata will not apply.
ShortcutManagerCompat.pushDynamicShortcut(context, shortcut)

// Create a bubble metadata.
val bubbleData = NotificationCompat.BubbleMetadata.Builder(bubbleIntent,
    IconCompat.createWithResource(context, R.drawable.ic_logo))
    .setDesiredHeight(600)
    .build()

// Create a notification, referencing the sharing shortcut.
val builder = NotificationCompat.Builder(context, CHANNEL_ID)
    .setContentIntent(contentIntent)
    .setSmallIcon(R.drawable.chat)
    .setBubbleMetadata(bubbleData)
    .setShortcutId(shortcutId)
    .addPerson(chatPartner)
```

<br />

> [!NOTE]
> **Note:** The first time you send the notification to display a bubble, make sure it's in a notification channel with [`IMPORTANCE_MIN`](https://developer.android.com/reference/android/app/NotificationManager.md.txt#IMPORTANCE_MIN) or higher.

If your app is in the foreground when a bubble is sent, importance is ignored
and your bubble is always shown, unless the user blocks bubbles or notifications
from your app.

### Create an expanded bubble

You can configure your bubble to present it in expanded state automatically. We
recommend only using this feature if the user performs an action that
results in a bubble, like tapping 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 behaviors:
[`setAutoExpandBubble()`](https://developer.android.com/reference/android/app/Notification.BubbleMetadata.Builder.md.txt#setAutoExpandBubble(boolean))
and
[`setSuppressNotification()`](https://developer.android.com/reference/android/app/Notification.BubbleMetadata.Builder.md.txt#setSuppressNotification(boolean)).

The following example shows how to configure a bubble to automatically present
in an expanded state:


```kotlin
val bubbleMetadata = NotificationCompat.BubbleMetadata.Builder()
    .setDesiredHeight(600)
    .setIntent(bubbleIntent)
    .setAutoExpandBubble(true)
    .setSuppressNotification(true)
    .build()
```

<br />

### Bubble content lifecycle

When a bubble is expanded, the content activity goes through the normal [process
lifecycle](https://developer.android.com/guide/components/activities/process-lifecycle), resulting in the
application becoming a foreground process, if it isn't already.

When the bubble is collapsed or dismissed, the activity is destroyed. This might
result in the process being cached and later killed, depending on whether the
app has other foreground components running.

## When bubbles appear

To reduce interruptions for the user, bubbles only appear under certain
circumstances.

If an app targets Android 11 (API level 30) or higher, a notification doesn't
appear as a bubble unless it meets the [conversation
requirements](https://developer.android.com/guide/topics/ui/conversations). If an app targets
Android 10 (API level 29) or lower, the notification appears as a bubble only if
one or more of the following conditions are met:

- The notification uses [`MessagingStyle`](https://developer.android.com/reference/android/app/Notification.MessagingStyle.md.txt) and has a [`Person`](https://developer.android.com/reference/android/app/Person.md.txt) added.
- The notification is from a call to [`Service.startForeground`](https://developer.android.com/reference/android/app/Service.md.txt#startForeground(int,%20android.app.Notification)), has a [`category`](https://developer.android.com/reference/android/app/Notification.Builder.md.txt#setCategory(java.lang.String)) of [`CATEGORY_CALL`](https://developer.android.com/reference/android/app/Notification.md.txt#CATEGORY_CALL), and has a `Person` added.
- The app is in the foreground when the notification is sent.

If none of these conditions are met, the notification is shown instead of a
bubble.

## Launching activities from bubbles

When a bubble launches a new activity, the new activity will either launch
within the same task and the same bubbled window, or in a new task
in fullscreen, collapsing the bubble that launched it.

To launch a new activity in the same task as the bubble:
1. Use the activity context when launching intents,
`activity.startActivity(intent)`, and
1. Don't set the `FLAG_ACTIVITY_NEW_TASK` flag on the intent.

Otherwise, the new activity is started in a new task and the bubble is
collapsed.

Keep in mind that a bubble represents a specific conversation, so activities
launched within the bubble should be related to that conversation. Additionally,
launching an activity within the bubble increases the task stack of the bubble
and could potentially complicate the user experience, specifically around
navigation.

## Best practices

- Send a notification as a bubble only if it is important, such as when it is part of an ongoing communication or if the user explicitly requests a bubble for content. Bubbles use screen real estate and cover other app content.
- Make sure your bubble notification also works as a normal notification. When the user disables the bubble, a bubble notification is shown as a normal notification.
- Use the [`BackHandler`](https://developer.android.com/reference/kotlin/androidx/activity/compose/package-summary.md.txt#backhandler) composable and tie its `enabled` parameter to your UI state so it only intercepts back presses when necessary. Once your handler disables itself, the bubble collapses.

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:

- [Update](https://developer.android.com/training/notify-user/build-notification#Updating) the `BubbleMetadata` to suppress the notification. Call [`BubbleMetadata.Builder.setSuppressNotification()`](https://developer.android.com/reference/android/app/Notification.BubbleMetadata.Builder.md.txt#setSuppressNotification(boolean)). This removes the badge icon to indicate that the user interacted with the message.
- Set [`Notification.Builder.setOnlyAlertOnce()`](https://developer.android.com/reference/android/app/Notification.Builder.md.txt#setOnlyAlertOnce(boolean)) to `true` to suppress the sound or vibration that accompanies the `BubbleMetadata` update.

## Sample app

The [SociaLite](https://github.com/android/socialite) sample app is a conversation app that uses
bubbles. For demonstration purposes, this app uses chatbots. In real-world
applications, use bubbles for messages by humans.