Suporte à acessibilidade de visualização personalizada no Android TV

Embora muitos apps do Android TV sejam criados com componentes nativos do Android, também é importante considerar a acessibilidade de frameworks ou componentes de terceiros, especialmente ao usar visualizações personalizadas.

Os componentes de visualização personalizados que interagem diretamente com o OpenGL ou o Canvas podem não funcionar bem com serviços de acessibilidade, como o Talkback e o acesso com interruptor.

Considere alguns dos seguintes problemas que podem ocorrer com o TalkBack ativado:

  • O foco de acessibilidade (um retângulo verde) pode desaparecer no app.
  • O foco da acessibilidade pode selecionar os limites de toda a tela.
  • O foco da acessibilidade pode não ser móvel.
  • As quatro teclas de direção no botão direcional podem não ter efeito, mesmo que sejam processadas pelo código.

Se você observar qualquer um desses problemas no app, confira se ele expõe a árvore AccessibilityNodeInfo aos serviços de acessibilidade.

O restante deste guia fornece algumas soluções e práticas recomendadas para resolver esses problemas.

Os eventos do botão direcional são consumidos pelos serviços de acessibilidade

A causa raiz desse problema é que os eventos de tecla são consumidos pelos serviços de acessibilidade.

Consumo de eventos do botão direcional Figura 1. Diagramas representando como o sistema funciona com o TalkBack ativado e desativado.

Conforme ilustrado na Figura 1, quando o TalkBack é ativado, os eventos do botão direcional não são transmitidos para o gerenciador definido pelo desenvolvedor. Em vez disso, os serviços de acessibilidade recebem os eventos de tecla para mover o foco da acessibilidade. Como os componentes personalizados do Android não expõem, por padrão, informações aos serviços de acessibilidade sobre a posição deles na tela, os serviços não podem mover o foco para destacá-los.

Outros serviços de acessibilidade são afetados da mesma forma: os eventos do botão direcional também podem ser consumidos ao usar o acesso com interruptor.

Como os eventos de botão direcional são enviados para os serviços de acessibilidade e esse serviço não sabe onde os componentes de interface estão em uma visualização personalizada, é necessário implementar AccessibilityNodeInfo para que seu app encaminhe os eventos de teclas corretamente.

Expor informações para serviços de acessibilidade

Para fornecer aos serviços de acessibilidade informações suficientes sobre o local e a descrição das visualizações personalizadas, implemente AccessibilityNodeInfo para expor detalhes de cada componente. Para definir a relação lógica de visualizações para que os serviços de acessibilidade possam gerenciar o foco, implemente ExploreByTouchHelper e configure-o usando ViewCompat.setAccessibilityDelegate(View, AccessibilityDelegateCompat) para visualizações personalizadas.

Ao implementar ExploreByTouchHelper, substitua os quatro métodos abstratos:

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 ver mais detalhes, assista Google I/O 2013 - Como ativar a acessibilidade para cegos e baixa visão no Android (em inglês) ou leia mais sobre como preencher eventos de acessibilidade.

Práticas recomendadas

Exemplo

Consulte o exemplo de acessibilidade de visualização personalizada para o Android TV e confira as práticas recomendadas para adicionar compatibilidade com acessibilidade a apps que usam visualizações personalizadas.