AccessibilityService 忽略 notificationTimeout 属性

AccessibilityService ignores notificationTimeout property

据我了解,设置 AccessibilityService 的 notificationTimeout 属性 应该可以限制 onAccessibilityEvent 的调用频率高于该超时值。我已经尝试在辅助功能服务的 xml 文件中和以编程方式使用 setServiceInfo.

进行设置

但是无论我将其设置为什么,我都会非常频繁地调用 onAccessibilityEvent。

这是我的一些代码:

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

无论我将其设置为什么,notificationTimeout 调试日志都能正确读取,但我收到的调用频率高达 0 毫秒,即使它应该等待整整一秒!

这是一个类似的问题:Notification Timeout - Specifying delay between accessibility events

通过阅读源码可以发现,如果事件类型是WINDOW_CONTNET_CHANGE,那么通知超时是没有用的。看来这是设计使然。也许他们希望尽快WINDOW_CONTENT_CHANGE事件通知。

您可以将 xml 中的事件类型更改为 WINDOW_CONTNET_CHANGE 中的其他类型,然后通知超时将起作用。

如果您必须使用 WINDOW_CONTNET_CHANGE,您可以在 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)