Sử dụng Instrument Cluster API (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 điều hướ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.
CarManager cho phép các ứng dụng bên ngoài khởi chạy một hoạt động trên Cụm đồng hồ và nhận lệnh gọi lại khi Cụm đồng hồ đã sẵn sàng hiển thị các hoạt động.android:singleUser. Tại bất kỳ thời điểm nào, tối đa một phiên bản của dịch vụ sẽ chạy trên hệ thống Android.Điều kiện tiên quyết
Trước khi tiếp tục, hãy nhớ chuẩn bị những yếu tố 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 phần 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 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). Thiết bị Android có thể chạy Android 9 (trở lên). Thiết bị này phải có màn hình riêng và có khả năng nhấp nháy màn hình bằng các bản dựng mới của Android.
- Cụm đồng hồ là một trong những loại sau:
- Màn hình phụ thực tế được gắn 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. Mọi đơn vị tính toán được kết nối với HU thông qua kết nối mạng, có khả năng 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 mọi bản phân phối Android AOSP, 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, sau đó chọn Mô phỏng màn hình phụ. Cấu hình này tương đương với việc gắn một màn hình phụ thực tế, với hạn chế là màn hình này sẽ được đặt chồng lên màn hình chính.
- Cụm đo lường được mô phỏng. Trình mô phỏng Android đi kèm với AAOS cung cấp một lựa chọn để hiển thị cụm đo lường 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ụ cụm đồng hồ của OEM

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 một thời điểm nhất định 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ụ, những ứng dụng chạy trong ô tô có thể truy cập vào các trình quản lý này.
Đối với việc triển khai cụm đồng hồ, các OEM trong ngành ô tô phải tạo một chế độ triển khai tuỳ chỉnh của InstrumentClusterRendererService và cập nhật ClusterRenderingService.
Khi hiển thị một Cụm công cụ, trong quá trình khởi động, CarService sẽ đọc khoá InstrumentClusterRendererService của ClusterRenderingService để xác định vị trí của một quy trình triển khai InstrumentClusterService. Trong AOSP, mục này trỏ đến dịch vụ kết xuất việc triển khai cụm mẫu Navigation State API:
<string name="instrumentClusterRendererService"> android.car.cluster/.ClusterRenderingService </string>
Dịch vụ được đề cập trong mục này sẽ được khởi tạo 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 Cụm công cụ từ InstrumentClusterRenderingService được liên kết.
(Trong trường hợp này, bound (được liên kết) đề cập đến Các dịch vụ của Android.)
Dịch vụ Cụm đồng hồ
Các OEM phải tạo một Gói Android (APK) chứa một lớp con của ClusterRenderingService.
Lớp này có 2 mục đích:
- Cung cấp giao diện Android và thiết bị kết xuất Cụm công cụ (mục đích của trang này).
- Nhận và hiển thị thông tin cập nhật về trạng thái chỉ đườ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 OEM phải khởi động màn hình phụ dùng để hiển thị thông tin trên màn hình trong khoang xe và truyền đạt thông tin này đến CarService bằng cách gọi đến các phương thức InstrumentClusterRendererService.setClusterActivityOptions() và InstrumentClusterRendererService.setClusterActivityState().
Đối với hàm thứ hai, dịch vụ Cụm công cụ phải cung cấp một cách triển khai giao diện ClusterRenderingService nhận các sự kiện cập nhật trạng thái điều hướng, được mã hoá dưới dạng 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 hiển thị các bản cập nhật:
Trong hình minh hoạ này, màu sắc biểu thị những điều sau:
- Màu vàng.
CarServicevàCarNavigationStatusManagerdo nền tảng Android cung cấp. Để tìm hiểu thêm, hãy xem Ô tô và CAR_NAVIGATION_SERVICE. - Lục lam.
InstrumentClusterRendererServicedo OEM triển khai. - Tím. Ứng dụng Điều hướng do Google và các nhà phát triển bên thứ ba triển khai.
- Xanh lục.
CarAppFocusManager. Để tìm hiểu thêm, hãy xem phần 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:
CarServicekhởi chạyInstrumentClusterRenderingService.- Trong quá trình khởi tạo,
InstrumentClusterRenderingServicesẽ cập nhậtCarServicebằng:- Các thuộc tính hiển thị của Cụm cô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 ở phần sau).
- Các lựa chọn về hoạt động cần thiết để khởi 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 phần ActivityOptions.
- Một ứng dụng chỉ đường (chẳng hạn như Google Maps cho Android Automotive hoặc bất kỳ ứng dụng bản đồ nào có các quyền bắt buộc):
- Lấy
CarAppFocusManagerbằng lớp Car từ car-lib. - Trước khi chỉ đường từng chặng bắt đầu, hãy gọi
CarAppFocusManager.requestFocus()để truyềnCarAppFocusManager.APP_FOCUS_TYPE_NAVIGATIONdưới dạng tham sốappType.
- Lấy
CarAppFocusManagertruyền đạt yêu cầu này choCarService. Nếu được cấp quyền,CarServicesẽ kiểm tra gói ứng dụng điều hướng và xác định vị trí một hoạt động được đánh dấu bằng danh mụcandroid.car.cluster.NAVIGATION.- Nếu tìm thấy, ứng dụng điều hướng sẽ sử dụng
ActivityOptionsdoInstrumentClusterRenderingServicebáo cáo để chạy hoạt động và thêm các thuộc tính hiển thị Cụm cô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à một 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ụ Cụm công cụ chạy, ngay cả trong quá trình khởi tạo 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 Cụm công cụ có trong ảnh hệ thống Android mới đượcCarServiceliê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ụ:
- Viết một lớp mở rộng từ ClusterRenderingService rồi thêm một mục nhập tương ứng vào tệp
AndroidManifest.xml. Lớp này kiểm soát màn hình Cụm đồng hồ và có thể (không bắt buộc) hiển thị dữ liệu API Trạng thái điều hướng. - Trong
onCreate(), hãy dùng dịch vụ này để khởi động 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ẽ được dùng cho Cụm đồng hồ.
- Tạo một màn hình ảo để ứng dụng Cụm công cụ kết xuất và truyền hình ảnh đã kết xuất đến một thiết bị bên ngoài (bằng cách sử dụng định dạng truyền phát video, chẳng hạn như H.264).
- Khi màn hình nêu trên đã sẵn sàng, dịch vụ này phải gọi
InstrumentClusterRenderingService#setClusterActivityLaunchOptions()để xác định chính xácActivityOptionsphải được dùng để hiển thị một Hoạt động trên Cụm công cụ. Sử dụng các tham số sau:category.ClusterRenderingService.ActivityOptions.Một thực thểActivityOptionscó thể dùng để chạy một Hoạt động trong Nhóm dụng cụ. Ví dụ: từ quá trình triển khai Nhóm công cụ mẫu trên AOSP:getService().setClusterActivityLaunchOptions( CATEGORY_NAVIGATION, ActivityOptions.makeBasic() .setLaunchDisplayId(displayId));
- Khi Cụm cô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:categoryClusterRenderingService.stateGói được tạo bằng ClusterRenderingService. Hãy nhớ cung cấp dữ liệu này:visibleChỉ định Cụm công cụ ở trạng thái hiển thị và sẵn sàng hiển thị nội dung.unobscuredBoundsMột hình chữ nhật xác định vùng bên trong màn hình Cụm cô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ó mặt số và đồng hồ đo.
- 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).
Mẫu triển khai InstrumentClusterRenderingService
Ví dụ sau đây trình bày một cách triển khai InstrumentClusterRenderingService, tạo ra một VirtualDisplay để trình bày nội dung Cụm công cụ trên một màn hình thực từ xa.
Ngoài ra, mã này có thể truyền displayId của màn hình phụ vật lý được kết nối với HU, nếu bạn biết có màn hình phụ.
/** * 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
API CarAppFocusManager cung cấp một phương thức có tên là getAppTypeOwner(), cho phép dịch vụ cụm do OEM viết biết ứng dụng chỉ đường nào có tiêu điểm điều hướng tại một thời điểm bất kỳ. OEM có thể dùng phương thức CarAppFocusManager#addFocusListener() hiện có, rồi dùng getAppTypeOwner() để tìm hiểu xem ứng dụng nào đang được lấy tiêu điểm. Với thông tin này, các OEM có thể:
- Chuyển hoạt động xuất hiện trong cụm sang hoạt động cụm do ứng dụng chỉ đường cung cấp, giữ tiêu điểm.
- 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 làm tiêu điểm không có hoạt động cụm (hoặc nếu hoạt động đó bị vô hiệu hoá), thì OEM 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 chỉ đường của cụm.
Sử dụng CarAppFocusManager để đặt và lắng nghe tiêu điểm ứng dụng hiện tại, chẳng hạn như chế độ điều hướng đang hoạt động hoặc lệnh thoại. Thông thường, chỉ có một phiên bản của ứng dụng như vậy đang chạy (hoặc được lấy làm 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 của ứ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 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 khách.
Để xác định ứng dụng khách điều hướng, các OEM 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ữ theo 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:
- Tạo và cài đặt Android Auto trên một HU được hỗ trợ. Làm theo hướng dẫn về cách tạo và cài đặt Android dành riêng cho thiết bị của bạn. Để biết hướng dẫn, hãy xem bài viết Sử dụng bảng tham khảo.
- Kết nối màn hình phụ thực tế với HU (nếu được hỗ trợ) hoặc bật HU phụ ảo:
- Chọn Chế độ nhà phát triển trong ứng dụng Cài đặt.
- 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ụ.
- Khởi động lại HU
- Cách chạy ứng dụng KitchenSink:
- Mở ngăn.
- Chuyển đến Inst. Cluster (Cụm thiết bị).
- Nhấp vào BẮT ĐẦU SIÊU DỮ LIỆU.
KitchenSink yêu cầu tiêu điểm NAVIGATION, hướng dẫn dịch vụ DirectRenderingCluster hiển thị giao diện người dùng mô phỏng trên Cụm công cụ.