androidaccessibilitytalkbackandroid-4.1-jelly-bean

How to check if Talkback is active in JellyBean


This question asked how to know if Android Talkback is active; that worked until Jelly Bean. Starting from Android 4.1, that steps no longer work, because the mentioned cursor is empty.

Having this said, I want to ask is if there is a way to do the same checking in Jelly Bean.

EDIT I tried to search for TalkBack code and I found it here. For checking if TalkBack is active, I am using the following code:

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
}

Having this said, if the cursor is empty, how do we know if TalkBack is running?

EDIT 2 Following @JoxTraex suggestions, I am now sending a broadcast to query whether or not TalkBack is enabled:

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

Now how should I receive the response?

I tried adding the following to manifest, but my receiver does not receive any response:

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


Solution

  • I'm not sure this is the best way of achieving what is proposed, but I managed to make this work by using the following code:

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

    Probably this is not the best way but it is the only one I can think of that works in Jelly Bean and in previous Android versions