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 personalizada que interagem diretamente com o OpenGL ou a tela de pintura podem não funcionar bem com serviços de acessibilidade, como o Talkback e o Acesso com interruptor.
Considere alguns dos problemas a seguir que podem ocorrer com o Talkback ativado:
- O foco de acessibilidade (um retângulo verde) pode desaparecer no seu app.
- O foco de acessibilidade pode selecionar o limite de toda a tela.
- O foco de acessibilidade não pode ser movido.
- As quatro teclas de direção no botão direcional podem não ter efeito, mesmo que o código as processe.
Se você observar algum desses problemas no seu app, verifique se ele expõe a
AccessibilityNodeInfo árvore aos serviços de acessibilidade.
O restante deste guia oferece algumas soluções e práticas recomendadas para resolver esses problemas.
Os eventos do botão direcional são consumidos por serviços de acessibilidade
A causa raiz desse problema é que os eventos de tecla são consumidos por serviços de acessibilidade.
Conforme ilustrado na Figura 1, quando o Talkback está ativado, os eventos do botão direcional não são transmitidos ao gerenciador do botão direcional definido pelo desenvolvedor. Em vez disso, os serviços de acessibilidade recebem os eventos de tecla para que possam mover o foco de acessibilidade. Como os componentes personalizados do Android não expõem informações aos serviços de acessibilidade sobre a posição deles na tela por padrão, os serviços de acessibilidade não podem mover o foco de acessibilidade para destacá-los.
Outros serviços de acessibilidade são afetados de maneira semelhante: os eventos do botão direcional também podem ser efetivados ao usar o Acesso com interruptor.
Como os eventos do botão direcional são enviados aos serviços de acessibilidade e esse serviço não sabe onde os componentes da interface estão em uma visualização personalizada, é necessário implementar AccessibilityNodeInfo para que o app encaminhe os eventos de tecla corretamente.
Expor informações aos 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 das visualizações
para que os serviços de acessibilidade possam gerenciar o foco, implemente
ExploreByTouchHelper e defina-o usando
ViewCompat.setAccessibilityDelegate(View, AccessibilityDelegateCompat)
para visualizações personalizadas.
Ao implementar ExploreByTouchHelper, substitua os quatro métodos abstratos dele:
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 mais detalhes, assista o Google I/O 2013 - Enabling Blind and Low-Vision Accessibility on Android ou leia mais sobre como preencher eventos de acessibilidade.
Práticas recomendadas
Obrigatório:
AccessibilityNodeInfo.getBoundsInScreen()precisa definir a posição do componente.Obrigatório:
AccessibilityNodeInfo.setVisibleToUser()precisa refletir a visibilidade do componente.Obrigatório:
AccessibilityNodeInfo.getContentDescription()precisa especificar a descrição do conteúdo para o Talkback anunciar.Especifique
AccessibilityNodeInfo.setClassName()para que os serviços possam distinguir o tipo de componente.Ao implementar
performAction(), reflita a ação usando um correspondenteAccessibilityEvent.Para implementar mais tipos de ação, como
ACTION_CLICK, invoqueAccessibilityNodeInfo.addAction(ACTION_CLICK)usando a lógica correspondente emperformAction().Quando aplicável, reflita o estado do componente para
setFocusable(),setClickable(),setScrollable()e métodos semelhantes.Consulte a documentação de
AccessibilityNodeInfopara identificar outras maneiras pelas quais os serviços de acessibilidade podem interagir melhor com seus componentes.
Exemplo
Consulte o exemplo de acessibilidade de visualização personalizada para Android TV para conferir as melhores práticas para adicionar suporte à acessibilidade a apps que usam visualizações personalizadas.