Thực hiện lệnh

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

Thực hiện các lệnh về nội dung nghe nhìn

Lệnh liên quan đến nội dung nghe nhì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 nghe nhìn phụ trợ (chẳng hạn như nhạc phát trực tuyến qua VIA).
  • Nguồn nội dung nghe nhìn cục bộ (chẳng hạn như đài ô tô).

Xử lý các lệnh của nguồn nội dung nghe nhìn bên ngoài

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

Lưu ý quan trọng: Để ứng dụng trợ lý kết nối với MediaBrowseService của tất 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 được hệ thống ký (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 quyền của hệ thống android.permission.MEDIA_CONTENT_CONTROL (xem phần Cấp quyền đặc quyền của hệ thống).

Ngoài MediaBrowserCompatMediaControllerCompat, AAOS còn cung cấp những tính năng 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. Lệnh này cũng được dùng để tiếp tục nguồn nội dung đa phương tiện đang phát trước đó sau khi xe tắt và khởi động lại.
  • 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 dành riêng cho 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 nguồn nội dung nghe nhìn bằng PackageManager và lọc các dịch vụ khớp với MediaBrowserService.SERVICE_INTERFACE. Trong 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 nghe nhìn đặc biệt, bạn nên loại trừ các cách triển khai này. Sau đâ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 các nguồn nội dung nghe nhìn có thể được cài đặt hoặc gỡ cài đặt bất cứ lúc nào. Để duy trì danh sách chính xác, bạn nên triển khai một thực thể BroadcastReceiver cho các hành động theo ý định ACTION_PACKAGE_ADDED, ACTION_PACKAGE_CHANGED, ACTION_PACKAGE_REPLACEDACTION_PACKAGE_REMOVED.

Kết nối với nguồn nội dung nghe nhì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 đang được chọn và khi 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à một đoạn mã đơn giản về cách kết nối với ứng dụng đa phương tiện đang đượ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
    }

    
}

Điều khiển chế độ phát của nguồn nội dung nghe nhìn đang phát

Với MediaBrowserCompat đã kết nối, bạn có thể dễ dàng gửi các lệnh điều khiển 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 nguồn nội dung nghe nhìn cục bộ (đài, máy phát CD, Bluetooth, USB)

Các nguồn nội dung nghe nhì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 nêu chi tiết ở trên. Để phù hợp với các đặ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à lệnh đa phương tiện.

Xử lý đài

Bạn có thể xác định Radio MediaBrowseService bằng bộ lọc ý định ACTION_PLAY_BROADCASTRADIO. Các thành phần này phải tuân theo các chế độ điều khiển phát và cấu trúc duyệt qua nội dung nghe nhìn được mô tả trong phần Triển khai đài. 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 phương thức 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, đồng thời hỗ trợ các ứng dụng sử dụng cây duyệt xem (ví dụ: VIA).

Xử lý đầu vào phụ, âm thanh CD và nội dung nghe nhìn qua USB

Không có cách triển khai mặc định nào cho các nguồn nội dung nghe nhìn này trong AOSP. Phương pháp đề xuất là:

  • Yêu cầu nhà sản xuất thiết bị gốc triển khai dịch vụ đa phương tiện cho từng thiết bị. Để 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 hoạt động triển khai MediaBrowseService này sẽ được xác định và phản hồi trong các thao tác theo ý định được xác định tại Ý định phát chung.
  • Các dịch vụ này sẽ hiển thị một cây duyệt theo các nguyên tắc được mô tả trong phần Các loại nguồn khác.

Xử lý Bluetooth

Nội dung đa phương tiện qua 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 việc triển khai MediaBrowserService và MediaSession để tóm tắt 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 lớp BrowseTree. Bạn có thể phân phối các lệnh điều khiển phát tương tự như mọi ứng dụng khác bằng cách triển khai MediaSession.

Xử lý các lệnh phát trực tuyến nội dung nghe nhìn

Để triển khai tính năng truyền trực tuyến nội dung nghe nhìn phía máy chủ, VIA phải tự trở thành một nguồn nội dung nghe nhìn, triển khai API MediaBrowse và MediaSession. 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 tính năng khác):

  • Tham gia liền mạch vào quá trình lựa 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ức năng điều khiển chế độ phát và duyệt qua bằng giao diện người dùng của Trung tâm đa phương tiện
  • Nhận sự kiện nút phát nội dung nghe nhìn phần cứng tiêu chuẩn

Không có cách tương tác chuẩn hoá với tất cả ứng dụng chỉ đường. Để tích hợp với Google Maps, hãy xem bài viết Google Maps cho Ý định trên Android Automotive. Để 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 một ý định đến bất kỳ ứng dụng nào (bao gồm cả Google Maps), hãy xác minh rằng ý định đó có thể được phân giải (xem Yêu cầu ý định). Đ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 hoạt động.

Thực hiện các lệnh của xe

Quyền truy cập vào các thuộc tính của xe để đọc và ghi được cung cấp thông qua CarPropertyManager. Các loại thuộc tính xe, cách triển khai và các thông tin chi tiết khác được giải thích trong phần Cấu hình thuộc tính. Để biết thông tin mô tả chính xác về các thuộc tính mà Android hỗ trợ, tốt nhất 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à thuộc tính dành riêng cho nhà cung cấp, loại dữ liệu, chế độ thay đổi, đơn vị và định nghĩa quyền truy cập đọc/ghi.

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

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

Sau đây là ví dụ minh hoạ cách đọc tốc độ xe:

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 xe

Sau đây là ví dụ minh hoạ 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 nhắn tin

VIA phải xử lý tin nhắn đến theo quy trình "nhấn để đọc" được mô tả trong phần Nhấn để đọc của Trợ lý thoại. Quy trình này có thể tuỳ ý xử lý việc gửi thư trả lời 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 ngay trên ô tô hoặc qua Bluetooth.

Xử lý lệnh gọi

Tương tự, VIA có thể sử dụng TelephonyManager để thực hiện cuộc gọi điện thoại và gọi đến số hộp thư thoại của người dùng. Trong những trường hợp này, các 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 Car Dialer. Trong mọi trường hợp, ứng dụng Car Dialer 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

Để biết danh sách các điểm tích hợp khác có thể có giữa VIA và hệ thống, hãy xem danh sách ý đị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ỳ 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 sống động (hiển thị nội dung hình ảnh)

Khi giúp người dùng hiểu rõ hơn hoặc thực hiện hành động, VIA có thể cung cấp nội dung hình ảnh 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ữ nội dung đó đơn giản, ngắn gọn và có thể hành động. Để biết thông tin chi tiết về nguyên tắc giao diện người dùng/trải nghiệm người dùng đối với các hành động sống động, hãy xem phần Trợ lý được tải trước: Hướng dẫn về trải nghiệm người dùng.

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