bootstrap之Click大事

上一篇文章中谈到了bootstrap流程,本文开始把目光bootstrap它可以接受指令(从源代码视图的透视。因为appium该项目现在还处于不断更新,因此,一些指令已经实现。也许未来会实现一些。从视图的源代码的点的优点是对未来要知道将来也许appium哪些功能可以做)。


在bootstrap项目中的io.appium.android.bootstrap.handler包中的类都是相应的相应的指令的类,里面都有execute方法来运行命令。先上上一篇文章中讲的map。


private static HashMap<String, CommandHandler> map = new HashMap<String, CommandHandler>();

  static {
    map.put("waitForIdle", new WaitForIdle());
    map.put("clear", new Clear());
    map.put("orientation", new Orientation());
    map.put("swipe", new Swipe());
    map.put("flick", new Flick());
    map.put("drag", new Drag());
    map.put("pinch", new Pinch());
    map.put("click", new Click());
    map.put("touchLongClick", new TouchLongClick());
    map.put("touchDown", new TouchDown());
    map.put("touchUp", new TouchUp());
    map.put("touchMove", new TouchMove());
    map.put("getText", new GetText());
    map.put("setText", new SetText());
    map.put("getName", new GetName());
    map.put("getAttribute", new GetAttribute());
    map.put("getDeviceSize", new GetDeviceSize());
    map.put("scrollTo", new ScrollTo());
    map.put("find", new Find());
    map.put("getLocation", new GetLocation());
    map.put("getSize", new GetSize());
    map.put("wake", new Wake());
    map.put("pressBack", new PressBack());
    map.put("dumpWindowHierarchy", new DumpWindowHierarchy());
    map.put("pressKeyCode", new PressKeyCode());
    map.put("longPressKeyCode", new LongPressKeyCode());
    map.put("takeScreenshot", new TakeScreenshot());
    map.put("updateStrings", new UpdateStrings());
    map.put("getDataDir", new GetDataDir());
    map.put("performMultiPointerGesture", new MultiPointerGesture());
    map.put("openNotification", new OpenNotification());
  }


我们就依照上面的顺序来讲。

首先声明一点,事先了解一下uiautomator的api非常有必要。由于这些指令中大多数都是调用uiautomator的方法去操作的,要么直接调用。要么反射调用。我的博客有非常多关于这方面的文章,能够先去看看。


click


package io.appium.android.bootstrap.handler;

import com.android.uiautomator.core.UiDevice;
import com.android.uiautomator.core.UiObjectNotFoundException;
import io.appium.android.bootstrap.*;
import org.json.JSONException;

import java.util.ArrayList;
import java.util.Hashtable;

/**
 * This handler is used to click elements in the Android UI.
 * 
 * Based on the element Id, click that element.
 * 
 */
public class Click extends CommandHandler {

  /*
   * @param command The {@link AndroidCommand}
   * 
   * @return {@link AndroidCommandResult}
   * 
   * @throws JSONException
   * 
   * @see io.appium.android.bootstrap.CommandHandler#execute(io.appium.android.
   * bootstrap.AndroidCommand)
   */
  @Override
  public AndroidCommandResult execute(final AndroidCommand command)
      throws JSONException {
    if (command.isElementCommand()) {
      try {
        final AndroidElement el = command.getElement();
        el.click();
        return getSuccessResult(true);
      } catch (final UiObjectNotFoundException e) {
        return new AndroidCommandResult(WDStatus.NO_SUCH_ELEMENT,
            e.getMessage());
      } catch (final Exception e) { // handle NullPointerException
        return getErrorResult("Unknown error");
      }
    } else {
      final Hashtable<String, Object> params = command.params();
      final Double[] coords = { Double.parseDouble(params.get("x").toString()),
          Double.parseDouble(params.get("y").toString()) };
      final ArrayList<Integer> posVals = absPosFromCoords(coords);
      final boolean res = UiDevice.getInstance().click(posVals.get(0),
          posVals.get(1));
      return getSuccessResult(res);
    }
  }
}

该类中的方法就是处理点击事件,首先方法会推断你传入的命令參数是针对控件对象的还是以坐标的形式的。


控件


假设是控件的话。首先会获得命令中的控件对象,然后调用click方法,我们进入click方法看看


AndroidElement.java

public boolean click() throws UiObjectNotFoundException {
    return el.click();
  }

e1的定义为


private final UiObject el;

说明终于调用的是uiautomator中的UiObject类的click方法。这种方法的click方法就是点击该控件的中心点。然后回到Click类中继续往下看。会调用


return getSuccessResult(true);


从字面意思来看,走到这一步肯定就是告诉调用者,我仅仅想成功了,跟你说一声。

然后我们来看看这种方法里面的详细实现。


/**
   * Returns success along with the payload.
   * 
   * @param value
   * @return {@link AndroidCommandResult}
   */
  protected AndroidCommandResult getSuccessResult(final Object value) {
    return new AndroidCommandResult(WDStatus.SUCCESS, value);
  }

创建AndroidCommandResult新对象,传入WDStatus.SUCCESS,和value(我们这里传入的值为true).首先看一下SUCCESS的值,该值存放在枚举类WDStatus中。


SUCCESS (0, "The command executed successfully."), 

就是一行文本。好,以下进入AndroidCommandResult类的构造方法里。


JSONObject json;
public AndroidCommandResult(final WDStatus status, final Object val) {
    json = new JSONObject();
    try {
      json.put("status", status.code());
      json.put("value", val);
    } catch (final JSONException e) {
      Logger.error("Couldn't create android command result!");
    }
  }

构造方法里把传入的參数保存在了json对象中。以键值对的形式。好了。条件为控件的情况分析结束,以下開始分析坐标。


坐标


假设是坐标的话。程序会获得命令里的坐标參数。保存在Double数组中。


final Hashtable<String, Object> params = command.params();
final Double[] coords = { Double.parseDouble(params.get("x").toString()),
          Double.parseDouble(params.get("y").toString()) };

接下来会通过absPosFromCoords方法将Double转换为List。所以以下来看absPosFromCoords方法的实现:


/**
   * Given a position, it will return either the position based on percentage
   * (by passing in a double between 0 and 1) or absolute position based on the
   * coordinates entered.
   * 
   * @param coordVals
   * @return ArrayList<Integer>
   */
  protected static ArrayList<Integer> absPosFromCoords(final Double[] coordVals) {
    final ArrayList<Integer> retPos = new ArrayList<Integer>();
    final UiDevice d = UiDevice.getInstance();

    final Double screenX = (double) d.getDisplayWidth();
    final Double screenY = (double) d.getDisplayHeight();

    if (coordVals[0] < 1 && coordVals[1] < 1) {
      retPos.add((int) (screenX * coordVals[0]));
      retPos.add((int) (screenY * coordVals[1]));
    } else {
      retPos.add(coordVals[0].intValue());
      retPos.add(coordVals[1].intValue());
    }

    return retPos;
  }

首先会推断传入的坐标是以百分比的形式还是以坐标的形式。假设是百分比说明你传入的不是绝对坐标,而是相对坐标(能够这么理解吧。这样能够适应各个屏幕)。这样的情况你就须要获取屏幕的尺寸,然后和百分比做计算得到当前屏幕中你所要点击的坐标点。假设你传入的就是坐标,那就直接将Double类型的值转化为Int的值。

经过上面的一番操作以后。会得到确切坐标值保存在数组中返回。

然后程序调用UiDevice的click方法点击啦:


final boolean res = UiDevice.getInstance().click(posVals.get(0), posVals.get(1));

最后返回一个成成功AndroidCommandResult物。


版权声明:本文博主原创文章,博客,未经同意不得转载。

posted @ 2015-10-11 20:39  phlsheji  阅读(504)  评论(0编辑  收藏  举报