bootstrap之MultiPointerGesture

MultiPointerGesture


package io.appium.android.bootstrap.handler;

import android.view.MotionEvent.PointerCoords;
import com.android.uiautomator.common.ReflectionUtils;
import io.appium.android.bootstrap.*;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.lang.reflect.Method;

import static io.appium.android.bootstrap.utils.API.API_18;

public class MultiPointerGesture extends CommandHandler {

  private double computeLongestTime(final JSONArray actions)
      throws JSONException {
    double max = 0.0;
    for (int i = 0; i < actions.length(); i++) {
      final JSONArray gestures = actions.getJSONArray(i);
      final double endTime = gestures.getJSONObject(gestures.length() - 1)
          .getDouble("time");
      if (endTime > max) {
        max = endTime;
      }
    }

    return max;
  }

  private PointerCoords createPointerCoords(final JSONObject obj)
      throws JSONException {
    final JSONObject o = obj.getJSONObject("touch");

    final int x = o.getInt("x");
    final int y = o.getInt("y");

    final PointerCoords p = new PointerCoords();
    p.size = 1;
    p.pressure = 1;
    p.x = x;
    p.y = y;

    return p;
  }

  @Override
  public AndroidCommandResult execute(final AndroidCommand command)
      throws JSONException {
    try {
      final PointerCoords[][] pcs = parsePointerCoords(command);

      if (command.isElementCommand()) {
        final AndroidElement el = command.getElement();
        if (el.performMultiPointerGesture(pcs)) {
          return getSuccessResult("OK");
        } else {
          return getErrorResult("Unable to perform multi pointer gesture");
        }
      } else {
        if (API_18) {
          final ReflectionUtils utils = new ReflectionUtils();
          final Method pmpg = utils.getControllerMethod("performMultiPointerGesture",
              PointerCoords[][].class);
          final Boolean rt = (Boolean) pmpg.invoke(utils.getController(),
              (Object) pcs);
          if (rt) {
            return getSuccessResult("OK");
          } else {
            return getErrorResult("Unable to perform multi pointer gesture");
          }
        } else {
          Logger.error("Device does not support API < 18!");
          return new AndroidCommandResult(WDStatus.UNKNOWN_ERROR,
              "Cannot perform multi pointer gesture on device below API level 18");
        }
      }
    } catch (final Exception e) {
      Logger.debug("Exception: " + e);
      e.printStackTrace();
      return new AndroidCommandResult(WDStatus.UNKNOWN_ERROR, e.getMessage());
    }
  }

  private PointerCoords[] gesturesToPointerCoords(final double maxTime,
      final JSONArray gestures) throws JSONException {
    // gestures, e.g.:
    // [
    // {"touch":{"y":529.5,"x":120},"time":0.2},
    // {"touch":{"y":529.5,"x":130},"time":0.4},
    // {"touch":{"y":454.5,"x":140},"time":0.6},
    // {"touch":{"y":304.5,"x":150},"time":0.8}
    // ]

    // From the docs:
    // "Steps are injected about 5 milliseconds apart, so 100 steps may take
    // around 0.5 seconds to complete."
    final int steps = (int) (maxTime * 200) + 2;

    final PointerCoords[] pc = new PointerCoords[steps];

    int i = 1;
    JSONObject current = gestures.getJSONObject(0);
    double currentTime = current.getDouble("time");
    double runningTime = 0.0;
    final int gesturesLength = gestures.length();
    for (int j = 0; j < steps; j++) {
      if (runningTime > currentTime && i < gesturesLength) {
        current = gestures.getJSONObject(i++);
        currentTime = current.getDouble("time");
      }

      pc[j] = createPointerCoords(current);

      runningTime += 0.005;
    }

    return pc;
  }

  private PointerCoords[][] parsePointerCoords(final AndroidCommand command)
      throws JSONException {
    final JSONArray actions = (org.json.JSONArray) command.params().get(
        "actions");

    final double time = computeLongestTime(actions);

    final PointerCoords[][] pcs = new PointerCoords[actions.length()][];
    for (int i = 0; i < actions.length(); i++) {
      final JSONArray gestures = actions.getJSONArray(i);

      pcs[i] = gesturesToPointerCoords(time, gestures);
    }

    return pcs;
  }
}

多点触控根据你传递过来的参数决定,如果参数是一个控件元素,那么就要调用performMultiPointerGesture方法,如果参数是一系列的点,那么就要调用反射。那么具体来看看2个方法细节。


控件


performMultiPointerGesture


public boolean performMultiPointerGesture(PointerCoords[] ...touches) {
    try {
      if (API_18) {
        // The compile-time SDK expects the wrong arguments, but the runtime
        // version in the emulator is correct. So we cannot do:
        //   `return el.performMultiPointerGesture(touches);`
        // Instead we need to use Reflection to do it all at runtime.
        Method method = this.el.getClass().getMethod("performMultiPointerGesture", PointerCoords[][].class);
        Boolean rt = (Boolean)method.invoke(this.el, (Object)touches);
        return rt;
      } else {
        Logger.error("Device does not support API < 18!");
        return false;
      }
    } catch (final Exception e) {
      Logger.error("Exception: " + e + " (" + e.getMessage() + ")");
      return false;
    }
  }


UiObject中有直接可以调用的performMultiPointerGesture方法,为什么还要用反射呢。上面的方法里的注释是这样解释的:编译的时候sdk会认为参数是错误的,但是运行时却认为是正确的,所以只有在运行时调用才能保证正确性。反射调用的就是运行时的环境,所以它使用了反射调用了performMultiPointerGesture。



点组


在api18以上的版本中才有传点组的方法可调用,所以先判断sdk的版本。如果api在18以上,那么就要调用InteractionController..performMultiPointerGesture的方法来执行



你可能感兴趣的:(bootstrap)