Measure SDK captures gestures like click, long click and scroll events automatically.
When Measure SDK is initialized, it registers a touch event interceptor using the Curtains library. It allows Measure to intercept every touch event in an application and process it.
There are two main parts to tracking gestures:
Warning
Gesture detection and gesture target detection work on best-effort basis, and can report a view group containing the interacted view instead of the view itself.
Measure tracks the time between ACTION_DOWN
and ACTION_UP
events and the distance moved to classify a touch as
click, long click or scroll.
A gesture is classified as a long click gesture if the time interval between ACTION_DOWN
and ACTION_UP
is more
than ViewConfiguration.getLongPressTimeout
time and the distance moved by the pointer between the two events is
less
than ViewConfiguration.get.getScaledTouchSlop.
A gesture is classified as a click if the distance moved by the pointer between the two events is less than ViewConfiguration.get.getScaledTouchSlop but the time interval between the two events is less than ViewConfiguration.getLongPressTimeout().
A gesture is classified as a scroll if the distance moved by the pointer between the two events is more than ViewConfiguration.get.scaledTouchSlop. An estimation of direction in which the scroll happened based on the pointer movement.
For compose, a click/long click is detected by traversing the semantics tree using SemanticsOwner.getAllSemanticsNodes and finding a composable at the point where the touch happened and checking for Semantics Properties - SemanticsActions.OnClick, SemanticsActions.OnLongClick and SemanticsActions.ScrollBy for click, long click and scroll respectively.
Along with the type of gesture which occurred, Measure can also estimate the target view/composable on which the gesture was performed on.
For a click/long click, a hit test is performed to check the views which are under the point where the touch occurred. A traversal is performed on the children of the view group found and is checked for any view which has either isClickable or isPressed set to true. If one is found, it is returned as the target, otherwise, the touch is discarded as can be classified as a "dead click".
Similarly, for a scroll, after the hit test, a traversal is performed for any view which has isScrollContainer set to true and canScrollVertically or canScrollHorizontally. If a view which satisfies this condition it is returned as the target, otherwise, the scroll is discarded and can be classified as a "dead scroll".
Checkout the results from a macro benchmark we ran for gesture target detection here. TLDR;
- On average, it takes 0.458 ms to find the clicked view in a deep view hierarchy.
- On average, it takes 0.658 ms to find the clicked composable in a deep composable hierarchy.
Note
Compose currently reports the target_id in the collected data
using testTag,
if it is set. While the
target
is always reported asAndroidComposeView
. This will be improved in the future, the progress can be tracked here.