Repository navigation
Conversation
After some touches with several fingers, Android's touch exploration can leave pointers it injected down. The input dispatcher then rejects every hover event that touch exploration injects, for every screen reader, until the phone restarts. Swipes and taps still work, but dragging a finger says nothing. Turning the screen reader off and on doesn't help, because the dispatcher keeps those pointers until the display is removed. Backtalk now notices touches that Android reports as touch exploration, that last at least 300 ms and hover over nothing. With the DUMP permission, granted once with adb, it reads the pointers that the dispatcher holds for device -1 from dumpsys input, twice 300 ms apart. If the same ones are held, it says "Fixing touch exploration", turns explore by touch off, lifts them with a gesture, turns explore by touch back on, and reads them again to check. If a touch is in progress, it waits for the touch to end first. Gesture events are also device -1, and the injector gives each new stroke the lowest unused pointer id. The gesture opens a stroke for each id up to the highest stuck one, keeps open the ones the dispatcher holds and lifts the others, then lifts the held ones. The dispatcher rejects every event until the open pointers match, then accepts the lifts. Strokes are outside the display, so no window gets a touch. Limitations: - Reading the pointers needs a dumpsys input that prints the injected event verifier, as Samsung's builds do. AOSP doesn't, so on other phones, and without the permission, Backtalk only says after three such touches in a row that touch exploration may be stuck. - Exploring something with nothing to read, such as blank space or a game, also hovers over nothing. Without the permission that can give a false warning, at most once every 10 minutes. With it, each such touch costs a dumpsys input, at most every 2 seconds. - Explore by touch is off while the gesture runs, usually under half a second and at most 3 seconds, and a touch then goes straight to the app. Such a touch cancels the gesture, and Backtalk tries again after the next exploring touch. - The injector gives pointer ids up to 10 only, and Android 8 to 10 allow 10 strokes, so stuck ids above 10, or above 9 on those versions, can't be lifted. Backtalk then says to restart the phone. - StuckTouchController watches touches, reads dumpsys input on a background thread with a 3 second limit, and runs the fix. - StuckPointerGesture plans the strokes. InjectedPointers parses dumpsys input. - Advanced settings > Fix stuck touch exploration, on by default. - The manifest asks for DUMP, which only adb can grant. - Unit tests replay the plan through models of the gesture injector and the dispatcher's verifier for every stuck set of ids 0 to 10, check the stroke limit, and test the parser.
Owner
|
Thanks, the Samsung stuck-pointer problem is real and this is a clever way out. A few things before it can go in:
|
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.
After some touches with several fingers, Android can stop touch exploration for every screen reader until the phone restarts. Swipes and taps still work, but dragging a finger says nothing. I've had this on a Galaxy Z Fold7 (Android 17) several times. Turning the screen reader off and on doesn't help.
The cause is in Android. TouchExplorer injects touch events for delegated and dragged touches, and InputDispatcher checks every injected event against the pointers it holds as down. After the multi-finger touch, TouchExplorer leaves injected pointers down. The dispatcher keeps them until the display is removed and rejects every hover event touch exploration injects afterwards:
I've reported it to Google. Until it's fixed, this PR lets Backtalk fix it without a restart.
How it works
adb shell pm grant fyi.quin.backtalk android.permission.DUMP, it reads the pointers the dispatcher holds for device -1 fromdumpsys input, twice, 300 ms apart.dispatchGestureare also device -1, so a gesture can lift the stuck pointers. The injector gives each new stroke the lowest unused pointer id, so the gesture opens one stroke per id up to the highest stuck one, keeps open the ones the dispatcher holds, lifts the others, then lifts the held ones. The dispatcher rejects every event until the open pointers match what it holds, then accepts the lifts. Strokes are outside the display, so no window gets a touch.dumpsys inputdoesn't show the pointers, Backtalk says after three such touches in a row that touch exploration may be stuck and the phone needs a restart.Limitations
dumpsys inputthat prints the injected event verifier ("Filter verifier on display N"), as Samsung's builds do. AOSP doesn't print it, so on other phones Backtalk can only warn.dumpsys input(about 40 ms), at most every 2 seconds.Testing
Unit tests replay the gesture plan through models of MotionEventInjector and the dispatcher's verifier for every stuck set of ids 0 to 10, check the stroke limit, and test the
dumpsys inputparser.On the Fold7, with the stuck state reproduced by injecting a down from the shell at an off-screen point and never lifting it: