Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Talkback double announcement when using accessibilityRole={'header'} #28800

Closed
JCron245 opened this issue May 1, 2020 · 20 comments
Closed

Talkback double announcement when using accessibilityRole={'header'} #28800

JCron245 opened this issue May 1, 2020 · 20 comments
Labels
Accessibility Team - Evaluated Accessibility API: AccessibilityInfo Platform: Android Android applications. Stale There has been a lack of activity on this issue and it may be closed soon.

Comments

@JCron245
Copy link

JCron245 commented May 1, 2020

Please provide all the information requested. Issues that do not follow this format are likely to stall.

Description

For whatever reason when attaching accessibilityRole={'header'} to an element it is announcing 'heading' twice with TalkBack on. Testing the same component on iOS using VoiceOver achieves the expected result of it only announcing once.

React Native version:

61.4

Steps To Reproduce

Provide a detailed list of steps that reproduce the issue.

  1. Create some sort of component with 'accessibilityRole={'header'}`
  2. Test on iOS and Android

Expected Results

Talkback should announce 'header' only once when using TalkBack like it does with VoiceOver.

Snack, code example, screenshot, or link to a repository:

https://snack.expo.io/@jcron/accessibility-role-double-announce

@JCron245
Copy link
Author

JCron245 commented May 1, 2020

Just as additional info I tested the above snack with the following devices:

iPhone X [iOS v13.4] - Works as expected
iPhone XS [iOS v13.5-b3] - Works as expected
iPad Mini 2 [iOS v12.4.5] - Works as expected
NVIDIA Shield Tablet [Android 7.0] - Announces 'heading' Twice
Galaxy Tab 10 [Android 8.1.0] - Announces 'heading' Twice
Moto E5 [Android 8.1.0] - Announces 'heading' Twice

@AnnieFisher
Copy link

*** Note :
When you do NOT apply an accessible label it announces "heading {Text} heading".
Not sure why this is or if it is even useful, just additional information.

@dotjay
Copy link

dotjay commented Jun 2, 2020

Another test result:
Motorola One Macro XT2016-1 [Android 9.0] - TalkBack announces 'heading' Twice

@heisenbugged
Copy link

This has been fixed in v0.63.1:
7428271

@elfstyle
Copy link

Just updated from RN 62.2 to 63.4 and accessibilityRole='header' doesn't work anymore. Does anyone experience the same issue?

@nico22utn
Copy link

Just updated from RN 62.2 to 63.4 and accessibilityRole='header' doesn't work anymore. Does anyone experience the same issue?

Yes! I have the same issue for Samsung s10e. It works as expected on any IOS device.

@amarlette
Copy link

@blavalla has not been able to reproduce this issue on the current RN version. Was this issue resolved by updates since the issue was created?

@arsimr16
Copy link

Just updated from RN 62.2 to 63.4 and accessibilityRole='header' doesn't work anymore. Does anyone experience the same issue?

I'm using a fork of react-native based on 61.4. I applied the change which @babylone-star said was added in 63.1.

This bug was reported after my app was tested for accessibility on a Pixel 4XL, but I could not reproduce it on the only testing phone I have, a Samsung Galaxy S8. Someone else tested this for me on a Razor Phone 2 and was able to reproduce the error. So it seems like the header role was announced once on Samsung phones and twice on other phones.

After applying this change, I don't hear the role announced at all on my Samsung device. I suspect the role will now be announced once on the Pixel 4XL and Razor Phone 2.

@blavalla
Copy link
Contributor

@arsimr16, this one may actually be caused by a difference in Talkback or Android versions between devices as well, or could possibly be caused by Samsung's own fork of Talkback that they use.

For what it's worth, I wasn't able to reproduce this on a Samsung Galaxy S20 or a Pixel 5. Both were running Android 11 however, and the latest versions of Talkback (Samsung's is technically a fork, but it's a new fork that should be up to date with Google's implementation).

This was the link used to test: https://snack.expo.io/7tjnjlJbO

On a technical note, the "header" role in RN right now is mapping to the older-style of heading that was only allowed within collection structures in Android (lists, grids, etc.). This works on both older and newer OS and Talkback versions (assuming your element is in a list), but starting in Android 9, Google added a more general-purpose API for headings.

Since you are already working with a fork of RN, one thing to try would be to update this to the newer-style of API to see if it works to resolve the issue. It will limit support down to only API 28 and above (Android 9) or API 19 and above (Android 4.4.) if using the AndroidX compat library.

To do that, you'll want to change these lines:

final AccessibilityNodeInfoCompat.CollectionItemInfoCompat itemInfo =
AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain(0, 1, 0, 1, true);
nodeInfo.setCollectionItemInfo(itemInfo);

To this:

nodeInfo.setHeading(true)

@kacieb, what is the lowest version of Android that React Native currently supports? If it's above 19, we may want to just switch to use the newer API here.

@arsimr16
Copy link

Thanks for the explanation. I switched to the newer API (I'm using AndroidX) and I still don't hear the header role being announced on my Samsung Galaxy S8 running Android 9.

@blavalla
Copy link
Contributor

@arsimr16, just to confirm here. Are you using Google's Talkback (installed from the Play Store), or Samsung's Voice Assistant (comes pre-installed). Voice Assistant was quite an old fork of talkback, and may not have support for the header role.

If you're using Talkback, which version?

@arsimr16
Copy link

Thanks, I didn't know that. I was using the Samsung Voice Assistant. Let me try downloading Talkback.

@arsimr16
Copy link

Works with Talkback! Thanks so much :)

@kacieb
Copy link
Contributor

kacieb commented Apr 2, 2021

@kacieb, what is the lowest version of Android that React Native currently supports? If it's above 19, we may want to just switch to use the newer API here.

That's a good idea. The minimum SDK version supported is 21 so we can switch to the newer API.

@anup690
Copy link

anup690 commented May 6, 2021

I had an issue with accessibilityRole="link", it's also announced twice like: " one link, link"
anyone had this issue and is it solved after the update?

@blavalla
Copy link
Contributor

blavalla commented May 6, 2021

@anup690 , was this double-link announcement on iOS or Android? If Android, was it using Samsung's "Voice Assistant" or Google's "Talkback"?

If I had to guess, I'd say that this sounds like something that Samsung's Voice Assistant would do. Generally speaking, Voice Assistant tried to be a bit more like Apple's VoiceOver (which automatically announces "link" after links), and RN adding a roleDescription of "Link" may have doubled this up inadvertently. That's a random guess though, and since Samsung has deprecated Voice Assistant in favor of Talkback, I can't really verify it on any of my devices.

If you do have a repro case, see if commenting out this line fixes it:

nodeInfo.setRoleDescription(context.getString(R.string.link_description));

@anup690
Copy link

anup690 commented May 28, 2021

@blavalla you guessed it bang on, it is Samsung's Voice Assistant indeed, got my tester do away with android talkback, yes I recently learned that Voice Assistant is a fork of talkback and outdated,
and the links do read fine on the stock based ROMs (due to Talkback that is)

though with talkback, it reads, "link", "links available, use swipe up and right to view" for each link in the page not the best UX,
i'm checking if there is a way to polish that like "links available, use swipe up and right to view" to utter only once in a page full of links,
thanks for the help

@blavalla
Copy link
Contributor

blavalla commented Jun 1, 2021

i'm checking if there is a way to polish that like "links available, use swipe up and right to view" to utter only once in a page full of links,

From an Android perspective, Talkback is doing this for each TextView that contains a ClickableSpan or URLSpan in its text.

From the RN side, whenever you set a link role on a component, we are under the hood creating a URLSpan and setting it as the full length of text on that component:

if (nodeInfo.getContentDescription() != null) {
SpannableString spannable = new SpannableString(nodeInfo.getContentDescription());
spannable.setSpan(new URLSpan(""), 0, spannable.length(), 0);
nodeInfo.setContentDescription(spannable);
}
if (nodeInfo.getText() != null) {
SpannableString spannable = new SpannableString(nodeInfo.getText());
spannable.setSpan(new URLSpan(""), 0, spannable.length(), 0);
nodeInfo.setText(spannable);
}

This is definitely not a great experience currently, and I'm actually working right now to implement a better approach to link handling in general, where the links act more like they do on web surfaces and get focused on their own rather than being accessed via a dedicated menu.

@github-actions
Copy link

This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.

@github-actions github-actions bot added the Stale There has been a lack of activity on this issue and it may be closed soon. label Apr 27, 2023
@github-actions
Copy link

github-actions bot commented May 4, 2023

This issue was closed because it has been stalled for 7 days with no activity.

@github-actions github-actions bot closed this as completed May 4, 2023
facebook-github-bot pushed a commit that referenced this issue Apr 19, 2024
Summary:
This sync includes the changes from:
- D56103750
- [TODO] A shim for SECRET_INTERNALS

This sync includes the following changes:
- **[b5e5ce8e0](facebook/react@b5e5ce8e0 )**: Update ReactNativeTypes for root options (part 2) ([#28857](facebook/react#28857)) //<Ricky>//
- **[da6ba53b1](facebook/react@da6ba53b1 )**: [UMD] Remove umd builds ([#28735](facebook/react#28735)) //<Josh Story>//
- **[0c245df1d](facebook/react@0c245df1d )**: Complete the typo fix ([#28856](facebook/react#28856)) //<Sebastian Silbermann>//
- **[f82051d7a](facebook/react@f82051d7a )**: console test utils fix: match entire string, not just first letter ([#28855](facebook/react#28855)) //<Andrew Clark>//
- **[4ca20fd36](facebook/react@4ca20fd36 )**: Test top level fragment inside lazy semantics ([#28852](facebook/react#28852)) //<Sebastian Markbåge>//
- **[c0cf7c696](facebook/react@c0cf7c696 )**: Promote ASYNC_ITERATOR symbol to React Symbols ([#28851](facebook/react#28851)) //<Sebastian Markbåge>//
- **[657428a9e](facebook/react@657428a9e )**: Add ReactNativeTypes for root options ([#28850](facebook/react#28850)) //<Ricky>//
- **[7909d8eab](facebook/react@7909d8eab )**: [Flight] Encode ReadableStream and AsyncIterables ([#28847](facebook/react#28847)) //<Sebastian Markbåge>//
- **[13eb61d05](facebook/react@13eb61d05 )**: Move enableUseDeferredValueInitialArg to canary ([#28818](facebook/react#28818)) //<Andrew Clark>//
- **[8afa144bd](facebook/react@8afa144bd )**: Enable flag disableClientCache ([#28846](facebook/react#28846)) //<Jan Kassens>//
- **[734956ace](facebook/react@734956ace )**: Devtools: Add support for useFormStatus ([#28413](facebook/react#28413)) //<Sebastian Silbermann>//
- **[17e920c00](facebook/react@17e920c00 )**: [Flight Reply] Encode Typed Arrays and Blobs ([#28819](facebook/react#28819)) //<Sebastian Markbåge>//
- **[0347fcd00](facebook/react@0347fcd00 )**: Add on(Caught|Uncaught|Recoverable) opts to RN ([#28836](facebook/react#28836)) //<Ricky>//
- **[c113503ad](facebook/react@c113503ad )**: Flush direct streams in Bun ([#28837](facebook/react#28837)) //<Kenta Iwasaki>//
- **[9defcd56b](facebook/react@9defcd56b )**: Remove redundant props assign ([#28829](facebook/react#28829)) //<Sebastian Silbermann>//
- **[ed4023603](facebook/react@ed4023603 )**: Fix mistaken "react-server" condition ([#28835](facebook/react#28835)) //<Sebastian Markbåge>//
- **[c8a035036](facebook/react@c8a035036 )**: [Fizz] hoistables should never flush before the preamble ([#28802](facebook/react#28802)) //<Josh Story>//
- **[4f5c812a3](facebook/react@4f5c812a3 )**: DevTools: Rely on sourcemaps to compute hook name of built-in hooks in newer versions ([#28593](facebook/react#28593)) //<Sebastian Silbermann>//
- **[435415962](facebook/react@435415962 )**: Backwards compatibility for string refs on WWW ([#28826](facebook/react#28826)) //<Jack Pope>//
- **[608edcc90](facebook/react@608edcc90 )**: [tests] add `assertConsole<method>Dev` helpers ([#28732](facebook/react#28732)) //<Ricky>//
- **[da69b6af9](facebook/react@da69b6af9 )**: ReactDOM.requestFormReset  ([#28809](facebook/react#28809)) //<Andrew Clark>//
- **[374b5d26c](facebook/react@374b5d26c )**: Scaffolding for requestFormReset API ([#28808](facebook/react#28808)) //<Andrew Clark>//
- **[41950d14a](facebook/react@41950d14a )**: Automatically reset forms after action finishes ([#28804](facebook/react#28804)) //<Andrew Clark>//
- **[dc6a7e01e](facebook/react@dc6a7e01e )**: [Float] Don't preload images inside `<noscript>` ([#28815](facebook/react#28815)) //<Josh Story>//
- **[3f947b1b4](facebook/react@3f947b1b4 )**: [tests] Assert scheduler log empty in internalAct ([#28737](facebook/react#28737)) //<Ricky>//
- **[bf09089f6](facebook/react@bf09089f6 )**: Remove Scheduler.log from ReactSuspenseFuzz-test ([#28812](facebook/react#28812)) //<Ricky>//
- **[84cb3b4cb](facebook/react@84cb3b4cb )**: Hardcode disableIEWorkarounds for www ([#28811](facebook/react#28811)) //<Ricky>//
- **[2243b40ab](facebook/react@2243b40ab )**: [tests] assertLog before act in useEffectEvent ([#28763](facebook/react#28763)) //<Ricky>//
- **[dfc64c6e3](facebook/react@dfc64c6e3 )**: [tests] assertLog before act in ReactUse ([#28762](facebook/react#28762)) //<Ricky>//
- **[42eff4bc7](facebook/react@42eff4bc7 )**: [tests] Fix assertions not flushed before act ([#28745](facebook/react#28745)) //<Ricky>//
- **[ed3c65caf](facebook/react@ed3c65caf )**: Warn if outdated JSX transform is detected ([#28781](facebook/react#28781)) //<Andrew Clark>//
- **[3f9e237a2](facebook/react@3f9e237a2 )**: Fix: Suspend while recovering from hydration error ([#28800](facebook/react#28800)) //<Andrew Clark>//
- **[7f5d25e23](facebook/react@7f5d25e23 )**: Fix cloneElement using string ref w no owner ([#28797](facebook/react#28797)) //<Joseph Savona>//
- **[bf40b0244](facebook/react@bf40b0244 )**: [Fizz] Stop publishing external-runtime to stable channel ([#28796](facebook/react#28796)) //<Josh Story>//
- **[7f93cb41c](facebook/react@7f93cb41c )**: [DOM] Infer react-server entries bundles if not explicitly configured ([#28795](facebook/react#28795)) //<Josh Story>//
- **[f61316535](facebook/react@f61316535 )**: Rename SECRET INTERNALS to `__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE` ([#28789](facebook/react#28789)) //<Sebastian Markbåge>//
- **[9644d206e](facebook/react@9644d206e )**: Soften useFormState warning ([#28788](facebook/react#28788)) //<Ricky>//
- **[c771016e1](facebook/react@c771016e1 )**: Rename The Secret Export of Server Internals ([#28786](facebook/react#28786)) //<Sebastian Markbåge>//
- **[d50323eb8](facebook/react@d50323eb8 )**: Flatten ReactSharedInternals ([#28783](facebook/react#28783)) //<Sebastian Markbåge>//
- **[f62cf8c62](facebook/react@f62cf8c62 )**: [Float] treat `props.async` in Float consistent with the rest of react-dom ([#26760](facebook/react#26760)) //<Josh Story>//
- **[dfd3d5af8](facebook/react@dfd3d5af8 )**: Add support for transition{run,start,cancel} events ([#27345](facebook/react#27345)) //<Hugo Sales>//
- **[1f8327f83](facebook/react@1f8327f83 )**: [Fiber] Use real event priority for hydration scheduling ([#28765](facebook/react#28765)) //<Josh Story>//
- **[97c90ed88](facebook/react@97c90ed88 )**: [DOM] Shrink ReactDOMCurrentDispatcher method names ([#28770](facebook/react#28770)) //<Josh Story>//
- **[9007fdc8f](facebook/react@9007fdc8f )**: [DOM] Shrink ReactDOMSharedInternals source representation ([#28771](facebook/react#28771)) //<Josh Story>//
- **[14f50ad15](facebook/react@14f50ad15 )**: [Flight] Allow lazily resolving outlined models ([#28780](facebook/react#28780)) //<Sebastian Markbåge>//
- **[4c12339ce](facebook/react@4c12339ce )**: [DOM] move `flushSync` out of the reconciler ([#28500](facebook/react#28500)) //<Josh Story>//
- **[8e1462e8c](facebook/react@8e1462e8c )**: [Fiber] Move updatePriority tracking to renderers ([#28751](facebook/react#28751)) //<Josh Story>//
- **[0b3b8a6a3](facebook/react@0b3b8a6a3 )**: jsx: Remove unnecessary hasOwnProperty check ([#28775](facebook/react#28775)) //<Andrew Clark>//
- **[2acfb7b60](facebook/react@2acfb7b60 )**: [Flight] Support FormData from Server to Client ([#28754](facebook/react#28754)) //<Sebastian Markbåge>//
- **[d1547defe](facebook/react@d1547defe )**: Fast JSX: Don't clone props object ([#28768](facebook/react#28768)) //<Andrew Clark>//
- **[bfd8da807](facebook/react@bfd8da807 )**: Make class prop resolution faster ([#28766](facebook/react#28766)) //<Andrew Clark>//
- **[cbb6f2b54](facebook/react@cbb6f2b54 )**: [Flight] Support Blobs from Server to Client ([#28755](facebook/react#28755)) //<Sebastian Markbåge>//
- **[f33a6b69c](facebook/react@f33a6b69c )**: Track Owner for Server Components in DEV ([#28753](facebook/react#28753)) //<Sebastian Markbåge>//
- **[e3ebcd54b](facebook/react@e3ebcd54b )**: Move string ref coercion to JSX runtime ([#28473](facebook/react#28473)) //<Andrew Clark>//
- **[fd0da3eef](facebook/react@fd0da3eef )**: Remove _owner field from JSX elements in prod if string refs are disabled ([#28739](facebook/react#28739)) //<Sebastian Markbåge>//

Changelog:
[General][Changed] - React Native sync for revisions 48b4ecc...b5e5ce8

jest_e2e[run_all_tests]
bypass-github-export-checks

Reviewed By: kassens

Differential Revision: D56251607

fbshipit-source-id: e16db2fa101fc7ed1e009158c76388206beabd5f
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Accessibility Team - Evaluated Accessibility API: AccessibilityInfo Platform: Android Android applications. Stale There has been a lack of activity on this issue and it may be closed soon.
Projects
None yet
Development

No branches or pull requests