Este artigo descreve como processar entradas rotativas no VHAL, configurar sua compilação para incluir o serviço rotativo e como personalizar a experiência rotativa em todos os aplicativos. Para aplicativos OEM pré-instalados, como um inicializador fornecido pelo OEM, consulte Car UI Library (car-ui-library) .
VHAL
Um controlador rotativo suporta as seguintes ações:
- Empurre para cima, para baixo, para a esquerda e para a direita.
- Gire no sentido horário e anti-horário.
- Pressione o botão central.
- Pressione o botão Voltar.
- Pressione o botão Início.
- Pressione outros botões, como Telefone e Mídia.
Consulte hardware/interfaces/automotive/vehicle/2.0/types.hal para documentação sobre as propriedades do sistema e int32Values correspondentes.
O VHAL deve lidar com estas ações:
Empurrar
Quando o usuário pressiona o controlador rotativo para a direita, o VHAL deve usar a propriedade HW_KEY_INPUT com os seguintes int32Values para enviar um evento para o Android:
-
ACTION_DOWN -
KEYCODE_SYSTEM_NAVIGATION_RIGHT - Exibição do alvo.
Quando o usuário libera o controlador rotativo, o VHAL deve usar a mesma propriedade e código de chave com ACTION_UP . Nudges em outras direções devem usar os códigos de chave correspondentes.
Não há códigos de teclas para diagonais, mas o VHAL pode combinar um evento horizontal e vertical para produzir uma diagonal se o hardware suportar diagonais. Por exemplo, empurrar 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 subsequentemente), a liberação do controlador rotativo deve produzir:
-
HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_LEFT ACTION_UP -
HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_UP ACTION_UP
O usuário pode empurrar o controlador rotativo em uma direção perpendicular antes de soltá-lo. Por exemplo, o seguinte cenário:

Isso deve 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 repetido deve ser gerado enquanto o controlador rotativo é mantido em uma direção.
Girar
Quando o usuário gira o controlador rotativo no sentido horário em um retentor (clique), o VHAL deve usar a propriedade HW_ROTARY_INPUT com os seguintes int32Values para enviar um evento para o Android:
-
ROTARY_INPUT_TYPE_SYSTEM_NAVIGATION - Um (1) retentor.
- Exibição do alvo.
O carimbo de data/hora do evento deve ser definido para o tempo decorrido em nanossegundos.
Uma rotação de um (1) detentor no sentido anti-horário deve gerar o mesmo evento, mas com -1 para o número de detentores.
Se ocorrerem vários detentores de rotação na mesma direção em rápida sucessão, o VHAL deve combinar os detentores em um único evento para não sobrecarregar o sistema com eventos. Nesse caso, o carimbo de data/hora do evento deve ser quando ocorreu o primeiro detentor da rotação. Os int32Values devem incluir o número de nanossegundos entre os detentores consecutivos de rotação.
Por exemplo, a seguinte sequência de rotações:
- No tempo t0, o usuário girou um detentor no sentido anti-horário.
- No tempo t0 + 5 ns, o usuário girou um detentor no sentido anti-horário.
- No tempo t0 + 8 ns, o usuário girou um detentor no sentido anti-horário.
deve gerar este evento:
- Propriedade:
HW_ROTARY_INPUT - Carimbo de data e hora:
t0 -
int32Values:-
ROTARY_INPUT_TYPE_SYSTEM_NAVIGATION - -3 (três batentes no sentido anti-horário).
- Exibição do alvo.
- 5 ns entre o primeiro e o segundo detentor.
- 3 ns entre o segundo e o terceiro detentor.
-
Botão central
Quando o usuário pressiona o botão central, o VHAL deve usar a propriedade HW_KEY_INPUT com os seguintes int32Values para enviar um evento para o Android:
-
ACTION_DOWN -
KEYCODE_DPAD_CENTER - Exibição do alvo.
Quando o usuário libera o controlador rotativo, o VHAL deve usar a mesma propriedade e código de chave com ACTION_UP .
Não gere eventos repetidos quando o botão central estiver pressionado.
Botão "voltar
Quando o usuário pressiona o botão Voltar, o VHAL deve usar a propriedade HW_KEY_INPUT com os seguintes int32Values para enviar um evento para o Android:
-
ACTION_DOWN -
KEYCODE_BACK - Exibição do alvo.
Quando o usuário libera o controlador rotativo, o VHAL deve usar a mesma propriedade e código de chave com ACTION_UP .
Nenhum evento repetido deve ser gerado enquanto o botão central estiver pressionado.
Botão de início
Manuseie 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 controlador rotativo incluir botões adicionais, o VHAL pode lidar com eles, no entanto, o OEM gosta, pois eles não são considerados parte do rotativo da perspectiva do Android. Normalmente, eles são tratados como os botões Voltar e Início, mas com códigos de chave diferentes. Por exemplo, KEYCODE_CALL ou KEYCODE_MUSIC .
Configuração de compilação
A navegação rotativa é fornecida por um serviço de acessibilidade chamado RotaryService . Para incluir este serviço na imagem do sistema do seu dispositivo, adicione a seguinte linha ao seu makefile:
PRODUCT_PACKAGES += CarRotaryController
Você também pode querer incluir os seguintes pacotes nas compilações de depuração:
-
RotaryPlaygroundUm aplicativo de referência para rotativo (consulte RotaryPlayground ). -
RotaryIMEUm IME rotativo de demonstração (consulte Editores de método de entrada ). -
CarRotaryImeRROA 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 a mesma compilação para carros com e sem um controlador rotativo, adicione CarRotaryController conforme mostrado acima para que o código necessário seja incluído na compilação. Para evitar que o serviço rotativo seja habilitado 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ê usará a mesma compilação, mas terá configurações de produto separadas, para dispositivos rotativos e não rotativos. Apenas este último inclui a sobreposição.
Costumização
Os OEMs podem personalizar a lógica de localização de foco, o destaque de foco e alguns itens adicionais por meio de sobreposições de recursos nos seguintes locais:
- car-ui-library está localizado em
packages/apps/Car/libs/car-ui-lib -
RotaryServiceestá localizado empackages/apps/Car/RotaryController -
Coreestá localizado emframeworks/base/core
Histórico de deslocamento
O OEM pode configurar se cada um dos dois tipos de histórico de nudge está habilitado e, em caso afirmativo, o tamanho do cache e a política de expiração. Tudo isso é feito substituindo vários recursos car-ui-library.
Cache do histórico de foco
( Android 11 QPR3, Android 11 Carro, Android 12 )
Esse cache FocusArea armazena a visualização focada mais recentemente dentro da FocusArea para que ela possa ser focada ao voltar para a FocusArea . Esse cache pode ser configurado sobrepondo os seguintes recursos car-ui-library:
-
car_ui_focus_history_cache_type:- O cache está desabilitado.
- O cache expirará após algum tempo (veja abaixo).
- O cache nunca expirará.
-
car_ui_focus_history_expiration_period_ms: Quantos milissegundos antes que o cache expire se o tipo de cache for definido como dois (2) (veja acima).
Cache de histórico do FocusArea
( Android 11 QPR3, Android 11 Carro, Android 12 )
Esse cache armazena um histórico de nudges para que o nudge na direção oposta possa retornar o foco para a mesma FocusArea . Esse cache pode ser configurado sobrepondo os seguintes recursos car-ui-library:
-
car_ui_focus_area_history_cache_type:- O cache está desabilitado.
- O cache expira após algum tempo (veja abaixo).
- O cache nunca expira.
-
car_ui_focus_area_history_expiration_period_ms: Quantos milissegundos antes do cache expirar se o tipo de cache for definido como 2 (veja acima). -
car_ui_clear_focus_area_history_when_rotating: se o cache deve ser anulado quando o usuário gira o controlador.
Rotação
( Android 11 QPR3, Android 11 Carro, Android 12 )
O OEM pode substituir dois recursos inteiros no RotaryService para especificar se há aceleração, como aceleração do mouse, para rotação:
-
rotation_acceleration_3x_ms: intervalo de tempo (em milissegundos) usado para decidir se o Google deve acelerar a rotação do controlador para um intervalo de rotação. Se o intervalo entre este batente e o batente de rotação anterior for menor que este valor, será tratado como três batentes 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 como2147483647para desativar a aceleração 2×.
A aceleração funciona melhor quando há registros de data e hora individuais para cada detentor de rotação, conforme exigido pelo VHAL. Se estes não estiverem disponíveis, o RotaryService assume que os detentores de rotação estão espaçados uniformemente.
/**
* 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 na estrutura do Android e vários recursos de destaque de foco em car-ui-library.
Destaque de foco padrão
A estrutura do Android fornece um destaque de foco padrão por meio do atributo selectableItemBackground . Em Theme.DeviceDefault , este atributo se refere a item_background.xml no Core . O OEM pode sobrepor item_background.xml para alterar o desenhável de destaque de foco padrão.
Esse drawable normalmente deve 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 controlador rotativo 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 controlador rotativo, android:state_focused e android:state_pressed serão true enquanto o usuário mantiver o botão pressionado. Quando o usuário soltar o botão, apenas android:state_focused permanecerá true .
car-ui-library usa um tema derivado de Theme.DeviceDefault . Como resultado, essa sobreposição afeta aplicativos que usam essa biblioteca e aplicativos que usam qualquer tema derivado de Theme.DeviceDefault . Ele não afetará aplicativos que usam um tema não relacionado, como Theme.Material .
Recursos de destaque de foco em car-ui-library
O OEM pode substituir vários recursos car-ui-library para controlar a aparência do destaque de foco em exibições com um destaque de foco não retangular (como redondo ou em forma de pílula) e em aplicativos que usam um tema que não deriva de Theme.DeviceDefault . Esses recursos devem ser sobrepostos para que o destaque de foco seja consistente com o desenhável de destaque de foco padrão .
( Android 11 QPR3, Android 11 Carro, Android 12 )
Os seguintes recursos são usados para indicar quando uma visualização está focada, 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 Carro, Android 12 )
Os seguintes recursos são usados para indicar quando uma visualização é focada 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 fundo sólida para chamar a atenção do usuário, como no exemplo mostrado. Isso pode dificultar a visualização do destaque do foco.

- ( Android 11 QPR3, Android 11 Carro, Android 12 )
car_ui_rotary_focus_fill_secondary_color
car_ui_rotary_focus_stroke_secondary_color - ( Android12 )
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 da área de foco
( Android 11 QPR3, Android 11 Carro, Android 12 )
FocusArea pode desenhar dois tipos de destaque quando um de seus descendentes está focado. Ambos podem ser usados em conjunto, se desejado. Esse recurso é desabilitado por padrão no AOSP, mas pode ser habilitado substituindo os recursos car-ui-library:
-
car_ui_enable_focus_area_foreground_highlight: Desenhe um destaque em cima doFocusAreae seus descendentes. No AOSP, este drawable é um contorno em torno doFocusArea. Os OEMs podem substituir o drawablecar_ui_focus_area_foreground_highlight. -
car_ui_enable_focus_area_background_highlight: Desenhe um destaque em cima doFocusAreamas atrás de seus descendentes. No AOSP, este drawable é um preenchimento sólido. Os OEMs podem substituir o drawablecar_ui_focus_area_background_highlight.
Editores de método de entrada
Editores de método de entrada (IME) são métodos de entrada. Por exemplo, um teclado na tela.
( Android 11 QPR3, Android 11 Carro, Android 12 )
O OEM deve 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 usar o IME fornecido com o Android Automotive, ele deverá especificar com.google.android.apps.automotive.inputmethod/.InputMethodService .
( Android 11 QPR3, Android 11 Carro, Android 12 )
Se o OEM criou um IME especificamente para rotativo, ele deve especificar seu ComponentName no recurso rotary_input_method . Se esse recurso for sobreposto, o IME especificado será usado sempre que o usuário estiver interagindo com a unidade principal por meio do botão de deslocamento, rotação e central do controlador rotativo. Quando o usuário tocar na tela, o IME anterior será usado. O botão Voltar (e outros botões no controlador giratório) não têm efeito na seleção de IME. Se esse recurso não for sobreposto, não ocorrerá troca de IME. O Carboard não é compatível com rotação, portanto, o usuário não pode inserir texto por meio do controlador giratório se o OEM não tiver fornecido um IME giratório.
RotaryIME é um IME rotativo de demonstração. Embora básico, é suficiente experimentar a troca automática de IME descrita acima. O código fonte do RotaryIME pode ser encontrado em packages/apps/Car/tests/RotaryIME/ .
Empurrões fora da tela
Por padrão, quando o usuário tenta afastar a borda da tela, nada acontece. O OEM pode configurar o que deve ocorrer para 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 intenção de iniciar uma atividade representada como um URL.
( Android 11 QPR3, Android 11 Carro, Android 12 )
Eles são especificados sobrepondo os seguintes recursos de array no RotaryService :
-
off_screen_nudge_global_actions: Matriz de ações globais a serem executadas quando o usuário empurra para cima, para baixo, para a esquerda ou para a direita na borda da tela. Nenhuma ação global é executada se o elemento relevante desta matriz for -1. -
off_screen_nudge_key_codes: matriz de códigos-chave de eventos de clique para injetar quando o usuário empurra para cima, para baixo, para a esquerda ou para a direita na borda da tela. Nenhum evento é injetado se o elemento relevante deste array 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 na borda da tela. Nenhuma atividade é iniciada se o elemento relevante desta matriz estiver vazio.
Outras configurações
Você deve sobrepor os seguintes recursos do RotaryService :
- ( Android 11 QPR3, Android 11 Carro, Android 12 )
config_showHeadsUpNotificationOnBottom: valor booleano para representar se as notificações de alerta devem ser mostradas na parte inferior e não na parte superior. Deve ter o mesmo valor que o recurso booleanoconfig_showHeadsUpNotificationOnBottomemframeworks/base/packages/CarSystemUI/res/values/config.xml - ( Android 11 QPR3, Android 11 Carro, Android 12 )
notification_headsup_card_margin_horizontal: Margem esquerda e direita da janela de notificação de heads-up. Isso deve ter o mesmo valor que o recurso de dimennotification_headsup_card_margin_horizontalempackages/apps/Car/Notification/res/values/dimens.xml - ( Android12 )
excluded_application_overlay_window_titles: uma matriz de títulos de janelas que não devem ser consideradas janelas de sobreposição. Isso deve incluir títulos de janelas de aplicativos que representamTaskViewsouTaskDisplayAreas. Por padrão, esta lista contém apenas "Mapas".
Você pode sobrepor o seguinte recurso RotaryService :
- ( Android 11 QPR3, Android 11 Carro, Android 12 )
long_press_ms: valor inteiro para representar quantos milissegundos o botão central deve ser pressionado para acionar um pressionamento longo. Zero indica que o tempo limite de pressionamento longo padrão do sistema deve ser usado. Este é o valor padrão.