/** * Returns an action that clicks a descendant of the view matched with the given resource id. * * @param id resource id of the view to click. * @return an action that clicks a descendant of the view matched with the given resource id. */ public static ViewAction clickDescendantViewWithId(@IdRes final int id) { return new ViewAction() { @Override public Matcher<View> getConstraints() { return hasDescendant(withId(id)); } @Override public String getDescription() { return "Click on a descendant view with id: " + id; } @Override public void perform(UiController uiController, View view) { GeneralClickAction action = new GeneralClickAction(Tap.SINGLE, GeneralLocation.VISIBLE_CENTER, Press.FINGER); View target = view.findViewById(id); // getConstraints() guarantees that the target never be null. action.perform(uiController, target); } }; }
/** * Returns an action that clicks a descendant of the view matched with the given resource id. */ public static ViewAction clickDescendantViewWithId(@IdRes final int id) { return new ViewAction() { @Override public Matcher<View> getConstraints() { return hasDescendant(withId(id)); } @Override public String getDescription() { return "Click on a descendant view with id: " + id; } @Override public void perform(UiController uiController, View view) { GeneralClickAction action = new GeneralClickAction(Tap.SINGLE, GeneralLocation.VISIBLE_CENTER, Press.FINGER); View target = view.findViewById(id); // getConstraints() guarantees that the target never be null. action.perform(uiController, target); } }; }
/** * Custom ViewAction to click on dedicated coordinates * @param x - * @param y - * @return ViewAction - */ private ViewAction clickXY( final int x, final int y ){ return new GeneralClickAction( Tap.SINGLE, new CoordinatesProvider() { @Override public float[] calculateCoordinates( View view ){ final int[] screenPos = new int[2]; view.getLocationOnScreen(screenPos); final float screenX = screenPos[0] + x; final float screenY = screenPos[1] + y; return new float[]{screenX, screenY}; } }, Press.FINGER); }
private static ViewAction clickXY(final int x, final int y) { return new GeneralClickAction( Tap.SINGLE, new CoordinatesProvider() { @Override public float[] calculateCoordinates(View view) { final int[] screenPos = new int[2]; view.getLocationOnScreen(screenPos); final float screenX = screenPos[0] + x; final float screenY = screenPos[1] + y; float[] coordinates = {screenX, screenY}; return coordinates; } }, Press.FINGER); }
public static ViewAction clickXY(final int x, final int y){ return new GeneralClickAction( Tap.SINGLE, new CoordinatesProvider() { @Override public float[] calculateCoordinates(View view) { final int[] screenPos = new int[2]; view.getLocationOnScreen(screenPos); final float screenX = screenPos[0] + x; final float screenY = screenPos[1] + y; float[] coordinates = {screenX, screenY}; return coordinates; } }, Press.FINGER); }
public static ViewAction clickPercent(final float pctX, final float pctY) { return new GeneralClickAction( Tap.SINGLE, view -> { final int[] screenPos = new int[2]; view.getLocationOnScreen(screenPos); int w = view.getWidth(); int h = view.getHeight(); float x = w * pctX; float y = h * pctY; final float screenX = screenPos[0] + x; final float screenY = screenPos[1] + y; return new float[]{screenX, screenY}; }, Press.FINGER); }
public static ViewAction clickXY(final int x, final int y){ return new GeneralClickAction( Tap.SINGLE, getCoordinatesProvider(x, y), Press.FINGER); }
public static ViewAction longClickXY(final int x, final int y){ return new GeneralClickAction( Tap.LONG, getCoordinatesProvider(x, y), Press.FINGER); }
public static ViewAction clickOnTop() { return new GeneralClickAction(Tap.SINGLE, GeneralLocation.TOP_CENTER, Press.FINGER); }
public CustomClickAction() { this(Tap.SINGLE, GeneralLocation.VISIBLE_CENTER, Press.FINGER); }
@Override public void perform(UiController uiController, View view) { float[] coordinates = coordinatesProvider.calculateCoordinates(view); float[] precision = precisionDescriber.describePrecision(); Tapper.Status status = Tapper.Status.FAILURE; int loopCount = 0; // Native event injection is quite a tricky process. A tap is actually 2 // seperate motion events which need to get injected into the system. Injection // makes an RPC call from our app under test to the Android system server, the // system server decides which window layer to deliver the event to, the system // server makes an RPC to that window layer, that window layer delivers the event // to the correct UI element, activity, or window object. Now we need to repeat // that 2x. for a simple down and up. Oh and the down event triggers timers to // detect whether or not the event is a long vs. short press. The timers are // removed the moment the up event is received (NOTE: the possibility of eventTime // being in the future is totally ignored by most motion event processors). // // Phew. // // The net result of this is sometimes we'll want to do a regular tap, and for // whatever reason the up event (last half) of the tap is delivered after long // press timeout (depending on system load) and the long press behaviour is // displayed (EG: show a context menu). There is no way to avoid or handle this more // gracefully. Also the longpress behavour is app/widget specific. So if you have // a seperate long press behaviour from your short press, you can pass in a // 'RollBack' ViewAction which when executed will undo the effects of long press. while (status != Tapper.Status.SUCCESS && loopCount < 3) { try { status = tapper.sendTap(uiController, coordinates, precision); } catch (RuntimeException re) { throw new PerformException.Builder() .withActionDescription( String.format("%s - At Coordinates: %d, %d and precision: %d, %d", this.getDescription(), (int) coordinates[0], (int) coordinates[1], (int) precision[0], (int) precision[1])) .withViewDescription(HumanReadables.describe(view)) .withCause(re) .build(); } int duration = ViewConfiguration.getPressedStateDuration(); // ensures that all work enqueued to process the tap has been run. if (duration > 0) { uiController.loopMainThreadForAtLeast(duration); } if (status == Tapper.Status.WARNING) { break; } loopCount++; } if (status == Tapper.Status.FAILURE) { throw new PerformException.Builder() .withActionDescription(this.getDescription()) .withViewDescription(HumanReadables.describe(view)) .withCause(new RuntimeException(String.format("Couldn't " + "click at: %s,%s precision: %s, %s . Tapper: %s coordinate provider: %s precision " + "describer: %s. Tried %s times. With Rollback? %s", coordinates[0], coordinates[1], precision[0], precision[1], tapper, coordinatesProvider, precisionDescriber, loopCount, false))) .build(); } if (tapper == Tap.SINGLE && view instanceof WebView) { // WebViews will not process click events until double tap // timeout. Not the best place for this - but good for now. uiController.loopMainThreadForAtLeast(ViewConfiguration.getDoubleTapTimeout()); } }
public static ViewAction clickOnChild(int childViewId) { return actionWithAssertions((new ChildClickAction( new GeneralClickAction(Tap.SINGLE, GeneralLocation.VISIBLE_CENTER, Press.FINGER), childViewId))); }