本页介绍了如何在 VHAL 中处理旋转输入,配置您的 build 以包含旋转服务,以及如何自定义所有应用的旋转体验。对于预安装的 OEM 应用(例如 OEM 提供的启动器),请参阅 Car UI 库 (car-ui-library)。
VHAL
旋转控制器支持以下操作
- 向上、向下、向左和向右轻推。
- 顺时针和逆时针旋转。
- 按下“中心”按钮。
- 按下“返回”按钮。
- 按下“主页”按钮。
- 按下其他按钮,例如“电话”和“媒体”。
请参阅 hardware/interfaces/automotive/vehicle/2.0/types.hal
,以获取有关系统属性和相应 int32Values
的文档。
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 纳秒,用户逆时针旋转了一个棘爪。
- 在时间 t0 + 8 纳秒,用户逆时针旋转了一个棘爪。
应生成此事件
- 属性:
HW_ROTARY_INPUT
- 时间戳:
t0
int32Values
:ROTARY_INPUT_TYPE_SYSTEM_NAVIGATION
- -3(逆时针三个棘爪)。
- 目标显示屏。
- 第一个和第二个棘爪之间间隔 5 纳秒。
- 第二个和第三个棘爪之间间隔 3 纳秒。
中心按钮
当用户按下“中心”按钮时,VHAL 应使用具有以下 int32Values
的 HW_KEY_INPUT
属性向 Android 发送事件
ACTION_DOWN
KEYCODE_DPAD_CENTER
- 目标显示屏。
当用户释放旋转控制器时,VHAL 应使用相同的属性和键代码以及 ACTION_UP
。
当“中心”按钮按住不放时,请勿生成重复事件。
返回按钮
当用户按下“返回”按钮时,VHAL 应使用具有以下 int32Values
的 HW_KEY_INPUT
属性向 Android 发送事件
ACTION_DOWN
KEYCODE_BACK
- 目标显示屏。
当用户释放旋转控制器时,VHAL 应使用相同的属性和键代码以及 ACTION_UP
。
当“中心”按钮按住不放时,不应生成重复事件。
主页按钮
处理“主页”按钮的方式应与处理“返回”按钮的方式相同,但使用 KEYCODE_HOME
而不是 KEYCODE_BACK
。
其他按钮
如果旋转控制器包含任何其他按钮,则 VHAL 可以随意处理这些按钮,因为从 Android 的角度来看,这些按钮不被视为旋转控制器的组成部分。这些按钮通常像“返回”和“主页”按钮一样处理,但使用不同的键代码。例如,KEYCODE_CALL
或 KEYCODE_MUSIC
。
构建配置
旋转导航由名为 RotaryService
的辅助功能服务提供。要将此服务包含在您设备的系统映像中,请将以下行添加到您的 makefile
PRODUCT_PACKAGES += CarRotaryController
您可能还希望在调试 build 中包含以下软件包
RotaryPlayground
旋转控制器的参考应用(请参阅 RotaryPlayground)。RotaryIME
演示旋转 IME(请参阅输入法编辑器)。CarRotaryImeRRO
RotaryIME
的叠加层。
旋转服务在设备启动时以及发生用户切换时自动启用。这可确保用户可以在设置期间使用旋转控制器。
如果您对配备和未配备旋转控制器的汽车使用相同的 build,请添加如上所示的 CarRotaryController
,以便必要的代码包含在 build 中。为了防止在非旋转汽车上启用旋转服务,请创建一个静态 RRO 以使用空字符串叠加 packages/services/Car/service
中的 rotaryService
字符串资源。您将对旋转和非旋转设备使用相同的 build,但具有单独的产品配置。只有后者包含叠加层。
自定义
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 Car、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 Car、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 Car、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
以更改默认焦点突出显示可绘制对象。
此可绘制对象通常应为 StateListDrawable
,它会根据状态的不同组合(包括 android:state_focused
和 android:state_pressed
)调整背景。当用户使用旋转控制器聚焦视图时,android:state_focused
将为 true
,但 android:state_pressed
将为 false
。如果用户随后按下旋转控制器上的“中心”按钮,则当用户按住按钮时,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
派生的主题的应用中的外观。应叠加这些资源,以便焦点突出显示与默认焦点突出显示可绘制对象一致。
(Android 11 QPR3、Android 11 Car、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 Car、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 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
任何颜色都可以是透明的,并且如果例如您只想要填充或只想要轮廓,则任一尺寸都可以为零。
FocusArea 突出显示
(Android 11 QPR3、Android 11 Car、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 Car、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 Car、Android 12)
如果 OEM 专门为旋转控制器创建了 IME,则应在 rotary_input_method
资源中指定其 ComponentName
。如果覆盖了此资源,则每当用户通过旋转控制器的轻推、旋转和“中心”按钮与主机交互时,都会使用指定的 IME。当用户触摸屏幕时,将使用之前的 IME。“返回”按钮(和旋转控制器上的其他按钮)对 IME 选择没有影响。Carboard 不支持旋转控制器,因此如果 OEM 未提供旋转 IME,则用户无法通过旋转控制器输入文本。
RotaryIME
是演示旋转 IME。虽然是基本的,但它足以试用上述自动 IME 切换。可以在 packages/apps/Car/tests/RotaryIME/
中找到 RotaryIME
的源代码。
屏幕外轻推
默认情况下,当用户尝试轻推屏幕边缘时,不会发生任何情况。OEM 可以通过指定以下任意组合来配置每个方向应发生的情况
- 由
AccessibilityService
定义的全局操作。例如,GLOBAL_ACTION_BACK
。 - 键代码,例如
KEYCODE_BACK
。 - 表示为网址的用于启动 Activity 的 intent。
(Android 11 QPR3、Android 11 Car、Android 12)
这些由覆盖 RotaryService
中的以下数组资源指定
off_screen_nudge_global_actions
:当用户向上、向下、向左或向右轻推屏幕边缘时要执行的全局操作数组。如果此数组的相关元素为 -1,则不执行全局操作。off_screen_nudge_key_codes
:当用户向上、向下、向左或向右轻推屏幕边缘时要注入的点击事件的键代码数组。如果此数组的相关元素为 0 (KEYCODE_UNKNOWN
),则不注入任何事件。off_screen_nudge_intents
:当用户向上、向下、向左或向右轻推屏幕边缘时要启动 Activity 的 intent 数组。如果此数组的相关元素为空,则不启动任何 Activity。
其他配置
您应覆盖以下 RotaryService
资源
- (Android 11 QPR3、Android 11 Car、Android 12)
config_showHeadsUpNotificationOnBottom
:布尔值,表示浮动通知是否应显示在底部而不是顶部。此值必须与frameworks/base/packages/CarSystemUI/res/values/config.xml
中的config_showHeadsUpNotificationOnBottom
布尔资源的值相同 - (Android 11 QPR3、Android 11 Car、Android 12)
notification_headsup_card_margin_horizontal
:浮动通知窗口的左右边距。此值必须与packages/apps/Car/Notification/res/values/dimens.xml
中的notification_headsup_card_margin_horizontal
尺寸资源的值相同 - (Android 12)
excluded_application_overlay_window_titles
:不应被视为叠加窗口的窗口标题数组。这应包括表示TaskViews
或TaskDisplayAreas
的应用窗口的标题。默认情况下,此列表仅包含“地图”。
您可以覆盖以下 RotaryService
资源
- (Android 11 QPR3、Android 11 Car、Android 12)
long_press_ms
:整数值,表示按住“中心”按钮多少毫秒后触发长按。零表示应使用系统默认长按超时。这是默认值。