Appium原始碼分析(四)-swipe
阿新 • • 發佈:2019-02-04
@Override
public AndroidCommandResult execute(final AndroidCommand command)
throws JSONException {
final Hashtable<String, Object> params = command.params();
final Point start = new Point(params.get("startX"), params.get("startY"));
final Point end = new Point(params.get("endX" ), params.get("endY"));
final Integer steps = (Integer) params.get("steps");
final UiDevice device = UiDevice.getInstance();
Point absStartPos = new Point();
Point absEndPos = new Point();
try {
if (command.isElementCommand()) {
final AndroidElement el = command.getElement();
absStartPos = el.getAbsolutePosition(start);
absEndPos = el.getAbsolutePosition(end);
} else {
absStartPos = PositionHelper.getDeviceAbsPos(start);
absEndPos = PositionHelper.getDeviceAbsPos(end);
}
} catch (final UiObjectNotFoundException e) {
return getErrorResult(e.getMessage());
} catch (final InvalidCoordinatesException e) {
return getErrorResult(e.getMessage());
} catch (final Exception e) { // handle NullPointerException
return getErrorResult("Unknown error");
}
Logger.debug("Swiping from " + absStartPos.toString() + " to "
+ absEndPos.toString() + " with steps: " + steps.toString());
final boolean rv = device.swipe(absStartPos.x.intValue(),
absStartPos.y.intValue(), absEndPos.x.intValue(),
absEndPos.y.intValue(), steps);
if (!rv) {
return getErrorResult("The swipe did not complete successfully");
}
return getSuccessResult(rv);
}
Swipe的程式碼其實很少,但是引數實際上不太少,param引數中包括了swipe的起始座標以及結束座標,還有一個步驟數,就是你從起始座標到結束座標需要滑動多少次。我們到UiAutomator裡面去看看 這個如何根據傳入的step來進行滑動呢
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);
}
挺清楚的了,原來swipe到最後是呼叫了touchDwon以及touchUp方法,通過結束的X/Y座標減去開始的X/Y座標,再除以一個步驟數,就得到了每次Swipe需要多長的距離了
再繼續前面Swipe的分析獲取到傳入的引數以後,首先判斷這個命令是針對於元素的滑動還是針對於裝置的滑動
- 如果是針對於元素進行滑動的話,這裡就要進行一個座標的轉換,將其轉換成相對於元素的座標。我們看看實際的程式碼
public static Point getAbsolutePosition(final Point point, final Rect displayRect,
final Point offsets, final boolean shouldCheckBounds)
throws UiObjectNotFoundException, InvalidCoordinatesException {
final Point absolutePosition = new Point();
absolutePosition.x = translateCoordinate(point.x, displayRect.width(), offsets.x);
absolutePosition.y = translateCoordinate(point.y, displayRect.height(), offsets.y);
if (shouldCheckBounds &&
!displayRect.contains(absolutePosition.x.intValue(), absolutePosition.y.intValue())) {
throw new InvalidCoordinatesException("Coordinate " + absolutePosition.toString() +
" is outside of element rect: " + displayRect.toShortString());
}
return absolutePosition;
}
這裡是分別對x,y座標進行轉換,分別傳入元素的寬高以及左頂點座標 看看實際轉換的程式碼
private static double translateCoordinate(double pointCoord, double length, double offset) {
double translatedCoord = 0;
if (pointCoord == 0) {
translatedCoord = length * 0.5;
} else if (Math.abs(pointCoord) > 0 && Math.abs(pointCoord) < 1) {
translatedCoord = length * pointCoord;
} else {
translatedCoord = pointCoord;
}
return translatedCoord + offset;
}
- 首先判斷傳入的座標值是不是0,如果是0的話就是從元素的中點開始
- 再來判斷傳入的座標是不是小數,也就是百分比,如果是的話就進行相應的轉換
- 最後如果前兩者都是那麼傳入的就是一個真實的座標,就直接取那個值就行
-
換算的值加上我們元素的一個偏移值,這個偏移值就是如果是X座標就是元素Rect的left,Y座標的話就是元素Rect的top了。
換算出來的值最後呼叫uiautomator的swipe方法就OK了。
下來我們再來看看針對於裝置的Swipe又是怎麼樣的呢
public static Point getDeviceAbsPos(final Point point)
throws UiObjectNotFoundException, InvalidCoordinatesException {
final UiDevice d = UiDevice.getInstance();
final Rect displayRect = new Rect(0, 0, d.getDisplayWidth(), d.getDisplayHeight());
Logger.debug("Display bounds: " + displayRect.toShortString());
return getAbsolutePosition(point, displayRect, new Point(), true);
}
改變的地方就是之前傳參傳的是元素的矩陣的座標,而這次傳入的是裝置的寬高。其他沒有什麼區別了。