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.
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
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 que será anunciado pelo TalkBack.Especifique
AccessibilityNodeInfo.setClassName()
para que os serviços possam distinguir o tipo de componente.Ao implementar
performAction()
, reflita a ação usando umAccessibilityEvent
correspondente.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
AccessibilityNodeInfo
para identificar outras maneiras de como os serviços de acessibilidade podem interagir melhor com os componentes.
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.