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.
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 EditText, CheckBox, Switch, 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.
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:
ViewGroup that only has text views and no actions.Unless if the statements above are wrong, then I recommend the following:
ViewGroupRegardless 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>
LinearLayout.Button.This is the expected behavior since we've asked for the LinearLayout to receive focus.
LinearLayout, announcing all its text content except for the Button text: "Heading one, Heading Two".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.
There are two ways that developers have been solving this issue:
android:focusable from the container (no need to group text content if they are separated by focusable views) or...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 ViewPager, RecyclerView, 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!