Repository navigation
Conversation
zfdang
added a commit
that referenced
this pull request
Sep 22, 2026
* escalate from ACTION_CLICK to a touch gesture when a skip button survives performAction(ACTION_CLICK) returning true only means the view handled the event; some ad SDKs ignore accessibility clicks, and a node that is not laid out yet (bounds 0,0,0,0, seen with Zhihu on a real device) reports success without any effect. PR #90 proposed replacing every ACTION_CLICK with a coordinate gesture, which handles those apps but taps the origin for unlaid-out nodes, can hit whatever replaced the ad when it closed a moment earlier, and drops the onlyClick rule flag. This keeps ACTION_CLICK (node, then its parent) as the first attempt, falls back to a gesture immediately when ACTION_CLICK is rejected, and otherwise escalates to a gesture only when the same widget is still on screen at least 500 ms later. A widget is attempted at most twice per skip-ad process. Widgets are identified by class, view id and bounds so that a changing countdown label ("跳过 5" -> "跳过 4") does not reset the attempt count. Gestures are only dispatched at a non-empty, on-screen, visible spot. The onlyClick flag of widget rules still forces a gesture. Adds Robolectric tests for the escalation, the immediate fallback, the parent click, invalid coordinates, onlyClick and attempt reset; 47 unit tests in total. * handle warm-start ads after the screen was unlocked Apps often show a splash ad when they come back to the foreground after the screen was locked. The existing hook only reacted to USER_PRESENT, restarted the skip-ad process for whatever package was last recorded, even a whitelisted app or the launcher, and then waited passively for events. - detect the warm start from the accessibility events: a system window shown while the keyguard is locked (or the screen is off) marks the current target app as covered, and the next window of that app restarts the skip-ad process. On OPPO devices the system skips USER_PRESENT/SCREEN_ON deliveries to third-party apps ("oplus skip sp"), so this path does not depend on broadcasts at all - the broadcast receiver stays as an additional trigger and now also listens for SCREEN_ON (devices without a lock screen never send USER_PRESENT) - both paths only act when the foreground app is one we handle, and scan its window right away and once more a second later instead of waiting for further events Adds Robolectric tests for the unlock broadcast, SCREEN_ON, unhandled apps, a foreign active window, the event-based detection and its negatives (notification shade, the app's own dialogs); 55 unit tests. * refresh nodes before gestures and fix retry bookkeeping found in review - a gesture is only dispatched after AccessibilityNodeInfo.refresh() succeeds and the refreshed node still belongs to a target package, still matches its rule, and is a visible spot on screen. A queued snapshot of a button whose ad has already closed is therefore never tapped at its old coordinates - widget rules stay active until the matched widget has had its final attempt, so a button that only matches by id can still be escalated to a gesture at the next sighting - click attempts are counted only when ACTION_CLICK or a gesture was actually issued; a gesture refused by the checks (e.g. the widget is not visible yet) leaves the attempt budget untouched - the pending warm start is kept while the device is still locked: a same-package window during the lock screen, or SCREEN_ON with the keyguard up, no longer starts a process that expires before the user unlocks Adds regression tests for each case; 61 unit tests in total. * keep in-flight clicks and scans from touching a newer skip-ad process startSkipAdProcess() clears the per-process click attempts. A click whose performAction() was still blocking on the worker when the user left and re-entered the app then recorded itself into the fresh table, so the same button in the new ad was either held back by the retry interval or escalated straight to a gesture. Every startSkipAdProcess() now bumps a generation counter. A traversal stops as soon as the generation changes, and a click only records its attempt when it completes under the generation it started in. Adds two controlled-concurrency tests; 63 unit tests in total. * give every skip-ad process its own click session The generation check before recording a click attempt was still a check-then-act: the worker could pass the check, get descheduled, and write into the table that startSkipAdProcess() had cleared in between. Click state now lives in a ClickSession object. startSkipAdProcess() installs a fresh session; a traversal captures the session it started under and passes it to every click, so an attempt is recorded in that session no matter when the click completes. A click that finishes after the user re-entered the app lands in the discarded old session and can never hold back or escalate the first click of the new ad. The stale traversal itself still stops as soon as the session changes. Test asserts the record ends up in the old session and the new one stays empty; 63 unit tests in total. * keep the widget-rules-done flag per skip-ad process The final attempt of a widget rule cleared the shared setTargetedWidgets field. When that attempt completed after the user had re-entered the app, it switched off the widget rules of the new process, which reuses the same rule set. The flag now lives in the ClickSession the scan started under and only that session's rules are considered done; scheduling reads the rules through activeWidgetRules(), which hides them once the current session is finished. Test blocks the old process inside its final gesture, starts a new process and checks the rules stay active; 64 unit tests in total.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR fixes http://jetbrain-licproxy.tools.huawei.com:8091/