API Cụm đồng hồ

Sử dụng Instrument Cluster API (API Nhóm dụng cụ) (một API Android) để hiển thị các ứng dụng chỉ đường, bao gồm cả Google Maps, trên màn hình phụ trong ô tô, chẳng hạn như phía sau vô lăng trên bảng điều khiển. Trang này mô tả cách tạo một dịch vụ để kiểm soát màn hình phụ đó và tích hợp dịch vụ này với CarService để các ứng dụng chỉ đường có thể hiển thị giao diện người dùng.

Thuật ngữ

Các thuật ngữ sau đây được dùng trên trang này.

CarInstrumentClusterManager
Một thực thể của CarManager cho phép các ứng dụng bên ngoài chạy một hoạt động trên Nhóm dụng cụ và nhận lệnh gọi lại khi Nhóm dụng cụ đã sẵn sàng hiển thị các hoạt động.
CarManager
Lớp cơ sở của tất cả trình quản lý mà các ứng dụng bên ngoài dùng để tương tác với các dịch vụ dành riêng cho ô tô do CarService triển khai.
CarService
Dịch vụ Nền tảng Android cung cấp khả năng giao tiếp giữa các ứng dụng bên ngoài (bao gồm cả Google Maps) và các tính năng dành riêng cho ô tô, chẳng hạn như quyền truy cập vào Nhóm dụng cụ.
Đích đến
Đích đến cuối cùng mà xe sẽ đi đến.
Thời gian đến dự kiến (ETA)
Thời gian đến dự kiến tại một đích đến.
Đầu phát trung tâm (HU)
Đơn vị tính toán chính được nhúng trong ô tô. HU chạy tất cả mã Android và được kết nối với màn hình trung tâm trong ô tô.
Nhóm dụng cụ
Màn hình phụ nằm phía sau vô lăng và giữa các dụng cụ trong ô tô. Đây có thể là một đơn vị tính toán độc lập được kết nối với HU thông qua mạng nội bộ của ô tô (CAN bus) hoặc một màn hình phụ được đính kèm vào HU.
InstrumentClusterRenderingService
Lớp cơ sở cho dịch vụ dùng để giao tiếp với màn hình Nhóm dụng cụ. Nhà sản xuất thiết bị gốc phải cung cấp một phần mở rộng của lớp này tương tác với phần cứng dành riêng cho nhà sản xuất thiết bị gốc.
Ứng dụng KitchenSink
Ứng dụng kiểm thử có trong Android Automotive.
Hành trình
Một đường dẫn cụ thể mà xe đi theo để đến đích.
Dịch vụ Singleton
Một dịch vụ Android có thuộc tính android:singleUser. Tại bất kỳ thời điểm nào, hệ thống Android sẽ chạy tối đa một thực thể của dịch vụ.

Điều kiện tiên quyết

Trước khi tiếp tục, hãy đảm bảo bạn có các thành phần sau:

  • Môi trường phát triển Android. Để thiết lập môi trường phát triển Android, hãy xem Yêu cầu về bản dựng.
  • Tải mã nguồn Android xuống. Tải phiên bản mới nhất của mã nguồn Android xuống từ nhánh pi-car-release (hoặc phiên bản mới hơn) tại https://android.googlesource.com.
  • Đầu phát trung tâm (HU). Một thiết bị Android có thể chạy Android 9 (hoặc phiên bản mới hơn). Thiết bị này phải có màn hình riêng và có thể chuyển màn hình sang các bản dựng mới của Android.
  • Nhóm dụng cụ là một trong những thành phần sau:
    • Màn hình phụ vật lý được đính kèm vào HU. Nếu phần cứng và nhân của thiết bị hỗ trợ việc quản lý nhiều màn hình.
    • Đơn vị độc lập. Bất kỳ đơn vị tính toán nào được kết nối với HU thông qua kết nối mạng, có thể nhận và hiển thị luồng video trên màn hình riêng.
    • Màn hình mô phỏng. Trong quá trình phát triển, bạn có thể sử dụng một trong các môi trường mô phỏng sau:
      • Màn hình phụ mô phỏng. Để bật màn hình phụ mô phỏng trên bất kỳ bản phân phối Android AOSP nào, hãy chuyển đến phần cài đặt Tuỳ chọn cho nhà phát triển trong ứng dụng hệ thống Cài đặt rồi chọn Mô phỏng màn hình phụ Cấu hình này tương đương với việc đính kèm màn hình phụ vật lý, với hạn chế là màn hình này được chồng lên màn hình chính.
      • Nhóm dụng cụ mô phỏng. Trình mô phỏng Android có trong AAOS cung cấp một tuỳ chọn để hiển thị nhóm dụng cụ bằng ClusterRenderingService.

Cấu trúc tích hợp

Thành phần tích hợp

Mọi hoạt động tích hợp Instrument Cluster API đều bao gồm 3 thành phần sau:

  • CarService
  • Ứng dụng chỉ đường
  • Dịch vụ Nhóm dụng cụ của nhà sản xuất thiết bị gốc

Thành phần tích hợp

CarService

CarService đóng vai trò trung gian giữa các ứng dụng chỉ đường và ô tô, đảm bảo rằng chỉ có một ứng dụng chỉ đường hoạt động tại bất kỳ thời điểm nào và chỉ những ứng dụng có quyền android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL mới có thể gửi dữ liệu đến ô tô.

CarService khởi động tất cả các dịch vụ dành riêng cho ô tô và cung cấp quyền truy cập vào các dịch vụ này thông qua một loạt trình quản lý. Để tương tác với các dịch vụ, các ứng dụng chạy trong ô tô có thể truy cập vào các trình quản lý này.

Để triển khai nhóm dụng cụ, các nhà sản xuất thiết bị gốc ô tô phải tạo một cách triển khai tuỳ chỉnh của InstrumentClusterRendererService và cập nhật ClusterRenderingService.

Khi kết xuất Nhóm dụng cụ, trong quá trình khởi động, CarService sẽ đọc khoá InstrumentClusterRendererService của ClusterRenderingService để xác định vị trí triển khai InstrumentClusterService. Trong AOSP, mục này trỏ đến dịch vụ kết xuất mẫu triển khai cụm API Trạng thái điều hướng:

<string name="instrumentClusterRendererService">
android.car.cluster/.ClusterRenderingService
</string>

Dịch vụ được đề cập trong mục này được khởi chạy và liên kết với CarService. Khi các ứng dụng chỉ đường (chẳng hạn như Google Maps) yêu cầu CarInstrumentClusterManager, CarService sẽ cung cấp một trình quản lý cập nhật trạng thái Nhóm dụng cụ từ InstrumentClusterRenderingService được liên kết. (Trong trường hợp này, liên kết đề cập đến Dịch vụ Android.)

Dịch vụ Nhóm dụng cụ

Nhà sản xuất thiết bị gốc phải tạo một Gói Android (APK) chứa một lớp con của ClusterRenderingService.

Lớp này phục vụ 2 mục đích:

  • Cung cấp giao diện Android và thiết bị kết xuất Nhóm dụng cụ (mục đích của trang này).
  • Nhận và kết xuất thông tin cập nhật về trạng thái điều hướng, chẳng hạn như hướng dẫn chỉ đường từng chặng.

Đối với mục đích đầu tiên, việc triển khai InstrumentClusterRendererService của nhà sản xuất thiết bị gốc phải khởi chạy màn hình phụ dùng để kết xuất thông tin trên màn hình trong cabin ô tô và truyền đạt thông tin này đến CarService bằng cách gọi các phương thức InstrumentClusterRendererService.setClusterActivityOptions()InstrumentClusterRendererService.setClusterActivityState().

Đối với chức năng thứ hai, dịch vụ Nhóm dụng cụ phải cung cấp một cách triển khai giao diện ClusterRenderingService nhận cập nhật trạng thái điều hướng sự kiện, được mã hoá dưới dạng một eventType và dữ liệu sự kiện được mã hoá trong một gói.

Trình tự tích hợp

Sơ đồ sau đây minh hoạ việc triển khai trạng thái điều hướng kết xuất thông tin cập nhật:

Trình tự tích hợp

Trong hình minh hoạ này, màu sắc biểu thị như sau:

  • Màu vàng. CarServiceCarNavigationStatusManager do nền tảng Android cung cấp. Để tìm hiểu thêm, hãy xem bài viết Ô tôCAR_NAVIGATION_SERVICE.
  • Màu lục lam. InstrumentClusterRendererService do nhà sản xuất thiết bị gốc triển khai.
  • Màu tím. Ứng dụng Chỉ đường do Google và nhà phát triển bên thứ ba triển khai.
  • Màu xanh lục. CarAppFocusManager. Để tìm hiểu thêm, hãy xem Sử dụng CarAppFocusManager API bên dưới và CarAppFocusManager.

Luồng thông tin Trạng thái điều hướng tuân theo trình tự sau:

  1. CarService khởi chạy InstrumentClusterRenderingService.
  2. Trong quá trình khởi chạy, InstrumentClusterRenderingService sẽ cập nhật CarService bằng:
    1. Thuộc tính hiển thị Nhóm dụng cụ, chẳng hạn như ranh giới không bị che khuất (xem thêm thông tin chi tiết về ranh giới không bị che khuất sau này).
    2. Các tuỳ chọn hoạt động cần thiết để chạy các hoạt động bên trong màn hình Nhóm dụng cụ. Để tìm hiểu thêm, hãy xem bài viết ActivityOptions.
  3. Ứng dụng chỉ đường (chẳng hạn như Google Maps cho Android Automotive hoặc bất kỳ ứng dụng Maps dành cho Android nào có các quyền cần thiết):
    1. Lấy CarAppFocusManager bằng cách sử dụng lớp Car từ car-lib.
    2. Trước khi hướng dẫn chỉ đường từng chặng bắt đầu, hãy gọi đến CarAppFocusManager.requestFocus() để chuyển CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION làm appType tham số.
  4. CarAppFocusManager truyền đạt yêu cầu này đến CarService. Nếu được cấp, CarService sẽ kiểm tra gói ứng dụng chỉ đường và xác định vị trí một hoạt động được đánh dấu bằng danh mục android.car.cluster.NAVIGATION.
  5. Nếu tìm thấy, ứng dụng chỉ đường sẽ sử dụng ActivityOptions do InstrumentClusterRenderingService báo cáo để chạy hoạt động và bao gồm các thuộc tính hiển thị Nhóm dụng cụ dưới dạng phần bổ sung trong ý định.

Tích hợp API

Việc triển khai InstrumentClusterRenderingService phải:

  • Được chỉ định là dịch vụ singleton bằng cách thêm giá trị sau vào AndroidManifest.xml. Điều này là cần thiết để đảm bảo rằng một bản sao duy nhất của dịch vụ Nhóm dụng cụ chạy, ngay cả trong quá trình khởi chạy và chuyển đổi người dùng:
    android:singleUser="true"
  • Giữ quyền hệ thống BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE. Điều này đảm bảo rằng chỉ dịch vụ kết xuất Nhóm dụng cụ được đưa vào dưới dạng một phần của hình ảnh hệ thống Android mới được CarService liên kết:
    <uses-permission android:name="android.car.permission.BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE"/>
    

Triển khai InstrumentClusterRenderingService

Cách tạo dịch vụ:

  1. Viết một lớp mở rộng từ ClusterRenderingService rồi thêm một mục tương ứng vào tệp AndroidManifest.xml. Lớp này kiểm soát màn hình Nhóm dụng cụ và có thể (không bắt buộc) kết xuất dữ liệu Navigation State API.
  2. Trong onCreate(), hãy sử dụng dịch vụ này để khởi chạy quá trình giao tiếp với phần cứng kết xuất. Các lựa chọn bao gồm:
    • Xác định màn hình phụ sẽ dùng cho Nhóm dụng cụ.
    • Tạo màn hình ảo để ứng dụng Nhóm dụng cụ kết xuất và truyền hình ảnh đã kết xuất đến một đơn vị bên ngoài (sử dụng định dạng phát trực tuyến video, chẳng hạn như H.264).
  3. Khi màn hình được chỉ định ở trên đã sẵn sàng, dịch vụ này phải gọi InstrumentClusterRenderingService#setClusterActivityLaunchOptions() để xác định chính xác ActivityOptions phải dùng để hiển thị Hoạt động trên Nhóm dụng cụ. Sử dụng các tham số sau:
    • category. ClusterRenderingService.
    • ActivityOptions. Một thực thể ActivityOptions có thể dùng để chạy Hoạt động trong Nhóm dụng cụ. Ví dụ: từ mẫu triển khai Nhóm dụng cụ trên AOSP:
      getService().setClusterActivityLaunchOptions(
        CATEGORY_NAVIGATION,
        ActivityOptions.makeBasic()
            .setLaunchDisplayId(displayId));
  4. Khi Nhóm dụng cụ đã sẵn sàng hiển thị các hoạt động, dịch vụ này phải gọi InstrumentClusterRenderingService#setClusterActivityState(). Sử dụng các tham số sau:
    • category ClusterRenderingService.
    • state Gói được tạo bằng ClusterRenderingService. Hãy nhớ cung cấp dữ liệu sau:
      • visible Chỉ định Nhóm dụng cụ là có thể nhìn thấy và đã sẵn sàng hiển thị nội dung.
      • unobscuredBounds Một hình chữ nhật xác định khu vực trong màn hình Nhóm dụng cụ mà bạn có thể hiển thị nội dung một cách an toàn. Ví dụ: các khu vực được bao phủ bởi mặt số và đồng hồ đo.
  5. Ghi đè phương thức Service#dump() và báo cáo thông tin trạng thái hữu ích cho việc gỡ lỗi (xem dumpsys để biết thêm thông tin).

Triển khai mẫu InstrumentClusterRenderingService

Ví dụ sau đây trình bày cách triển khai InstrumentClusterRenderingService, tạo VirtualDisplay để trình bày nội dung Nhóm dụng cụ trên màn hình vật lý từ xa.

Ngoài ra, mã này có thể chuyển displayId của màn hình phụ vật lý được kết nối với HU, nếu có.

/**
* Sample {@link InstrumentClusterRenderingService} implementation
*/
public class SampleClusterServiceImpl extends InstrumentClusterRenderingService {
   // Used to retrieve or create displays
   private final DisplayManager mDisplayManager;
   // Unique identifier for the display to be used for instrument
   // cluster
   private final String mUniqueId = UUID.randomUUID().toString();
   // Format of the instrument cluster display
   private static final int DISPLAY_WIDTH = 1280;
   private static final int DISPLAY_HEIGHT = 720;
   private static final int DISPLAY_DPI = 320;
   // Area not covered by instruments
   private static final int DISPLAY_UNOBSCURED_LEFT = 40;
   private static final int DISPLAY_UNOBSCURED_TOP = 0;
   private static final int DISPLAY_UNOBSCURED_RIGHT = 1200;
   private static final int DISPLAY_UNOBSCURED_BOTTOM = 680;
   @Override
   public void onCreate() {
      super.onCreate();
      // Create a virtual display to render instrument cluster activities on
      mDisplayManager = getSystemService(DisplayManager.class);
      VirtualDisplay display = mDisplayManager.createVirtualDisplay(
          mUniqueId, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_DPI, null,
          0 /* flags */, null, null);
      // Do any additional initialization (e.g.: start a video stream
      // based on this virtual display to present activities on a remote
      // display).
      onDisplayReady(display.getDisplay());
}
private void onDisplayReady(Display display) {
    // Report activity options that should be used to launch activities on
    // the instrument cluster.
    String category = CarInstrumentClusterManager.CATEGORY_NAVIGATION;
    ActionOptions options = ActivityOptions.makeBasic()
        .setLaunchDisplayId(display.getDisplayId());
    setClusterActivityOptions(category, options);
    // Report instrument cluster state.
    Rect unobscuredBounds = new Rect(DISPLAY_UNOBSCURED_LEFT,
        DISPLAY_UNOBSCURED_TOP, DISPLAY_UNOBSCURED_RIGHT,
        DISPLAY_UNOBSCURED_BOTTOM);
    boolean visible = true;
    ClusterActivityState state = ClusterActivityState.create(visible,
       unobscuredBounds);
    setClusterActivityState(category, options);
  }
}

Sử dụng CarAppFocusManager API

CarAppFocusManager API cung cấp một phương thức có tên là getAppTypeOwner(), cho phép dịch vụ cụm do nhà sản xuất thiết bị gốc viết biết ứng dụng chỉ đường nào có tiêu điểm điều hướng tại bất kỳ thời điểm nào. Nhà sản xuất thiết bị gốc có thể sử dụng phương thức CarAppFocusManager#addFocusListener() hiện có, và sau đó sử dụng getAppTypeOwner() để tìm hiểu ứng dụng nào có tiêu điểm. Với thông tin này, nhà sản xuất thiết bị gốc có thể:

  • Chuyển hoạt động được hiển thị trong cụm sang hoạt động cụm do ứng dụng chỉ đường giữ tiêu điểm cung cấp.
  • Có thể phát hiện xem ứng dụng chỉ đường được lấy tiêu điểm có hoạt động cụm hay không. Nếu ứng dụng chỉ đường được lấy tiêu điểm không có hoạt động cụm (hoặc nếu hoạt động đó bị tắt), thì nhà sản xuất thiết bị gốc có thể gửi tín hiệu này đến DIM của ô tô để bỏ qua hoàn toàn khía cạnh điều hướng của cụm.

Sử dụng CarAppFocusManager để đặt và theo dõi tiêu điểm ứng dụng hiện tại, chẳng hạn như điều hướng đang hoạt động hoặc lệnh thoại. Thông thường, chỉ có một thực thể của ứng dụng như vậy đang chạy (hoặc được lấy tiêu điểm) trong hệ thống.

Sử dụng phương thức CarAppFocusManager#addFocusListener(..) để theo dõi các thay đổi về tiêu điểm ứng dụng:

import android.car.CarAppFocusManager;

...

Car car = Car.createCar(this);
mAppFocusManager = (CarAppFocusManager)car.getCarManager(Car.APP_FOCUS_SERVICE);
mAppFocusManager.addFocusListener(this, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);

...

public void onAppFocusChanged(int appType, boolean active) {
    // Use the CarAppFocusManager#getAppTypeOwner(appType) method call
    // to retrieve a list of active package names
}

Sử dụng phương thức CarAppFocusManager#getAppTypeOwner(..) để truy xuất tên gói của chủ sở hữu hiện tại của một loại ứng dụng nhất định đang ở trọng tâm. Phương thức này có thể trả về nhiều tên gói nếu chủ sở hữu hiện tại sử dụng tính năng android:sharedUserId.

import android.car.CarAppFocusManager;

...

Car car = Car.createCar(this);
mAppFocusManager = (CarAppFocusManager)car.getCarManager(Car.APP_FOCUS_SERVICE);
List<String> focusOwnerPackageNames = mAppFocusManager.getAppTypeOwner(
              CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);

if (focusOwnerPackageNames == null || focusOwnerPackageNames.isEmpty()) {
        // No Navigation app has focus
        // OEM may choose to show their default cluster view
} else {
       // focusOwnerPackageNames
       // Use the PackageManager to retrieve the cluster activity for the package(s)
       // returned in focusOwnerPackageNames
}

...

Xác định ứng dụng mẫu

Đối với các ứng dụng chỉ đường dựa trên mẫu sử dụng thư viện Ứng dụng dành cho ô tô, CarAppFocusManager#getAppTypeOwner() sẽ trả về tên gói của máy chủ lưu trữ (ví dụ: com.google.android.apps.automotive.templates.host) vì máy chủ lưu trữ giữ tiêu điểm hệ thống thay cho ứng dụng máy khách.

Để xác định ứng dụng máy khách đang điều hướng, nhà sản xuất thiết bị gốc có thể trích xuất tên gói từ gói trạng thái điều hướng được gửi bằng CarNavigationStatusManager. Tên gói được lưu trữ trong khoá active_app_package_name trong gói mà NavigationRenderer#onNavigationStateChanged(Bundle) nhận được:

// In your NavigationRenderer implementation
@Override
public void onNavigationStateChanged(Bundle bundle) {
    if (bundle.containsKey("active_app_package_name")) {
        String activeAppPackage = bundle.getString("active_app_package_name");
        // Use the package name to identify the navigating app (e.g., com.waze)
    }
}

Phụ lục: Sử dụng ứng dụng mẫu

AOSP cung cấp một ứng dụng mẫu triển khai Navigation State API.

Cách chạy ứng dụng mẫu này:

  1. Tạo và chuyển Android Auto sang HU được hỗ trợ. Sử dụng hướng dẫn tạo và chuyển Android dành riêng cho thiết bị của bạn. Để được hướng dẫn, hãy xem bài viết Sử dụng bảng tham chiếu.
  2. Kết nối màn hình phụ vật lý với HU (nếu được hỗ trợ) hoặc bật HU phụ ảo:
    1. Chọn Chế độ nhà phát triển trong ứng dụng Cài đặt.
    2. Chuyển đến phần Cài đặt > Hệ thống > Nâng cao > Tuỳ chọn cho nhà phát triển > Mô phỏng màn hình phụ.
  3. Khởi động lại HU
  4. Cách chạy ứng dụng KitchenSink:
    1. Mở ngăn.
    2. Chuyển đến Nhóm dụng cụ.
    3. Nhấp vào BẮT ĐẦU SIÊU DỮ LIỆU.

KitchenSink yêu cầu tiêu điểm ĐIỀU HƯỚNG, hướng dẫn dịch vụ DirectRenderingCluster hiển thị giao diện người dùng mô phỏng trên Nhóm dụng cụ.