/* * Copyright 2012-2014 eBay Software Foundation and selendroid committers. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * in compliance with the License. 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.selendroid.client; import com.google.common.base.Strings; import com.google.common.collect.Maps; import io.selendroid.client.adb.AdbConnection; import io.selendroid.server.common.utils.CallLogEntry; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.json.JSONArray; import org.json.JSONException; import org.openqa.selenium.Capabilities; import org.openqa.selenium.ContextAware; import org.openqa.selenium.OutputType; import org.openqa.selenium.Rotatable; import org.openqa.selenium.ScreenOrientation; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebDriverException; import org.openqa.selenium.interactions.HasTouchScreen; import org.openqa.selenium.interactions.TouchScreen; import org.openqa.selenium.remote.CommandExecutor; import org.openqa.selenium.remote.ExecuteMethod; import org.openqa.selenium.remote.RemoteExecuteMethod; import org.openqa.selenium.remote.RemoteTouchScreen; import org.openqa.selenium.remote.RemoteWebDriver; import org.openqa.selenium.remote.Response; import com.google.common.collect.ImmutableMap; /** * {@inheritDoc} */ public class SelendroidDriver extends RemoteWebDriver implements HasTouchScreen, HasMultiTouchScreen, ScreenBrightness, Rotatable, Configuration, AdbSupport, ContextAware, SetsSystemProperties, CallsGc { private RemoteTouchScreen touchScreen; private MultiTouchScreen multiTouchScreen; private RemoteAdbConnection adbConnection; private TrackBall trackBall; private SelendroidDriver(CommandExecutor executor, Capabilities caps) throws Exception { super(executor, caps); RemoteExecuteMethod executeMethod = new RemoteExecuteMethod(this); touchScreen = new RemoteTouchScreen(executeMethod); multiTouchScreen = new MultiTouchScreen(executeMethod); adbConnection = new RemoteAdbConnection(executeMethod); trackBall = new TrackBall(executeMethod); } public SelendroidDriver(URL url, Capabilities caps) throws Exception { this(new SelendroidCommandExecutor(url), caps); } public SelendroidDriver(Capabilities caps) throws Exception { this(new SelendroidCommandExecutor(), caps); } /** * {@inheritDoc} */ @Override public TouchScreen getTouch() { return touchScreen; } public void roll(int dimensionX, int dimensionY) { trackBall.roll(dimensionX, dimensionY); } public MultiTouchScreen getMultiTouchScreen() { return multiTouchScreen; } /** * {@inheritDoc} */ @Override public int getBrightness() { Response response = execute("selendroid-getBrightness"); Number value = (Number) response.getValue(); return value.intValue(); } /** * {@inheritDoc} */ @Override public void setBrightness(int desiredBrightness) { execute("selendroid-setBrightness", ImmutableMap.of("brightness", desiredBrightness)); } @Override public void rotate(ScreenOrientation orientation) { execute(org.openqa.selenium.remote.DriverCommand.SET_SCREEN_ORIENTATION, ImmutableMap.of("orientation", orientation)); } @Override public ScreenOrientation getOrientation() { return ScreenOrientation.valueOf((String) execute( org.openqa.selenium.remote.DriverCommand.GET_SCREEN_ORIENTATION).getValue()); } @Override public void setConfiguration(DriverCommand command, String key, Object value) { Map<String, Object> parameters = new HashMap<String, Object>(); parameters.put("command", command.command); parameters.put(key, value); execute("selendroid-setCommandConfiguration", parameters); } @Override public Map<String, Object> getConfiguration(DriverCommand command) { Response response = execute("selendroid-getCommandConfiguration", ImmutableMap.of("command", command.command)); return (Map<String, Object>) response.getValue(); } @Override public AdbConnection getAdbConnection() { return adbConnection; } public boolean isAirplaneModeEnabled() { return ((Number) execute("getNetworkConnection").getValue()).intValue() == 1; } public void setAirplaneMode(boolean enabled) { Map<String, Integer> mode = ImmutableMap.of("type", enabled ? 1 : 6); execute("setNetworkConnection", ImmutableMap.of("parameters", mode)); } public class RemoteAdbConnection implements AdbConnection { private final ExecuteMethod executeMethod; public RemoteAdbConnection(ExecuteMethod executeMethod) { this.executeMethod = executeMethod; } @Override public void tap(int x, int y) { Map<String, Object> parameters = new HashMap<String, Object>(); parameters.put("x", x); parameters.put("y", y); executeMethod.execute("selendroid-adb-tap", parameters); } @Override public void sendText(String text) { executeMethod.execute("selendroid-adb-sendText", ImmutableMap.of("text", text)); } @Override public void sendKeyEvent(int keyCode) { executeMethod.execute("selendroid-adb-sendKeyEvent", ImmutableMap.of("keyCode", keyCode)); } @Override public String executeShellCommand(String command) { return (String) execute("selendroid-adb-executeShellCommand", ImmutableMap.of("command", command)).getValue(); } } @Override public WebDriver context(String name) { execute(org.openqa.selenium.remote.DriverCommand.SWITCH_TO_CONTEXT, ImmutableMap.of("name", name)); return this; } @Override public Set<String> getContextHandles() { Response response = execute(org.openqa.selenium.remote.DriverCommand.GET_CONTEXT_HANDLES); Object value = response.getValue(); try { List<String> returnedValues = (List<String>) value; return new LinkedHashSet<String>(returnedValues); } catch (ClassCastException ex) { throw new WebDriverException("Returned value cannot be converted to List<String>: " + value, ex); } } @Override public String getContext() { return String.valueOf(execute( org.openqa.selenium.remote.DriverCommand.GET_CURRENT_CONTEXT_HANDLE).getValue()); } /** * Sends app under test to background. */ public void backgroundApp() { execute("backgroundApp"); } /** * Bring app under test back to foreground with its previous state. */ public void resumeApp() { execute("resumeApp"); } public void addCallLog(CallLogEntry log) { Map<String, String> info = ImmutableMap.of("calllogjson", log.toJSON()); execute("addCallLog", ImmutableMap.of("parameters",info)); } public List<CallLogEntry> readCallLog() { Response response = execute("readCallLog"); Object value = response.getValue(); try { List<String> returnedLogs = (List<String>) value; List<CallLogEntry> logEntries = new ArrayList<CallLogEntry>(returnedLogs.size()); for (String jsonLogEntry : returnedLogs) { logEntries.add(CallLogEntry.fromJson(jsonLogEntry)); } return logEntries; } catch (ClassCastException ex) { throw new WebDriverException("Returned value cannot be converted to List<String>: " + value, ex); } } public Object callExtension(String extensionMethod) { return callExtension(extensionMethod, ImmutableMap.<String, Object>of()); } public Object callExtension(String extensionMethod, Map<String, ?> parameters) { Map<String, Object> paramsWithHandler = Maps.newHashMap(); paramsWithHandler.putAll(parameters); paramsWithHandler.put("handlerName", extensionMethod); Response response = execute("selendroid-handleByExtension", paramsWithHandler); return response.getValue(); } /** * Sets a Java System Property. */ @Override public void setSystemProperty(String propertyName, String value) { if (Strings.isNullOrEmpty(propertyName)) { throw new IllegalArgumentException("Property name can't be empty."); } execute( "-selendroid-setAndroidOsSystemProperty", ImmutableMap.of( "propertyName", propertyName, "value", value)); } /** * Synchronously calls "System.gc()" on device. */ @Override public void gc() { execute("-selendroid-forceGcExplicitly"); } }