diff --git a/src/main/java/io/appium/java_client/AppiumDriver.java b/src/main/java/io/appium/java_client/AppiumDriver.java index 7b023405b..bf2d412b9 100644 --- a/src/main/java/io/appium/java_client/AppiumDriver.java +++ b/src/main/java/io/appium/java_client/AppiumDriver.java @@ -28,8 +28,6 @@ import org.openqa.selenium.By; import org.openqa.selenium.Capabilities; import org.openqa.selenium.DeviceRotation; -import org.openqa.selenium.Dimension; -import org.openqa.selenium.Point; import org.openqa.selenium.ScreenOrientation; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebDriverException; @@ -67,7 +65,7 @@ * for each target mobile OS (still Android and iOS) */ @SuppressWarnings("unchecked") -public abstract class AppiumDriver +public class AppiumDriver extends DefaultGenericMobileDriver { private static final ErrorHandler errorHandler = new ErrorHandler(new ErrorCodesMobile(), true); @@ -214,9 +212,11 @@ public List findElementsByXPath(String using) { } /** - * @see TouchShortcuts#tap(int, WebElement, int). + * This method is deprecated and it is going to be removed soon. + * Please use {@link MultiTouchAction#tap(int, WebElement, int)}. */ - @Override public void tap(int fingers, WebElement element, int duration) { + @Deprecated + public void tap(int fingers, WebElement element, int duration) { MultiTouchAction multiTouch = new MultiTouchAction(this); for (int i = 0; i < fingers; i++) { @@ -227,81 +227,49 @@ public List findElementsByXPath(String using) { } /** - * @see TouchShortcuts#tap(int, int, int, int). + * This method is deprecated and it is going to be removed soon. + * Please use {@link MultiTouchAction#tap(int, int, int, int)}. */ - @Override public void tap(int fingers, int x, int y, int duration) { + @Deprecated + public void tap(int fingers, int x, int y, int duration) { MultiTouchAction multiTouch = new MultiTouchAction(this); for (int i = 0; i < fingers; i++) { multiTouch.add(createTap(x, y, duration)); } - multiTouch.perform(); } - protected void doSwipe(int startx, int starty, int endx, int endy, int duration) { - TouchAction touchAction = new TouchAction(this); - - // appium converts press-wait-moveto-release to a swipe action - touchAction.press(startx, starty).waitAction(duration).moveTo(endx, endy).release(); - - touchAction.perform(); - } - /** - * @see TouchShortcuts#swipe(int, int, int, int, int). + * This method is deprecated. + * It was moved to {@link CreatesSwipeAction#swipe(int, int, int, int, int)}. */ - @Override public abstract void swipe(int startx, int starty, int endx, int endy, int duration); + @Deprecated + public void swipe(int startx, int starty, int endx, int endy, int duration) { + //does nothing + } /** - * Convenience method for pinching an element on the screen. - * "pinching" refers to the action of two appendages pressing the - * screen and sliding towards each other. - * NOTE: - * This convenience method places the initial touches around the element, if this would - * happen to place one of them off the screen, appium with return an outOfBounds error. - * In this case, revert to using the MultiTouchAction api instead of this method. - * - * @param el The element to pinch. + * This method is deprecated and it is going to be removed soon. + * Please use {@link MultiTouchAction#pinch(WebElement)}. */ + @Deprecated public void pinch(WebElement el) { MultiTouchAction multiTouch = new MultiTouchAction(this); - Dimension dimensions = el.getSize(); - Point upperLeft = el.getLocation(); - Point center = new Point(upperLeft.getX() + dimensions.getWidth() / 2, - upperLeft.getY() + dimensions.getHeight() / 2); - int yOffset = center.getY() - upperLeft.getY(); - - TouchAction action0 = - new TouchAction(this).press(el, center.getX(), center.getY() - yOffset).moveTo(el) - .release(); - TouchAction action1 = - new TouchAction(this).press(el, center.getX(), center.getY() + yOffset).moveTo(el) - .release(); - - multiTouch.add(action0).add(action1); - - multiTouch.perform(); + multiTouch.pinch(el).perform(); } /** - * Convenience method for pinching an element on the screen. - * "pinching" refers to the action of two appendages pressing the screen and - * sliding towards each other. - * NOTE: - * This convenience method places the initial touches around the element at a distance, - * if this would happen to place one of them off the screen, appium will return an - * outOfBounds error. In this case, revert to using the MultiTouchAction api instead of this - * method. - * - * @param x x coordinate to terminate the pinch on. - * @param y y coordinate to terminate the pinch on. + * This method is deprecated and it is going to be removed soon. + * Please use {@link MultiTouchAction#pinch(int, int, int, int)} or + * {@link MultiTouchAction#pinch(int, int, int)} */ + @Deprecated public void pinch(int x, int y) { MultiTouchAction multiTouch = new MultiTouchAction(this); - int scrHeight = manage().window().getSize().getHeight(); + int scrHeight = this.manage().window().getSize().getHeight(); int yOffset = 100; if (y - 100 < 0) { @@ -313,57 +281,30 @@ public void pinch(int x, int y) { TouchAction action0 = new TouchAction(this).press(x, y - yOffset).moveTo(x, y).release(); TouchAction action1 = new TouchAction(this).press(x, y + yOffset).moveTo(x, y).release(); - multiTouch.add(action0).add(action1); - - multiTouch.perform(); + multiTouch.add(action0).add(action1).perform(); } /** - * Convenience method for "zooming in" on an element on the screen. - * "zooming in" refers to the action of two appendages pressing the screen and sliding - * away from each other. - * NOTE: - * This convenience method slides touches away from the element, if this would happen - * to place one of them off the screen, appium will return an outOfBounds error. - * In this case, revert to using the MultiTouchAction api instead of this method. - * - * @param el The element to pinch. + * This method is deprecated and it is going to be removed soon. + * Please use {@link MultiTouchAction#zoom(WebElement)}. */ + @Deprecated public void zoom(WebElement el) { MultiTouchAction multiTouch = new MultiTouchAction(this); - Dimension dimensions = el.getSize(); - Point upperLeft = el.getLocation(); - Point center = new Point(upperLeft.getX() + dimensions.getWidth() / 2, - upperLeft.getY() + dimensions.getHeight() / 2); - int yOffset = center.getY() - upperLeft.getY(); - - TouchAction action0 = new TouchAction(this).press(center.getX(), center.getY()) - .moveTo(el, center.getX(), center.getY() - yOffset).release(); - TouchAction action1 = new TouchAction(this).press(center.getX(), center.getY()) - .moveTo(el, center.getX(), center.getY() + yOffset).release(); - - multiTouch.add(action0).add(action1); - - multiTouch.perform(); + multiTouch.zoom(el).perform(); } /** - * Convenience method for "zooming in" on an element on the screen. - * "zooming in" refers to the action of two appendages pressing the screen - * and sliding away from each other. - * NOTE: - * This convenience method slides touches away from the element, if this would happen to - * place one of them off the screen, appium will return an outOfBounds error. In this case, - * revert to using the MultiTouchAction api instead of this method. - * - * @param x x coordinate to start zoom on. - * @param y y coordinate to start zoom on. + * This method is deprecated and it is going to be removed soon. + * Please use {@link MultiTouchAction#zoom(int, int, int, int)} or + * {@link MultiTouchAction#zoom(int, int, int)}. */ + @Deprecated public void zoom(int x, int y) { MultiTouchAction multiTouch = new MultiTouchAction(this); - int scrHeight = manage().window().getSize().getHeight(); + int scrHeight = this.manage().window().getSize().getHeight(); int yOffset = 100; if (y - 100 < 0) { @@ -375,9 +316,7 @@ public void zoom(int x, int y) { TouchAction action0 = new TouchAction(this).press(x, y).moveTo(0, -yOffset).release(); TouchAction action1 = new TouchAction(this).press(x, y).moveTo(0, yOffset).release(); - multiTouch.add(action0).add(action1); - - multiTouch.perform(); + multiTouch.add(action0).add(action1).perform(); } @Override public WebDriver context(String name) { @@ -447,11 +386,13 @@ public void zoom(int x, int y) { locationContext.setLocation(location); } + @Deprecated private TouchAction createTap(WebElement element, int duration) { TouchAction tap = new TouchAction(this); return tap.press(element).waitAction(duration).release(); } + @Deprecated private TouchAction createTap(int x, int y, int duration) { TouchAction tap = new TouchAction(this); return tap.press(x, y).waitAction(duration).release(); diff --git a/src/main/java/io/appium/java_client/CreatesSwipeAction.java b/src/main/java/io/appium/java_client/CreatesSwipeAction.java new file mode 100644 index 000000000..2f821e285 --- /dev/null +++ b/src/main/java/io/appium/java_client/CreatesSwipeAction.java @@ -0,0 +1,101 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.appium.java_client; + +import org.openqa.selenium.WebElement; + +public interface CreatesSwipeAction { + + /** + * Creates combined touch action for the swiping by start/end coordinates. + * + * @param startX x-coordinate to swipe from + * @param startY y-coordinate to swipe from + * @param endX x-coordinate to swipe to + * @param endY y-coordinate to swipe to + * @param duration in milliseconds + * @return an instance of combined {@link TouchAction} + */ + TouchAction swipe(int startX, int startY, int endX, int endY, int duration); + + /** + * Creates combined touch action for the swiping from given coordinates to the given element. + * + * @param startX x-coordinate to swipe from + * @param startY y-coordinate to swipe from + * @param element an element to swipe to + * @param duration in milliseconds + * @return an instance of combined {@link TouchAction} + */ + TouchAction swipe(int startX, int startY, WebElement element, int duration); + + /** + * Creates combined touch action for the swiping from one element to another. + * + * @param element1 an element to swipe to + * @param element2 an element to swipe to + * @param duration in milliseconds + * @return an instance of combined {@link TouchAction} + */ + TouchAction swipe(WebElement element1, WebElement element2, int duration); + + + /** + * Creates combined touch action for the swiping inside an element. + * + * @param element an element where the swiping is performed + * @param direction is the direction to perform the swiping inside the element + * @param duration in milliseconds + * @return an instance of combined {@link TouchAction} + */ + default TouchAction swipe(MobileElement element, SwipeElementDirection direction, int duration) { + return direction.swipe(this, element, 0, 0, duration); + } + + /** + * Creates combined touch action for the swiping inside an element using some offset from its + * borders. + * + * @param element an element where the swiping is performed + * @param direction is the direction to perform the swiping inside the element + * @param offsetFromStartBorder is the offset from the border of the element where the + * swiping should be started. If direction is UP then + * this is offset from the bottom of the element. + * If direction is DOWN then this is offset from the top of + * the element. If direction is RIGHT then this is offset from + * the left border of the element. If direction is LEFT then + * this is offset from the right border of the element. + * @param offsetFromEndBorder is the offset from the border of the element where + * the swiping should be finished. If direction is UP then + * this is offset from the top of the element. + * If direction is DOWN then this is offset from the bottom + * of the element. If direction is RIGHT then + * this is offset from the right border of the element. + * If direction is LEFT then this is offset from the + * left border of the element. + * @param duration in milliseconds + * @return an instance of combined {@link TouchAction} + * @throws IllegalCoordinatesException when resulted coordinates are out of the + * element borders or disagree with the given direction. + */ + default TouchAction swipe(MobileElement element, SwipeElementDirection direction, int offsetFromStartBorder, + int offsetFromEndBorder, + int duration) throws IllegalCoordinatesException { + return direction.swipe(this, element, offsetFromStartBorder, offsetFromEndBorder, + duration); + } +} diff --git a/src/main/java/io/appium/java_client/DeviceActionShortcuts.java b/src/main/java/io/appium/java_client/DeviceActionShortcuts.java index 2790bf045..4f819d489 100644 --- a/src/main/java/io/appium/java_client/DeviceActionShortcuts.java +++ b/src/main/java/io/appium/java_client/DeviceActionShortcuts.java @@ -21,6 +21,11 @@ import org.openqa.selenium.remote.Response; +@Deprecated +/** + * This interface is deprecated and won't be supported anymore. + * Please use {@link HasDeviceTime} and {@link HidesKeyboard} API instead. + */ public interface DeviceActionShortcuts extends ExecutesMethod { /** diff --git a/src/main/java/io/appium/java_client/HasDeviceTime.java b/src/main/java/io/appium/java_client/HasDeviceTime.java new file mode 100644 index 000000000..292c83189 --- /dev/null +++ b/src/main/java/io/appium/java_client/HasDeviceTime.java @@ -0,0 +1,31 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.appium.java_client; + +import static io.appium.java_client.MobileCommand.GET_DEVICE_TIME; + +import org.openqa.selenium.remote.Response; + +public interface HasDeviceTime extends ExecutesMethod { + /* + Gets device date and time for both iOS(Supports only real device) and Android devices + */ + default String getDeviceTime() { + Response response = execute(GET_DEVICE_TIME); + return response.getValue().toString(); + } +} diff --git a/src/main/java/io/appium/java_client/HidesKeyboard.java b/src/main/java/io/appium/java_client/HidesKeyboard.java new file mode 100644 index 000000000..5f292b0ce --- /dev/null +++ b/src/main/java/io/appium/java_client/HidesKeyboard.java @@ -0,0 +1,29 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.appium.java_client; + +import static io.appium.java_client.MobileCommand.HIDE_KEYBOARD; + +public interface HidesKeyboard extends ExecutesMethod { + + /** + * Hides the keyboard if it is showing. + */ + default void hideKeyboard() { + execute(HIDE_KEYBOARD); + } +} diff --git a/src/main/java/io/appium/java_client/HidesKeyboardWithKeyName.java b/src/main/java/io/appium/java_client/HidesKeyboardWithKeyName.java new file mode 100644 index 000000000..011d4e0f5 --- /dev/null +++ b/src/main/java/io/appium/java_client/HidesKeyboardWithKeyName.java @@ -0,0 +1,35 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.appium.java_client; + +import static io.appium.java_client.ios.IOSMobileCommandHelper.hideKeyboardCommand; + +public interface HidesKeyboardWithKeyName extends HidesKeyboard { + + /** + * Hides the keyboard if it is showing. Hiding the keyboard often + * depends on the way an app is implemented, no single strategy always + * works. + * + * @param strategy HideKeyboardStrategy. + * @param keyName a String, representing the text displayed on the button of the + * keyboard you want to press. For example: "Done". + */ + default void hideKeyboard(String strategy, String keyName) { + CommandExecutionHelper.execute(this, hideKeyboardCommand(strategy, keyName)); + } +} diff --git a/src/main/java/io/appium/java_client/MobileCommand.java b/src/main/java/io/appium/java_client/MobileCommand.java index 6929d91cf..7923ca347 100644 --- a/src/main/java/io/appium/java_client/MobileCommand.java +++ b/src/main/java/io/appium/java_client/MobileCommand.java @@ -22,6 +22,7 @@ import org.openqa.selenium.remote.CommandInfo; import org.openqa.selenium.remote.http.HttpMethod; +import java.util.AbstractMap; import java.util.HashMap; import java.util.Map; @@ -178,4 +179,64 @@ public static ImmutableMap prepareArguments(String[] params, } return builder.build(); } + + /** + * This method forms a {@link java.util.Map} of parameters for the + * key event invocation. + * + * @param key code for the key pressed on the device. + * @return a key-value pair. The key is the command name. The value is a + * {@link java.util.Map} command arguments. + */ + public static Map.Entry> pressKeyCodeCommand(int key) { + return new AbstractMap.SimpleEntry<>( + PRESS_KEY_CODE, prepareArguments("keycode", key)); + } + + /** + * This method forms a {@link java.util.Map} of parameters for the + * key event invocation. + * + * @param key code for the key pressed on the Android device. + * @param metastate metastate for the keypress. + * @return a key-value pair. The key is the command name. The value is a + * {@link java.util.Map} command arguments. + */ + public static Map.Entry> pressKeyCodeCommand(int key, + Integer metastate) { + String[] parameters = new String[] {"keycode", "metastate"}; + Object[] values = new Object[] {key, metastate}; + return new AbstractMap.SimpleEntry<>( + PRESS_KEY_CODE, prepareArguments(parameters, values)); + } + + /** + * This method forms a {@link java.util.Map} of parameters for the + * long key event invocation. + * + * @param key code for the long key pressed on the device. + * @return a key-value pair. The key is the command name. The value is a + * {@link java.util.Map} command arguments. + */ + public static Map.Entry> longPressKeyCodeCommand(int key) { + return new AbstractMap.SimpleEntry<>( + LONG_PRESS_KEY_CODE, prepareArguments("keycode", key)); + } + + /** + * This method forms a {@link java.util.Map} of parameters for the + * long key event invocation. + * + * @param key code for the long key pressed on the Android device. + * @param metastate metastate for the long key press. + * @return a key-value pair. The key is the command name. The value is a + * {@link java.util.Map} command arguments. + */ + public static Map.Entry> longPressKeyCodeCommand(int key, + Integer metastate) { + String[] parameters = new String[] {"keycode", "metastate"}; + Object[] values = new Object[] {key, metastate}; + return new AbstractMap.SimpleEntry<>( + LONG_PRESS_KEY_CODE, prepareArguments(parameters, values)); + } } diff --git a/src/main/java/io/appium/java_client/MobileDriver.java b/src/main/java/io/appium/java_client/MobileDriver.java index 44fa065ff..57a2c71bc 100644 --- a/src/main/java/io/appium/java_client/MobileDriver.java +++ b/src/main/java/io/appium/java_client/MobileDriver.java @@ -35,7 +35,7 @@ import java.util.Map; public interface MobileDriver extends WebDriver, PerformsTouchActions, ContextAware, Rotatable, - FindsByAccessibilityId, LocationContext, DeviceActionShortcuts, TouchShortcuts, + FindsByAccessibilityId, LocationContext, HidesKeyboard, HasDeviceTime, InteractsWithFiles, InteractsWithApps, HasAppStrings, FindsByClassName, FindsByCssSelector, FindsById, FindsByLinkText, FindsByName, FindsByTagName, FindsByXPath, FindsByFluentSelector, ExecutesMethod, HasSessionDetails { diff --git a/src/main/java/io/appium/java_client/MobileElement.java b/src/main/java/io/appium/java_client/MobileElement.java index 958c409ed..4cdb7e208 100644 --- a/src/main/java/io/appium/java_client/MobileElement.java +++ b/src/main/java/io/appium/java_client/MobileElement.java @@ -26,7 +26,7 @@ import java.util.List; @SuppressWarnings({"unchecked"}) -public abstract class MobileElement +public class MobileElement extends DefaultGenericMobileElement { protected FileDetector fileDetector; @@ -42,27 +42,41 @@ public Point getCenter() { upperLeft.getY() + dimensions.getHeight() / 2); } - @Override public void pinch() { - ((AppiumDriver) parent).pinch(this); + @Override public void tap(int fingers, int duration) { + MultiTouchAction tapMultiTouchAction = + new MultiTouchAction(PerformsTouchActions.class.cast(parent)); + tapMultiTouchAction.tap(fingers, this, duration).perform(); } - @Override public void tap(int fingers, int duration) { - ((AppiumDriver) parent).tap(fingers, this, duration); + @Override public void pinch() { + MultiTouchAction pinchMultiTouchAction = new MultiTouchAction( + PerformsTouchActions.class.cast(parent)); + pinchMultiTouchAction.pinch(this).perform(); } @Override public void zoom() { - ((AppiumDriver) parent).zoom(this); + MultiTouchAction zoomMultiTouchAction = new MultiTouchAction( + PerformsTouchActions.class.cast(parent)); + zoomMultiTouchAction.zoom(this).perform(); } - + @Deprecated + /** + * This method does nothing. It is going to be removed. + * Please use {@link CreatesSwipeAction#swipe(MobileElement, SwipeElementDirection, int)} instead. + */ @Override public void swipe(SwipeElementDirection direction, int duration) { - direction.swipe((AppiumDriver) parent, this, 0, 0, duration); + //does nothing } + @Deprecated + /** + * This method does nothing. It is going to be removed. + * Please use {@link CreatesSwipeAction#swipe(MobileElement, SwipeElementDirection, int, int, int)} instead. + */ @Override public void swipe(SwipeElementDirection direction, int offsetFromStartBorder, int offsetFromEndBorder, int duration) throws IllegalCoordinatesException { - direction.swipe((AppiumDriver) parent, this, offsetFromStartBorder, offsetFromEndBorder, - duration); + //does nothing } @Override public List findElements(By by) { diff --git a/src/main/java/io/appium/java_client/MultiTouchAction.java b/src/main/java/io/appium/java_client/MultiTouchAction.java index 7bde2a05d..c44160a37 100644 --- a/src/main/java/io/appium/java_client/MultiTouchAction.java +++ b/src/main/java/io/appium/java_client/MultiTouchAction.java @@ -20,30 +20,34 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import org.openqa.selenium.Dimension; +import org.openqa.selenium.Point; +import org.openqa.selenium.WebElement; + /** * Used for Webdriver 3 multi-touch gestures * See the Webriver 3 spec https://dvcs.w3.org/hg/webdriver/raw-file/default/webdriver-spec.html * The MultiTouchAction object is a collection of TouchAction objects * (remember that TouchAction objects are in turn, a chain of individual actions) * Add multiple TouchAction objects using the add() method. - * When perform() method is called, all actions are sent to the driver. - * The driver performs the first step of each TouchAction object simultaneously as a multi-touch + * When perform() method is called, all actions are sent to the performsTouchActions. + * The performsTouchActions performs the first step of each TouchAction object simultaneously as a multi-touch * "execution group". Conceptually, the number of TouchAction objects added to the MultiTouchAction * is equal to the number of "fingers" or other appendages or tools touching the screen at the - * same time as part of this multi-gesture. Then the driver performs the second step of each + * same time as part of this multi-gesture. Then the performsTouchActions performs the second step of each * TouchAction object and another "execution group", and the third, and so on. * Using a waitAction() action within a TouchAction takes up one of the slots in an * "execution group", so these can be used to sync up complex actions. * Calling perform() sends the action command to the Mobile Driver. Otherwise, more and * more actions can be chained. */ -@SuppressWarnings({"rawtypes", "unchecked"}) public class MultiTouchAction { +public class MultiTouchAction { - ImmutableList.Builder actions; - private MobileDriver driver; + private ImmutableList.Builder actions; + private PerformsTouchActions performsTouchActions; - public MultiTouchAction(MobileDriver driver) { - this.driver = driver; + public MultiTouchAction(PerformsTouchActions performsTouchActions) { + this.performsTouchActions = performsTouchActions; actions = ImmutableList.builder(); } @@ -55,20 +59,19 @@ public MultiTouchAction(MobileDriver driver) { */ public MultiTouchAction add(TouchAction action) { actions.add(action); - return this; } /** - * Perform the multi-touch action on the mobile driver. + * Perform the multi-touch action on the mobile performsTouchActions. */ public void perform() { int size = actions.build().size(); if (size > 1) { - driver.performMultiTouchAction(this); + performsTouchActions.performMultiTouchAction(this); } else if (size == 1) { //android doesn't like having multi-touch actions with only a single TouchAction... - driver.performTouchAction(actions.build().get(0)); + performsTouchActions.performTouchAction(actions.build().get(0)); } else { throw new MissingParameterException( "MultiTouch action must have at least one TouchAction " @@ -77,13 +80,143 @@ public void perform() { } - protected ImmutableMap getParameters() { + protected ImmutableMap> getParameters() { ImmutableList.Builder listOfActionChains = ImmutableList.builder(); ImmutableList touchActions = actions.build(); - for (TouchAction action : touchActions) { + touchActions.forEach(action -> { listOfActionChains.add(action.getParameters().get("actions")); - } + }); return ImmutableMap.of("actions", listOfActionChains.build()); } + + /** + * Creates few combined touch actions which performs the pinching on the given elements. + */ + public MultiTouchAction pinch(WebElement el) { + Dimension dimensions = el.getSize(); + Point upperLeft = el.getLocation(); + Point center = new Point(upperLeft.getX() + dimensions.getWidth() / 2, + upperLeft.getY() + dimensions.getHeight() / 2); + int yOffset = center.getY() - upperLeft.getY(); + + TouchAction action0 = + new TouchAction(performsTouchActions).press(el, center.getX(), center.getY() - yOffset).moveTo(el) + .release(); + TouchAction action1 = + new TouchAction(performsTouchActions).press(el, center.getX(), center.getY() + yOffset).moveTo(el) + .release(); + + this.add(action0).add(action1); + return this; + } + + /** + * Creates few combined touch actions which performs the pinching by given coordinates and offsets. + * @param x is a x-coordinate to perform the pinching to + * @param y is an y-coordinate to perform the pinching to + * @param xOffset is an +/- offset from the given x-coordinate to perform the pinching to + * @param yOffset is an +/- offset from the given y-coordinate to perform the pinching to + * @return the self-reference + */ + public MultiTouchAction pinch(int x, int y, int xOffset, int yOffset) { + TouchAction action0 = new TouchAction(performsTouchActions).press(x + xOffset, y - yOffset) + .moveTo(- xOffset, yOffset).release(); + TouchAction action1 = new TouchAction(performsTouchActions).press(x - xOffset, y + yOffset) + .moveTo(xOffset, -yOffset).release(); + + this.add(action0).add(action1); + return this; + } + + /** + * Creates few combined touch actions which performs the vertical pinching by given coordinates and y-Offset. + * @param x is a x-coordinate to perform the pinching to + * @param y is an y-coordinate to perform the pinching to + * @param yOffset is an +/- offset from the given y-coordinate to perform the pinching to + * @return the self-reference + */ + public MultiTouchAction pinch(int x, int y, int yOffset) { + return pinch(x, y, 0, yOffset); + } + + /** + * Creates few combined touch actions which performs the zooming on the given element. + */ + public MultiTouchAction zoom(WebElement el) { + Dimension dimensions = el.getSize(); + Point upperLeft = el.getLocation(); + Point center = new Point(upperLeft.getX() + dimensions.getWidth() / 2, + upperLeft.getY() + dimensions.getHeight() / 2); + int yOffset = center.getY() - upperLeft.getY(); + + TouchAction action0 = new TouchAction(performsTouchActions).press(center.getX(), center.getY()) + .moveTo(el, center.getX(), center.getY() - yOffset).release(); + TouchAction action1 = new TouchAction(performsTouchActions).press(center.getX(), center.getY()) + .moveTo(el, center.getX(), center.getY() + yOffset).release(); + + this.add(action0).add(action1); + return this; + } + + /** + * Creates few combined touch actions which performs the zooming by given coordinates and x/y-Offset value. + * @param x is a x-coordinate to perform the zooming from + * @param y is a y-coordinate to perform the zooming from + * @param xOffset is an +/- offset from the given x-coordinate to perform the zooming from + * @param yOffset is an +/- offset from the given y-coordinate to perform the zooming from + * @return the self-reference + */ + public MultiTouchAction zoom(int x, int y, int xOffset, int yOffset) { + TouchAction action0 = new TouchAction(performsTouchActions).press(x, y) + .moveTo(xOffset, -yOffset).release(); + TouchAction action1 = new TouchAction(performsTouchActions).press(x, y) + .moveTo(-xOffset, yOffset).release(); + + return this.add(action0).add(action1); + } + + /** + * Creates few combined touch actions which performs the vertical zooming by given coordinates and x/y-Offset value. + * @param x is a x-coordinate to perform the zooming from + * @param y is a y-coordinate to perform the zooming from + * @param yOffset is an +/- offset from the given y-coordinate to perform the zooming from + * @return the self-reference + */ + public MultiTouchAction zoom(int x, int y, int yOffset) { + return zoom(x, y, 0, yOffset); + } + + /** + * Creates the tapping by few finders using given coordinates. + * + * @param fingers is a count of fingers to tap + * @param x coordinate + * @param y coordinate + * @param duration is a time for the tapping in milliseconds + * @return the self-reference + */ + public MultiTouchAction tap(int fingers, int x, int y, int duration) { + for (int i = 0; i < fingers; i++) { + TouchAction tap = new TouchAction(performsTouchActions); + this.add(tap.press(x, y).waitAction(duration).release()); + } + return this; + } + + /** + * Creates the tapping by few finders on the element. + * + * @param fingers is a count of fingers to tap + * @param element to be tapped + * @param duration is a time for the tapping in milliseconds + * @return the self-reference + */ + public MultiTouchAction tap(int fingers, WebElement element, int duration) { + for (int i = 0; i < fingers; i++) { + TouchAction tap = new TouchAction(performsTouchActions); + this.add(tap.press(element).waitAction(duration).release()); + } + return this; + } } diff --git a/src/main/java/io/appium/java_client/PerformsTouchActions.java b/src/main/java/io/appium/java_client/PerformsTouchActions.java index 123811b2c..0a3056730 100644 --- a/src/main/java/io/appium/java_client/PerformsTouchActions.java +++ b/src/main/java/io/appium/java_client/PerformsTouchActions.java @@ -35,7 +35,7 @@ public interface PerformsTouchActions extends ExecutesMethod { * @return the same touch action object */ default TouchAction performTouchAction(TouchAction touchAction) { - ImmutableMap parameters = touchAction.getParameters(); + ImmutableMap> parameters = touchAction.getParameters(); execute(PERFORM_TOUCH_ACTION, parameters); return touchAction; } @@ -50,7 +50,7 @@ default TouchAction performTouchAction(TouchAction touchAction) { * @param multiAction the MultiTouchAction object to perform. */ default void performMultiTouchAction(MultiTouchAction multiAction) { - ImmutableMap parameters = multiAction.getParameters(); + ImmutableMap> parameters = multiAction.getParameters(); execute(PERFORM_MULTI_TOUCH, parameters); } } diff --git a/src/main/java/io/appium/java_client/PressesKeyCode.java b/src/main/java/io/appium/java_client/PressesKeyCode.java new file mode 100644 index 000000000..4ad06f104 --- /dev/null +++ b/src/main/java/io/appium/java_client/PressesKeyCode.java @@ -0,0 +1,63 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.appium.java_client; + +import static io.appium.java_client.MobileCommand.longPressKeyCodeCommand; +import static io.appium.java_client.MobileCommand.pressKeyCodeCommand; + +public interface PressesKeyCode extends ExecutesMethod { + + /** + * Send a key event to the device. + * + * @param key code for the key pressed on the device. + */ + default void pressKeyCode(int key) { + CommandExecutionHelper.execute(this, pressKeyCodeCommand(key)); + } + + /** + * Send a key event along with an Android metastate to an Android device. + * Metastates are things like *shift* to get uppercase characters. + * + * @param key code for the key pressed on the Android device. + * @param metastate metastate for the keypress. + */ + default void pressKeyCode(int key, Integer metastate) { + CommandExecutionHelper.execute(this, pressKeyCodeCommand(key, metastate)); + } + + /** + * Send a long key event to the device. + * + * @param key code for the key pressed on the device. + */ + default void longPressKeyCode(int key) { + CommandExecutionHelper.execute(this, longPressKeyCodeCommand(key)); + } + + /** + * Send a long key event along with an Android metastate to an Android device. + * Metastates are things like *shift* to get uppercase characters. + * + * @param key code for the key pressed on the Android device. + * @param metastate metastate for the keypress. + */ + default void longPressKeyCode(int key, Integer metastate) { + CommandExecutionHelper.execute(this, longPressKeyCodeCommand(key, metastate)); + } +} diff --git a/src/main/java/io/appium/java_client/SwipeElementDirection.java b/src/main/java/io/appium/java_client/SwipeElementDirection.java index add3c29ed..15cd87a7e 100644 --- a/src/main/java/io/appium/java_client/SwipeElementDirection.java +++ b/src/main/java/io/appium/java_client/SwipeElementDirection.java @@ -16,6 +16,7 @@ package io.appium.java_client; +import org.aspectj.lang.annotation.SuppressAjWarnings; import org.openqa.selenium.Dimension; import org.openqa.selenium.Point; @@ -142,6 +143,7 @@ public enum SwipeElementDirection { } }; + @SuppressAjWarnings("unused") static void checkYCoordinate(int y, Point location, Dimension size, int offSet) throws IllegalCoordinatesException { int bottom = location.getY() + size.getHeight(); @@ -157,6 +159,7 @@ static void checkYCoordinate(int y, Point location, Dimension size, int offSet) } + @SuppressAjWarnings("unused") static void checkXCoordinate(int x, Point location, Dimension size, int offSet) throws IllegalCoordinatesException { int right = location.getX() + size.getWidth(); @@ -182,7 +185,18 @@ static void checkXCoordinate(int x, Point location, Dimension size, int offSet) abstract void checkDirection(int x1, int y1, int x2, int y2); - void swipe(AppiumDriver driver, MobileElement element, int offset1, int offset2, + /** + * Creates the swiping action. It is supposed to be performed inside the given element. + * + * @param createsSwipeAction an instance that implements {@link CreatesSwipeAction} + * @param element the element that is going to be swiped + * @param offset1 from the first (starting) element board + * @param offset2 from the ending element board + * @param duration in milliseconds + * @return an instance of {@link TouchAction} + * @throws IllegalCoordinatesException when starting/ending coordinates are outside of the given element + */ + public TouchAction swipe(CreatesSwipeAction createsSwipeAction, MobileElement element, int offset1, int offset2, int duration) throws IllegalCoordinatesException { Point p = element.getCenter(); Point location = element.getLocation(); @@ -193,6 +207,6 @@ void swipe(AppiumDriver driver, MobileElement element, int offset1, int offse int endY = getEndY(p, location, size, offset2); checkDirection(startX, startY, endX, endY); - driver.swipe(startX, startY, endX, endY, duration); + return createsSwipeAction.swipe(startX, startY, endX, endY, duration); } } diff --git a/src/main/java/io/appium/java_client/TouchAction.java b/src/main/java/io/appium/java_client/TouchAction.java index 3d1ba66a2..9666f9204 100644 --- a/src/main/java/io/appium/java_client/TouchAction.java +++ b/src/main/java/io/appium/java_client/TouchAction.java @@ -22,24 +22,23 @@ import org.openqa.selenium.WebElement; import org.openqa.selenium.internal.HasIdentity; - /** * Used for Webdriver 3 touch actions * See the Webriver 3 spec * https://dvcs.w3.org/hg/webdriver/raw-file/default/webdriver-spec.html * The flow is to chain individual touch actions into an entire gesture. e.g. - * TouchAction action = new TouchAction(driver); + * TouchAction action = new TouchAction(performsTouchActions); * action.press(element).waitAction(300).moveTo(element1).release().perform(); * Calling perform() sends the action command to the Mobile Driver. Otherwise, * more and more actions can be chained. */ -@SuppressWarnings({"rawtypes", "unchecked"}) public class TouchAction { +public class TouchAction { - ImmutableList.Builder parameterBuilder; - private MobileDriver driver; + private ImmutableList.Builder parameterBuilder; + private PerformsTouchActions performsTouchActions; - public TouchAction(MobileDriver driver) { - this.driver = driver; + public TouchAction(PerformsTouchActions performsTouchActions) { + this.performsTouchActions = performsTouchActions; parameterBuilder = ImmutableList.builder(); } @@ -306,7 +305,7 @@ public TouchAction longPress(WebElement el, int x, int y, int duration) { } /** - * Cancel this action, if it was partially completed by the driver. + * Cancel this action, if it was partially completed by the performsTouchActions. */ public void cancel() { ActionParameter action = new ActionParameter("wait"); @@ -315,12 +314,12 @@ public void cancel() { } /** - * Perform this chain of actions on the driver. + * Perform this chain of actions on the performsTouchActions. * * @return this TouchAction, for possible segmented-touches. */ public TouchAction perform() { - driver.performTouchAction(this); + performsTouchActions.performTouchAction(this); return this; } @@ -329,13 +328,12 @@ public TouchAction perform() { * * @return A map of parameters for this touch action to pass as part of mjsonwp. */ - protected ImmutableMap getParameters() { + protected ImmutableMap> getParameters() { - ImmutableList.Builder parameters = ImmutableList.builder(); + ImmutableList.Builder parameters = ImmutableList.builder(); ImmutableList actionList = parameterBuilder.build(); - for (ActionParameter action : actionList) { - parameters.add(action.getParameterMap()); - } + + actionList.forEach(action -> parameters.add(action.getParameterMap())); return ImmutableMap.of("actions", parameters.build()); } @@ -346,9 +344,9 @@ protected void clearParameters() { /** * Just holds values to eventually return the parameters required for the mjsonwp. */ - private class ActionParameter { + protected class ActionParameter { private String actionName; - private ImmutableMap.Builder optionsBuilder; + private ImmutableMap.Builder optionsBuilder; public ActionParameter(String actionName) { this.actionName = actionName; @@ -362,7 +360,7 @@ public ActionParameter(String actionName, HasIdentity el) { } public ImmutableMap getParameterMap() { - ImmutableMap.Builder builder = ImmutableMap.builder(); + ImmutableMap.Builder builder = ImmutableMap.builder(); builder.put("action", actionName).put("options", optionsBuilder.build()); return builder.build(); } diff --git a/src/main/java/io/appium/java_client/TouchShortcuts.java b/src/main/java/io/appium/java_client/TouchShortcuts.java deleted file mode 100644 index ab8625ef2..000000000 --- a/src/main/java/io/appium/java_client/TouchShortcuts.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * See the NOTICE file distributed with this work for additional - * information regarding copyright ownership. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.appium.java_client; - -import org.openqa.selenium.WebElement; - -public interface TouchShortcuts { - - /** - * Convenience method for "zooming in" on an element on the screen. - * "zooming in" refers to the action of two appendages pressing the - * screen and sliding away from each other. - * NOTE: - * This convenience method slides touches away from the element, - * if this would happen to place one of them off the screen, appium will return an - * outOfBounds error. In this case, revert to using the MultiTouchAction api - * instead of this method. - * - * @param x x coordinate to start zoom on. - * @param y y coordinate to start zoom on. - */ - void zoom(int x, int y); - - /** - * Convenience method for "zooming in" on an element on the screen. - * "zooming in" refers to the action of two appendages pressing the screen - * and sliding away from each other. - * NOTE: - * This convenience method slides touches away from the element, if this would - * happen to place one of them off the screen, appium will return an outOfBounds - * error. In this case, revert to using the MultiTouchAction api - * instead of this method. - * - * @param el The element to pinch. - */ - void zoom(WebElement el); - - /** - * Convenience method for tapping a position on the screen. - * - * @param fingers number of fingers/appendages to tap with. - * @param x x coordinate. - * @param y y coordinate. - * @param duration how long between pressing down, and lifting fingers/appendages. - */ - void tap(int fingers, int x, int y, int duration); - - /** - * Convenience method for tapping the center of an element on the screen. - * - * @param fingers number of fingers/appendages to tap with. - * @param element element to tap. - * @param duration how long between pressing down, and lifting fingers/appendages. - */ - void tap(int fingers, WebElement element, int duration); - - /** - * Convenience method for swiping across the screen. - * - * @param startx starting x coordinate. - * @param starty starting y coordinate. - * @param endx ending x coordinate. - * @param endy ending y coordinate. - * @param duration amount of time in milliseconds for the entire swipe action to take - */ - void swipe(int startx, int starty, int endx, int endy, int duration); - - /** - * Convenience method for pinching an element on the screen. - * "pinching" refers to the action of two appendages pressing the screen - * and sliding towards each other. - * NOTE: - * This convenience method places the initial touches around the element at a distance, - * if this would happen to place one of them off the screen, appium will return an - * outOfBounds error. In this case, revert to using the MultiTouchAction api - * instead of this method. - * - * @param x x coordinate to terminate the pinch on. - * @param y y coordinate to terminate the pinch on. - */ - void pinch(int x, int y); - - /** - * Convenience method for pinching an element on the screen. - * "pinching" refers to the action of two appendages pressing the screen and - * sliding towards each other. - * NOTE: - * This convenience method places the initial touches around the element, if this would - * happen to place one of them off the screen, appium with return an outOfBounds error. - * In this case, revert to using the MultiTouchAction api instead of this method. - * - * @param el The element to pinch. - */ - void pinch(WebElement el); - -} diff --git a/src/main/java/io/appium/java_client/TouchableElement.java b/src/main/java/io/appium/java_client/TouchableElement.java index bba550448..07b2e0add 100644 --- a/src/main/java/io/appium/java_client/TouchableElement.java +++ b/src/main/java/io/appium/java_client/TouchableElement.java @@ -104,40 +104,22 @@ public interface TouchableElement extends WebElement, Find */ void zoom(); + + @Deprecated /** - * Convenience method for swiping on the given element to the given direction. - * - * @param direction UP, DOWN, LEFT, RIGHT. - * @param duration amount of time in milliseconds for the entire swipe action to - * take. + * This method is deprecated and it is going to be removed. + * Please use the {@link CreatesSwipeAction#swipe(WebElement, SwipeElementDirection, int)} + * instead. */ void swipe(SwipeElementDirection direction, int duration); + @Deprecated /** - * Convenience method for swiping on the given element to the given direction. - * - * @param direction direction UP, DOWN, LEFT, RIGHT. - * @param offsetFromStartBorder is the offset from the border of the element where the - * swiping should be started. If direction is UP then - * this is offset from the bottom of the element. - * If direction is DOWN then this is offset from the top of - * the element. If direction is RIGHT then this is offset from - * the left border of the element. If direction is LEFT then - * this is offset from the right border of the element. - * @param offsetFromEndBorder is the offset from the border of the element where - * the swiping should be finished. If direction is UP then - * this is offset from the top of the element. - * If direction is DOWN then this is offset from the bottom - * of the element. If direction is RIGHT then - * this is offset from the right border of the element. - * If direction is LEFT then this is offset from the - * left border of the element. - * @param duration amount of time in milliseconds for the entire swipe action to - * take. - * @throws IllegalCoordinatesException when resulted coordinates are out of the - * element borders or disagree with the given direction. + * This method is deprecated and it is going to be removed. + * Please use the {@link CreatesSwipeAction#swipe(WebElement, SwipeElementDirection, int, int, int)} + * instead. */ void swipe(SwipeElementDirection direction, int offsetFromStartBorder, int offsetFromEndBorder, - int duration) throws IllegalCoordinatesException; -} + int duration) throws IllegalCoordinatesException; +} \ No newline at end of file diff --git a/src/main/java/io/appium/java_client/android/AndroidDeviceActionShortcuts.java b/src/main/java/io/appium/java_client/android/AndroidDeviceActionShortcuts.java index 16b13c264..4fa8eb101 100644 --- a/src/main/java/io/appium/java_client/android/AndroidDeviceActionShortcuts.java +++ b/src/main/java/io/appium/java_client/android/AndroidDeviceActionShortcuts.java @@ -22,6 +22,11 @@ import io.appium.java_client.CommandExecutionHelper; import io.appium.java_client.DeviceActionShortcuts; +@Deprecated +/** + * This interface is deprecated and won't be supported anymore. + * Please use {@link io.appium.java_client.PressesKeyCode} API instead + */ public interface AndroidDeviceActionShortcuts extends DeviceActionShortcuts { /** diff --git a/src/main/java/io/appium/java_client/android/AndroidDriver.java b/src/main/java/io/appium/java_client/android/AndroidDriver.java index 7b92a2b81..2ccae1c34 100644 --- a/src/main/java/io/appium/java_client/android/AndroidDriver.java +++ b/src/main/java/io/appium/java_client/android/AndroidDriver.java @@ -23,6 +23,7 @@ import io.appium.java_client.AppiumDriver; import io.appium.java_client.CommandExecutionHelper; import io.appium.java_client.FindsByAndroidUIAutomator; +import io.appium.java_client.PressesKeyCode; import io.appium.java_client.android.internal.JsonToAndroidElementConverter; import io.appium.java_client.remote.MobilePlatform; import io.appium.java_client.service.local.AppiumDriverLocalService; @@ -46,7 +47,7 @@ */ public class AndroidDriver extends AppiumDriver - implements AndroidDeviceActionShortcuts, HasNetworkConnection, PushesFiles, StartsActivity, + implements PressesKeyCode, HasNetworkConnection, PushesFiles, StartsActivity, FindsByAndroidUIAutomator, LocksAndroidDevice, HasSettings { private static final String ANDROID_PLATFORM = MobilePlatform.ANDROID; @@ -160,11 +161,11 @@ public AndroidDriver(Capabilities desiredCapabilities) { JsonToAndroidElementConverter.class); } - /** - * @see io.appium.java_client.TouchShortcuts#swipe(int, int, int, int, int) - */ + @Override public void swipe(int startx, int starty, int endx, int endy, int duration) { - doSwipe(startx, starty, endx, endy, duration); + AndroidTouchAction touchaction = new AndroidTouchAction(this); + + touchaction.swipe(startx, starty, endx, endy, duration).perform(); } /** diff --git a/src/main/java/io/appium/java_client/android/AndroidMobileCommandHelper.java b/src/main/java/io/appium/java_client/android/AndroidMobileCommandHelper.java index ff7362857..450965707 100644 --- a/src/main/java/io/appium/java_client/android/AndroidMobileCommandHelper.java +++ b/src/main/java/io/appium/java_client/android/AndroidMobileCommandHelper.java @@ -87,28 +87,20 @@ public class AndroidMobileCommandHelper extends MobileCommand { IS_LOCKED, ImmutableMap.of()); } + /** - * This method forms a {@link java.util.Map} of parameters for the - * key event invocation. - * - * @param key code for the key pressed on the device. - * @return a key-value pair. The key is the command name. The value is a - * {@link java.util.Map} command arguments. + * It is deprecated. Please use {@link MobileCommand#pressKeyCodeCommand(int)} instead. */ + @Deprecated public static Map.Entry> pressKeyCodeCommand(int key) { return new AbstractMap.SimpleEntry<>( PRESS_KEY_CODE, prepareArguments("keycode", key)); } /** - * This method forms a {@link java.util.Map} of parameters for the - * key event invocation. - * - * @param key code for the key pressed on the Android device. - * @param metastate metastate for the keypress. - * @return a key-value pair. The key is the command name. The value is a - * {@link java.util.Map} command arguments. + * It is deprecated. Please use {@link MobileCommand#pressKeyCodeCommand(int, Integer)} instead. */ + @Deprecated public static Map.Entry> pressKeyCodeCommand(int key, Integer metastate) { String[] parameters = new String[] {"keycode", "metastate"}; @@ -118,27 +110,18 @@ public class AndroidMobileCommandHelper extends MobileCommand { } /** - * This method forms a {@link java.util.Map} of parameters for the - * long key event invocation. - * - * @param key code for the long key pressed on the device. - * @return a key-value pair. The key is the command name. The value is a - * {@link java.util.Map} command arguments. + * It is deprecated. Please use {@link MobileCommand#longPressKeyCodeCommand(int)} instead. */ + @Deprecated public static Map.Entry> longPressKeyCodeCommand(int key) { return new AbstractMap.SimpleEntry<>( LONG_PRESS_KEY_CODE, prepareArguments("keycode", key)); } /** - * This method forms a {@link java.util.Map} of parameters for the - * long key event invocation. - * - * @param key code for the long key pressed on the Android device. - * @param metastate metastate for the long key press. - * @return a key-value pair. The key is the command name. The value is a - * {@link java.util.Map} command arguments. + * It is deprecated. Please use {@link MobileCommand#longPressKeyCodeCommand(int, Integer)} instead. */ + @Deprecated public static Map.Entry> longPressKeyCodeCommand(int key, Integer metastate) { String[] parameters = new String[] {"keycode", "metastate"}; diff --git a/src/main/java/io/appium/java_client/android/AndroidTouchAction.java b/src/main/java/io/appium/java_client/android/AndroidTouchAction.java new file mode 100644 index 000000000..6ece07766 --- /dev/null +++ b/src/main/java/io/appium/java_client/android/AndroidTouchAction.java @@ -0,0 +1,28 @@ +package io.appium.java_client.android; + +import io.appium.java_client.CreatesSwipeAction; +import io.appium.java_client.PerformsTouchActions; +import io.appium.java_client.TouchAction; +import org.openqa.selenium.WebElement; + +public class AndroidTouchAction extends TouchAction implements CreatesSwipeAction { + + public AndroidTouchAction(PerformsTouchActions performsTouchActions) { + super(performsTouchActions); + } + + @Override + public TouchAction swipe(int startX, int startY, int endx, int endy, int duration) { + return press(startX, startY).waitAction(duration).moveTo(endx, endy).release(); + } + + @Override + public TouchAction swipe(int startX, int startY, WebElement element, int duration) { + return press(startX, startY).waitAction(duration).moveTo(element).release(); + } + + @Override + public TouchAction swipe(WebElement element1, WebElement element2, int duration) { + return press(element1).waitAction(duration).moveTo(element2).release(); + } +} diff --git a/src/main/java/io/appium/java_client/ios/IOSDeviceActionShortcuts.java b/src/main/java/io/appium/java_client/ios/IOSDeviceActionShortcuts.java index 190fcc6a4..122b25f14 100644 --- a/src/main/java/io/appium/java_client/ios/IOSDeviceActionShortcuts.java +++ b/src/main/java/io/appium/java_client/ios/IOSDeviceActionShortcuts.java @@ -22,6 +22,11 @@ import io.appium.java_client.CommandExecutionHelper; import io.appium.java_client.DeviceActionShortcuts; +@Deprecated +/** + * This interface is deprecated and won't be supported anymore. + * Please use {@link io.appium.java_client.HidesKeyboardWithKeyName} and {@link ShakesDevice} API instead. + */ public interface IOSDeviceActionShortcuts extends DeviceActionShortcuts { /** diff --git a/src/main/java/io/appium/java_client/ios/IOSDriver.java b/src/main/java/io/appium/java_client/ios/IOSDriver.java index 4fe0a2683..3e606de84 100644 --- a/src/main/java/io/appium/java_client/ios/IOSDriver.java +++ b/src/main/java/io/appium/java_client/ios/IOSDriver.java @@ -20,6 +20,7 @@ import io.appium.java_client.AppiumDriver; import io.appium.java_client.FindsByIosUIAutomation; +import io.appium.java_client.HidesKeyboardWithKeyName; import io.appium.java_client.ios.internal.JsonToIOSElementConverter; import io.appium.java_client.remote.MobilePlatform; import io.appium.java_client.service.local.AppiumDriverLocalService; @@ -49,7 +50,7 @@ */ public class IOSDriver extends AppiumDriver - implements IOSDeviceActionShortcuts, + implements HidesKeyboardWithKeyName, ShakesDevice, FindsByIosUIAutomation, LocksIOSDevice, PerformsTouchID { private static final String IOS_PLATFORM = MobilePlatform.IOS; @@ -164,10 +165,12 @@ public IOSDriver(Capabilities desiredCapabilities) { } /** - * @see io.appium.java_client.TouchShortcuts#swipe(int, int, int, int, int). + * @see io.appium.java_client.CreatesSwipeAction#swipe(int, int, int, int, int). */ @Override public void swipe(int startx, int starty, int endx, int endy, int duration) { - doSwipe(startx, starty, endx - startx, endy - starty, duration); + IOSTouchAction touchaction = new IOSTouchAction(this); + + touchaction.swipe(startx, starty, endx, endy, duration).perform(); } @Override public TargetLocator switchTo() { diff --git a/src/main/java/io/appium/java_client/ios/IOSTouchAction.java b/src/main/java/io/appium/java_client/ios/IOSTouchAction.java new file mode 100644 index 000000000..e11292734 --- /dev/null +++ b/src/main/java/io/appium/java_client/ios/IOSTouchAction.java @@ -0,0 +1,31 @@ +package io.appium.java_client.ios; + +import io.appium.java_client.CreatesSwipeAction; +import io.appium.java_client.PerformsTouchActions; +import io.appium.java_client.TouchAction; +import org.openqa.selenium.WebElement; + + +public class IOSTouchAction extends TouchAction implements CreatesSwipeAction { + + public IOSTouchAction(PerformsTouchActions performsTouchActions) { + super(performsTouchActions); + } + + @Override + public TouchAction swipe(int startX, int startY, int endX, int endY, int duration) { + int xOffset = endX - startX; + int yOffset = endY - startY; + return press(startX, startY).waitAction(duration).moveTo(xOffset, yOffset).release(); + } + + @Override + public TouchAction swipe(int startX, int startY, WebElement element, int duration) { + return press(startX, startY).waitAction(duration).moveTo(element).release(); + } + + @Override + public TouchAction swipe(WebElement element1, WebElement element2, int duration) { + return press(element1).waitAction(duration).moveTo(element2).release(); + } +} diff --git a/src/main/java/io/appium/java_client/ios/ShakesDevice.java b/src/main/java/io/appium/java_client/ios/ShakesDevice.java new file mode 100644 index 000000000..208f05bb1 --- /dev/null +++ b/src/main/java/io/appium/java_client/ios/ShakesDevice.java @@ -0,0 +1,32 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.appium.java_client.ios; + +import static io.appium.java_client.ios.IOSMobileCommandHelper.shakeCommand; + +import io.appium.java_client.CommandExecutionHelper; +import io.appium.java_client.ExecutesMethod; + +public interface ShakesDevice extends ExecutesMethod { + + /** + * Simulate shaking the device. + */ + default void shake() { + CommandExecutionHelper.execute(this, shakeCommand()); + } +} diff --git a/src/main/java/io/appium/java_client/pagefactory/bys/builder/AppiumByBuilder.java b/src/main/java/io/appium/java_client/pagefactory/bys/builder/AppiumByBuilder.java index 1b9aa7a59..2f6d8e746 100644 --- a/src/main/java/io/appium/java_client/pagefactory/bys/builder/AppiumByBuilder.java +++ b/src/main/java/io/appium/java_client/pagefactory/bys/builder/AppiumByBuilder.java @@ -119,7 +119,6 @@ private static By getMobileBy(Annotation annotation, String valueName) { + valueName); } - @SuppressWarnings("unchecked") private static T getComplexMobileBy(Annotation[] annotations, Class requiredByClass) { By[] byArray = new By[annotations.length]; @@ -127,9 +126,9 @@ private static T getComplexMobileBy(Annotation[] annotations, byArray[i] = getMobileBy(annotations[i], getFilledValue(annotations[i])); } try { - Constructor c = requiredByClass.getConstructor(By[].class); + Constructor c = requiredByClass.getConstructor(By[].class); Object[] values = new Object[] {byArray}; - return (T) c.newInstance(values); + return c.newInstance(values); } catch (Exception e) { throw new RuntimeException(e); } diff --git a/src/main/java/io/appium/java_client/service/local/AppiumServiceBuilder.java b/src/main/java/io/appium/java_client/service/local/AppiumServiceBuilder.java index fb51b497d..c168907d2 100644 --- a/src/main/java/io/appium/java_client/service/local/AppiumServiceBuilder.java +++ b/src/main/java/io/appium/java_client/service/local/AppiumServiceBuilder.java @@ -372,8 +372,7 @@ private String parseCapabilitiesIfUNIX() { return "{" + result + "}"; } - - @SuppressWarnings("unchecked") + private String parseCapabilities() { if (Platform.getCurrent().is(Platform.WINDOWS)) { return parseCapabilitiesIfWindows(); diff --git a/src/test/java/io/appium/java_client/android/AndroidGestureTest.java b/src/test/java/io/appium/java_client/android/AndroidGestureTest.java index 69f7ffcba..ce393fd55 100644 --- a/src/test/java/io/appium/java_client/android/AndroidGestureTest.java +++ b/src/test/java/io/appium/java_client/android/AndroidGestureTest.java @@ -22,7 +22,6 @@ import io.appium.java_client.MobileBy; import io.appium.java_client.MobileElement; import io.appium.java_client.MultiTouchAction; -import io.appium.java_client.SwipeElementDirection; import io.appium.java_client.TouchAction; import org.junit.Test; import org.openqa.selenium.By; @@ -35,14 +34,15 @@ public class AndroidGestureTest extends BaseAndroidTest { driver.startActivity("io.appium.android.apis", ".view.Buttons1"); Point point = driver.findElementById("io.appium.android.apis:id/button_toggle").getLocation(); - driver.tap(1, point.x + 20, point.y + 30, 1000); + new MultiTouchAction(driver).tap(1, point.x + 20, point.y + 30, 1000).perform(); assertEquals("ON" ,driver .findElementById("io.appium.android.apis:id/button_toggle").getText()); } @Test public void singleElementTapTest() throws Exception { driver.startActivity("io.appium.android.apis", ".view.Buttons1"); - driver.tap(1, driver.findElementById("io.appium.android.apis:id/button_toggle"), 1000); + new MultiTouchAction(driver).tap(1, driver.findElementById("io.appium.android.apis:id/button_toggle"), 1000) + .perform(); assertEquals("ON" ,driver .findElementById("io.appium.android.apis:id/button_toggle").getText()); } @@ -107,34 +107,4 @@ public class AndroidGestureTest extends BaseAndroidTest { assertEquals("OFF" ,driver .findElementById("io.appium.android.apis:id/button_toggle").getText()); } - - @Test public void verticalSwipingTest() throws Exception { - driver.findElementByAccessibilityId("Views").click(); - AndroidElement listView = driver.findElementByClassName("android.widget.ListView"); - MobileElement textView = driver.findElementById("android:id/text1"); - - String originalText = textView.getText(); - - listView.swipe(SwipeElementDirection.UP, 20, 15, 1000); - assertNotEquals(originalText, textView.getText()); - - listView.swipe(SwipeElementDirection.DOWN, 20, 15, 1000); - assertEquals(originalText, textView.getText()); - } - - @Test public void horizontalSwipingTest() throws Exception { - driver.startActivity("io.appium.android.apis", ".view.Gallery1"); - - AndroidElement gallery = driver.findElementById("io.appium.android.apis:id/gallery"); - int originalImageCount = gallery - .findElementsByClassName("android.widget.ImageView").size(); - - gallery.swipe(SwipeElementDirection.LEFT, 5, 5, 2000); - assertNotEquals(originalImageCount, gallery - .findElementsByClassName("android.widget.ImageView").size()); - - gallery.swipe(SwipeElementDirection.RIGHT, 5, 5, 2000); - assertEquals(originalImageCount, gallery - .findElementsByClassName("android.widget.ImageView").size()); - } } diff --git a/src/test/java/io/appium/java_client/android/AndroidSwipeGestureTest.java b/src/test/java/io/appium/java_client/android/AndroidSwipeGestureTest.java new file mode 100644 index 000000000..e5dbc34c9 --- /dev/null +++ b/src/test/java/io/appium/java_client/android/AndroidSwipeGestureTest.java @@ -0,0 +1,99 @@ +package io.appium.java_client.android; + +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertThat; + +import io.appium.java_client.MobileElement; +import io.appium.java_client.SwipeElementDirection; +import org.junit.Before; +import org.junit.Test; +import org.openqa.selenium.Point; + +public class AndroidSwipeGestureTest extends BaseAndroidTest { + + @Before + public void setUp() throws Exception { + driver.resetApp(); + } + + @Test + public void verticalSwipingTest() throws Exception { + driver.findElementByAccessibilityId("Views").click(); + AndroidElement listView = driver.findElementByClassName("android.widget.ListView"); + MobileElement textView = driver.findElementById("android:id/text1"); + + String originalText = textView.getText(); + + AndroidTouchAction touchAction = new AndroidTouchAction(driver); + touchAction.swipe(listView, SwipeElementDirection.UP, 20, 15, 1000).perform(); + assertNotEquals(originalText, textView.getText()); + + AndroidTouchAction touchAction2 = new AndroidTouchAction(driver); + touchAction2.swipe(listView, SwipeElementDirection.DOWN, 20, 15, 1000).perform(); + + Thread.sleep(5000); + assertEquals(originalText, textView.getText()); + } + + @Test public void horizontalSwipingTest() throws Exception { + driver.startActivity("io.appium.android.apis", ".view.Gallery1"); + + AndroidElement gallery = driver.findElementById("io.appium.android.apis:id/gallery"); + int originalImageCount = gallery + .findElementsByClassName("android.widget.ImageView").size(); + + AndroidTouchAction touchAction = new AndroidTouchAction(driver); + touchAction.swipe(gallery, SwipeElementDirection.LEFT, 5, 5, 2000).perform(); + assertNotEquals(originalImageCount, gallery + .findElementsByClassName("android.widget.ImageView").size()); + + AndroidTouchAction touchAction2 = new AndroidTouchAction(driver); + touchAction2.swipe(gallery, SwipeElementDirection.RIGHT, 5, 5, 2000).perform(); + assertEquals(originalImageCount, gallery + .findElementsByClassName("android.widget.ImageView").size()); + } + + @Test public void swipeFromElementToElement() { + driver.findElementByAccessibilityId("Views").click(); + + AndroidElement e1 = driver.findElementByAccessibilityId("Chronometer"); + AndroidElement e2 = driver.findElementByAccessibilityId("Focus"); + + Point originalLocation = e2.getLocation(); + AndroidTouchAction touchAction = new AndroidTouchAction(driver); + touchAction.swipe(e2, e1, 2000).perform(); + + Point newLocation = e2.getLocation(); + assertNotEquals(originalLocation, newLocation); + } + + @Test public void swipeFromCoordinatesToElement() { + driver.findElementByAccessibilityId("Views").click(); + + AndroidElement e1 = driver.findElementByAccessibilityId("Chronometer"); + AndroidElement e2 = driver.findElementByAccessibilityId("Focus"); + + Point originalLocation = e2.getLocation(); + AndroidTouchAction touchAction = new AndroidTouchAction(driver); + touchAction.swipe(originalLocation.x + 50, originalLocation.y, e1, 2000).perform(); + + Point newLocation = e2.getLocation(); + assertNotEquals(originalLocation, newLocation); + } + + @Test public void whenSwipingIsCombinedWithOtherActions() { + driver.findElementByAccessibilityId("Views").click(); + + AndroidElement chronometer = driver.findElementByAccessibilityId("Chronometer"); + AndroidElement focus = driver.findElementByAccessibilityId("Focus"); + + AndroidTouchAction touchAction = new AndroidTouchAction(driver); + touchAction.swipe(focus, chronometer, 2000) + .tap(driver.findElementByAccessibilityId("Gallery")).perform(); + + assertThat(driver.findElementsByClassName("android.widget.TextView").size(), is(3)); + } + +} diff --git a/src/test/java/io/appium/java_client/ios/IOSElementTest.java b/src/test/java/io/appium/java_client/ios/IOSElementTest.java index fc465395a..5eaf52a0b 100644 --- a/src/test/java/io/appium/java_client/ios/IOSElementTest.java +++ b/src/test/java/io/appium/java_client/ios/IOSElementTest.java @@ -34,7 +34,7 @@ public class IOSElementTest extends BaseIOSTest { .findElementByIosUIAutomation(".elements().withName(\"Answer\")").getText(), null); } - @Test public void setValueNunslaughterTest() { + @Test public void setValuerTest() { IOSElement slider = (IOSElement) driver.findElementByClassName("UIASlider"); slider.setValue("0%"); assertEquals("0%", slider.getAttribute("value")); diff --git a/src/test/java/io/appium/java_client/ios/IOSGesturesTest.java b/src/test/java/io/appium/java_client/ios/IOSGesturesTest.java index 7de46cfff..39b8fa1bd 100644 --- a/src/test/java/io/appium/java_client/ios/IOSGesturesTest.java +++ b/src/test/java/io/appium/java_client/ios/IOSGesturesTest.java @@ -19,37 +19,28 @@ import static org.junit.Assert.assertEquals; import io.appium.java_client.MobileElement; -import io.appium.java_client.SwipeElementDirection; +import io.appium.java_client.MultiTouchAction; import org.junit.Test; public class IOSGesturesTest extends BaseIOSTest { - @Test public void tapTest() { driver.findElementById("IntegerA").sendKeys("2"); driver.findElementById("IntegerB").sendKeys("4"); MobileElement e = driver.findElementByAccessibilityId("ComputeSumButton"); - driver.tap(2, e, 2000); + new MultiTouchAction(driver).tap(2, e, 2000).perform(); assertEquals(driver.findElementByXPath("//*[@name = \"Answer\"]").getText(), "6"); } @Test public void zoomTest() { MobileElement e = driver.findElementById("IntegerA"); - driver.zoom(e); + new MultiTouchAction(driver).zoom(e).perform(); } @Test public void pinchTest() { MobileElement e = driver.findElementById("IntegerA"); - driver.pinch(e); - } - - @Test public void horizontalSwipingTest() { - MobileElement slider = driver.findElementByClassName("UIASlider"); - slider.swipe(SwipeElementDirection.LEFT, slider.getSize().getWidth() / 2, 0, 3000); - assertEquals("1%", slider.getAttribute("value")); - slider.swipe(SwipeElementDirection.RIGHT, 2, 0, 3000); - assertEquals("100%", slider.getAttribute("value")); + new MultiTouchAction(driver).pinch(e).perform(); } } diff --git a/src/test/java/io/appium/java_client/ios/IOSScrollingSearchingTest.java b/src/test/java/io/appium/java_client/ios/IOSScrollingSearchingTest.java index 05824852f..0e55343b9 100644 --- a/src/test/java/io/appium/java_client/ios/IOSScrollingSearchingTest.java +++ b/src/test/java/io/appium/java_client/ios/IOSScrollingSearchingTest.java @@ -23,6 +23,7 @@ import io.appium.java_client.remote.IOSMobileCapabilityType; import io.appium.java_client.remote.MobileCapabilityType; import io.appium.java_client.service.local.AppiumDriverLocalService; +import io.appium.java_client.service.local.AppiumServerHasNotBeenStartedLocallyException; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; @@ -41,7 +42,8 @@ public static void beforeClass() throws Exception { service.start(); if (service == null || !service.isRunning()) { - throw new RuntimeException("An appium server node is not started!"); + throw new AppiumServerHasNotBeenStartedLocallyException( + "An appium server node is not started!"); } File appDir = new File("src/test/java/io/appium/java_client"); diff --git a/src/test/java/io/appium/java_client/ios/IOSSwipeGestureTest.java b/src/test/java/io/appium/java_client/ios/IOSSwipeGestureTest.java new file mode 100644 index 000000000..3916f2777 --- /dev/null +++ b/src/test/java/io/appium/java_client/ios/IOSSwipeGestureTest.java @@ -0,0 +1,155 @@ +package io.appium.java_client.ios; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; + +import io.appium.java_client.MobileElement; +import io.appium.java_client.SwipeElementDirection; +import io.appium.java_client.remote.IOSMobileCapabilityType; +import io.appium.java_client.remote.MobileCapabilityType; +import io.appium.java_client.service.local.AppiumDriverLocalService; +import io.appium.java_client.service.local.AppiumServerHasNotBeenStartedLocallyException; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.openqa.selenium.Point; +import org.openqa.selenium.interactions.internal.Coordinates; +import org.openqa.selenium.remote.DesiredCapabilities; + +import java.io.File; + +public class IOSSwipeGestureTest { + + private static AppiumDriverLocalService service; + protected static IOSDriver driver; + + @BeforeClass + public static void beforeClass() throws Exception { + service = AppiumDriverLocalService.buildDefaultService(); + service.start(); + + if (service == null || !service.isRunning()) { + throw new AppiumServerHasNotBeenStartedLocallyException( + "An appium server node is not started!"); + } + + File appDir = new File("src/test/java/io/appium/java_client"); + File app = new File(appDir, "UICatalog.app.zip"); + DesiredCapabilities capabilities = new DesiredCapabilities(); + capabilities.setCapability(MobileCapabilityType.BROWSER_NAME, ""); + capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "9.2"); + capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "iPhone Simulator"); + //sometimes environment has performance problems + capabilities.setCapability(IOSMobileCapabilityType.LAUNCH_TIMEOUT, 500000); + capabilities.setCapability(MobileCapabilityType.APP, app.getAbsolutePath()); + driver = new IOSDriver<>(service.getUrl(), capabilities); + } + + /** + * finishing. + */ + @AfterClass + public static void afterClass() { + if (driver != null) { + driver.quit(); + } + if (service != null) { + service.stop(); + } + } + + @After public void afterMethod() { + driver.resetApp(); + } + + @Test + public void horizontalSwipingTest() { + driver.findElementByAccessibilityId("Sliders").click(); + MobileElement slider = driver.findElementsByClassName("UIASlider").get(1); + + IOSTouchAction touchAction = new IOSTouchAction(driver); + touchAction.swipe(slider, + SwipeElementDirection.LEFT, slider.getSize().getWidth() / 2, 0, 3000).perform(); + assertEquals("0%", slider.getAttribute("value")); + + IOSTouchAction touchAction2 = new IOSTouchAction(driver); + touchAction2.swipe(slider, SwipeElementDirection.RIGHT, 2, 0, 3000).perform(); + assertEquals("100%", slider.getAttribute("value")); + } + + @Test + public void verticalSwipingTest() throws InterruptedException { + IOSElement tableView = (IOSElement) driver.findElementByClassName("UIATableView"); + MobileElement element = driver.findElementsByClassName("UIAStaticText").get(1); + + IOSTouchAction touchAction = new IOSTouchAction(driver); + touchAction.swipe(tableView, SwipeElementDirection.UP, 20, 15, 3000).perform(); + assertFalse(element.isDisplayed()); + + IOSTouchAction touchAction2 = new IOSTouchAction(driver); + touchAction2.swipe(tableView, SwipeElementDirection.DOWN, 20, 15, 3000).perform(); + + Thread.sleep(5000); + assertTrue(element.isDisplayed()); + } + + @Test + public void swipeFromElementToElement() { + IOSElement e1 = (IOSElement) driver.findElementsByClassName("UIAWindow").get(1) + .findElementByAccessibilityId("Buttons"); + IOSElement e2 = (IOSElement) driver.findElementsByClassName("UIAWindow").get(1) + .findElementByAccessibilityId("Sliders"); + + Point originalLocation = e2.getLocation(); + IOSTouchAction touchAction = new IOSTouchAction(driver); + touchAction.swipe(e2, e1, 3000).perform(); + + Point newLocation = e2.getLocation(); + assertNotEquals(originalLocation, newLocation); + } + + @Test public void swipeFromCoordinatesToElement() { + IOSElement e1 = (IOSElement) driver.findElementsByClassName("UIAWindow").get(1) + .findElementByAccessibilityId("Buttons"); + IOSElement e2 = (IOSElement) driver.findElementsByClassName("UIAWindow").get(1) + .findElementByAccessibilityId("Sliders"); + + Point originalLocation = e2.getLocation(); + IOSTouchAction touchAction = new IOSTouchAction(driver); + touchAction.swipe(originalLocation.x + 50, originalLocation.y, e1, 3000).perform(); + + Point newLocation = e2.getLocation(); + assertNotEquals(originalLocation, newLocation); + } + + @Test public void whenSwipingIsCombinedWithOtherActions() { + IOSElement e1 = (IOSElement) driver.findElementsByClassName("UIAWindow").get(1) + .findElementByAccessibilityId("Buttons"); + IOSElement e2 = (IOSElement) driver.findElementsByClassName("UIAWindow").get(1) + .findElementByAccessibilityId("Sliders"); + IOSElement e3 = (IOSElement) driver.findElementsByClassName("UIAWindow").get(1) + .findElementByAccessibilityId("Date Picker"); + + Coordinates originalCoordinates = e3.getCoordinates(); + + IOSTouchAction touchAction = new IOSTouchAction(driver); + touchAction.swipe(e1, e2, 3000).moveTo(e3).perform(); + + assertNotEquals(originalCoordinates, e3.getCoordinates()); + } + + @Test public void swipeChainingTest() { + IOSElement e1 = (IOSElement) driver.findElementsByClassName("UIAWindow").get(1) + .findElementByAccessibilityId("Buttons"); + IOSElement e2 = (IOSElement) driver.findElementsByClassName("UIAWindow").get(1) + .findElementByAccessibilityId("Sliders"); + + IOSTouchAction touchAction = new IOSTouchAction(driver); + ((IOSTouchAction) touchAction.swipe(e2, e1, 3000)).swipe(e1, e2, 3000).perform(); + + assertTrue(e1.isDisplayed()); + } +} diff --git a/src/test/java/io/appium/java_client/ios/XCUIAutomationTest.java b/src/test/java/io/appium/java_client/ios/XCUIAutomationTest.java index e608e581e..269fd3326 100644 --- a/src/test/java/io/appium/java_client/ios/XCUIAutomationTest.java +++ b/src/test/java/io/appium/java_client/ios/XCUIAutomationTest.java @@ -16,7 +16,6 @@ package io.appium.java_client.ios; - import static org.junit.Assert.assertEquals; import io.appium.java_client.MobileElement; diff --git a/src/test/java/io/appium/java_client/pagefactory_tests/IOSPageFactoryTest.java b/src/test/java/io/appium/java_client/pagefactory_tests/IOSPageFactoryTest.java index 6b6965785..df269a4fe 100644 --- a/src/test/java/io/appium/java_client/pagefactory_tests/IOSPageFactoryTest.java +++ b/src/test/java/io/appium/java_client/pagefactory_tests/IOSPageFactoryTest.java @@ -163,7 +163,7 @@ public class IOSPageFactoryTest { //sometimes environment has performance problems capabilities.setCapability(IOSMobileCapabilityType.LAUNCH_TIMEOUT, 500000); capabilities.setCapability(MobileCapabilityType.APP, app.getAbsolutePath()); - driver = new IOSDriver(service.getUrl(), capabilities); + driver = new IOSDriver<>(service.getUrl(), capabilities); } /** diff --git a/src/test/java/io/appium/java_client/pagefactory_tests/widgets/combined/SelendroidCombinedWidgetTest.java b/src/test/java/io/appium/java_client/pagefactory_tests/widgets/combined/SelendroidCombinedWidgetTest.java index 6b72e4983..f381960e3 100644 --- a/src/test/java/io/appium/java_client/pagefactory_tests/widgets/combined/SelendroidCombinedWidgetTest.java +++ b/src/test/java/io/appium/java_client/pagefactory_tests/widgets/combined/SelendroidCombinedWidgetTest.java @@ -26,7 +26,7 @@ import java.util.concurrent.TimeUnit; public class SelendroidCombinedWidgetTest implements WidgetTest { - private static int SELENDROID_PORT = 9999; + private static AppiumDriverLocalService service; private AndroidDriver driver; private RottenTomatoesAppWithCombinedWidgets rottenTomatoes;