Chạm để đọc của trợ lý thoại

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 trong khi lái xe. Do đó, chúng tôi đã mở rộng API trợ lý thoại Android (bao gồm VoiceInteractionSession) để cho phép trợ lý thoại thực hiện các nhiệm vụ cho người dùng khó thực hiện được trong khi lái xe.

Tính năng Nhấn để đọc cho phép trợ lý thoại đọc và trả lời tin nhắn văn bản trên thay mặt cho 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 tính năng này, bạn có thể tích hợp trợ lý thoại với CarVoiceInteractionSession.

Trong Automotive, các thông báo đăng lên Trung tâm thông báo đã xác định được dưới tên INBOX hoặc INBOX_IN_GROUP (ví dụ: tin nhắn SMS), hãy bao gồm Nút Phát. Người dùng có thể nhấp vào Phát để chọn trợ lý thoại sẽ đọc to thông báo và tuỳ ý 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 CarVoiceVoiceSession

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

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

Ứng dụng cung cấp dịch vụ tương tác bằng giọng nói cho ô tô phải tích hợp với các tương tác bằng giọng nói hiện có trên Android. Để tìm hiểu thêm, hãy xem Trợ lý Google cho Android (ngoại trừ VoiceInteractionSession). Trong khi tất cả API tương tác bằng giọng nói các yếu tố vẫn giữ nguyên như đã triển khai trên thiết bị di động, CarVoiceInteractionSession (được mô tả trong phần Triển khai CarVoice mạoSession) thay thế VoiceInteractionSession. Để biết thêm thông tin chi tiết, vui lòng xem những trang sau:

Triển khai CarVoiceVoiceSession

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

Điểm khác biệt chính giữa CarVoiceInteractionSession và Có lớp VoiceInteractionSession CarVoiceInteractionSession đường chuyền trong trận đấu ở onShow để trợ lý thoạ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 một phiên. Các tham số cho onShow cho từng lớp được liệt kê trong bảng sau:

Phiên tương tác với giọng nói trong Car Voice Phiên tương tác bằng giọng nói
onShow nhận ba thông số sau:
  • args
  • showFlags
  • actions
onShow nhận hai thông số sau:
  • args
  • showFlags

Các thay đổi trong Android 10

Kể từ Android 10, nền tảng này sẽ gọi VoiceInteractionService.onGetSupportedVoiceActions để phát hiện hành động nào được hỗ trợ. Trợ lý thoạ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 thông tin chi tiết về từng thao tác, hãy xem Biểu đồ trình tự.

Hành độ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 thông báo cho người dùng, sau đó kích hoạt Đánh dấu là đã đọc đang chờ xử lý ý định ngược lại khi các thông báo được đọc thành công. Nếu muốn, hãy nhắc để trả lời.
VOICE_ACTION_REPLY_NOTIFICATION Theo gói bằng khoá.
KEY_NOTIFICATION liên kết với StatusBarNotification.
Cần có android.permission.BIND_NOTIFICATION_LISTENER_SERVICE.
Nhắc người dùng nêu tin nhắn trả lời rồi nhập tin nhắn trả lời vào RemoteInputReply của ý định đang chờ xử lý, sau đó kích hoạt ý định đang chờ xử lý.
VOICE_ACTION_HANDLE_EXCEPTION Chuỗi có khoá.
KEY_EXCEPTION liên kết với ExceptionValue (mô tả trong Giá trị ngoại lệ).
KEY_FALLBACK_ASSISTANT_ENABLED liên kết với một 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 tắt.
Hành động dự kiến cần thực hiện cho trường hợp ngoại lệ được xác định trong tài liệu về ngoại lệ này.

Giá trị ngoại lệ

EXCEPTION_NOTIFICATION_LISTENER_PERMISSIONS_MISSING sẽ cho trợ lý thoại biết rằng ứng dụng đang thiếu quyền Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE và cần người dùng cấp quyền này.

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

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

Nền tảng này đề xuất trợ lý thoại thêm logic giới hạn số lượng yêu cầu cho số lần quyền này được yêu cầu. Khi làm như vậy, người dùng không tôn trọng muốn cấp quyền này cho trợ lý thoại và ưu tiên FallbackAssistant để đọc to tin nhắn văn bản. Đặt câu lệnh người dùng để cấp quyền mỗi khi người dùng nhấn vào nút Play (Phát) trên một thông báo tin nhắn có thể là trải nghiệm người dùng tiêu cực. Nền tảng này không áp dụng giới hạn số lượng yêu cầu thay mặt cho trợ lý thoại.

Khi yêu cầu quyền nghe thông báo, trợ lý thoại sẽ sử dụng CarUxRestrictionsManager để xác định người dùng đang đỗ xe hay đang lái xe. Trợ lý thoại nếu người dùng đang lái xe sẽ hiển thị thông báo hướng dẫn cách cấp quyền. Đang thực hiện sẽ giúp (và nhắc) người dùng cấp quyền khi phương thức đó an toàn hơn.

Làm việc với StatusBarNotification

StatusBarNotification đã vượt qua yêu cầu Đọc và trả lời thao tác bằng giọng nói sẽ luôn xuất hiện trong thông báo tin nhắn tương thích với ô tô như được mô tả trong mục Thông báo người dùng tin nhắn. Mặc dù một số thông báo có thể không có Câu trả lời đang chờ xử lý ý định, đều có ý định đang chờ xử lý Đánh dấu là đã đọc.

Để đơn giản hoá các hoạt động tương tác với thông báo, hãy sử dụng NotificationPayloadHandler, Cung cấp các phương thức để trích xuất thông báo từ thông báo và ghi trả lời tin nhắn cho ý định đang chờ xử lý thích hợp của thông báo. Sau trợ lý thoại đọc tin nhắn, thì trợ lý thoại phải kích hoạt nhãn làm ý định đọc.

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

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

Biểu đồ trình tự

Những hình này minh hoạ các luồng logic của CarVoiceInteractionSession actions:

Hàm VOICE_ACTION_READ_),

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

Trong Hình 3, bạn nên áp dụng giới hạn số lượng yêu cầu quyền:

Hàm VOICE_ACTION_REPLY_REPLY

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

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ý thoại của mình đọc to tên ứng dụng nhắn tin trong đọc to tin nhắn (ví dụ: "Sam từ Hangouts đã nói..."), tạo một hàm như được hiển thị trong mã ví dụ sau đây để đảm bảo Trợ lý đọc đúng tên:

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