Why Accessibility Service doesn’t works in suspend state?

Accessibility Service feature in android
Photo by Paul Green on Unsplash

Yes, you read it right, Accessibility service won’t work if the device is in suspend state. There is no doubt it is one of the powerful tools present in the Android framework, with which you can read the UI of any other application. You can events get the events when any button is pressed or when you hover on the screen. But it has a limitation. The limitation is, this service won’t work when the device is in suspend state. That means, when the screen goes off or the backlight is off, the accessibility is not going to be functional. In this post, we will be going to find out why is this behaviour and what is causing this behavior.

Before going deep into it, let’s have a piece of quick information about the Accessibility Service.

What is Accessibility Service in Android?

As per the android document, an Accessibility service is an application that helps the user having certain disabilities or to the user who may not be able to fully interact with the device temporarily, by enhancing the user interface.

For Example, You can think of a scenario, a user is driving his car and he/she need to interact with his device. Or a user is attending a very loud function and he/she got a call, then they need additional interactive feedback.

It is such a powerful tool, that if you grant an accessibility service permission to your application, then that application will run in the background and can read UI(layout) of any other application. It can detect if the user has performed any click or pressed any button on the device. With the help of this service, you can even read the notification coming from a different application. Not only this, with the help of accessibility service you can even perform things on behalf of a user, like performing a click event, changing the state of a checkbox, adding text to a textview without letting the user know that this is a secret job is being done by your application.

To know more about the accessibility service, its use case, and how to setup, you can read the article here.

Why Accessibility Service doesn't work in suspend state?

In one of my project, we have a requirement of using accessibility service to get the keypress of any physical button. Whenever any key is pressed, the accessibility service will get the events in the onKeyEvent() callback.The service was working fine till the device was in resume state. We were able to get the keyevents when any key was pressed (either it is a volume up, volume down, power, SCAN, etc). But as soon as the device display goes off or the device goes to suspend state, we were unable to get the keyevents from the accessibility service.

Then we started to debug why accessibility fails to receive onKeyEvent() callback. The failure was because the device was not in an interactive state.

Here is the code snippet  of the AccessibilityInputFilter.java.

@Override
public void onInputEvent(InputEvent event, int policyFlags) {
    if (DEBUG) {
        Slog.d(TAG, "Received event: " + event + ", policyFlags=0x"
        + Integer.toHexString(policyFlags));
    }

    if (mEventHandler == null) {
        if (DEBUG) Slog.d(TAG, "mEventHandler == null for event " + event);
        super.onInputEvent(event, policyFlags);
        return;
    }

    EventStreamState state = getEventStreamState(event);
    if (state == null) {
        super.onInputEvent(event, policyFlags);
        return;
    }

    int eventSource = event.getSource();
    if ((policyFlags & WindowManagerPolicy.FLAG_PASS_TO_USER) == 0) {
        state.reset();
        mEventHandler.clearEvents(eventSource);
        super.onInputEvent(event, policyFlags);
        return;
    }

    if (state.updateDeviceId(event.getDeviceId())) {
        mEventHandler.clearEvents(eventSource);
    }

    if (!state.deviceIdValid()) {
        super.onInputEvent(event, policyFlags);
        return;
     }

    if (event instanceof MotionEvent) {
        if ((mEnabledFeatures & FEATURES_AFFECTING_MOTION_EVENTS) != 0) {
            MotionEvent motionEvent = (MotionEvent) event;
            processMotionEvent(state, motionEvent, policyFlags);
            return;
        } else {
            super.onInputEvent(event, policyFlags);
        }
    } else if (event instanceof KeyEvent) {
        KeyEvent keyEvent = (KeyEvent) event;
        processKeyEvent(state, keyEvent, policyFlags);
    }
}

The onInputEvent() will be called from the InputManagerService whenever any key is pressed. When the device is not in interactive state, the following condition results to 0 (policyFlags & WindowManagerPolicy.FLAG_PASS_TO_USER) . The KeyDown event gets blocked and does not get passed to the Accessibility Service.

The subsequent check for KeyEvent.ACTION_UP won’t be processed because of the below function.

@Override
final public boolean shouldProcessKeyEvent(KeyEvent event) {
    // For each keyboard device, wait for a down event from a device to start processing
    int deviceId = event.getDeviceId();
    if (mEventSequenceStartedMap.get(deviceId, false)) {
        return true;
    }
    boolean shouldProcess = event.getAction() == KeyEvent.ACTION_DOWN;
    mEventSequenceStartedMap.put(deviceId, shouldProcess);
    return shouldProcess;
}

Here, the shouldProcess will return false because ACTION_DOWN has been discarded.

Conclusion

Accessibility service is one of the features of android framework that is designed to provide an alternative feedback to the user if he/she is not able to fully interact with the device. Android provides a standard example of the Accessibility Service in form of Talkback. The service will only be able to receive KeyEvents if the device is in an interactive state. If the device goes to suspend state, then it will not be able to receive the onKeyEvent() callback. If you like this post, please do share it on social media like Facebook or WhatsApp. If you have any suggestions or questions please do let me know in the comment section. Or if you want to know anything about any app or software for your own purpose, write us to support@gizmomind.com, and please like our Facebook page.

Swetabh

Swetabh is an Android Developer and a Tech enthusiast. His enthusiasm drives him to know about various technologies. Now he wanted to share his knowledge to other enthusiast who are passionate to know-how and become a GIZMOMIND.

Leave a Reply