会話に通知バブルを使用する

通知バブルを使用すると、会話の内容を簡単に把握したり、会話に参加したりできます。

図 1. チャットバブル。

別のアプリ コンテンツの上にフローティング表示され、ユーザーはバブルを展開してアプリのコンテンツを表示したり、操作したりできます。バブルが不要になったら、折りたたむことが可能です。

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

通知バブルはユーザーが有効にします。バブルをサポートする通知のバブルボタンをタップすると、有効にできます。これにより、特定のチャットが常にバブル表示されるようになります。設定では、バブル表示するチャットを調整したり、アプリ全体の設定を変更したりできます。

ユーザーは次の操作を行うことができます。

  • アプリからの通知バブルをすべてブロックする。通知はブロックされませんが、バブルとして表示されることはありません。
  • アプリからの通知バブルを選択して許可する。バブルボタンを使用してバブル表示される通知は「選択」されます。
  • アプリからの通知バブルをすべて許可する。BubbleMetadata を指定して送信された通知は、すべてバブルとして表示されます。

通知バブル API

通知バブルは Notification API を使用して作成されます。通知をバブルとして表示するには、通知に追加データを付加します。

バブルの展開ビューは、デベロッパーが選択したアクティビティから作成されます。 バブルとして正しく表示されるようにアクティビティを設定します。アクティビティの要件として、 サイズ変更が可能であること埋め込み型であることが求められます。この要件を 1 つでも満たさなかった場合は、バブルではなく、通知として表示されます。

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

<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(API レベル 30)以降をターゲットとしている場合は、バブルのメタデータまたは通知が共有ショートカットを参照していることを確認します。
  5. バブルとして表示される通知をキャンセルしない ようにアプリを変更します。 通知をキャンセルすると、バブルが画面から削除されます。バブルを開くと、関連付けられた通知が自動的に非表示になります。

次の例に、これらの手順を示します。

// 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)

バブルが送信されたときにアプリがフォアグラウンドの場合は、重要度は無視され、バブルは常に表示されます(ユーザーがバブルをブロックしている場合は除きます)。

展開表示バブルを作成する

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

上記動作を実現するには、 setAutoExpandBubble()setSuppressNotification()でフラグをセットします。

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

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

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

バブルが展開されると、コンテンツ アクティビティは通常のプロセス ライフサイクルを経て、 アプリがフォアグラウンド プロセスに移行することになります(まだ移行していない場合)。

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

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

ユーザーの作業を中断する回数を減らすため、バブルは特定の状況でのみ表示されます。

アプリが Android 11(API レベル 30)以降をターゲットにしている場合、通知は 会話要件 を満たしていない限り、バブルとして表示されません。アプリが Android 10(API レベル 29)以下をターゲットとしている場合、通知がバブルとして表示されるのは、以下の条件のうち、少なくとも 1 つが当てはまる場合に限られます。

これらの条件が満たされない場合は、バブルの代わりに通知が表示されます。

バブルからアクティビティを起動する

バブルが新しいアクティビティを起動すると、新しいアクティビティは同じタスクとバブル表示されたウィンドウ内で起動するか、新しいタスクで全画面表示で起動し、起動元のバブルを折りたたみます。

バブルと同じタスクで新しいアクティビティを起動するには: 1. インテントを起動するときにアクティビティ コンテキストを使用し、 activity.startActivity(intent)、および 1. インテントに FLAG_ACTIVITY_NEW_TASK フラグを設定しないでください。

それ以外の場合、新しいアクティビティは新しいタスクで開始され、バブルは折りたたまれます。

バブルは特定の会話を表すため、バブル内で起動されるアクティビティはその会話に関連している必要があります。また、バブル内でアクティビティを起動すると、バブルのタスクスタックが増加し、特にナビゲーションに関してユーザー エクスペリエンスが複雑になる可能性があります。

ベスト プラクティス

  • 通知をバブルとして送信するのは、進行中の通信の一部である場合や、ユーザーが明示的にバブル表示をリクエストしているコンテンツの場合など、重要度が高い場合に限るようにしてください。バブルは、実際の画面領域を占有し、他のアプリのコンテンツの上を覆います。
  • バブル通知が通常の通知としても機能することを確認してください。ユーザーがバブルを無効にすると、バブル通知は通常の通知として表示されます。
  • BackHandler コンポーザブルを使用し、その enabled パラメータを UI の状態に関連付けて、必要な場合にのみ戻るボタンの押下をインターセプトするようにします。ハンドラが無効になると、バブルは折りたたまれます。

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

サンプルアプリ

SociaLite サンプルアプリは、 バブルを使用する会話型アプリです。デモ用に、このアプリではチャットボットを使用します。実際のアプリでは、バブルは人間によるメッセージに使用してください。