Skip to content
This repository has been archived by the owner on Jan 25, 2024. It is now read-only.

Grouping non-focusable content with android:focusable shouldn't be recommended #4

Closed
renatoi opened this issue Nov 29, 2016 · 10 comments

Comments

@renatoi
Copy link

renatoi commented Nov 29, 2016

First of all, I appreciate all the work Google is putting together about accessibility. It's great to have more materials about Android Accessibility.

I'm an accessibility professional myself that have been working closely with Android applications. I'd like to share a few thoughts/problems about the subject of grouping content.

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 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.

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. I believe this distinction is only mentioned here in the notes.
  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 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!

@Kyle-Falconer
Copy link

Seems like this might be a solution to issue #1

@bamarch92
Copy link

I have been encountering this exact issue in my development work.
These accessibility practices need more references & support—as does how to best use AccessibilityNodeInfo events.

@martygeek
Copy link

Excellent article. I just spent a few days doing my first accessibility rework and finding the same issues of grouping content but allowing keyboard navigation. You've encapsulated the issues well.

@yychun1990
Copy link

from Android P onwards, you can use android:screenReaderFocusable to achieve accessibility focusable, cheers~~
https://developer.android.com/reference/android/R.attr#screenReaderFocusable

@tiembo
Copy link
Contributor

tiembo commented Nov 8, 2019

Hi there - this codelab has been recently updated. Closing out this issue as it's over a year old; please comment if you are still running into this problem. Thank you!

@tiembo tiembo closed this as completed Nov 8, 2019
@wesalvaro
Copy link

@tiembo The codelab still says to use focusable and makes no mention of importantForAccessibility nor screenReaderFocusable.

@karan4c6
Copy link

The issue still exists because we need to set the view as focusable=true, in order for it to be read by talkback. Then the keyboard focus will also go there, which is not required. How do we solve this for Android Versions < P ?

@Txagg1992
Copy link

How would you remove the focus for a webview while using Talkback?

@zsperske
Copy link

zsperske commented Feb 28, 2023

screenReaderFocusable attribute appears not to work even following the basic examples in the the official Google documentation for it. I filed this bug along with a reproducer project: https://issuetracker.google.com/issues/270525321

@wesalvaro
Copy link

The project linked from that bug seems to be missing importantForAccessibility=YES which is required for screenReaderFocusable.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants