Trợ lý giọng nói Nhấn để đọc

Android Automotive coi giọng nói là một thành phần quan trọng để tương tác an toàn khi lái xe và là một trong những cách an toàn nhất để người dùng tương tác với Android Automotive OS khi đang lái xe. Do đó, chúng tôi đã mở rộng API trợ lý giọng nói của Android (bao gồm VoiceInteractionSession ) để cho phép trợ lý giọng nói thực hiện các tác vụ cho người dùng có thể khó thực hiện khi lái xe.

Nhấn để đọc cho phép trợ lý giọng nói đọc và trả lời tin nhắn văn bản thay mặt người dùng khi người dùng tương tác với thông báo tin nhắn. Để cung cấp chức năng này, bạn có thể tích hợp trợ lý giọng nói với CarVoiceInteractionSession .

Trong Ô tô, thông báo được đăng lên Trung tâm thông báo được xác định là INBOX hoặc INBOX_IN_GROUP (ví dụ: tin nhắn SMS) bao gồm nút Phát . Người dùng có thể nhấp vào Phát để yêu cầu trợ lý giọng nói đã chọn đọc to thông báo và tùy chọn trả lời bằng giọng nói.

Thông báo nhấn để đọc

Hình 1. Thông báo nhấn để đọc bằng nút Phát.

Tích hợp với CarVoiceInteractionSession

Các phần tiếp theo mô tả cách tích hợp trợ lý giọng nói với CarVoiceInteractionSession .

Hỗ trợ tương tác bằng giọng nói

Các ứng dụng cung cấp dịch vụ tương tác bằng giọng nói trên ô tô phải tích hợp với các tương tác bằng giọng nói hiện có của Android. Để tìm hiểu thêm, hãy xem Trợ lý Google dành cho Android (ngoại trừ VoiceInteractionSession ). Mặc dù tất cả các thành phần API tương tác bằng giọng nói vẫn giống như được triển khai trên thiết bị di động, CarVoiceInteractionSession (được mô tả trong Triển khai CarVoiceInteractionSession ) sẽ thay thế VoiceInteractionSession . Để biết thêm thông tin, hãy xem các trang sau:

Triển khai CarVoiceInteractionSession

CarVoiceInteractionSession hiển thị các API mà bạn có thể sử dụng để cho phép trợ lý giọng nói đọc to tin nhắn văn bản và sau đó thay mặt người dùng trả lời những tin nhắn này.

Điểm khác biệt chính giữa các lớp CarVoiceInteractionSessionVoiceInteractionSessionCarVoiceInteractionSession chuyển hành động trong onShow để trợ lý giọng nói có thể phát hiện ngữ cảnh yêu cầu của người dùng ngay khi CarVoiceInteractionSession bắt đầu phiên. Các tham số cho onShow cho mỗi lớp được liệt kê trong bảng sau:

Phiên xe hơiVoiceTương tác Phiên tương tác bằng giọng nói
onShow nhận ba tham số sau:
  • args
  • showFlags
  • actions
onShow nhận hai tham số sau :
  • args
  • showFlags

Những thay đổi trong Android 10

Bắt đầu từ Android 10, nền tảng này gọi VoiceInteractionService.onGetSupportedVoiceActions để phát hiện hành động nào được hỗ trợ. Trợ lý giọng nói sẽ ghi đè và triển khai VoiceInteractionService.onGetSupportedVoiceActions , như trong ví dụ sau:

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

Các hành động hợp lệ được mô tả trong bảng sau. Để biết chi tiết về từng hành động, hãy xem Sơ đồ trình tự .

Hoạt động Tải trọng dự kiến Hành động tương tác bằng giọng nói dự kiến
VOICE_ACTION_READ_NOTIFICATION Đọc to tin nhắn cho người dùng rồi kích hoạt lại mục đích Đánh dấu là đã đọc khi tin nhắn được đọc thành công. Tùy chọn, nhắc người dùng trả lời.
VOICE_ACTION_REPLY_NOTIFICATION Có thể gửi bưu kiện bằng chìa khóa.
KEY_NOTIFICATION ánh xạ tới StatusBarNotification .
Yêu cầu android.permission.BIND_NOTIFICATION_LISTENER_SERVICE .
Nhắc người dùng nêu thông báo trả lời, nhập thông báo trả lời vào RemoteInputReply của mục đích đang chờ xử lý, sau đó kích hoạt mục đích đang chờ xử lý.
VOICE_ACTION_HANDLE_EXCEPTION Chuỗi có chìa khóa.
KEY_EXCEPTION ánh xạ tới ExceptionValue (được mô tả trong Giá trị ngoại lệ ).
KEY_FALLBACK_ASSISTANT_ENABLED ánh xạ tới giá trị Boolean. Nếu giá trị là true thì trợ lý dự phòng có thể xử lý yêu cầu của người dùng đã bị tắt.
Hành động dự kiến ​​được thực hiện đối với trường hợp ngoại lệ được xác định trong tài liệu về trường hợp ngoại lệ đó.

Giá trị ngoại lệ

EXCEPTION_NOTIFICATION_LISTENER_PERMISSIONS_MISSING cho trợ lý giọng nói biết rằng nó thiếu quyền Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE và yêu cầu người dùng cho phép này.

Yêu cầu quyền nghe thông báo

Nếu trợ lý giọng nói mặc định không có quyền nghe thông báo thì FallbackAssistant của nền tảng (nếu được nhà sản xuất ô tô bật) có thể đọc to tin nhắn trước khi trợ lý giọng nói được thông báo yêu cầu quyền. Để xác định xem FallbackAssistant đã được bật và đã đọc tin nhắn hay chưa, trợ lý giọng nói phải kiểm tra giá trị Boolean KEY_FALLBACK_ASSISTANT_ENABLED trong tải trọng.

Nền tảng này khuyến nghị trợ lý giọng nói thêm logic giới hạn tốc độ cho số lần quyền này được yêu cầu. Làm như vậy sẽ tôn trọng người dùng không muốn cấp quyền này cho trợ lý giọng nói và muốn FallbackAssistant đọc to tin nhắn văn bản. Nhắc người dùng cấp phép mỗi lần người dùng nhấn Phát trên thông báo tin nhắn có thể là trải nghiệm tiêu cực cho người dùng. Nền tảng không áp đặt giới hạn tốc độ thay mặt cho trợ lý giọng nói.

Khi yêu cầu quyền của người nghe thông báo, trợ lý giọng nói phải sử dụng CarUxRestrictionsManager để xác định xem người dùng đang đỗ xe hay đang lái xe. Nếu người dùng đang lái xe, trợ lý giọng nói sẽ hiển thị thông báo cung cấp hướng dẫn về cách cấp quyền. Làm như vậy sẽ giúp (và nhắc nhở) người dùng cấp quyền khi an toàn hơn.

Làm việc với StatusBarNotification

StatusBarNotification được truyền cùng với tác vụ thoại Đọc và Trả lời luôn ở trong thông báo nhắn tin tương thích với ô tô như được mô tả trong Thông báo cho người dùng tin nhắn . Mặc dù một số thông báo có thể không có mục đích Đang chờ trả lời nhưng tất cả chúng đều có mục đích Đang chờ xử lý Đánh dấu là đã đọc.

Để hợp lý hóa các tương tác với thông báo, hãy sử dụng NotificationPayloadHandler , cung cấp các phương pháp trích xuất tin nhắn từ thông báo và viết tin nhắn trả lời theo mục đích chờ xử lý thích hợp của thông báo. Sau khi trợ lý giọng nói đọc tin nhắn, trợ lý giọng nói phải kích hoạt ý định Đánh dấu là đã đọc.

Đáp ứng các điều kiện tiên quyết của Chạm để Đọc

Chỉ VoiceInteractionSession của trợ lý giọng nói mặc định mới được thông báo khi người dùng kích hoạt tác vụ thoại để đọc và trả lời tin nhắn. Như đã đề cập ở trên, trợ lý giọng nói mặc định này cũng phải có quyền nghe thông báo.

Sơ đồ trình tự

Những số liệu này hiển thị luồng logic của CarVoiceInteractionSession actions :

VOICE_ACTION_READ_NOTIFICATION

Hình 2. Sơ đồ trình tự cho VOICE_ACTION_READ_NOTIFICATION.

Trong trường hợp Hình 3, nên áp dụng giới hạn tốc độ đối với các yêu cầu cấp phép:

VOICE_ACTION_REPLY_NOTIFICATION

Hình 3. Sơ đồ trình tự cho VOICE_ACTION_REPLY_NOTIFICATION.

VOICE_ACTION_HANDLE_EXCEPTION

Hình 4. Sơ đồ trình tự cho VOICE_ACTION_HANDLE_EXCEPTION.

Đọc tên ứng dụng

Nếu bạn muốn trợ lý giọng nói của mình đọc to tên ứng dụng nhắn tin trong khi đọc tin nhắn (ví dụ: "Sam từ Hangouts đã nói..."), hãy tạo một hàm giống như trong ví dụ về mã sau đây để đảm bảo trợ lý đang đọc tên chính xác:

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