Android has a powerful built-in accessibility system that allows people to use applications through an alternative interaction mode called “focus navigation.” Rather than directly touching the screen to activate an element, focus navigation allows people who use accessibility services such as screen readers, physical switch devices, refreshable Braille displays, or voice control to focus on and activate different elements of an interface.
Although focus navigation is built into the Android platform, many engineers don’t consider it when designing, building, and testing their applications. This can lead to a variety of problems, such as the inability to activate buttons or content being announced in the wrong order, which can be difficult to debug.
Accessibility is important to our work at Facebook, so to help with the above challenges we’ve added support for accessibility properties to Stetho, our open source Android debugging tool. Now engineers can easily find elements that aren’t accessible through focus navigation, understand the reasons behind the bug, and implement a fix.
Let’s go over an example of a UI with a focus navigation issue and show how Stetho makes the problem easier to debug.
In this fairly simple UI, there are two
TextViews and a
Button inside a
LinearLayout is found inside a
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" 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:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout>
Which views would you expect to be focusable? If you answered “the
TextViews and the
Button,” you’d be wrong. The correct answer is the
Button and the
Since focus will first fall on the
LinearLayout, screen reader users will hear the content of both
TextViews before the
Button that is between them. This could cause confusion if the context of the button’s action depended on being preceded by the first heading. For example, if the button said “Buy Now,” and the headings were the names of two different products, a user may not understand which product they would be purchasing by clicking the button. So why is this the case, how can we fix it, and most importantly, how could we have predicted this would happen?
Well, you could run every view through this flow chart, and keep note of what is focusable and what isn’t.
Or you could use Stetho! Stetho is an Android debugging platform that we open sourced last year. Since then, we’ve added a ton of new features, including accessibility inspection.
Stetho now includes an Accessibility Properties section that shows:
- Whether or not a
- Why a
Viewis or isn’t focusable
- Whether it is the currently focused
- The description that will be sent to any Accessibility Service
- A list of supported
AccessibilityActions, including any custom actions.
Let’s go over these in detail.
- Ignored: A boolean displaying whether a
Viewwill be ignored by Accessibility Services. This will always be the opposite of focusable.
- Focusable: A boolean displaying whether a view will be focusable by Accessibility Services. This will always be the opposite of ignored.
- Ignored-reasons: For ignored
Views, a plain-text message explaining precisely why the
Viewis being ignored.
- Focusable-reasons: For focusable Views, a plain-text message explaining precisely why the View is focusable.
Note that “actionable” in this context means a
View is clickable, long-clickable, or focusable. This could be set explicitly via setting any of those attributes, or implicitly via adding click, long-click or focus listeners.
- Focused: For focusable
Views, a boolean displaying whether this is the currently focused view.
- Description: For focusable
Views, the description that will be sent to Accessibility Services. This may simply be the
Viewitself, or may be computed by concatenating the descriptions of un-focusable child views.
This will not contain any additional text that individual Accessibility Services may add, such as the current state (selected, disabled, etc.) or position (in list, out of list, etc.) of the
- Actions: For focusable
Views, a list of all supported
AccessibilityActions that can be taken on this view, including any custom actions.
Running Stetho on the original example given shows that the
TextViews are not focusable because they are not actionable, and therefore their description was co-opted by their ancestor, the
android:focusable="true" on the
TextViews will solve the problem by making them actionable.
<TextView android:text="Heading One" android:focusable="true" android:layout_width="match_parent" android:layout_height="wrap_content" />
When both of the
TextViews are focusable, the
LinearLayout will inherently become un-focusable since it has no description of its own. Stetho will tell you this is the ignored reason when you inspect the
The new accessibility additions to Stetho made the problem easy to debug and provided a clearer understanding of why the problem occurred. Stetho now makes it easier than ever to ensure your app will be a great experience for people with disabilities and other users of assistive technology.
To learn how to integrate Stetho into your app, check out our documentation. If you’re interested in contributing to the project, check out Stetho on GitHub.