android / android/android-test
Swipe distance is not consistent due to problem with x,y rounding
- Dominant language
- Java
- Stars
- 1.2k
- Forks
- 342
- Avg merge
- 11h 29m
- Merged PRs (30d)
- 2
Description
### Description
Swipe code is using swipeSteps to make it looks smooth that is rounding numbers that break distance, especially when you swipe more than once.
#### Little backstory:
Code is not changed since 9 years.
Took me a while to figure it out and I don't know where to report it cause each site is trying to redirect me to other site. Anyway back to topic.
What I did to make sure I'm looking at good code I decompiled latest uiautomator2.aar from maven cause I couldn't find source code and `InteractionController` looks the same like in the https://android.googlesource.com/platform/frameworks/uiautomator so I will use it as example.
#### Actual description
Your `InteractionController` `swipe` code is broken.
I highlighted source of swipe method here
https://android.googlesource.com/platform/frameworks/uiautomator/+/refs/heads/master/src/com/android/uiautomator/core/InteractionController.java#438
Basically what's happening is to make swipe smooth you divide swipe to smaller chunks in lines 448-449 and cast this to double.
```java
xStep = ((double)(upX - downX)) / swipeSteps;
yStep = ((double)(upY - downY)) / swipeSteps;
````
After that in the loop you cast this to int so you're starting loosing pixels multiplied by amount of swipeSteps (line 456)
```java
ret &= touchMove(downX + (int)(xStep * i), downY + (int)(yStep * i));
```
At the end you just skip missing distance or dump missing pixels cause there is no correct rounding or no
```java
ret &= touchMove(upX, upY);
```
and just
```java
ret &= touchUp(upX, upY);
```
Swipe action goes off the desired position. It's visible every time when swipe coordinates cannot be divided by 100 and `swipeSteps` variable is large.
Swipe method code
```java
public boolean swipe(int downX, int downY, int upX, int upY, int steps, boolean drag) {
boolean ret = false;
int swipeSteps = steps;
double xStep = 0;
double yStep = 0;
// avoid a divide by zero
if(swipeSteps == 0)
swipeSteps = 1;
xStep = ((double)(upX - downX)) / swipeSteps;
yStep = ((double)(upY - downY)) / swipeSteps;
// first touch starts exactly at the point requested
ret = touchDown(downX, downY);
if (drag)
SystemClock.sleep(mUiAutomatorBridge.getSystemLongPressTime());
for(int i = 1; i < swipeSteps; i++) {
ret &= touchMove(downX + (int)(xStep * i), downY + (int)(yStep * i));
if(ret == false)
break;
// set some known constant delay between steps as without it this
// become completely dependent on the speed of the system and results
// may vary on different devices. This guarantees at minimum we have
// a preset delay.
SystemClock.sleep(MOTION_EVENT_INJECTION_DELAY_MILLIS);
}
if (drag)
SystemClock.sleep(REGULAR_CLICK_LENGTH);
ret &= touchUp(upX, upY);
return(ret);
}
```
### Steps to Reproduce
Swipe multiple times by same amount using uiautomator and see the distance is inconsistent.
Swipe with plain actions touchDown / touchMove / touchUp and single step.
### Expected Results
Swipe distance is consistent
### Actual Results
Swipe distance is inconsistent
### AndroidX Test and Android OS Versions
All
### Link to a public git repo demonstrating the problem:
Contributor guide
Research direction
Locate the InteractionController swipe implementation and compare its swipe-step coordinate calculations with the linked uiautomator source. Reproduce repeated swipes with coordinates that do not divide evenly by swipeSteps, then add coverage showing that the final touch reaches the requested endpoint and repeated swipes travel consistently.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- android, java
- Domain
- mobile-dev, testing
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100