tap, swipe and two smoking events

Android application developers as well as testers know about commands adb shell input tap X Y and adb shell input swipe X1 Y1 X2 Y2 [DurationMs]. But each of them has its own fatal flaw. What are these shortcomings, how to fix them with the help of events and the nuances I will tell in this article. Yes, I almost forgot: third-party applications are not used, root is not needed.

adb input tap

Let’s analyze the shortcomings adb input tap. In general, this command works well and reliably, it performs the function, but slowly. under the hood the following happens: adb connects to local “server” adb process; the request goes through it to the device; a shell is launched on the device and the script for the input command is executed; this script starts a new java process; java process simulates a click. The most time-consuming, as they say on the link, is the launch of the java process. For example, on my Galaxy Note 4, adb input tap takes 1160ms.

There is a better way: use the shell command sendevent. And on the Internet, it is usually advised to do so (or write your own “sendevent”). Indeed, its use speeds up the process (on the same phone, one tap takes 860 ms), but the main drawback is reliability. Rarely (about one in a thousand or more) some messages seem to get corrupted or incompletely processed. For example, two consecutive taps turn into a swipe across the screen (from the point of the first tap to the point of the second). There is an even better way: write data directly to the event device, but first a little theory.

Let’s figure out what commands you need to send to simulate a tap on the screen. As follows from documentation, there are two types of protocols: A and B. Moreover, the first one is marked as obsolete, and, apparently, is no longer used (it does not work on the phone or on the Memu emulator). We will use protocol B.

The easiest way to make a list of messages “on your knee” is to write down the messages that occur when you actually tap on the screen. First, let’s determine which device is used for the actual touchscreen. Let’s use the command adb shell getevent -p. The device that is on the list ABS (0003) there will be values 0030, 0035 and 0036, and is a touchscreen. What these numbers mean, I will explain below. (strictly speaking, any device that responds to touches on a certain area, such as a touchpad, looks like this, but such cases are not considered in this article for simplicity)

Now, knowing the name of the device (for example, let it be /dev/input/event6) use the command adb shell getevent /dev/input/event6. If the output is delayed and has large blocks, replace shell on exec-out: adb exec-out getevent /dev/input/event6. An example of output from one tap on the screen (from the phone):

0003 0039 0000046E
0001 014a 00000001
0001 0145 00000001
0003 0035 0000039C
0003 0036 000005AC
0003 0030 00000007
0000 0000 00000000
0003 0039 FFFFFFFF
0001 014a 00000000
0001 0145 00000000
0000 0000 00000000

Each line consists of three hexadecimal numbers. The first number is the message type, the second is the message code, the third is some value, the meaning of which is determined by the first two. Let’s take a closer look at what these numbers mean. sources. Message types:

EV_SYN 0 // синхронизация пакетов, используем только один код:
SYN_REPORT 0 // значение для этого кода всегда 0

EV_KEY 1 // кнопки и "кнопки", мы будем использовать следующие коды сообщений:
BTN_TOOL_FINGER 0x0145 // значения: 0 - нет пальца, 1 - есть палец
BTN_TOUCH 0x014A // значения: 0 - нет нажатия, 1 - есть нажатие

EV_ABS 3 // абсолютные оси и также MT (multitouch) события, используем следующие коды сообщений:
ABS_MT_TRACKING_ID 0x0039 // идентификатор контакта с тач-скрином
ABS_MT_POSITION_X 0x0035 // координата X
ABS_MT_POSITION_Y 0x0036 // координата Y
ABS_MT_TOUCH_MAJOR 0x0030 // сила нажатия

Interaction messages are packaged and packages in packages with packages. The first touch packet must contain a non-negative surface contact identifier. And in the last release, the identifier is -1. The real driver for each contact increments the identifier, but for simple, non-multi-touch touches, you can always use the same one. For example, zero. Multi-touch touches are a little more complicated and are well described in the documentation (I will duplicate it again link), but are outside the scope of this article.

A single tap consists of touching at a specified point and releasing. These are two packages:

EV_ABS, ABS_MT_TRACKING_ID, 0
EV_ABS, ABS_MT_POSITION_X, <координата X>
EV_ABS, ABS_MT_POSITION_Y, <координата Y>
EV_ABS, ABS_MT_TOUCH_MAJOR, 5
EV_KEY, BTN_TOUCH, 1
EV_KEY, BTN_TOOL_FINGER, 1
EV_SYN, SYN_REPORT, 0

EV_ABS, ABS_MT_TRACKING_ID, -1
EV_KEY, BTN_TOUCH, 0
EV_KEY, BTN_TOOL_FINGER, 0
EV_ABS, ABS_MT_TOUCH_MAJOR, 0
EV_SYN, SYN_REPORT, 0

If you use the method adb shell sendevent, and even if you list sendevents separated by a semicolon, it’s still 12 command calls. Let’s see the message format in sendevent.c source. We are interested in what is written directly to the device:

struct input_event {
struct timeval time;
__u16 type;
__u16 code;
__s32 value;
};

Everything about everything – 16 bytes. The timeval structure is 8 bytes, it is not used, all zeros. Byte order is LSB. For example, sending a messageEV_ABS, ABS_MT_TRACKING_ID, -1 causes the following bytes to be written to the device:

0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x00, 0x39, 0x00, 0xFF, 0xFF, 0xFF, 0xFF

In Linux, there are two ways to display arbitrary values: printf and echo -en. But printf ends the output after it meets the first 0 (but at the same time, for example, printf "\x31\x00\x32\x00">test.txt will create a 2-byte file). At echo there is no such disadvantage. As a result, the command looks like this: (in quotes you need to write all the package data, but I shortened it here for clarity)

adb shell echo -en "\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x39\x00...">/dev/input/event6

In order not to start the adb process every time, you can start it once with the parameter shell and write commands to it in stdin (after writing, do not forget to flush for stdin).

To control the execution of the click, start the second process adb with parameter shell getevent /dev/input/event6 or exec-out getevent /dev/input/event6 and we will listen to its stdout. Output example – see above (three hex numbers in each non-empty line). After sending packets to push, wait for messages to be received EV_ABS, ABS_MT_TRACKING_ID, -1and then EV_SYN, SYN_REPORT, 0. This can be considered a confirmation that the push was handled. (yes, technically the user can tap on the screen and we count his the last package, but we are talking about automated interaction and the user should not be here)

Choice shell or exec-out for adb getevent still depends on the device. When the program starts, we do auto-detection: you need to send a dummy of four messages: EV_ABS, ABS_MT_TRACKING_ID, 0; EV_SYN, SYN_REPORT, 0; EV_ABS, ABS_MT_TRACKING_ID, -1; EV_SYN, SYN_REPORT, 0and if nothing was received in, say, one tenth of a second, we try another parameter.

As a result, the entire time from sending the command to receiving confirmation on the same experimental phone is about 60 ms, i.e. twenty times faster than adb input tap.

adb input swipe

Disadvantages: like tap, firstly, it takes a long time, and secondly, “on its own” adds inertia. Those. it’s not just “touch at point A, swipe to B and let go”. The actual release may occur a little further or closer to the specified point B. This depends on the duration parameter.

Three packets are used to write directly to the device: touch, move, and release by completion:

EV_ABS, ABS_MT_TRACKING_ID, 0
EV_ABS, ABS_MT_POSITION_X, <координата X1>
EV_ABS, ABS_MT_POSITION_Y, <координата Y1>
EV_ABS, ABS_MT_TOUCH_MAJOR, 5
EV_KEY, BTN_TOUCH, 1
EV_KEY, BTN_TOOL_FINGER, 1
EV_SYN, SYN_REPORT, 0

EV_ABS, ABS_MT_POSITION_X, <координата X2>
EV_ABS, ABS_MT_POSITION_Y, <координата Y2>
EV_SYN, SYN_REPORT, 0

EV_ABS, ABS_MT_TRACKING_ID, -1
EV_KEY, BTN_TOUCH, 0
EV_KEY, BTN_TOOL_FINGER, 0
EV_ABS, ABS_MT_TOUCH_MAJOR, 0
EV_SYN, SYN_REPORT, 0

Side control getevent similar to that used for tapa. The execution speed is also almost the same as for tapa.

Notes and Conclusions

1. Android before version 7.1.2 had a shell command size limit of 1024 bytes. Beginning from 7.1.2 restriction removed (unfortunately, I could not find official information, as well as the size of the new limit). However, the above commands also fit into the limit of 1024: for tap, the command length is 797 bytes, for swipe – 989.

2. You can navigate the screen not just from point A to point B, but also add any intermediate points. And so that this does not happen instantly, but with a delay, the echo command can be broken like this:

echo -en "данные_пакета">dev/input/event6;sleep delaySec;echo -en "данные_следующего_пакета">dev/input/event6 … and so on

, where delaySec is the delay in seconds. Fractional numbers are allowed, i.e. sleep 0.1 delay by 100ms.

3. When using the echo method, tap and tap with movement are significantly faster than adb input tap / swipe and guarantee accuracy.

Similar Posts

Leave a Reply