Guia de integração para OEMs

Esta página descreve como processar entradas rotativas na VHAL, configurar seu build para incluir o serviço rotativo e personalizar a experiência rotativa 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 é compatível com as 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 ver a documentação sobre as propriedades do sistema e os int32Values correspondentes.

A VHAL precisa processar estas ações:

Cutucada

Quando o usuário pressiona o controlador rotativo para a direita, a VHAL precisa usar a propriedade HW_KEY_INPUT com o seguinte int32Values para enviar um evento ao Android:

  1. ACTION_DOWN
  2. KEYCODE_SYSTEM_NAVIGATION_RIGHT
  3. Segmentação na Rede de Display.

Quando o usuário solta o controlador rotativo, a VHAL precisa usar a mesma propriedade e keycode com ACTION_UP. Os toques em outras direções devem usar os códigos de tecla correspondentes.

Não há keycodes para diagonais, mas a VHAL pode combinar um evento horizontal e vertical para produzir uma diagonal se o hardware for compatível com diagonais. Por exemplo, um toque 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), soltar o controle 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 pressionar o controle giratório em uma direção perpendicular antes de soltar. Por exemplo, o seguinte cenário:

Direção perpendicular
Figura 1. Direção perpendicular

Isso vai gerar a seguinte sequência de eventos:

  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

Nenhum evento de repetição deve ser gerado enquanto o controlador giratório estiver mantido em uma direção.

Girar

Quando o usuário gira o controlador rotativo no sentido horário em um travamento (clique), a VHAL precisa usar a propriedade HW_ROTARY_INPUT com o seguinte int32Values para enviar um evento ao Android:

  1. ROTARY_INPUT_TYPE_SYSTEM_NAVIGATION
  2. Um (1) detent.
  3. Segmentação na Rede de Display.

O carimbo de data/hora do evento precisa ser definido como o tempo decorrido em nanossegundos.

Uma rotação de um (1) retentor no sentido anti-horário deve gerar o mesmo evento, mas com -1 para o número de retentores.

Se ocorrerem vários travamentos de rotação na mesma direção em rápida sucessão, a VHAL deverá combinar os travamentos 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 travamento da rotação. O int32Values precisa incluir o número de nanossegundos entre os travamentos consecutivos da rotação.

Por exemplo, a seguinte sequência de rotações:

  • No tempo t0, o usuário girou um encaixe no sentido anti-horário.
  • No tempo t0 + 5 ns, o usuário girou um clique no sentido anti-horário.
  • No tempo t0 + 8 ns, o usuário girou um retentor no sentido anti-horário.

vai gerar este evento:

  • Propriedade: HW_ROTARY_INPUT
  • Carimbo de data/hora: t0
  • int32Values:
    1. ROTARY_INPUT_TYPE_SYSTEM_NAVIGATION
    2. -3 (três travamentos no sentido anti-horário).
    3. Segmentação na Rede de Display.
    4. 5 ns entre o primeiro e o segundo travamento.
    5. 3 ns entre o segundo e o terceiro travamento.

Botão central

Quando o usuário pressiona o botão central, a VHAL precisa usar a propriedade HW_KEY_INPUT com o seguinte int32Values para enviar um evento ao Android:

  1. ACTION_DOWN
  2. KEYCODE_DPAD_CENTER
  3. Segmentação na Rede de Display.

Quando o usuário solta o controlador rotativo, a VHAL precisa usar a mesma propriedade e o mesmo 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", a VHAL precisa usar a propriedade HW_KEY_INPUT com o seguinte int32Values para enviar um evento ao Android:

  1. ACTION_DOWN
  2. KEYCODE_BACK
  3. Segmentação na Rede de Display.

Quando o usuário solta o controlador rotativo, a VHAL precisa usar a mesma propriedade e o mesmo código de tecla com ACTION_UP.

Nenhum evento de repetição deve ser gerado enquanto o botão central estiver pressionado.

botão "Página inicial"

Use o botão home como o botão voltar, mas com KEYCODE_HOME em vez de KEYCODE_BACK.

Outros botões

Se o controlador giratório incluir outros botões, a VHAL poderá processá-los da maneira que o OEM preferir, já que eles não são considerados parte do seletor giratório na perspectiva do Android. Normalmente, eles 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 rotação é 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 é possí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 giratório de demonstração (consulte Editores de método de entrada).
  • CarRotaryImeRRO A sobreposição para RotaryIME.

O serviço rotativo é ativado automaticamente quando o dispositivo é inicializado e quando um usuário muda. Isso garante que o usuário possa usar o controle giratório 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 evitar que o serviço rotativo seja ativado em carros não rotativos, crie uma RRO estática para substituir 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 giratórios e não giratórios. Somente o último inclui a sobreposição.

Personalização

Os OEMs podem personalizar a lógica de localização do foco, o destaque do 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 em packages/apps/Car/RotaryController
  • Core está localizado em frameworks/base/core

Histórico de alertas

O OEM pode configurar se cada um dos dois tipos de histórico de sugestões está ativado e, em caso afirmativo, 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 de foco

(Android 11 QPR3, Android 11 Car, Android 12)
Esse cache por FocusArea armazena a visualização focada mais recentemente no FocusArea para que ela possa ser focada ao voltar para o FocusArea. Esse cache pode ser configurado sobrepondo os seguintes recursos da biblioteca car-ui:

  • car_ui_focus_history_cache_type:
    1. O cache está desativado.
    2. O cache expira depois de algum tempo (confira abaixo).
    3. O cache nunca expira.
  • car_ui_focus_history_expiration_period_ms: quantos milissegundos antes da expiração do cache se o tipo de cache estiver 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 cutucões para que um cutucão na direção oposta possa retornar o foco para o mesmo FocusArea. Esse cache pode ser configurado sobrepondo os seguintes recursos da biblioteca car-ui:

  • car_ui_focus_area_history_cache_type:
    1. O cache está desativado.
    2. O cache expira após algum tempo (veja abaixo).
    3. O cache nunca expira.
  • car_ui_focus_area_history_expiration_period_ms: quantos milissegundos antes da expiração do cache se o tipo de cache estiver definido como 2 (consulte acima).
  • car_ui_clear_focus_area_history_when_rotating: se o cache deve ser invalidado quando o usuário gira o controlador.

Rotação

(Android 11 QPR3, Android 11 Car, Android 12)
O OEM pode substituir dois recursos de números inteiros no RotaryService para especificar se há aceleração, como a 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 uma trava de rotação. Se o intervalo entre esse travamento e o anterior for menor que esse valor, ele será tratado como três travamentos de rotação. Defina como 2147483647 para desativar a aceleração de 3×.
  • rotation_acceleration_2x_ms: semelhante a rotation_acceleration_3x_ms. Usado para aceleração de 2x. Defina como 2147483647 para desativar a aceleração 2x.

A aceleração funciona melhor quando há carimbos de data/hora individuais para cada trava de rotação, conforme exigido pela VHAL. Se esses valores não estiverem disponíveis, o RotaryService vai presumir que os retentores 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 no framework do Android e vários recursos de destaque de foco na 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 destaque de foco padrão.

Normalmente, esse elemento combinável é 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 giratório, android:state_focused e android:state_pressed serão true enquanto o botão estiver pressionado. Quando o usuário soltar o botão, apenas android:state_focused vai permanecer true.

A car-ui-library usa um tema derivado de Theme.DeviceDefault. Como resultado, essa sobreposição afeta apps que usam essa biblioteca e apps que usam qualquer tema derivado de Theme.DeviceDefault. Isso não vai afetar apps que usam um tema não relacionado, como Theme.Material.

Focar recursos de destaque em car-ui-library

O OEM pode substituir vários recursos da biblioteca car-ui para controlar a aparência do destaque do 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 deriva de Theme.DeviceDefault. Esses recursos precisam ser sobrepostos para que o destaque do foco seja consistente com o drawable padrão.

(Android 11 QPR3, Android 11 Car, 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á 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.

Botão com plano de fundo sólido
Figura 2. Botão com plano de fundo sólido

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)
O FocusArea pode desenhar dois tipos de destaque quando um dos descendentes dele está em foco. Os dois podem ser usados em conjunto, se desejado. Esse recurso é desativado por padrão no AOSP, mas pode ser ativado substituindo os recursos da biblioteca car-ui:

  • car_ui_enable_focus_area_foreground_highlight: desenha um destaque em cima do FocusArea e dos descendentes dele. No AOSP, esse drawable é um contorno ao redor do FocusArea. Os OEMs podem substituir o recurso drawable car_ui_focus_area_foreground_highlight.
  • car_ui_enable_focus_area_background_highlight: desenha um destaque em cima do FocusArea, mas atrás dos descendentes dele. No AOSP, esse elemento drawable é um preenchimento sólido. Os OEMs podem substituir o elemento combinável car_ui_focus_area_background_highlight.

Editores do método de entrada

Os Editores de método de entrada (IME, na sigla em inglês) 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 usar o IME fornecido com o Android Automotive, ele precisará 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 rotação, 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 usando o toque, a rotação e o botão central do controle giratório. Quando o usuário tocar na tela, o IME anterior será usado. O botão "Voltar" (e outros botões no controle giratório) não afeta a seleção do IME. Se esse recurso não for sobreposto, não haverá troca de IME. O Cardboard não oferece suporte ao seletor giratório. Portanto, o usuário não pode inserir texto usando o controlador se o OEM não tiver fornecido um IME de seletor 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 empurrar a tela para fora da borda, nada acontece. O OEM pode configurar o que deve acontecer em cada uma das quatro direções especificando qualquer combinação de:

  1. Uma ação global definida por AccessibilityService. Por exemplo, GLOBAL_ACTION_BACK.
  2. Um código de chave, como KEYCODE_BACK.
  3. Uma intent para iniciar uma atividade representada como um URL.

(Android 11 QPR3, Android 11 Car, Android 12)
Eles são especificados ao sobrepor os seguintes recursos de matriz no RotaryService:

  • off_screen_nudge_global_actions: matriz de ações globais a serem realizadas quando o usuário desliza para cima, para baixo, para a esquerda ou para a direita na borda da tela. Nenhuma ação global é realizada se o elemento relevante dessa matriz for -1.
  • off_screen_nudge_key_codes: matriz de códigos de teclas de eventos de clique a serem injetados quando o usuário move para cima, para baixo, para a esquerda ou para a direita na 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 desliza para cima, para baixo, para a esquerda ou para a direita na borda da tela. Nenhuma atividade será iniciada se o elemento relevante dessa matriz estiver vazio.

Outras configurações

Sobreponha os seguintes recursos RotaryService:

  • (Android 11 QPR3, Android 11 Car, Android 12)
    config_showHeadsUpNotificationOnBottom: valor booleano para representar se as notificações heads-up devem ser mostradas na parte de baixo em vez da parte de cima. Ele precisa ter o mesmo valor do recurso booleano config_showHeadsUpNotificationOnBottom em frameworks/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 heads-up. Ele precisa ter o mesmo valor do recurso de dimensão notification_headsup_card_margin_horizontal em packages/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 inclui títulos de janelas de apps que representam TaskViews ou TaskDisplayAreas. 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 deve ser usado. Esse é o valor padrão.