Search code examples
androidaccessibilityservice

AccessibilityService ignores notificationTimeout property


As I understand it, setting an AccessibilityService's notificationTimeout property should limit onAccessibilityEvent from being called more frequently than that timeout. I have tried setting this both in the accessibility service's xml file and programmatically with setServiceInfo.

However no matter what I set it to, I get very frequent calls of onAccessibilityEvent.

Here's some of my code:

XML:

<accessibility-service
xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityEventTypes="typeWindowStateChanged|typeWindowContentChanged"
android:accessibilityFeedbackType="feedbackAllMask"
android:accessibilityFlags="flagReportViewIds|flagIncludeNotImportantViews"
android:canRetrieveWindowContent="true"
android:description="@string/accessibility_service_description"
android:notificationTimeout="100">

JAVA:

@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
    AccessibilityServiceInfo accessibilityServiceInfo = new AccessibilityServiceInfo();
    accessibilityServiceInfo.notificationTimeout = 1000;
    setServiceInfo(accessibilityServiceInfo);
    Utils.logDebug(TAG, "TIMEOUT: " + getServiceInfo().notificationTimeout);

    long currentTime = System.currentTimeMillis();
    long timeSinceLastEvent = currentTime - timeLastAccessibilityEvent;
    Utils.logDebug(TAG, "onAccessibilityEvent(), type: " + event.getEventType() + ", last event: " + timeSinceLastEvent + "ms ago");

    if(!event.equals(lastAccessibilityEvent) && timeSinceLastEvent < MAX_FREQUENCY_ACCESSIBILITY_EVENT_MS) {
        Utils.logDebug(TAG, "Too soon, returning!");
        timeLastAccessibilityEvent = currentTime;
        return;
    }
    timeLastAccessibilityEvent = currentTime;
}

The notificationTimeout debug log reads correctly for whatever I set it to, but I get calls as frequent as 0ms old even though it should be waiting a full second!

Here is a similar question: Notification Timeout - Specifying delay between accessibility events


Solution

  • By reading the source code, you can find that if the event type is WINDOW_CONTNET_CHANGE, the notification timeout is useless. It seems it is by design. Maybe they want WINDOW_CONTENT_CHANGE event notice as soon as possible.

    You can change the event type in your xml by other TYPEs inside of WINDOW_CONTNET_CHANGE, then the notification timeout will work.

    If you have to use WINDOW_CONTNET_CHANGE, you can set a timer to drop extra incoming events in your onAccessibilityEvent().

    https://github.com/aosp-mirror/platform_frameworks_base/blob/master/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java#L1219

      if ((mNotificationTimeout > 0)
                        **&& (eventType != AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED)**) {
                    // Allow at most one pending event
                    final AccessibilityEvent oldEvent = mPendingEvents.get(eventType);
                    mPendingEvents.put(eventType, newEvent);
                    if (oldEvent != null) {
                        mEventDispatchHandler.removeMessages(eventType);
                        oldEvent.recycle();
                    }
                    message = mEventDispatchHandler.obtainMessage(eventType);
                } else {
                    // Send all messages, bypassing mPendingEvents
                    message = mEventDispatchHandler.obtainMessage(eventType, newEvent);
                }
                message.arg1 = serviceWantsEvent ? 1 : 0;
    
                mEventDispatchHandler.sendMessageDelayed(message, mNotificationTimeout)