Android Recyclerview Talkback issue - android

I have an Android Recyclerview which has some more rows of item.
In the sense
Recyclerview comprises of
Row 1 ->> TextView , below that one more textview
Row 2 ->> TextView , below that one more textview
Issue is that, whenever I turn on the Talkback, it reads out the entire Recyclerview in one go, which is not expected, it should read one item at a time depending on the focussed item.
Expected behavior is - Read component on Focus when d-pad is moved onto it.
Any help??

Contrary to ChrisCM's answer, you should NOT set...
android:importantForAccessibility="no"
... on your RecyclerView. This will disable all native accessibility functionality related to your list, including the ACTION_SCROLL_FORWARD / ACTION_SCROLL_BACKWARD actions (Accessibility Source), and the ability to append "In List" / "Out of List" context to accessibility announcements.
Instead, you should set...
android:focusable="true"
android:focusableInTouchMode="true"
...on the root layout of your List items, which will enable them to gain focus individually when the accessibility user navigates to them.

It would appear that at some point in the construction process your Recycler View is marked as importantForAccessibility. When a container view is marked as important for accessibility it gathers all of the information within that container and announces it as the content description.
This should remedy the situation.
android:importantForAccessibility="no" //Or "auto"
If at no point in code did you set this otherwise, this would appear to be a bug with your flavor of Android. This is certainly not desirable default behavior.
Edit:
Changed "no" to "auto". Really we just want it to not be "yes", which is the value that creates the poor behavior. Auto behaves better with Switch Control on modern devices.
Been investigating this on and off for a bit, I don't think there's a Android OS Version agnostic solution here. Android APIs have changed their definition of Focusability vs Accessibility Focusability too many times across too many versions.

Related

Talkback announces focused button's label first before the title on Android TV

I'm implementing a screen for Android TV, which has a screen title and a button on the left side. And a list of custom views/rows(selectable/clickable), arranged vertically, on the right side of the page.
We want the button on the left to be in focus when the user sees that screen. For that, I'm calling button.requestFocus() in the onResume() of the fragment.
This breaks the accessibility. When talkback is enabled, the first thing announced is the button's label. What I want is to announce the title first and then the button's label.
I tried to announce a custom text(could be title) by
rootView.announceForAccessibility(accessibilityText)
where rootView is the root of the xml layout and accessibilityText a text which needs to be announced.
But it doesn't help, and the button's label gets the priority.
How can I solve the issue?
I would ask you to consider WCAG Guideline 3.2.1:
The intent of this Success Criterion is to ensure that functionality is predictable as visitors navigate their way through a document. Any component that is able to trigger an event when it receives focus must not change the context. Examples of changing context when a component receives focus include, but are not limited to:
forms submitted automatically when a component receives focus;
new windows launched when a component receives focus;
focus is changed to another component when that component receives focus; <-- emphasis here
Also a quote from the Android Accessibility Team:
So something similar that people like to do is manage accessibility focus themselves. And again, this is a bad idea. accessibility focus has to be determined by the accessibility service, and just like announcements this creates an inconsistency in experience. And actually, that one of the biggest issues that accessibility users face, inconsistency, across applications and over time.
With that said, you may want to consider looking at ensuring the focus order / priority of the component using the following attributes:
android:nextFocusUp
android:nextFocusDown
android:nextFocusLeft
android:nextFocusRight
And also ensure that any group component that may get highlighted has the importantForAccessibility attribute set.
I'd like to try help some more, but without an example XML file, it's difficult to get to your particular use case. Have you tried testing the view layout with accessibility users?
I took a cue from this article by ATAUL MUNIM. I added a check if talkback is enabled, before requesting the focus explicitly.
protected fun isTalkBackEnabled(): Boolean {
val a11yServices = context?.getSystemService(ACCESSIBILITY_SERVICE) as? AccessibilityManager
return a11yServices?.isTouchExplorationEnabled?:false
}
and
if(isTalkBackEnabled().not()) {
button.requestFocus()
}
This solution pretty much bailed me out from the problem I was facing. It was also the only way forward for me because my app's min API level is 21 which eliminates the option to use android:screenReaderFocusable

Can you jump out of a RecyclerView while using TalkBack gesture navigation on Android?

short version: navigating into a RecyclerView with TalkBack gestures forces you to swipe through every item before you can move on, is that normal? Is there a standard way to navigate out and onto the next element?
I'm trying to get accessibility features working smoothly in an app I'm working on, but I've run into a problem with part of the UI. I'm using RecyclerViews sized so you can only see one item at a time, snapping to the centre, so you can swipe to change the current value from a range. It's basically the NumberPicker approach but directly in the UI, instead of a separate dialog.
The issue is by doing swipe gestures (Default linear navigation) through the UI, as soon as it lands on the RecyclerView, it starts on the current item and then navigates through every single item in the list. It won't exit the RecyclerView until it's hit the last item and has nowhere else to go.
My question is, is this normal? I'm new to TalkBack and I can't find much info on what's expected in every situation. I know my situation is a little unusual (since navigating the RecyclerView implicitly means changing the current item) but just being trapped inside the list until you go through every item seems a really strange way to navigate in general.
I know there are solutions like adding navigation headings etc (which is how the Play Store seems to handle this with their "infinite" horizontally scrolling app selections) but I just wanted to check I wasn't missing something. TalkBack announces "in list" and "out of list" when you tap on/outside of the RecyclerView, so it seems like there should be a way to explicitly navigate in and out with a gesture too...? Would users be used to switching to Controls or Headings navigations to do this?
Thanks! I really want to make this work for everyone but it's hard to know if I've done something wrong, or if I'm just bumping into limitations with the standard components

Is there any Android equivalent of iOS UIAccessibilityTraits?

In my Android app I have a custom layout that is being used as a button - it consists of some TextViews and an ImageView, additionally it has some gradient background.
I'm aligning my app now to conform to the Accessibility rules. In order to do so, I would need to convert this layout into a button, so that TalkBack can correctly indicate the action, that this whole layout is clickable and serves like a button.
I know that on iOS there is a possibility to set the UIAccessibilityTraits to treat such view as a button - this kind of solution would save me a huge amount of work in terms of migration.
Is there any similar solution on Android for that? What approach should I follow in order to make this layout recognized correctly by TalkBack?
No, there's no concept of accessibility traits on Android - but you can still get a good accessibility experience without needing to specifically convert your layout into a Button.
Generally, it's most important that TalkBack (or whatever accessibility service is being used - remember, it's not just TalkBack) is able to detect that the widget is clickable and to be able to read a coherent description of what it does. The additional information that it's a button, specifically, isn't super useful, especially because there are so many different kinds of UI elements that it's often a very ambiguous question whether something even is a button.
You can test this by selecting it in TalkBack and confirming that it reads the content description properly, says something along the lines of "Double tap to activate," and performs the correct action when you double tap.
If it's not correct, make sure the content description, clickable flag, and click action are set correctly on the widget's AccessibilityNodeInfo.

How to associate Buttons with the parent view and announce to the user with TalkBack?

I'm trying to make TalkBack work for my Android app, in my app layout I have a list of CardViews inside a RecyclerView, each CardView contains several TextViews and several Buttons: App layout image
When I turn on Android TalkBack, and tap on a CardView, TalkBack announces all the TextViews, but doesn't announce any Button. If I continue swiping right, the buttons will gain focus one by one. Not sure if my understanding is correct, but seems like TalkBack treats TextViews and Buttons differently because the buttons are focusable.
Is there a way to make TalkBack announce all content on the CardView (TextViews and Buttons) and keep the Buttons focusable (so I'll still be able to set focus on Buttons by swiping)?
PS:
One solution that worked is to directly set a content description on the CardView, and make the content description contain all content of TextViews and Buttons, but that's kind of hacky, so I'm trying to find a better solution here.
Any help is appreciated. Thanks!
The behaviour you've described is expected and your solution is the correct one.
For ViewGroups with no explicit content description, TalkBack will attempt to infer one from the children, by concatenating the content description (or text value if view extends from TextView) of all the children.
Since the buttons themselves are actionable (focusable/clickable), they are not included in the inferred content description.
Setting an explicit content description on the card is the correct approach to take - your goal should be to describe the information that the card represents. IMO, it should not contain the description for the buttons since they will be separately focusable and will be read aloud when the user focuses on them.
The best approach IMO is to hide the buttons if TalkBack is enabled, and to present the cards as entities that contain a single action and a single, explicitly-set content description.
It's important not to reduce functionality for TalkBack users - all the user goals that were achievable should still be achievable; there is no requirement that the goals must be achieved in the same way by all users. So in this case, you could make the card's primary action as the click action, and offer the actions from the buttons in another place in the app.
One pattern which works well is to display a dialog on click, and this contains all the actions. This has a couple of benefits:
the card is single action so navigating between cards is single-swipe only
the default dialog is accessible by default - no extra work needed
I wrote a blog post explaining how you can do it with (and without) a library I helped write. The section under "actions dialog" is the relevant bit.
A button is actionable. If you want your users to be able to do the actions of each button, they need to be separately focusable. If they aren't actionable, they shouldn't be buttons.

How to scroll scrollable AccessibilityNodeInfo nodes

Using Android 4.2.2
I'm trying to write an AccessibilityService, and have most of the required features. I'm drawing on an overlay and allowing the user to select/cligk highlighted items via a bluetooth switch (the purpose is a disabled client wanting to interact with an android device using only one switch).
Whilst parsing a screen, I can get the root accessibiltyNodeInfo object, and all its children. I can highlight on the screen all such elements, and click a desired one by the .performAction() method.
On the home screen, there are 3 "panes" available, with the middle one being shown. Swipe left or right to see the others (standard launcher behaviour). There is a node that reports isScrollable = true, but the Action Flags do not report ACTION_SCROLL_FORWARD or ACTION_SCROLL_BACKWARDS. How do I scroll such a node, if I cannot call .performAction() on it as it does not support scrolling? Why does it report isScrollable = true if its not somehow scrollable?
Any help appreciated - thanks.
You cannot scroll a node that cannot perform ACTION_SCROLL_FORWARD or ACTION_SCROLL_BACKWARDS.
The Accessibility framework on Android is experimental at best and is plagued with inconsistencies such as the one you mentioned. In general, it is best not to rely on any of the is[Property]() methods. Instead, you should test for the property you are interested in yourself, after calling getActions() or getActionsList() on the node.

Categories

Resources