如何在JellyBean中检查Talkback是否激活

4

这个问题询问如何知道Android Talkback是否处于活动状态;这在Jelly Bean之前有效。从Android 4.1开始,这些步骤不再适用,因为所提到的光标为空。

话虽如此,我想问的是,在Jelly Bean中是否有一种方法可以进行相同的检查。

编辑 我尝试搜索TalkBack代码,并在这里找到了它。 为了检查TalkBack是否正在运行,我正在使用以下代码:

Intent screenReaderIntent = new Intent("android.accessibilityservice.AccessibilityService");
screenReaderIntent.addCategory("android.accessibilityservice.category.FEEDBACK_SPOKEN");
List<ResolveInfo> screenReaders = getPackageManager().queryIntentServices(screenReaderIntent, 0);
Cursor cursor = null;
ContentResolver cr = getContentResolver();
for (ResolveInfo screenReader : screenReaders) {
    cursor = cr.query(Uri.parse("content://" + screenReader.serviceInfo.packageName
            + ".providers.StatusProvider"), null, null, null, null);
    //here, cursor is not null, but calling cursor.moveToFirst() returns false, which means the cursor is empty
}

话虽如此,如果光标为空,我们如何知道TalkBack是否正在运行?

编辑2 根据@JoxTraex的建议,我现在发送广播查询是否启用TalkBack:

Intent i = new Intent();
i.setAction("com.google.android.marvin.talkback.ACTION_QUERY_TALKBACK_ENABLED_COMMAND");
sendBroadcast(i);

现在,我应该如何接收响应呢?
我尝试将以下内容添加到清单文件中,但是我的接收器没有收到任何响应:
<receiver android:name="my.package.MyBroadcastReceiver"
android:permission="com.google.android.marvin.talkback.PERMISSION_SEND_INTENT_BROADCAST_COMMANDS_TO_TALKBACK">
<intent-filter>
    <action android:name="com.google.android.marvin.talkback.ACTION_QUERY_TALKBACK_ENABLED_COMMAND" />
</intent-filter>


我的建议是浏览AOSP源代码,看看TalkBack使用了哪些API。如果TalkBack的源代码可用。 - JoxTraex
@JoxTraex 谢谢回复。我用新信息编辑了帖子,你有什么建议吗? - pandre
4个回答

21

通过使用 AccessibilityManager 可以更轻松地实现此目标。

AccessibilityManager am = (AccessibilityManager) getSystemService(ACCESSIBILITY_SERVICE);
boolean isAccessibilityEnabled = am.isEnabled();
boolean isExploreByTouchEnabled = am.isTouchExplorationEnabled();

我想在屏幕阅读器激活时禁用某个功能,这对我来说完美地解决了问题。谢谢! :) - Adam Martinu

1
你可以检查启用的语音辅助服务器。
fun Context.isScreenReaderEnabled(): Boolean {
    val accessibilityManager = getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager

    if (!accessibilityManager.isEnabled)
        return false

    val serviceInfoList = accessibilityManager.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_SPOKEN)

    if (serviceInfoList.isNullOrEmpty())
        return false

    return true
}

0

在查看TalkBackService.java时,我发现了这些代码片段。这些片段应该提供一些关于如何查询状态的见解。

代码

/**
     * {@link Intent} broadcast action for querying the state of TalkBack. </p>
     * Note: Sending intent broadcast commands to TalkBack must be performed
     * through {@link Context#sendBroadcast(Intent, String)}
     */
    @Deprecated
    // TODO(caseyburkhardt): Remove when we decide to no longer support intent broadcasts for
    // querying the current state of TalkBack.
    public static final String ACTION_QUERY_TALKBACK_ENABLED_COMMAND = "com.google.android.marvin.talkback.ACTION_QUERY_TALKBACK_ENABLED_COMMAND";

    /**
     * Result that TalkBack is enabled.
     *
     * @see #ACTION_QUERY_TALKBACK_ENABLED_COMMAND
     */
    public static final int RESULT_TALKBACK_ENABLED = 0x00000001;

    /**
     * Result that TalkBack is disabled.
     *
     * @see #ACTION_QUERY_TALKBACK_ENABLED_COMMAND
     */
    public static final int RESULT_TALKBACK_DISABLED = 0x00000002;

    /**
     * Permission to send {@link Intent} broadcast commands to TalkBack.
     */
    public static final String PERMISSION_SEND_INTENT_BROADCAST_COMMANDS_TO_TALKBACK = "com.google.android.marvin.talkback.PERMISSION_SEND_INTENT_BROADCAST_COMMANDS_TO_TALKBACK";

    /**
     * Tag for logging.
     */
    private static final String LOG_TAG = "TalkBackService";

public static final String ACTION_QUERY_TALKBACK_ENABLED_COMMAND = "com.google.android.marvin.talkback.ACTION_QUERY_TALKBACK_ENABLED_COMMAND";
..

            } else if (ACTION_QUERY_TALKBACK_ENABLED_COMMAND.equals(intentAction)) {
            // TODO(caseyburkhardt): Remove this block when we decide to no
            // longer support
            // intent broadcasts for determining the state of TalkBack in
            // favor of the content
            // provider method.
            if (sInfrastructureInitialized) {
                setResultCode(RESULT_TALKBACK_ENABLED);
            } else {
                setResultCode(RESULT_TALKBACK_DISABLED);
            }
        }
            ...
    }

解释

您必须使用以下操作将 Intent 广播发送到 TalkBackService:

public static final String ACTION_QUERY_TALKBACK_ENABLED_COMMAND = "com.google.android.marvin.talkback.ACTION_QUERY_TALKBACK_ENABLED_COMMAND";

然后检查Extras的内容并相应地处理它。

另外确保您拥有正确的权限:

public static final String PERMISSION_SEND_INTENT_BROADCAST_COMMANDS_TO_TALKBACK = "com.google.android.marvin.talkback.PERMISSION_SEND_INTENT_BROADCAST_COMMANDS_TO_TALKBACK";

那么我猜应该使用 Intent i = new Intent(); i.setAction(ACTION_QUERY_TALKBACK_ENABLED_COMMAND); sendBroadcast(i); 发送广播。但是如何接收答案呢?我应该在应用程序清单中声明一个接收器来接收答案吗? - pandre
嗨,@JoxTraex!我正在尝试弄清楚如何接收广播的响应,但到目前为止我没有成功(我在我的BroadcastReceiver中没有收到任何答案)。你能详细解释一下如何接收TalkBack的响应吗? - pandre
感谢大家的建议,但我已经发布了我找到的解决方案。 - pandre
嘿,看这里...我在一个 TODO 中! :) 如果你刚好找到了这个页面,请避免使用这种方法,因为不能保证这种行为受屏幕阅读器的支持。相反,如果必要的话,请使用 AccessibilityManager 来查询屏幕阅读器的状态。 - caseyburkhardt

0

我不确定这是实现所提出的最佳方式,但我通过使用以下代码成功地使其工作:

Intent screenReaderIntent = new Intent("android.accessibilityservice.AccessibilityService");
screenReaderIntent.addCategory("android.accessibilityservice.category.FEEDBACK_SPOKEN");
List<ResolveInfo> screenReaders = getPackageManager().queryIntentServices(screenReaderIntent, 0);
Cursor cursor = null;
int status = 0;
ContentResolver cr = getContentResolver();

List<String> runningServices = new ArrayList<String>();
ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
    runningServices.add(service.service.getPackageName());
}

for (ResolveInfo screenReader : screenReaders) {
    cursor = cr.query(Uri.parse("content://" + screenReader.serviceInfo.packageName
            + ".providers.StatusProvider"), null, null, null, null);

    if (cursor != null && cursor.moveToFirst()) { //this part works for Android <4.1
        status = cursor.getInt(0);
        cursor.close();
        if (status == 1) {
            //screen reader active!
        } else {
            //screen reader inactive
        }
    } else {  //this part works for Android 4.1+
        if (runningServices.contains(screenReader.serviceInfo.packageName)) {
            //screen reader active!
        } else {
            //screen reader inactive
        }
    }
}

也许这不是最好的方法,但这是我能想到的唯一一个在果冻豆和之前的 Android 版本中都能工作的方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接