diff --git a/lib/devices/android/android-controller.js b/lib/devices/android/android-controller.js index e0321840a4e..2d3ffc769d6 100644 --- a/lib/devices/android/android-controller.js +++ b/lib/devices/android/android-controller.js @@ -24,10 +24,19 @@ var NATIVE_WIN = "NATIVE_APP"; var WEBVIEW_WIN = "WEBVIEW"; var WEBVIEW_BASE = WEBVIEW_WIN + "_"; -androidController.keyevent = function (keycode, metastate, cb) { +androidController.pressKeyCode = function (keycode, metastate, cb) { this.proxy(["pressKeyCode", {keycode: keycode, metastate: metastate}], cb); }; +androidController.longPressKeyCode = function (keycode, metastate, cb) { + this.proxy(["longPressKeyCode", {keycode: keycode, metastate: metastate}], cb); +}; + +androidController.keyevent = function (keycode, metastate, cb) { + warnDeprecated('function', 'keyevent', 'pressKeyCode'); + this.pressKeyCode(keycode, metastate, cb); +}; + androidController.defaultContext = function () { return NATIVE_WIN; }; diff --git a/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/handler/TouchableEvent.java b/lib/devices/android/bootstrap/src/com/android/uiautomator/common/ReflectionUtils.java similarity index 60% rename from lib/devices/android/bootstrap/src/io/appium/android/bootstrap/handler/TouchableEvent.java rename to lib/devices/android/bootstrap/src/com/android/uiautomator/common/ReflectionUtils.java index 8f6306296fd..35ab0bc8dc2 100644 --- a/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/handler/TouchableEvent.java +++ b/lib/devices/android/bootstrap/src/com/android/uiautomator/common/ReflectionUtils.java @@ -1,23 +1,15 @@ -package io.appium.android.bootstrap.handler; +package com.android.uiautomator.common; -import io.appium.android.bootstrap.CommandHandler; import io.appium.android.bootstrap.Logger; -import android.os.Build; +import java.lang.reflect.Field; +import java.lang.reflect.Method; -import android.view.MotionEvent.PointerCoords; +import android.os.Build; import com.android.uiautomator.core.UiDevice; -import java.lang.reflect.Field; -import java.lang.reflect.Method; - -/** - * This handler is and abstract class that contains all the common code for - * touch event handlers. - * - */ -public abstract class TouchableEvent extends CommandHandler { +public class ReflectionUtils { private static Field enableField(final Class clazz, final String field) throws SecurityException, NoSuchFieldException { Logger.debug("Updating class \"" + clazz + "\" to enable field \"" + field @@ -27,40 +19,39 @@ private static Field enableField(final Class clazz, final String field) return fieldObject; } - /* - * getAutomatorBridge is private so we access the bridge via reflection to use - * the touchDown / touchUp / touchMove methods. - */ - protected Object getController() throws IllegalArgumentException, + private Object controller = null; + + public ReflectionUtils() throws IllegalArgumentException, IllegalAccessException, SecurityException, NoSuchFieldException { final UiDevice device = UiDevice.getInstance(); final Object bridge = enableField(device.getClass(), "mUiAutomationBridge") .get(device); - Object controller = null; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { controller = enableField(bridge.getClass().getSuperclass(), "mInteractionController").get(bridge); } else { - controller = enableField(bridge.getClass(), - "mInteractionController").get(bridge); + controller = enableField(bridge.getClass(), "mInteractionController") + .get(bridge); } - return controller; + } + /* + * getAutomatorBridge is private so we access the bridge via reflection to use + * the touchDown / touchUp / touchMove methods. + */ + public Object getController() throws IllegalArgumentException, + IllegalAccessException, SecurityException, NoSuchFieldException { + return controller; } - protected Method getMethod(final String name, final Object controller) + public Method getMethod(final String name, final Class... parameterTypes) throws NoSuchMethodException, SecurityException { final Class controllerClass = controller.getClass(); Logger.debug("Finding methods on class: " + controllerClass); final Method method; - if (name.equals("performMultiPointerGesture")) { - // multi pointer gestures take a 2d array of coordinates - method = controllerClass.getDeclaredMethod(name, PointerCoords[][].class); - } else { - // all the other touch events send two ints - method = controllerClass.getDeclaredMethod(name, int.class, int.class); - } + method = controllerClass.getDeclaredMethod(name, parameterTypes); + method.setAccessible(true); return method; } diff --git a/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/AndroidCommandExecutor.java b/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/AndroidCommandExecutor.java index ec270009e2f..949149cf2ef 100644 --- a/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/AndroidCommandExecutor.java +++ b/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/AndroidCommandExecutor.java @@ -14,6 +14,7 @@ import io.appium.android.bootstrap.handler.GetName; import io.appium.android.bootstrap.handler.GetSize; import io.appium.android.bootstrap.handler.GetText; +import io.appium.android.bootstrap.handler.LongPressKeyCode; import io.appium.android.bootstrap.handler.MultiPointerGesture; import io.appium.android.bootstrap.handler.Orientation; import io.appium.android.bootstrap.handler.Pinch; @@ -70,6 +71,7 @@ class AndroidCommandExecutor { map.put("pressBack", new PressBack()); map.put("dumpWindowHierarchy", new DumpWindowHierarchy()); map.put("pressKeyCode", new PressKeyCode()); + map.put("longPressKeyCode", new LongPressKeyCode()); map.put("takeScreenshot", new TakeScreenshot()); map.put("updateStrings", new UpdateStrings()); map.put("getDataDir", new GetDataDir()); diff --git a/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/handler/LongPressKeyCode.java b/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/handler/LongPressKeyCode.java new file mode 100644 index 00000000000..0badc85131e --- /dev/null +++ b/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/handler/LongPressKeyCode.java @@ -0,0 +1,72 @@ +package io.appium.android.bootstrap.handler; + +import io.appium.android.bootstrap.AndroidCommand; +import io.appium.android.bootstrap.AndroidCommandResult; +import io.appium.android.bootstrap.CommandHandler; + +import java.lang.reflect.Method; +import java.util.Hashtable; + +import org.json.JSONException; +import org.json.JSONObject; + +import android.os.SystemClock; +import android.view.InputDevice; +import android.view.InputEvent; +import android.view.KeyCharacterMap; +import android.view.KeyEvent; + +import com.android.uiautomator.common.ReflectionUtils; + +/** + * This handler is used to LongPressKeyCode. + * + */ +public class LongPressKeyCode extends CommandHandler { + public Integer keyCode; + + public Integer metaState; + + /* + * @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 { + try { + final ReflectionUtils utils = new ReflectionUtils(); + final Method injectEventSync = utils.getMethod("injectEventSync", + InputEvent.class); + final Hashtable params = command.params(); + keyCode = (Integer) params.get("keycode"); + metaState = params.get("metastate") != JSONObject.NULL ? (Integer) params + .get("metastate") : 0; + final long eventTime = SystemClock.uptimeMillis(); + // Send an initial down event + final KeyEvent downEvent = new KeyEvent(eventTime, eventTime, + KeyEvent.ACTION_DOWN, keyCode, 0, metaState, + KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD); + if ((Boolean) injectEventSync.invoke(utils.getController(), downEvent)) { + // Send a repeat event. This will cause the FLAG_LONG_PRESS to be set. + final KeyEvent repeatEvent = KeyEvent.changeTimeRepeat(downEvent, + eventTime, 1); + injectEventSync.invoke(utils.getController(), repeatEvent); + // Finally, send the up event + final KeyEvent upEvent = new KeyEvent(eventTime, eventTime, + KeyEvent.ACTION_UP, keyCode, 0, metaState, + KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD); + injectEventSync.invoke(utils.getController(), upEvent); + } + return getSuccessResult(true); + } catch (final Exception e) { + return getErrorResult(e.getMessage()); + } + } +} diff --git a/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/handler/MultiPointerGesture.java b/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/handler/MultiPointerGesture.java index d1402a2a3a5..968d8c8a4f2 100644 --- a/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/handler/MultiPointerGesture.java +++ b/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/handler/MultiPointerGesture.java @@ -1,18 +1,5 @@ package io.appium.android.bootstrap.handler; -import android.os.Build; - -import android.view.MotionEvent.PointerCoords; - -import com.android.uiautomator.core.UiObject; -import com.android.uiautomator.core.UiObjectNotFoundException; -import com.android.uiautomator.core.UiScrollable; -import com.android.uiautomator.core.UiSelector; - -import org.json.JSONException; -import org.json.JSONArray; -import org.json.JSONObject; - import io.appium.android.bootstrap.AndroidCommand; import io.appium.android.bootstrap.AndroidCommandResult; import io.appium.android.bootstrap.AndroidElement; @@ -23,14 +10,53 @@ import java.lang.reflect.Method; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import android.os.Build; +import android.view.MotionEvent.PointerCoords; + +import com.android.uiautomator.common.ReflectionUtils; + +public class MultiPointerGesture extends CommandHandler { + + private double computeLongestTime(final JSONArray actions) + throws JSONException { + double max = 0.0; + for (int i = 0; i < actions.length(); i++) { + final JSONArray gestures = actions.getJSONArray(i); + final double endTime = gestures.getJSONObject(gestures.length() - 1) + .getDouble("time"); + if (endTime > max) { + max = endTime; + } + } + + return max; + } + + private PointerCoords createPointerCoords(final JSONObject obj) + throws JSONException { + final JSONObject o = obj.getJSONObject("touch"); + + final int x = o.getInt("x"); + final int y = o.getInt("y"); + + final PointerCoords p = new PointerCoords(); + p.size = 1; + p.pressure = 1; + p.x = x; + p.y = y; -public class MultiPointerGesture extends TouchableEvent { + return p; + } @Override public AndroidCommandResult execute(final AndroidCommand command) throws JSONException { try { - PointerCoords[][] pcs = parsePointerCoords(command); + final PointerCoords[][] pcs = parsePointerCoords(command); if (command.isElementCommand()) { final AndroidElement el = command.getElement(); @@ -40,10 +66,12 @@ public AndroidCommandResult execute(final AndroidCommand command) return getErrorResult("Unable to perform multi pointer gesture"); } } else { - Object controller = getController(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { - final Method pmpg = getMethod("performMultiPointerGesture", controller); - Boolean rt = (Boolean)pmpg.invoke(controller, (Object)pcs); + final ReflectionUtils utils = new ReflectionUtils(); + final Method pmpg = utils.getMethod("performMultiPointerGesture", + PointerCoords[][].class); + final Boolean rt = (Boolean) pmpg.invoke(utils.getController(), + (Object) pcs); if (rt.booleanValue()) { return getSuccessResult("OK"); } else { @@ -64,45 +92,28 @@ public AndroidCommandResult execute(final AndroidCommand command) } } - private PointerCoords[][] parsePointerCoords(AndroidCommand command) - throws JSONException { - JSONArray actions = (org.json.JSONArray)command.params().get("actions"); - - double time = computeLongestTime(actions); - - PointerCoords[][] pcs = new PointerCoords[actions.length()][]; - for (int i = 0; i < actions.length(); i++) { - JSONArray gestures = actions.getJSONArray(i); - - pcs[i] = gesturesToPointerCoords(time, gestures); - } - - return pcs; - } - - private PointerCoords[] gesturesToPointerCoords(double maxTime, JSONArray gestures) - throws JSONException { + private PointerCoords[] gesturesToPointerCoords(final double maxTime, + final JSONArray gestures) throws JSONException { // gestures, e.g.: - // [ - // {"touch":{"y":529.5,"x":120},"time":0.2}, - // {"touch":{"y":529.5,"x":130},"time":0.4}, - // {"touch":{"y":454.5,"x":140},"time":0.6}, - // {"touch":{"y":304.5,"x":150},"time":0.8} - // ] - + // [ + // {"touch":{"y":529.5,"x":120},"time":0.2}, + // {"touch":{"y":529.5,"x":130},"time":0.4}, + // {"touch":{"y":454.5,"x":140},"time":0.6}, + // {"touch":{"y":304.5,"x":150},"time":0.8} + // ] // From the docs: // "Steps are injected about 5 milliseconds apart, so 100 steps may take // around 0.5 seconds to complete." - int steps = (int)(maxTime * 200) + 2; + final int steps = (int) (maxTime * 200) + 2; - PointerCoords[] pc = new PointerCoords[steps]; + final PointerCoords[] pc = new PointerCoords[steps]; int i = 1; JSONObject current = gestures.getJSONObject(0); double currentTime = current.getDouble("time"); double runningTime = 0.0; - int gesturesLength = gestures.length(); + final int gesturesLength = gestures.length(); for (int j = 0; j < steps; j++) { if (runningTime > currentTime && i < gesturesLength) { current = gestures.getJSONObject(i++); @@ -117,31 +128,20 @@ private PointerCoords[] gesturesToPointerCoords(double maxTime, JSONArray gestur return pc; } - private PointerCoords createPointerCoords(JSONObject obj) throws JSONException { - JSONObject o = obj.getJSONObject("touch"); - - int x = o.getInt("x"); - int y = o.getInt("y"); - - PointerCoords p = new PointerCoords(); - p.size = 1; - p.pressure = 1; - p.x = x; - p.y = y; + private PointerCoords[][] parsePointerCoords(final AndroidCommand command) + throws JSONException { + final JSONArray actions = (org.json.JSONArray) command.params().get( + "actions"); - return p; - } + final double time = computeLongestTime(actions); - private double computeLongestTime(JSONArray actions) throws JSONException { - double max = 0.0; + final PointerCoords[][] pcs = new PointerCoords[actions.length()][]; for (int i = 0; i < actions.length(); i++) { - JSONArray gestures = actions.getJSONArray(i); - double endTime = gestures.getJSONObject(gestures.length()-1).getDouble("time"); - if (endTime > max) { - max = endTime; - } + final JSONArray gestures = actions.getJSONArray(i); + + pcs[i] = gesturesToPointerCoords(time, gestures); } - return max; + return pcs; } } diff --git a/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/handler/TouchDown.java b/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/handler/TouchDown.java index 65cc61b5f8d..75b27bd86bb 100644 --- a/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/handler/TouchDown.java +++ b/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/handler/TouchDown.java @@ -4,6 +4,7 @@ import java.lang.reflect.Method; +import com.android.uiautomator.common.ReflectionUtils; import com.android.uiautomator.core.UiObjectNotFoundException; /** @@ -17,9 +18,10 @@ public class TouchDown extends TouchEvent { protected boolean executeTouchEvent() throws UiObjectNotFoundException { printEventDebugLine("TouchDown"); try { - final Object controller = getController(); - final Method touchDown = getMethod("touchDown", controller); - return (Boolean) touchDown.invoke(controller, clickX, clickY); + final ReflectionUtils utils = new ReflectionUtils(); + final Method touchDown = utils.getMethod("touchDown", int.class, + int.class); + return (Boolean) touchDown.invoke(utils.getController(), clickX, clickY); } catch (final Exception e) { Logger.debug("Problem invoking touchDown: " + e); return false; diff --git a/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/handler/TouchEvent.java b/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/handler/TouchEvent.java index e1d1402cd76..372f944a35c 100644 --- a/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/handler/TouchEvent.java +++ b/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/handler/TouchEvent.java @@ -8,8 +8,6 @@ import io.appium.android.bootstrap.WDStatus; import io.appium.android.bootstrap.exceptions.ElementNotInHashException; -import java.lang.reflect.Field; -import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Hashtable; @@ -17,15 +15,14 @@ import android.graphics.Rect; -import com.android.uiautomator.core.UiDevice; import com.android.uiautomator.core.UiObjectNotFoundException; /** * This handler is and abstract class that contains all the common code for * touch event handlers. - * + * */ -public abstract class TouchEvent extends TouchableEvent { +public abstract class TouchEvent extends CommandHandler { protected AndroidElement el; protected int clickX; @@ -37,7 +34,7 @@ public abstract class TouchEvent extends TouchableEvent { protected boolean isElement; /** - * + * * @param command * The {@link AndroidCommand} * @return {@link AndroidCommandResult} diff --git a/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/handler/TouchLongClick.java b/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/handler/TouchLongClick.java index 1ecd4cf4c3a..298413ab041 100644 --- a/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/handler/TouchLongClick.java +++ b/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/handler/TouchLongClick.java @@ -6,6 +6,7 @@ import android.os.SystemClock; +import com.android.uiautomator.common.ReflectionUtils; import com.android.uiautomator.core.UiObjectNotFoundException; /** @@ -24,13 +25,14 @@ private boolean correctLongClick(final int x, final int y, final int duration) { * the super class. */ - final Object controller = getController(); - final Method touchDown = getMethod("touchDown", controller); - final Method touchUp = getMethod("touchUp", controller); + final ReflectionUtils utils = new ReflectionUtils(); + final Method touchDown = utils.getMethod("touchDown", int.class, + int.class); + final Method touchUp = utils.getMethod("touchUp", int.class, int.class); - if ((Boolean) touchDown.invoke(controller, x, y)) { + if ((Boolean) touchDown.invoke(utils.getController(), x, y)) { SystemClock.sleep(duration); - if ((Boolean) touchUp.invoke(controller, x, y)) { + if ((Boolean) touchUp.invoke(utils.getController(), x, y)) { return true; } } diff --git a/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/handler/TouchMove.java b/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/handler/TouchMove.java index 2f3e101c140..ebb6ec4e0ae 100644 --- a/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/handler/TouchMove.java +++ b/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/handler/TouchMove.java @@ -4,6 +4,7 @@ import java.lang.reflect.Method; +import com.android.uiautomator.common.ReflectionUtils; import com.android.uiautomator.core.UiObjectNotFoundException; /** @@ -17,9 +18,10 @@ public class TouchMove extends TouchEvent { protected boolean executeTouchEvent() throws UiObjectNotFoundException { printEventDebugLine("TouchMove"); try { - final Object controller = getController(); - final Method touchMove = getMethod("touchMove", controller); - return (Boolean) touchMove.invoke(controller, clickX, clickY); + final ReflectionUtils utils = new ReflectionUtils(); + final Method touchMove = utils.getMethod("touchMove", int.class, + int.class); + return (Boolean) touchMove.invoke(utils.getController(), clickX, clickY); } catch (final Exception e) { Logger.debug("Problem invoking touchMove: " + e); return false; diff --git a/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/handler/TouchUp.java b/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/handler/TouchUp.java index f043302e81c..0cb240af986 100644 --- a/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/handler/TouchUp.java +++ b/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/handler/TouchUp.java @@ -4,6 +4,7 @@ import java.lang.reflect.Method; +import com.android.uiautomator.common.ReflectionUtils; import com.android.uiautomator.core.UiObjectNotFoundException; /** @@ -17,9 +18,9 @@ public class TouchUp extends TouchEvent { protected boolean executeTouchEvent() throws UiObjectNotFoundException { printEventDebugLine("TouchUp"); try { - final Object controller = getController(); - final Method touchUp = getMethod("touchUp", controller); - return (Boolean) touchUp.invoke(controller, clickX, clickY); + final ReflectionUtils utils = new ReflectionUtils(); + final Method touchUp = utils.getMethod("touchUp", int.class, int.class); + return (Boolean) touchUp.invoke(utils.getController(), clickX, clickY); } catch (final Exception e) { Logger.debug("Problem invoking touchUp: " + e); return false; diff --git a/lib/devices/firefoxos/firefoxos.js b/lib/devices/firefoxos/firefoxos.js index 59cf1eb15bc..da60190a26b 100644 --- a/lib/devices/firefoxos/firefoxos.js +++ b/lib/devices/firefoxos/firefoxos.js @@ -260,6 +260,8 @@ Firefox.prototype.notImplementedCmds = function () { , 'getSize' , 'getWindowSize' , 'getPageIndex' + , 'pressKeyCode' + , 'longPressKeyCode' , 'keyevent' , 'back' , 'forward' diff --git a/lib/devices/ios/ios-controller.js b/lib/devices/ios/ios-controller.js index 092a2e84d88..608ec00da27 100644 --- a/lib/devices/ios/ios-controller.js +++ b/lib/devices/ios/ios-controller.js @@ -657,6 +657,14 @@ iOSController.submit = function (elementId, cb) { } }; +iOSController.pressKeyCode = function (keycode, metastate, cb) { + cb(new NotImplementedError(), null); +}; + +iOSController.longPressKeyCode = function (keycode, metastate, cb) { + cb(new NotImplementedError(), null); +}; + iOSController.keyevent = function (keycode, metastate, cb) { cb(new NotImplementedError(), null); }; diff --git a/lib/server/controller.js b/lib/server/controller.js index 7cf7bbb4557..9a597a38d62 100644 --- a/lib/server/controller.js +++ b/lib/server/controller.js @@ -614,6 +614,26 @@ exports.getPageIndex = function (req, res) { req.device.getPageIndex(elementId, getResponseHandler(req, res)); }; +exports.pressKeyCode = function (req, res) { + req.body = _.defaults(req.body, { + keycode: null + , metastate: null + }); + var keycode = req.body.keycode + , metastate = req.body.metastate; + req.device.pressKeyCode(keycode, metastate, getResponseHandler(req, res)); +}; + +exports.longPressKeyCode = function (req, res) { + req.body = _.defaults(req.body, { + keycode: null + , metastate: null + }); + var keycode = req.body.keycode + , metastate = req.body.metastate; + req.device.longPressKeyCode(keycode, metastate, getResponseHandler(req, res)); +}; + exports.keyevent = function (req, res) { req.body = _.defaults(req.body, { keycode: null diff --git a/lib/server/routing.js b/lib/server/routing.js index 12d04bfee00..6d911aa4151 100644 --- a/lib/server/routing.js +++ b/lib/server/routing.js @@ -94,6 +94,8 @@ module.exports = function (appium) { // appium-specific extensions to JSONWP rest.post('/wd/hub/session/:sessionId?/appium/device/shake', controller.mobileShake); rest.post('/wd/hub/session/:sessionId?/appium/device/lock', controller.lock); + rest.post('/wd/hub/session/:sessionId?/appium/device/press_keycode', controller.pressKeyCode); + rest.post('/wd/hub/session/:sessionId?/appium/device/long_press_keycode', controller.longPressKeyCode); rest.post('/wd/hub/session/:sessionId?/appium/device/keyevent', controller.keyevent); rest.post('/wd/hub/session/:sessionId?/appium/device/rotate', controller.mobileRotation); rest.get('/wd/hub/session/:sessionId?/appium/device/current_activity', controller.getCurrentActivity); diff --git a/sample-code/examples/python/android_contacts.py b/sample-code/examples/python/android_contacts.py index 105d22ea99e..ba560df5566 100644 --- a/sample-code/examples/python/android_contacts.py +++ b/sample-code/examples/python/android_contacts.py @@ -44,7 +44,7 @@ def test_add_contacts(self): # no way to handle alerts in Android self.driver.find_element_by_android_uiautomator('new UiSelector().clickable(true)').click() - self.driver.keyevent(3) + self.driver.press_keycode(3)