Search code examples
androidaccessibilitytext-to-speechandroid-menutalkback

Android - How to set an Accessibility Delegate on a Menu Item?


Is it possible in any way to set an Accessibility Delegate on a Menu Item? My app uses text-to-speech and I want to execute some custom code before TalkBack starts speaking the content description of my menu item (which happens when the menu item gets accessibility focus). Otherwise, the text-to-speech from my app will clash with TalkBack's text-to-speech.

Update: My app fetches a sentence from a WebView, highlights it and reads it using the TTS engine. When the sentence has been spoken, the onDone() callback starts the same method but for the next sentence.

Since TalkBack and my app are using the same TTS engine, only one utterance is allowed to be spoken at a time. So my app is reading its WebView sentence per sentence, but then the user focuses on a Menu Item and TalkBack will read its description. Because my speech utterance was interrupted, onDone() will be called (onDone() cannot distinguish whether the utterance was fully spoken or simply interrupted), so the speakNextSentence() will be called, even though my previous sentence might be interrupted after only two words. I'd like to somehow put the isPaused boolean to true before the accessibility event of the Menu Item is fired.

private class ttsUtteranceListener extends UtteranceProgressListener {

    @Override
    public void onStart(String utteranceId) {
    }

    @Override
    public void onDone(final String utteranceId) {
        if (!isPaused) {   
            ...
            speakNextSentence();
            ...
        }
    }

    @Override
    public void onError(String utteranceId) {
    }

Solution

  • What your app does could be viewed as inaccessible under WCag 2.0, guideline 2.2.2, unless handled carefully.

    Solution 1: Under this guideline the proper way to handle this scenario is to provide the user the ability to manually start/stop/pause the content. This should be fairly simple to implement. This alone should really be enough, and is really required for all 3 solutions.

    Solution 2: Another way for you to do this, would be to not do your own speech synthesis when you detect that the accessibility engine is active. Mark up your webview as a liveRegion using ACCESSIBILITY_LIVE_REGION_POLITE. Then just let talkback grab on to your updating contentDescriptions, which should contain the text of the currently highlighted sentence. This leaves TalkBack the job of figuring out what to announce when. This has the added benefit that even though your region is active and providing a lot of feedback, it will behave in a predictable way to TalkBack users. As such it is less likely to be in violation of WCag 2.2.2, though you should still be careful! And likely still need to provide the ability to pause the content.

    Solution 3: Android MenuItem's don't come with all of the accessibility API callbacks implemented. If your MenuItems for example, were buttons instead, the solution would be to override onRequestSendAccessibilityEvent and look for TYPE_VIEW_ACCESSIBILITY_FOCUSED. But MenuItems don't implement this API. So you could code up your own menu, using elements that implement these APIs, and do it the way you want. Though, I don't recommend this approach, as I mentioned before. This approach mostly likely is in violation of WCag 2.0 Accessibility Guidelines.