バブルを使用してユーザーが会話に参加できるようにする

バブルを使用すると、ユーザーは会話を簡単に確認したり、参加したりできます。

図 1. チャットのふきだし。

バブルは通知システムに組み込まれています。バブルは他のアプリ コンテンツの上にフロート表示され、ユーザーがどこにいてもフォローできます。バブルを開くと、アプリの機能や情報が表示され、使用していないときは閉じることができます。

デバイスがロックされている場合、または常に表示状態のディスプレイが有効な場合、通常の通知と同様にバブルが表示されます。

バブルは、オプトアウト式の機能です。アプリが最初のバブルを表示すると、権限ダイアログに次の 2 つの選択肢が表示されます。

  • アプリからのすべてのバブルをブロックします。通知はブロックされませんが、バブルとして表示されることはありません。
  • アプリからのすべてのバブルを許可します。BubbleMetaData で送信された通知はすべてバブルとして表示されます。

バブル API

バブルは通知 API を介して作成されるため、通常どおり通知を送信します。通知をバブルとして表示するには、通知に追加のデータを追加します。

バブルの展開ビューは、選択したアクティビティから作成されます。バブルとして適切に表示されるようにアクティビティを設定します。アクティビティはサイズ変更が可能で、埋め込まれている必要があります。これらの要件のいずれかがない場合は、通知として表示されます。

シンプルなバブルを実装する方法を次のコードに示します。

<activity
  android:name=".bubbles.BubbleActivity"
  android:theme="@style/AppTheme.NoActionBar"
  android:label="@string/title_activity_bubble"
  android:allowEmbedded="true"
  android:resizeableActivity="true"
/>

連絡先が異なる複数のチャットの会話など、同じタイプのバブルが複数表示される場合、アクティビティは複数のインスタンスを起動できる必要があります。Android 10 以前を搭載しているデバイスでは、documentLaunchMode を明示的に "always" に設定しない限り、通知はバブルとして表示されません。Android 11 以降では、すべての会話の documentLaunchMode が自動的に "always" に設定されるため、この値を明示的に設定する必要はありません。

バブルを送信する手順は次のとおりです。

  1. 通常どおりに通知を作成します。
  2. BubbleMetadata.Builder(PendingIntent, Icon) または BubbleMetadata.Builder(String) を呼び出して、BubbleMetadata オブジェクトを作成します。
  3. メタデータを通知に追加するには、setBubbleMetadata() を使用します。
  4. Android 11 以降をターゲットとする場合は、バブルのメタデータまたは通知が共有ショートカットを参照していることを確認してください。

次の例はそれらの手順を示しています。

Kotlin

// Create a 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 a 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 a bubble metadata.
val bubbleData = Notification.BubbleMetadata.Builder(bubbleIntent,
            Icon.createWithResource(context, R.drawable.icon))
    .setDesiredHeight(600)
    .build()

// Create a notification, referencing the sharing shortcut.
val builder = Notification.Builder(context, CHANNEL_ID)
    .setContentIntent(contentIntent)
    .setSmallIcon(smallIcon)
    .setBubbleMetadata(bubbleData)
    .setShortcutId(shortcutId)
    .addPerson(chatPartner)

Java

// Create a 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 a 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 a bubble metadata.
Notification.BubbleMetadata bubbleData =
    new Notification.BubbleMetadata.Builder(bubbleIntent,
            Icon.createWithResource(context, R.drawable.icon))
        .setDesiredHeight(600)
        .build();

// Create a notification, referencing the sharing shortcut.
Notification.Builder builder =
    new Notification.Builder(mContext, CHANNEL_ID)
        .setContentIntent(contentIntent)
        .setSmallIcon(smallIcon)
        .setBubbleMetadata(bubbleData)
        .setShortcutId(shortcutId)
        .addPerson(chatPartner);

バブル送信時にアプリがフォアグラウンドにある場合、ユーザーがバブルまたはアプリからの通知をブロックしない限り、重要度は無視され、バブルは常に表示されます。

展開したバブルを作成する

バブルが自動的に展開された状態で表示されるように設定できます。この機能は、ボタンをタップして新しいチャットを開始するなど、バブルが表示されるアクションをユーザーが行う場合にのみ使用することをおすすめします。この場合、バブルの作成時に送信される最初の通知を抑制することも理にかなっています。

これらの動作を有効にするフラグを設定するには、setAutoExpandBubble()setSuppressNotification() のメソッドを使用できます。

次の例は、展開された状態でバブルが自動的に表示されるよう構成する方法を示しています。

Kotlin

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

Java

Notification.BubbleMetadata bubbleData =
    new Notification.BubbleMetadata.Builder()
        .setDesiredHeight(600)
        .setIntent(bubbleIntent)
        .setAutoExpandBubble(true)
        .setSuppressNotification(true)
        .build();

バブル コンテンツのライフサイクル

バブルが展開されると、コンテンツ アクティビティは通常のプロセス ライフサイクルを通過します。つまり、アプリがまだフォアグラウンド プロセスになっていなければ、フォアグラウンド プロセスになります。

バブルが折りたたまれるか閉じられると、アクティビティは破棄されます。これにより、アプリで他のフォアグラウンド コンポーネントが実行されているかどうかに応じて、プロセスがキャッシュされ、後で強制終了される可能性があります。

バブルが表示されるタイミング

ユーザーの混乱を減らすために、バブルは特定の状況でのみ表示されます。

Android 11 以降をターゲットとするアプリの場合、会話の要件を満たしていない限り、通知はバブルとして表示されません。Android 10 以前をターゲットとするアプリの場合、次の条件の 1 つ以上が満たされた場合にのみ、通知がバブルとして表示されます。

上記の条件がいずれも満たされない場合、バブルではなく通知が表示されます。

おすすめの方法

  • 重要な場合にのみ、通知をバブルとして送信します。たとえば、進行中の通信の一部である場合や、ユーザーがコンテンツのバブルを明示的にリクエストした場合などです。バブルは画面内のスペースを利用し、他のアプリ コンテンツを覆います。
  • バブル通知が通常の通知としても機能することを確認します。ユーザーがバブルを無効にすると、バブル通知が通常の通知として表示されます。
  • 機能をできる限り具体的かつ軽量に保ちます。アクティビティやダイアログなど、バブルから起動するプロセスは、バブル コンテナ内に表示されます。つまり、バブルにはタスクスタックを含めることができます。バブル内に多数の機能やナビゲーションが含まれていると、事態が複雑になる可能性があります。
  • バブル アクティビティで onBackPressed をオーバーライドするときに、super.onBackPressed を呼び出します。そうしないと、バブルが正しく動作しない可能性があります。

折りたたまれたバブルが更新されたメッセージを受け取ると、バブルには未読メッセージを示すバッジアイコンが表示されます。ユーザーが関連付けられたアプリでメッセージを開いたら、次の手順を行います。

サンプルアプリ

People サンプルアプリは、バブルを使用するシンプルな会話アプリです。このアプリはデモを目的として chatbot を使用します。実際のアプリケーションでは、バブルは bot ではなく、人間がメッセージに使用する必要があります。