/*
   * UiAutomator has a broken longClick. getAutomatorBridge is private so we
   * access the bridge via reflection to use the touchDown / touchUp methods.
   */
  private boolean correctLongClick(final int x, final int y, final int duration) {
    try {
      /*
       * bridge.getClass() returns ShellUiAutomatorBridge on API 18/19 so use
       * the super class.
       */

      final UiDevice device = UiDevice.getInstance();
      final Object bridge = enableField(device.getClass(), "mUiAutomationBridge").get(device);
      final Object controller =
          enableField(bridge.getClass().getSuperclass(), "mInteractionController").get(bridge);
      final Class<?> controllerClass = controller.getClass();

      Logger.debug("Finding methods on class: " + controllerClass);
      final Method touchDown = controllerClass.getDeclaredMethod("touchDown", int.class, int.class);
      touchDown.setAccessible(true);
      final Method touchUp = controllerClass.getDeclaredMethod("touchUp", int.class, int.class);
      touchUp.setAccessible(true);

      if ((Boolean) touchDown.invoke(controller, x, y)) {
        SystemClock.sleep(duration);
        if ((Boolean) touchUp.invoke(controller, x, y)) {
          return true;
        }
      }
      return false;

    } catch (final Exception e) {
      Logger.debug("Problem invoking correct long click: " + e);
      return false;
    }
  }
 private static Field enableField(final Class<?> clazz, final String field)
     throws SecurityException, NoSuchFieldException {
   Logger.debug("Updating class \"" + clazz + "\" to enable field \"" + field + "\"");
   final Field fieldObject = clazz.getDeclaredField(field);
   fieldObject.setAccessible(true);
   return fieldObject;
 }
Exemple #3
0
 protected void printEventDebugLine(final String methodName, final Integer... duration) {
   String extra = "";
   if (duration.length > 0) {
     extra = ", duration: " + duration[0];
   }
   Logger.debug(
       "Performing "
           + methodName
           + " using element? "
           + isElement
           + " x: "
           + clickX
           + ", y: "
           + clickY
           + extra);
 }
  /*
   * @param command The {@link AndroidCommand} used for this handler.
   *
   * @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 {
    final Hashtable<String, Object> params = command.params();

    AndroidElement el;
    final String direction = params.get("direction").toString();
    final Integer percent = (Integer) params.get("percent");
    final Integer steps = (Integer) params.get("steps");
    try {
      el = command.getElement();
      if (el == null) {
        return getErrorResult(
            "Could not find an element with elementId: " + params.get("elementId"));
      }
    } catch (final Exception e) { // JSONException, NullPointerException, etc.
      return getErrorResult("Unknown error:" + e.getMessage());
    }

    Logger.debug(
        "Pinching "
            + direction
            + " "
            + percent.toString()
            + "%"
            + " with steps: "
            + steps.toString());
    boolean res;
    if (direction.equals("in")) {
      try {
        res = el.pinchIn(percent, steps);
      } catch (final UiObjectNotFoundException e) {
        return getErrorResult("Selector could not be matched to any UI element displayed");
      }
    } else {
      try {
        res = el.pinchOut(percent, steps);
      } catch (final UiObjectNotFoundException e) {
        return getErrorResult("Selector could not be matched to any UI element displayed");
      }
    }

    if (res) {
      return getSuccessResult(res);
    } else {
      return getErrorResult("Pinch did not complete successfully");
    }
  }
Exemple #5
0
  @Override
  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;
  }
Exemple #6
0
  /*
   * UiAutomator has a broken longClick, so we'll try to implement it using the
   * touchDown / touchUp events.
   */
  protected static boolean correctLongClick(final int x, final int y, final int duration) {
    try {
      /*
       * bridge.getClass() returns ShellUiAutomatorBridge on API 18/19 so use
       * the super class.
       */

      final ReflectionUtils utils = new ReflectionUtils();
      final Method touchDown = utils.getControllerMethod("touchDown", int.class, int.class);
      final Method touchUp = utils.getControllerMethod("touchUp", int.class, int.class);

      if ((Boolean) touchDown.invoke(utils.getController(), x, y)) {
        SystemClock.sleep(duration);
        if ((Boolean) touchUp.invoke(utils.getController(), x, y)) {
          return true;
        }
      }
      return false;

    } catch (final Exception e) {
      Logger.debug("Problem invoking correct long click: " + e);
      return false;
    }
  }
  /**
   * @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 {
    try {
      final Hashtable<String, Object> params = command.params();
      AndroidElement el = null;
      int clickX = -1;
      int clickY = -1;

      boolean isElement = false;
      // 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) {
      }

      if (isElement) {
        // extract x and y from the element.
        el = command.getElement();

        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");
        double targetX = 0.5;
        double targetY = 0.5;
        if (paramX != null) {
          targetX = Double.parseDouble(paramX.toString());
        }

        if (paramY != null) {
          targetY = Double.parseDouble(paramY.toString());
        }

        final ArrayList<Integer> posVals = absPosFromCoords(new Double[] {targetX, targetY});
        clickX = posVals.get(0);
        clickY = posVals.get(1);
      }

      final Object paramDuration = params.get("duration");
      int duration = 2000; // two seconds
      if (paramDuration != null) {
        duration = Integer.parseInt(paramDuration.toString());
      }

      Logger.debug(
          "longClick using element? "
              + isElement
              + " x: "
              + clickX
              + ", y: "
              + clickY
              + ", duration: "
              + duration);
      if (correctLongClick(clickX, clickY, duration)) {
        return getSuccessResult(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");

        final boolean res = el.longClick();
        return getSuccessResult(res);
      }
    } catch (final UiObjectNotFoundException e) {
      return new AndroidCommandResult(WDStatus.NO_SUCH_ELEMENT, e.getMessage());
    } catch (final ElementNotInHashException e) {
      return new AndroidCommandResult(WDStatus.NO_SUCH_ELEMENT, e.getMessage());
    } catch (final Exception e) {
      return getErrorResult(e.getMessage());
    }
    return getErrorResult("Failed to long click");
  }
Exemple #8
0
  /*
   * @param command The {@link AndroidCommand} used for this handler.
   *
   * @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 {
    final Hashtable<String, Object> params = command.params();

    // only makes sense on a device
    final Strategy strategy = Strategy.fromString((String) params.get("strategy"));
    final String text = (String) params.get("selector");
    final String contextId = (String) params.get("context");

    Logger.debug(
        "Finding " + text + " using " + strategy.toString() + " with the contextId: " + contextId);

    final Boolean multiple = (Boolean) params.get("multiple");
    final boolean isXpath = strategy.equals("xpath");

    if (isXpath) {
      final JSONArray xpathPath = (JSONArray) params.get("path");
      final String xpathAttr = (String) params.get("attr");
      final String xpathConstraint = (String) params.get("constraint");
      final Boolean xpathSubstr = (Boolean) params.get("substr");

      try {
        if (multiple) {
          final UiSelector sel =
              getSelectorForXpath(xpathPath, xpathAttr, xpathConstraint, xpathSubstr);
          return getSuccessResult(fetchElements(sel, contextId));
        } else {
          final UiSelector sel =
              getSelectorForXpath(xpathPath, xpathAttr, xpathConstraint, xpathSubstr);
          return getSuccessResult(fetchElement(sel, contextId));
        }
      } catch (final AndroidCommandException e) {
        return getErrorResult(e.getMessage());
      } catch (final ElementNotFoundException e) {
        return getErrorResult(e.getMessage());
      } catch (final ElementNotInHashException e) {
        return getErrorResult(e.getMessage());
      } catch (final UiObjectNotFoundException e) {
        return getErrorResult(e.getMessage());
      }
    } else {
      try {
        final UiSelector sel = getSelector(strategy, text, multiple);
        if (multiple) {
          return getSuccessResult(fetchElements(sel, contextId));
        } else {
          return getSuccessResult(fetchElement(sel, contextId));
        }
      } catch (final InvalidStrategyException e) {
        return getErrorResult(e.getMessage());
      } catch (final ElementNotFoundException e) {
        return new AndroidCommandResult(WDStatus.NO_SUCH_ELEMENT, e.getMessage());
      } catch (final AndroidCommandException e) {
        return getErrorResult(e.getMessage());
      } catch (final ElementNotInHashException e) {
        return getErrorResult(e.getMessage());
      } catch (final UiObjectNotFoundException e) {
        return getErrorResult(e.getMessage());
      }
    }
  }