Focus Navigation and Accessibility Focus conflicts

1,274 views
Skip to first unread message

Renato Iwashima

unread,
Nov 28, 2016, 7:35:55 PM11/28/16
to Eyes-free Programming and development

Hi,


I originally posted this at the Google Code Labs - Basic Android Accessibility training repository as an issue. I'm posting it here as well to see if any other developers or Google developers have any feedback on this.


I'd like to share a few thoughts/problems about the subject of grouping content for accessibility services.


Focus navigation vs Accessibility Focus


Here's a quick definition before we continue:

  • Focus navigation: Similar to desktop keyboard navigation (tab, arrows keys, enter, esc). Keyboard or Directional Pad users. Focus is placed only on items that require user interaction (e.g. clickable views or buttons, inputs like EditTextCheckBoxSwitch, etc).

  • Accessibility Focus: Focus for accessibility services, primarily screen readers such as TalkBack. Focus is placed on all meaningful views of the screen, including non-focusable views such as TextView or ImageView, which has either text or content descriptions.

The problem


Google has been advocating a technique to group non-focusable items by using android:focusable="true" to the parent ViewGroup so that its contents are read all at once for screen reader users.

You can see this recommendation in one of the Google Code Labs courses.


While grouping content is good for screen reader users, it creates a problem for keyboard users.


The problem is that android:focusable is meant for focus navigation and not accessibility focus. The consequences are:

  1. Views with no user interaction will now have focus via keyboard navigation. For example, focus on a ViewGroup that only has text views and no actions.
  2. These views will probably not have a focusable indicator (added as a StateListDrawable). Keyboard users won't be able to tell where the focus is at anymore. Even if we add a focusable indicator to these views, there is still no reason to have focus on TextViews for example.

Solutions


Unless if the statements above are wrong, then I recommend the following:

  1. Make it more evident the distinction between focus navigation and accessibility focus in Google's documentation and training material.
  2. Suggest using android:importantForAccessibility instead of android:focusable. The only drawback is the API level since it was only introduced at API 16.

Focus behavior in a ViewGroup


Regardless of the issue mentioned above, there's an interesting thing about allowing a ViewGroup to receive focus. Consider the following code:


<LinearLayout
    android:orientation="vertical"
    android:focusable="true"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:text="Heading One"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <Button
        android:text="Action"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:text="Heading Two"
        android:background="@drawable/focusable"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>


What's the focus behavior for focus navigation (Keyboard)?

  1. Focus moves to the LinearLayout.
  2. Focus moves to the Button.

This is the expected behavior since we've asked for the LinearLayout to receive focus.


What's the accessibility focus behavior?

  1. Focus moves to the LinearLayout, announcing all its text content except for the Button text: "Heading one, Heading Two".
  2. Focus moves to the Button, announcing the button: "Action, Button".

This creates a problem since the order here matters and the original order is different then the one being announced.


Solutions


There are two ways that developers have been solving this issue:

  1. Remove android:focusable from the container (no need to group text content if they are separated by focusable views) or...
  2. Add android:focusable to the two TextView inside.

Removing android:focusable from the container is not always an option and having focus on a container can actually be important. For example, a ViewPager will announce that you are on a multi-page view, which page it is currently displaying, and allowing us to use gestures or keyboard arrows to switch pages. We still want to keep this behavior. ViewPager is a very popular widget and it is quite common to find this problem on many Android apps.


Adding android:focusable to the two TextView is a solution but it makes non-focusable views now focusable to keyboard users (the issue mentioned at the beginning). For ViewPager, developers must also provide at least an android:contentDescription to the ViewPager, otherwise the it won't gain focus since it has no description.


Adding android:importantForAccessibility="yes" to the two TextView doesn't help since they are already set to yes by default. What dictates the accessibility focus behavior here is wether child views is focusable or not.


Luckily, we can set a view focusable only to accessibility services. To do this, we have to set to true the setFocusable(boolean focusable) method in the AccessibilityNodeInfo using an accessibility delegate instead of the setFocusable(boolean focusable) from a View.


It would be better, though, if Android could provide something like android:accessibilityFocusable.


There could be other options like changing TalkBack behavior or fixing the most popular ViewGroups like ViewPagerRecyclerView, etc.




I'm looking for a feedback on this, see if any of my suggestions or assumptions are wrong, or even the possibility of Google to implement any of the suggestions.


Thanks!

Victor Tsaran

unread,
Dec 9, 2016, 11:42:06 PM12/9/16
to Eyes-free Programming and development
Hi.
You should not overuse the view grouping technique as it primarily intended to cover cases where the children of a grouping view would need no focus. For example, a playlist or a receipt,  or an entry in the list of email messages.
If a view group contains elements that require focus, this technique probably is not the best candidate for the reasons you described.
In some instances, addChildrenForAccessibility API in the View class may help with grouping elements for readability.

Renato Iwashima

unread,
Dec 20, 2016, 3:12:31 PM12/20/16
to Eyes-free Programming and development
Thanks for the response Victor and for pointing out the addChildrenForAccessibility API.

I agree with you. However, I believe there are special cases where a focus on the container is desired even if it has child elements that require focus.

For example, having focus on the container of a ViewPager is desired since by default it has the following properties:

1. Role (multi-page view)
2. Value (current page and total number of pages)
3. It also allows gestures to go to the next or previous page

This is usually where I find the problem I previously described (text views being combined and skipping focusable elements).

So to fix this, I do the following:

1. Add a content description to the view pager container to serve as the name of the view. For example, "Photos".
2. Make all text views focusable to prevent them from being combined when focus is on the view pager.

I believe this solution works great but the only issue is that by using "android:focusable", it makes all text views also focusable for keyboard users.

So to make it only focusable for accessibility, I use the "setFocusable" method in the AccessibilityNodeInfo class only and not the one in the View class.

Let me know if this is an acceptable approach. It would be nice if Android could provide "android:accessibilityFocusable" attribute as a helper.

Thanks!
Reply all
Reply to author
Forward
0 new messages