This page describes how to process rotary inputs in the VHAL, configure your build to include the rotary service, and how to customize the rotary experience across all apps. For preinstalled OEM apps, such as an OEM-provided launcher, see Car UI Library (car-ui-library).
VHAL
A rotary controller supports the following actions:
- Nudge up, down, left, and right.
- Rotate clockwise and counterclockwise.
- Press the Center button.
- Press the Back button.
- Press the Home button.
- Press other buttons, such as Phone and Media.
See hardware/interfaces/automotive/vehicle/2.0/types.hal
for documentation on
the system properties and corresponding int32Values
.
The VHAL should handle these actions:
Nudge
When the user pushes the rotary controller right, the VHAL should use the
HW_KEY_INPUT
property with the following int32Values
to send an
event to Android:
ACTION_DOWN
KEYCODE_SYSTEM_NAVIGATION_RIGHT
- Target display.
When the user releases the rotary controller, the VHAL should use the same property and
keycode with ACTION_UP
. Nudges in other directions should use the
corresponding keycodes.
There aren't keycodes for diagonals but the VHAL can combine a horizontal and vertical event to produce a diagonal if the hardware supports diagonals. For example, nudging up and to the left should produce:
HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_LEFT ACTION_DOWN
HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_UP ACTION_DOWN
In either order (and subsequently) releasing the rotary controller should produce:
HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_LEFT ACTION_UP
HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_UP ACTION_UP
The user may push the rotary controller in a perpendicular direction before releasing it. For example, the following scenario:
This should generate the following sequence of events:
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
No repeat events should be generated while the rotary controller is held in one direction.
Rotate
When the user rotates the rotary controller clockwise by one detent (click), the VHAL
should use the HW_ROTARY_INPUT
property with the following int32Values
to send an event to Android:
ROTARY_INPUT_TYPE_SYSTEM_NAVIGATION
- One (1) detent.
- Target display.
The timestamp of the event should be set to the elapsed time in nanoseconds.
A one (1) detent counterclockwise rotation should generate the same event but with -1 for the number of detents.
If multiple detents of rotation in the same direction occur in rapid succession, the VHAL
should combine the detents into a single event so as not to overload the system with events.
In this case, the timestamp of the event should be when the first detent of rotation occurred.
The int32Values
should include the number of nanoseconds between consecutive detents
of rotation.
For example, the following sequence of rotations:
- At time t0, the user rotated one detent counterclockwise.
- At time t0 + 5 ns, the user rotated one detent counterclockwise.
- At time t0 + 8 ns, the user rotated one detent counterclockwise.
should generate this event:
- Property:
HW_ROTARY_INPUT
- Timestamp:
t0
int32Values
:ROTARY_INPUT_TYPE_SYSTEM_NAVIGATION
- -3 (three detents counterclockwise).
- Target display.
- 5 ns between first and second detent.
- 3 ns between second and third detent.
Center button
When the user presses the Center button, the VHAL should use the HW_KEY_INPUT
property with the following int32Values
to send an event to Android:
ACTION_DOWN
KEYCODE_DPAD_CENTER
- Target display.
When the user releases the rotary controller, the VHAL should use the same property
and keycode with ACTION_UP
.
Do not generate repeat events when the Center button is held down.
Back button
When the user presses the Back button, the VHAL should use the HW_KEY_INPUT
property with the following int32Values
to send an event to Android:
ACTION_DOWN
KEYCODE_BACK
- Target display.
When the user releases the rotary controller, the VHAL should use the same property
and keycode with ACTION_UP
.
No repeat events should be generated while the Center button is held down.
Home button
Handle the Home button as you would the Back button but with KEYCODE_HOME
instead
of KEYCODE_BACK
.
Other buttons
If the rotary controller includes any additional buttons, the VHAL can handle them however
the OEM likes as they aren't considered part of rotary from the perspective of Android.
These are typically handled like the Back and Home buttons but with different keycodes.
For example, KEYCODE_CALL
or KEYCODE_MUSIC
.
Build configuration
Rotary navigation is provided by an accessibility service called RotaryService
.
To include this service in the system image for your device, add the following line to your
makefile:
PRODUCT_PACKAGES += CarRotaryController
You may also want to include the follow packages in debug builds:
RotaryPlayground
A reference app for rotary (see RotaryPlayground).RotaryIME
A demo rotary IME (see Input Method Editors).CarRotaryImeRRO
The overlay forRotaryIME
.
The rotary service is enabled automatically when the device boots and when a user switch occurs. This ensures that the user can use the rotary controller during set-up.
If you use the same build for cars with and without a rotary controller,
add CarRotaryController
as shown above so that the necessary code is included
in the build. To prevent the rotary service from being enabled on non-rotary cars, create a
static RRO to overlay the rotaryService
string resource in
packages/services/Car/service
with an empty string. You'll use the same build,
but have separate product configurations, for rotary and non-rotary devices. Only the latter
includes the overlay.
Customization
OEMs can customize focus finding logic, the focus highlight, and some additional items through resource overlays in the following locations:
- car-ui-library is located in
packages/apps/Car/libs/car-ui-lib
RotaryService
is located inpackages/apps/Car/RotaryController
Core
is located inframeworks/base/core
Nudge history
The OEM can configure whether or not each of two types of nudge history is enabled and, if so, the cache size and expiration policy. This is all done by overriding various car-ui-library resources.
Focus history cache
(Android 11 QPR3, Android 11 Car,
Android 12)
This per-FocusArea
cache stores the most recently focused view within the
FocusArea
so that it can be focused when nudging back to the FocusArea
.
This cache can be configured by overlaying the following car-ui-library resources:
-
car_ui_focus_history_cache_type
:- Cache is disabled.
- Cache will expire after some time (see below).
- Cache will never expire.
car_ui_focus_history_expiration_period_ms
: How many milliseconds before the cache expires if the cache type is set to two (2) (see above).
FocusArea history cache
(Android 11 QPR3, Android 11 Car,
Android 12)
This cache stores a history of nudges so that nudging in the opposite direction can
return focus to the same FocusArea
. This cache can be configured by overlaying the
following car-ui-library resources:
-
car_ui_focus_area_history_cache_type
:- Cache is disabled.
- Cache expires after some time (see below).
- Cache never expires.
car_ui_focus_area_history_expiration_period_ms
: How many milliseconds before the cache expires if the cache type is set to 2 (see above).car_ui_clear_focus_area_history_when_rotating
: Whether to void the cache when the user rotates the controller.
Rotation
(Android 11 QPR3, Android 11 Car,
Android 12)
The OEM can override two integer resources in the RotaryService
to specify whether
there is acceleration, such as mouse acceleration, for rotation:
rotation_acceleration_3x_ms
: Time interval (in milliseconds) used to decide whether Google should accelerate the controller rotation for a detent of rotation. If the interval between this detent and the previous detent of rotation is smaller than this value, it will be treated as three detents of rotation. Set this to 2147483647 to disable 3× acceleration.rotation_acceleration_2x_ms
: Similar torotation_acceleration_3x_ms
. Used for 2× acceleration. Set this to2147483647
to disable 2× acceleration.
Acceleration works best when there are individual timestamps for each detent of
rotation, as
required
by the VHAL. If these aren't available, the RotaryService
assumes that the detents of
rotation are evenly spaced.
/** * 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),
Focus highlight
The OEM can override the default focus highlight in the Android framework and several focus highlight resources in car-ui-library.
Default focus highlight
The Android framework provides a default focus highlight through the attribute
selectableItemBackground
. In Theme.DeviceDefault
, this
attribute refers to item_background.xml
in Core
. The OEM can overlay
item_background.xml
to change the default focus highlight drawable.
This drawable should typically be a StateListDrawable
, which adjusts the background
based on different combinations of states, including android:state_focused
and android:state_pressed
. When the user uses the rotary controller to
focus a view, android:state_focused
will be true
, but
android:state_pressed
will be false
. If the user then presses
the Center button on the rotary controller, both android:state_focused
and
android:state_pressed
will be true
while the user holds the button down.
When the user releases the button, only android:state_focused
will remain
true
.
car-ui-library uses a theme derived from Theme.DeviceDefault
. As a result,
this overlay affects apps that use this library and apps that use any theme derived from
Theme.DeviceDefault
. It won't affect apps that use an unrelated theme,
such as Theme.Material
.
Focus highlight resources in car-ui-library
The OEM can override several car-ui-library resources to control how the focus highlight
looks on views with a non-rectangular (such as round or pill-shaped) focus highlight and in
apps that use a theme that doesn't derive from Theme.DeviceDefault
. These
resources should be overlaid so that the focus highlight is consistent with the
default focus highlight drawable.
(Android 11 QPR3, Android 11 Car,
Android 12)
The following resources are used to indicate when a view is focused but not pressed:
car_ui_rotary_focus_fill_color
: Fill color.car_ui_rotary_focus_stroke_color
: Outline color.car_ui_rotary_focus_stroke_width
: Thickness of the outline.
(Android 11 QPR3, Android 11 Car,
Android 12)
The following resources are used to indicate when a view is focused and pressed:
car_ui_rotary_focus_pressed_fill_color
: Fill color.car_ui_rotary_focus_pressed_stroke_color
: Outline color.car_ui_rotary_focus_pressed_stroke_width
: Thickness of the outline.
Sometimes a button is given a solid background color to bring it to the user's attention, as in the example shown. This may make the focus highlight difficult to see.
In this situation, the developer can specify a custom focus highlight using secondary colors:
- (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
Any of the colors can be transparent and either dimension can be zero if, for example, you wanted only a fill or only an outline.
FocusArea highlight
(Android 11 QPR3, Android 11 Car,
Android 12)
FocusArea
can draw two types of highlight when one of its descendants is
focused. Both can be used in conjunction, if desired. This feature is disabled by default in
AOSP, but can be enabled by overriding car-ui-library resources:
car_ui_enable_focus_area_foreground_highlight
: Draw a highlight on top of theFocusArea
and its descendants. In AOSP, this drawable is an outline around theFocusArea
. OEMs can override thecar_ui_focus_area_foreground_highlight
drawable.car_ui_enable_focus_area_background_highlight
: Draw a highlight on top of theFocusArea
but behind its descendants. In AOSP, this drawable is a solid fill. OEMs can override thecar_ui_focus_area_background_highlight
drawable.
Input Method Editors
Input Method Editors (IME) are input methods. For example, an on-screen keyboard.
(Android 11 QPR3, Android 11 Car,
Android 12)
The OEM must overlay the default_touch_input_method
string resource
in the RotaryService
to specify the ComponentName
of the
touch-based IME. For example, if the OEM uses the IME provided with Android Automotive,
they should specify
com.google.android.apps.automotive.inputmethod/.InputMethodService
.
(Android 11 QPR3, Android 11 Car,
Android 12)
If the OEM has created an IME specifically for rotary, they should specify its
ComponentName
in the rotary_input_method
resource. If this resource
is overlaid, the specified IME is used whenever the user is interacting with the head unit
through the rotary controller's nudge, rotation, and Center button. When the user touches
the screen, the previous IME will be used. The Back button (and other buttons on the rotary
controller) have no effect on IME selection. If this resource isn't overlaid, no IME switching
occurs. Carboard does not support rotary so the user can't enter text through the rotary
controller if the OEM hasn't provided a rotary IME.
RotaryIME
is a demo rotary IME. While basic, it's sufficient to
try out the automatic IME switching described above. The source code for RotaryIME
can be found in packages/apps/Car/tests/RotaryIME/
.
Off-screen nudges
By default, when the user tries to nudge off the edge of the screen, nothing happens. The OEM can configure what should occur for each of the four directions by specifying any combination of:
- A global action defined by
AccessibilityService
. For example,GLOBAL_ACTION_BACK
. - A key code, such as
KEYCODE_BACK
. - An intent to launch an activity represented as a URL.
(Android 11 QPR3, Android 11 Car,
Android 12)
These are specified by overlaying the following array resources in the
RotaryService
:
off_screen_nudge_global_actions
: Array of global actions to perform when the user nudges up, down, left, or right off the edge of the screen. No global action is performed if the relevant element of this array is -1.off_screen_nudge_key_codes
: Array of key codes of click events to inject when the user nudges up, down, left, or right off the edge of the screen. No events are injected if the relevant element of this array is 0 (KEYCODE_UNKNOWN
).off_screen_nudge_intents
: Array of intents to launch an activity when the user nudges up, down, left, or right off the edge of the screen. No activity is launched if the relevant element of this array is empty.
Other configurations
You should overlay the following RotaryService
resources:
- (Android 11 QPR3, Android 11 Car,
Android 12)
config_showHeadsUpNotificationOnBottom
: Boolean value to represent whether heads-up notifications should be shown on the bottom as opposed to the top. This must have the same value as theconfig_showHeadsUpNotificationOnBottom
Boolean resource inframeworks/base/packages/CarSystemUI/res/values/config.xml
- (Android 11 QPR3, Android 11 Car,
Android 12)
notification_headsup_card_margin_horizontal
: Left and right margin for heads-up notification window. This must have the same value as thenotification_headsup_card_margin_horizontal
dimen resource inpackages/apps/Car/Notification/res/values/dimens.xml
- (Android 12)
excluded_application_overlay_window_titles
: An array of titles of windows that shouldn't be considered overlay windows. This should include titles of app windows that representTaskViews
orTaskDisplayAreas
. By default, this list contains only "Maps."
You can overlay the following RotaryService
resource:
- (Android 11 QPR3, Android 11 Car,
Android 12)
long_press_ms
: Integer value to represent how many milliseconds the Center button must be held down to trigger a long-press. Zero indicates the system default long-press timeout should be used. This is the default value.