1

I'm developing an accessibility service in Android. I want to disable some functions when the user turns off accessibility service, but I'm not sure how I can detect that.

I thought when user turns it off, it will call onDestroy(), but apparently, it's not being called.

Is there any way to know when the user toggles off accessibility service? Or is there a function which gets called whenever user toggles off?

(Just in case, I'm developing for Android wear.)

Thanks very much!! I appreciate your help! :)

user3415167
  • 1,013
  • 2
  • 13
  • 23
  • AFAIK I don't think there is a System Broadcast action for this. So you have to check at runtime . For more info read https://developer.android.com/reference/android/accessibilityservice/AccessibilityService. – ADM May 02 '18 at 09:28
  • 1
    For me, the AccessibilityService's `onDestroy` method is invoked reliably if the user disables it. – Phocacius Sep 20 '18 at 14:24

3 Answers3

1

interface AccessibilityManager.AccessibilityStateChangeListener

Listener for the system accessibility state. To listen for changes to the accessibility state on the device, implement this interface and register it with the system by calling addAccessibilityStateChangeListener.

Example:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // ...
    AccessibilityManager am = (AccessibilityManager) getSystemService(Context.ACCESSIBILITY_SERVICE);
    am.addAccessibilityStateChangeListener(new AccessibilityManager.AccessibilityStateChangeListener() {
        @Override
        public void onAccessibilityStateChanged(boolean b) {
            Log.d(TAG,"onAccessibilityStateChanged b=" + b);
            updateServiceStatus(b);
        }
    });
    updateServiceStatus(am.isEnabled());
}

More java examples on programcreek.com.

naXa stands with Ukraine
  • 35,493
  • 19
  • 190
  • 259
  • 1
    Unfortunately this only checks if any accessibility service is enabled. It triggers when the first service is enabled or the last one disabled. The same applies for your first answer and `AccessibilityManager.isEnabled` – Phocacius Sep 20 '18 at 14:22
  • As @Phoca said this method does not behave as one think it should. But accessibilityService will call onDestroy when disabled – galaxigirl Feb 17 '19 at 14:34
0

I don't know about any event, broadcast or callback that notifies applications about state changes in Accessibility Service. The best thing I can think of is to manually check service status occasionally:

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

Docs: AccessibilityManager#isEnabled().

naXa stands with Ukraine
  • 35,493
  • 19
  • 190
  • 259
0

This works for me. addAccessibilityStateChangeListener does not fire when activating TalkBack with long-hold volume-button shortcut, probably because accessibility is already enabled, but TalkBack navigation isn't. Its probably enough to just add listener for addTouchExplorationStateChangeListener, but to be safe I also added a addAccessibilityStateChangeListener listener.

I deliberately do not use a StateFlow which remembers the state the last broadcast value, in case our change-listener does not fire in all situations where we need it. This way my GUI can check isAccessibilityTalkBackEnabled on creation, and listen via accessibilityTalkBackEnabledUpdates.collect{} for updates, and we will always at least have the state that was at time of creating the GUI-component. If we used StateFlow and listener didn't work, we would have state that was present when app was launched (or more precisely when the class DefaultAndroidApplicationServices was initiated).

interface AndroidApplicationServices {
    val accessibilityTalkBackEnabledUpdates: SharedFlow<Boolean>
    val isAccessibilityTalkBackEnabled: Boolean
}

class DefaultAndroidApplicationServices(context: Context) : AndroidApplicationServices {
    private val am = context.getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager

    override val accessibilityTalkBackEnabledUpdates = MutableSharedFlow<Boolean>()

    override val isAccessibilityTalkBackEnabled: Boolean
        get() {
            return if (am.isEnabled) {
                // am.isEnabled is true on my test-device, when TalkBack is off, but below check works
                am.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_SPOKEN).isNotEmpty()
            } else false
        }

    init {        
        am.addAccessibilityStateChangeListener {
            CoroutineScope(Dispatchers.Main).launch {
                accessibilityTalkBackEnabledUpdates.emit(isAccessibilityTalkBackEnabled)
            }
        }
        am.addTouchExplorationStateChangeListener {
            CoroutineScope(Dispatchers.Main).launch {
                accessibilityTalkBackEnabledUpdates.emit(isAccessibilityTalkBackEnabled)
            }
        }
    }
}
arberg
  • 4,148
  • 4
  • 31
  • 39