Asisten suara Ketuk untuk Membaca

Android Automotive menganggap suara sebagai komponen penting untuk interaksi yang aman saat berkendara dan salah satu cara teraman bagi pengguna untuk berinteraksi dengan Android Automotive OS saat mengemudi. Hasilnya, kami memperluas API asisten suara Android (termasuk VoiceInteractionSession ) untuk memungkinkan asisten suara melakukan tugas bagi pengguna yang mungkin sulit diselesaikan saat mengemudi.

Tap-to-Read memungkinkan asisten suara membaca dan membalas pesan teks atas nama pengguna, saat pengguna berinteraksi dengan notifikasi pesan. Untuk menyediakan fungsi ini, Anda dapat mengintegrasikan asisten suara dengan CarVoiceInteractionSession .

Di Otomotif, notifikasi yang diposting ke Pusat Notifikasi yang diidentifikasi sebagai INBOX atau INBOX_IN_GROUP (misalnya, pesan SMS) menyertakan tombol Putar . Pengguna dapat mengklik Putar agar asisten suara yang dipilih membacakan notifikasi dengan keras, dan secara opsional membalas dengan suara.

Notifikasi ketuk untuk membaca

Gambar 1. Notifikasi Tap-to-Read dengan tombol Play.

Integrasikan dengan CarVoiceInteractionSession

Bagian selanjutnya menjelaskan cara mengintegrasikan asisten suara dengan CarVoiceInteractionSession .

Mendukung interaksi suara

Aplikasi yang menyediakan layanan interaksi suara mobil harus berintegrasi dengan interaksi suara Android yang ada. Untuk mempelajari lebih lanjut, lihat Asisten Google untuk Android (dengan pengecualian VoiceInteractionSession ). Meskipun semua elemen API interaksi suara tetap sama seperti yang diterapkan pada perangkat seluler, CarVoiceInteractionSession (dijelaskan dalam Implementasi CarVoiceInteractionSession ) menggantikan VoiceInteractionSession . Untuk informasi lebih lanjut, lihat halaman ini:

Menerapkan CarVoiceInteractionSession

CarVoiceInteractionSession memaparkan API yang dapat Anda gunakan untuk mengaktifkan asisten suara membacakan pesan teks dengan lantang dan kemudian membalas pesan tersebut atas nama pengguna.

Perbedaan utama antara kelas CarVoiceInteractionSession dan VoiceInteractionSession adalah CarVoiceInteractionSession meneruskan tindakan di onShow sehingga asisten suara dapat mendeteksi konteks permintaan pengguna segera setelah CarVoiceInteractionSession memulai sesi. Parameter onShow untuk setiap kelas tercantum dalam tabel berikut:

Sesi Interaksi Suara Mobil Sesi Interaksi Suara
onShow mengambil tiga parameter berikut:
  • args
  • showFlags
  • actions
onShow mengambil dua parameter ini:
  • args
  • showFlags

Perubahan di Android 10

Dimulai dengan Android 10, platform ini memanggil VoiceInteractionService.onGetSupportedVoiceActions untuk mendeteksi tindakan mana yang didukung. Asisten suara mengambil alih dan mengimplementasikan VoiceInteractionService.onGetSupportedVoiceActions , seperti yang ditunjukkan dalam contoh berikut:

public class MyInteractionService extends VoiceInteractionService {
    private static final List SUPPORTED_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;
   }
}

Tindakan yang valid dijelaskan dalam tabel berikut. Untuk detail tentang setiap tindakan, lihat Diagram urutan .

Tindakan Muatan yang diharapkan Tindakan interaksi suara yang diharapkan
VOICE_ACTION_READ_NOTIFICATION Bacakan pesan dengan lantang kepada pengguna lalu aktifkan kembali maksud Tandai sebagai Telah Dibaca tertunda ketika pesan berhasil dibaca. Secara opsional, minta balasan kepada pengguna.
VOICE_ACTION_REPLY_NOTIFICATION Dapat dibagikan dengan kunci.
KEY_NOTIFICATION yang dipetakan ke StatusBarNotification .
Membutuhkan android.permission.BIND_NOTIFICATION_LISTENER_SERVICE .
Minta pengguna untuk menyatakan pesan balasan, masukkan pesan balasan ke RemoteInputReply dari maksud yang tertunda, lalu aktifkan maksud yang tertunda.
VOICE_ACTION_HANDLE_EXCEPTION Tali dengan kunci.
KEY_EXCEPTION yang dipetakan ke ExceptionValue (dijelaskan dalam Exception value ).
KEY_FALLBACK_ASSISTANT_ENABLED yang dipetakan ke nilai Boolean. Jika nilainya true , asisten fallback yang dapat menangani permintaan pengguna telah dinonaktifkan.
Tindakan yang diharapkan untuk diambil untuk pengecualian ditentukan dalam dokumentasi pengecualian.

Nilai pengecualian

EXCEPTION_NOTIFICATION_LISTENER_PERMISSIONS_MISSING menunjukkan kepada asisten suara bahwa izin Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE tidak ada dan untuk mendapatkan izin ini dari pengguna.

Minta izin pendengar notifikasi

Jika asisten suara default tidak memiliki izin pendengar notifikasi, FallbackAssistant platform (jika diaktifkan oleh produsen mobil) mungkin membacakan pesan dengan lantang sebelum asisten suara diberi tahu untuk meminta izin. Untuk menentukan apakah FallbackAssistant diaktifkan dan telah membaca pesan, asisten suara harus memeriksa nilai Boolean KEY_FALLBACK_ASSISTANT_ENABLED di payload.

Platform merekomendasikan asisten suara untuk menambahkan logika pembatasan kecepatan untuk berapa kali izin ini diminta. Hal ini menghormati pengguna yang tidak ingin memberikan izin ini kepada asisten suara dan lebih memilih FallbackAssistant untuk membacakan pesan teks dengan lantang. Meminta izin kepada pengguna setiap kali pengguna menekan Putar pada notifikasi pesan dapat menimbulkan pengalaman pengguna yang negatif. Platform tidak menerapkan batasan tarif atas nama asisten suara.

Saat meminta izin pendengar notifikasi, asisten suara harus menggunakan CarUxRestrictionsManager untuk menentukan apakah pengguna sedang parkir atau sedang mengemudi. Jika pengguna sedang mengemudi, asisten suara akan menampilkan notifikasi yang memberikan petunjuk tentang cara memberikan izin. Melakukannya akan membantu (dan mengingatkan) pengguna untuk memberikan izin saat lebih aman.

Bekerja dengan StatusBarNotification

StatusBarNotification yang diteruskan dengan tindakan suara Baca dan Balas selalu ada dalam notifikasi perpesanan yang kompatibel dengan mobil seperti yang dijelaskan dalam Memberi tahu pengguna tentang pesan . Meskipun beberapa notifikasi mungkin tidak memiliki maksud Balasan Tertunda, semuanya memiliki maksud Tandai sebagai Telah Dibaca tertunda.

Untuk menyederhanakan interaksi dengan notifikasi, gunakan NotificationPayloadHandler , yang menyediakan metode untuk mengekstrak pesan dari notifikasi dan menulis pesan balasan ke maksud tertunda yang sesuai dari notifikasi. Setelah asisten suara membaca pesan, asisten suara harus mengaktifkan maksud Tandai sebagai Telah Dibaca.

Memenuhi prasyarat Ketuk untuk Membaca

Hanya VoiceInteractionSession dari asisten suara default yang diberi tahu saat pengguna memicu tindakan suara untuk membaca dan membalas pesan. Seperti disebutkan di atas, asisten suara default ini juga harus memiliki izin pendengar notifikasi.

Diagram urutan

Angka-angka ini menampilkan alur logika CarVoiceInteractionSession actions :

VOICE_ACTION_READ_NOTIFICATION

Gambar 2. Diagram urutan untuk VOICE_ACTION_READ_NOTIFICATION.

Dalam kasus Gambar 3, penerapan batas kecepatan permintaan izin direkomendasikan:

VOICE_ACTION_REPLY_NOTIFICATION

Gambar 3. Diagram urutan untuk VOICE_ACTION_REPLY_NOTIFICATION.

VOICE_ACTION_HANDLE_EXCEPTION

Gambar 4. Diagram urutan untuk VOICE_ACTION_HANDLE_EXCEPTION.

Baca nama aplikasi

Jika Anda ingin asisten suara Anda membacakan nama aplikasi perpesanan selama pembacaan pesan (misalnya, "Sam dari Hangouts mengatakan..."), buat fungsi seperti yang ditunjukkan dalam contoh kode berikut untuk memastikan asisten membacakan nama yang benar:

@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;
}