0

Bacground

I have been working on stripping out a library that deals with adding Accessibility with Talkback that I have created in an existing app. Originally my custom views were all ViewGroups, so I got everything working amazingly with ViewGroups (focusable navigation with D-pad, initial view focus, and content descriptions)

When I was moving this to a standalone library, I noticed that it didn't work with View. I thought ViewGroup was the superclass, but it turns out that View is the superclass. So I have been trying to find some workarounds to fix my issue. I started to do the following, and have a question based on this approach...

Code In Question

public class Accessibility {
    public static ViewGroupAccessibility with(ViewGroup viewGroup) {
        return new ViewGroupAccessibility(viewGroup);
    }
    public static ViewAccessibility with(View view){
        return new ViewAccessibility(view);
    }
}

I have fully implemented ViewGroupAccessibility and I intend to fully implement ViewAccessibility as it is a stub right now. So far the below code works well with TalkBack, I can do ViewGroup related stuff with ViewGroups, and it appears that I can do View related stuff with Views; however, I am wondering if this is even needed

What I know

Accessibility.with(new RelativeLayout(...))  // Returns ViewGroupAccessibility as RelativeLayout is a ViewGroup
//

...will return a ViewGroupAccessibility that can handle ViewGroup related stuff that can contain many different View and ViewGroup. (See code at the bottom of this post for real usage, and what what methods are available for ViewGroupAccessibility)

Accessibility.with(new Button(...))  // Returns ViewAccessibility as Button is a View
//

...will return a ViewAccessibility that can handle single View only related stuff (that is my assumption). Think only a Button.

What I don't know

// Hypothetical Usage
Accessibility
    .with(new ClassThatExtendsView_WithMultipleComponentsThatCanHaveAccessibilitySetOnEachComponentIndividually(...));

// Custom View that extends View
public class ClassThatExtendsView_WithMultipleComponentsThatCanHaveAccessibilitySetOnEachComponentIndividually extends View { 
    ... 
}
  • Is this even possible? If no, then I am good. If yes, then I have a lot extra to think about
  • It will return a ViewAccessibility that can handle single View only, but then that would be the wrong thing to return.

Another way of asking the question is am I guaranteed that if a user calls Accessibility.with(View) that the given view will ALWAYS be a single view only? Like Just a single Button. Or can the View be made of more than one component


Full Code

You can check out the code at https://codereview.stackexchange.com/questions/134289/easily-add-accessibility-to-your-app-as-an-afterthought-yes-as-an-afterthought (there is also a GitHub link to the original code). I go in incredible detail into how the project was started, my design decisions, and my future goals all to help guide the code review process.

However, here is a snippet of a usage I have for ViewGroup

public class ContributionView extends RelativeLayout implements Mappable<Resume.Contribution> {

    // Called from Constructors
    private void init(AttributeSet attrs, int defStyle) {

        root = (ViewGroup) LayoutInflater.from(getContext()).inflate(
                R.layout.internal_contribution_view, this, true);

        ...

        // Declare Navigation Accessibility
        Accessibility.with(root)
                
                // Disable certain views in the ViewGroup from ever gaining focus
                .disableFocusableNavigationOn(
                        R.id.contribution_textview_creator,
                        R.id.contribution_textview_year)

                // For all focusable views in the ViewGroup, set the D-pad Navigation
                .setFocusableNavigationOn(txtProjectName)
                    .down(R.id.contribution_textview_description).complete()
                .setFocusableNavigationOn(txtContributionDescription)
                    .up(R.id.contribution_textview_name)
                    .down(R.id.contribution_textview_link).complete()
                .setFocusableNavigationOn(txtProjectLink)
                    .up(R.id.project_textview_description).complete()

                // Set which view in the ViewGroup will have be first to be focused
                .requestFocusOn(R.id.contribution_textview_name);

        invalidateView();

    }
  
    private void invalidateView() {

        ...

        // Declare Content Description Accessibility
        Accessibility.with(root)

                // Set the content descriptions for each focusable view in the ViewGroup

                // Set the content description for the Contribution Name
                .setAccessibilityTextOn(txtProjectName)
                    .setModifiableContentDescription(getProjectName())
                        .prepend("Contribution occurred on the Project called ")
                        .append(String.format(" by %s in %s",
                                getProjectCreator(),
                                getContributionYear())).complete()

                // Set the content description for the Contribution Description
                .setAccessibilityTextOn(txtContributionDescription)
                    .setModifiableContentDescription(getContributionDescription())
                        .prepend("Description: ").complete()

                // Set the content description for the Contribution URL
                .setAccessibilityTextOn(txtProjectLink)
                    .setModifiableContentDescription(getProjectLink())
                        .prepend("URL is ").complete();

    }

    ...

}
Community
  • 1
  • 1
Christopher Rucinski
  • 4,737
  • 2
  • 27
  • 58
  • I know a `View` can be a `ViewGroup`, but in the case where I specifically handle `ViewGroup`, can a `View` contain multiple UI components that need Talkback support – Christopher Rucinski Jul 09 '16 at 11:24
  • I think the **smallest resolution** for the Talkback focus box is a single View. If you are navigating a ViewGroup, then Talkback can walk every view inside of the ViewGroup. However, IF you were to draw several "labels with descriptions" as a Single View, and wanted to walk them individually, then that would NOT be possible. Talkback will see it as a single View only. If you wanted Talkback to read the text, you could set the content description of what is displayed, but you can pause and swipe to read the next label and description – Christopher Rucinski Jul 10 '16 at 19:55

1 Answers1

1

Yes, there is a way to move accessibility amongst the various areas/components of a View. It requires a little work, though.

Start here: https://developer.android.com/reference/android/view/accessibility/AccessibilityNodeProvider.html

Streets Of Boston
  • 12,576
  • 2
  • 25
  • 28
  • I know that you don't have a lot of knowledge of my API, but based on the usage code at the bottom of my post, do you believe that this should NOT work? `Accessibility.with((ViewGroup) new HypotheticalComplexSingleView(getContext())).disableFocusableNavigationOn(...).setFocusableNavigationOn(...)...` (allowing me to search for view ids and use the android View object). Basically what I am saying is that to handle this use-case I would need special APIs and logic? – Christopher Rucinski Jul 10 '16 at 20:18
  • I am looking at this video from Google I/O 2013 @16:00+ The example at 17minutes seems just like the HypotheticalComplexSingleView item, and that means I would need to implement a new branch to my API https://youtu.be/ld7kZRpMGb8?t=15m56s – Christopher Rucinski Jul 10 '16 at 21:00