Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android TalkBack: Is there a Listener to catch all Accessibility Events?

Background: What is the problem

My app has this acronym for a word let us assume it is

ABC

When I use Google's voice service it reads out the letters which is great

However when I use Samsung Voice (S Voice), it reads it out as 1 word which is not great!

So why not just set content descriptions?

ABC appears in many places, it is not viable to setup alternative content descriptions. Also it could break the content description for other voice over services that read it out correctly like Google's one

My Plan

So I had an issue a while back and I found this great method for classes that extend ViewGroup which was onRequestSendAccessibilityEvent. To sum up, this method allows you to catch a AccessibilityEvent to modify it in some way before it is processed. Among other things you can grab the content description to be read out and modify it.

My idea is to obtain what the current TTS or TalkBack service engine is being used and use regex to edit a content description for the letters ABC and make it A B C if it Samsung Voice (S Voice). Hopefully!

My question

Anyone know a listener or callback to get the AccessibilityEvent to be processed in a global or generic case? onRequestSendAccessibilityEvent is only for ViewGroup. I could not find an alternative for Activity.

Anyone know how to catch all incoming AccessibilityEvent or maybe an alternative solution to my problem

Thanks for reading!

like image 595
Ersen Osman Avatar asked May 30 '17 19:05

Ersen Osman


People also ask

What can you do with TalkBack?

TalkBack is the Google screen reader included on Android devices. TalkBack gives you eyes-free control of your device. The setup of your device depends on the device manufacturer, Android version, and TalkBack version. These help pages apply to most devices, but you might experience some differences.

How do you know if TalkBack is active on Android?

More details: if you are strictly interested in whether TalkBack is enabled, use am. isTouchExplorationEnabled() . (If Select to Speak is enabled and TalkBack disabled, am. isEnabled() will still return true.)

How do you escape TalkBack?

On the side of your device, find both volume keys. Press and hold both volume keys for 3 seconds. To confirm that you want to turn TalkBack on or off, press both volume keys for 3 seconds again.


1 Answers

No accessibility events/delegates do not apply to Activities, and they don't need to. Every Activity should have a root/content view that is an instance of ViewGroup. This has worked well for me to filter all accessibility events within an activity:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    View contentView = findViewById(android.R.id.content);

    contentView.setAccessibilityDelegate(new View.AccessibilityDelegate(){
        @Override
        public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child, AccessibilityEvent event) {
            Log.wtf("Event: " + event.toString());
            return super.onRequestSendAccessibilityEvent(host, child, event);
        }

    });

}

I would also point out, that TalkBack supports the ability to navigate by character, and that such a solution may be solving a problem that TalkBack users do not see as a problem. In fact in some circumstances this could be viewed as worse. Any time you're changing the content an individual with a disability sees in compared to the actual content you have to do so VERY carefully. Even though the announcement is cleaner:

"ABC" != "A B C"

For example in a different case, one might view this behavior as a "feature" like:

"NASA" 

A naive implementation of this might be to just "toLowerCase" all of your content descriptions or add a space betwenn all capital letters. Clearly each of these solutions creates a different type of problem.

My point is, TalkBack gives users the ability to navigate by character if content on the screen is confusing them. AT users on various platforms will become accustomed to the "quarks" of their platform. By using one of the above solutions you have forced on them a different quark. Sometimes, the most accessible solution is to just let "ABC" == "ABC", and allow AT users to sort things out for themselves.

If you're not going to go to the trouble to fix all of your strings in the "ideal" way specifically, it is most certainly better to just leave things alone. Though, the best case scenario is to properly consider both of these problems and which solution best applies given the scenario.

Some examples of times when I prefer overriding with a content description, that could potentially be caught with regular expressions or string matching. A good implementation of this would be spotting these specific scenarios and fixing them via a REGEX -> String dictionary with "replace" to the text or content description property, and set it as the new content description.

"OFF" -> "off" //This one is super dumb on Google's part. "OFF" shows up on every switch in the OS!
"ON" -> "on" //See above comment.
"NASA" -> "nasa"
etc.

Note that in my dictionary, I'm always going towards the word and not towards the individual character announcement :). The reason for this is, I am not changing the nature of the string. Or rather, in every insance the following is true:

oldString.equalsIgnoreCase(newString);

Now add string localization into the equation and well... this is a very complicated problem indeed. Maybe just leaving things alone is the best option.

like image 133
ChrisCM Avatar answered Oct 13 '22 01:10

ChrisCM