Search code examples
androidtalkbackswitchcompataccessibility

Android toggle textOn/Off prevent reading from Talkback


I have a SwitchCompat as toggle with text on it (HQ/LQ for different qualities of a stream). For users with good sight I think it is obvious what it means. But I have problems finding a good solution how to make it accessible.

I have set a ContentDescription for the SwitchCompatin general

<android.support.v7.widget.SwitchCompat
            android:id="@+id/qualitySwitch"
            style="@style/SwitchStyleCompat"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textOff="LQ"
            android:textOn="HQ"
            android:contentDescription="stream quality"

and want to set a contentDescription every time the SwitchCompat was toggled.

if (isChecked) {
 streamPlayerService.desireHighQuality();
 mQualitySwitch.setContentDescription("quality high");

} else {
 streamPlayerService.desireLowQuality();
 mQualitySwitch.setContentDescription("quality low");
}

But even with a contentDescription, the textOn/textOff flag will also still be read by Talkbackresulting in something like "Quality high HQ switch". Is there any way to disable reading of the textOn/textOff attributes, so that just the contentDescription is read to the user?


Solution

  • You can get the exact behaviour your looking for. But the only way to do it would be a custom control, or some hackery involving invisible views behind your switch. If TalkBack encounters a switch, it is going to read it out the way you said. Sharing state and value information. Before you go and hack together a custom control, let me present you with what I believe to be a more accessible solution. And also encourage you to check out my open source app, that deals with a lot of accessibility concepts, and in fact contains an example of the approach I'm sharing with you here.

    https://github.com/dequelabs/Deque-University-for-Android

    Remember that for accessibility any text or state must be shared in an equivalent way. You can't separate what the user hears from what they see. We are not only concerned about blind individuals, but those who may only have difficulty seeing. If the announcement is completely different from what they would expect, it can be very confusing. Also, if the announcement is confusing, perhaps you should reconsider whether or not it is equally confusing for sighted users...

    So, if you have an on/off switch, it is appropriate that at some point during an announcement it reads on or off. This is what users will be accustom to, and for perhaps dislexic users who use your controls, very confusing if you were to override this behavior. If the text of your control is confusing for sighted users, and you reiterate this exact text, it will be equally confusing for non-sighted users. This is actually more "accessible" than creating a separate user experience for TalkBack users. As it just means you have a user experience issue, and need to change the wording of your label.

    The best way to accomplish this is with a LabelFor attribute.

    <TextView
        android:labelFor="@+id/your_id"
        android:text="My Text" />
    
    <ToggleButton android:id="@+id/your_id"/>
    

    This will result in it reading off like this:

    HQ, switch, for Quality High

    If your focused on the switch this is exactly the information you need. The text on the switch is "HQ" it is a switch, and it is associated with the visual label "quality high". State, role, name... right in a row. It's a beautiful thing!

    If you think this is still confusing, you may also add a content description to the TextView, so that TalkBack users get some additional context, though it should very closely resemble the actual text. (EX: Contain the actual text, with addtional information, or perhaps do some acronym expansion).

    <TextView
        android:labelFor="@+id/my_id"
        android:text="Quality High"
        android:contentDescription="... Quality High ..." />
    
    <ToggleButton android:id="@+id/my_id"/>
    

    This will cause the content description to be read out so it reads off like this instead:

    HQ, switch for ... Quality High ...

    Or like this:

    <TextView
        android:labelFor="@+id/my_id"
        android:text="A misleading acronym CA"
        android:contentDescription="A misleading acronym Certificate Authority" />
    
    <ToggleButton android:id="@+id/my_id"/>