摘要
这次主要分析的对象时touch功能,如touchMove、touchUp、touchDown、touchLongClick。查看这些源代码的时候你会发现,他们都是继承于TouchEvent的这个类,并且execute的方法也是在TouchEvent里面实现的,所以我们有必要去看看touchEvent这个基类里面实现了那些内容
正文
说白了,touch类的操作也是分为两种,一种就是坐标的操作,一种是针对于元素的操作,了解了这个我们就好更清楚的明白touchEvent的代码实现了。
public AndroidCommandResult execute(final AndroidCommand command)
throws JSONException {
initalize();
try {
params = command.params();
// isElementCommand doesn't check to see if we actually have an element
// so getElement is used instead.
try {
if (command.getElement() != null) {
isElement = true;
}
} catch (final Exception e) {
isElement = false;
}
if (isElement) {
// extract x and y from the element.
el = command.getElement();
// check if element exists without wait
if(! el.exists()) {
throw new UiObjectNotFoundException("TouchEvent element does not exist.");
}
final Rect bounds = el.getVisibleBounds();
clickX = bounds.centerX();
clickY = bounds.centerY();
} else { // no element so extract x and y from params
final Object paramX = params.get("x");
final Object paramY = params.get("y");
// these will be defaulted to 0.5 when passed to getDeviceAbsPos
double targetX = 0;
double targetY = 0;
if (paramX != null) {
targetX = Double.parseDouble(paramX.toString());
}
if (paramY != null) {
targetY = Double.parseDouble(paramY.toString());
}
Point coords = new Point(targetX, targetY);
coords = PositionHelper.getDeviceAbsPos(coords);
clickX = coords.x.intValue();
clickY = coords.y.intValue();
}
if (executeTouchEvent()) {
return getSuccessResult(true);
}
} catch (final UiObjectNotFoundException e) {
return new AndroidCommandResult(WDStatus.NO_SUCH_ELEMENT, e.getMessage());
} catch (final InvalidCoordinatesException e) {
return new AndroidCommandResult(WDStatus.INVALID_ELEMENT_COORDINATES,
e.getMessage());
} catch (final Exception e) {
return getErrorResult(e.getMessage());
}
return getErrorResult("Failed to execute touch event");
}
protected abstract boolean executeTouchEvent()
throws UiObjectNotFoundException;
以上的一些步骤实际上之前的都有类似的分析过首先判断command是否是针对于元素操作的命令。
-非元素操作:获取param中的x,y坐标值转换成double类型的坐标,再将坐标值转换成point的对象后最后通过getDeviceAbsPos方法转换成相对的设备的坐标。执行抽象方法executeTouchEvent()
-元素操作:获取到元素的可见矩形区域后,直接获取元素的中点坐标即可。执行抽象方法executeTouchEvent()
我们这里就看看TouchLongClick吧,因为
protected boolean executeTouchEvent() throws UiObjectNotFoundException {
final Object paramDuration = params.get("duration");
int duration = 2000; // two seconds
if (paramDuration != null) {
duration = Integer.parseInt(paramDuration.toString());
}
printEventDebugLine("TouchLongClick", duration);
if (correctLongClick(clickX, clickY, duration)) {
return true;
}
// if correctLongClick failed and we have an element
// then uiautomator's longClick is used as a fallback.
if (isElement) {
Logger.debug("Falling back to broken longClick");
return el.longClick();
}
return false;
}
这里首先先获取到参数里面的持续时间,再来调用correctLongClick方法
InteractionController interactionController = UiAutomatorBridge.getInstance().getInteractionController();
if (interactionController.touchDown(x, y)) {
SystemClock.sleep(duration);
if (interactionController.touchUp(x, y)) {
return true;
}
}
这里实际上通过反射调用了interactionController中的touchDown以及touchUp。实际上到这里我们是不是就结束了呢。实际上并没有,我们再继续看下executeTouchEvent的代码
// if correctLongClick failed and we have an element
// then uiautomator's longClick is used as a fallback.
if (isElement) {
Logger.debug("Falling back to broken longClick");
return el.longClick();
}
实际上下面还有这句,看看注释,说的是,如果correctLongClick 失败了,并且我们是有一个元素的时候,我们可以使用uiautomator的longclick方法。
那我们再看看uiautomator里面的longclick跟我们correctLongClick 的区别是什么
**
* Touches down for a long press at the specified coordinates.
*
* @param x
* @param y
* @return true if successful.
*/
public boolean longTapNoSync(int x, int y) {
if (DEBUG) {
Log.d(LOG_TAG, "longTapNoSync (" + x + ", " + y + ")");
}
if (touchDown(x, y)) {
SystemClock.sleep(mUiAutomatorBridge.getSystemLongPressTime());
if(touchUp(x, y)) {
return true;
}
}
return false;
}
以上就是uiautomator关于longclick的代码了。乍一看咦 这个不是跟我们correctLongClick 的方法一模一样吗?为什么appium又要重复造轮子,重新写一遍呢。这明显不是他们的作风啊。
我们再回到前面TouchEvent里面看看,想想一开始的时候做了什么判断吗?
哦对了。我们首先判断这个操作的对象是个元素还是坐标对吧,但是我们再看看UiAutomator里面的longclick,这个方法是只属于UiObject的。这一想就明白了。appium对touch做了扩展,让其能够即支持坐标又支持元素。这下子是不是就清晰很多了。