AccessibilityService events delayed by 1-2 seconds on Samsung devices during Fragment/Activity transitions
I am building a personal App Blocker with Claude's help that restricts access to the Settings -> Accessibility page using an AccessibilityService.
The scanning logic is heavily optimized (takes ~7ms to execute), but on Samsung devices (especially Samsung S25), there is a 1.5 to 2-second delay before my service even receives the AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED or TYPE_WINDOW_STATE_CHANGED event when navigating into the Accessibility menu. It seems Android/Samsung freezes event delivery while the screen-sliding animation plays. I'm not sure how to navigate this issue as I have tried setting notificationTimeout = 0 in AccessibilityServiceInfo, using event.source instead of rootInActiveWindow to bypass global window delays, trying to intercept TYPE_VIEW_CLICKED before the transition happens (didn't catch the tap reliably, likely because the tap lands on a wrapper ViewGroup rather than the TextView).
Here is the setup:
1. Service Configuration:
override fun onServiceConnected() {
this.serviceInfo = AccessibilityServiceInfo().apply {
eventTypes = AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED or
AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED or
AccessibilityEvent.TYPE_VIEW_CLICKED
feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC
flags = AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS or
AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS
notificationTimeout = 0
}
}
2. Event Interception:
override fun onAccessibilityEvent(event: AccessibilityEvent?) {
val packageName = event?.packageName?.toString() ?: return
// Only scan if we are inside a Settings app
if (packageName.contains("settings", ignoreCase = true) ||
packageName.contains("accessibility", ignoreCase = true)) {
val rootNode = event.source ?: rootInActiveWindow
if (isRestrictedSettingsPage(rootNode)) {
performGlobalAction(GLOBAL_ACTION_HOME)
}
}
}
3. Node Scanning Logic (BFS):
private fun isRestrictedSettingsPage(rootNode: AccessibilityNodeInfo?): Boolean {
if (rootNode == null) return false
val queue = ArrayDeque<AccessibilityNodeInfo>()
queue.add(rootNode)
while (queue.isNotEmpty()) {
val currentNode = queue.removeFirst()
val text = currentNode.text?.toString() ?: currentNode.contentDescription?.toString()
if (text != null && text.contains("Accessibility shortcuts", ignoreCase = true)) {
return true
}
for (i in 0 until currentNode.childCount) {
currentNode.getChild(i)?.let { queue.add(it) }
}
}
return false
}
The Logs proving the OS delay:
Notice the 1.5-second gap between when the first screen finishes scanning and when the OS finally delivers the CONTENT_CHANGED event for the next screen.
22:45:51.985 D --- END UI TREE SCAN --- (Main settings menu) 22:45:51.985 D No banned keywords found on this scan. *(I click "Accessibility" here. The screen slides in. The service gets nothing until 1.5s later)* 22:45:53.551 D => EVENT FIRED: CONTENT_CHANGED 22:45:53.565 D Found Accessibility Keyword inside: 'Accessibility shortcuts' 22:45:53.565 D Match Found! Blocking settings page instantly 22:45:53.566 I performGlobalAction(GLOBAL_ACTION_HOME) triggered
I'm not sure if the problem stems from my code or it's a problem for that specific phone, since the app successfully detects the setting pages on other older Samsung devices like Note10 lite running on android 13. How can I block the "Accessibility" page in Samsung's settings successfully? For example, if you know any documentation on how other blocker apps navigate through this issue, I'd love to see it.
Update: I logged the entire process again and noticed that after I restart the phone, there are two processes that come before my accessibility function fires off. They are com.samsung.android.honeyboard | v0 Universal SwitchOn and com.samsung.android.honeyboard | v0 Voice Assistant On. My code blocks successfully right after that.
Update 2: I dug a little deeper and in the logs, I saw FreecessController and OLAF restriction. These weren't happening in the past versions of OneUI as much as I know, or at least they didn't cause any disturbances. Can these be the cause? Why would they appear and meddle with accessibility alerts?