Repository navigation
Detect gestures on the main thread, in order with their timeouts - #144
Merged
Merged
Conversation
On Android 13 and later, Backtalk recognizes gestures itself. The touch
interaction controller passed each motion event to a thread of its own,
but the gesture matchers and the touch exploration delay counted their
timeouts on the main thread, so the same state changed on both threads
without locking:
- A timeout that completes or cancels a gesture, such as the hold of a
double tap and hold, could run on the main thread while the gesture
thread handled the lift that ended it, and both could report a
gesture.
- When the touch exploration delay ended, it handed its request to the
gesture thread, where cancelling the delay no longer stopped it, so a
swipe that started just then could still start touch exploration.
- Following a held touch with the circle menu and two-finger rotation
kept state that either thread changed.
- Cancelling the phonetic letter hint ran the feedback pipeline on the
gesture thread, and turning touch exploration off once a touch ended
changed the service info there.
- Each restart of gesture detection started a new thread without
stopping the old one.
Android passes motion events and touch state changes to the service
through its main thread before the controller hands them on, so the
gesture thread never got them sooner. The controller now calls the
monitor on the main thread as each event comes in, with no executor,
and the monitor no longer hands requests to another thread; the
requestStateChangeInSameThread flag, which only chose that, is gone.
Events and timeouts wait in one queue, in the order they came in, and
cancelling a timeout is exact. An executor that posts to the main
thread would not do: a timeout that ran out while the main thread was
busy would then run before an event that came in earlier.
TouchInteractionMonitorTest runs the monitor with Android's own
controller and keeps the main thread busy during a touch: a swipe stays
a swipe instead of starting touch exploration, a double tap is not
taken for a double tap and hold, touch exploration turned off during a
touch changes when the touch ends, and a finger held still starts touch
exploration after the delay. Registering the monitor with an executor
that posts to the main thread fails two of these tests, and with a
thread of its own, all four.
On an Android 16 emulator, swipes, double taps and touch exploration
work, also after turning the service off and on, and gesture detection
logs come from the main thread.
Limitations: gestures still wait while the main thread is busy, as
before, since Android passes them through it. Following a held touch
still posts each move to the circle menu, all displays still share the
finger-down state, and stopping detection still goes through the
connected displays rather than the registered monitors.
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.
On Android 13 and later, Backtalk recognizes gestures itself. The touch
interaction controller passed each motion event to a thread of its own,
but the gesture matchers and the touch exploration delay counted their
timeouts on the main thread, so the same state changed on both threads
without locking:
double tap and hold, could run on the main thread while the gesture
thread handled the lift that ended it, and both could report a
gesture.
gesture thread, where cancelling the delay no longer stopped it, so a
swipe that started just then could still start touch exploration.
kept state that either thread changed.
gesture thread, and turning touch exploration off once a touch ended
changed the service info there.
stopping the old one.
Android passes motion events and touch state changes to the service
through its main thread before the controller hands them on, so the
gesture thread never got them sooner. The controller now calls the
monitor on the main thread as each event comes in, with no executor,
and the monitor no longer hands requests to another thread; the
requestStateChangeInSameThread flag, which only chose that, is gone.
Events and timeouts wait in one queue, in the order they came in, and
cancelling a timeout is exact. An executor that posts to the main
thread would not do: a timeout that ran out while the main thread was
busy would then run before an event that came in earlier.
TouchInteractionMonitorTest runs the monitor with Android's own
controller and keeps the main thread busy during a touch: a swipe stays
a swipe instead of starting touch exploration, a double tap is not
taken for a double tap and hold, touch exploration turned off during a
touch changes when the touch ends, and a finger held still starts touch
exploration after the delay. Registering the monitor with an executor
that posts to the main thread fails two of these tests, and with a
thread of its own, all four.
On an Android 16 emulator, swipes, double taps and touch exploration
work, also after turning the service off and on, and gesture detection
logs come from the main thread.
Limitations: gestures still wait while the main thread is busy, as
before, since Android passes them through it. Following a held touch
still posts each move to the circle menu, all displays still share the
finger-down state, and stopping detection still goes through the
connected displays rather than the registered monitors.