Guía de integración para OEM

En esta página, se describe cómo procesar entradas rotativas en el VHAL, configurar tu compilación para incluir el servicio rotativo y cómo personalizar la experiencia rotativa en todas las apps. Para las apps preinstaladas del OEM, como un selector proporcionado por el OEM, consulta Biblioteca de IU del vehículo (car-ui-library).

VHAL

Un controlador rotativo admite las siguientes acciones:

  • Desplazar hacia arriba, abajo, izquierda y derecha
  • Girar en el sentido de las manecillas del reloj y en el sentido contrario.
  • Presiona el botón Central.
  • Presiona el botón Atrás.
  • Presiona el botón de inicio.
  • Presiona otros botones, como Teléfono y Multimedia.

Consulta hardware/interfaces/automotive/vehicle/2.0/types.hal para obtener documentación sobre las propiedades del sistema y el int32Values correspondiente.

El VHAL debe controlar las siguientes acciones:

Aviso

Cuando el usuario presiona el controlador rotativo hacia la derecha, el VHAL debe usar la propiedad HW_KEY_INPUT con el siguiente int32Values para enviar un evento a Android:

  1. ACTION_DOWN
  2. KEYCODE_SYSTEM_NAVIGATION_RIGHT
  3. Pantalla de destino

Cuando el usuario suelta el controlador rotativo, el VHAL debe usar la misma propiedad y el mismo código de tecla con ACTION_UP. Los empujones en otras direcciones deben usar los códigos de teclas correspondientes.

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

  • HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_LEFT ACTION_DOWN
  • HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_UP ACTION_DOWN

En cualquier orden (y, posteriormente), soltar el controlador rotativo debería producir lo siguiente:

  • HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_LEFT ACTION_UP
  • HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_UP ACTION_UP

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

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 de repetición mientras el controlador rotativo se mantiene en una dirección.

Rotar

Cuando el usuario gira el controlador rotativo en el sentido de las manecillas del reloj un punto de detención (clic), el VHAL debe usar la propiedad HW_ROTARY_INPUT con el siguiente int32Values para enviar un evento a Android:

  1. ROTARY_INPUT_TYPE_SYSTEM_NAVIGATION
  2. Tiene un (1) seguro.
  3. Pantalla de destino

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

Una rotación de un (1) punto de detención en sentido contrario a las manecillas del reloj debería generar el mismo evento, pero con -1 para la cantidad de puntos de detención.

Si se producen varios puntos de detención de rotación en la misma dirección en rápida sucesión, el VHAL debe combinar los puntos de detención en un solo evento para no sobrecargar el sistema con eventos. En este caso, la marca de tiempo del evento debe ser cuando se produjo la primera detención de rotación. El int32Values debe incluir la cantidad de nanosegundos entre los puntos de detención de rotación consecutivos.

Por ejemplo, la siguiente secuencia de rotaciones:

  • En el paso 0, el usuario giró un seguro en sentido contrario a las manecillas del reloj.
  • En el tiempo t0 + 5 ns, el usuario giró un seguro en sentido contrario a las manecillas del reloj.
  • En el tiempo t0 + 8 ns, el usuario giró un seguro en sentido contrario a las manecillas del reloj.

debería generar este evento:

  • Propiedad: HW_ROTARY_INPUT
  • Marca de tiempo: t0
  • int32Values:
    1. ROTARY_INPUT_TYPE_SYSTEM_NAVIGATION
    2. -3 (tres puntos de detención en sentido contrario a las manecillas del reloj).
    3. Pantalla de destino
    4. 5 ns entre el primer y el segundo punto de detención.
    5. 3 ns entre el segundo y el tercer punto de detención

Botón central

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

  1. ACTION_DOWN
  2. KEYCODE_DPAD_CENTER
  3. Pantalla de destino

Cuando el usuario suelta el controlador rotativo, el VHAL debe usar la misma propiedad y el mismo código de tecla con ACTION_UP.

No generes eventos de repetición cuando se mantenga presionado el botón central.

Botón Atrás

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

  1. ACTION_DOWN
  2. KEYCODE_BACK
  3. Pantalla de destino

Cuando el usuario suelta el controlador rotativo, el VHAL debe usar la misma propiedad y el mismo código de tecla con ACTION_UP.

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

Botón Inicio

Usa el botón de inicio como lo harías con el botón Atrás, pero con KEYCODE_HOME en lugar de KEYCODE_BACK.

Otros botones

Si el controlador rotativo incluye botones adicionales, el VHAL puede controlarlos como desee el OEM, ya que no se consideran parte del control rotativo desde la perspectiva de Android. Por lo general, se controlan como los botones Atrás y Inicio, pero con códigos de teclas diferentes. Por ejemplo, KEYCODE_CALL o KEYCODE_MUSIC.

Configuración de compilación

La navegación rotativa se proporciona a través de un servicio de accesibilidad llamado RotaryService. Para incluir este servicio en la imagen del sistema de tu dispositivo, agrega la siguiente línea a tu archivo makefile:

PRODUCT_PACKAGES += CarRotaryController

También te recomendamos que incluyas los siguientes paquetes en las compilaciones de depuración:

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

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

Personalización

Los OEMs 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 sugerencias

El OEM puede configurar si está habilitado o no cada uno de los dos tipos de historial de sugerencias y, de ser así, el tamaño de la caché y la política de vencimiento. Para ello, se anula varios recursos de car-ui-library.

Caché del historial de enfoque

(Android 11 QPR3, Android 11 Car y Android 12)
Esta caché por FocusArea almacena la vista enfocada más reciente dentro de FocusArea para que se pueda enfocar cuando se vuelva a la FocusArea. Para configurar esta caché, superpone los siguientes recursos de car-ui-library:

  • car_ui_focus_history_cache_type:
    1. La caché está inhabilitada.
    2. La caché vencerá después de un tiempo (consulta a continuación).
    3. La caché nunca vencerá.
  • car_ui_focus_history_expiration_period_ms: Indica cuántos milisegundos faltan para que venza la caché si el tipo de caché se establece en dos (2) (consulta más arriba).

Caché de historial de FocusArea

(Android 11 QPR3, Android 11 Car y Android 12)
Esta caché almacena un historial de los empujones para que, cuando se empuje en la dirección opuesta, se pueda volver a enfocar en el mismo FocusArea. Para configurar esta caché, superpone los siguientes recursos de car-ui-library:

  • car_ui_focus_area_history_cache_type:
    1. La caché está inhabilitada.
    2. La caché vence después de un tiempo (consulta a continuación).
    3. La caché nunca vence.
  • car_ui_focus_area_history_expiration_period_ms: Indica cuántos milisegundos antes de que venza la caché si el tipo de caché se establece en 2 (consulta más arriba).
  • car_ui_clear_focus_area_history_when_rotating: Indica si se debe anular la caché cuando el usuario rota el controlador.

Rotación

(Android 11 QPR3, Android 11 Car y 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: Es el intervalo de tiempo (en milisegundos) que se usa para decidir si Google debe acelerar la rotación del controlador para un punto de detención de rotación. Si el intervalo entre este punto de detención y el punto de detención de rotación anterior es menor que este valor, se tratará como tres puntos de detención de rotación. Configúralo en 2147483647 para inhabilitar la aceleración 3x.
  • rotation_acceleration_2x_ms: Similar a rotation_acceleration_3x_ms. Se usa para una aceleración de 2 veces. Configúralo como 2147483647 para inhabilitar la aceleración 2x.

La aceleración funciona mejor cuando hay marcas de tiempo individuales para cada punto de detención de rotación, como exige el VHAL. Si no están disponibles, RotaryService supone que los puntos de detención de la rotación están espaciados de manera 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),

Destacado de enfoque

El OEM puede anular el elemento destacado de enfoque predeterminado en el framework de Android y varios recursos de elementos destacados de enfoque en car-ui-library.

Destacado de enfoque predeterminado

El framework de Android proporciona un elemento destacado 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 elemento de diseño de elemento destacado de enfoque predeterminado.

Por lo general, este elemento debe ser un StateListDrawable, que ajusta el fondo según diferentes combinaciones de estados, incluidos android:state_focused y android:state_pressed. Cuando el usuario use el control rotativo para enfocar una vista, android:state_focused será true, pero android:state_pressed será false. Si el usuario presiona el botón Central en el controlador rotativo, android:state_focused y android:state_pressed serán true mientras el usuario mantiene presionado el botón. Cuando el usuario suelte el botón, solo quedará android:state_focused true.

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

Enfocar recursos de elementos destacados en car-ui-library

El OEM puede anular varios recursos de car-ui-library para controlar el aspecto del foco destacado en vistas con un foco destacado no rectangular (como redondo o con forma de píldora) y en apps que usan un tema que no se deriva de Theme.DeviceDefault. Estos recursos se deben superponer para que el elemento destacado del enfoque sea coherente con el elemento de diseño del enfoque destacado predeterminado.

(Android 11 QPR3, Android 11 Car y Android 12)
Los siguientes recursos se usan para indicar cuándo una vista está enfocada, pero no se presiona:

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

(Android 11 QPR3, Android 11 Car y Android 12)
Los siguientes recursos se usan para indicar cuándo se enfoca una vista y se presiona:

  • car_ui_rotary_focus_pressed_fill_color: Es el color de relleno.
  • car_ui_rotary_focus_pressed_stroke_color: Es el color del contorno.
  • car_ui_rotary_focus_pressed_stroke_width: Grosor del contorno.

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

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

En esta situación, el desarrollador puede especificar un elemento destacado de enfoque personalizado con colores secundarios:
  • (Android 11 QPR3, Android 11 Car y 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, solo quieres un relleno o solo un contorno.

Destacado de FocusArea

(Android 11 QPR3, Android 11 Car y Android 12)
FocusArea puede dibujar dos tipos de elementos destacados cuando se enfoca uno de sus elementos secundarios. Si lo deseas, puedes usar ambos en conjunto. Esta función está inhabilitada de forma predeterminada en AOSP, pero se puede habilitar anulando los recursos de car-ui-library:

  • car_ui_enable_focus_area_foreground_highlight: Dibuja un elemento destacado sobre FocusArea y sus elementos secundarios. En AOSP, este elemento de diseño es un contorno alrededor de FocusArea. Los OEMs pueden anular el elemento car_ui_focus_area_foreground_highlight de diseño.
  • car_ui_enable_focus_area_background_highlight: Dibuja un elemento destacado sobre el FocusArea, pero detrás de sus descendientes. En AOSP, este elemento de diseño es un relleno sólido. Los OEMs pueden anular el elemento drawable car_ui_focus_area_background_highlight.

Editores de método 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 Car y Android 12)
El OEM debe superponer el recurso de cadena default_touch_input_method en RotaryService para especificar el ComponentName del IME táctil. Por ejemplo, si el OEM usa el IME proporcionado con Android Automotive, debe especificar com.google.android.apps.automotive.inputmethod/.InputMethodService.

(Android 11 QPR3, Android 11 Car y Android 12)
Si el OEM creó un IME específicamente para la rueda rotativa, debe especificar su ComponentName en el recurso rotary_input_method. Si se superpone este recurso, se usa el IME especificado cada vez que el usuario interactúa con la unidad principal a través del empujón, la rotación y el botón Central del control rotativo. Cuando el usuario toque la pantalla, se usará el IME anterior. El botón Atrás (y otros botones del control rotativo) no tienen efecto en la selección del IME. Si este recurso no se superpone, no se produce ningún cambio de IME. Carboard no admite dispositivos rotativos, por lo que el usuario no puede ingresar texto a través del controlador rotativo si el OEM no proporcionó un IME rotativo.

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

Sugerencias fuera de la pantalla

De forma predeterminada, cuando el usuario intenta mover 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 lo siguiente:

  1. Es una acción global definida por AccessibilityService. Por ejemplo, GLOBAL_ACTION_BACK.
  2. Un código de clave, como KEYCODE_BACK
  3. Un intent para iniciar una actividad representada como una URL.

(Android 11 QPR3, Android 11 Car y Android 12)
Para especificarlos, se superponen los siguientes recursos de array en RotaryService:

  • off_screen_nudge_global_actions: Es un array de acciones globales que se deben realizar cuando el usuario empuja hacia arriba, abajo, izquierda o derecha desde el borde de la pantalla. No se realiza ninguna acción global si el elemento relevante de este array es -1.
  • off_screen_nudge_key_codes: Es un array de códigos de teclas de eventos de clic para insertar cuando el usuario empuja hacia arriba, abajo, izquierda o derecha desde el borde de la pantalla. No se insertan eventos si el elemento relevante de este array es 0 (KEYCODE_UNKNOWN).
  • off_screen_nudge_intents: Es un array de intents para iniciar una actividad cuando el usuario presiona hacia arriba, abajo, izquierda o derecha desde el borde de la pantalla. No se inicia ninguna actividad si el elemento relevante de este array está vacío.

Otros parámetros de configuración

Debes superponer los siguientes recursos de RotaryService:

  • (Android 11 QPR3, Android 11 Car y Android 12)
    config_showHeadsUpNotificationOnBottom: Es un valor booleano que representa si las notificaciones emergentes se deben mostrar en la parte inferior en lugar de 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 Car y 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 dimensión notification_headsup_card_margin_horizontal en packages/apps/Car/Notification/res/values/dimens.xml.
  • (Android 12)
    excluded_application_overlay_window_titles: Es un array de títulos de ventanas que no se deben considerar ventanas superpuestas. Esto debe incluir los títulos de las ventanas de la app que representan TaskViews o TaskDisplayAreas. De forma predeterminada, esta lista solo contiene "Maps".

Puedes superponer el siguiente recurso RotaryService:

  • (Android 11 QPR3, Android 11 para vehículos y Android 12)
    long_press_ms: Es un valor entero que representa cuántos milisegundos se debe mantener presionado el botón central para activar una acción de mantener presionado. Cero indica que se debe usar el tiempo de espera predeterminado del sistema para mantener presionada la pantalla. Este es el valor predeterminado.