user1980386
user1980386

Reputation: 33

PagerTabStrip TalkBack accessibility

I'm currently struggling to create PagerTabStrip with more TalkBack vocalization. The context is:

I already succeeded partially doing it by rewriting all the needed classes (for instance: PagerTitleStrip, ViewPager, FragmentPagerAdapter) and adding the right contentDescription directly on the tab TextView. It works rather well but i'm not satisfied. The maintenance of those classes need to be updated for each new versions of the Android main classes (or i will keep the old design) and i find dirty to copy paste all the class content each time (and what about the next developers ?). So, I tried another approches:

So, i wonder whether it is possible or not to use a subclass to solve my problem or if i have no choice but copying the main classes. Thanks in advance for your help.

Upvotes: 3

Views: 3725

Answers (2)

ataulm
ataulm

Reputation: 15334

For the tab itself, if you are responsible for inflating the View, then you can use a custom TextView that modifies its content description based on its activated (or selected) state:

public class TabTextView extends TextView {

    public TabTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public CharSequence getContentDescription() {
        CharSequence contentDescription = super.getContentDescription();
        return isActivated() ? appendSelectedTo(contentDescription) : contentDescription;
    }

    private String appendSelectedTo(CharSequence contentDescription) {
        return getResources().getString(R.string.tab_selected, contentDescription);
    }
}

where R.string.tab_selected is <string name="tab_selected">%1$s selected</string>

This pre-supposes that you (or the library you're using) is marking the tab view with setActivated(true)/setSelected(true) when selected (and all the other tabs with setActivated(false)/setSelected(false)).


The simplest way to announce to the user that the content has changed is to add a ViewPager.OnPageChangeListener that announces when the page changes:

viewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {

    @Override
    public void onPageSelected(int position) {
        // TODO: format correctly with String resource to support translation
        viewPager.announceForAccessibility("Showing " + viewPager.getAdapter().getPageTitle(position));
    }

});

I know Android TalkBack users are used to the behavior without indication on what is clickable

There is (by default) an indication on elements that are clickable as @ChrisCM mentioned - TalkBack will append "Double Tap to Activate" (previously "Double Tap to Select") onto Views with a View.OnClickListener attached.

You can modify the action that TalkBack reads aloud with an accessibility delegate by overriding the onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) method:

class TabAccessibilityDelegate extends AccessibilityDelegateCompat {

    @Override
    public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
        super.onInitializeAccessibilityNodeInfo(host, info);
        info.addAction(
                new AccessibilityNodeInfoCompat.AccessibilityActionCompat(
                        AccessibilityNodeInfoCompat.ACTION_CLICK,
                        "select tab"
                )
        );
    }

}

and setting it on each of your tab Views:

ViewCompat.setAccessibilityDelegate(tabView, new TabAccessibilityDelegate());

such that now TalkBack will read: "<tab content description>... double tap to select tab".

Other ways to customise the usage hint is given in this answer.

Upvotes: 1

MobA11y
MobA11y

Reputation: 18870

This is actually pretty simple. What you want to do is create a subclass of PagerTabStrip. In this subclass, augment the propagation of accessibility events to add the information that you wish! Below is my implementation.

public class A11yPagerTabStrip extends PagerTabStrip {

    public A11yPagerTabStrip(Context context) {
        super(context);
    }

    public A11yPagerTabStrip(Context context, AttributeSet attrs) {
        super(context, attrs);
    }


    @Override
    public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
        Log.wtf(LOG_TAG, "onRequestSendAccessibilityEvent: " + event.toString());

        final String textViewTitle = ((TextView) child).getText().toString();
        final ViewPager viewPager = (ViewPager) this.getParent();
        final int itemIndex = viewPager.getCurrentItem();

        String title = viewPager.getAdapter().getPageTitle(itemIndex).toString();

        if (textViewTitle.equalsIgnoreCase(title)) {
            child.setContentDescription("Tab " + textViewTitle + "selected.");
        } else {
            child.setContentDescription("Tab " + textViewTitle + "not selected.");
        }

        return super.onRequestSendAccessibilityEvent(child, event);
    }

}

Notice that I override the content description. In this way we don't change any of the visual representation of the application, just what talk back reads out.

NOTE: Talkback users are use to the "double tap to select" portion. I would leave this off, as I have done in my code.

Upvotes: 2

Related Questions