Thực hiện lệnh

Trang này mô tả cách thực hiện các lệnh bằng cách tương tác bằng giọng nói.

Thực hiện các lệnh liên quan đến nội dung đa phương tiện

Lệnh liên quan đến nội dung đa phương tiện có thể được chia thành 3 nhóm:

  • Nguồn nội dung đa phương tiện bên ngoài (chẳng hạn như Spotify được cài đặt trong AAOS).
  • Nguồn nội dung đa phương tiện phụ trợ (chẳng hạn như nhạc được phát trực tuyến thông qua VIA).
  • Nguồn nội dung đa phương tiện cục bộ (chẳng hạn như đài phát thanh trên ô tô).

Xử lý các lệnh liên quan đến nguồn nội dung đa phương tiện bên ngoài

Nguồn nội dung đa phương tiện bên ngoài được xác định là các ứng dụng Android hỗ trợ API MediaSessionCompatMediaBrowseCompat (tham khảo Tạo ứng dụng đa phương tiện cho ô tô để biết giải thích chi tiết về cách sử dụng các API này).

Quan trọng: Để ứng dụng trợ lý kết nối với MediaBrowseService của tất cả các ứng dụng đa phương tiện đã cài đặt trong hệ thống, ứng dụng đó phải:

  1. Được cài đặt dưới dạng ứng dụng đã ký bằng hệ thống (xem Nguyên tắc phát triển ứng dụng đa phương tiện cho AAOS và mã PackageValidator mẫu).
  2. Giữ quyền được ưu tiên trong hệ thống android.permission.MEDIA_CONTENT_CONTROL (xem bài viết Cấp quyền được ưu tiên trong hệ thống).

Ngoài MediaBrowserCompatMediaControllerCompat, AAOS còn cung cấp những nội dung sau:

  • CarMediaService cung cấp thông tin tập trung về nguồn nội dung đa phương tiện hiện được chọn. API này cũng được dùng để tiếp tục phát nguồn nội dung đa phương tiện đã phát trước đó sau khi khởi động lại ô tô.
  • car-media-common cung cấp các phương thức thuận tiện để liệt kê, kết nối và tương tác với các ứng dụng đa phương tiện.

Dưới đây là các nguyên tắc cụ thể về việc triển khai các lệnh tương tác bằng giọng nói phổ biến.

Lấy danh sách các nguồn nội dung đa phương tiện đã cài đặt

Bạn có thể phát hiện các nguồn nội dung đa phương tiện bằng cách sử dụng PackageManager, và lọc các dịch vụ khớp với MediaBrowserService.SERVICE_INTERFACE. Ở một số ô tô, có thể có một số cách triển khai dịch vụ trình duyệt nội dung đa phương tiện đặc biệt mà bạn nên loại trừ. Dưới đây là ví dụ về logic này:

private Map<String, MediaSource> getAvailableMediaSources() {
    List<String> customMediaServices =
        Arrays.asList(mContext.getResources()
            .getStringArray(R.array.custom_media_packages));
    List<ResolveInfo> mediaServices = mPackageManager.queryIntentServices(
            new Intent(MediaBrowserService.SERVICE_INTERFACE),
            PackageManager.GET_RESOLVED_FILTER);
    Map<String, MediaSource> result = new HashMap<>();
    for (ResolveInfo info : mediaServices) {
        String packageName = info.serviceInfo.packageName;
        if (customMediaServices.contains(packageName)) {
            // Custom media sources should be ignored, as they might have a
            // specialized handling (e.g., radio).
            continue;
        }
        String className = info.serviceInfo.name;
        ComponentName componentName = new ComponentName(packageName,
            className);
        MediaSource source = MediaSource.create(mContext, componentName);
        result.put(source.getDisplayName().toString().toLowerCase(),
            source);
    }
    return result;
}

Xin lưu ý rằng bạn có thể cài đặt hoặc gỡ cài đặt các nguồn nội dung đa phương tiện bất cứ lúc nào. Để duy trì danh sách chính xác, bạn nên triển khai thực thể BroadcastReceiver cho các hành động theo ý định ACTION_PACKAGE_ADDED, ACTION_PACKAGE_CHANGED, ACTION_PACKAGE_REPLACED, và ACTION_PACKAGE_REMOVED.

Kết nối với nguồn nội dung đa phương tiện đang phát

CarMediaService cung cấp các phương thức để lấy nguồn nội dung đa phương tiện hiện được chọn và thời điểm nguồn nội dung đa phương tiện này thay đổi. Những thay đổi này có thể xảy ra do người dùng tương tác trực tiếp với giao diện người dùng hoặc do sử dụng các nút phần cứng trong ô tô. Mặt khác, thư viện car-media-common cung cấp các cách thuận tiện để kết nối với một nguồn nội dung đa phương tiện nhất định. Dưới đây là đoạn mã đơn giản về cách kết nối với ứng dụng đa phương tiện hiện được chọn:

public class MediaActuator implements
        MediaBrowserConnector.onConnectedBrowserChanged {
    private final Car mCar;
    private CarMediaManager mCarMediaManager;
    private MediaBrowserConnector mBrowserConnector;

    

    public void initialize(Context context) {
        mCar = Car.createCar(context);
        mBrowserConnector = new MediaBrowserConnector(context, this);
        mCarMediaManager = (CarMediaManager)
            mCar.getCarManager(Car.CAR_MEDIA_SERVICE);
        mBrowserConnector.connectTo(mCarMediaManager.getMediaSource());
        
    }

    @Override
    public void onConnectedBrowserChanged(
            @Nullable MediaBrowserCompat browser) {
        // TODO: Handle connected/disconnected browser
    }

    
}

Kiểm soát hoạt động phát của nguồn nội dung đa phương tiện đang phát

Với MediaBrowserCompat `MediaBrowserCompat` đã kết nối, bạn có thể dễ dàng gửi các lệnh điều khiển hoạt động truyền tải đến ứng dụng mục tiêu. Dưới đây là ví dụ đơn giản:

public class MediaActuator   {
    
    private MediaControllerCompat mMediaController;

    @Override
    public void onConnectedBrowserChanged(
            @Nullable MediaBrowserCompat browser) {
        if (browser != null && browser.isConnected()) {
            mMediaController = new MediaControllerCompat(mContext,
                browser.getSessionToken());
        } else {
            mMediaController = null;
        }
    }

    private boolean playSongOnCurrentSource(String song) {
        if (mMediaController == null) {
            // No source selected.
            return false;
        }
        MediaControllerCompat.TransportControls controls =
            mMediaController.getTransportControls();
        PlaybackStateCompat state = controller.getPlaybackState();
        if (state == null || ((state.getActions() &
                PlaybackStateCompat.ACTION_PLAY_FROM_SEARCH) == 0)) {
            // Source can't play from search
            return false;
        }
        controls.playFromSearch(query, null);
        return true;
    }

    
}

Xử lý các lệnh liên quan đến nguồn nội dung đa phương tiện cục bộ (đài phát thanh, đầu đĩa CD, Bluetooth, USB)

Các nguồn nội dung đa phương tiện cục bộ hiển thị chức năng của chúng cho hệ thống bằng cách sử dụng cùng một API MediaSession và MediaBrowse được trình bày chi tiết ở trên. Để phù hợp với đặc điểm của từng loại phần cứng, các dịch vụ MediaBrowse này sử dụng các quy ước cụ thể để sắp xếp thông tin và các lệnh liên quan đến nội dung đa phương tiện.

Xử lý đài phát thanh

Bạn có thể xác định Radio MediaBrowseService bằng bộ lọc ý định ACTION_PLAY_BROADCASTRADIO. Các dịch vụ này dự kiến sẽ tuân theo các chế độ điều khiển hoạt động phát và cấu trúc duyệt nội dung đa phương tiện được mô tả trong bài viết Triển khai đài phát thanh. AAOS cung cấp thư viện car-broadcastradio-support chứa các hằng số và phương thức giúp OEM tạo các cách triển khai MediaBrowseService cho các dịch vụ đài phát thanh của riêng họ tuân theo giao thức đã xác định, và hỗ trợ các ứng dụng sử dụng cây duyệt nội dung (ví dụ: VIA).

Xử lý đầu vào phụ, âm thanh CD và nội dung đa phương tiện trên USB

Không có cách triển khai mặc định nào cho các nguồn nội dung đa phương tiện này trong AOSP. Bạn nên làm như sau:

  • Yêu cầu OEM triển khai các dịch vụ đa phương tiện cho từng nguồn nội dung đa phương tiện. Để biết thông tin chi tiết, hãy xem bài viết Tạo ứng dụng đa phương tiện cho ô tô.
  • Các cách triển khai MediaBrowseService này sẽ được xác định và phản hồi trong các hành động theo ý định được xác định tại Ý định phát chung.
  • Các dịch vụ này sẽ hiển thị cây duyệt nội dung theo các nguyên tắc được mô tả tại Các loại nguồn khác.

Xử lý Bluetooth

Nội dung đa phương tiện trên Bluetooth được hiển thị thông qua hồ sơ Bluetooth AVRCP. Để tạo điều kiện truy cập vào chức năng này, AAOS bao gồm một cách triển khai MediaBrowserService và MediaSession giúp loại bỏ các thông tin chi tiết về giao tiếp (xem packages/apps/Bluetooth).

Cấu trúc cây trình duyệt nội dung đa phương tiện tương ứng được xác định tại BrowseTree lớp. Bạn có thể gửi các lệnh điều khiển hoạt động phát tương tự như bất kỳ ứng dụng nào khác bằng cách sử dụng cách triển khai MediaSession.

Xử lý các lệnh liên quan đến nội dung đa phương tiện phát trực tuyến

Để triển khai tính năng phát trực tuyến nội dung đa phương tiện ở phía máy chủ, VIA phải tự trở thành nguồn nội dung đa phương tiện, triển khai API MediaBrowse và MediaSession. Hãy tham khảo bài viết Tạo ứng dụng đa phương tiện cho ô tô. Bằng cách triển khai các API này, ứng dụng điều khiển bằng giọng nói có thể (trong số những việc khác):

  • Tham gia liền mạch vào quá trình chọn nguồn nội dung đa phương tiện
  • Tự động tiếp tục sau khi khởi động lại ô tô
  • Cung cấp chế độ điều khiển hoạt động phát và duyệt nội dung bằng giao diện người dùng Trung tâm đa phương tiện
  • Nhận các sự kiện liên quan đến nút phần cứng tiêu chuẩn cho nội dung đa phương tiện

Không có cách tiêu chuẩn nào để tương tác với tất cả các ứng dụng điều hướng. Để tích hợp với Google Maps, hãy xem bài viết Google Ý định của Google Maps cho Android. Để tích hợp với các ứng dụng khác, hãy liên hệ trực tiếp với nhà phát triển ứng dụng. Trước khi khởi chạy ý định cho bất kỳ ứng dụng nào (kể cả Google Maps), hãy xác minh rằng ý định đó có thể được phân giải (xem bài viết Ý định của Google Maps). Điều này tạo cơ hội để thông báo cho người dùng trong trường hợp ứng dụng mục tiêu không có sẵn.

Thực hiện các lệnh liên quan đến ô tô

Bạn có thể truy cập vào các thuộc tính của ô tô để đọc và ghi thông qua CarPropertyManager. Các loại thuộc tính của ô tô, cách triển khai và các thông tin chi tiết khác được giải thích trong Cấu hình thuộc tính. Để biết nội dung mô tả chính xác về các thuộc tính mà Android hỗ trợ, bạn nên tham khảo trực tiếp hardware/interfaces/automotive/vehicle/2.0/types.hal. Enum VehicleProperty được xác định ở đó chứa cả các thuộc tính tiêu chuẩn và dành riêng cho nhà cung cấp, các loại dữ liệu, chế độ thay đổi, đơn vị và định nghĩa về quyền truy cập đọc/ghi.

Để truy cập vào các hằng số tương tự này từ Java, bạn có thể sử dụng VehiclePropertyIds và các lớp đồng hành của nó. Các thuộc tính khác nhau có các quyền Android khác nhau để kiểm soát quyền truy cập của chúng. Các quyền này được khai báo trong tệp kê khai CarService manifest và mối liên kết giữa các thuộc tính và quyền được mô tả trong VehiclePropertyIds Javadoc và được thực thi trong PropertyHalServiceIds.

Đọc thuộc tính của ô tô

Sau đây là ví dụ cho thấy cách đọc tốc độ của ô tô:

public class CarActuator ... {
    private final Car mCar;
    private final CarPropertyManager mCarPropertyManager;
    private final TextToSpeech mTTS;

    /** Global VHAL area id */
    public static final int GLOBAL_AREA_ID = 0;

    public CarActuator(Context context, TextToSpeech tts) {
        mCar = Car.createCar(context);
        mCarPropertyManager = (CarPropertyManager) mCar.getCarManager(Car.PROPERTY_SERVICE);
        mTTS = tts;
        ...
    }

    @Nullable
    private void getSpeedInMetersPerSecond() {
        if (!mCarPropertyManager.isPropertyAvailable(VehiclePropertyIds.PERF_VEHICLE_SPEED,
                GLOBAL_AREA_ID)) {
            mTTS.speak("I'm sorry, but I can't read the speed of this vehicle");
            return;
        }
        // Data type and unit can be found in
        // automotive/vehicle/2.0/types.hal
        float speedInMps = mCarPropertyManager.getFloatProperty(
                VehiclePropertyIds.PERF_VEHICLE_SPEED, GLOBAL_AREA_ID);
        int speedInMph = (int)(speedInMetersPerSecond * 2.23694f);
        mTTS.speak(String.format("Sure. Your current speed is %d miles "
                + "per hour", speedInUserUnit);
    }

    ...
}

Đặt thuộc tính của ô tô

Sau đây là ví dụ cho thấy cách bật và tắt điều hoà ở phía trước.

public class CarActuator … {
    …

    private void changeFrontAC(boolean turnOn) {
        List<CarPropertyConfig> configs = mCarPropertyManager
                .getPropertyList(new ArraySet<>(Arrays.asList(
                    VehiclePropertyIds.HVAC_AC_ON)));
        if (configs == null || configs.size() != 1) {
            mTTS.speak("I'm sorry, but I can't control the AC of your vehicle");
            return;
        }

        // Find the front area Ids for the AC property.
        int[] areaIds = configs.get(0).getAreaIds();
        List<Integer> areasToChange = new ArrayList<>();
        for (int areaId : areaIds) {
            if ((areaId & (VehicleAreaSeat.SEAT_ROW_1_CENTER
                        | VehicleAreaSeat.SEAT_ROW_1_LEFT
                        | VehicleAreaSeat.SEAT_ROW_1_RIGHT)) == 0) {
                continue;
            }
            boolean isACInAreaAlreadyOn = mCarPropertyManager
                    .getBooleanProperty(VehiclePropertyIds.HVAC_AC_ON, areaId);
            if ((!isACInAreaAlreadyOn && turnOn) || (isACInAreaAlreadyOn && !turnOn)) {
                areasToChange.add(areaId);
            }
        }
        if (areasToChange.isEmpty()) {
            mTTS.speak(String.format("The AC is already %s", turnOn ? "on" : "off"));
            return;
        }

        for (int areaId : areasToChange) {
            mCarPropertyManager.setBooleanProperty(
                VehiclePropertyIds.HVAC_AC_ON, areaId, turnOn);
        }
        mTTS.speak(String.format("Okay, I'm turning your front AC %s",
            turnOn ? "on" : "off"));
    }

    …
}

Thực hiện các lệnh liên lạc

Xử lý các lệnh liên quan đến tin nhắn

VIA phải xử lý các tin nhắn đến theo quy trình "nhấn để đọc" được mô tả trong Trợ lý giọng nói Nhấn để đọc. Bạn có thể chọn xử lý việc gửi câu trả lời cho người gửi tin nhắn đến. Ngoài ra, VIA có thể sử dụng SmsManager (một phần của gói android.telephony ) để soạn và gửi tin nhắn SMS trực tiếp từ ô tô hoặc qua Bluetooth.

Xử lý các lệnh liên quan đến cuộc gọi

Tương tự, VIA có thể sử dụng TelephonyManager để gọi điện thoại và gọi đến số thư thoại của người dùng. Trong những trường hợp này, VIA sẽ tương tác trực tiếp với ngăn xếp điện thoại hoặc với ứng dụng Trình quay số trên ô tô. Trong mọi trường hợp, ứng dụng Trình quay số trên ô tô phải là ứng dụng hiển thị giao diện người dùng liên quan đến cuộc gọi thoại cho người dùng.

Thực hiện các lệnh khác

Để xem danh sách các điểm tích hợp có thể có khác giữa VIA và hệ thống, hãy xem danh sách các ý định Android nổi tiếng. Nhiều lệnh của người dùng có thể được phân giải ở phía máy chủ (ví dụ: đọc email và sự kiện trên lịch của người dùng) và không yêu cầu bất kỳ hoạt động tương tác nào với hệ thống ngoài chính hoạt động tương tác bằng giọng nói.

Hành động nhập vai (hiển thị nội dung trực quan)

Khi cải thiện hoạt động hoặc khả năng hiểu của người dùng, VIA có thể cung cấp nội dung trực quan bổ sung trên màn hình ô tô. Để giảm thiểu sự phân tâm của người lái xe, hãy giữ cho nội dung đó đơn giản, ngắn gọn và có thể thực hiện. Để biết thông tin chi tiết về nguyên tắc liên quan đến giao diện người dùng/trải nghiệm người dùng đối với các hành động nhập vai, hãy xem bài viết Trợ lý được tải sẵn: Hướng dẫn về trải nghiệm người dùng.

Để bật tính năng tuỳ chỉnh và đảm bảo tính nhất quán với phần còn lại của thiết kế đơn vị chính (HU), VIA nên sử dụng các thành phần trong Thư viện giao diện người dùng trên ô tô cho hầu hết các phần tử trên giao diện người dùng. Để biết thông tin chi tiết, hãy xem bài viết Tuỳ chỉnh.