Esta página descreve como processar entradas de seletor rotativo no VHAL, configurar seu build para incluir o serviço de seletor rotativo e como personalizar a experiência do seletor em todos os apps. Para apps OEM pré-instalados, como um iniciador fornecido pelo OEM, consulte Biblioteca da interface do carro (car-ui-library).
VHAL
Um controlador rotativo oferece suporte às seguintes ações:
- Deslocar para cima, baixo, esquerda e direita.
- Gire no sentido horário e anti-horário.
- Pressione o botão central.
- Pressione o botão Voltar .
- Pressione o botão home.
- Pressione outros botões, como "Telefone" e "Mídia".
Consulte hardware/interfaces/automotive/vehicle/2.0/types.hal
para conferir a documentação sobre
as propriedades do sistema e o int32Values
correspondente.
O VHAL precisa processar estas ações:
Piano
Quando o usuário pressiona o controle rotativo para a direita, o VHAL precisa usar a
propriedade HW_KEY_INPUT
com o int32Values
a seguir para enviar um
evento ao Android:
ACTION_DOWN
KEYCODE_SYSTEM_NAVIGATION_RIGHT
- Selecione a tela de destino.
Quando o usuário libera o controlador rotativo, o VHAL precisa usar a mesma propriedade e
o código de tecla com ACTION_UP
. Os nudges em outras direções precisam usar os
códigos de tecla correspondentes.
Não há códigos de tecla para diagonais, mas o VHAL pode combinar um evento horizontal e vertical para produzir uma diagonal se o hardware oferecer suporte a diagonais. Por exemplo, mover para cima e para a esquerda deve produzir:
HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_LEFT ACTION_DOWN
HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_UP ACTION_DOWN
Em qualquer ordem (e posteriormente), a liberação do controlador rotativo vai produzir:
HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_LEFT ACTION_UP
HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_UP ACTION_UP
O usuário pode pressionar o controlador rotativo em uma direção perpendicular antes de soltá-lo. Por exemplo, o seguinte cenário:

Isso vai gerar a seguinte sequência de eventos:
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
Nenhum evento de repetição será gerado enquanto o seletor giratório estiver em uma direção.
Girar
Quando o usuário gira o controlador rotativo no sentido horário em um dente (clique), o VHAL
precisa usar a propriedade HW_ROTARY_INPUT
com o seguinte int32Values
para enviar um evento ao Android:
ROTARY_INPUT_TYPE_SYSTEM_NAVIGATION
- Uma (1) retenção.
- Selecione a tela de destino.
O carimbo de data/hora do evento precisa ser definido como o tempo decorrido em nanossegundos.
Uma rotação no sentido anti-horário de uma (1) dente deve gerar o mesmo evento, mas com -1 para o número de dentes.
Se vários pontos de parada de rotação na mesma direção ocorrerem em rápida sucessão, o VHAL
vai combinar os pontos de parada em um único evento para não sobrecarregar o sistema com eventos.
Nesse caso, o carimbo de data/hora do evento deve ser quando a primeira detenção de rotação ocorreu.
O int32Values
precisa incluir o número de nanossegundos entre as posições de retenção
consecutivas.
Por exemplo, a seguinte sequência de rotações:
- No momento t0, o usuário girou uma dente no sentido anti-horário.
- No tempo t0 + 5 ns, o usuário girou uma dente no sentido anti-horário.
- No tempo t0 + 8 ns, o usuário girou uma dente no sentido anti-horário.
deve gerar este evento:
- Propriedade:
HW_ROTARY_INPUT
- Carimbo de data/hora:
t0
int32Values
:ROTARY_INPUT_TYPE_SYSTEM_NAVIGATION
- -3 (três engrenagens no sentido anti-horário).
- Selecione a tela de destino.
- 5 ns entre a primeira e a segunda retenção.
- 3 ns entre a segunda e a terceira retenção.
Botão central
Quando o usuário pressiona o botão central, o VHAL precisa usar a propriedade HW_KEY_INPUT
com o seguinte int32Values
para enviar um evento ao Android:
ACTION_DOWN
KEYCODE_DPAD_CENTER
- Selecione a tela de destino.
Quando o usuário libera o controlador rotativo, o VHAL precisa usar a mesma propriedade
e o código de tecla com ACTION_UP
.
Não gere eventos de repetição quando o botão central for pressionado.
Botão "Voltar"
Quando o usuário pressiona o botão "Voltar", o VHAL precisa usar a propriedade HW_KEY_INPUT
com o seguinte int32Values
para enviar um evento ao Android:
ACTION_DOWN
KEYCODE_BACK
- Selecione a tela de destino.
Quando o usuário libera o controlador rotativo, o VHAL precisa usar a mesma propriedade
e o código de tecla com ACTION_UP
.
Nenhum evento de repetição será gerado enquanto o botão central estiver pressionado.
Botão "Início"
Processe o botão "Home" como faria com o botão "Voltar", mas com KEYCODE_HOME
em vez
de KEYCODE_BACK
.
Outros botões
Se o controle rotativo incluir outros botões, o VHAL poderá processá-los da maneira
que o OEM preferir, já que eles não são considerados parte do seletor giratório do ponto de vista do Android.
Eles geralmente são tratados como os botões "Voltar" e "Início", mas com códigos de tecla diferentes.
Por exemplo, KEYCODE_CALL
ou KEYCODE_MUSIC
.
Configuração do build
A navegação por seletor giratório é fornecida por um serviço de acessibilidade chamado RotaryService
.
Para incluir esse serviço na imagem do sistema do dispositivo, adicione a seguinte linha ao
makefile:
PRODUCT_PACKAGES += CarRotaryController
Também é recomendável incluir os seguintes pacotes em builds de depuração:
RotaryPlayground
Um app de referência para seletor giratório (consulte RotaryPlayground).RotaryIME
Um IME rotativo de demonstração (consulte Editores de método de entrada).CarRotaryImeRRO
A sobreposição paraRotaryIME
.
O serviço rotativo é ativado automaticamente quando o dispositivo é inicializado e quando ocorre uma troca de usuário. Isso garante que o usuário possa usar o controlador rotativo durante a configuração.
Se você usar o mesmo build para carros com e sem um controle giratório,
adicione CarRotaryController
, conforme mostrado acima, para que o código necessário seja incluído
no build. Para impedir que o serviço de rotatória seja ativado em carros não rotativos, crie um
RRO estático para sobrepor o recurso de string rotaryService
em
packages/services/Car/service
com uma string vazia. Você vai usar o mesmo build,
mas terá configurações de produto separadas para dispositivos rotativos e não rotativos. Somente o último
inclui a sobreposição.
Personalização
Os OEMs podem personalizar a lógica de busca de foco, o destaque de foco e alguns itens adicionais usando sobreposições de recursos nos seguintes locais:
- car-ui-library está localizado em
packages/apps/Car/libs/car-ui-lib
RotaryService
está localizado empackages/apps/Car/RotaryController
Core
está localizado emframeworks/base/core
Histórico de sugestões
O OEM pode configurar se cada um dos dois tipos de histórico de sugestões está ativado ou não e, se sim, o tamanho do cache e a política de expiração. Isso é feito substituindo vários recursos da car-ui-library.
Cache do histórico do foco
(Android 11 QPR3, Android 11 para carros,
Android 12)
Esse cache por FocusArea
armazena a visualização mais recente focada no
FocusArea
para que ela possa ser focada ao voltar para o FocusArea
.
Esse cache pode ser configurado sobrepondo os seguintes recursos da car-ui-library:
-
car_ui_focus_history_cache_type
:- O cache está desativado.
- O cache expira após algum tempo (confira abaixo).
- O cache nunca expira.
car_ui_focus_history_expiration_period_ms
: quantos milissegundos antes do cache expirar se o tipo de cache for definido como dois (2) (consulte acima).
Cache do histórico do FocusArea
(Android 11 QPR3, Android 11 Car,
Android 12)
Esse cache armazena um histórico de sugestões para que a sugestão na direção oposta possa
retornar o foco para o mesmo FocusArea
. Esse cache pode ser configurado sobrepondo os
seguintes recursos da car-ui-library:
-
car_ui_focus_area_history_cache_type
:- O cache está desativado.
- O cache expira após algum tempo (confira abaixo).
- O cache nunca expira.
car_ui_focus_area_history_expiration_period_ms
: quantos milissegundos antes do cache expirar se o tipo de cache estiver definido como 2 (consulte acima).car_ui_clear_focus_area_history_when_rotating
: se o cache será anulado quando o usuário girar o controle.
Rotação
(Android 11 QPR3, Android 11 Car,
Android 12)
O OEM pode substituir dois recursos de inteiros no RotaryService
para especificar se
há aceleração, como a aceleração do mouse, para a rotação:
rotation_acceleration_3x_ms
: intervalo de tempo (em milissegundos) usado para decidir se o Google deve acelerar a rotação do controle para uma detenção de rotação. Se o intervalo entre esse dente e o dente de rotação anterior for menor que esse valor, ele será tratado como três dentes de rotação. Defina como 2147483647 para desativar a aceleração 3×.rotation_acceleration_2x_ms
: semelhante arotation_acceleration_3x_ms
. Usado para aceleração 2×. Defina como2147483647
para desativar a aceleração 2x.
A aceleração funciona melhor quando há carimbos de data/hora individuais para cada dente de
rotação, conforme
requerido
pelo VHAL. Se eles não estiverem disponíveis, o RotaryService
vai presumir que os detents de
rotação estão espaçados de maneira uniforme.
/** * 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),
Destaque de foco
O OEM pode substituir o destaque de foco padrão no framework do Android e vários recursos de destaque de foco na biblioteca car-ui-library.
Destaque de foco padrão
O framework do Android fornece um destaque de foco padrão pelo atributo
selectableItemBackground
. Em Theme.DeviceDefault
, esse
atributo se refere a item_background.xml
em Core
. O OEM pode sobrepor
item_background.xml
para mudar o drawable de destaque de foco padrão.
Esse drawable normalmente precisa ser um StateListDrawable
, que ajusta o plano de fundo
com base em diferentes combinações de estados, incluindo android:state_focused
e android:state_pressed
. Quando o usuário usa o controle giratório para
focar uma visualização, android:state_focused
será true
, mas
android:state_pressed
será false
. Se o usuário pressionar
o botão central no controle rotativo, android:state_focused
e
android:state_pressed
serão true
enquanto o usuário mantiver o botão pressionado.
Quando o usuário libera o botão, apenas android:state_focused
permanece
true
.
A car-ui-library usa um tema derivado de Theme.DeviceDefault
. Como resultado,
essa sobreposição afeta os apps que usam essa biblioteca e os que usam qualquer tema derivado de
Theme.DeviceDefault
. Ele não vai afetar apps que usam um tema não relacionado,
como Theme.Material
.
Foco nos recursos de destaque na car-ui-library
O OEM pode substituir vários recursos da biblioteca car-ui-library para controlar a aparência do destaque de foco
em visualizações com um destaque de foco não retangular (como redondo ou em forma de pílula) e em
apps que usam um tema que não é derivado de Theme.DeviceDefault
. Esses
recursos precisam ser sobrepostos para que o destaque de foco seja consistente com o
drawable padrão.
(Android 11 QPR3, Android 11 para carros,
Android 12)
Os recursos a seguir são usados para indicar quando uma visualização está em foco, mas não pressionada:
car_ui_rotary_focus_fill_color
: cor de preenchimento.car_ui_rotary_focus_stroke_color
: cor do contorno.car_ui_rotary_focus_stroke_width
: espessura do contorno.
(Android 11 QPR3, Android 11 Car,
Android 12)
Os recursos a seguir são usados para indicar quando uma visualização está com foco e pressionada:
car_ui_rotary_focus_pressed_fill_color
: cor de preenchimento.car_ui_rotary_focus_pressed_stroke_color
: cor do contorno.car_ui_rotary_focus_pressed_stroke_width
: espessura do contorno.
Às vezes, um botão recebe uma cor de plano de fundo sólida para chamar a atenção do usuário, como no exemplo mostrado. Isso pode dificultar a visualização do destaque de foco.

Nessa situação, o desenvolvedor pode especificar um destaque de foco personalizado usando cores secundárias:
- (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
Qualquer uma das cores pode ser transparente, e qualquer dimensão pode ser zero se, por exemplo, você quiser apenas um preenchimento ou apenas um contorno.
Destaque de FocusArea
(Android 11 QPR3, Android 11 Car,
Android 12)
FocusArea
pode desenhar dois tipos de destaque quando um dos descendentes está
em foco. Ambos podem ser usados em conjunto, se necessário. Esse recurso fica desativado por padrão no
AOSP, mas pode ser ativado substituindo os recursos da car-ui-library:
car_ui_enable_focus_area_foreground_highlight
: desenha um destaque sobreFocusArea
e seus descendentes. No AOSP, esse drawable é um contorno ao redor doFocusArea
. Os OEMs podem substituir o drawablecar_ui_focus_area_foreground_highlight
.car_ui_enable_focus_area_background_highlight
: desenha um destaque na parte de cima doFocusArea
, mas atrás dos descendentes. No AOSP, esse drawable é um preenchimento sólido. Os OEMs podem substituir ocar_ui_focus_area_background_highlight
drawable.
Editores do método de entrada
Os editores de método de entrada (IME) são métodos de entrada. Por exemplo, um teclado na tela.
(Android 11 QPR3, Android 11 Car,
Android 12)
O OEM precisa sobrepor o recurso de string default_touch_input_method
no RotaryService
para especificar o ComponentName
do
IME baseado em toque. Por exemplo, se o OEM usa o IME fornecido com o Android Automotive,
ele precisa especificar
com.google.android.apps.automotive.inputmethod/.InputMethodService
.
(Android 11 QPR3, Android 11 Car,
Android 12)
Se o OEM tiver criado um IME especificamente para o seletor giratório, ele precisará especificar o
ComponentName
no recurso rotary_input_method
. Se esse recurso
for sobreposto, o IME especificado será usado sempre que o usuário interagir com a unidade principal
pelo botão de centralização, rotação e empurrão do controle giratório. Quando o usuário toca
na tela, o IME anterior é usado. O botão "Voltar" (e outros botões no controle
giratório) não afetam a seleção do IME. Se esse recurso não for sobreposto, nenhuma troca de IME
ocorrerá. O Carboard não oferece suporte a seletor giratório. Portanto, o usuário não pode inserir texto pelo controle
se o OEM não tiver fornecido um IME giratório.
RotaryIME
é um IME rotativo de demonstração. Embora seja básico, ele é suficiente para
testar a troca automática de IME descrita acima. O código-fonte de RotaryIME
pode ser encontrado em packages/apps/Car/tests/RotaryIME/
.
Alertas fora da tela
Por padrão, quando o usuário tenta sair da borda da tela, nada acontece. O OEM pode configurar o que deve ocorrer em cada uma das quatro direções especificando qualquer combinação de:
- Uma ação global definida por
AccessibilityService
. Por exemplo,GLOBAL_ACTION_BACK
. - Um código de chave, como
KEYCODE_BACK
. - Uma intent para iniciar uma atividade representada como um URL.
(Android 11 QPR3, Android 11 Car,
Android 12)
Eles são especificados sobrepondo os seguintes recursos de matriz no
RotaryService
:
off_screen_nudge_global_actions
: matriz de ações globais a serem realizadas quando o usuário empurrar para cima, para baixo, para a esquerda ou para a direita fora da borda da tela. Nenhuma ação global será realizada se o elemento relevante dessa matriz for -1.off_screen_nudge_key_codes
: matriz de códigos de teclas de eventos de clique para injetar quando o usuário empurra para cima, para baixo, para a esquerda ou para a direita fora da borda da tela. Nenhum evento será injetado se o elemento relevante dessa matriz for 0 (KEYCODE_UNKNOWN
).off_screen_nudge_intents
: matriz de intents para iniciar uma atividade quando o usuário empurra para cima, para baixo, para a esquerda ou para a direita fora da borda da tela. Nenhuma atividade será iniciada se o elemento relevante dessa matriz estiver vazio.
Outras configurações
É necessário sobrepor os seguintes recursos RotaryService
:
- (Android 11 QPR3, Android 11 Car,
Android 12)
config_showHeadsUpNotificationOnBottom
: valor booleano para representar se as notificações de alerta precisam ser mostradas na parte de baixo, e não na parte de cima. Ele precisa ter o mesmo valor que o recurso booleanoconfig_showHeadsUpNotificationOnBottom
emframeworks/base/packages/CarSystemUI/res/values/config.xml
. - (Android 11 QPR3, Android 11 Car,
Android 12)
notification_headsup_card_margin_horizontal
: margem esquerda e direita para janela de notificação de aviso. Ele precisa ter o mesmo valor do recurso de dimennotification_headsup_card_margin_horizontal
empackages/apps/Car/Notification/res/values/dimens.xml
. - (Android 12)
excluded_application_overlay_window_titles
: uma matriz de títulos de janelas que não devem ser consideradas janelas de sobreposição. Isso precisa incluir títulos de janelas de apps que representamTaskViews
ouTaskDisplayAreas
. Por padrão, essa lista contém apenas "Maps".
É possível sobrepor o seguinte recurso RotaryService
:
- (Android 11 QPR3, Android 11 Car,
Android 12)
long_press_ms
: valor inteiro para representar quantos milissegundos o botão central precisa ser pressionado para acionar um toque longo. Zero indica que o tempo limite padrão de pressionamento longo do sistema precisa ser usado. Esse é o valor padrão.