Hướng dẫn tích hợp dành cho nhà sản xuất thiết bị gốc (OEM)

Trang này mô tả cách xử lý dữ liệu đầu vào xoay trong VHAL, cách định cấu hình bản dựng để đưa dịch vụ xoay vào và cách tuỳ chỉnh trải nghiệm xoay trên tất cả các ứng dụng. Đối với các ứng dụng được cài đặt sẵn của nhà sản xuất thiết bị gốc (OEM), chẳng hạn như trình chạy do OEM cung cấp, hãy xem Thư viện giao diện người dùng trên ô tô (car-ui-library).

VHAL

Bộ điều khiển xoay hỗ trợ các thao tác sau:

  • Dịch lên trên, xuống dưới, sang trái và phải.
  • Xoay theo chiều kim đồng hồ và ngược chiều kim đồng hồ.
  • Nhấn nút Giữa.
  • Nhấn nút Quay lại.
  • Nhấn nút Màn hình chính.
  • Nhấn các nút khác, chẳng hạn như nút Điện thoại và Nội dung nghe nhìn.

Hãy xem hardware/interfaces/automotive/vehicle/2.0/types.hal để biết tài liệu về các thuộc tính hệ thống và int32Values tương ứng.

VHAL sẽ xử lý các thao tác sau:

Hích tay

Khi người dùng đẩy bộ điều khiển xoay sang phải, VHAL sẽ sử dụng thuộc tính HW_KEY_INPUT với int32Values sau đây để gửi một sự kiện đến Android:

  1. ACTION_DOWN
  2. KEYCODE_SYSTEM_NAVIGATION_RIGHT
  3. Hiển thị mục tiêu.

Khi người dùng nhả bộ điều khiển xoay, VHAL sẽ sử dụng cùng một thuộc tính và mã khoá với ACTION_UP. Các thao tác đẩy theo hướng khác phải sử dụng mã khoá tương ứng.

Không có mã khoá cho các đường chéo, nhưng VHAL có thể kết hợp sự kiện ngang và dọc để tạo ra đường chéo nếu phần cứng hỗ trợ đường chéo. Ví dụ: việc đẩy lên và sang trái sẽ tạo ra:

  • HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_LEFT ACTION_DOWN
  • HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_UP ACTION_DOWN

Việc thả bộ điều khiển xoay theo thứ tự bất kỳ (và sau đó) sẽ tạo ra:

  • HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_LEFT ACTION_UP
  • HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_UP ACTION_UP

Người dùng có thể đẩy bộ điều khiển xoay theo hướng vuông góc trước khi thả ra. Ví dụ: trường hợp sau đây:

Hướng vuông góc
Hình 1. Hướng vuông góc

Thao tác này sẽ tạo ra chuỗi sự kiện sau:

  1. HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_LEFT ACTION_DOWN
  2. HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_UP ACTION_DOWN
  3. HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_LEFT ACTION_UP
  4. HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_UP ACTION_UP

Không được tạo sự kiện lặp lại khi người dùng giữ bộ điều khiển xoay theo một hướng.

Xoay

Khi người dùng xoay bộ điều khiển xoay theo chiều kim đồng hồ một nấc (nhấp), VHAL sẽ sử dụng thuộc tính HW_ROTARY_INPUT với int32Values sau đây để gửi một sự kiện đến Android:

  1. ROTARY_INPUT_TYPE_SYSTEM_NAVIGATION
  2. Một (1) nấc.
  3. Hiển thị mục tiêu.

Dấu thời gian của sự kiện phải được đặt thành thời gian đã trôi qua tính bằng nano giây.

Thao tác xoay ngược chiều kim đồng hồ một (1) nấc sẽ tạo ra cùng một sự kiện nhưng có giá trị -1 cho số nấc.

Nếu nhiều lần xoay theo cùng một hướng xảy ra liên tiếp, VHAL sẽ kết hợp các lần xoay thành một sự kiện duy nhất để không làm quá tải hệ thống bằng các sự kiện. Trong trường hợp này, dấu thời gian của sự kiện phải là khi xảy ra lần xoay có khấc đầu tiên. int32Values phải bao gồm số lượng nano giây giữa các điểm dừng liên tiếp của vòng xoay.

Ví dụ: chuỗi xoay sau:

  • Tại thời điểm t0, người dùng đã xoay một nấc ngược chiều kim đồng hồ.
  • Tại thời điểm t0 + 5 ns, người dùng xoay một nấc ngược chiều kim đồng hồ.
  • Tại thời điểm t0 + 8 ns, người dùng đã xoay một nấc ngược chiều kim đồng hồ.

sẽ tạo ra sự kiện này:

  • Tài sản: HW_ROTARY_INPUT
  • Dấu thời gian: t0
  • int32Values:
    1. ROTARY_INPUT_TYPE_SYSTEM_NAVIGATION
    2. -3 (3 nấc ngược chiều kim đồng hồ).
    3. Hiển thị mục tiêu.
    4. 5 ns giữa điểm dừng thứ nhất và thứ hai.
    5. 3 ns giữa điểm dừng thứ hai và thứ ba.

Nút giữa

Khi người dùng nhấn nút Giữa, VHAL sẽ sử dụng thuộc tính HW_KEY_INPUT với int32Values sau đây để gửi một sự kiện đến Android:

  1. ACTION_DOWN
  2. KEYCODE_DPAD_CENTER
  3. Hiển thị mục tiêu.

Khi người dùng nhả bộ điều khiển xoay, VHAL sẽ sử dụng cùng một thuộc tính và mã khoá với ACTION_UP.

Không tạo sự kiện repeat khi người dùng giữ nút Giữa.

Nút quay lại

Khi người dùng nhấn nút Quay lại, VHAL sẽ sử dụng thuộc tính HW_KEY_INPUT với int32Values sau đây để gửi một sự kiện đến Android:

  1. ACTION_DOWN
  2. KEYCODE_BACK
  3. Hiển thị mục tiêu.

Khi người dùng nhả bộ điều khiển xoay, VHAL sẽ sử dụng cùng một thuộc tính và mã khoá với ACTION_UP.

Không được tạo sự kiện lặp lại khi bạn giữ nút Giữa.

Nút trang chủ

Xử lý nút Màn hình chính như cách bạn xử lý nút Quay lại nhưng dùng KEYCODE_HOME thay vì KEYCODE_BACK.

Các nút khác

Nếu bộ điều khiển xoay có thêm các nút, thì VHAL có thể xử lý các nút đó theo cách mà OEM muốn vì chúng không được coi là một phần của bộ điều khiển xoay theo quan điểm của Android. Các nút này thường được xử lý giống như nút Quay lại và nút Màn hình chính nhưng có mã khoá khác. Ví dụ: KEYCODE_CALL hoặc KEYCODE_MUSIC.

Cấu hình bản dựng

Dịch vụ hỗ trợ tiếp cận RotaryService cung cấp chế độ thao tác xoay. Để thêm dịch vụ này vào hình ảnh hệ thống cho thiết bị của bạn, hãy thêm dòng sau vào makefile:

PRODUCT_PACKAGES += CarRotaryController

Bạn cũng có thể muốn thêm các gói sau vào bản gỡ lỗi:

Dịch vụ xoay sẽ tự động bật khi thiết bị khởi động và khi người dùng chuyển đổi. Điều này đảm bảo người dùng có thể sử dụng bộ điều khiển xoay trong quá trình thiết lập.

Nếu bạn sử dụng cùng một bản dựng cho ô tô có và không có bộ điều khiển xoay, hãy thêm CarRotaryController như minh hoạ ở trên để mã cần thiết được đưa vào bản dựng. Để ngăn dịch vụ xoay được bật trên những ô tô không có bộ điều khiển xoay, hãy tạo một RRO tĩnh để phủ lên tài nguyên chuỗi rotaryService trong packages/services/Car/service bằng một chuỗi trống. Bạn sẽ sử dụng cùng một bản dựng, nhưng có các cấu hình sản phẩm riêng biệt cho thiết bị xoay và thiết bị không xoay. Chỉ có lựa chọn sau mới bao gồm lớp phủ.

Tùy chỉnh

Các OEM có thể tuỳ chỉnh logic tìm tiêu điểm, điểm đánh dấu tiêu điểm và một số mục bổ sung thông qua lớp phủ tài nguyên ở những vị trí sau:

  • car-ui-library nằm trong packages/apps/Car/libs/car-ui-lib
  • RotaryService nằm ở packages/apps/Car/RotaryController
  • Core nằm ở frameworks/base/core

Nhật ký nhắc nhở

Nhà sản xuất thiết bị gốc có thể định cấu hình xem có bật từng loại trong số hai loại nhật ký thông báo hay không và nếu có, thì kích thước bộ nhớ đệm và chính sách hết hạn. Tất cả những việc này được thực hiện bằng cách ghi đè nhiều tài nguyên car-ui-library.

Bộ nhớ đệm nhật ký tiêu điểm

(Android 11 QPR3, Android 11 Car, Android 12)
Bộ nhớ đệm FocusArea này lưu trữ khung hiển thị được lấy tiêu điểm gần đây nhất trong FocusArea để có thể lấy tiêu điểm khi quay lại FocusArea. Bạn có thể định cấu hình bộ nhớ đệm này bằng cách phủ các tài nguyên car-ui-library sau:

  • car_ui_focus_history_cache_type:
    1. Bộ nhớ đệm đã bị tắt.
    2. Bộ nhớ đệm sẽ hết hạn sau một khoảng thời gian (xem bên dưới).
    3. Bộ nhớ đệm sẽ không bao giờ hết hạn.
  • car_ui_focus_history_expiration_period_ms: Số mili giây trước khi bộ nhớ đệm hết hạn nếu loại bộ nhớ đệm được đặt thành 2 (xem ở trên).

Bộ nhớ đệm nhật ký FocusArea

(Android 11 QPR3, Android 11 Car, Android 12)
Bộ nhớ đệm này lưu trữ nhật ký về các thao tác đẩy để thao tác đẩy theo hướng ngược lại có thể trả lại tiêu điểm cho cùng một FocusArea. Bạn có thể định cấu hình bộ nhớ đệm này bằng cách phủ các tài nguyên car-ui-library sau:

  • car_ui_focus_area_history_cache_type:
    1. Bộ nhớ đệm đã bị tắt.
    2. Bộ nhớ đệm sẽ hết hạn sau một khoảng thời gian (xem bên dưới).
    3. Bộ nhớ đệm không bao giờ hết hạn.
  • car_ui_focus_area_history_expiration_period_ms: Số mili giây trước khi bộ nhớ đệm hết hạn nếu loại bộ nhớ đệm được đặt thành 2 (xem ở trên).
  • car_ui_clear_focus_area_history_when_rotating: Có huỷ bộ nhớ đệm hay không khi người dùng xoay bộ điều khiển.

Xoay

(Android 11 QPR3, Android 11 Car, Android 12)
Nhà sản xuất thiết bị gốc có thể ghi đè 2 tài nguyên số nguyên trong RotaryService để chỉ định xem có gia tốc hay không, chẳng hạn như gia tốc chuột, để xoay:

  • rotation_acceleration_3x_ms: Khoảng thời gian (tính bằng mili giây) dùng để quyết định xem Google có nên tăng tốc độ xoay bộ điều khiển cho một điểm dừng xoay hay không. Nếu khoảng thời gian giữa khấc này và khấc xoay trước đó nhỏ hơn giá trị này, thì khoảng thời gian đó sẽ được coi là 3 khấc xoay. Đặt giá trị này thành 2147483647 để tắt tính năng tăng tốc 3×.
  • rotation_acceleration_2x_ms: Tương tự như rotation_acceleration_3x_ms. Dùng để tăng tốc gấp 2 lần. Đặt thành 2147483647 để tắt tính năng tăng tốc gấp 2 lần.

Gia tốc hoạt động hiệu quả nhất khi có dấu thời gian riêng cho từng nấc xoay, theo yêu cầu của VHAL. Nếu không có các thông tin này, RotaryService sẽ giả định rằng các điểm dừng của thao tác xoay được đặt cách đều nhau.

/**
     * Property to feed H/W rotary events to android
     *
     * int32Values[0] : RotaryInputType identifying which rotary knob rotated
     * int32Values[1] : number of detents (clicks), positive for clockwise,
     *                  negative for counterclockwise
     * int32Values[2] : target display defined in VehicleDisplay. Events not
     *                  tied to specific display must be sent to
     *                  VehicleDisplay#MAIN.
     * int32values[3 .. 3 + abs(number of detents) - 2]:
     *                  nanosecond deltas between pairs of consecutive detents,
     *                  if the number of detents is > 1 or < -1
     *
     * VehiclePropValue.timestamp: when the rotation occurred. If the number of
     *                             detents is > 1 or < -1, this is when the
     *                             first detent of rotation occurred.
     *
     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
     * @data_enum RotaryInputType
     * @access VehiclePropertyAccess:READ
     */
    HW_ROTARY_INPUT = (
        0x0A20
        | VehiclePropertyGroup:SYSTEM
        | VehiclePropertyType:INT32_VEC
        | VehicleArea:GLOBAL),

Làm nổi bật tiêu điểm

Nhà sản xuất thiết bị gốc có thể ghi đè chế độ làm nổi bật tiêu điểm mặc định trong khung Android và một số tài nguyên làm nổi bật tiêu điểm trong car-ui-library.

Làm nổi bật tiêu điểm mặc định

Khung Android cung cấp một điểm đánh dấu tiêu điểm mặc định thông qua thuộc tính selectableItemBackground. Trong Theme.DeviceDefault, thuộc tính này đề cập đến item_background.xml trong Core. OEM có thể phủ item_background.xml để thay đổi drawable tiêu điểm nổi bật mặc định.

Thông thường, đối tượng có thể vẽ này phải là StateListDrawable, điều chỉnh nền dựa trên các tổ hợp trạng thái khác nhau, bao gồm android:state_focusedandroid:state_pressed. Khi người dùng sử dụng bộ điều khiển xoay để lấy tiêu điểm một khung hiển thị, android:state_focused sẽ là true, nhưng android:state_pressed sẽ là false. Nếu sau đó người dùng nhấn nút Giữa trên bộ điều khiển xoay, cả android:state_focusedandroid:state_pressed sẽ là true trong khi người dùng giữ nút. Khi người dùng thả nút, chỉ android:state_focused sẽ vẫn còn true.

car-ui-library sử dụng một giao diện bắt nguồn từ Theme.DeviceDefault. Do đó, lớp phủ này ảnh hưởng đến những ứng dụng sử dụng thư viện này và những ứng dụng sử dụng mọi giao diện bắt nguồn từ Theme.DeviceDefault. Việc này sẽ không ảnh hưởng đến những ứng dụng sử dụng một giao diện không liên quan, chẳng hạn như Theme.Material.

Tập trung vào các tài nguyên làm nổi bật trong car-ui-library

Nhà sản xuất thiết bị gốc có thể ghi đè một số tài nguyên car-ui-library để kiểm soát giao diện của điểm nổi bật khi lấy tiêu điểm trên các khung hiển thị có điểm nổi bật khi lấy tiêu điểm không phải hình chữ nhật (chẳng hạn như hình tròn hoặc hình viên thuốc) và trong các ứng dụng sử dụng một giao diện không bắt nguồn từ Theme.DeviceDefault. Bạn nên phủ các tài nguyên này để tiêu điểm nổi bật nhất quán với đối tượng có thể vẽ tiêu điểm nổi bật mặc định.

(Android 11 QPR3, Android 11 Car, Android 12)
Các tài nguyên sau đây được dùng để cho biết thời điểm một khung hiển thị được lấy tiêu điểm nhưng không được nhấn:

  • car_ui_rotary_focus_fill_color: Màu nền.
  • car_ui_rotary_focus_stroke_color: Màu đường viền.
  • car_ui_rotary_focus_stroke_width: Độ dày của đường viền.

(Android 11 QPR3, Android 11 Car, Android 12)
Các tài nguyên sau đây được dùng để cho biết thời điểm một khung hiển thị được lấy tiêu điểm được nhấn:

  • car_ui_rotary_focus_pressed_fill_color: Màu nền.
  • car_ui_rotary_focus_pressed_stroke_color: Màu đường viền.
  • car_ui_rotary_focus_pressed_stroke_width: Độ dày của đường viền.

Đôi khi, một nút sẽ có màu nền đồng nhất để thu hút sự chú ý của người dùng, như trong ví dụ minh hoạ. Điều này có thể khiến bạn khó nhìn thấy điểm đánh dấu tiêu điểm.

Nút có nền đồng nhất
Hình 2. Nút có nền đồng nhất

Trong trường hợp này, nhà phát triển có thể chỉ định một điểm nổi bật tuỳ chỉnh cho tiêu điểm bằng cách sử dụng màu thứ cấp:
  • (Android 11 QPR3, Android 11 Car, Android 12)
    car_ui_rotary_focus_fill_secondary_color
    car_ui_rotary_focus_stroke_secondary_color
  • (Android 12)
    car_ui_rotary_focus_pressed_fill_secondary_color
    car_ui_rotary_focus_pressed_stroke_secondary_color

Mọi màu đều có thể trong suốt và một trong hai phương diện có thể bằng 0 nếu, ví dụ: bạn chỉ muốn có màu nền hoặc chỉ muốn có đường viền.

Giới thiệu nổi bật FocusArea

(Android 11 QPR3, Android 11 Car, Android 12)
FocusArea có thể vẽ hai loại điểm nổi bật khi một trong các thành phần con của nó được lấy làm tiêu điểm. Bạn có thể sử dụng cả hai cùng lúc nếu muốn. Tính năng này bị tắt theo mặc định trong AOSP, nhưng bạn có thể bật bằng cách ghi đè các tài nguyên car-ui-library:

  • car_ui_enable_focus_area_foreground_highlight: Vẽ một điểm nổi bật lên trên FocusArea và các thành phần con của nó. Trong AOSP, thành phần có thể vẽ này là một đường viền xung quanh FocusArea. Các OEM có thể ghi đè hình ảnh có thể vẽ car_ui_focus_area_foreground_highlight.
  • car_ui_enable_focus_area_background_highlight: Vẽ một điểm nổi bật lên trên FocusArea nhưng ở phía sau các thành phần con của nó. Trong AOSP, thành phần có thể vẽ này là một vùng tô màu đồng nhất. Các OEM có thể ghi đè hình ảnh có thể vẽ car_ui_focus_area_background_highlight.

Trình chỉnh sửa phương thức nhập

Trình chỉnh sửa phương thức nhập (IME) là phương thức nhập. Ví dụ: bàn phím ảo.

(Android 11 QPR3, Android 11 Car, Android 12)
Nhà sản xuất thiết bị gốc phải phủ lớp tài nguyên chuỗi default_touch_input_method trong RotaryService để chỉ định ComponentName của IME dựa trên thao tác chạm. Ví dụ: nếu OEM sử dụng IME đi kèm với Android Automotive, thì họ nên chỉ định com.google.android.apps.automotive.inputmethod/.InputMethodService.

(Android 11 QPR3, Android 11 Car, Android 12)
Nếu đã tạo một IME dành riêng cho bộ điều khiển xoay, thì OEM nên chỉ định ComponentName của IME đó trong tài nguyên rotary_input_method. Nếu tài nguyên này được phủ lên, thì IME được chỉ định sẽ được dùng bất cứ khi nào người dùng tương tác với đầu phát trung tâm thông qua thao tác hích, xoay và nhấn nút Giữa của bộ điều khiển xoay. Khi người dùng chạm vào màn hình, IME trước đó sẽ được dùng. Nút Quay lại (và các nút khác trên bộ điều khiển xoay) không ảnh hưởng đến việc chọn IME. Nếu tài nguyên này không được phủ lên, thì sẽ không có hoạt động chuyển đổi IME nào xảy ra. Carboard không hỗ trợ phương thức nhập xoay nên người dùng không thể nhập văn bản thông qua bộ điều khiển xoay nếu OEM chưa cung cấp IME xoay.

RotaryIME là một IME xoay minh hoạ. Mặc dù là cơ bản, nhưng như vậy là đủ để thử tính năng chuyển đổi IME tự động như mô tả ở trên. Bạn có thể tìm thấy mã nguồn cho RotaryIME trong packages/apps/Car/tests/RotaryIME/.

Thông báo nhắc nhở khi màn hình tắt

Theo mặc định, khi người dùng cố gắng đẩy ra khỏi cạnh màn hình, sẽ không có gì xảy ra. OEM có thể định cấu hình những gì sẽ xảy ra cho từng hướng trong số 4 hướng bằng cách chỉ định bất kỳ tổ hợp nào sau đây:

  1. Một thao tác chung do AccessibilityService xác định. Ví dụ: GLOBAL_ACTION_BACK.
  2. Một mã khoá, chẳng hạn như KEYCODE_BACK.
  3. Một ý định chạy một hoạt động được biểu thị dưới dạng URL.

(Android 11 QPR3, Android 11 Car, Android 12)
Các tài nguyên này được chỉ định bằng cách phủ các tài nguyên mảng sau đây trong RotaryService:

  • off_screen_nudge_global_actions: Mảng các thao tác chung cần thực hiện khi người dùng đẩy lên, xuống, trái hoặc phải ra khỏi cạnh màn hình. Không có thao tác chung nào được thực hiện nếu phần tử liên quan của mảng này là -1.
  • off_screen_nudge_key_codes: Mảng mã khoá của các sự kiện nhấp để chèn khi người dùng đẩy lên, xuống, trái hoặc phải ra khỏi cạnh màn hình. Không có sự kiện nào được chèn nếu phần tử liên quan của mảng này là 0 (KEYCODE_UNKNOWN).
  • off_screen_nudge_intents: Mảng ý định khởi chạy một hoạt động khi người dùng đẩy lên, xuống, sang trái hoặc sang phải khỏi cạnh màn hình. Không có hoạt động nào được khởi chạy nếu phần tử có liên quan của mảng này bị trống.

Các cấu hình khác

Bạn nên phủ các tài nguyên RotaryService sau đây:

  • (Android 11 QPR3, Android 11 Car, Android 12)
    config_showHeadsUpNotificationOnBottom: Giá trị boolean để biểu thị việc thông báo dạng nổi sẽ xuất hiện ở dưới cùng thay vì ở trên cùng. Giá trị này phải giống với tài nguyên Boolean config_showHeadsUpNotificationOnBottom trong frameworks/base/packages/CarSystemUI/res/values/config.xml
  • (Android 11 QPR3, Android 11 Car, Android 12)
    notification_headsup_card_margin_horizontal: Lề trái và lề phải cho cửa sổ thông báo dạng nổi. Giá trị này phải giống với tài nguyên dimen notification_headsup_card_margin_horizontal trong packages/apps/Car/Notification/res/values/dimens.xml
  • (Android 12)
    excluded_application_overlay_window_titles: Một mảng tiêu đề của các cửa sổ không được coi là cửa sổ lớp phủ. Điều này bao gồm tiêu đề của các cửa sổ ứng dụng đại diện cho TaskViews hoặc TaskDisplayAreas. Theo mặc định, danh sách này chỉ chứa "Maps".

Bạn có thể phủ lớp tài nguyên RotaryService sau đây:

  • (Android 11 QPR3, Android 11 Car, Android 12)
    long_press_ms: Giá trị số nguyên biểu thị số mili giây mà nút Giữa phải được giữ để kích hoạt thao tác nhấn và giữ. Số 0 cho biết bạn nên sử dụng thời gian chờ mặc định của hệ thống cho thao tác nhấn và giữ. Đây là giá trị mặc định.