Guia de integração para OEMs

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:

  1. ACTION_DOWN
  2. KEYCODE_SYSTEM_NAVIGATION_RIGHT
  3. 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:

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

Isso deve 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 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:

  1. ROTARY_INPUT_TYPE_SYSTEM_NAVIGATION
  2. Um (1) retentor.
  3. 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 :
    1. ROTARY_INPUT_TYPE_SYSTEM_NAVIGATION
    2. -3 (três batentes no sentido anti-horário).
    3. Exibição do alvo.
    4. 5 ns entre o primeiro e o segundo detentor.
    5. 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:

  1. ACTION_DOWN
  2. KEYCODE_DPAD_CENTER
  3. 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:

  1. ACTION_DOWN
  2. KEYCODE_BACK
  3. 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:

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
  • RotaryService está localizado em packages/apps/Car/RotaryController
  • Core está localizado em frameworks/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 :
    1. O cache está desabilitado.
    2. O cache expirará após algum tempo (veja abaixo).
    3. 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 :
    1. O cache está desabilitado.
    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 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 a rotation_acceleration_3x_ms . Usado para aceleração 2×. Defina como 2147483647 para 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.

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

Nessa situação, o desenvolvedor pode especificar um destaque de foco personalizado usando cores secundárias :
  • ( 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 do FocusArea e seus descendentes. No AOSP, este drawable é um contorno em torno do FocusArea . Os OEMs podem substituir o drawable car_ui_focus_area_foreground_highlight .
  • car_ui_enable_focus_area_background_highlight : Desenhe um destaque em cima do FocusArea mas atrás de seus descendentes. No AOSP, este drawable é um preenchimento sólido. Os OEMs podem substituir o drawable car_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:

  1. Uma ação global definida por AccessibilityService . Por exemplo, GLOBAL_ACTION_BACK .
  2. Um código de chave, como KEYCODE_BACK .
  3. 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 booleano config_showHeadsUpNotificationOnBottom em frameworks/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 dimen notification_headsup_card_margin_horizontal em packages/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 representam TaskViews ou TaskDisplayAreas . 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.