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.
Example problem
In this fairly simple UI, there are two TextView
s and a Button
inside a LinearLayout
. The LinearLayout
is found inside a ListView
.
<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 TextView
s and the Button
,” you’d be wrong. The correct answer is the Button
and the LinearLayout
.
Since focus will first fall on the LinearLayout
, screen reader users will hear the content of both TextView
s 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.
Stetho
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
View
is focusable - Why a
View
is or isn’t focusable - Whether it is the currently focused
View
- The description that will be sent to any Accessibility Service
- A list of supported
AccessibilityAction
s, including any custom actions.
Let’s go over these in detail.
- Ignored: A boolean displaying whether a
View
will 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
View
s, a plain-text message explaining precisely why theView
is 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
View
s, a boolean displaying whether this is the currently focused view. - Description: For focusable
View
s, the description that will be sent to Accessibility Services. This may simply be thecontentDescription
ortext
of theView
itself, 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 View
.
- Actions: For focusable
View
s, a list of all supportedAccessibilityAction
s that can be taken on this view, including any custom actions.
Running Stetho on the original example given shows that the TextView
s are not focusable because they are not actionable, and therefore their description was co-opted by their ancestor, the LinearLayout
.
Setting android:focusable="true"
on the TextView
s 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 TextView
s 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 LinearLayout
.
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.