How to stop Accessibility from announcing android button as "button"? - android

I have a button in Android which has text "Next" written on it.
when, I have the accsessibility cursor focus on the button, it reads out "Next button". This is something I don't want. I want whenever, the cursor to have focus on the "Next" button, it must read out as "Next button. Double tap to select". This I can easily do, by setting the
btn.contentDescription("Next button. Double tap to select"),
but then it reads out as
"Next button. Double tap to select button", means it additionally reads out the last button, which seems very odd, with the "button" text getting read twice.
Is there any way, by which I can stop the last button to be announced?

You're trying to do things that are the responsibility of the AT. The AT knows that the object is a button due to its class type. The AT knows that it is clickable, because Clickable is a valid accessibility action.
TalkBack will then share this information, here is the breakdown:
"Next button, (pause) double tap to select"
"Next" -> Content Description/Text. This is the part you control.
"Button" -> Calculated in TalkBack based off of the valid actions and type(class) of the object.
"Double tap to select" -> This announcement is based off of Clickable being a valid accessibility action.
SO, when you set the contentdescription to "Next ....." you end up with an announcement of "next ....... button (pause) double tap to select" and no, there is no way to override this.
IF you are absolutely intent on making your app less accessible, you could create a custom control, write your own gesture recognizers (as in not using "onClick" events, because this would make your element accessibility clickable) to recognize tap gestures. And then write your own content description, that includes name, role, and instructions yourself.
This would be very silly in my opinion! Just let the content-description be "next" and let TalkBack tell users that your element is a button and how to interact with it. While perhaps not the "perfect" wording you/whoever this requirement came from's vision. It will be the way TalkBack users are accustomed to having this type of control announced. Consistency is sometimes more important than having things "just so".

I know I'm way late to the game, but posting an answer here for anyone that may happen to come across this post.
The others are right... we should not be putting the type of widget or how to interact with the widget in the content description. However, all is not lost.
Starting with API 21, there is a way to customize the interaction text through AccessibilityNodeInfo. You can use this class in two different ways:
AccessibilityNodeInfo has a getActionList() method. You can add customize the text that is read out by TalkBack by adding a new item to that list:
info.getActionList().add(new AccessibilityNodeInfo.AccessibilityAction(AccessibilityAction.ACTION_CLICK, "select");
The above code should change "Double-tap to activate" to "Double-tap to select". I say should because I'm just writing that code from memory... I haven't verified it's 100% correct, but it should be something along those lines.
There are two ways to utilize that class, and the one you choose is going to depend on your situation.
Method 1: Subclass your view:
If you create a subclass of the view you are using (in the case of the OP it would be a subclass of Button) then you can override the onInitializeAccessibilityNodeInfo() method and put the code there.
Documentation: https://developer.android.com/reference/android/view/View.html#onInitializeAccessibilityNodeInfo(android.view.accessibility.AccessibilityNodeInfo)
Method 2: Create a view accessibility delegate
This can be a bit more tricky and involved, but it does offer a ton of flexibility because you don't have to subclass the views you are working with.
Every view has a method that allows you to set an accessibility delegate, which acts like a man-in-the-middle and you can tweak things for accessibility purposes before the info goes to TalkBack.
Documentation: https://developer.android.com/reference/android/view/View.html#setAccessibilityDelegate(android.view.View.AccessibilityDelegate)
So basically you create a subclass of View.AccessibilityDelegate and override it's onInitializeAccessibilityNodeInfo() method with the code I posted above.
Documentation: https://developer.android.com/reference/android/view/View.AccessibilityDelegate.html#onInitializeAccessibilityNodeInfo(android.view.View,%20android.view.accessibility.AccessibilityNodeInfo)
Last but not least...
I did come across a way to stop the "Double tap to activate" text from being spoken out by Talkback. This should only be used when it really does make sense to remove it.
I repeat... this is not normally something you want to do.
I did recently come across a case where it made sense. I was using a TabLayout, and I noticed that Talkback would always read out "Double-tap to select" when the focus was on the selected tab (yes, I had used the method described above to change the text). Well... we don't want to tell the user to select a tab that is already selected, especially when the action results in a no-op. So, I used this little trick to get rid of that, but only for the currently selected tab. I left the unselected tabs alone so that Talkback would still give them the interaction text.
In your onInitializeAccessibilityNodeInfo() method, you can put the following code to remove that text:
info.addAction(AccessibilityNodeInfo.ACTION_FOCUS);
Again, I'm writing this code from memory, so I don't know if that's 100% there, but it gives you the gist of what to do.

Try to uncheck the setting in TalkBack -> verbosity -> speak element type -> uncheck. Now talkback will not announce class type of view at end of content description.

What you want to do is employ android:hint to provide information on inputting information (instead of adding it to the label).
Your label would be "Next" (either using labelFor with an onscreen label or android:contentDescription for hidden labeling)
Then your hint would be "Double tap to select" (using android:hint)

Related

How to make TalkBack read Android accessibility events in order without cutting them off

I have a filters view which upon dismissing, I'd like to do 2 accessibility things:
announce "$listSize items in list" since applying the filters will change the list size
set focus to the "Add filters" button
I tried the following:
filtersButton.announceForAccessibility("$listSize items in list")
filtersButton.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED)
I would expect TalkBack to read, in order:
"20 items in list"
"Filters button"
However, it usually skips the first read-out and only reads the text on filtersButton. Sometimes it will read only part of the first before skipping to the second.
How do I force TalkBack to read out both accessibility events?
It is good practice, and a recommended approach, to make the textual and audible information similar. Try to avoid announcements, instead make the screen reader read the information that is shown. The method announceForAccessibility() is intended to inform visual changes that otherwise would be unnoticed.
Do you have a view on your screen that shows the total number of items? If you don't have a visual clue of the item count, you shouldn't announce it on TalkBack. Either the information is important and you should present it visually to all users, or the information is not that important to be displayed on the screen, and shouldn't be announced on the screen reader.
If you have it visible on the screen, you may use the AccessibilityLiveRegion to let the reader announce the changed value, and keep the focus on the Add filters button. Another approach would be simply setting the first focus to the view showing the items list count, and letting the user navigate to the button next.
ViewCompat.setAccessibilityLiveRegion(itemCountTextView, ACCESSIBILITY_LIVE_REGION_POLITE)

What is the difference between accessible, accessibilityLabel and accessibilityHint properties of Text component in react native?

What is the difference between accessible, accessibilityLabel and accessibilityHint properties of Text component in react native? React native documentation is not enough to understand. Examples would be more appreciated.
accessible - the flag set to true will enable the view or component to be an accessibility element that can be read by VoiceOver for people with disabilities.
accessibilityLabel - When the VoiceOver goes over the accessibility element if there is no label given it will just read as a textfield, label or button. Instead you can make it read as "username field", "password field", "Login button" etc
accessibilityHint - This is used to inform the user what will be the action performed on tapping or interacting with that UI element.
For example if you've a "Login button" when the user clicks on it. You want to inform the user the action that will be performed after that some like - "When you tap on this login button. Your username and password will be validated and on successfull login you will be taken to the dashboard screen"
Also please refer this section of the ReactNative documentation. It is very thorough with some code examples https://facebook.github.io/react-native/docs/accessibility.
I hope this should help.
Get truth from the source: https://reactnative.dev/docs/accessibility:
accessible When true, indicates that the view is an accessibility element. When a view is an accessibility element, it groups its children into a single selectable component. By default, all touchable elements are accessible.On Android, accessible={true} property for a react-native View will be translated into native focusable={true}.
accessibilityHint
An accessibility hint helps users understand what will happen when they perform an action on the accessibility element when that result is not clear from the accessibility label.
Hints are only necessary for elements that are uncertain, and primarily intended for interactive elements, not text. Login buttons don't need hints. You know you are logging in. But maybe selecting text plays a song. What? That is not expected, so the accessibilityHint for that would be something simple and direct, like "plays this song". Notice the verb is not a command. And it's not a long sentence like #Hasseb here suggested. Also note that this interactive example is a button because it performs an action. Code it as a button with accessibilityRole="button".
accessibilityLabel
When a view is marked as accessible, it is a good practice to set an accessibilityLabel on the view, so that people who use VoiceOver know what element they have selected. VoiceOver will read this string when a user selects the associated element.
The example in ReactNative of stating "Tap me" when a button has text saying "Press me!" is not good; text is already there and the suggested label is a different word. That's straight up confusing! AccessibilityLabel is more intended for icons like info icons; or a settings menu (whether shaped like a hamburger menu, person outline, or a gear, it's still settings); or images that are tappable. The accessibilityLabel for settings is AccessibilityLabel="settings". Until you label that icon, it's just "button".
There are quiet a few more ReactNative APIs. Learn them, it will help your career.

How to tell TalkBack a custom view is being used as a button

I’m using a custom view as a button on Android, which doesn't inherit from android.widget.Button. What is the best way of telling the accessibility services it's a button?
Is it enough to just call setClickable(true) on the view?
With a standard Button, TalkBack appends the word "button" as a hint, but with a custom view it doesn’t do that. Should I be adding the word "button" as a hint somewhere?
On iOS, I’d add a button "trait" to the view, and VoiceOver annonces it as a button. Is there anything similar on Android?
If you dig through the TalkBack project, in Role.java, you will see that the hint text "button" is applied in the following circumstances:
The element has a class of android.widget.Button
OR
The element has a class of android.widget.ImageView
The element isClickable()
HOWEVER, anything that isClickable() will have the hint text "Double tap to ...." applied to it. So, the answer is NO, you should not. "Button" means something very specific to TalkBack users, and it is best to allow the Android Operating System and TalkBack to work together to figure out what that is.
Would it be better if TalkBack just announced all Trivially clickable things as buttons, instead of putting that information in the delayed hint text: "Double tap to..." (... = Expand, activate, etc, depending on control) Yes, it probably would.
Would it be better if Android allowed you to say: "Yes this thing I've subclassed is a button", like iOS traits. Yes, it probably would.
In fact, I would argue that given the: "Double tap to ...." announcement, that the announcement of "button" in this scenario is additional information. "Button" means nothing more than the thing can be double tapped to be actioned. If "button" announcement only applied to "buttons" this wouldn't be the case, as "android.widget.Button" objects are styled certain ways (typically). But, since this is also applied to IMAGE_VIEWS, without being applied to other simple "clickable" views, its purpose is muddy, and ultimately useless and confusing. AND NO, you should not attempt to rectify this. It is absolutely TalkBack's job to get this right, which it does... just in other ways. Let me explain:
The announcement of button has essentially been deprecated, and replaced by the delayed announcement "double tap to ...". The "button" announcement was left in as legacy support for users that were accustomed to that announcement.
To summarize: ensure that "Double tap to ...." is announced AFTER your control. Though, just ensuring that your node has a click listener and "isClickable" should be enough for this. This delayed hint announcement is the important bit. The announcement of "button" is unimportant, legacy garbage leftover from unfortunate decisions made early on in the development of the TalkBack project. THAT, or it will be fixed to be applied to all clickable things (like custom controls) in a future release. Either way, adding the word "button" to your content description would be ill advised.

Appium testing: Clicking on a textview when clickable=true

Android has a technique where you can turn text into a button. You set the element to clickable, and then define an onClick() method for it.
On the Appium side, what I'm seeing is that the text for the element ends with an "#" character. For example from "UI Automator Viewer" :
(2) TextView: Purchase an item # [69,1038][1011,1110]
The '#' is displayed as an arrow symbol on the actual phone, and clicking on the arrow, and only the arrow, will take you to a different dialog (one to make a purchase in this case). Manually clicking on the text itself does not move the app to the dialog. Only clicking on the arrow works.
My Python code looks like:
self.driver.find_element_by_id("com.mycompany.project:id/make_a_purchase_text").click()
The click() method does not take me to the correct dialog. In fact, nothing apparent happens at all. I am click()ing on a lot of elements that are buttons in order to get to this point, so I know my setup is good. Is there any support at all in Appium for this sort of control?
I'm not sure whether this is the best way of doing it. To me it seems that selenium WebElement cannot detect the additional properties given to a TextView or a UIAStaticText. So when we assign a click property the base class behind the element cannot do the click event.
So as a workaround i sent a touch event to the required x,y location
driver.executeScript("mobile: tap", new HashMap<String, Double>() {
{
put("tapCount", 1d);
put("touchCount", 1d);
put("duration", 0.52478515625);
put("x", 127d);
put("y", 571d);
}
});

Setting the Return key on the Android keyboard

Does anyone of you friendly coders know how to change the text on the return key of the android keyboard. I am catching the return event of an EditText element to start an action. So I would like to show the user, that he can start the action with that key. Some applications do that. E.g. they replace the key with a search symbol.
I am also wondering why apps always have an additional button aside the text field. Clearly, this takes away screen space. But it may be necessary for some purpose I am not aware off. The one problem I could imagine is task switching. After switching back, the user would have to call the keyboard before he could start the action. The other is a hardware keyboard, but anyone will assume that the return key will start the action.
R.G.
There are some ways to change the behaviour of the return button on your software keyboard. If you want to have the search Icon on your keyboard you have to add android:imeOptions="actionSearch" to your EditText View. There are some other actions that you can set for an overview over the available options have a look at the documentation of the TextView.
I would guess the reason that there are buttons next to many textfields to trigger the action is because users are used to it and would be a little bit at loss if the button is missing especially users with a hardware keyboard or if the software keyboard disappeared. One additional problem is that the return key is also used to create line breaks this means that if you want to have a multi line text field you cant use the return key to start an action.
If you want, you can hide the additional button beside the text area by adding the attribute
android:imeOptions="flagNoAccessoryAction" to your TextView or add it in code using
myTextView.setImeOptions(EditorInfo.IME_MASK_ACTION & EditorInfo.IME_FLAG_NO_ACCESSORY_ACTION);.
This is generally advised against, however, because of the user not being able to see what action will be performed when, say, the return key is pressed, or not being able to perform an action at all.
More info in this blog post: http://android-developers.blogspot.dk/2009/04/updating-applications-for-on-screen.html.

Categories

Resources