Graph Theory
Graph Theory

Reputation: 699

AccessibilityEvents not being caught by service on Activity start

I'm trying to have my app announce some information to my custom AccessibilityService when the user starts an Activity. I have a TextView that calls requestFocus() when the activity starts, and then I send an AccessibilityEvent to have the AccessibilityService read the TextView's content description. I've isolated the problem into a small application.

Here's the main Activity:

package com.example.ttstest;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        View v = findViewById(R.id.textView1);
        v.requestFocus();
        v.sendAccessibilityEvent(AccessibilityEvent.TYPE_ANNOUNCEMENT);
    }
}

The layout file:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.ttstest.MainActivity" >

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:focusable="true"
        android:focusableInTouchMode="true"
        android:contentDescription="Secondarily focused text view"
        android:text="@string/hello_world" />

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/textView2"
        android:layout_marginLeft="54dp"
        android:layout_marginTop="145dp"
        android:layout_toRightOf="@+id/textView2"
        android:contentDescription="Initially focused text view"
        android:focusable="true"
        android:focusableInTouchMode="true"
        android:text="Initially focused text view" />

</RelativeLayout>

And the AccessibilityService:

package com.example.ttstest;

import android.accessibilityservice.AccessibilityService;
import android.speech.tts.TextToSpeech;
import android.speech.tts.TextToSpeech.OnInitListener;
import android.util.Log;
import android.view.accessibility.AccessibilityEvent;

public class TextToSpeechService extends AccessibilityService {
    private static TextToSpeech textToSpeech = null;
    private static boolean ttsReady = false;

    @Override
    protected void onServiceConnected() {
        super.onServiceConnected();
        Log.e("TextToSpeechService", "Got to onServiceConnected()");
        textToSpeech = new TextToSpeech(this.getApplicationContext(), new OnInitListener() {
            @Override
            public void onInit(int status) {
                if(status == TextToSpeech.SUCCESS) {
                    ttsReady = true;
                }
            }
        });
    }

    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
        Log.e("TextToSpeechService", "Entering onAccessibilityEvent().");
        Log.e("TextToSpeechService", "Event type: " + event.getEventType() + ", from class " + event.getClassName());
        if(event.getContentDescription() != null) {
            Log.e("TextToSpeechService", "" + event.getContentDescription());
        }
        if(textToSpeech != null && ttsReady == true) {
            if(event.getEventType() == AccessibilityEvent.TYPE_VIEW_FOCUSED) {
                CharSequence contentDescription = event.getContentDescription();
                if(contentDescription != null) {
                    String say = contentDescription.toString();
                    textToSpeech.speak(say, TextToSpeech.QUEUE_FLUSH, null);
                }
            } else if (event.getEventType() == AccessibilityEvent.TYPE_ANNOUNCEMENT) {
                CharSequence contentDescription = event.getContentDescription();
                if(contentDescription != null) {
                    textToSpeech.speak(event.getContentDescription().toString(), TextToSpeech.QUEUE_FLUSH, null);
                }
            }
        }
        Log.e("TextToSpeechService", "Exiting onAccessibilityEvent().");
    }

    @Override
    public void onInterrupt() {
        Log.e("TextToSpeechService", "Entering onInterrupt()");
        if(textToSpeech != null && ttsReady == true) {
            textToSpeech.stop();
        }
    }
}

This has been added to my AndroidManifest.xml in the appropriate location:

<service android:name="com.example.ttstest.TextToSpeechService"
    android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE" >
    <intent-filter>
        <action android:name="android.accessibilityservice.AccessibilityService" />
    </intent-filter>

    <meta-data android:name="android.accessibilityservice"
        android:resource="@xml/accessibilityservice"/>
</service>

My accessibilityservice.xml settings:

<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:accessibilityEventTypes="typeAllMask"
    android:notificationTimeout="100"
    android:accessibilityFeedbackType="feedbackSpoken"
    android:accessibilityFlags="flagDefault"
    android:canRetrieveWindowContent="true"
    android:packageNames="com.example.ttstest"/>

And finally, the problem. When I first start the application, neither the TextView gaining focus from requestFocus() or the call to sendAccessibilityEvent() actually send anything to the AccessibilityService. If I tab through the TextViews by attaching a physical keyboard, the focus events are received. I have made sure to turn on the AccessibilityService in the settings, and I have proof from the application I made this example from that the AccessibilityService is enabled when requestFocus() and sendAccessibilityEvent() are called. This doesn't help. It seems like when an Activity is first started, neither of these methods send anything to the AccessibilityService. I've also tried calling announceForAccessibility() with similar results.

Am I doing this wrong? How can I fix it, or at least get around it? Specifically, I want to send an event to my AccessibilityService when an Activity first starts.

More information: I have tried moving the requestFocus() and sendAccessibilityEvent() calls to onStart() and onWindowFocusChanged(); neither of these work either.

Upvotes: 2

Views: 1237

Answers (1)

tarrant
tarrant

Reputation: 2633

I may be mistaken but the "UI" isn't ready until onResume() is called so perhaps that is the issue?

Upvotes: 1

Related Questions