Android Automotive では、音声は運転中の安全な操作にとって重要なコンポーネントであり、ユーザーが運転中に Android Automotive OS を操作するための最も安全な方法の 1 つであると考えています。その結果、Android 音声アシスタント API ( VoiceInteractionSession
を含む) を拡張し、運転中に実行するのが難しいユーザーのタスクを音声アシスタントが実行できるようにしました。
Tap-to-Read を使用すると、ユーザーがメッセージ通知を操作するときに、音声アシスタントがユーザーに代わってテキスト メッセージを読んで返信できるようになります。この機能を提供するには、音声アシスタントをCarVoiceInteractionSession
と統合します。
Automotive では、 INBOX
またはINBOX_IN_GROUP
として識別される通知センターに投稿される通知 (SMS メッセージなど) には、再生ボタンが含まれます。ユーザーは、 「再生」をクリックして、選択した音声アシスタントに通知を読み上げさせたり、必要に応じて音声で応答したりすることができます。
図 1. [再生] ボタンを備えたタップして読む通知。
CarVoiceInteractionSession との統合
次のセクションでは、音声アシスタントをCarVoiceInteractionSession
と統合する方法について説明します。
音声インタラクションをサポート
車の音声対話サービスを提供するアプリは、既存の Android 音声対話と統合する必要があります。詳細については、 「Android 用 Google アシスタント」を参照してください ( VoiceInteractionSession
を除く)。すべての音声対話 API 要素はモバイル デバイスに実装されているものと同じままですが、 CarVoiceInteractionSession
( CarVoiceInteractionSession の実装で説明) がVoiceInteractionSession
を置き換えます。詳細については、次のページを参照してください。
CarVoiceInteractionSession を実装する
CarVoiceInteractionSession
音声アシスタントがテキスト メッセージを読み上げ、ユーザーに代わってメッセージに返信できるようにするために使用できる API を公開します。
CarVoiceInteractionSession
クラスとVoiceInteractionSession
クラスの主な違いは、 CarVoiceInteractionSession
がonShow
でアクションを渡すため、 CarVoiceInteractionSession
がセッションを開始するとすぐに音声アシスタントがユーザーのリクエストのコンテキストを検出できることです。各クラスのonShow
のパラメーターを次の表に示します。
CarVoiceインタラクションセッション | VoiceInteractionセッション |
---|---|
onShow 次の3 つのパラメータを受け取ります。
| onShow 次の2 つのパラメータを受け取ります。
|
Android 10での変更点
Android 10 以降、プラットフォームはVoiceInteractionService.onGetSupportedVoiceActions
を呼び出して、サポートされているアクションを検出します。次の例に示すように、音声アシスタントはVoiceInteractionService.onGetSupportedVoiceActions
をオーバーライドして実装します。
public class MyInteractionService extends VoiceInteractionService { private static final ListSUPPORTED_VOICE_ACTIONS = Arrays.asList( CarVoiceInteractionSession.VOICE_ACTION_READ_NOTIFICATION); @Override public Set onGetSupportedVoiceActions(@NonNull Set voiceActions) { Set result = new HashSet<>(voiceActions); result.retainAll(SUPPORTED_VOICE_ACTIONS); return result; } }
有効なアクションについては、次の表で説明します。各アクションの詳細については、 「シーケンス図」を参照してください。
アクション | 予想されるペイロード | 予想される音声インタラクションアクション |
---|---|---|
VOICE_ACTION_READ_NOTIFICATION | ユーザーにメッセージを読み上げてから、メッセージが正常に読み取られたときに保留中のインテントとして既読としてマークを実行します。必要に応じて、ユーザーに応答を求めます。 | |
VOICE_ACTION_REPLY_NOTIFICATION | 鍵付きで取り出し可能です。StatusBarNotification にマップされるKEY_NOTIFICATION 。android.permission.BIND_NOTIFICATION_LISTENER_SERVICE が必要です。 | ユーザーに応答メッセージを入力するように求め、その応答メッセージを保留インテントのRemoteInputReply に入力して、保留インテントを起動します。 |
VOICE_ACTION_HANDLE_EXCEPTION | キー付きの文字列。ExceptionValue にマップされるKEY_EXCEPTION ( 「例外値」で説明)。KEY_FALLBACK_ASSISTANT_ENABLED 。ブール値にマップされます。値がtrue の場合、ユーザーのリクエストを処理できるフォールバック アシスタントが無効になっています。 | 例外に対して実行されることが予想されるアクションは、例外のドキュメントで定義されています。 |
例外値
EXCEPTION_NOTIFICATION_LISTENER_PERMISSIONS_MISSING
は、 Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE
権限がないこと、およびユーザーからこの権限を取得することを音声アシスタントに示します。
通知リスナー権限をリクエストする
デフォルトの音声アシスタントに通知リスナー権限がない場合、音声アシスタントに権限を要求する通知が送信される前に、プラットフォームのFallbackAssistant
(自動車メーカーによって有効にされている場合) がメッセージを読み上げる可能性があります。 FallbackAssistant
が有効になっていてメッセージを読んだかどうかを判断するには、音声アシスタントはペイロード内のKEY_FALLBACK_ASSISTANT_ENABLED
ブール値を確認する必要があります。
プラットフォームは、音声アシスタントに、この権限が要求される回数に対するレート制限ロジックを追加することを推奨します。そうすることで、音声アシスタントにこの権限を付与したくないユーザー、およびFallbackAssistant
がテキスト メッセージを読み上げることを希望するユーザーが尊重されます。ユーザーがメッセージ通知で[再生] を押すたびに許可を求めるプロンプトを表示すると、ユーザー エクスペリエンスが低下する可能性があります。プラットフォームは、音声アシスタントに代わってレート制限を課しません。
通知リスナーの許可を要求する場合、音声アシスタントはCarUxRestrictionsManager
を使用して、ユーザーが駐車中か運転中かを判断する必要があります。ユーザーが運転中の場合、音声アシスタントは許可を与える方法を説明する通知を表示します。そうすることで、より安全なときにアクセス許可を付与するようにユーザーに知らせることができます。
StatusBarNotification の操作
Read および Reply 音声アクションで渡されるStatusBarNotification
「ユーザーにメッセージを通知する」で説明されているように、常に自動車互換のメッセージング通知内にあります。一部の通知には返信保留インテントがない場合がありますが、すべての通知に保留中既読としてマークインテントがあります。
通知との対話を合理化するには、通知からメッセージを抽出し、通知の適切な保留中のインテントに応答メッセージを書き込むメソッドを提供するNotificationPayloadHandler
を使用します。音声アシスタントがメッセージを読み上げた後、音声アシスタントは既読としてマークインテントを起動する必要があります。
Tap-to-Readの前提条件を満たす
ユーザーがメッセージを読んで返信する音声アクションをトリガーすると、デフォルトの音声アシスタントのVoiceInteractionSession
のみが通知されます。前述したように、このデフォルトの音声アシスタントには通知リスナー権限も必要です。
シーケンス図
これらの図は、 CarVoiceInteractionSession actions
のロジック フローを示しています。
図 2. VOICE_ACTION_READ_NOTIFICATION のシーケンス図。
図 3 の場合、アクセス許可リクエストに対するレート制限のアプリが推奨されます。
図 3. VOICE_ACTION_REPLY_NOTIFICATION のシーケンス図。
図 4. VOICE_ACTION_HANDLE_EXCEPTION のシーケンス図。
アプリ名を読む
メッセージの読み上げ中に音声アシスタントにメッセージング アプリの名前を読み上げてもらいたい場合 (たとえば、「ハングアウトのサムが言った...」)、次のコード例に示すような関数を作成して、アシスタントがメッセージを確実に読み上げられるようにします。正しい名前:
@Nullable String getMessageApplicationName(Context context, StatusBarNotification statusBarNotification) { ApplicationInfo info = getApplicationInfo(context, statusBarNotification.getPackageName()); if (info == null) return null; Notification notification = statusBarNotification.getNotification(); // Sometimes system packages will post on behalf of other apps, so check this // field for a system app notification. if (isSystemApp(info) && notification.extras.containsKey(Notification.EXTRA_SUBSTITUTE_APP_NAME)) { return notification.extras.getString(Notification.EXTRA_SUBSTITUTE_APP_NAME); } else { PackageManager pm = context.getPackageManager(); return String.valueOf(pm.getApplicationLabel(info)); } } @Nullable ApplicationInfo getApplicationInfo(Context context, String packageName) { final PackageManager pm = context.getPackageManager(); ApplicationInfo info; try { info = pm.getApplicationInfo(packageName, 0); } catch (PackageManager.NameNotFoundException e) { return null; } return info; } boolean isSystemApp(ApplicationInfo info) { return (info.flags & ApplicationInfo.FLAG_SYSTEM) != 0; }