Compatibilidad con accesibilidad de vistas personalizada en Android TV

Si bien muchas apps de Android TV se compilan con componentes nativos de Android, también es importante tener en cuenta la accesibilidad de los frameworks o componentes de terceros, en especial cuando se usan vistas personalizadas.

Es posible que los componentes de vista personalizada que interactúan directamente con OpenGL o Canvas no funcionen bien con los servicios de accesibilidad, como TalkBack y Accesibilidad con interruptores.

Considera algunos de los siguientes problemas que pueden ocurrir con TalkBack activado:

  • Es posible que el enfoque de accesibilidad (un rectángulo verde) desaparezca en tu app.
  • Es posible que el enfoque de accesibilidad seleccione el límite de toda la pantalla.
  • Es posible que el enfoque de accesibilidad no se pueda mover.
  • Es posible que las cuatro teclas de dirección del pad direccional no tengan ningún efecto, incluso si tu código las controla.

Si observas alguno de estos problemas en tu app, verifica que exponga su AccessibilityNodeInfo árbol a los servicios de accesibilidad.

En el resto de esta guía, se proporcionan algunas soluciones y prácticas recomendadas para abordar estos problemas.

Los servicios de accesibilidad consumen los eventos del pad direccional

La causa principal de este problema es que los servicios de accesibilidad consumen los eventos de teclas.

Consumo de eventos del D-pad y TalkBack
Figura 1. Diagramas que muestran cómo funciona el sistema con TalkBack activado y desactivado.

Como se muestra en la figura 1, cuando TalkBack está activado, los eventos del pad direccional no se pasan al controlador del pad direccional definido por el desarrollador. En cambio, los servicios de accesibilidad reciben los eventos de teclas para que puedan mover el enfoque de accesibilidad. Debido a que los componentes personalizados de Android no exponen de forma predeterminada información a los servicios de accesibilidad sobre su posición en la pantalla, los servicios de accesibilidad no pueden mover el enfoque de accesibilidad para destacarlos.

Otros servicios de accesibilidad se ven afectados de manera similar: los eventos del pad direccional también se pueden consumir cuando se usa Accesibilidad con interruptores.

Debido a que los eventos del pad direccional se envían a los servicios de accesibilidad y ese servicio no sabe dónde están los componentes de la IU en una vista personalizada, debes implementar AccessibilityNodeInfo para que tu app reenvíe los eventos de teclas correctamente.

Expón información a los servicios de accesibilidad

Para proporcionar a los servicios de accesibilidad información suficiente sobre la ubicación y la descripción de las vistas personalizadas, implementa AccessibilityNodeInfo para exponer detalles de cada componente. Para definir la relación lógica de las vistas de modo que los servicios de accesibilidad puedan administrar el enfoque, implementa ExploreByTouchHelper y configúralo con ViewCompat.setAccessibilityDelegate(View, AccessibilityDelegateCompat) para las vistas personalizadas.

Cuando implementes ExploreByTouchHelper, anula sus cuatro métodos abstractos:

Kotlin

// Return the virtual view ID whose view is covered by the input point (x, y).
protected fun getVirtualViewAt(x: Float, y: Float): Int

// Fill the virtual view ID list into the input parameter virtualViewIds.
protected fun getVisibleVirtualViews(virtualViewIds: List<Int>)

// For the view whose virtualViewId is the input virtualViewId, populate the
// accessibility node information into the AccessibilityNodeInfoCompat parameter.
protected fun onPopulateNodeForVirtualView(virtualViewId: Int, @NonNull node: AccessibilityNodeInfoCompat)

// Set the accessibility handling when perform action.
protected fun onPerformActionForVirtualView(virtualViewId: Int, action: Int, @Nullable arguments: Bundle): Boolean

Java

// Return the virtual view ID whose view is covered by the input point (x, y).
protected int getVirtualViewAt(float x, float y)

// Fill the virtual view ID list into the input parameter virtualViewIds.
protected void getVisibleVirtualViews(List<Integer> virtualViewIds)

// For the view whose virtualViewId is the input virtualViewId, populate the
// accessibility node information into the AccessibilityNodeInfoCompat parameter.
protected void onPopulateNodeForVirtualView(int virtualViewId, @NonNull AccessibilityNodeInfoCompat node)

// Set the accessibility handling when perform action.
protected boolean onPerformActionForVirtualView(int virtualViewId, int action, @Nullable Bundle arguments)

Para obtener más detalles, mira Google I/O 2013: Cómo habilitar la accesibilidad para personas ciegas y con visión reducida en Android o lee más sobre cómo propagar eventos de accesibilidad.

Prácticas recomendadas

Muestra

Consulta la muestra de accesibilidad de vistas personalizadas para Android TV para ver las prácticas recomendadas para agregar compatibilidad con la accesibilidad a las apps que usan vistas personalizadas.