diff --git a/src/main/java/io/appium/java_client/ExecuteCDPCommand.java b/src/main/java/io/appium/java_client/ExecuteCDPCommand.java new file mode 100644 index 000000000..8cf09f357 --- /dev/null +++ b/src/main/java/io/appium/java_client/ExecuteCDPCommand.java @@ -0,0 +1,61 @@ +/* + * 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 com.google.common.collect.ImmutableMap; +import org.openqa.selenium.remote.Response; + +import javax.annotation.Nullable; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import static com.google.common.base.Preconditions.checkNotNull; +import static io.appium.java_client.MobileCommand.EXECUTE_GOOGLE_CDP_COMMAND; + +public interface ExecuteCDPCommand extends ExecutesMethod { + + /** + * Allows to execute ChromeDevProtocol commands against Android Chrome browser session. + * + * @param command Command to execute against the browser (For Ref : https://chromedevtools.github.io/devtools-protocol/) + * @param params additional parameters required to execute the command + * @return Value (Output of the command execution) + * @throws org.openqa.selenium.WebDriverException if there was a failure while executing the command + * @since Appium 1.18 + */ + default Map executeCdpCommand(String command, @Nullable Map params) { + Map data = new HashMap<>(); + data.put("cmd", checkNotNull(command)); + data.put("params", params == null ? Collections.emptyMap() : params); + Response response = execute(EXECUTE_GOOGLE_CDP_COMMAND, data); + //noinspection unchecked + return ImmutableMap.copyOf((Map) response.getValue()); + } + + /** + * Allows to execute ChromeDevProtocol commands against Android Chrome browser session without parameters. + * + * @param command Command to execute against the browser (For Ref : https://chromedevtools.github.io/devtools-protocol/) + * @return Value (Output of the command execution) + * @throws org.openqa.selenium.WebDriverException if there was a failure while executing the command + * @since Appium 1.18 + */ + default Map executeCdpCommand(String command) { + return executeCdpCommand(command, null); + } +} diff --git a/src/main/java/io/appium/java_client/MobileCommand.java b/src/main/java/io/appium/java_client/MobileCommand.java index 58a3b6098..df50c962f 100644 --- a/src/main/java/io/appium/java_client/MobileCommand.java +++ b/src/main/java/io/appium/java_client/MobileCommand.java @@ -114,6 +114,7 @@ public class MobileCommand { protected static final String COMPARE_IMAGES; protected static final String EXECUTE_DRIVER_SCRIPT; protected static final String GET_ALLSESSION; + protected static final String EXECUTE_GOOGLE_CDP_COMMAND; public static final Map commandRepository; @@ -192,6 +193,7 @@ public class MobileCommand { COMPARE_IMAGES = "compareImages"; EXECUTE_DRIVER_SCRIPT = "executeDriverScript"; GET_ALLSESSION = "getAllSessions"; + EXECUTE_GOOGLE_CDP_COMMAND = "executeCdp"; commandRepository = new HashMap<>(); commandRepository.put(RESET, postC("/session/:sessionId/appium/app/reset")); @@ -282,6 +284,7 @@ public class MobileCommand { commandRepository.put(COMPARE_IMAGES, postC("/session/:sessionId/appium/compare_images")); commandRepository.put(EXECUTE_DRIVER_SCRIPT, postC("/session/:sessionId/appium/execute_driver")); commandRepository.put(GET_ALLSESSION, getC("/sessions")); + commandRepository.put(EXECUTE_GOOGLE_CDP_COMMAND, postC("/session/:sessionId/goog/cdp/execute")); } /** 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 9fc18bd51..62016e814 100644 --- a/src/main/java/io/appium/java_client/android/AndroidDriver.java +++ b/src/main/java/io/appium/java_client/android/AndroidDriver.java @@ -25,6 +25,7 @@ import io.appium.java_client.AppiumDriver; import io.appium.java_client.CommandExecutionHelper; +import io.appium.java_client.ExecuteCDPCommand; import io.appium.java_client.FindsByAndroidDataMatcher; import io.appium.java_client.FindsByAndroidViewMatcher; import io.appium.java_client.FindsByAndroidUIAutomator; @@ -67,7 +68,7 @@ public class AndroidDriver HasSupportedPerformanceDataType, AuthenticatesByFinger, HasOnScreenKeyboard, CanRecordScreen, SupportsSpecialEmulatorCommands, SupportsNetworkStateManagement, ListensToLogcatMessages, HasAndroidClipboard, - HasBattery { + HasBattery, ExecuteCDPCommand { private static final String ANDROID_PLATFORM = MobilePlatform.ANDROID; diff --git a/src/test/java/io/appium/java_client/android/ExecuteCDPCommandTest.java b/src/test/java/io/appium/java_client/android/ExecuteCDPCommandTest.java new file mode 100644 index 000000000..3637d0360 --- /dev/null +++ b/src/test/java/io/appium/java_client/android/ExecuteCDPCommandTest.java @@ -0,0 +1,98 @@ +/* + * 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.android; + +import io.appium.java_client.pagefactory.AppiumFieldDecorator; +import io.appium.java_client.remote.MobileBrowserType; +import io.appium.java_client.remote.MobileCapabilityType; +import io.appium.java_client.service.local.AppiumDriverLocalService; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.remote.DesiredCapabilities; +import org.openqa.selenium.remote.RemoteWebElement; +import org.openqa.selenium.support.FindBy; +import org.openqa.selenium.support.PageFactory; + +import java.util.HashMap; +import java.util.Map; + +import static java.time.Duration.ofSeconds; +import static org.junit.Assert.assertNotNull; + +public class ExecuteCDPCommandTest { + + private WebDriver driver; + + private AppiumDriverLocalService service; + + @FindBy(name = "q") + private WebElement searchTextField; + + + /** + * The setting up. + */ + @Before + public void setUp() { + service = AppiumDriverLocalService.buildDefaultService(); + service.start(); + + DesiredCapabilities capabilities = new DesiredCapabilities(); + capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Android Emulator"); + capabilities.setCapability(MobileCapabilityType.BROWSER_NAME, MobileBrowserType.CHROME); + capabilities.setCapability(MobileCapabilityType.AUTOMATION_NAME, "UiAutomator2"); + driver = new AndroidDriver(service.getUrl(), capabilities); + //This time out is set because test can be run on slow Android SDK emulator + PageFactory.initElements(new AppiumFieldDecorator(driver, ofSeconds(5)), this); + } + + /** + * finishing. + */ + @After + public void tearDown() { + if (driver != null) { + driver.quit(); + } + + if (service != null) { + service.stop(); + } + } + + @Test + public void testExecuteCDPCommandWithoutParam() { + driver.get("https://www.google.com"); + searchTextField.sendKeys("Hello"); + Map cookies = ((AndroidDriver) driver).executeCdpCommand("Page.getCookies"); + assertNotNull(cookies); + } + + @Test + public void testExecuteCDPCommandWithParams() { + Map params = new HashMap(); + params.put("latitude", 13.0827); + params.put("longitude", 80.2707); + params.put("accuracy", 1); + ((AndroidDriver) driver).executeCdpCommand("Emulation.setGeolocationOverride", params); + driver.get("https://www.google.com"); + } + +}