本文介紹如何在 VHAL 中處理輪播輸入、配置構建以包含輪播服務,以及如何跨所有應用自定義輪播體驗。對於預裝的 OEM 應用程序,例如 OEM 提供的啟動器,請參閱汽車 UI 庫 (car-ui-library) 。
VHAL
旋轉控制器支持以下操作:
- 向上、向下、向左和向右輕推。
- 順時針和逆時針旋轉。
- 按中心按鈕。
- 按返回按鈕。
- 按主頁按鈕。
- 按其他按鈕,例如電話和媒體。
有關係統屬性和相應int32Values的文檔,請參閱hardware/interfaces/automotive/vehicle/2.0/types.hal types.hal 。
VHAL 應處理以下操作:
輕推
當用戶向右推動旋轉控制器時,VHAL 應使用具有以下int32Values的HW_KEY_INPUT屬性向 Android 發送事件:
-
ACTION_DOWN -
KEYCODE_SYSTEM_NAVIGATION_RIGHT - 目標顯示。
當用戶釋放旋轉控制器時,VHAL 應該使用與ACTION_UP相同的屬性和鍵碼。其他方向的輕推應使用相應的鍵碼。
對角線沒有鍵碼,但如果硬件支持對角線,VHAL 可以結合水平和垂直事件來產生對角線。例如,向上和向左輕推應該產生:
-
HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_LEFT ACTION_DOWN -
HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_UP ACTION_DOWN
在任一順序(以及隨後)釋放旋轉控制器應產生:
-
HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_LEFT ACTION_UP -
HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_UP ACTION_UP
用戶可以在釋放之前沿垂直方向推動旋轉控制器。例如,以下場景:

這應該生成以下事件序列:
-
HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_LEFT ACTION_DOWN -
HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_UP ACTION_DOWN -
HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_LEFT ACTION_UP -
HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_UP ACTION_UP
當旋轉控制器保持在一個方向時,不應產生重複事件。
旋轉
當用戶將旋轉控制器順時針旋轉一個定位器(單擊)時,VHAL 應使用具有以下int32Values的HW_ROTARY_INPUT屬性向 Android 發送事件:
-
ROTARY_INPUT_TYPE_SYSTEM_NAVIGATION - 一 (1) 個制動器。
- 目標顯示。
事件的時間戳應設置為以納秒為單位的經過時間。
一 (1) 個止動逆時針旋轉應生成相同的事件,但止動數為 -1。
如果同一方向上的多個旋轉棘爪快速連續發生,VHAL 應將這些棘爪組合成一個事件,以免事件使系統過載。在這種情況下,事件的時間戳應該是第一次旋轉制動發生的時間。 int32Values應包括連續旋轉制動之間的納秒數。
例如,以下旋轉順序:
- 在時間 t0,用戶逆時針旋轉了一個棘爪。
- 在時間 t0 + 5 ns,用戶逆時針旋轉了一個棘爪。
- 在時間 t0 + 8 ns,用戶逆時針旋轉了一個棘爪。
應該生成這個事件:
- 屬性:
HW_ROTARY_INPUT - 時間戳:
t0 -
int32Values:-
ROTARY_INPUT_TYPE_SYSTEM_NAVIGATION - -3(逆時針三個棘爪)。
- 目標顯示。
- 第一個和第二個棘爪之間的 5 ns。
- 第二個和第三個棘爪之間的 3 ns。
-
中心按鈕
當用戶按下中心按鈕時,VHAL 應使用HW_KEY_INPUT屬性和以下int32Values向 Android 發送事件:
-
ACTION_DOWN -
KEYCODE_DPAD_CENTER - 目標顯示。
當用戶釋放旋轉控制器時,VHAL 應該使用與ACTION_UP相同的屬性和鍵碼。
按住 Center 按鈕時不生成重複事件。
返回鍵
當用戶按下返回按鈕時,VHAL 應使用HW_KEY_INPUT屬性和以下int32Values向 Android 發送事件:
-
ACTION_DOWN -
KEYCODE_BACK - 目標顯示。
當用戶釋放旋轉控制器時,VHAL 應該使用與ACTION_UP相同的屬性和鍵碼。
按住 Center 按鈕時不應生成重複事件。
主頁按鈕
像處理 Back 按鈕一樣處理 Home 按鈕,但使用KEYCODE_HOME而不是KEYCODE_BACK 。
其他按鈕
如果旋轉控制器包含任何其他按鈕,VHAL 可以處理它們,但 OEM 喜歡,因為從 Android 的角度來看,它們不被視為旋轉的一部分。這些通常像返回和主頁按鈕一樣處理,但使用不同的鍵碼。例如, KEYCODE_CALL或KEYCODE_MUSIC 。
構建配置
旋轉導航由名為RotaryService的無障礙服務提供。要將此服務包含在您設備的系統映像中,請將以下行添加到您的 makefile 中:
PRODUCT_PACKAGES += CarRotaryController
您可能還希望在調試版本中包含以下包:
-
RotaryPlayground旋轉的參考應用程序(請參閱RotaryPlayground )。 -
RotaryIME演示旋轉 IME(請參閱輸入法編輯器)。 -
CarRotaryImeRRORotaryIME疊加層。
當設備啟動和發生用戶切換時,旋轉服務會自動啟用。這確保了用戶可以在設置期間使用旋轉控制器。
如果您對帶有和不帶有旋轉控制器的汽車使用相同的構建,請如上所示添加CarRotaryController ,以便在構建中包含必要的代碼。為了防止在非旋轉汽車上啟用旋轉服務,請創建一個靜態 RRO 以用空字符串覆蓋rotaryService packages/services/Car/service中的旋轉服務字符串資源。對於旋轉和非旋轉設備,您將使用相同的構建,但具有不同的產品配置。只有後者包括覆蓋。
定制
OEM 可以通過以下位置的資源疊加自定義焦點查找邏輯、焦點突出顯示和一些附加項目:
- car-ui-library 位於
packages/apps/Car/libs/car-ui-lib -
RotaryService位於packages/apps/Car/RotaryController -
Core位於frameworks/base/core
輕推歷史
OEM 可以配置是否啟用兩種類型的微調歷史記錄,如果啟用,還可以配置緩存大小和過期策略。這一切都是通過覆蓋各種 car-ui-library 資源來完成的。
焦點歷史緩存
( Android 11 QPR3、Android 11 汽車、Android 12 )
每個FocusArea緩存將最近聚焦的視圖存儲在FocusArea中,以便在輕推回到FocusArea時可以聚焦。可以通過覆蓋以下 car-ui-library 資源來配置此緩存:
-
car_ui_focus_history_cache_type:- 緩存被禁用。
- 緩存將在一段時間後過期(見下文)。
- 緩存永遠不會過期。
-
car_ui_focus_history_expiration_period_ms:如果緩存類型設置為二 (2)(見上文),則緩存過期前的毫秒數。
FocusArea 歷史緩存
( Android 11 QPR3、Android 11 汽車、Android 12 )
此緩存存儲微移的歷史記錄,以便在相反方向微移可以將焦點返回到相同的FocusArea 。可以通過覆蓋以下 car-ui-library 資源來配置此緩存:
-
car_ui_focus_area_history_cache_type:- 緩存被禁用。
- 緩存會在一段時間後過期(見下文)。
- 緩存永不過期。
-
car_ui_focus_area_history_expiration_period_ms:如果緩存類型設置為 2(見上文),緩存過期前的毫秒數。 -
car_ui_clear_focus_area_history_when_rotating:當用戶旋轉控制器時是否清空緩存。
迴轉
( Android 11 QPR3、Android 11 汽車、Android 12 )
OEM可以覆蓋RotaryService中的兩個整數資源來指定旋轉是否有加速,比如鼠標加速:
-
rotation_acceleration_3x_ms:時間間隔(以毫秒為單位),用於決定 Google 是否應加速控制器旋轉以獲得旋轉制動。如果本次棘爪與上一次轉動棘爪之間的間隔小於該值,則將其視為三個轉動棘爪。將此設置為 2147483647 以禁用 3 倍加速。 -
rotation_acceleration_2x_ms:類似於rotation_acceleration_3x_ms。用於 2 倍加速。將此設置為2147483647以禁用 2 倍加速。
根據 VHAL 的要求,當每個旋轉定位都有單獨的時間戳時,加速效果最佳。如果這些不可用,則RotaryService假定旋轉棘爪是均勻分佈的。
/**
* 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),
焦點亮點
OEM 可以覆蓋 Android 框架中的默認焦點高亮和 car-ui-library 中的幾個焦點高亮資源。
默認焦點突出顯示
Android 框架通過屬性selectableItemBackground提供默認的焦點突出顯示。在Theme.DeviceDefault中,此屬性是指Core中的item_background.xml 。 OEM 可以覆蓋item_background.xml以更改默認的焦點高亮可繪製對象。
這個drawable通常應該是一個StateListDrawable ,它根據不同的狀態組合調整背景,包括android:state_focused和android:state_pressed 。當用戶使用旋轉控制器聚焦視圖時, android:state_focused將為true ,但android:state_pressed將為false 。如果用戶隨後按下旋轉控制器上的 Center 按鈕,則android:state_focused和android:state_pressed都會在用戶按住按鈕時為true 。當用戶釋放按鈕時,只有android:state_focused將保持為true 。
car-ui-library 使用派生自Theme.DeviceDefault的主題。因此,此覆蓋影響使用此庫的應用程序和使用派生自Theme.DeviceDefault的任何主題的應用程序。它不會影響使用不相關主題的應用,例如Theme.Material 。
關注car-ui-library中的高亮資源
OEM 可以覆蓋多個 car-ui-library 資源,以控制焦點突出顯示在具有非矩形(例如圓形或藥丸形)焦點突出顯示的視圖上以及使用不是從Theme.DeviceDefault派生的主題的應用程序中的外觀Theme.DeviceDefault 。這些資源應該被覆蓋,以便焦點突出顯示與默認的焦點突出顯示一致。
( Android 11 QPR3、Android 11 汽車、Android 12 )
以下資源用於指示視圖何時獲得焦點但未按下:
-
car_ui_rotary_focus_fill_color:填充顏色。 -
car_ui_rotary_focus_stroke_color:輪廓顏色。 -
car_ui_rotary_focus_stroke_width:輪廓的厚度。
( Android 11 QPR3、Android 11 汽車、Android 12 )
以下資源用於指示視圖何時獲得焦點和按下:
-
car_ui_rotary_focus_pressed_fill_color:填充顏色。 -
car_ui_rotary_focus_pressed_stroke_color:輪廓顏色。 -
car_ui_rotary_focus_pressed_stroke_width:輪廓的厚度。
有時,按鈕會被賦予純色背景色以引起用戶注意,如示例所示。這可能會使焦點高光難以看到。

- ( Android 11 QPR3、Android 11 汽車、Android 12 )
car_ui_rotary_focus_fill_secondary_color
car_ui_rotary_focus_stroke_secondary_color - (安卓12 )
car_ui_rotary_focus_pressed_fill_secondary_color
car_ui_rotary_focus_pressed_stroke_secondary_color
任何顏色都可以是透明的,並且任何一個維度都可以為零,例如,如果您只需要填充或只需要輪廓。
重點區域亮點
( Android 11 QPR3、Android 11 汽車、Android 12 )
FocusArea可以在其後代之一被聚焦時繪製兩種類型的高亮。如果需要,兩者可以結合使用。此功能在 AOSP 中默認禁用,但可以通過覆蓋 car-ui-library 資源來啟用:
-
car_ui_enable_focus_area_foreground_highlight:在FocusArea及其後代之上繪製高光。在 AOSP 中,這個可繪製對像是圍繞FocusArea的輪廓。 OEM 可以覆蓋car_ui_focus_area_foreground_highlight可繪製對象。 -
car_ui_enable_focus_area_background_highlight:在FocusArea頂部但在其後代之後繪製高光。在 AOSP 中,此可繪製對像是實心填充。 OEM 可以覆蓋car_ui_focus_area_background_highlight可繪製對象。
輸入法編輯器
輸入法編輯器 (IME) 是輸入法。例如,屏幕鍵盤。
( Android 11 QPR3、Android 11 汽車、Android 12 )
OEM 必須覆蓋RotaryService中的default_touch_input_method字符串資源,以指定基於觸摸的 IME 的ComponentName 。例如,如果 OEM 使用 Android Automotive 提供的 IME,他們應該指定com.google.android.apps.automotive.inputmethod/.InputMethodService 。
( Android 11 QPR3、Android 11 汽車、Android 12 )
如果 OEM 專門為旋轉創建了一個 IME,他們應該在rotary_input_method資源中指定它的ComponentName 。如果此資源被覆蓋,則只要用戶通過旋轉控制器的輕推、旋轉和中心按鈕與主機交互,就會使用指定的 IME。當用戶觸摸屏幕時,將使用以前的 IME。 Back 按鈕(和旋轉控制器上的其他按鈕)對 IME 選擇沒有影響。如果不覆蓋此資源,則不會發生 IME 切換。 Carboard 不支持旋轉,因此如果 OEM 未提供旋轉 IME,則用戶無法通過旋轉控制器輸入文本。
RotaryIME是一個演示旋轉輸入法。雖然基本,但嘗試上述自動 IME 切換就足夠了。 RotaryIME的源代碼可以在packages/apps/Car/tests/RotaryIME/中找到。
屏幕外輕推
默認情況下,當用戶試圖從屏幕邊緣移開時,什麼也沒有發生。 OEM 可以通過指定以下任意組合來配置四個方向中的每一個應該發生的情況:
-
AccessibilityService定義的全局操作。例如,GLOBAL_ACTION_BACK。 - 鍵碼,例如
KEYCODE_BACK。 - 啟動表示為 URL 的活動的意圖。
( Android 11 QPR3、Android 11 汽車、Android 12 )
這些是通過在RotaryService中覆蓋以下數組資源來指定的:
-
off_screen_nudge_global_actions:當用戶從屏幕邊緣向上、向下、向左或向右移動時要執行的全局操作數組。如果此數組的相關元素為 -1,則不執行全局操作。 -
off_screen_nudge_key_codes:當用戶從屏幕邊緣向上、向下、向左或向右移動時要注入的單擊事件的鍵代碼數組。如果此數組的相關元素為 0 (KEYCODE_UNKNOWN),則不會注入任何事件。 -
off_screen_nudge_intents:當用戶從屏幕邊緣向上、向下、向左或向右移動時啟動 Activity 的意圖數組。如果此數組的相關元素為空,則不會啟動任何活動。
其他配置
您應該覆蓋以下RotaryService資源:
- ( Android 11 QPR3、Android 11 汽車、Android 12 )
config_showHeadsUpNotificationOnBottom:布爾值,表示抬頭通知是否應顯示在底部而不是頂部。這必須與frameworks/base/packages/CarSystemUI/res/values/config.xml中的config_showHeadsUpNotificationOnBottom布爾資源具有相同的值 - ( Android 11 QPR3、Android 11 汽車、Android 12 )
notification_headsup_card_margin_horizontal:提示通知窗口的左右邊距。這必須與packages/apps/Car/Notification/res/values/dimens.xml的notification_headsup_card_margin_horizontalntal 維度資源具有相同的值 - (安卓12 )
excluded_application_overlay_window_titles:不應被視為覆蓋窗口的窗口標題數組。這應該包括代表TaskViews或TaskDisplayAreas的應用程序窗口的標題。默認情況下,此列表僅包含“地圖”。
您可以覆蓋以下RotaryService資源:
- ( Android 11 QPR3、Android 11 汽車、Android 12 )
long_press_ms:整數值,表示必須按住中心按鈕多少毫秒才能觸髮長按。零表示應使用系統默認的長按超時。這是默認值。