适用于 OEM 的集成指南

本文介绍了如何在 VHAL 中处理旋转输入、如何配置您的 build 以包含旋转服务,以及如何跨所有应用自定义旋转体验。对于预安装的 OEM 应用(例如 OEM 提供的启动器),请参阅车载设备界面库 (car-ui-library)

VHAL

旋控器支持以下操作:

  • 向上、向下、向左和向右轻推。
  • 顺时针和逆时针旋转。
  • 按中心按钮。
  • 按返回按钮。
  • 按主屏幕按钮。
  • 按其他按钮,例如“电话”和“媒体”。

如需查看有关系统属性和相应 int32Values 的文档,请参阅 hardware/interfaces/automotive/vehicle/2.0/types.hal

VHAL 应该处理下列操作:

轻推

当用户向右推动旋控器时,VHAL 应使用带有以下 int32ValuesHW_KEY_INPUT 属性向 Android 发送一个事件:

  1. ACTION_DOWN
  2. KEYCODE_SYSTEM_NAVIGATION_RIGHT
  3. 目标屏幕。

当用户松开旋控器时,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

用户可以在垂直方向上推动旋控器,然后再松开。 例如,在以下情况下:

垂直方向
图 1. 垂直方向

这应该生成以下事件序列:

  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

当旋控器保持在某一个方向时,不应生成重复的事件。

旋转

当用户顺时针旋转旋控器一个定位点(点击)时,VHAL 应使用带有以下 int32ValuesHW_ROTARY_INPUT 属性向 Android 发送一个事件:

  1. ROTARY_INPUT_TYPE_SYSTEM_NAVIGATION
  2. 一 (1) 个定位点。
  3. 目标屏幕。

事件的时间戳应设置为经过的时间(以纳秒为单位)。

逆时针旋转一 (1) 个定位点应生成相同的事件,但定位点数应为 -1。

如果同一方向上接二连三地出现多个旋转定位点,VHAL 应将这些定位点合并为一个事件,以免让系统承受过多的事件。在这种情况下,事件的时间戳应是出现第一次旋转定位点的时间。int32Values 应包括旋转连续定位点之间的纳秒数。

例如,以下旋转序列:

  • 在时间 t0 时,用户逆时针旋转一个定位点。
  • 在时间 t0 + 5ns 时,用户逆时针旋转一个定位点。
  • 在 t0 + 8ns 时,用户逆时针旋转一个定位点。

应生成下列事件:

  • 属性:HW_ROTARY_INPUT
  • 时间戳:t0
  • int32Values
    1. ROTARY_INPUT_TYPE_SYSTEM_NAVIGATION
    2. -3(三个逆时针定位点)。
    3. 目标屏幕。
    4. 第 1 个和第 2 个定位点相隔 5ns。
    5. 第 2 个和第 3 个定位点相隔 3ns。

中心按钮

当用户按中心按钮时,VHAL 应使用带有以下 int32ValuesHW_KEY_INPUT 属性向 Android 发送一个事件:

  1. ACTION_DOWN
  2. KEYCODE_DPAD_CENTER
  3. 目标屏幕。

当用户松开旋控器时,VHAL 应使用与 ACTION_UP 相同的属性和键码。

按住中心按钮不放时,不应生成重复的事件。

返回按钮

当用户按返回按钮时,VHAL 使用带有以下 int32ValuesHW_KEY_INPUT 属性向 Android 发送一个事件:

  1. ACTION_DOWN
  2. KEYCODE_BACK
  3. 目标屏幕。

当用户松开旋控器时,VHAL 应使用与 ACTION_UP 相同的属性和键码。

按住中心按钮不放时,不应生成重复的事件。

主屏幕按钮

像处理返回按钮一样处理主屏幕按钮,但要使用 KEYCODE_HOME,而不是 KEYCODE_BACK

其他按钮

如果旋控器包含任何其他按钮,VHAL 可以用 OEM 喜好的任何方式处理它们,因为 Android 不会将它们视为旋转的一部分。这些按钮的处理方式通常与返回按钮和主屏幕按钮类似,但键码不同。例如,KEYCODE_CALLKEYCODE_MUSIC

build 配置

旋转导航由名为 RotaryService 的无障碍服务提供。如需将此服务添加到设备的系统映像中,请将以下行添加到 makefile 中:

PRODUCT_PACKAGES += CarRotaryController

不妨在调试 build 中添加以下软件包:

  • RotaryPlayground:一个旋转参考应用(请参阅 RotaryPlayground)。
  • RotaryIME:一个演示性的旋转 IME(请参阅输入法)。
  • CarRotaryImeRRORotaryIME 的叠加层。

旋转服务会在设备启动以及用户切换时自动启用。这可以确保用户在设置过程中能使用旋控器。

如果您对带有旋控器和不带旋控器的汽车使用相同的 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
    1. 缓存已停用。
    2. 缓存将会在一段时间后过期(见下文)。
    3. 缓存永不过期。
  • 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
    1. 缓存已停用。
    2. 缓存会在一段时间后过期(见下文)。
    3. 缓存永不过期。
  • 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 是否应让控制器加速旋转一个定位点的时间间隔(以毫秒为单位)。如果此定位点与前一个旋转定位点之间的时间间隔小于这个值,系统会将其视为 3 个旋转定位点。将这个值设置为 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_focusedandroid:state_pressed)组合调整背景。当用户使用旋控器聚焦某个视图时,android:state_focused 将是 true,但 android:state_pressed 将是 false。如果用户随后按旋控器上的中心按钮,并且按住该按钮不放,android:state_focusedandroid: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:轮廓的粗细。

有时,我们会对按钮使用纯色背景,使其吸引用户的注意,如下例所示。这可能会使焦点突出显示标志不够显眼。

具有纯色背景的按钮
图 2. 具有纯色背景的按钮

在这种情况下,开发者可以指定一个使用辅助颜色的自定义焦点突出显示标志:
  • (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 的选择没有影响。如果这项资源未被叠加,则不会进行 IME 切换。Carboard 不支持旋转,因此,如果 OEM 未提供旋转 IME,用户就无法通过旋控器输入文本。

RotaryIME 是一个演示性的旋转 IME。它虽然是基本 IME,但足以支持我们尝试上述的自动 IME 切换。您可以在 packages/apps/Car/tests/RotaryIME/ 中找到 RotaryIME 的源代码。

屏幕外轻推

默认情况下,当用户尝试轻推到屏幕边缘之外时,系统不会执行任何操作。通过指定以下任何组合,OEM 可以配置针对四个方向中的每个方向应执行的操作:

  1. AccessibilityService 定义的全局操作,如 GLOBAL_ACTION_BACK
  2. 键码,如 KEYCODE_BACK
  3. 用于启动用网址表示的 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.xmlconfig_showHeadsUpNotificationOnBottom 布尔值资源的值相同
  • (Android 11 QPR3、Android 11 Car、Android 12)
    notification_headsup_card_margin_horizontal:浮动通知窗口的左外边距和右外边距。此资源的值必须与 packages/apps/Car/Notification/res/values/dimens.xmlnotification_headsup_card_margin_horizontal 尺寸资源的值相同
  • (Android 12)
    excluded_application_overlay_window_titles:不应被视为叠加窗口的窗口的标题数组。其中应包括表示 TaskViewsTaskDisplayAreas 的应用窗口的标题。默认情况下,此列表仅包含“地图”。

您可以叠加以下 RotaryService 资源:

  • (Android 11 QPR3、Android 11 Car、Android 12)
    long_press_ms:整数值,用于表示必须按住中心按钮多少毫秒才能触发长按操作。零表示应使用系统默认的长按超时。这是默认值。