Android Input Events
What Are Input Events¶
Android OS uses the events concept to handle signals received from different input devices.
It supports a wide range of different devices, such as touch screen, light pen, mouse, keyboard,
but most of them are using MotionEvent
or KeyEvent APIs, which are
derived from the base InputEvent
class. These APIs are quite flexible and support a wide range of different settings.
We are particularly interested in the APIs responsible for the generation and emulation of touch and keyboard events.
How Input Events Work¶
An event is an object which is generated in response to a signal from an input device. These objects are then delivered to the corresponding kernel subsystem, which processes them and notifies all listening processes about taps, key presses, swipes, etc. This means that in order to emulate a signal generated by an external device such as a touch screen, it is necessary to just send event objects with the same properties and in the same sequence as they would be generated by a real device.
Each input device has a set of actions whose property ranges and sequences are already predefined in the operating system. These are actions such as "tap", "swipe", "double tap", etc. The properties of each action could be found either in the Android documentation or in the OS source code.
Simulating a Single Tap¶
In order to perform a sequence of events recognized as single tap, it is necessary to generate the following motion events:
ACTION_POINTER_DOWN- wait 125ms (525ms or longer wait will synthesize a long tap action instead)
ACTION_POINTER_UP. ThedownTimeproperty should be set to the same timestamp as forACTION_POINTER_DOWN
It is also important for the coordinates and other properties of both the starting and the closing
event to be equal, except of the eventTime one, which is always equal to the current system
timestamp in milliseconds (SystemClock.uptimeMillis()).
The MotionEvent object itself could be created via the obtain()
API, where parameters are the corresponding event properties.
After events are created, they must be passed to the system for execution. This action is not
considered secure, so it is only possible in instrumented tests via the injectInputEvent
method of the IUiAutomationConnection interface. This is a very low-level method and it can only
be accessed via reflection in automated tests. Typical UiAutomator2 driver APIs use wrappers over
it (e.g. touchDown, touchMove), that already simulate the stuff described above.
More Complicated Actions¶
In theory it is possible to emulate any input action using a generated events sequence. Still, some
actions like multi-finger swipe are complicated, and require a lot of events to be generated with
correct properties and timings. The OS simply ignores given events if they don't follow internal
action requirements. There is also a little assistance from the UI Automator framework, because
Google only has wrappers for a limited set of simple actions, like tap, drag or swipe.
So, in order to generate two-finger symmetric swipe, the following event chain is used:
ACTION_POINTER_DOWN(finger1)ACTION_POINTER_DOWN(finger2)- start a loop, that generates
ACTION_POINTER_MOVEevent each20msfor bothfinger1andfinger2untilACTION_POINTER_UPis performed. ThedownTimeshould be set to the same timestamp as for the correspondingACTION_POINTER_DOWN. The coordinates of each move event should be points belonging to the path between the corresponding start and end point coordinates normalized by the current timestamp (x0 + sqrt(sqr(x0) + sqr(x1))) * k, y0 + sqrt(sqr(y0) + sqr(y1))) * k). ACTION_POINTER_UP(finger1) ThedownTimeproperty should be set to the same timestamp as for the correspondingACTION_POINTER_DOWNACTION_POINTER_UP(finger2) ThedownTimeproperty should be set to the same timestamp as for the correspondingACTION_POINTER_DOWN
Google uses 5ms as the interval between move events in UI Automator code, but testing has
confirmed that this value is too small, which causes noticeable delays in actions execution.
Further Reading¶
Unfortunately, there is not much detailed information on this topic. The only reliable source of information is Android OS sources. Consider visiting the following resources:
- https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/view/ViewConfiguration.java
- https://android.googlesource.com/platform/frameworks/uiautomator/+/refs/heads/master
- https://github.com/appium/appium-android/tree/main/packages/uiautomator2-server/app/src/main/java/io/appium/uiautomator2/utils/w3c
- https://github.com/appium/appium-android/tree/main/packages/uiautomator2-server/app/src/test/java/io/appium/uiautomator2/utils/w3c
- https://github.com/appium/appium-espresso-driver/tree/master/espresso-server/library/src/main/java/io/appium/espressoserver/lib/helpers/w3c