我正在尝试让我的应用在用户启动Activity时向我的自定义AccessibilityService宣布一些信息。我有一个TextView,它在活动开始时会调用requestFocus(),然后发送AccessibilityEvent,以使AccessibilityService读取TextView的内容描述。我已将问题隔离到一个小型应用程序中。

这是主要活动:

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);
    }
}


布局文件:

<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>


和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();
        }
    }
}


这已添加到我的AndroidManifest.xml中的适当位置:

<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>


我的accessibilityservice.xml设置:

<?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"/>


最后,问题。当我第一次启动应用程序时,TextView不能从requestFocus()获得焦点,或者对sendAccessibilityEvent()的调用实际上都不会向AccessibilityService发送任何内容。如果我通过连接物理键盘在TextViews中进行切换,则会收到焦点事件。我已经确保在设置中打开AccessibilityService,并且从我做这个示例的应用程序中得到的证据是,在调用requestFocus()和sendAccessibilityEvent()时启用了AccessibilityService。这没有帮助。似乎在首次启动Activity时,这些方法都不向AccessibilityService发送任何内容。我也尝试过以类似结果调用announceForAccessibility()。

我做错了吗?我该如何解决,或者至少可以解决它?具体来说,我想在活动首次启动时将事件发送到我的AccessibilityService。

更多信息:我尝试将requestFocus()和sendAccessibilityEvent()调用移到onStart()和onWindowFocusChanged();上。这些都不起作用。

最佳答案

我可能会弄错,但是在调用onResume()之前“ UI”还没有准备好,所以也许这是问题所在吗?

08-18 08:04