Guía de integración para OEM

Este artículo describe cómo procesar entradas rotativas en VHAL, configurar su compilación para incluir el servicio rotativo y cómo personalizar la experiencia rotatoria en todas las aplicaciones. Para aplicaciones OEM preinstaladas, como un iniciador proporcionado por OEM, consulte Biblioteca de interfaz de usuario de automóvil (car-ui-library) .

VHAL

Un controlador giratorio admite las siguientes acciones:

  • Empuje hacia arriba, abajo, izquierda y derecha.
  • Girar en sentido horario y antihorario.
  • Presiona el botón central.
  • Presiona el botón de atrás.
  • Presiona el botón Inicio.
  • Presione otros botones, como Teléfono y Medios.

Consulte hardware/interfaces/automotive/vehicle/2.0/types.hal para obtener documentación sobre las propiedades del sistema y los int32Values ​​correspondientes.

El VHAL debe manejar estas acciones:

Empujar

Cuando el usuario empuja el control giratorio hacia la derecha, el VHAL debe usar la propiedad HW_KEY_INPUT con los siguientes int32Values para enviar un evento a Android:

  1. ACTION_DOWN
  2. KEYCODE_SYSTEM_NAVIGATION_RIGHT
  3. Visualización de objetivos.

Cuando el usuario suelta el control giratorio, el VHAL debe usar la misma propiedad y código clave con ACTION_UP . Los empujones en otras direcciones deben usar los códigos clave correspondientes.

No hay códigos clave para las diagonales, pero VHAL puede combinar un evento horizontal y vertical para producir una diagonal si el hardware admite diagonales. Por ejemplo, empujar hacia arriba y hacia la izquierda debería producir:

  • HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_LEFT ACTION_DOWN
  • HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_UP ACTION_DOWN

En cualquier orden (y posteriormente), la liberación del controlador giratorio debería producir:

  • HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_LEFT ACTION_UP
  • HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_UP ACTION_UP

El usuario puede empujar el controlador giratorio en una dirección perpendicular antes de soltarlo. Por ejemplo, el siguiente escenario:

dirección perpendicular
Figura 1. Dirección perpendicular

Esto debería generar la siguiente secuencia 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

No se deben generar eventos repetidos mientras el control giratorio se mantiene en una dirección.

Girar

Cuando el usuario gira el controlador giratorio en el sentido de las agujas del reloj un tope (clic), el VHAL debe usar la propiedad HW_ROTARY_INPUT con los siguientes int32Values ​​para enviar un evento a Android:

  1. ROTARY_INPUT_TYPE_SYSTEM_NAVIGATION
  2. Un (1) retén.
  3. Visualización de objetivos.

La marca de tiempo del evento debe establecerse en el tiempo transcurrido en nanosegundos.

Una rotación de un (1) retén en sentido antihorario debería generar el mismo evento pero con -1 para el número de retenes.

Si ocurren múltiples retenes de rotación en la misma dirección en rápida sucesión, el VHAL debe combinar los retenes en un solo evento para no sobrecargar el sistema con eventos. En este caso, la marca de tiempo del evento debe ser cuando ocurrió el primer tope de rotación. Los int32Values deben incluir el número de nanosegundos entre detenciones de rotación consecutivas.

Por ejemplo, la siguiente secuencia de rotaciones:

  • En el momento t0, el usuario giró un tope en sentido contrario a las agujas del reloj.
  • En el momento t0 + 5 ns, el usuario giró un tope en sentido antihorario.
  • En el momento t0 + 8 ns, el usuario giró un tope en sentido antihorario.

debe generar este evento:

  • Propiedad: HW_ROTARY_INPUT
  • Marca de tiempo: t0
  • int32Values :
    1. ROTARY_INPUT_TYPE_SYSTEM_NAVIGATION
    2. -3 (tres retenes en sentido contrario a las agujas del reloj).
    3. Visualización de objetivos.
    4. 5 ns entre el primer y el segundo retén.
    5. 3 ns entre el segundo y el tercer retén.

Botón central

Cuando el usuario presiona el botón Centro, VHAL debe usar la propiedad HW_KEY_INPUT con los siguientes int32Values para enviar un evento a Android:

  1. ACTION_DOWN
  2. KEYCODE_DPAD_CENTER
  3. Visualización de objetivos.

Cuando el usuario suelta el control giratorio, el VHAL debe usar la misma propiedad y código clave con ACTION_UP .

No genere eventos repetidos cuando se mantiene presionado el botón central.

Botón de retroceso

Cuando el usuario presiona el botón Atrás, VHAL debe usar la propiedad HW_KEY_INPUT con los siguientes int32Values para enviar un evento a Android:

  1. ACTION_DOWN
  2. KEYCODE_BACK
  3. Visualización de objetivos.

Cuando el usuario suelta el control giratorio, el VHAL debe usar la misma propiedad y código clave con ACTION_UP .

No se deben generar eventos repetidos mientras se mantiene presionado el botón central.

Botón de inicio

Maneje el botón Inicio como lo haría con el botón Atrás pero con KEYCODE_HOME en lugar de KEYCODE_BACK .

Otros botones

Si el controlador rotatorio incluye botones adicionales, el VHAL puede manejarlos como le guste al OEM, ya que no se consideran parte del rotativo desde la perspectiva de Android. Por lo general, se manejan como los botones Atrás e Inicio, pero con diferentes códigos clave. Por ejemplo, KEYCODE_CALL o KEYCODE_MUSIC .

Configuración de compilación

La navegación rotatoria es proporcionada por un servicio de accesibilidad llamado RotaryService . Para incluir este servicio en la imagen del sistema de su dispositivo, agregue la siguiente línea a su archivo MAKE:

PRODUCT_PACKAGES += CarRotaryController

También es posible que desee incluir los siguientes paquetes en las compilaciones de depuración:

El servicio rotativo se activa automáticamente cuando se inicia el dispositivo y cuando se produce un cambio de usuario. Esto garantiza que el usuario pueda utilizar el controlador giratorio durante la configuración.

Si usa la misma compilación para automóviles con y sin controlador giratorio, agregue CarRotaryController como se muestra arriba para que el código necesario se incluya en la compilación. Para evitar que el servicio rotativo se habilite en automóviles que no sean rotativos, cree un RRO estático para superponer el rotaryService de cadena de servicio rotativo en packages/services/Car/service con una cadena vacía. Usará la misma compilación, pero tendrá configuraciones de productos separadas, para dispositivos rotativos y no rotativos. Solo este último incluye la superposición.

personalización

Los OEM pueden personalizar la lógica de búsqueda de enfoque, el resaltado de enfoque y algunos elementos adicionales a través de superposiciones de recursos en las siguientes ubicaciones:

  • car-ui-library se encuentra en packages/apps/Car/libs/car-ui-lib
  • RotaryService se encuentra en packages/apps/Car/RotaryController
  • Core se encuentra en frameworks/base/core

Historial de empujones

El OEM puede configurar si cada uno de los dos tipos de historial de nudge está habilitado o no y, de ser así, el tamaño de caché y la política de caducidad. Todo esto se hace anulando varios recursos car-ui-library.

Caché de historial de enfoque

( Android 11 QPR3, Android 11 Coche, Android 12 )
Esta FocusArea caché por área de enfoque almacena la vista enfocada más recientemente dentro del área de FocusArea para que se pueda enfocar al regresar al área de FocusArea . Este caché se puede configurar superponiendo los siguientes recursos car-ui-library:

  • car_ui_focus_history_cache_type :
    1. El caché está deshabilitado.
    2. El caché caducará después de un tiempo (ver más abajo).
    3. El caché nunca caducará.
  • car_ui_focus_history_expiration_period_ms : cuántos milisegundos antes de que caduque la caché si el tipo de caché se establece en dos (2) (ver arriba).

Caché de historial de FocusArea

( Android 11 QPR3, Android 11 Coche, Android 12 )
Este caché almacena un historial de toques para que empujar en la dirección opuesta pueda devolver el foco a la misma FocusArea . Este caché se puede configurar superponiendo los siguientes recursos car-ui-library:

  • car_ui_focus_area_history_cache_type :
    1. El caché está deshabilitado.
    2. El caché caduca después de un tiempo (ver más abajo).
    3. El caché nunca caduca.
  • car_ui_focus_area_history_expiration_period_ms : cuántos milisegundos antes de que caduque la caché si el tipo de caché se establece en 2 (ver arriba).
  • car_ui_clear_focus_area_history_when_rotating : si se anula la memoria caché cuando el usuario gira el controlador.

Rotación

( Android 11 QPR3, Android 11 Coche, Android 12 )
El OEM puede anular dos recursos enteros en RotaryService para especificar si hay aceleración, como la aceleración del mouse, para la rotación:

  • rotation_acceleration_3x_ms : Intervalo de tiempo (en milisegundos) utilizado para decidir si Google debe acelerar la rotación del controlador para un tope de rotación. Si el intervalo entre este retén y el retén de rotación anterior es menor que este valor, se tratará como tres retenes de rotación. Establézcalo en 2147483647 para deshabilitar la aceleración 3×.
  • rotation_acceleration_2x_ms : similar a rotation_acceleration_3x_ms . Se utiliza para una aceleración de 2×. Establézcalo en 2147483647 para deshabilitar la aceleración 2×.

La aceleración funciona mejor cuando hay marcas de tiempo individuales para cada tope de rotación, según lo requiera el VHAL. Si no están disponibles, RotaryService asume que los topes de rotación están espaciados 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),

Foco resaltado

El OEM puede anular el resaltado de enfoque predeterminado en el marco de Android y varios recursos de resaltado de enfoque en car-ui-library.

Destacado de enfoque predeterminado

El marco de trabajo de Android proporciona un resaltado de enfoque predeterminado a través del atributo selectableItemBackground . En Theme.DeviceDefault , este atributo hace referencia a item_background.xml en Core . El OEM puede superponer item_background.xml para cambiar el resaltado de enfoque predeterminado dibujable.

Este elemento de diseño normalmente debe ser un StateListDrawable , que ajusta el fondo en función de diferentes combinaciones de estados, incluidos android:state_focused y android:state_pressed . Cuando el usuario usa el control giratorio para enfocar una vista, android:state_focused será true , pero android:state_pressed será false . Si el usuario luego presiona el botón central en el control giratorio, tanto android:state_focused como android:state_pressed serán true mientras el usuario mantiene presionado el botón. Cuando el usuario suelta el botón, solo android:state_focused seguirá siendo true .

car-ui-library usa un tema derivado de Theme.DeviceDefault . Como resultado, esta superposición afecta a las aplicaciones que usan esta biblioteca y las aplicaciones que usan cualquier tema derivado de Theme.DeviceDefault . No afectará a las aplicaciones que usan un tema no relacionado, como Theme.Material .

Enfocar recursos destacados en car-ui-library

El OEM puede anular varios recursos de la biblioteca de interfaz de usuario del automóvil para controlar cómo se ve el resaltado de enfoque en las vistas con un resaltado de enfoque no rectangular (como redondo o en forma de píldora) y en aplicaciones que usan un tema que no se deriva de Theme.DeviceDefault . Estos recursos deben superponerse para que el resaltado de enfoque sea coherente con el elemento de diseño resaltado de enfoque predeterminado .

( Android 11 QPR3, Android 11 Coche, Android 12 )
Los siguientes recursos se utilizan para indicar cuándo una vista está enfocada pero no presionada:

  • car_ui_rotary_focus_fill_color : color de relleno.
  • car_ui_rotary_focus_stroke_color : Color del contorno.
  • car_ui_rotary_focus_stroke_width : Grosor del contorno.

( Android 11 QPR3, Android 11 Coche, Android 12 )
Los siguientes recursos se utilizan para indicar cuándo una vista está enfocada y presionada:

  • car_ui_rotary_focus_pressed_fill_color : Color de relleno.
  • car_ui_rotary_focus_pressed_stroke_color : Color del contorno.
  • car_ui_rotary_focus_pressed_stroke_width : Grosor del contorno.

A veces, a un botón se le da un color de fondo sólido para llamar la atención del usuario, como en el ejemplo que se muestra. Esto puede hacer que el punto culminante del enfoque sea difícil de ver.

Botón con fondo sólido
Figura 2. Botón con fondo sólido

En esta situación, el desarrollador puede especificar un resaltado de enfoque personalizado usando colores secundarios :
  • ( Android 11 QPR3, Android 11 Coche, 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

Cualquiera de los colores puede ser transparente y cualquiera de las dimensiones puede ser cero si, por ejemplo, desea solo un relleno o solo un contorno.

Área de enfoque destacada

( Android 11 QPR3, Android 11 Coche, Android 12 )
FocusArea puede dibujar dos tipos de resaltado cuando uno de sus descendientes está enfocado. Ambos se pueden usar en conjunto, si se desea. Esta función está deshabilitada de forma predeterminada en AOSP, pero se puede habilitar anulando los recursos de car-ui-library:

  • car_ui_enable_focus_area_foreground_highlight : Dibuje un resaltado en la parte superior de FocusArea y sus descendientes. En AOSP, este dibujable es un contorno alrededor del FocusArea . Los OEM pueden anular el elemento de car_ui_focus_area_foreground_highlight .
  • car_ui_enable_focus_area_background_highlight : Dibuje un resaltado en la parte superior del FocusArea pero detrás de sus descendientes. En AOSP, este dibujable es un relleno sólido. Los OEM pueden anular el elemento de car_ui_focus_area_background_highlight .

Editores de métodos de entrada

Los editores de métodos de entrada (IME) son métodos de entrada. Por ejemplo, un teclado en pantalla.

( Android 11 QPR3, Android 11 Coche, Android 12 )
El OEM debe superponer el recurso de cadena default_touch_input_method en el RotaryService para especificar el ComponentName del IME táctil. Por ejemplo, si el OEM usa el IME provisto con Android Automotive, debe especificar com.google.android.apps.automotive.inputmethod/.InputMethodService .

( Android 11 QPR3, Android 11 Coche, Android 12 )
Si el OEM ha creado un IME específicamente para rotativo, debe especificar su ComponentName en el recurso rotary_input_method . Si este recurso está superpuesto, el IME especificado se usa cada vez que el usuario interactúa con la unidad principal a través del botón de empuje, rotación y centro del control giratorio. Cuando el usuario toca la pantalla, se utilizará el IME anterior. El botón Atrás (y otros botones del control giratorio) no tienen efecto en la selección de IME. Si este recurso no está superpuesto, no se produce ningún cambio de IME. Carboard no admite rotativo, por lo que el usuario no puede ingresar texto a través del controlador rotatorio si el OEM no ha proporcionado un IME rotatorio.

RotaryIME es un IME rotativo de demostración. Si bien es básico, basta con probar el cambio automático de IME descrito anteriormente. El código fuente de RotaryIME se puede encontrar en packages/apps/Car/tests/RotaryIME/ .

Empujones fuera de pantalla

De forma predeterminada, cuando el usuario intenta empujar el borde de la pantalla, no sucede nada. El OEM puede configurar lo que debe ocurrir para cada una de las cuatro direcciones especificando cualquier combinación de:

  1. Una acción global definida por AccessibilityService . Por ejemplo, GLOBAL_ACTION_BACK .
  2. Un código clave, como KEYCODE_BACK .
  3. Una intención de lanzar una actividad representada como una URL.

( Android 11 QPR3, Android 11 Coche, Android 12 )
Estos se especifican superponiendo los siguientes recursos de matriz en RotaryService :

  • off_screen_nudge_global_actions : Matriz de acciones globales para realizar cuando el usuario empuja hacia arriba, hacia abajo, hacia la izquierda o hacia la derecha desde el borde de la pantalla. No se realiza ninguna acción global si el elemento relevante de esta matriz es -1.
  • off_screen_nudge_key_codes : Matriz de códigos clave de eventos de clic para inyectar cuando el usuario empuja hacia arriba, hacia abajo, hacia la izquierda o hacia la derecha desde el borde de la pantalla. No se inyectan eventos si el elemento relevante de esta matriz es 0 ( KEYCODE_UNKNOWN ).
  • off_screen_nudge_intents : matriz de intentos para iniciar una actividad cuando el usuario empuja hacia arriba, hacia abajo, hacia la izquierda o hacia la derecha desde el borde de la pantalla. No se inicia ninguna actividad si el elemento relevante de esta matriz está vacío.

Otras configuraciones

Debe superponer los siguientes recursos RotaryService :

  • ( Android 11 QPR3, Android 11 Coche, Android 12 )
    config_showHeadsUpNotificationOnBottom : valor booleano para representar si las notificaciones emergentes deben mostrarse en la parte inferior en lugar de en la parte superior. Debe tener el mismo valor que el recurso booleano config_showHeadsUpNotificationOnBottom en frameworks/base/packages/CarSystemUI/res/values/config.xml
  • ( Android 11 QPR3, Android 11 Coche, Android 12 )
    notification_headsup_card_margin_horizontal : Margen izquierdo y derecho para la ventana de notificación emergente. Debe tener el mismo valor que el recurso de notification_headsup_card_margin_horizontal en packages/apps/Car/Notification/res/values/dimens.xml
  • ( Android 12 )
    excluded_application_overlay_window_titles : una matriz de títulos de ventanas que no deben considerarse ventanas superpuestas. Esto debe incluir títulos de ventanas de aplicaciones que representen TaskViews o TaskDisplayAreas . De forma predeterminada, esta lista contiene solo "Mapas".

Puede superponer el siguiente recurso RotaryService :

  • ( Android 11 QPR3, Android 11 Coche, Android 12 )
    long_press_ms : valor entero para representar cuántos milisegundos se debe mantener presionado el botón central para activar una pulsación prolongada. Cero indica que se debe usar el tiempo de espera de pulsación prolongada predeterminado del sistema. Este es el valor predeterminado.