Showing preview only (275K chars total). Download the full file or copy to clipboard to get everything.
Repository: SonicCloudOrg/sonic-driver-core
Branch: main
Commit: d8d310a20ccd
Files: 60
Total size: 251.5 KB
Directory structure:
gitextract_j_5ezhz9/
├── .github/
│ ├── dependabot.yml
│ └── workflows/
│ ├── maven.yml
│ └── release.yml
├── .gitignore
├── LICENSE
├── README.md
├── README_CN.md
├── pom.xml
└── src/
├── main/
│ └── java/
│ └── org/
│ └── cloud/
│ └── sonic/
│ └── driver/
│ ├── android/
│ │ ├── AndroidDriver.java
│ │ ├── enmus/
│ │ │ └── AndroidSelector.java
│ │ └── service/
│ │ ├── AndroidElement.java
│ │ ├── UiaClient.java
│ │ └── impl/
│ │ ├── AndroidElementImpl.java
│ │ └── UiaClientImpl.java
│ ├── common/
│ │ ├── enums/
│ │ │ └── PasteboardType.java
│ │ ├── models/
│ │ │ ├── BaseElement.java
│ │ │ ├── BaseResp.java
│ │ │ ├── Capabilities.java
│ │ │ ├── ElementRect.java
│ │ │ ├── ErrorMsg.java
│ │ │ ├── SessionInfo.java
│ │ │ └── WindowSize.java
│ │ └── tool/
│ │ ├── Logger.java
│ │ ├── RespHandler.java
│ │ └── SonicRespException.java
│ ├── ios/
│ │ ├── IOSDriver.java
│ │ ├── enums/
│ │ │ ├── ActionType.java
│ │ │ ├── AuthResource.java
│ │ │ ├── IOSSelector.java
│ │ │ ├── Orientation.java
│ │ │ ├── SystemButton.java
│ │ │ ├── TextKey.java
│ │ │ └── XCUIElementType.java
│ │ ├── models/
│ │ │ └── TouchActions.java
│ │ └── service/
│ │ ├── IOSElement.java
│ │ ├── WdaClient.java
│ │ └── impl/
│ │ ├── IOSElementImpl.java
│ │ └── WdaClientImpl.java
│ └── poco/
│ ├── PocoDriver.java
│ ├── enums/
│ │ ├── PocoEngine.java
│ │ └── PocoSelector.java
│ ├── models/
│ │ ├── PocoElement.java
│ │ └── RootElement.java
│ ├── service/
│ │ ├── PocoClient.java
│ │ ├── PocoConnection.java
│ │ └── impl/
│ │ ├── PocoClientImpl.java
│ │ ├── SocketClientImpl.java
│ │ └── WebSocketClientImpl.java
│ └── util/
│ ├── PocoJsonToXml.java
│ ├── PocoTool.java
│ └── PocoXYTransformer.java
└── test/
└── java/
└── org/
└── cloud/
└── sonic/
└── driver/
├── android/
│ ├── AndroidDriverTest.java
│ └── service/
│ └── UiaClientTest.java
├── common/
│ └── tool/
│ ├── RespHandlerTest.java
│ └── SonicRespExceptionTest.java
├── ios/
│ ├── IOSDriverTest.java
│ └── service/
│ └── WdaClientTest.java
└── poco/
├── PocoDriverTest.java
├── PocoJsonToXmlTest.java
└── PocoXYTransformerTest.java
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
- package-ecosystem: "maven"
directory: "/"
schedule:
interval: "weekly"
================================================
FILE: .github/workflows/maven.yml
================================================
name: maven compile test
on: [pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 17
uses: actions/setup-java@v2
with:
java-version: '17'
distribution: 'temurin'
cache: maven
- name: Validate and Compile with Maven
run: mvn validate compile
================================================
FILE: .github/workflows/release.yml
================================================
# name: release to github
# on:
# push:
# tags:
# - "*.*.*"
# jobs:
# doc:
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v2
# with:
# fetch-depth: 0
# - name: 'Get Previous tag'
# id: previoustag
# uses: "WyriHaximus/github-action-get-previous-tag@v1"
# - name: 'Get previous release tag'
# id: tag
# uses: "sammcoe/get-previous-release-action@v1"
# - name: replace version
# run: sed -i "s/${{steps.tag.outputs.tag}}/${{steps.previoustag.outputs.tag}}/g" README*.md
# - name: Create Pull Request
# id: cpr
# uses: peter-evans/create-pull-request@v4
# with:
# commit-message: Update README file.
# author: GitHub <noreply@github.com>
# signoff: false
# branch: doc/${{steps.previoustag.outputs.tag}}
# labels: document
# base: main
# delete-branch: true
# title: 'doc: update README files version to ${{steps.previoustag.outputs.tag}}'
# body: |
# **在提出此拉取请求时,我确认了以下几点(保存后请点击复选框):**
# - [x] 标题为fix、feat或doc开头
# - [x] 我已检查没有与此请求重复的拉取请求。
# - [x] 我已经考虑过,并确认这份呈件对其他人很有价值。
# - [x] 我接受此提交可能不会被使用,并根据维护人员的意愿关闭拉取请求。
# **填写PR内容:**
# - Update README files version to latest tag by bot 🚀.
# draft: false
# - name: Auto approve
# if: steps.cpr.outputs.pull-request-operation == 'created'
# uses: juliangruber/approve-pull-request-action@v1
# with:
# github-token: ${{ secrets.PAT }}
# number: ${{ steps.cpr.outputs.pull-request-number }}
# - id: automerge
# name: automerge
# uses: "pascalgn/automerge-action@v0.15.3"
# env:
# MERGE_LABELS: "document"
# MERGE_DELETE_BRANCH: true
# GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
# PULL_REQUEST: ${{ steps.cpr.outputs.pull-request-number }}
# MERGE_RETRIES: 18
# MERGE_RETRY_SLEEP: 10000
# release:
# needs: doc
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v2
# with:
# fetch-depth: 0
# - name: 'Get Previous tag'
# id: previoustag
# uses: "WyriHaximus/github-action-get-previous-tag@v1"
# - name: replace version
# run: sed -i "s/SONIC_VERSION/${{ steps.previoustag.outputs.tag }}/g" pom.xml
# - name: Set up Maven Central Repo
# uses: actions/setup-java@v1
# with:
# java-version: 1.8
# server-id: sonatype-nexus-staging
# server-username: ${{ secrets.OSSRH_USER }}
# server-password: ${{ secrets.OSSRH_PASSWORD }}
# gpg-passphrase: ${{ secrets.GPG_PASSWORD }}
# - name: Release Maven package
# uses: WasiqB/maven-publish-action@v1
# with:
# maven_args: -Dmaven.test.skip=true
# gpg_private_key: ${{ secrets.GPG_SECRET }}
# gpg_passphrase: ${{ secrets.GPG_PASSWORD }}
# nexus_username: ${{ secrets.OSSRH_USER }}
# nexus_password: ${{ secrets.OSSRH_PASSWORD }}
# - uses: softprops/action-gh-release@v1
# with:
# draft: false
# generate_release_notes: true
# # mvn clean deploy -Pdeploy -Dmaven.test.skip=true
================================================
FILE: .gitignore
================================================
/.idea/
/target/
/logs/
*.iml
*/.DS_Store
.DS_Store
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright © [SonicCloudOrg] Sonic Project
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.
================================================
FILE: README.md
================================================
<p align="center">
<img width="80px" src="https://raw.githubusercontent.com/SonicCloudOrg/sonic-server/main/logo.png">
</p>
<p align="center">🎉The Sonic UIAutomation Driver Core</p>
<p align="center">
<span>English |</span>
<a href="https://github.com/SonicCloudOrg/sonic-driver-core/blob/main/README_CN.md">
简体中文
</a>
</p>
<p align="center">
<a href="#">
<img src="https://img.shields.io/maven-central/v/io.github.soniccloudorg/sonic-driver-core">
</a>
<a href="#">
<img src="https://img.shields.io/github/commit-activity/m/SonicCloudOrg/sonic-driver-core">
</a>
<a href="https://app.fossa.com/projects/git%2Bgithub.com%2FSonicCloudOrg%2Fsonic-driver-core?ref=badge_shield" alt="FOSSA Status"><img src="https://app.fossa.com/api/projects/git%2Bgithub.com%2FSonicCloudOrg%2Fsonic-driver-core.svg?type=shield"/></a>
<a href="https://codecov.io/gh/SonicCloudOrg/sonic-driver-core">
<img src="https://codecov.io/gh/SonicCloudOrg/sonic-driver-core/branch/main/graph/badge.svg?token=PZ5295WQP1">
</a>
</p>
<p align="center">
<a href="https://github.com/SonicCloudOrg/sonic-driver-core">
<img src="https://www.oscs1024.com/platform/badge/SonicCloudOrg/sonic-driver-core.svg?size=large">
</a>
</p>
## What is sonic-driver-core?
sonic-driver-core can be separated from appium and interact directly with webdriveragent or uiautomator2, which reduces the communication layer of appium and makes the test faster and more stable.
## Use in Java code
### Add dependency
#### Maven Central
```xml
<dependency>
<groupId>io.github.soniccloudorg</groupId>
<artifactId>sonic-driver-core</artifactId>
<version>1.1.30</version>
</dependency>
```
#### Gradle
```
implementation 'io.github.soniccloudorg:sonic-driver-core:1.1.30'
```
### Code
```java
package org.cloud.sonic.driver.ios;
import org.cloud.sonic.driver.ios.enums.IOSSelector;
import org.cloud.sonic.driver.common.tool.SonicRespException;
public class MyTest {
public void test() throws SonicRespException {
IOSDriver iosDriver = new IOSDriver("http://localhost:8100");
iosDriver.showLog();
//touch
iosDriver.swipe(100, 256, 50, 256);
iosDriver.tap(150, 81);
iosDriver.longPress(150, 281, 1500);
iosDriver.performTouchAction(new TouchActions().press(50, 256).wait(50).move(100, 256).wait(10).release());
//element
iosDriver.findElement(IOSSelector.XPATH, "//XCUIElementTypeTextField").click();
//more...
}
}
```
## More Example
See [Here](https://github.com/SonicCloudOrg/sonic-uiautomation-example/tree/main/java-example).
## Document
See [Here](https://sonic-cloud.cn/sdc/re-sdc.html).
## Sponsors
Thank you to all our sponsors!
[<img src="https://ceshiren.com/uploads/default/original/3X/7/0/70299922296e93e2dcab223153a928c4bfb27df9.jpeg" alt="霍格沃兹测试开发学社" width="500">](https://qrcode.testing-studio.com/f?from=sonic&url=https://ceshiren.com)
> [霍格沃兹测试开发学社](https://qrcode.testing-studio.com/f?from=sonic&url=https://ceshiren.com)是业界领先的测试开发技术高端教育品牌,隶属于[测吧(北京)科技有限公司](http://qrcode.testing-studio.com/f?from=sonic&url=https://www.testing-studio.com) 。学院课程由一线大厂测试经理与资深测试开发专家参与研发,实战驱动。课程涵盖 web/app 自动化测试、接口测试、性能测试、安全测试、持续集成/持续交付/DevOps,测试左移&右移、精准测试、测试平台开发、测试管理等内容,帮助测试工程师实现测试开发技术转型。通过优秀的学社制度(奖学金、内推返学费、行业竞赛等多种方式)来实现学员、学社及用人企业的三方共赢。[进入测试开发技术能力测评!](https://qrcode.testing-studio.com/f?from=sonic&url=https://ceshiren.com/t/topic/14940)
## LICENSE
[License](LICENSE)
[](https://app.fossa.com/projects/git%2Bgithub.com%2FSonicCloudOrg%2Fsonic-driver-core?ref=badge_large)
================================================
FILE: README_CN.md
================================================
<p align="center">
<img width="80px" src="https://raw.githubusercontent.com/SonicCloudOrg/sonic-server/main/logo.png">
</p>
<p align="center">🎉Sonic UI自动化Driver核心</p>
<p align="center">
<a href="https://github.com/SonicCloudOrg/sonic-driver-core/blob/main/README.md">
English
</a>
<span>| 简体中文</span>
</p>
<p align="center">
<a href="#">
<img src="https://img.shields.io/maven-central/v/io.github.soniccloudorg/sonic-driver-core">
</a>
<a href="#">
<img src="https://img.shields.io/github/commit-activity/m/SonicCloudOrg/sonic-driver-core">
</a>
<a href="https://codecov.io/gh/SonicCloudOrg/sonic-driver-core">
<img src="https://codecov.io/gh/SonicCloudOrg/sonic-driver-core/branch/main/graph/badge.svg?token=PZ5295WQP1">
</a>
</p>
<p align="center">
<a href="https://github.com/SonicCloudOrg/sonic-driver-core">
<img src="https://www.oscs1024.com/platform/badge/SonicCloudOrg/sonic-driver-core.svg?size=large">
</a>
</p>
## sonic-driver-core是什么?
sonic-driver-core可以脱离Appium,直接与WebDriverAgent或UIautomator2交互,减少了Appium的通信层,让测试更快更稳定。
## 在你的Java代码中使用
### 引用库
#### Maven
```xml
<dependency>
<groupId>io.github.soniccloudorg</groupId>
<artifactId>sonic-driver-core</artifactId>
<version>1.1.30</version>
</dependency>
```
#### Gradle
```
implementation 'io.github.soniccloudorg:sonic-driver-core:1.1.30'
```
### 代码
```java
package org.cloud.sonic.driver.ios;
import org.cloud.sonic.driver.common.tool.SonicRespException;
public class MyTest {
public void test() throws SonicRespException {
IOSDriver iosDriver = new IOSDriver("http://localhost:8100");
iosDriver.showLog();
//touch
iosDriver.swipe(100, 256, 50, 256);
iosDriver.tap(150, 81);
iosDriver.longPress(150, 281, 1500);
iosDriver.performTouchAction(new TouchActions().press(50, 256).wait(50).move(100, 256).wait(10).release());
//element
iosDriver.findElement(IOSSelector.XPATH, "//XCUIElementTypeTextField").click();
//更多...
}
}
```
## 更多例子
查看 [这里](https://github.com/SonicCloudOrg/sonic-uiautomation-example/tree/main/java-example).
## 文档
查看 [这里](https://sonic-cloud.cn/sdc/re-sdc.html).
## 赞助商
感谢所有赞助商!
[<img src="https://ceshiren.com/uploads/default/original/3X/7/0/70299922296e93e2dcab223153a928c4bfb27df9.jpeg" alt="霍格沃兹测试开发学社" width="500">](https://qrcode.testing-studio.com/f?from=sonic&url=https://ceshiren.com)
> [霍格沃兹测试开发学社](https://qrcode.testing-studio.com/f?from=sonic&url=https://ceshiren.com)是业界领先的测试开发技术高端教育品牌,隶属于[测吧(北京)科技有限公司](http://qrcode.testing-studio.com/f?from=sonic&url=https://www.testing-studio.com) 。学院课程由一线大厂测试经理与资深测试开发专家参与研发,实战驱动。课程涵盖 web/app 自动化测试、接口测试、性能测试、安全测试、持续集成/持续交付/DevOps,测试左移&右移、精准测试、测试平台开发、测试管理等内容,帮助测试工程师实现测试开发技术转型。通过优秀的学社制度(奖学金、内推返学费、行业竞赛等多种方式)来实现学员、学社及用人企业的三方共赢。[进入测试开发技术能力测评!](https://qrcode.testing-studio.com/f?from=sonic&url=https://ceshiren.com/t/topic/14940)
## 开源许可协议
[License](LICENSE)
================================================
FILE: pom.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>io.github.soniccloudorg</groupId>
<artifactId>sonic-driver-core</artifactId>
<version>1.1.33</version>
<name>sonic-driver-core</name>
<description>The Sonic Project UIAutomation Driver Core for Android, iOS, Windows, Mac and so on.</description>
<url>https://github.com/SonicCloudOrg/sonic-driver-core</url>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<scm>
<tag>main</tag>
<url>https://github.com/SonicCloudOrg/sonic-driver-core</url>
<connection>https://github.com/SonicCloudOrg/sonic-driver-core</connection>
<developerConnection>https://github.com/SonicCloudOrg/sonic-driver-core</developerConnection>
</scm>
<licenses>
<license>
<name>APACHE2</name>
<url>https://github.com/SonicCloudOrg/sonic-driver-core/blob/main/LICENSE</url>
</license>
</licenses>
<issueManagement>
<system>Github Issue</system>
<url>https://github.com/SonicCloudOrg/sonic-driver-core/issues</url>
</issueManagement>
<distributionManagement>
<snapshotRepository>
<id>ossrh</id>
<url>https://s01.oss.sonatype.org/content/repositories/snapshots</url>
</snapshotRepository>
<repository>
<id>ossrh</id>
<url>https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository>
</distributionManagement>
<developers>
<developer>
<name>SonicCloudOrg</name>
<email>soniccloudorg@163.com</email>
<timezone>+8</timezone>
<roles>
<role>Developer</role>
</roles>
</developer>
</developers>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.36</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-http</artifactId>
<version>5.8.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.17.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.56</version>
</dependency>
<dependency>
<groupId>org.java-websocket</groupId>
<artifactId>Java-WebSocket</artifactId>
<version>1.5.4</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>4.6.1</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.jsoup/jsoup -->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.15.4</version>
</dependency>
</dependencies>
<profiles>
<profile>
<id>deploy</id>
<build>
<plugins>
<!-- Source plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Javadoc plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.4</version>
<configuration>
<additionalparam>-Xdoclint:none</additionalparam>
</configuration>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- GPG plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
<configuration>
<gpgArguments>
<arg>--pinentry-mode</arg>
<arg>loopback</arg>
</gpgArguments>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<version>2.7</version>
<configuration>
<formats>
<format>html</format>
<format>xml</format>
</formats>
<check/>
</configuration>
</plugin>
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.6.8</version>
<extensions>true</extensions>
<configuration>
<serverId>ossrh</serverId>
<nexusUrl>https://s01.oss.sonatype.org/</nexusUrl>
<autoReleaseAfterClose>true</autoReleaseAfterClose>
</configuration>
</plugin>
</plugins>
</build>
</project>
================================================
FILE: src/main/java/org/cloud/sonic/driver/android/AndroidDriver.java
================================================
/*
* Copyright (C) [SonicCloudOrg] Sonic Project
*
* 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 org.cloud.sonic.driver.android;
import com.alibaba.fastjson.JSONObject;
import org.cloud.sonic.driver.android.enmus.AndroidSelector;
import org.cloud.sonic.driver.android.service.AndroidElement;
import org.cloud.sonic.driver.android.service.UiaClient;
import org.cloud.sonic.driver.android.service.impl.AndroidElementImpl;
import org.cloud.sonic.driver.android.service.impl.UiaClientImpl;
import org.cloud.sonic.driver.common.enums.PasteboardType;
import org.cloud.sonic.driver.common.models.WindowSize;
import org.cloud.sonic.driver.common.tool.RespHandler;
import org.cloud.sonic.driver.common.tool.SonicRespException;
import java.util.List;
/**
* @author Eason
* android driver
*/
public class AndroidDriver {
private UiaClient uiaClient;
/**
* Init android driver.
*
* @param url
* @throws SonicRespException
*/
public AndroidDriver(String url) throws SonicRespException {
this(url, RespHandler.DEFAULT_REQUEST_TIMEOUT);
}
/**
* Init android driver.
*
* @param url
* @param timeOut
* @throws SonicRespException
*/
public AndroidDriver(String url, int timeOut) throws SonicRespException {
this(url, timeOut, new JSONObject());
}
/**
* Init android driver.
*
* @param url
* @param cap
* @throws SonicRespException
*/
public AndroidDriver(String url, JSONObject cap) throws SonicRespException {
this(url, RespHandler.DEFAULT_REQUEST_TIMEOUT, cap);
}
/**
* Init android driver.
*
* @param url
* @param timeOut
* @param cap
* @throws SonicRespException
*/
public AndroidDriver(String url, int timeOut, JSONObject cap) throws SonicRespException {
uiaClient = new UiaClientImpl();
uiaClient.setRemoteUrl(url);
uiaClient.setGlobalTimeOut(timeOut);
uiaClient.newSession(cap);
}
/**
* Get uia2 client.
*
* @return
*/
public UiaClient getUiaClient() {
return uiaClient;
}
/**
* get uia2 sessionId.
*
* @return
*/
public String getSessionId() {
return uiaClient.getSessionId();
}
/**
* destroy sessionId.
*
* @throws SonicRespException
*/
public void closeDriver() throws SonicRespException {
uiaClient.closeSession();
}
/**
* show log.
*/
public void showLog() {
uiaClient.showLog();
}
/**
* disable log.
*/
public void disableLog() {
uiaClient.disableLog();
}
/**
* get device window size.
*
* @return
* @throws SonicRespException
*/
public WindowSize getWindowSize() throws SonicRespException {
return uiaClient.getWindowSize();
}
/**
* send key without element.
*
* @param text
* @throws SonicRespException
*/
public void sendKeys(String text) throws SonicRespException {
sendKeys(text, false);
}
/**
* send key without element.
*
* @param text
* @param isCover
* @throws SonicRespException
*/
public void sendKeys(String text, boolean isCover) throws SonicRespException {
uiaClient.sendKeys(text, isCover);
}
/**
* set pasteboard.
*
* @param contentType
* @param content
* @throws SonicRespException
*/
public void setPasteboard(String contentType, String content) throws SonicRespException {
uiaClient.setPasteboard(contentType, content);
}
/**
* set pasteboard.
*
* @param pasteboardType
* @param content
* @throws SonicRespException
*/
public void setPasteboard(PasteboardType pasteboardType, String content) throws SonicRespException {
setPasteboard(pasteboardType.getType(), content);
}
/**
* get pasteboard.
*
* @param contentType
* @return
* @throws SonicRespException
*/
public byte[] getPasteboard(String contentType) throws SonicRespException {
return uiaClient.getPasteboard(contentType);
}
/**
* get pasteboard.
*
* @param pasteboardType
* @return
* @throws SonicRespException
*/
public byte[] getPasteboard(PasteboardType pasteboardType) throws SonicRespException {
return getPasteboard(pasteboardType.getType());
}
/**
* get page source.
*
* @return
* @throws SonicRespException
*/
public String getPageSource() throws SonicRespException {
return uiaClient.pageSource();
}
/**
* set default FindElement retry time and interval.
*
* @param retry
* @param interval
*/
public void setDefaultFindElementInterval(Integer retry, Integer interval) {
uiaClient.setDefaultFindElementInterval(retry, interval);
}
/**
* find element in device.
*
* @param androidSelector
* @param value
* @return
* @throws SonicRespException
*/
public AndroidElement findElement(AndroidSelector androidSelector, String value) throws SonicRespException {
return findElement(androidSelector, value, null);
}
/**
* find element in device.
*
* @param uiaElementID This ID is the id returned by uia after finding the control
* @return
* @throws SonicRespException
*/
public AndroidElement findElement(String uiaElementID) throws SonicRespException {
return new AndroidElementImpl(uiaElementID, uiaClient);
}
/**
* find element in device.
*
* @param selector
* @param value
* @return
* @throws SonicRespException
*/
public AndroidElement findElement(String selector, String value) throws SonicRespException {
return findElement(selector, value, null);
}
/**
* find element in device.
*
* @param androidSelector
* @param value
* @param retry
* @return
* @throws SonicRespException
*/
public AndroidElement findElement(AndroidSelector androidSelector, String value, Integer retry) throws SonicRespException {
return findElement(androidSelector, value, retry, null);
}
/**
* find element in device.
*
* @param selector
* @param value
* @param retry
* @return
* @throws SonicRespException
*/
public AndroidElement findElement(String selector, String value, Integer retry) throws SonicRespException {
return findElement(selector, value, retry, null);
}
/**
* find element in device.
*
* @param androidSelector
* @param value
* @param retry
* @param interval
* @return
* @throws SonicRespException
*/
public AndroidElement findElement(AndroidSelector androidSelector, String value, Integer retry, Integer interval) throws SonicRespException {
return findElement(androidSelector.getSelector(), value, retry, interval);
}
/**
* find element in device.
*
* @param selector
* @param value
* @param retry
* @param interval
* @return
* @throws SonicRespException
*/
public AndroidElement findElement(String selector, String value, Integer retry, Integer interval) throws SonicRespException {
return uiaClient.findElement(selector, value, retry, interval);
}
/**
* find element list in device.
*
* @param androidSelector
* @param value
* @return
* @throws SonicRespException
*/
public List<AndroidElement> findElementList(AndroidSelector androidSelector, String value) throws SonicRespException {
return findElementList(androidSelector, value, null);
}
/**
* find element list in device.
*
* @param selector
* @param value
* @return
* @throws SonicRespException
*/
public List<AndroidElement> findElementList(String selector, String value) throws SonicRespException {
return findElementList(selector, value, null);
}
/**
* find element list in device.
*
* @param androidSelector
* @param value
* @param retry
* @return
* @throws SonicRespException
*/
public List<AndroidElement> findElementList(AndroidSelector androidSelector, String value, Integer retry) throws SonicRespException {
return findElementList(androidSelector, value, retry, null);
}
/**
* find element list in device.
*
* @param selector
* @param value
* @param retry
* @return
* @throws SonicRespException
*/
public List<AndroidElement> findElementList(String selector, String value, Integer retry) throws SonicRespException {
return findElementList(selector, value, retry, null);
}
/**
* find element list in device.
*
* @param androidSelector
* @param value
* @param retry
* @param interval
* @return
* @throws SonicRespException
*/
public List<AndroidElement> findElementList(AndroidSelector androidSelector, String value, Integer retry, Integer interval) throws SonicRespException {
return findElementList(androidSelector.getSelector(), value, retry, interval);
}
/**
* find element list in device.
*
* @param selector
* @param value
* @param retry
* @param interval
* @return
* @throws SonicRespException
*/
public List<AndroidElement> findElementList(String selector, String value, Integer retry, Integer interval) throws SonicRespException {
return uiaClient.findElementList(selector, value, retry, interval);
}
/**
* get screenshot.
*
* @return
* @throws SonicRespException
*/
public byte[] screenshot() throws SonicRespException {
return uiaClient.screenshot();
}
/**
* set appium settings.
*
* @param settings
* @throws SonicRespException
*/
public void setAppiumSettings(JSONObject settings) throws SonicRespException {
uiaClient.setAppiumSettings(settings);
}
/**
* tap position on screen.
*
* @param x
* @param y
* @throws SonicRespException
*/
public void tap(int x, int y) throws SonicRespException {
uiaClient.tap(x, y);
}
/**
* long press position on screen.
*
* @param x
* @param y
* @param ms
* @throws SonicRespException
*/
public void longPress(double x, double y, double ms) throws SonicRespException {
uiaClient.longPress(x, y, ms);
}
/**
* swipe position on screen.
*
* @param fromX
* @param fromY
* @param toX
* @param toY
* @throws SonicRespException
*/
public void swipe(int fromX, int fromY, int toX, int toY) throws SonicRespException {
this.swipe(fromX, fromY, toX, toY, null);
}
/**
* swipe position on screen with target time
*
* @param fromX
* @param fromY
* @param toX
* @param toY
* @param duration
* @throws SonicRespException
*/
public void swipe(int fromX, int fromY, int toX, int toY, Integer duration) throws SonicRespException {
uiaClient.swipe(fromX, fromY, toX, toY, duration);
}
/**
* Performs a long press followed by an immediate drag to a location and releases.
* fromX(Y) are required if elementId is not provided, so do toX(Y) if destElId is not provided.
*
* @param fromX Starting X coordinate
* @param fromY Starting Y coordinate
* @param toX Ending X coordinate
* @param toY Ending Y coordinate
* @param duration Duration of the action in milliseconds
* @param elementId ID of the original element (optional), for specific interaction scenarios
* @param destElId ID of the target element (optional), for specific interaction scenarios
* @throws SonicRespException Throws when the operation fails
*/
public void drag(int fromX, int fromY, int toX, int toY, Integer duration, String elementId, String destElId) throws SonicRespException {
uiaClient.drag(fromX, fromY, toX, toY, duration, elementId, destElId);
}
/**
* Performs a touch action.
* This method delegates to the UIA client's touchAction method to simulate
* a touch event at a specified position on the screen with a given action type.
*
* @param methodType The type of touch action, enumerate in (down, up, move).
* Specific supported types depend on the UIA client's implementation.
* @param x The X coordinate of the touch point.
* @param y The Y coordinate of the touch point.
* @throws SonicRespException If an error occurs while performing the touch action,
* this exception is thrown.
*/
public void touchAction(String methodType, int x, int y) throws SonicRespException {
uiaClient.touchAction(methodType, x, y);
}
}
================================================
FILE: src/main/java/org/cloud/sonic/driver/android/enmus/AndroidSelector.java
================================================
/*
* Copyright (C) [SonicCloudOrg] Sonic Project
*
* 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 org.cloud.sonic.driver.android.enmus;
public enum AndroidSelector {
CLASS_NAME("class name"),
Id("id"),
ACCESSIBILITY_ID("accessibility id"),
XPATH("xpath"),
UIAUTOMATOR("-android uiautomator");
private final String selector;
AndroidSelector(String selector) {
this.selector = selector;
}
public String getSelector() {
return selector;
}
}
================================================
FILE: src/main/java/org/cloud/sonic/driver/android/service/AndroidElement.java
================================================
/*
* Copyright (C) [SonicCloudOrg] Sonic Project
*
* 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 org.cloud.sonic.driver.android.service;
import org.cloud.sonic.driver.common.models.BaseElement;
import org.cloud.sonic.driver.common.tool.SonicRespException;
/**
* @author Eason
* web element interface
*/
public interface AndroidElement extends BaseElement {
void click() throws SonicRespException;
void sendKeys(String text) throws SonicRespException;
void sendKeys(String text, boolean isCover) throws SonicRespException;
void clear() throws SonicRespException;
String getText() throws SonicRespException;
byte[] screenshot() throws SonicRespException;
}
================================================
FILE: src/main/java/org/cloud/sonic/driver/android/service/UiaClient.java
================================================
/*
* Copyright (C) [SonicCloudOrg] Sonic Project
*
* 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 org.cloud.sonic.driver.android.service;
import com.alibaba.fastjson.JSONObject;
import org.cloud.sonic.driver.common.models.WindowSize;
import org.cloud.sonic.driver.common.tool.Logger;
import org.cloud.sonic.driver.common.tool.RespHandler;
import org.cloud.sonic.driver.common.tool.SonicRespException;
import java.util.List;
/**
* @author Eason
* uia client interface
*/
public interface UiaClient {
//Client Setting
void setGlobalTimeOut(int timeOut);
RespHandler getRespHandler();
void setRespHandler(RespHandler respHandler);
Logger getLogger();
void showLog();
void disableLog();
//Session handler.
String getRemoteUrl();
void setRemoteUrl(String remoteUrl);
String getSessionId();
void setSessionId(String sessionId);
void newSession(JSONObject capabilities) throws SonicRespException;
void closeSession() throws SonicRespException;
void checkSessionId() throws SonicRespException;
//window handler.
WindowSize getWindowSize() throws SonicRespException;
//keyboard handler.
void sendKeys(String text, boolean isCover) throws SonicRespException;
void setPasteboard(String contentType, String content) throws SonicRespException;
byte[] getPasteboard(String contentType) throws SonicRespException;
//source handler.
String pageSource() throws SonicRespException;
//element handler.
void setDefaultFindElementInterval(Integer retry, Integer interval);
AndroidElement findElement(String selector, String value, Integer retry, Integer interval) throws SonicRespException;
List<AndroidElement> findElementList(String selector, String value, Integer retry, Integer interval) throws SonicRespException;
//screen handler.
byte[] screenshot() throws SonicRespException;
//appium setting handler.
void setAppiumSettings(JSONObject settings) throws SonicRespException;
void tap(int x, int y) throws SonicRespException;
void longPress(double x, double y, double ms) throws SonicRespException;
void swipe(int fromX, int fromY, int toX, int toY, Integer duration) throws SonicRespException;
void drag(int fromX, int fromY, int toX, int toY, Integer duration, String elementId, String destElId) throws SonicRespException;
// touch handler.
void touchAction(String methodType, int x, int y) throws SonicRespException;
}
================================================
FILE: src/main/java/org/cloud/sonic/driver/android/service/impl/AndroidElementImpl.java
================================================
/*
* Copyright (C) [SonicCloudOrg] Sonic Project
*
* 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 org.cloud.sonic.driver.android.service.impl;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson2.JSON;
import org.cloud.sonic.driver.android.service.AndroidElement;
import org.cloud.sonic.driver.android.service.UiaClient;
import org.cloud.sonic.driver.common.models.BaseResp;
import org.cloud.sonic.driver.common.models.ElementRect;
import org.cloud.sonic.driver.common.tool.Logger;
import org.cloud.sonic.driver.common.tool.SonicRespException;
import java.util.Base64;
public class AndroidElementImpl implements AndroidElement {
private String id;
private UiaClient uiaClient;
private Logger logger;
public AndroidElementImpl(String id, UiaClient uiaClient) {
this.id = id;
this.uiaClient = uiaClient;
logger = uiaClient.getLogger();
}
@Override
public void click() throws SonicRespException {
uiaClient.checkSessionId();
BaseResp b = uiaClient.getRespHandler().getResp(
HttpUtil.createPost(uiaClient.getRemoteUrl() + "/session/"
+ uiaClient.getSessionId() + "/element/" + id + "/click"));
if (b.getErr() == null) {
logger.info("click element %s.", id);
} else {
logger.error("click element %s failed.", id);
throw new SonicRespException(b.getErr().getMessage());
}
}
@Override
public void sendKeys(String text) throws SonicRespException {
sendKeys(text, false);
}
@Override
public void sendKeys(String text, boolean isCover) throws SonicRespException {
uiaClient.checkSessionId();
JSONObject data = new JSONObject();
data.put("text", text);
data.put("replace", isCover);
BaseResp b = uiaClient.getRespHandler().getResp(
HttpUtil.createPost(uiaClient.getRemoteUrl() + "/session/"
+ uiaClient.getSessionId() + "/element/" + id + "/value")
.body(data.toJSONString()), 60000);
if (b.getErr() == null) {
logger.info("send key to %s.", id);
} else {
logger.error("send key to %s failed.", id);
throw new SonicRespException(b.getErr().getMessage());
}
}
@Override
public void clear() throws SonicRespException {
uiaClient.checkSessionId();
BaseResp b = uiaClient.getRespHandler().getResp(
HttpUtil.createPost(uiaClient.getRemoteUrl() + "/session/"
+ uiaClient.getSessionId() + "/element/" + id + "/clear"), 60000);
if (b.getErr() == null) {
logger.info("clear %s.", id);
} else {
logger.error("clear %s failed.", id);
throw new SonicRespException(b.getErr().getMessage());
}
}
@Override
public String getText() throws SonicRespException {
uiaClient.checkSessionId();
BaseResp b = uiaClient.getRespHandler().getResp(
HttpUtil.createGet(uiaClient.getRemoteUrl() + "/session/"
+ uiaClient.getSessionId() + "/element/" + id + "/text"));
if (b.getErr() == null) {
logger.info("get %s text %s.", id, b.getValue().toString());
return b.getValue().toString();
} else {
logger.error("get %s text failed.", id);
throw new SonicRespException(b.getErr().getMessage());
}
}
@Override
public String getAttribute(String name) throws SonicRespException {
uiaClient.checkSessionId();
BaseResp b = uiaClient.getRespHandler().getResp(
HttpUtil.createGet(uiaClient.getRemoteUrl() + "/session/"
+ uiaClient.getSessionId() + "/element/" + id + "/attribute/" + name));
if (b.getErr() == null) {
logger.info("get %s attribute %s result %s.", id, name, b.getValue().toString());
return b.getValue().toString();
} else {
logger.error("get %s attribute failed.", id);
throw new SonicRespException(b.getErr().getMessage());
}
}
@Override
public String getUniquelyIdentifies() throws SonicRespException {
return id;
}
@Override
public ElementRect getRect() throws SonicRespException {
uiaClient.checkSessionId();
BaseResp b = uiaClient.getRespHandler().getResp(
HttpUtil.createGet(uiaClient.getRemoteUrl() + "/session/"
+ uiaClient.getSessionId() + "/element/" + id + "/rect"));
if (b.getErr() == null) {
ElementRect elementRect = JSON.parseObject(b.getValue().toString(), ElementRect.class);
logger.info("get %s rect %s.", id, elementRect.toString());
return elementRect;
} else {
logger.error("get %s rect failed.", id);
throw new SonicRespException(b.getErr().getMessage());
}
}
@Override
public byte[] screenshot() throws SonicRespException {
uiaClient.checkSessionId();
BaseResp b = uiaClient.getRespHandler().getResp(
HttpUtil.createGet(uiaClient.getRemoteUrl() + "/session/"
+ uiaClient.getSessionId() + "/element/" + id + "/screenshot"), 60000);
if (b.getErr() == null) {
logger.info("get element %s screenshot.", id);
return Base64.getMimeDecoder().decode(b.getValue().toString());
} else {
logger.error("get element %s screenshot failed.", id);
throw new SonicRespException(b.getErr().getMessage());
}
}
@Override
public boolean isDisplayed() throws SonicRespException {
String result = getAttribute("displayed");
return Boolean.parseBoolean(result);
}
}
================================================
FILE: src/main/java/org/cloud/sonic/driver/android/service/impl/UiaClientImpl.java
================================================
/*
* Copyright (C) [SonicCloudOrg] Sonic Project
*
* 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 org.cloud.sonic.driver.android.service.impl;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.Method;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.cloud.sonic.driver.android.service.AndroidElement;
import org.cloud.sonic.driver.android.service.UiaClient;
import org.cloud.sonic.driver.common.models.BaseResp;
import org.cloud.sonic.driver.common.models.SessionInfo;
import org.cloud.sonic.driver.common.models.WindowSize;
import org.cloud.sonic.driver.common.tool.Logger;
import org.cloud.sonic.driver.common.tool.RespHandler;
import org.cloud.sonic.driver.common.tool.SonicRespException;
import java.nio.charset.StandardCharsets;
import java.util.*;
public class UiaClientImpl implements UiaClient {
private String remoteUrl;
private String sessionId;
private RespHandler respHandler;
private Logger logger;
private final String LEGACY_WEB_ELEMENT_IDENTIFIER = "ELEMENT";
private final String WEB_ELEMENT_IDENTIFIER = "element-6066-11e4-a52e-4f735466cecf";
private int FIND_ELEMENT_INTERVAL = 3000;
private int FIND_ELEMENT_RETRY = 5;
private WindowSize size;
public UiaClientImpl() {
respHandler = new RespHandler();
logger = new Logger();
}
private void checkBundleId(String bundleId) throws SonicRespException {
if (bundleId == null || bundleId.length() == 0) {
logger.error("bundleId not found.");
throw new SonicRespException("bundleId not found.");
}
}
private String parseElementId(Object o) {
JSONObject jsonObject = (JSONObject) o;
List<String> identifier = Arrays.asList(LEGACY_WEB_ELEMENT_IDENTIFIER, WEB_ELEMENT_IDENTIFIER);
for (String i : identifier) {
String result = jsonObject.getString(i);
if (result != null && result.length() > 0) {
return result;
}
}
return "";
}
@Override
public void setGlobalTimeOut(int timeOut) {
respHandler.setRequestTimeOut(timeOut);
}
@Override
public RespHandler getRespHandler() {
return respHandler;
}
@Override
public void setRespHandler(RespHandler respHandler) {
this.respHandler = respHandler;
}
@Override
public Logger getLogger() {
return logger;
}
@Override
public void showLog() {
logger.showLog();
}
@Override
public void disableLog() {
logger.disableLog();
}
@Override
public String getRemoteUrl() {
return remoteUrl;
}
@Override
public void setRemoteUrl(String remoteUrl) {
this.remoteUrl = remoteUrl;
}
@Override
public String getSessionId() {
return sessionId;
}
@Override
public void setSessionId(String sessionId) {
this.sessionId = sessionId;
}
@Override
public void newSession(JSONObject capabilities) throws SonicRespException {
JSONObject data = new JSONObject();
data.put("capabilities", capabilities);
BaseResp b = respHandler.getResp(HttpUtil.createPost(remoteUrl + "/session").body(data.toJSONString()));
if (b.getErr() == null) {
SessionInfo sessionInfo = JSON.parseObject(b.getValue().toString(), SessionInfo.class);
setSessionId(sessionInfo.getSessionId());
logger.info("start session successful!");
logger.info("session : %s", sessionInfo.getSessionId());
} else {
logger.error("start session failed.");
logger.error("cause: %s", b.getErr().toString());
throw new SonicRespException(b.getErr().getMessage());
}
}
@Override
public void closeSession() throws SonicRespException {
checkSessionId();
respHandler.getResp(HttpUtil.createRequest(Method.DELETE, remoteUrl + "/session/" + sessionId));
logger.info("close session successful!");
}
@Override
public void checkSessionId() throws SonicRespException {
if (sessionId == null || sessionId.length() == 0) {
logger.error("sessionId not found.");
throw new SonicRespException("sessionId not found.");
}
}
@Override
public WindowSize getWindowSize() throws SonicRespException {
if (size == null) {
checkSessionId();
BaseResp b = respHandler.getResp(HttpUtil.createGet(remoteUrl + "/session/" + sessionId + "/window/:windowHandle/size"));
if (b.getErr() == null) {
size = JSON.parseObject(b.getValue().toString(), WindowSize.class);
logger.info("get window size %s.", size.toString());
} else {
logger.error("get window size failed.");
throw new SonicRespException(b.getErr().getMessage());
}
}
return size;
}
@Override
public void sendKeys(String text, boolean isCover) throws SonicRespException {
checkSessionId();
JSONObject data = new JSONObject();
data.put("text", text);
data.put("replace", isCover);
BaseResp b = respHandler.getResp(HttpUtil.createPost(remoteUrl + "/session/" + sessionId + "/keys")
.body(data.toJSONString()));
if (b.getErr() == null) {
logger.info("send key %s.", text);
} else {
logger.error("send key failed.");
throw new SonicRespException(b.getErr().getMessage());
}
}
@Override
public void setPasteboard(String contentType, String content) throws SonicRespException {
checkSessionId();
JSONObject data = new JSONObject();
data.put("contentType", contentType.toUpperCase(Locale.ROOT));
data.put("content", Base64.getEncoder().encodeToString(content.getBytes(StandardCharsets.UTF_8)));
BaseResp b = respHandler.getResp(HttpUtil.createPost(remoteUrl + "/session/" + sessionId + "/appium/device/set_clipboard")
.body(data.toJSONString()));
if (b.getErr() == null) {
logger.info("set pasteboard %s.", content);
} else {
logger.error("set pasteboard failed.");
throw new SonicRespException(b.getErr().getMessage());
}
}
@Override
public byte[] getPasteboard(String contentType) throws SonicRespException {
checkSessionId();
JSONObject data = new JSONObject();
data.put("contentType", contentType.toUpperCase(Locale.ROOT));
BaseResp b = respHandler.getResp(HttpUtil.createPost(remoteUrl + "/session/" + sessionId + "/appium/device/get_clipboard")
.body(data.toJSONString()));
if (b.getErr() == null) {
byte[] result = Base64.getMimeDecoder().decode(b.getValue().toString());
logger.info("get pasteboard length: %d.", result.length);
return result;
} else {
logger.error("get pasteboard failed.");
throw new SonicRespException(b.getErr().getMessage());
}
}
@Override
public String pageSource() throws SonicRespException {
checkSessionId();
BaseResp b = respHandler.getResp(HttpUtil.createGet(remoteUrl + "/session/" + sessionId + "/source"), 60000);
if (b.getErr() == null) {
logger.info("get page source.");
return b.getValue().toString();
} else {
logger.error("get page source failed.");
throw new SonicRespException(b.getErr().getMessage());
}
}
@Override
public void setDefaultFindElementInterval(Integer retry, Integer interval) {
if (retry != null) {
FIND_ELEMENT_RETRY = retry;
}
if (interval != null) {
FIND_ELEMENT_INTERVAL = interval;
}
}
@Override
public AndroidElement findElement(String selector, String value, Integer retry, Integer interval) throws SonicRespException {
AndroidElement androidElement = null;
int wait = 0;
int intervalInit = (interval == null ? FIND_ELEMENT_INTERVAL : interval);
int retryInit = (retry == null ? FIND_ELEMENT_RETRY : retry);
String errMsg = "";
while (wait < retryInit) {
wait++;
checkSessionId();
JSONObject data = new JSONObject();
data.put("strategy", selector);
data.put("selector", value);
BaseResp b = respHandler.getResp(HttpUtil.createPost(remoteUrl + "/session/" + sessionId + "/element")
.body(data.toJSONString()));
if (b.getErr() == null) {
logger.info("find element successful.");
String id = parseElementId(b.getValue());
if (id.length() > 0) {
androidElement = new AndroidElementImpl(id, this);
break;
} else {
logger.error("parse element id %s failed. retried %d times, retry in %d ms.", b.getValue().toString(), wait, intervalInit);
}
} else {
logger.error("element not found. retried %d times, retry in %d ms.", wait, intervalInit);
errMsg = b.getErr().getMessage();
}
if (wait < retryInit) {
try {
Thread.sleep(intervalInit);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
if (androidElement == null) {
throw new SonicRespException(errMsg);
}
return androidElement;
}
@Override
public List<AndroidElement> findElementList(String selector, String value, Integer retry, Integer interval) throws SonicRespException {
List<AndroidElement> androidElementList = new ArrayList<>();
int wait = 0;
int intervalInit = (interval == null ? FIND_ELEMENT_INTERVAL : interval);
int retryInit = (retry == null ? FIND_ELEMENT_RETRY : retry);
String errMsg = "";
while (wait < retryInit) {
wait++;
checkSessionId();
JSONObject data = new JSONObject();
data.put("strategy", selector);
data.put("selector", value);
BaseResp b = respHandler.getResp(HttpUtil.createPost(remoteUrl + "/session/" + sessionId + "/elements")
.body(data.toJSONString()));
if (b.getErr() == null) {
logger.info("find elements successful.");
List<JSONObject> ids = JSON.parseObject(b.getValue().toString(), ArrayList.class);
for (JSONObject ele : ids) {
String id = parseElementId(ele);
if (id.length() > 0) {
androidElementList.add(new AndroidElementImpl(id, this));
} else {
logger.error("parse element id %s failed.", ele);
}
}
if (androidElementList.size() > 0) {
break;
}
} else {
logger.error("elements not found. retried %d times, retry in %d ms.", wait, intervalInit);
errMsg = b.getErr().getMessage();
}
if (wait < retryInit) {
try {
Thread.sleep(intervalInit);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
if (androidElementList.size() == 0) {
throw new SonicRespException(errMsg);
}
return androidElementList;
}
@Override
public byte[] screenshot() throws SonicRespException {
checkSessionId();
BaseResp b = respHandler.getResp(
HttpUtil.createGet(remoteUrl + "/session/" + sessionId + "/screenshot"), 60000);
if (b.getErr() == null) {
logger.info("get screenshot.");
return Base64.getMimeDecoder().decode(b.getValue().toString());
} else {
logger.error("get screenshot failed.");
throw new SonicRespException(b.getErr().getMessage());
}
}
@Override
public void setAppiumSettings(JSONObject settings) throws SonicRespException {
checkSessionId();
JSONObject data = new JSONObject();
data.put("settings", settings);
BaseResp b = respHandler.getResp(HttpUtil.createPost(remoteUrl + "/session/" + sessionId + "/appium/settings")
.body(data.toJSONString()));
if (b.getErr() == null) {
logger.info("set appium settings %s.", settings.toJSONString());
} else {
logger.error("set appium settings failed.");
throw new SonicRespException(b.getErr().getMessage());
}
}
@Override
public void tap(int x, int y) throws SonicRespException {
checkSessionId();
JSONObject data = new JSONObject();
data.put("x", x);
data.put("y", y);
BaseResp b = respHandler.getResp(HttpUtil.createPost(remoteUrl + "/session/" + sessionId + "/appium/tap")
.body(data.toJSONString()));
if (b.getErr() == null) {
logger.info("perform tap action %s.", data.toString());
} else {
logger.error("perform tap action failed.");
throw new SonicRespException(b.getErr().getMessage());
}
}
@Override
public void longPress(double x, double y, double ms) throws SonicRespException {
checkSessionId();
JSONObject data = new JSONObject();
JSONObject touchEventParams = new JSONObject();
touchEventParams.put("x", x);
touchEventParams.put("y", y);
touchEventParams.put("duration", ms);
data.put("params", touchEventParams);
BaseResp b = respHandler.getResp(HttpUtil.createPost(remoteUrl + "/session/" + sessionId + "/touch/longclick")
.body(data.toJSONString()));
if (b.getErr() == null) {
logger.info("perform longPress action %s.", data.toString());
} else {
logger.error("perform longPress action failed.");
throw new SonicRespException(b.getErr().getMessage());
}
}
@Override
public void swipe(int fromX, int fromY, int toX, int toY, Integer duration) throws SonicRespException {
checkSessionId();
JSONObject data = new JSONObject();
data.put("startX", fromX);
data.put("startY", fromY);
data.put("endX", toX);
data.put("endY", toY);
// steps 参数为uiautomator层定义的单位
// example:So for a 100 steps, the swipe will take about 1/2 second to complete.
if (duration == null) {
data.put("steps", 100);
} else {
data.put("steps", duration / 5);
}
BaseResp b = respHandler.getResp(HttpUtil.createPost(remoteUrl + "/session/" + sessionId + "/touch/perform")
.body(data.toJSONString()));
if (b.getErr() == null) {
logger.info("perform swipe action %s.", data.toString());
} else {
logger.error("perform swipe action failed.");
throw new SonicRespException(b.getErr().getMessage());
}
}
@Override
public void drag(int fromX, int fromY, int toX, int toY, Integer duration, String elementId, String destElId) throws SonicRespException {
checkSessionId();
JSONObject data = new JSONObject();
data.put("startX", fromX);
data.put("startY", fromY);
data.put("endX", toX);
data.put("endY", toY);
data.put("steps", duration != null && duration > 0 ? duration / 5 : 100);
data.put("elementId", elementId);
data.put("destElId", destElId);
BaseResp move = respHandler.getResp(HttpUtil.createPost(remoteUrl + "/session/" + sessionId + "/touch/drag").body(data.toJSONString()));
if (move.getErr() == null) {
logger.info("perform drag action %s.", data.toString());
} else {
logger.error("perform drag action failed.");
throw new SonicRespException(move.getErr().getMessage());
}
}
@Override
public void touchAction(String methodType, int x, int y) throws SonicRespException {
checkSessionId();
JSONObject data = new JSONObject();
JSONObject touchEventParams = new JSONObject();
touchEventParams.put("x", x);
touchEventParams.put("y", y);
data.put("params", touchEventParams);
String path = "/touch/down";
switch (methodType) {
case "down":
break;
case "up":
path = "/touch/up";
break;
case "move":
path = "/touch/move";
break;
default:
throw new RuntimeException("methodType error.");
}
BaseResp b = respHandler.getResp(HttpUtil.createPost(remoteUrl + "/session/" + sessionId + path)
.body(data.toJSONString()));
if (b.getErr() == null) {
logger.info(String.format("perform touch %s action %s.", methodType, data));
} else {
logger.error("perform touch %s action failed.", methodType);
throw new SonicRespException(b.getErr().getMessage());
}
}
}
================================================
FILE: src/main/java/org/cloud/sonic/driver/common/enums/PasteboardType.java
================================================
/*
* Copyright (C) [SonicCloudOrg] Sonic Project
*
* 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 org.cloud.sonic.driver.common.enums;
public enum PasteboardType {
PLAIN_TEXT("plaintext"),
IMAGE("image"),
URL("url");
private final String type;
PasteboardType(String pasteboardType) {
this.type = pasteboardType;
}
public String getType() {
return type;
}
}
================================================
FILE: src/main/java/org/cloud/sonic/driver/common/models/BaseElement.java
================================================
package org.cloud.sonic.driver.common.models;
import org.cloud.sonic.driver.common.tool.SonicRespException;
public interface BaseElement {
ElementRect getRect() throws SonicRespException;
String getAttribute(String name) throws SonicRespException;
// the xpath or id or csspath...
String getUniquelyIdentifies() throws SonicRespException;
// List<BaseElement> getChildren() throws SonicRespException;
/**
* Is this element displayed or not?
* This method avoids the problem of having to parse an element's "style" attribute.
*
* @return whether the element is displayed
*/
boolean isDisplayed() throws SonicRespException;
}
================================================
FILE: src/main/java/org/cloud/sonic/driver/common/models/BaseResp.java
================================================
/*
* Copyright (C) [SonicCloudOrg] Sonic Project
*
* 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 org.cloud.sonic.driver.common.models;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Getter
@NoArgsConstructor
public class BaseResp<T> {
private String sessionId;
private ErrorMsg err;
private T value;
public void setErr(ErrorMsg err) {
this.err = err;
}
public void setValue(T value) {
this.value = value;
}
}
================================================
FILE: src/main/java/org/cloud/sonic/driver/common/models/Capabilities.java
================================================
/*
* Copyright (C) [SonicCloudOrg] Sonic Project
*
* 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 org.cloud.sonic.driver.common.models;
import lombok.AllArgsConstructor;
import lombok.ToString;
@ToString
@AllArgsConstructor
public class Capabilities {
private String device;
private String browserName;
private String sdkVersion;
private String CFBundleIdentifier;
}
================================================
FILE: src/main/java/org/cloud/sonic/driver/common/models/ElementRect.java
================================================
/*
* Copyright (C) [SonicCloudOrg] Sonic Project
*
* 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 org.cloud.sonic.driver.common.models;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.ToString;
@Getter
@ToString
@AllArgsConstructor
public class ElementRect {
private int x;
private int y;
private int width;
private int height;
@Getter
@ToString
@AllArgsConstructor
public class IOSRectCenter {
private int x;
private int y;
}
public IOSRectCenter getCenter() {
return new IOSRectCenter(x / 2, y / 2);
}
}
================================================
FILE: src/main/java/org/cloud/sonic/driver/common/models/ErrorMsg.java
================================================
/*
* Copyright (C) [SonicCloudOrg] Sonic Project
*
* 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 org.cloud.sonic.driver.common.models;
import lombok.AllArgsConstructor;
import lombok.ToString;
@ToString
@AllArgsConstructor
public class ErrorMsg {
private String error;
private String message;
private String traceback;
public String getMessage() {
return message;
}
}
================================================
FILE: src/main/java/org/cloud/sonic/driver/common/models/SessionInfo.java
================================================
/*
* Copyright (C) [SonicCloudOrg] Sonic Project
*
* 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 org.cloud.sonic.driver.common.models;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.ToString;
@Getter
@ToString
@AllArgsConstructor
public class SessionInfo {
private String sessionId;
private Capabilities capabilities;
}
================================================
FILE: src/main/java/org/cloud/sonic/driver/common/models/WindowSize.java
================================================
/*
* Copyright (C) [SonicCloudOrg] Sonic Project
*
* 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 org.cloud.sonic.driver.common.models;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.ToString;
@Getter
@ToString
@AllArgsConstructor
public class WindowSize {
private int width;
private int height;
}
================================================
FILE: src/main/java/org/cloud/sonic/driver/common/tool/Logger.java
================================================
/*
* Copyright (C) [SonicCloudOrg] Sonic Project
*
* 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 org.cloud.sonic.driver.common.tool;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Logger {
private SimpleDateFormat formatter;
private boolean isShowLog;
public Logger() {
formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
isShowLog = true;
}
public void showLog() {
isShowLog = true;
}
public void disableLog() {
isShowLog = false;
}
private void print(String level, String msg, Object... args) {
if (isShowLog) {
System.out.println(String.format("[sonic-driver-core] %s [%s] %s",
formatter.format(new Date()), level, String.format(msg, args)));
}
}
public void info(String msg, Object... args) {
print("INFO", msg, args);
}
public void error(String msg, Object... args) {
print("ERROR", msg, args);
}
}
================================================
FILE: src/main/java/org/cloud/sonic/driver/common/tool/RespHandler.java
================================================
/*
* Copyright (C) [SonicCloudOrg] Sonic Project
*
* 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 org.cloud.sonic.driver.common.tool;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.http.HttpException;
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.cloud.sonic.driver.common.models.BaseResp;
import org.cloud.sonic.driver.common.models.ErrorMsg;
import java.util.HashMap;
import java.util.Map;
public class RespHandler {
public static final int DEFAULT_REQUEST_TIMEOUT = 15000;
private int requestTimeout = 15000;
public void setRequestTimeOut(int timeOut) {
requestTimeout = timeOut;
}
public BaseResp getResp(HttpRequest httpRequest) throws SonicRespException {
return getResp(httpRequest, requestTimeout);
}
public BaseResp getResp(HttpRequest httpRequest, int timeout) throws SonicRespException {
synchronized (this) {
try {
return initResp(httpRequest.addHeaders(initHeader()).timeout(timeout).execute().body());
} catch (HttpException | IORuntimeException e) {
e.printStackTrace();
throw new SonicRespException(e.getMessage());
}
}
}
public BaseResp initResp(String response) {
if (response.contains("traceback") || response.contains("stacktrace")) {
return initErrorMsg(response.replace("stacktrace", "traceback"));
} else {
return JSON.parseObject(response, BaseResp.class);
}
}
public Map<String, String> initHeader() {
Map<String, String> headers = new HashMap<>();
headers.put("Content-Type", "application/json; charset=utf-8");
return headers;
}
public BaseResp initErrorMsg(String resp) {
BaseResp err = JSON.parseObject(resp, BaseResp.class);
ErrorMsg errorMsg = JSONObject.parseObject(err.getValue().toString(), ErrorMsg.class);
err.setErr(errorMsg);
err.setValue(null);
return err;
}
}
================================================
FILE: src/main/java/org/cloud/sonic/driver/common/tool/SonicRespException.java
================================================
/*
* Copyright (C) [SonicCloudOrg] Sonic Project
*
* 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 org.cloud.sonic.driver.common.tool;
public class SonicRespException extends Exception {
public SonicRespException(String message) {
super(message);
}
public SonicRespException(String message, Throwable cause) {
super(message, cause);
}
}
================================================
FILE: src/main/java/org/cloud/sonic/driver/ios/IOSDriver.java
================================================
/*
* Copyright (C) [SonicCloudOrg] Sonic Project
*
* 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 org.cloud.sonic.driver.ios;
import com.alibaba.fastjson.JSONObject;
import org.cloud.sonic.driver.common.enums.PasteboardType;
import org.cloud.sonic.driver.common.models.WindowSize;
import org.cloud.sonic.driver.common.tool.RespHandler;
import org.cloud.sonic.driver.common.tool.SonicRespException;
import org.cloud.sonic.driver.ios.enums.*;
import org.cloud.sonic.driver.ios.models.TouchActions;
import org.cloud.sonic.driver.ios.service.IOSElement;
import org.cloud.sonic.driver.ios.service.WdaClient;
import org.cloud.sonic.driver.ios.service.impl.IOSElementImpl;
import org.cloud.sonic.driver.ios.service.impl.WdaClientImpl;
import java.util.List;
/**
* @author Eason
* ios driver
*/
public class IOSDriver {
private WdaClient wdaClient;
/**
* Init ios driver.
*
* @param url
* @throws SonicRespException
*/
public IOSDriver(String url) throws SonicRespException {
this(url, RespHandler.DEFAULT_REQUEST_TIMEOUT);
}
/**
* Init ios driver.
*
* @param url
* @param timeOut
* @throws SonicRespException
*/
public IOSDriver(String url, int timeOut) throws SonicRespException {
this(url, timeOut, new JSONObject());
}
/**
* Init ios driver.
*
* @param url
* @param cap
* @throws SonicRespException
*/
public IOSDriver(String url, JSONObject cap) throws SonicRespException {
this(url, RespHandler.DEFAULT_REQUEST_TIMEOUT, cap);
}
/**
* Init ios driver.
*
* @param url
* @param timeOut
* @param cap
* @throws SonicRespException
*/
public IOSDriver(String url, int timeOut, JSONObject cap) throws SonicRespException {
wdaClient = new WdaClientImpl();
wdaClient.setRemoteUrl(url);
wdaClient.setGlobalTimeOut(timeOut);
wdaClient.newSession(cap);
}
/**
* Get wda client.
*
* @return
*/
public WdaClient getWdaClient() {
return wdaClient;
}
/**
* get wda sessionId.
*
* @return
*/
public String getSessionId() {
return wdaClient.getSessionId();
}
/**
* destroy sessionId.
*
* @throws SonicRespException
*/
public void closeDriver() throws SonicRespException {
wdaClient.closeSession();
}
/**
* show log.
*/
public void showLog() {
wdaClient.showLog();
}
/**
* disable log.
*/
public void disableLog() {
wdaClient.disableLog();
}
/**
* get device window size.
*
* @return
* @throws SonicRespException
*/
public WindowSize getWindowSize() throws SonicRespException {
return wdaClient.getWindowSize();
}
/**
* get device lock status.
*
* @return
* @throws SonicRespException
*/
public boolean isLocked() throws SonicRespException {
return wdaClient.isLocked();
}
/**
* lock device.
*
* @throws SonicRespException
*/
public void lock() throws SonicRespException {
wdaClient.lock();
}
/**
* unlock device.
*
* @throws SonicRespException
*/
public void unlock() throws SonicRespException {
wdaClient.unlock();
}
/**
* tap position on screen.
*
* @param x
* @param y
* @throws SonicRespException
*/
public void tap(int x, int y) throws SonicRespException {
performTouchAction(new TouchActions.FingerTouchAction().press(x, y).release());
}
/**
* double tap position on screen
* @param x
* @param y
* @throws SonicRespException
*/
public void doubleTap(int x, int y) throws SonicRespException {
wdaClient.doubleTap(x,y);
}
/**
* long press position on screen.
*
* @param x
* @param y
* @param ms
* @throws SonicRespException
*/
public void longPress(int x, int y, int ms) throws SonicRespException {
performTouchAction(new TouchActions.FingerTouchAction().press(x, y).wait(ms).release());
}
/**
* swipe position on screen.
*
* @param fromX
* @param fromY
* @param toX
* @param toY
* @throws SonicRespException
*/
public void swipe(int fromX, int fromY, int toX, int toY) throws SonicRespException {
performTouchAction(new TouchActions.FingerTouchAction().press(fromX, fromY).wait(300).move(toX, toY).wait(10).release());
}
/**
* swipe position on screen with target time
*
* @param fromX
* @param fromY
* @param toX
* @param toY
* @param duration 滑动完成的时间,单位为毫秒
* @throws SonicRespException
*/
public void swipe(double fromX, double fromY, double toX, double toY, double duration) throws SonicRespException {
wdaClient.swipe(fromX, fromY, toX, toY, duration);
}
/**
* perform touch action.
*
* @param touchActions
* @throws SonicRespException
*/
public void performTouchAction(TouchActions touchActions) throws SonicRespException {
wdaClient.performTouchAction(touchActions);
}
public void performTouchAction(TouchActions.FingerTouchAction fingerTouchActions) throws SonicRespException {
performTouchAction(new TouchActions(fingerTouchActions));
}
/**
* press system button.
*
* @param systemButton
* @throws SonicRespException
*/
public void pressButton(String systemButton) throws SonicRespException {
wdaClient.pressButton(systemButton);
}
/**
* press system button.
*
* @param systemButton
* @throws SonicRespException
*/
public void pressButton(SystemButton systemButton) throws SonicRespException {
pressButton(systemButton.getButton());
}
/**
* send key without element.
*
* @param text
* @throws SonicRespException
*/
public void sendKeys(String text) throws SonicRespException {
sendKeys(text, 3);
}
/**
* send key without element.
*
* @param text
* @param frequency
* @throws SonicRespException
*/
public void sendKeys(String text, int frequency) throws SonicRespException {
wdaClient.sendKeys(text, frequency);
}
/**
* send key without element.
*
* @param text
* @throws SonicRespException
*/
public void sendKeys(TextKey text) throws SonicRespException {
sendKeys(text, 3);
}
/**
* send key without element.
*
* @param text
* @param frequency
* @throws SonicRespException
*/
public void sendKeys(TextKey text, int frequency) throws SonicRespException {
sendKeys(text.getKey(), frequency);
}
/**
* set pasteboard.
*
* @param contentType
* @param content
* @throws SonicRespException
*/
public void setPasteboard(String contentType, String content) throws SonicRespException {
wdaClient.setPasteboard(contentType, content);
}
/**
* set pasteboard.
*
* @param pasteboardType
* @param content
* @throws SonicRespException
*/
public void setPasteboard(PasteboardType pasteboardType, String content) throws SonicRespException {
setPasteboard(pasteboardType.getType(), content);
}
/**
* get pasteboard.
*
* @param contentType
* @return
* @throws SonicRespException
*/
public byte[] getPasteboard(String contentType) throws SonicRespException {
return wdaClient.getPasteboard(contentType);
}
/**
* get pasteboard.
*
* @param pasteboardType
* @return
* @throws SonicRespException
*/
public byte[] getPasteboard(PasteboardType pasteboardType) throws SonicRespException {
return getPasteboard(pasteboardType.getType());
}
/**
* get page source.
*
* @return
* @throws SonicRespException
*/
public String getPageSource() throws SonicRespException {
return wdaClient.pageSource();
}
/**
* send siri command.
*
* @param command
* @throws SonicRespException
*/
public void sendSiriCommand(String command) throws SonicRespException {
wdaClient.sendSiriCommand(command);
}
/**
* activate app.
*
* @param bundleId
* @throws SonicRespException
*/
public void appActivate(String bundleId) throws SonicRespException {
wdaClient.appActivate(bundleId);
}
/**
* terminate app and get status.
*
* @param bundleId
* @return
* @throws SonicRespException
*/
public boolean appTerminate(String bundleId) throws SonicRespException {
return wdaClient.appTerminate(bundleId);
}
/**
* run app background in seconds.
*
* @param duration
* @throws SonicRespException
*/
public void appRunBackground(int duration) throws SonicRespException {
wdaClient.appRunBackground(duration);
}
/**
* reset app auth source.
*
* @param resource
* @throws SonicRespException
*/
public void appAuthReset(int resource) throws SonicRespException {
wdaClient.appAuthReset(resource);
}
/**
* reset app auth source.
*
* @param authResource
* @throws SonicRespException
*/
public void appAuthReset(AuthResource authResource) throws SonicRespException {
appAuthReset(authResource.getResource());
}
/**
* set default FindElement retry time and interval.
*
* @param retry
* @param interval
*/
public void setDefaultFindElementInterval(Integer retry, Integer interval) {
wdaClient.setDefaultFindElementInterval(retry, interval);
}
/**
* find element in device.
*
* @param iosSelector
* @param value
* @return
* @throws SonicRespException
*/
public IOSElement findElement(IOSSelector iosSelector, String value) throws SonicRespException {
return findElement(iosSelector, value, null);
}
/**
* find element in device.
*
* @param wdaElementID This id is the id returned by the wda lookup control
* @return
* @throws SonicRespException
*/
public IOSElement findElement(String wdaElementID) throws SonicRespException {
return new IOSElementImpl(wdaElementID, wdaClient);
}
/**
* find element in device.
*
* @param xcuiElementType
* @return
* @throws SonicRespException
*/
public IOSElement findElement(XCUIElementType xcuiElementType) throws SonicRespException {
return findElement(xcuiElementType, null);
}
/**
* find element in device.
*
* @param selector
* @param value
* @return
* @throws SonicRespException
*/
public IOSElement findElement(String selector, String value) throws SonicRespException {
return findElement(selector, value, null);
}
/**
* find element in device.
*
* @param iosSelector
* @param value
* @param retry
* @return
* @throws SonicRespException
*/
public IOSElement findElement(IOSSelector iosSelector, String value, Integer retry) throws SonicRespException {
return findElement(iosSelector, value, retry, null);
}
/**
* find element in device.
*
* @param xcuiElementType
* @param retry
* @return
* @throws SonicRespException
*/
public IOSElement findElement(XCUIElementType xcuiElementType, Integer retry) throws SonicRespException {
return findElement(xcuiElementType, retry, null);
}
/**
* find element in device.
*
* @param selector
* @param value
* @param retry
* @return
* @throws SonicRespException
*/
public IOSElement findElement(String selector, String value, Integer retry) throws SonicRespException {
return findElement(selector, value, retry, null);
}
/**
* find element in device.
*
* @param iosSelector
* @param value
* @param retry
* @param interval
* @return
* @throws SonicRespException
*/
public IOSElement findElement(IOSSelector iosSelector, String value, Integer retry, Integer interval) throws SonicRespException {
return findElement(iosSelector.getSelector(), value, retry, interval);
}
/**
* find element in device.
*
* @param xcuiElementType
* @param retry
* @param interval
* @return
* @throws SonicRespException
*/
public IOSElement findElement(XCUIElementType xcuiElementType, Integer retry, Integer interval) throws SonicRespException {
return findElement(IOSSelector.CLASS_NAME.getSelector(), xcuiElementType.getType(), retry, interval);
}
/**
* find element in device.
*
* @param selector
* @param value
* @param retry
* @param interval
* @return
* @throws SonicRespException
*/
public IOSElement findElement(String selector, String value, Integer retry, Integer interval) throws SonicRespException {
return wdaClient.findElement(selector, value, retry, interval);
}
/**
* find element list in device.
*
* @param iosSelector
* @param value
* @return
* @throws SonicRespException
*/
public List<IOSElement> findElementList(IOSSelector iosSelector, String value) throws SonicRespException {
return findElementList(iosSelector, value, null);
}
/**
* find element list in device.
*
* @param xcuiElementType
* @return
* @throws SonicRespException
*/
public List<IOSElement> findElementList(XCUIElementType xcuiElementType) throws SonicRespException {
return findElementList(xcuiElementType, null);
}
/**
* find element list in device.
*
* @param selector
* @param value
* @return
* @throws SonicRespException
*/
public List<IOSElement> findElementList(String selector, String value) throws SonicRespException {
return findElementList(selector, value, null);
}
/**
* find element list in device.
*
* @param iosSelector
* @param value
* @param retry
* @return
* @throws SonicRespException
*/
public List<IOSElement> findElementList(IOSSelector iosSelector, String value, Integer retry) throws SonicRespException {
return findElementList(iosSelector, value, retry, null);
}
/**
* find element list in device.
*
* @param xcuiElementType
* @param retry
* @return
* @throws SonicRespException
*/
public List<IOSElement> findElementList(XCUIElementType xcuiElementType, Integer retry) throws SonicRespException {
return findElementList(xcuiElementType, retry, null);
}
/**
* find element list in device.
*
* @param selector
* @param value
* @param retry
* @return
* @throws SonicRespException
*/
public List<IOSElement> findElementList(String selector, String value, Integer retry) throws SonicRespException {
return findElementList(selector, value, retry, null);
}
/**
* find element list in device.
*
* @param iosSelector
* @param value
* @param retry
* @param interval
* @return
* @throws SonicRespException
*/
public List<IOSElement> findElementList(IOSSelector iosSelector, String value, Integer retry, Integer interval) throws SonicRespException {
return findElementList(iosSelector.getSelector(), value, retry, interval);
}
/**
* find element list in device.
*
* @param xcuiElementType
* @param retry
* @param interval
* @return
* @throws SonicRespException
*/
public List<IOSElement> findElementList(XCUIElementType xcuiElementType, Integer retry, Integer interval) throws SonicRespException {
return findElementList(IOSSelector.CLASS_NAME.getSelector(), xcuiElementType.getType(), retry, interval);
}
/**
* find element list in device.
*
* @param selector
* @param value
* @param retry
* @param interval
* @return
* @throws SonicRespException
*/
public List<IOSElement> findElementList(String selector, String value, Integer retry, Integer interval) throws SonicRespException {
return wdaClient.findElementList(selector, value, retry, interval);
}
/**
* get current active element
* @return
* @throws SonicRespException
*/
public IOSElement activeElement() throws SonicRespException{
return wdaClient.activeElement();
}
/**
* get screenshot.
*
* @return
* @throws SonicRespException
*/
public byte[] screenshot() throws SonicRespException {
return wdaClient.screenshot();
}
/**
* set appium settings.
*
* @param settings
* @throws SonicRespException
*/
public void setAppiumSettings(JSONObject settings) throws SonicRespException {
wdaClient.setAppiumSettings(settings);
}
/**
* rotate screen orientation
* @throws SonicRespException
*/
public void rotate(Orientation orientation) throws SonicRespException {
wdaClient.rotate(orientation);
}
public Orientation getRotate() throws SonicRespException {
return wdaClient.getRotate();
}
}
================================================
FILE: src/main/java/org/cloud/sonic/driver/ios/enums/ActionType.java
================================================
/*
* Copyright (C) [SonicCloudOrg] Sonic Project
*
* 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 org.cloud.sonic.driver.ios.enums;
public enum ActionType {
PRESS("pointerDown"),
WAIT("pause"),
MOVE("pointerMove"),
RELEASE("pointerUp");
private final String type;
ActionType(String type) {
this.type = type;
}
public String getType() {
return type;
}
}
================================================
FILE: src/main/java/org/cloud/sonic/driver/ios/enums/AuthResource.java
================================================
/*
* Copyright (C) [SonicCloudOrg] Sonic Project
*
* 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 org.cloud.sonic.driver.ios.enums;
public enum AuthResource {
CONTACTS(1),
CALENDAR(2),
REMINDERS(3),
PHOTOS(4),
MICROPHONE(5),
CAMERA(6),
MEDIA_LIBRARY(7),
HOME_KIT(8),
SYSTEM_ROOT_DIRECTORY(0x40000000),
USER_DESKTOP_DIRECTORY(0x40000001),
USER_DOWNLOADS_DIRECTORY(0x40000002),
USER_DOCUMENTS_DIRECTORY(0x40000003),
BLUETOOTH(-0x40000000),
KEYBOARD_NETWORK(-0x40000001),
LOCATION(-0x40000002),
HEALTH(-0x40000003);
private final int resource;
AuthResource(int resource) {
this.resource = resource;
}
public int getResource() {
return resource;
}
}
================================================
FILE: src/main/java/org/cloud/sonic/driver/ios/enums/IOSSelector.java
================================================
/*
* Copyright (C) [SonicCloudOrg] Sonic Project
*
* 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 org.cloud.sonic.driver.ios.enums;
public enum IOSSelector {
CLASS_NAME("class name"),
NAME("name"),
Id("id"),
ACCESSIBILITY_ID("accessibility id"),
XPATH("xpath"),
PREDICATE("predicate string"),
CLASS_CHAIN("class chain"),
LINK_TEXT("link text"),
PARTIAL_LINK_TEXT("partial link text");
private final String selector;
IOSSelector(String selector) {
this.selector = selector;
}
public String getSelector() {
return selector;
}
}
================================================
FILE: src/main/java/org/cloud/sonic/driver/ios/enums/Orientation.java
================================================
package org.cloud.sonic.driver.ios.enums;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import java.util.HashMap;
public enum Orientation {
UNKNOWN(0),
PORTRAIT(1),
PORTRAITUPSIDEDOWN(2),
LANDSCAPELEFT(3),
LANDSCAPERIGHT(4);
private final int orientation;
Orientation(int orientation) {
this.orientation = orientation;
}
public JSONObject getValue() {
JSONObject value = new JSONObject();
value.put("x",0);
value.put("y",0);
switch (this.orientation) {
case 1:
value.put("z",0);
break;
case 2:
value.put("z",180);
break;
case 3:
value.put("z",90);
break;
case 4:
value.put("z",270);
break;
}
return value;
}
}
================================================
FILE: src/main/java/org/cloud/sonic/driver/ios/enums/SystemButton.java
================================================
/*
* Copyright (C) [SonicCloudOrg] Sonic Project
*
* 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 org.cloud.sonic.driver.ios.enums;
public enum SystemButton {
HOME("home"),
VOLUME_UP("volumeUp"),
VOLUME_DOWN("volumeDown");
private final String button;
SystemButton(String button) {
this.button = button;
}
public String getButton() {
return button;
}
}
================================================
FILE: src/main/java/org/cloud/sonic/driver/ios/enums/TextKey.java
================================================
/*
* Copyright (C) [SonicCloudOrg] Sonic Project
*
* 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 org.cloud.sonic.driver.ios.enums;
public enum TextKey {
BACK_SPACE("\u0008"),
DELETE("\u007F");
private final String key;
TextKey(String key) {
this.key = key;
}
public String getKey() {
return key;
}
}
================================================
FILE: src/main/java/org/cloud/sonic/driver/ios/enums/XCUIElementType.java
================================================
/*
* Copyright (C) [SonicCloudOrg] Sonic Project
*
* 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 org.cloud.sonic.driver.ios.enums;
public enum XCUIElementType {
ANY("XCUIElementTypeAny"),
OTHER("XCUIElementTypeOther"),
APPLICATION("XCUIElementTypeApplication"),
GROUP("XCUIElementTypeGroup"),
WINDOW("XCUIElementTypeWindow"),
SHEET("XCUIElementTypeSheet"),
DRAWER("XCUIElementTypeDrawer"),
ALERT("XCUIElementTypeAlert"),
DIALOG("XCUIElementTypeDialog"),
BUTTON("XCUIElementTypeButton"),
DISCLOSURE_TRIANGLE("XCUIElementTypeDisclosureTriangle"),
POP_UP_BUTTON("XCUIElementTypePopUpButton"),
COMBO_BOX("XCUIElementTypeComboBox"),
MENU_BUTTON("XCUIElementTypeMenuButton"),
TOOLBAR_BUTTON("XCUIElementTypeToolbarButton"),
POPOVER("XCUIElementTypePopover"),
KEYBOARD("XCUIElementTypeKeyboard"),
NAVIGATION_BAR("XCUIElementTypeNavigationBar"),
KEY("XCUIElementTypeKey"),
STATUS_BAR("XCUIElementTypeStatusBar"),
SWITCH("XCUIElementTypeSwitch"),
TOGGLE("XCUIElementTypeToggle"),
LINK("XCUIElementTypeLink"),
IMAGE("XCUIElementTypeImage"),
ICON("XCUIElementTypeIcon"),
SEARCH_FIELD("XCUIElementTypeSearchField"),
STATIC_TEXT("XCUIElementTypeStaticText"),
CHECK_BOX("XCUIElementTypeCheckBox"),
TEXT_VIEW("XCUIElementTypeTextView"),
SEGMENTED_CONTROL("XCUIElementTypeSegmentedControl"),
BROWSER("XCUIElementTypeBrowser"),
COLLECTION_VIEW("XCUIElementTypeCollectionView"),
SLIDER("XCUIElementTypeSlider"),
MAP("XCUIElementTypeMap"),
WEB_VIEW("XCUIElementTypeWebView"),
TIME_LINE("XCUIElementTypeTimeline"),
COLOR_WELL("XCUIElementTypeColorWell"),
HELP_TAG("XCUIElementTypeHelpTag"),
MATTE("XCUIElementTypeMatte"),
DOCK_ITEM("XCUIElementTypeDockItem"),
GRID("XCUIElementTypeGrid"),
CELL("XCUIElementTypeCell"),
HANDLE("XCUIElementTypeHandle"),
STEPPER("XCUIElementTypeStepper"),
TAB("XCUIElementTypeTab"),
TOUCH_BAR("XCUIElementTypeTouchBar"),
STATUS_ITEM("XCUIElementTypeStatusItem"),
LAYOUT_AREA("XCUIElementTypeLayoutArea"),
LAYOUT_ITEM("XCUIElementTypeLayoutItem"),
RULER("XCUIElementTypeRuler"),
RULER_MARKER("XCUIElementTypeRulerMarker"),
RADIO_BUTTON("XCUIElementTypeRadioButton"),
RADIO_GROUP("XCUIElementTypeRadioGroup"),
TAB_BAR("XCUIElementTypeTabBar"),
TAB_GROUP("XCUIElementTypeTabGroup"),
TABLE("XCUIElementTypeTable"),
TABLE_ROW("XCUIElementTypeTableRow"),
TABLE_COLUMN("XCUIElementTypeTableColumn"),
OUTLINE("XCUIElementTypeOutline"),
OUTLINE_ROW("XCUIElementTypeOutlineRow"),
PAGE_INDICATOR("XCUIElementTypePageIndicator"),
PROGRESS_INDICATOR("XCUIElementTypeProgressIndicator"),
ACTIVITY_INDICATOR("XCUIElementTypeActivityIndicator"),
RATING_INDICATOR("XCUIElementTypeRatingIndicator"),
VALUE_INDICATOR("XCUIElementTypeValueIndicator"),
RELEVANCE_INDICATOR("XCUIElementTypeRelevanceIndicator"),
LEVEL_INDICATOR("XCUIElementTypeLevelIndicator"),
SPLIT_GROUP("XCUIElementTypeSplitGroup"),
SPLITTER("XCUIElementTypeSplitter"),
PICKER("XCUIElementTypePicker"),
PICKER_WHEEL("XCUIElementTypePickerWheel"),
DATE_PICKER("XCUIElementTypeDatePicker"),
SCROLL_VIEW("XCUIElementTypeScrollView"),
SCROLL_BAR("XCUIElementTypeScrollBar"),
TEXT_FIELD("XCUIElementTypeTextField"),
SECURE_TEXT_FIELD("XCUIElementTypeSecureTextField"),
MENU("XCUIElementTypeMenu"),
MENU_ITEM("XCUIElementTypeMenuItem"),
MENU_BAR("XCUIElementTypeMenuBar"),
MENU_BAR_ITEM("XCUIElementTypeMenuBarItem"),
INCREMENT_ARROW("XCUIElementTypeIncrementArrow"),
DECREMENT_ARROW("XCUIElementTypeDecrementArrow"),
;
private final String type;
XCUIElementType(String type) {
this.type = type;
}
public String getType() {
return type;
}
}
================================================
FILE: src/main/java/org/cloud/sonic/driver/ios/models/TouchActions.java
================================================
/*
* Copyright (C) [SonicCloudOrg] Sonic Project
*
* 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 org.cloud.sonic.driver.ios.models;
import cn.hutool.core.map.MapUtil;
import lombok.Getter;
import lombok.ToString;
import org.cloud.sonic.driver.ios.enums.ActionType;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Getter
@ToString
public class TouchActions {
private List<FingerTouchAction> actions;
@Getter
@ToString
public static class FingerTouchAction {
private final String id;
private final String type = "pointer";
private final Map<String, String> parameters = MapUtil.of("pointerType", "touch");
private final List<TouchAction> actions;
public FingerTouchAction(String fingerName) {
this.id = "finger-" + fingerName;
actions = new ArrayList<>();
}
public FingerTouchAction() {
this("0");
}
public FingerTouchAction press(int x, int y) {
move(x, y);
TouchAction touchAction = new TouchAction(ActionType.PRESS);
actions.add(touchAction);
return this;
}
public FingerTouchAction wait(int ms) {
PauseAction touchAction = new PauseAction();
touchAction.duration = ms;
actions.add(touchAction);
return this;
}
public FingerTouchAction move(int x, int y) {
MoveAction touchAction = new MoveAction();
touchAction.x = x;
touchAction.y = y;
actions.add(touchAction);
return this;
}
public FingerTouchAction release() {
TouchAction touchAction = new TouchAction(ActionType.RELEASE);
actions.add(touchAction);
return this;
}
}
@Getter
@ToString
public static class TouchAction {
private final String type;
public TouchAction(ActionType actionType) {
this.type = actionType.getType();
}
}
@Getter
@ToString(callSuper = true)
public static class MoveAction extends TouchAction {
private int x;
private int y;
public MoveAction() {
super(ActionType.MOVE);
}
}
@Getter
@ToString(callSuper = true)
public static class PauseAction extends TouchAction {
private int duration;
public PauseAction() {
super(ActionType.WAIT);
}
}
public TouchActions() {
actions = new ArrayList<>();
}
public TouchActions(FingerTouchAction finger) {
this();
this.actions.add(finger);
}
public FingerTouchAction finger(String name) {
FingerTouchAction finger = new FingerTouchAction(name);
actions.add(finger);
return finger;
}
}
================================================
FILE: src/main/java/org/cloud/sonic/driver/ios/service/IOSElement.java
================================================
/*
* Copyright (C) [SonicCloudOrg] Sonic Project
*
* 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 org.cloud.sonic.driver.ios.service;
import org.cloud.sonic.driver.common.models.BaseElement;
import org.cloud.sonic.driver.common.tool.SonicRespException;
/**
* @author Eason
* web element interface
*/
public interface IOSElement extends BaseElement {
void click() throws SonicRespException;
void sendKeys(String text) throws SonicRespException;
void sendKeys(String text, int frequency) throws SonicRespException;
void clear() throws SonicRespException;
String getText() throws SonicRespException;
byte[] screenshot() throws SonicRespException;
}
================================================
FILE: src/main/java/org/cloud/sonic/driver/ios/service/WdaClient.java
================================================
/*
* Copyright (C) [SonicCloudOrg] Sonic Project
*
* 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 org.cloud.sonic.driver.ios.service;
import com.alibaba.fastjson.JSONObject;
import org.cloud.sonic.driver.common.models.WindowSize;
import org.cloud.sonic.driver.common.tool.Logger;
import org.cloud.sonic.driver.common.tool.RespHandler;
import org.cloud.sonic.driver.common.tool.SonicRespException;
import org.cloud.sonic.driver.ios.enums.Orientation;
import org.cloud.sonic.driver.ios.models.TouchActions;
import java.util.List;
/**
* @author Eason
* wda client interface
*/
public interface WdaClient {
//Client Setting
void setGlobalTimeOut(int timeOut);
RespHandler getRespHandler();
void setRespHandler(RespHandler respHandler);
Logger getLogger();
void showLog();
void disableLog();
//Session handler.
String getRemoteUrl();
void setRemoteUrl(String remoteUrl);
String getSessionId();
void setSessionId(String sessionId);
void newSession(JSONObject capabilities) throws SonicRespException;
void closeSession() throws SonicRespException;
void checkSessionId() throws SonicRespException;
//window handler.
WindowSize getWindowSize() throws SonicRespException;
//lock handler.
boolean isLocked() throws SonicRespException;
void lock() throws SonicRespException;
void unlock() throws SonicRespException;
//perform handler.
void performTouchAction(TouchActions touchActions) throws SonicRespException;
//button handler.
void pressButton(String buttonName) throws SonicRespException;
void doubleTap(int x, int y) throws SonicRespException;
//keyboard handler.
void sendKeys(String text, Integer frequency) throws SonicRespException;
void setPasteboard(String contentType, String content) throws SonicRespException;
byte[] getPasteboard(String contentType) throws SonicRespException;
//source handler.
String pageSource() throws SonicRespException;
//siri handler.
void sendSiriCommand(String command) throws SonicRespException;
//app handler.
void appActivate(String bundleId) throws SonicRespException;
boolean appTerminate(String bundleId) throws SonicRespException;
void appRunBackground(int duration) throws SonicRespException;
void appAuthReset(int resource) throws SonicRespException;
//element handler.
void setDefaultFindElementInterval(Integer retry, Integer interval);
IOSElement findElement(String selector, String value, Integer retry, Integer interval) throws SonicRespException;
List<IOSElement> findElementList(String selector, String value, Integer retry, Integer interval) throws SonicRespException;
// get current active element
IOSElement activeElement() throws SonicRespException;
//screen handler.
byte[] screenshot() throws SonicRespException;
//appium setting handler.
void setAppiumSettings(JSONObject settings) throws SonicRespException;
void swipe(double fromX, double fromY, double toX, double toY, double duration) throws SonicRespException;
void rotate(Orientation orientation) throws SonicRespException;
Orientation getRotate() throws SonicRespException;
}
================================================
FILE: src/main/java/org/cloud/sonic/driver/ios/service/impl/IOSElementImpl.java
================================================
/*
* Copyright (C) [SonicCloudOrg] Sonic Project
*
* 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 org.cloud.sonic.driver.ios.service.impl;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson2.JSON;
import org.cloud.sonic.driver.common.models.BaseResp;
import org.cloud.sonic.driver.common.models.ElementRect;
import org.cloud.sonic.driver.common.tool.Logger;
import org.cloud.sonic.driver.common.tool.SonicRespException;
import org.cloud.sonic.driver.ios.service.IOSElement;
import org.cloud.sonic.driver.ios.service.WdaClient;
import java.util.Base64;
public class IOSElementImpl implements IOSElement {
private String id;
private WdaClient wdaClient;
private Logger logger;
public IOSElementImpl(String id, WdaClient wdaClient) {
this.id = id;
this.wdaClient = wdaClient;
logger = wdaClient.getLogger();
}
@Override
public void click() throws SonicRespException {
wdaClient.checkSessionId();
BaseResp b = wdaClient.getRespHandler().getResp(
HttpUtil.createPost(wdaClient.getRemoteUrl() + "/session/"
+ wdaClient.getSessionId() + "/element/" + id + "/click"));
if (b.getErr() == null) {
logger.info("click element %s.", id);
} else {
logger.error("click element %s failed.", id);
throw new SonicRespException(b.getErr().getMessage());
}
}
@Override
public void sendKeys(String text) throws SonicRespException {
sendKeys(text, 3);
}
@Override
public void sendKeys(String text, int frequency) throws SonicRespException {
wdaClient.checkSessionId();
JSONObject data = new JSONObject();
data.put("value", text.split(""));
data.put("frequency", frequency);
BaseResp b = wdaClient.getRespHandler().getResp(
HttpUtil.createPost(wdaClient.getRemoteUrl() + "/session/"
+ wdaClient.getSessionId() + "/element/" + id + "/value")
.body(data.toJSONString()), 60000);
if (b.getErr() == null) {
logger.info("send key to %s.", id);
} else {
logger.error("send key to %s failed.", id);
throw new SonicRespException(b.getErr().getMessage());
}
}
@Override
public void clear() throws SonicRespException {
wdaClient.checkSessionId();
BaseResp b = wdaClient.getRespHandler().getResp(
HttpUtil.createPost(wdaClient.getRemoteUrl() + "/session/"
+ wdaClient.getSessionId() + "/element/" + id + "/clear"), 60000);
if (b.getErr() == null) {
logger.info("clear %s.", id);
} else {
logger.error("clear %s failed.", id);
throw new SonicRespException(b.getErr().getMessage());
}
}
@Override
public String getText() throws SonicRespException {
wdaClient.checkSessionId();
BaseResp b = wdaClient.getRespHandler().getResp(
HttpUtil.createGet(wdaClient.getRemoteUrl() + "/session/"
+ wdaClient.getSessionId() + "/element/" + id + "/text"));
if (b.getErr() == null) {
logger.info("get %s text %s.", id, b.getValue().toString());
return b.getValue().toString();
} else {
logger.error("get %s text failed.", id);
throw new SonicRespException(b.getErr().getMessage());
}
}
@Override
public ElementRect getRect() throws SonicRespException {
wdaClient.checkSessionId();
BaseResp b = wdaClient.getRespHandler().getResp(
HttpUtil.createGet(wdaClient.getRemoteUrl() + "/session/"
+ wdaClient.getSessionId() + "/element/" + id + "/rect"));
if (b.getErr() == null) {
ElementRect elementRect = JSON.parseObject(b.getValue().toString(), ElementRect.class);
logger.info("get %s rect %s.", id, elementRect.toString());
return elementRect;
} else {
logger.error("get %s rect failed.", id);
throw new SonicRespException(b.getErr().getMessage());
}
}
@Override
public String getAttribute(String name) throws SonicRespException {
wdaClient.checkSessionId();
BaseResp b = wdaClient.getRespHandler().getResp(
HttpUtil.createGet(wdaClient.getRemoteUrl() + "/session/"
+ wdaClient.getSessionId() + "/element/" + id + "/attribute/" + name), 60000);
if (b.getErr() == null) {
logger.info("get %s attribute %s.", id, name);
return b.getValue().toString();
} else {
logger.info("get %s attribute %s.", id, name);
throw new SonicRespException(b.getErr().getMessage());
}
}
@Override
public String getUniquelyIdentifies() throws SonicRespException {
return id;
}
@Override
public byte[] screenshot() throws SonicRespException {
wdaClient.checkSessionId();
BaseResp b = wdaClient.getRespHandler().getResp(
HttpUtil.createGet(wdaClient.getRemoteUrl() + "/session/"
+ wdaClient.getSessionId() + "/element/" + id + "/screenshot"), 60000);
if (b.getErr() == null) {
logger.info("get element %s screenshot.", id);
return Base64.getMimeDecoder().decode(b.getValue().toString());
} else {
logger.error("get element %s screenshot failed.", id);
throw new SonicRespException(b.getErr().getMessage());
}
}
@Override
public boolean isDisplayed() throws SonicRespException {
wdaClient.checkSessionId();
BaseResp b = wdaClient.getRespHandler().getResp(
HttpUtil.createGet(wdaClient.getRemoteUrl() + "/session/"
+ wdaClient.getSessionId() + "/element/" + id + "/displayed"));
if (b.getErr() == null) {
logger.info("get %s displayed,result is %s.", id, b.getValue().toString());
return Boolean.parseBoolean(b.getValue().toString());
} else {
logger.error("get %s displayed failed.", id);
throw new SonicRespException(b.getErr().getMessage());
}
}
}
================================================
FILE: src/main/java/org/cloud/sonic/driver/ios/service/impl/WdaClientImpl.java
================================================
/*
* Copyright (C) [SonicCloudOrg] Sonic Project
*
* 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 org.cloud.sonic.driver.ios.service.impl;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.Method;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.cloud.sonic.driver.common.models.BaseResp;
import org.cloud.sonic.driver.common.models.SessionInfo;
import org.cloud.sonic.driver.common.models.WindowSize;
import org.cloud.sonic.driver.common.tool.Logger;
import org.cloud.sonic.driver.common.tool.RespHandler;
import org.cloud.sonic.driver.common.tool.SonicRespException;
import org.cloud.sonic.driver.ios.enums.Orientation;
import org.cloud.sonic.driver.ios.models.TouchActions;
import org.cloud.sonic.driver.ios.service.IOSElement;
import org.cloud.sonic.driver.ios.service.WdaClient;
import org.jsoup.select.CombiningEvaluator;
import java.nio.charset.StandardCharsets;
import java.util.*;
public class WdaClientImpl implements WdaClient {
private String remoteUrl;
private String sessionId;
private RespHandler respHandler;
private Logger logger;
private final String LEGACY_WEB_ELEMENT_IDENTIFIER = "ELEMENT";
private final String WEB_ELEMENT_IDENTIFIER = "element-6066-11e4-a52e-4f735466cecf";
private int FIND_ELEMENT_INTERVAL = 3000;
private int FIND_ELEMENT_RETRY = 5;
public WdaClientImpl() {
respHandler = new RespHandler();
logger = new Logger();
}
private void checkBundleId(String bundleId) throws SonicRespException {
if (bundleId == null || bundleId.length() == 0) {
logger.error("bundleId not found.");
throw new SonicRespException("bundleId not found.");
}
}
private String parseElementId(Object o) {
JSONObject jsonObject = (JSONObject) o;
List<String> identifier = Arrays.asList(LEGACY_WEB_ELEMENT_IDENTIFIER, WEB_ELEMENT_IDENTIFIER);
for (String i : identifier) {
String result = jsonObject.getString(i);
if (result != null && result.length() > 0) {
return result;
}
}
return "";
}
@Override
public void setGlobalTimeOut(int timeOut) {
respHandler.setRequestTimeOut(timeOut);
}
@Override
public RespHandler getRespHandler() {
return respHandler;
}
@Override
public void setRespHandler(RespHandler respHandler) {
this.respHandler = respHandler;
}
@Override
public Logger getLogger() {
return logger;
}
@Override
public void showLog() {
logger.showLog();
}
@Override
public void disableLog() {
logger.disableLog();
}
@Override
public String getRemoteUrl() {
return remoteUrl;
}
@Override
public void setRemoteUrl(String remoteUrl) {
this.remoteUrl = remoteUrl;
}
@Override
public String getSessionId() {
return sessionId;
}
@Override
public void setSessionId(String sessionId) {
this.sessionId = sessionId;
}
@Override
public void newSession(JSONObject capabilities) throws SonicRespException {
JSONObject data = new JSONObject();
data.put("capabilities", capabilities);
BaseResp b = respHandler.getResp(HttpUtil.createPost(remoteUrl + "/session").body(data.toJSONString()));
if (b.getErr() == null) {
SessionInfo sessionInfo = JSON.parseObject(b.getValue().toString(), SessionInfo.class);
setSessionId(sessionInfo.getSessionId());
logger.info("start session successful!");
logger.info("session : %s", sessionInfo.getSessionId());
logger.info("session capabilities : %s", sessionInfo.getCapabilities().toString());
} else {
logger.error("start session failed.");
logger.error("cause: %s", b.getErr().toString());
throw new SonicRespException(b.getErr().getMessage());
}
}
@Override
public void closeSession() throws SonicRespException {
checkSessionId();
respHandler.getResp(HttpUtil.createRequest(Method.DELETE, remoteUrl + "/session/" + sessionId));
logger.info("close session successful!");
}
@Override
public void checkSessionId() throws SonicRespException {
if (sessionId == null || sessionId.length() == 0) {
logger.error("sessionId not found.");
throw new SonicRespException("sessionId not found.");
}
}
@Override
public WindowSize getWindowSize() throws SonicRespException {
checkSessionId();
BaseResp b = respHandler.getResp(HttpUtil.createGet(remoteUrl + "/session/" + sessionId + "/window/size"));
if (b.getErr() == null) {
logger.info("get window size %s.", b.getValue().toString());
return JSON.parseObject(b.getValue().toString(), WindowSize.class);
} else {
logger.error("get window size failed.");
throw new SonicRespException(b.getErr().getMessage());
}
}
@Override
public boolean isLocked() throws SonicRespException {
checkSessionId();
BaseResp b = respHandler.getResp(HttpUtil.createGet(remoteUrl + "/session/" + sessionId + "/wda/locked"));
if (b.getErr() == null) {
logger.info("device lock status: %b.", b.getValue());
return (boolean) b.getValue();
} else {
logger.error("get device lock status failed.");
throw new SonicRespException(b.getErr().getMessage());
}
}
@Override
public void lock() throws SonicRespException {
checkSessionId();
BaseResp b = respHandler.getResp(HttpUtil.createPost(remoteUrl + "/session/" + sessionId + "/wda/lock"));
if (b.getErr() == null) {
logger.info("lock device.");
} else {
logger.error("lock device failed.");
throw new SonicRespException(b.getErr().getMessage());
}
}
@Override
public void unlock() throws SonicRespException {
checkSessionId();
BaseResp b = respHandler.getResp(HttpUtil.createPost(remoteUrl + "/session/" + sessionId + "/wda/unlock"));
if (b.getErr() == null) {
logger.info("unlock device.");
} else {
logger.error("unlock device failed.");
throw new SonicRespException(b.getErr().getMessage());
}
}
@Override
public void performTouchAction(TouchActions touchActions) throws SonicRespException {
checkSessionId();
BaseResp b = respHandler.getResp(HttpUtil.createPost(remoteUrl + "/session/" + sessionId + "/actions")
.body(JSON.toJSONString(touchActions)));
if (b.getErr() == null) {
logger.info("perform action %s.", touchActions.toString());
} else {
logger.error("perform failed.");
throw new SonicRespException(b.getErr().getMessage());
}
}
@Override
public void pressButton(String buttonName) throws SonicRespException {
checkSessionId();
JSONObject data = new JSONObject();
data.put("name", buttonName);
BaseResp b = respHandler.getResp(HttpUtil.createPost(remoteUrl + "/session/" + sessionId + "/wda/pressButton")
.body(data.toJSONString()));
if (b.getErr() == null) {
logger.info("press button %s.", buttonName);
} else {
logger.error("press button failed.");
throw new SonicRespException(b.getErr().getMessage());
}
}
@Override
public void doubleTap(int x, int y) throws SonicRespException {
checkSessionId();
JSONObject data = new JSONObject();
data.put("x",x);
data.put("y",y);
BaseResp b = respHandler.getResp(HttpUtil.createPost(remoteUrl + "/session/" + sessionId + "/wda/doubleTap")
.body(data.toJSONString()));
if (b.getErr() == null) {
logger.info("double tap success. %s", data.toJSONString());
} else {
logger.error("double tap failed.");
throw new SonicRespException(b.getErr().getMessage());
}
}
@Override
public void sendKeys(String text, Integer frequency) throws SonicRespException {
checkSessionId();
JSONObject data = new JSONObject();
data.put("value", text.split(""));
data.put("frequency", frequency);
BaseResp b = respHandler.getResp(HttpUtil.createPost(remoteUrl + "/session/" + sessionId + "/wda/keys")
.body(data.toJSONString()));
if (b.getErr() == null) {
logger.info("send key %s.", text);
} else {
logger.error("send key failed.");
throw new SonicRespException(b.getErr().getMessage());
}
}
@Override
public void setPasteboard(String contentType, String content) throws SonicRespException {
checkSessionId();
JSONObject data = new JSONObject();
data.put("contentType", contentType);
data.put("content", Base64.getEncoder().encodeToString(content.getBytes(StandardCharsets.UTF_8)));
BaseResp b = respHandler.getResp(HttpUtil.createPost(remoteUrl + "/session/" + sessionId + "/wda/setPasteboard")
.body(data.toJSONString()));
if (b.getErr() == null) {
logger.info("set pasteboard %s.", content);
} else {
logger.error("set pasteboard failed.");
throw new SonicRespException(b.getErr().getMessage());
}
}
@Override
public byte[] getPasteboard(String contentType) throws SonicRespException {
checkSessionId();
JSONObject data = new JSONObject();
data.put("contentType", contentType);
BaseResp b = respHandler.getResp(HttpUtil.createPost(remoteUrl + "/session/" + sessionId + "/wda/getPasteboard")
.body(data.toJSONString()));
if (b.getErr() == null) {
byte[] result = Base64.getMimeDecoder().decode(b.getValue().toString());
logger.info("get pasteboard length: %d.", result.length);
return result;
} else {
logger.error("get pasteboard failed.");
throw new SonicRespException(b.getErr().getMessage());
}
}
@Override
public String pageSource() throws SonicRespException {
checkSessionId();
BaseResp b = respHandler.getResp(HttpUtil.createGet(remoteUrl + "/session/" + sessionId + "/source"), 5 * 60 * 1000);
if (b.getErr() == null) {
logger.info("get page source.");
return b.getValue().toString();
} else {
logger.error("get page source failed.");
throw new SonicRespException(b.getErr().getMessage());
}
}
@Override
public void sendSiriCommand(String command) throws SonicRespException {
if (command != null && command.length() != 0) {
checkSessionId();
JSONObject data = new JSONObject();
data.put("text", command);
BaseResp b = respHandler.getResp(HttpUtil.createPost(remoteUrl + "/session/" + sessionId + "/wda/siri/activate")
.body(data.toJSONString()));
if (b.getErr() == null) {
logger.info("send siri command: %s", command);
} else {
logger.error("send siri command [%s] failed.", command);
throw new SonicRespException(b.getErr().getMessage());
}
} else {
logger.error("siri command is null!");
throw new SonicRespException("siri command is null!");
}
}
@Override
public void appActivate(String bundleId) throws SonicRespException {
checkSessionId();
checkBundleId(bundleId);
JSONObject data = new JSONObject();
data.put("bundleId", bundleId);
BaseResp b = respHandler.getResp(HttpUtil.createPost(remoteUrl + "/session/" + sessionId + "/wda/apps/activate")
.body(data.toJSONString()));
if (b.getErr() == null) {
logger.info("activate app %s.", bundleId);
} else {
logger.error("activate app %s failed.", bundleId);
throw new SonicRespException(b.getErr().getMessage());
}
}
@Override
public boolean appTerminate(String bundleId) throws SonicRespException {
checkSessionId();
checkBundleId(bundleId);
JSONObject data = new JSONObject();
data.put("bundleId", bundleId);
BaseResp b = respHandler.getResp(HttpUtil.createPost(remoteUrl + "/session/" + sessionId + "/wda/apps/terminate")
.body(data.toJSONString()));
if (b.getErr() == null) {
logger.info("terminate app %s status: %b.", bundleId, b.getValue());
return (boolean) b.getValue();
} else {
logger.error("terminate app failed.", bundleId);
throw new SonicRespException(b.getErr().getMessage());
}
}
@Override
public void appRunBackground(int duration) throws SonicRespException {
checkSessionId();
JSONObject data = new JSONObject();
data.put("duration", duration);
BaseResp b = respHandler.getResp(HttpUtil.createPost(remoteUrl + "/session/" + sessionId + "/wda/deactivateApp")
.body(data.toJSONString()));
if (b.getErr() == null) {
logger.info("run app background in %d seconds.", duration);
} else {
logger.error("run app background failed.");
throw new SonicRespException(b.getErr().getMessage());
}
}
@Override
public void appAuthReset(int resource) throws SonicRespException {
checkSessionId();
JSONObject data = new JSONObject();
data.put("resource", resource);
BaseResp b = respHandler.getResp(HttpUtil.createPost(remoteUrl + "/session/" + sessionId + "/wda/resetAppAuth")
.body(data.toJSONString()));
if (b.getErr() == null) {
logger.info("reset app auth %s.", resource);
} else {
logger.error("reset app auth failed.");
throw new SonicRespException(b.getErr().getMessage());
}
}
@Override
public void setDefaultFindElementInterval(Integer retry, Integer interval) {
if (retry != null) {
FIND_ELEMENT_RETRY = retry;
}
if (interval != null) {
FIND_ELEMENT_INTERVAL = interval;
}
}
@Override
public IOSElement findElement(String selector, String value, Integer retry, Integer interval) throws SonicRespException {
IOSElement iosElement = null;
int wait = 0;
int intervalInit = (interval == null ? FIND_ELEMENT_INTERVAL : interval);
int retryInit = (retry == null ? FIND_ELEMENT_RETRY : retry);
String errMsg = "";
while (wait < retryInit) {
wait++;
checkSessionId();
JSONObject data = new JSONObject();
data.put("using", selector);
data.put("value", value);
BaseResp b = respHandler.getResp(HttpUtil.createPost(remoteUrl + "/session/" + sessionId + "/element")
.body(data.toJSONString()));
if (b.getErr() == null) {
logger.info("find element successful.");
String id = parseElementId(b.getValue());
if (id.length() > 0) {
iosElement = new IOSElementImpl(id, this);
break;
} else {
logger.error("parse element id %s failed. retried %d times, retry in %d ms.", b.getValue().toString(), wait, intervalInit);
}
} else {
logger.error("element not found. retried %d times, retry in %d ms.", wait, intervalInit);
errMsg = b.getErr().getMessage();
}
if (wait < retryInit) {
try {
Thread.sleep(intervalInit);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
if (iosElement == null) {
throw new SonicRespException(errMsg);
}
return iosElement;
}
@Override
public List<IOSElement> findElementList(String selector, String value, Integer retry, Integer interval) throws SonicRespException {
List<IOSElement> iosElementList = new ArrayList<>();
int wait = 0;
int intervalInit = (interval == null ? FIND_ELEMENT_INTERVAL : interval);
int retryInit = (retry == null ? FIND_ELEMENT_RETRY : retry);
String errMsg = "";
while (wait < retryInit) {
wait++;
checkSessionId();
JSONObject data = new JSONObject();
data.put("using", selector);
data.put("value", value);
BaseResp b = respHandler.getResp(HttpUtil.createPost(remoteUrl + "/session/" + sessionId + "/elements")
.body(data.toJSONString()));
if (b.getErr() == null) {
logger.info("find elements successful.");
List<JSONObject> ids = JSON.parseObject(b.getValue().toString(), ArrayList.class);
for (JSONObject ele : ids) {
String id = parseElementId(ele);
if (id.length() > 0) {
iosElementList.add(new IOSElementImpl(id, this));
} else {
logger.error("parse element id %s failed.", ele);
}
}
if (iosElementList.size() > 0) {
break;
}
} else {
logger.error("elements not found. retried %d times, retry in %d ms.", wait, intervalInit);
errMsg = b.getErr().getMessage();
}
if (wait < retryInit) {
try {
Thread.sleep(intervalInit);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
if (iosElementList.size() == 0) {
throw new SonicRespException(errMsg);
}
return iosElementList;
}
@Override
public IOSElement activeElement() throws SonicRespException {
checkSessionId();
BaseResp b = respHandler.getResp(
HttpUtil.createGet(remoteUrl + "/session/" + sessionId + "/element/active"));
if (b.getErr() == null) {
logger.info("find active elements successful.");
JSONObject value = JSON.parseObject(b.getValue().toString(), JSONObject.class);
List<String> identifier = Arrays.asList("ELEMENT", "element-6066-11e4-a52e-4f735466cecf");
Iterator var4 = identifier.iterator();
String eleId;
do {
if (!var4.hasNext()) {
return null;
}
String i = (String)var4.next();
eleId = value.getString(i);
} while(eleId == null || eleId.length() <= 0);
return new IOSElementImpl(eleId,this);
} else {
logger.error("active element not found.");
throw new SonicRespException(b.getErr().getMessage());
}
}
@Override
public byte[] screenshot() throws SonicRespException {
checkSessionId();
BaseResp b = respHandler.getResp(
HttpUtil.createGet(remoteUrl + "/session/" + sessionId + "/screenshot"), 60000);
if (b.getErr() == null) {
logger.info("get screenshot.");
return Base64.getMimeDecoder().decode(b.getValue().toString());
} else {
logger.error("get screenshot failed.");
throw new SonicRespException(b.getErr().getMessage());
}
}
@Override
public void setAppiumSettings(JSONObject settings) throws SonicRespException {
checkSessionId();
JSONObject data = new JSONObject();
data.put("settings", settings);
BaseResp b = respHandler.getResp(HttpUtil.createPost(remoteUrl + "/session/" + sessionId + "/appium/settings")
.body(data.toJSONString()));
if (b.getErr() == null) {
logger.info("set appium settings %s.", settings.toJSONString());
} else {
logger.error("set appium settings failed.");
throw new SonicRespException(b.getErr().getMessage());
}
}
@Override
public void swipe(double fromX, double fromY, double toX, double toY, double duration) throws SonicRespException {
checkSessionId();
JSONObject data = new JSONObject();
double maxSwipeDistance = Math.max(Math.abs(toX - fromX), Math.abs(toY - fromY));
double velocity = maxSwipeDistance / duration * 1000;
// velocity 单位为像素/秒,这里做个限制,如果超过1000则滑动的过快,很容易触发fling行为
velocity = Math.min(velocity, 1000);
data.put("fromX", fromX);
data.put("fromY", fromY);
data.put("toX", toX);
data.put("toY", toY);
data.put("velocity", velocity);
BaseResp b = respHandler.getResp(HttpUtil.createPost(remoteUrl + "/session/" + sessionId + "/wda/pressAndDragWithVelocity")
.body(data.toJSONString()));
if (b.getErr() == null) {
logger.info("perform swipe %s successful.", data.toString());
} else {
logger.error("perform swipe %s failed.", data.toString());
throw new SonicRespException(b.getErr().getMessage());
}
}
@Override
public void rotate(Orientation orientation) throws SonicRespException {
JSONObject xyz = orientation.getValue();
BaseResp b = respHandler.getResp(HttpUtil.createPost(remoteUrl + "/rotation").body(String.valueOf(xyz.toJSONString())));
if (b.getErr() == null) {
logger.info("set orientation success. %s", xyz.toJSONString());
} else {
logger.error("set orientation failed.");
throw new SonicRespException(b.getErr().getMessage());
}
}
@Override
public Orientation getRotate() throws SonicRespException {
BaseResp b = respHandler.getResp(HttpUtil.createGet(remoteUrl + "/rotation"));
if (b.getErr() == null) {
logger.info("get orientation %s.",b.getValue());
JSONObject value = JSON.parseObject(b.getValue().toString(), JSONObject.class);
Integer zValue = Integer.valueOf(value.getString("z"));
switch (zValue) {
case 0:
return Orientation.PORTRAIT;
case 180:
return Orientation.PORTRAITUPSIDEDOWN;
case 90:
return Orientation.LANDSCAPELEFT;
case 270:
return Orientation.LANDSCAPERIGHT;
default:
return Orientation.UNKNOWN;
}
} else {
logger.error("get orientation failed.");
throw new SonicRespException(b.getErr().getMessage());
}
}
}
================================================
FILE: src/main/java/org/cloud/sonic/driver/poco/PocoDriver.java
================================================
/*
* Copyright (C) [SonicCloudOrg] Sonic Project
*
* 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 org.cloud.sonic.driver.poco;
import org.cloud.sonic.driver.common.models.WindowSize;
import org.cloud.sonic.driver.common.tool.SonicRespException;
import org.cloud.sonic.driver.poco.enums.PocoEngine;
import org.cloud.sonic.driver.poco.enums.PocoSelector;
import org.cloud.sonic.driver.poco.models.PocoElement;
import org.cloud.sonic.driver.poco.service.PocoClient;
import org.cloud.sonic.driver.poco.service.impl.PocoClientImpl;
import org.jsoup.nodes.Element;
import java.util.List;
/**
* @author Eason
* poco driver
*/
public class PocoDriver {
private PocoClient pocoClient;
/**
* init poco driver
*
* @param pocoEngine
*/
public PocoDriver(PocoEngine pocoEngine) {
this(pocoEngine, pocoEngine.getDefaultPort());
}
/**
* init poco driver
*
* @param pocoEngine
* @param port
*/
public PocoDriver(PocoEngine pocoEngine, int port) {
pocoClient = new PocoClientImpl();
pocoClient.newClient(pocoEngine, port);
}
/**
* close driver
*/
public void closeDriver() {
pocoClient.closeClient();
}
/**
* show log.
*/
public void showLog() {
pocoClient.showLog();
}
/**
* disable log.
*/
public void disableLog() {
pocoClient.disableLog();
}
/**
* get Poco element
*
* @return
* @throws SonicRespException
*/
public PocoElement getPageSource() throws SonicRespException {
return pocoClient.pageSource();
}
/**
* get Poco element for Json
*
* @return
* @throws SonicRespException
*/
public String getPageSourceForJsonString() throws SonicRespException {
return pocoClient.pageSourceForJsonString();
}
/**
* get Poco element for jsoup.Element
*
* @return
* @throws SonicRespException
*/
public Element getPageSourceForXmlElement() throws SonicRespException {
return pocoClient.pageSourceForXmlElement();
}
/**
* find poco elements
*
* @param expression
* @return
*/
public List<PocoElement> findElements(String selector, String expression) throws SonicRespException {
return pocoClient.findElements(selector, expression);
}
/**
* find poco elements
*
* @param expression
* @return
*/
public List<PocoElement> findElements(PocoSelector selector, String expression) throws SonicRespException {
return findElements(selector.getSelector(), expression);
}
/**
* find poco element
*
* @param expression
* @return
*/
public PocoElement findElement(String selector, String expression) throws SonicRespException {
return pocoClient.findElement(selector, expression);
}
/**
* find poco element
*
* @param expression
* @return
*/
public PocoElement findElement(PocoSelector selector, String expression) throws SonicRespException {
return findElement(selector.getSelector(), expression);
}
/**
* Freeze page source
*/
public void freezeSource() {
pocoClient.freezeSource();
}
/**
* Thaw page source
*/
public void thawSource() {
pocoClient.thawSource();
}
/**
* get windows size
*
* @return
* @throws SonicRespException
*/
public WindowSize getScreenSize() throws SonicRespException {
return pocoClient.getScreenSize();
}
}
================================================
FILE: src/main/java/org/cloud/sonic/driver/poco/enums/PocoEngine.java
================================================
/*
* Copyright (C) [SonicCloudOrg] Sonic Project
*
* 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 org.cloud.sonic.driver.poco.enums;
public enum PocoEngine {
UNITY_3D("Unity3d", 5001),
UE4("UE4", 5001),
COCOS_2DX_JS("Cocos2dx-js", 5003),
COCOS_2DX_LUA("Cocos2dx-lua", 15004),
COCOS_2DX_C_PLUS_1("Cocos2dx-c++", 18888),
COCOS_CREATOR("cocos-creator", 5003),
EGRET("Egret", 5003);
private final String name;
private final int defaultPort;
PocoEngine(String name, int defaultPort) {
this.name = name;
this.defaultPort = defaultPort;
}
public int getDefaultPort() {
return defaultPort;
}
}
================================================
FILE: src/main/java/org/cloud/sonic/driver/poco/enums/PocoSelector.java
================================================
/*
* Copyright (C) [SonicCloudOrg] Sonic Project
*
* 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 org.cloud.sonic.driver.poco.enums;
public enum PocoSelector {
POCO("poco"),
XPATH("xpath"),
CSS_SELECTOR("cssSelector");
private final String selector;
PocoSelector(String selector) {
this.selector = selector;
}
public String getSelector() {
return selector;
}
}
================================================
FILE: src/main/java/org/cloud/sonic/driver/poco/models/PocoElement.java
================================================
/*
* Copyright (C) [SonicCloudOrg] Sonic Project
*
* 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 org.cloud.sonic.driver.poco.models;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.ToString;
import org.cloud.sonic.driver.common.models.BaseElement;
import org.cloud.sonic.driver.common.models.ElementRect;
import org.cloud.sonic.driver.common.tool.SonicRespException;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Getter
@ToString
@AllArgsConstructor
public class PocoElement implements BaseElement {
public String currentNodeSelector = "Root";
private Payload payload;
private List<PocoElement> children;
RootElement rootElement;
private Element currentNodeXmlElement;
private long version;
@Override
// the poco given pos is a point where the origin of the coordinates will change with
// the rotation of the screen. The function and others are not uniform, so the implementation
// is not considered, you can get the pos point through the payload, and then convert it at
// the application layer
public ElementRect getRect() throws SonicRespException {
throw new SonicRespException("poco element unrealized");
}
@Override
public String getAttribute(String name) throws SonicRespException {
return currentNodeXmlElement.attr(name);
}
@Override
public String getUniquelyIdentifies() throws SonicRespException {
return currentNodeSelector;
}
@Override
public boolean isDisplayed() throws SonicRespException {
throw new SonicRespException("poco element unrealized");
}
@Getter
@ToString
@AllArgsConstructor
public class Payload {
private String layer;
private String name;
private String tag;
private String text;
private String texture;
private Integer _instanceId;
private Integer _ilayer;
private String type;
private Boolean visible;
private ZOrders zOrders;
private List<String> components;
private List<Float> anchorPoint;
private List<Float> scale;
private List<Float> size;
private List<Float> pos;
private Boolean clickable;
@Getter
@ToString
@AllArgsConstructor
public class ZOrders {
private Float global;
private Float local;
public ZOrders() {
}
}
public Payload() {
zOrders = new ZOrders();
}
}
public PocoElement(RootElement root) {
this.rootElement = root;
this.currentNodeSelector = root.getXmlElement().cssSelector();
payload = new Payload();
children = new ArrayList<>();
}
public PocoElement(RootElement root, Element currentNodeXmlElement) {
this(root);
this.currentNodeXmlElement = currentNodeXmlElement;
this.currentNodeSelector = currentNodeXmlElement.cssSelector();
parseXmlNode(currentNodeXmlElement);
}
public Payload getPayload() {
if (rootElement.getVersion() != getVersion()) {
Element xmlPocoNode = rootElement.getXmlElement().select(currentNodeSelector).first();
if (xmlPocoNode == null) {
return null;
}
parseXmlNode(xmlPocoNode);
version = rootElement.getVersion();
}
return payload;
}
public List<PocoElement> getChildren() {
if (rootElement.getVersion() != getVersion()) {
Element xmlPocoNode = rootElement.getXmlElement().select(currentNodeSelector).first();
if (xmlPocoNode == null) {
return null;
}
children.clear();
currentNodeXmlElement = xmlPocoNode;
Elements childList = xmlPocoNode.children();
for (Element child : childList) {
children.add(new PocoElement(rootElement, child));
}
version = rootElement.getVersion();
}
return children;
}
public void parseXmlNode(Element xmlNode) {
payload.layer = xmlNode.attr("layer");
payload.name = xmlNode.attr("name");
payload.tag = xmlNode.attr("tag");
payload.text = xmlNode.attr("text");
payload.texture = xmlNode.attr("texture");
String _instanceId = xmlNode.attr("_instanceId");
payload._instanceId = _instanceId.isEmpty() ? 0 : Integer.parseInt(_instanceId);
String _ilayer = xmlNode.attr("_ilayer");
payload._ilayer = _ilayer.isEmpty() ? 0 : Integer.parseInt(_ilayer);
payload.type = xmlNode.attr("type");
String visible = xmlNode.attr("visible");
payload.visible = Boolean.parseBoolean(visible);
String global = xmlNode.attr("global");
payload.zOrders.global = global.isEmpty() ? 0 : Float.parseFloat(global);
String local = xmlNode.attr("local");
payload.zOrders.local = local.isEmpty() ? 0 : Float.parseFloat(local);
String components = xmlNode.attr("components");
if (components.length() > 2) {
components = components.substring(1, components.length() - 1);
payload.components = Arrays.asList(components.split(","));
}
payload.anchorPoint = parseFloatAttrList(xmlNode.attr("anchorPoint"));
payload.scale = parseFloatAttrList(xmlNode.attr("scale"));
payload.size = parseFloatAttrList(xmlNode.attr("size"));
payload.pos = parseFloatAttrList(xmlNode.attr("pos"));
payload.clickable = Boolean.parseBoolean(xmlNode.attr("clickable"));
}
private List<Float> parseFloatAttrList(String floatAttrStr) {
if (floatAttrStr.length() <= 2) return null;
List<Float> result = new ArrayList<Float>();
floatAttrStr = floatAttrStr.substring(1, floatAttrStr.length() - 1);
for (String numStr : floatAttrStr.split(",")) {
result.add(Float.parseFloat(numStr));
}
return result;
}
public Boolean currentTheNodeExists() {
return rootElement.getXmlElement().select(currentNodeSelector).first() != null;
}
public PocoElement getParentNode() {
Element xmlPocoNode = rootElement.getXmlElement().select(currentNodeSelector).first();
if (xmlPocoNode == null) {
return null;
}
Element parentNode = xmlPocoNode.parent();
if (parentNode == null) {
return null;
}
return new PocoElement(rootElement, parentNode);
}
}
================================================
FILE: src/main/java/org/cloud/sonic/driver/poco/models/RootElement.java
================================================
/*
* Copyright (C) [SonicCloudOrg] Sonic Project
*
* 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 org.cloud.sonic.driver.poco.models;
import org.jsoup.nodes.Element;
public class RootElement {
private Element XmlElement;
private long version;
public RootElement() {
}
public RootElement(Element XmlElement) {
this.XmlElement = XmlElement;
}
public RootElement(Element XmlElement, long version) {
this(XmlElement);
this.version = version;
}
public Element getXmlElement() {
return XmlElement;
}
public void setXmlElement(Element xmlElement) {
this.XmlElement = xmlElement;
}
public long getVersion() {
return version;
}
public void setVersion(long version) {
this.version = version;
}
public synchronized void updateVersion(Element rootXmlElement) {
this.XmlElement = rootXmlElement;
this.version += 1;
}
}
================================================
FILE: src/main/java/org/cloud/sonic/driver/poco/service/PocoClient.java
================================================
/*
* Copyright (C) [SonicCloudOrg] Sonic Project
*
* 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 org.cloud.sonic.driver.poco.service;
import org.cloud.sonic.driver.common.models.WindowSize;
import org.cloud.sonic.driver.common.tool.Logger;
import org.cloud.sonic.driver.common.tool.SonicRespException;
import org.cloud.sonic.driver.poco.enums.PocoEngine;
import org.cloud.sonic.driver.poco.models.PocoElement;
import org.jsoup.nodes.Element;
import java.util.List;
/**
* @author Eason
* poco client interface
*/
public interface PocoClient {
//Client Setting
Logger getLogger();
void showLog();
void disableLog();
//Client handler.
void newClient(PocoEngine engine, int port);
void closeClient();
//source handler.
PocoElement pageSource() throws SonicRespException;
String pageSourceForJsonString() throws SonicRespException;
Element pageSourceForXmlElement() throws SonicRespException;
PocoElement findElement(String selector, String expression) throws SonicRespException;
List<PocoElement> findElements(String selector, String expression) throws SonicRespException;
void freezeSource();
void thawSource();
//other
WindowSize getScreenSize() throws SonicRespException;
}
================================================
FILE: src/main/java/org/cloud/sonic/driver/poco/service/PocoConnection.java
================================================
/*
* Copyright (C) [SonicCloudOrg] Sonic Project
*
* 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 org.cloud.sonic.driver.poco.service;
import com.alibaba.fastjson.JSONObject;
import org.cloud.sonic.driver.common.tool.SonicRespException;
public interface PocoConnection {
void connect();
void disconnect();
String sendAndReceive(JSONObject jsonObject) throws SonicRespException;
}
================================================
FILE: src/main/java/org/cloud/sonic/driver/poco/service/impl/PocoClientImpl.java
================================================
/*
* Copyright (C) [SonicCloudOrg] Sonic Project
*
* 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 org.cloud.sonic.driver.poco.service.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.cloud.sonic.driver.common.models.WindowSize;
import org.cloud.sonic.driver.common.tool.Logger;
import org.cloud.sonic.driver.common.tool.SonicRespException;
import org.cloud.sonic.driver.poco.enums.PocoEngine;
import org.cloud.sonic.driver.poco.models.PocoElement;
import org.cloud.sonic.driver.poco.models.RootElement;
import org.cloud.sonic.driver.poco.service.PocoClient;
import org.cloud.sonic.driver.poco.service.PocoConnection;
import org.cloud.sonic.driver.poco.util.PocoJsonToXml;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Element;
import org.jsoup.parser.Parser;
import org.jsoup.select.Elements;
import java.util.*;
import static org.cloud.sonic.driver.poco.enums.PocoEngine.*;
public class PocoClientImpl implements PocoClient {
private Logger logger;
private PocoConnection pocoConnection;
private PocoEngine engine;
private String source;
public RootElement rootNode;
private boolean isFrozen = false;
public PocoClientImpl() {
logger = new Logger();
rootNode = new RootElement();
}
@Override
public Logger getLogger() {
return logger;
}
@Override
public void showLog() {
logger.showLog();
}
@Override
public void disableLog() {
logger.disableLog();
}
@Override
public void newClient(PocoEngine engine, int port) {
this.engine = engine;
if (engine.equals(COCOS_2DX_JS) || engine.equals(COCOS_CREATOR) || engine.equals(EGRET)) {
pocoConnection = new WebSocketClientImpl(port, logger);
} else {
pocoConnection = new SocketClientImpl(port, logger);
}
pocoConnection.connect();
}
@Override
public void closeClient() {
pocoConnection.disconnect();
}
@Override
public PocoElement pageSource() throws SonicRespException {
pageSourceForXmlElement();
return new PocoElement(rootNode);
}
@Override
public String pageSourceForJsonString() throws SonicRespException {
if (isFrozen) {
return source;
}
JSONObject jsonObject = new JSONObject();
jsonObject.put("jsonrpc", "2.0");
jsonObject.put("params", Arrays.asList(true));
jsonObject.put("id", UUID.randomUUID().toString());
jsonObject.put("method", "Dump");
if (engine.equals(COCOS_CREATOR) || engine.equals(COCOS_2DX_JS)) {
jsonObject.put("method", "dump");
}
source = pocoConnection.sendAndReceive(jsonObject);
return source;
}
@Override
public Element pageSourceForXmlElement() throws SonicRespException {
pageSourceForJsonString();
// String pocoJson = "{\"Root\"" + source.substring("{\"result\"".length());
Element rootXmlElement = Jsoup.parse(PocoJsonToXml.jsonObjToXml(JSON.parseObject(source).getJSONObject("result")), "", Parser.xmlParser());
rootNode.updateVersion(rootXmlElement);
return rootNode.getXmlElement();
}
@Override
public PocoElement findElement(String selector, String expression) throws SonicRespException {
List<PocoElement> pocoElements = findElements(selector, expression);
return pocoElements.get(0);
}
@Override
public List<PocoElement> findElements(String selector, String expression) throws SonicRespException {
if (rootNode.getXmlElement() == null) {
pageSourceForXmlElement();
}
Elements xmlNodes = null;
switch (selector) {
case "poco":
String newExpress = "";
String[] steps = expression.split("\\.");
for (String step : steps) {
if (step.startsWith("poco")) {
newExpress += ("//*" + parseAttr(step));
} else if (step.startsWith("child")) {
newExpress += ("/*" + parseAttr(step));
}
if (step.endsWith("]") && step.contains("[")) {
int index = Integer.parseInt(step.substring(step.indexOf("[") + 1, step.indexOf("]")));
newExpress = String.format("(%s)[%d]", newExpress, (index + 1));
}
}
xmlNodes = rootNode.getXmlElement().selectXpath(newExpress);
break;
case "xpath":
xmlNodes = rootNode.getXmlElement().selectXpath(expression);
break;
case "cssSelector":
xmlNodes = rootNode.getXmlElement().select(expression);
break;
}
if (xmlNodes == null || xmlNodes.isEmpty()) {
throw new SonicRespException(String.format("poco element not found for selector:%s, value:%s", selector, expression));
}
List<PocoElement> result = new ArrayList<>();
for (Element node : xmlNodes) {
PocoElement pocoElement = new PocoElement(rootNode, node);
result.add(pocoElement);
}
return result;
}
private String parseAttr(String express) {
String result = "[";
String attrExpression = express.substring(express.indexOf("(") + 1, express.lastIndexOf(")"));
if (attrExpression.startsWith("\"") && attrExpression.endsWith("\"")) {
attrExpression = "name=" + attrExpression.replace("\"", "");
}
String[] attrs = attrExpression.split(",");
for (String attr : attrs) {
String field = attr.substring(0, attr.indexOf("="));
String value = attr.substring(attr.indexOf("=") + 1).replace("\"", "");
if ("visible".equals(value) || "clickable".equals(value)) {
value = value.toLowerCase(Locale.ROOT);
}
result += ("@" + field + "=\"" + value + "\" and ");
}
result += "]";
return result.replace(" and ]", "]");
}
@Override
public void freezeSource() {
isFrozen = true;
}
@Override
public void thawSource() {
isFrozen = false;
}
@Override
public WindowSize getScreenSize() throws SonicRespException {
if (engine.equals(UNITY_3D) || engine.equals(COCOS_2DX_LUA)) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("jsonrpc", "2.0");
jsonObject.put("params", Arrays.asList(true));
jsonObject.put("id", UUID.randomUUID().toString());
jsonObject.put("method", "GetScreenSize");
List<Integer> result = ((JSONArray) JSONObject.parseObject(
pocoConnection.sendAndReceive(jsonObject))
.get("result"))
.toJavaList(Integer.class);
return new WindowSize(result.get(0), result.get(1));
}
return null;
}
}
================================================
FILE: src/main/java/org/cloud/sonic/driver/poco/service/impl/SocketClientImpl.java
================================================
/*
* Copyright (C) [SonicCloudOrg] Sonic Project
*
* 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 org.cloud.sonic.driver.poco.service.impl;
import com.alibaba.fastjson.JSONObject;
import org.cloud.sonic.driver.common.tool.Logger;
import org.cloud.sonic.driver.common.tool.SonicRespException;
import org.cloud.sonic.driver.poco.service.PocoConnection;
import org.cloud.sonic.driver.poco.util.PocoTool;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
public class SocketClientImpl implements PocoConnection {
private Socket poco = null;
private InputStream inputStream = null;
private OutputStream outputStream = null;
private int port;
private Logger logger;
public SocketClientImpl(int port, Logger logger) {
this.port = port;
this.logger = logger;
}
@Override
public String sendAndReceive(JSONObject jsonObject) throws SonicRespException {
byte[] data = jsonObject.toJSONString().getBytes(StandardCharsets.UTF_8);
byte[] header = intToByteArray(data.length);
synchronized (SocketClientImpl.class) {
try {
outputStream.write(header);
outputStream.write(data);
outputStream.flush();
byte[] head = new byte[4];
byte[] buffer = new byte[8192];
inputStream.read(head);
int headLen = toInt(head);
ByteBuffer rData = ByteBuffer.allocate(headLen);
while (poco.isConnected() && !Thread.interrupted()) {
int realLen;
realLen = inputStream.read(buffer);
if (realLen > 0) {
rData.put(buffer, 0, realLen);
}
if (rData.position() == headLen) {
rData.flip();
String pocoResult = new String(rData.array(), StandardCharsets.UTF_8);
int subStartIndex = pocoResult.indexOf("\"result\"");
// when cocos is integrated there will be no id
// String pocoPrefix = pocoResult.substring(0, subStartIndex) + "}";
// if (PocoTool.checkPocoRpcResultID(pocoPrefix, jsonObject.getString("id"))) {
return "{" + pocoResult.substring(subStartIndex);
// } else {
// throw new SonicRespException("id not found!");
// }
}
}
} catch (Exception e) {
throw new SonicRespException(e.getMessage());
}
}
return null;
}
@Override
public void connect() {
int waitConnect = 0;
while (poco == null || !poco.isConnected()) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
waitConnect++;
if (waitConnect >= 20) {
break;
}
try {
poco = new Socket("localhost", port);
inputStream = poco.getInputStream();
outputStream = poco.getOutputStream();
} catch (Exception e) {
logger.info(e.getMessage());
}
}
if (poco != null) {
logger.info("poco socket connected.");
} else {
logger.info("poco socket disconnected.");
}
}
@Override
public void disconnect() {
if (poco != null && poco.isConnected()) {
try {
poco.close();
logger.info("poco socket closed.");
} catch (IOException e) {
e.printStackTrace();
}
}
if (inputStream != null) {
try {
inputStream.close();
logger.info("poco input stream closed.");
} catch (IOException e) {
e.printStackTrace();
}
}
if (outputStream != null) {
try {
outputStream.close();
logger.info("poco output stream closed.");
} catch (IOException e) {
e.printStackTrace();
}
}
}
private byte[] intToByteArray(int i) {
byte[] result = new byte[4];
result[0] = (byte) (i & 0xff);
result[1] = (byte) (i >> 8 & 0xff);
result[2] = (byte) (i >> 16 & 0xff);
result[3] = (byte) (i >> 24 & 0xff);
return result;
}
private int toInt(byte[] b) {
int res = 0;
for (int i = 0; i < b.length; i++) {
res += (b[i] & 0xff) << (i * 8);
}
return res;
}
}
================================================
FILE: src/main/java/org/cloud/sonic/driver/poco/service/impl/WebSocketClientImpl.java
================================================
/*
* Copyright (C) [SonicCloudOrg] Sonic Project
*
* 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 org.cloud.sonic.driver.poco.service.impl;
import com.alibaba.fastjson.JSONObject;
import org.cloud.sonic.driver.common.tool.Logger;
import org.cloud.sonic.driver.common.tool.SonicRespException;
import org.cloud.sonic.driver.poco.service.PocoConnection;
import org.cloud.sonic.driver.poco.util.PocoTool;
import org.java_websocket.handshake.ServerHandshake;
import java.net.URI;
import java.net.URISyntaxException;
public class WebSocketClientImpl implements PocoConnection {
private int port;
private Logger logger;
private org.java_websocket.client.WebSocketClient webSocketClient;
private String result = null;
public WebSocketClientImpl(int port, Logger logger) {
this.port = port;
this.logger = logger;
}
@Override
public String sendAndReceive(JSONObject jsonObject) throws SonicRespException {
synchronized (WebSocketClientImpl.class) {
webSocketClient.send(jsonObject.toString());
int wait = 0;
while (result == null) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
wait++;
if (wait >= 20) {
break;
}
}
if (result != null) {
int subStartIndex = result.indexOf("\"result\"");
String pocoPrefix = result.substring(0, subStartIndex) + "}";
if (PocoTool.checkPocoRpcResultID(pocoPrefix, jsonObject.getString("id"))) {
String re = "{" + result.substring(subStartIndex);
result = null;
return re;
} else {
throw new SonicRespException("id not found!");
}
}
}
return null;
}
@Override
public void connect() {
URI ws = null;
try {
ws = new URI("ws://localhost:" + port);
} catch (URISyntaxException e) {
e.printStackTrace();
}
webSocketClient = new org.java_websocket.client.WebSocketClient(ws) {
@Override
public void onOpen(ServerHandshake serverHandshake) {
logger.info("poco ws connected.");
}
@Override
public void onMessage(String s) {
logger.info(s);
result = s;
}
@Override
public void onClose(int i, String s, boolean b) {
logger.info("poco ws close.");
}
@Override
public void onError(Exception e) {
}
};
webSocketClient.connect();
int waitConnect = 0;
while (!webSocketClient.isOpen()) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
waitConnect++;
if (waitConnect >= 20) {
break;
}
}
}
@Override
public void disconnect() {
webSocketClient.close();
}
}
================================================
FILE: src/main/java/org/cloud/sonic/driver/poco/util/PocoJsonToXml.java
================================================
/*
* Copyright (C) [SonicCloudOrg] Sonic Project
*
* 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 org.cloud.sonic.driver.poco.util;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.cloud.sonic.driver.common.tool.SonicRespException;
import java.util.Map;
public class PocoJsonToXml {
/**
* convert json to xml
*
* @param jo JSONObject
* @return xml
*/
public static String jsonObjToXml(JSONObject jo) throws SonicRespException {
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + jsonToXml(jo, "");
return xml;
}
/**
* json object to xml
*
* @param jo JSONObject
* @param gt "\n" shifter
* @return XML
*/
@SuppressWarnings("rawtypes")
private static String jsonToXml(JSONObject jo, String gt) throws SonicRespException {
StringBuffer xmlStr = new StringBuffer();
try {
JSONObject payload = jo.getJSONObject("payload");
JSONArray children = jo.getJSONArray("children");
xmlStr.append(gt);
xmlStr.append("<");
String name = String.join("__", payload.get("name").toString().split(" "));
if (name.equals("<Root>")) name = "Root";
if (!checkName(name)) {
name = "invalidName";
}
xmlStr.append(name);
xmlStr.append(getAttrStr(payload));
xmlStr.append(">\n");
if (children != null) {
for (int i = 0; i < children.size(); i++) {
JSONObject child = children.getJSONObject(i);
xmlStr.append(jsonToXml(child, gt + "\t"));
}
}
addTag(xmlStr, gt, name, true);
} catch (Exception e) {
throw new SonicRespException(e.getMessage());
}
return xmlStr.toString();
}
public static void addTag(StringBuffer xmlStr, String gt, String tagName, boolean isItTheEnd) {
xmlStr.append(gt);
if (isItTheEnd) {
xmlStr.append("</");
} else {
xmlStr.append("<");
}
xmlStr.append(tagName);
xmlStr.append(">\n");
}
public static StringBuilder getAttrStr(JSONObject payload) {
StringBuilder sb = new StringBuilder();
sb.append(" ");
for (Map.Entry<String, Object> stringObjectEntry : payload.entrySet()) {
Map.Entry entry = (Map.Entry) stringObjectEntry;
String key = entry.getKey().toString();
String val = entry.getValue().toString();
if (key.equals("zOrders")) {
JSONObject zOrders = JSONObject.parseObject(val);
sb.append(String.format("global=\"%s\" ", zOrders.get("global")));
sb.append(String.format("local=\"%s\" ", zOrders.get("local")));
} else if (key.equals("components")) {
val = val.replace("\"", "");
sb.append(String.format("%s=\"%s\" ", key, val));
} else {
val = escapingSpecialCharacters(val);
sb.append(String.format("%s=\"%s\" ", k
gitextract_j_5ezhz9/
├── .github/
│ ├── dependabot.yml
│ └── workflows/
│ ├── maven.yml
│ └── release.yml
├── .gitignore
├── LICENSE
├── README.md
├── README_CN.md
├── pom.xml
└── src/
├── main/
│ └── java/
│ └── org/
│ └── cloud/
│ └── sonic/
│ └── driver/
│ ├── android/
│ │ ├── AndroidDriver.java
│ │ ├── enmus/
│ │ │ └── AndroidSelector.java
│ │ └── service/
│ │ ├── AndroidElement.java
│ │ ├── UiaClient.java
│ │ └── impl/
│ │ ├── AndroidElementImpl.java
│ │ └── UiaClientImpl.java
│ ├── common/
│ │ ├── enums/
│ │ │ └── PasteboardType.java
│ │ ├── models/
│ │ │ ├── BaseElement.java
│ │ │ ├── BaseResp.java
│ │ │ ├── Capabilities.java
│ │ │ ├── ElementRect.java
│ │ │ ├── ErrorMsg.java
│ │ │ ├── SessionInfo.java
│ │ │ └── WindowSize.java
│ │ └── tool/
│ │ ├── Logger.java
│ │ ├── RespHandler.java
│ │ └── SonicRespException.java
│ ├── ios/
│ │ ├── IOSDriver.java
│ │ ├── enums/
│ │ │ ├── ActionType.java
│ │ │ ├── AuthResource.java
│ │ │ ├── IOSSelector.java
│ │ │ ├── Orientation.java
│ │ │ ├── SystemButton.java
│ │ │ ├── TextKey.java
│ │ │ └── XCUIElementType.java
│ │ ├── models/
│ │ │ └── TouchActions.java
│ │ └── service/
│ │ ├── IOSElement.java
│ │ ├── WdaClient.java
│ │ └── impl/
│ │ ├── IOSElementImpl.java
│ │ └── WdaClientImpl.java
│ └── poco/
│ ├── PocoDriver.java
│ ├── enums/
│ │ ├── PocoEngine.java
│ │ └── PocoSelector.java
│ ├── models/
│ │ ├── PocoElement.java
│ │ └── RootElement.java
│ ├── service/
│ │ ├── PocoClient.java
│ │ ├── PocoConnection.java
│ │ └── impl/
│ │ ├── PocoClientImpl.java
│ │ ├── SocketClientImpl.java
│ │ └── WebSocketClientImpl.java
│ └── util/
│ ├── PocoJsonToXml.java
│ ├── PocoTool.java
│ └── PocoXYTransformer.java
└── test/
└── java/
└── org/
└── cloud/
└── sonic/
└── driver/
├── android/
│ ├── AndroidDriverTest.java
│ └── service/
│ └── UiaClientTest.java
├── common/
│ └── tool/
│ ├── RespHandlerTest.java
│ └── SonicRespExceptionTest.java
├── ios/
│ ├── IOSDriverTest.java
│ └── service/
│ └── WdaClientTest.java
└── poco/
├── PocoDriverTest.java
├── PocoJsonToXmlTest.java
└── PocoXYTransformerTest.java
SYMBOL INDEX (568 symbols across 52 files)
FILE: src/main/java/org/cloud/sonic/driver/android/AndroidDriver.java
class AndroidDriver (line 36) | public class AndroidDriver {
method AndroidDriver (line 45) | public AndroidDriver(String url) throws SonicRespException {
method AndroidDriver (line 56) | public AndroidDriver(String url, int timeOut) throws SonicRespException {
method AndroidDriver (line 67) | public AndroidDriver(String url, JSONObject cap) throws SonicRespExcep...
method AndroidDriver (line 79) | public AndroidDriver(String url, int timeOut, JSONObject cap) throws S...
method getUiaClient (line 91) | public UiaClient getUiaClient() {
method getSessionId (line 100) | public String getSessionId() {
method closeDriver (line 109) | public void closeDriver() throws SonicRespException {
method showLog (line 116) | public void showLog() {
method disableLog (line 123) | public void disableLog() {
method getWindowSize (line 133) | public WindowSize getWindowSize() throws SonicRespException {
method sendKeys (line 143) | public void sendKeys(String text) throws SonicRespException {
method sendKeys (line 154) | public void sendKeys(String text, boolean isCover) throws SonicRespExc...
method setPasteboard (line 165) | public void setPasteboard(String contentType, String content) throws S...
method setPasteboard (line 176) | public void setPasteboard(PasteboardType pasteboardType, String conten...
method getPasteboard (line 187) | public byte[] getPasteboard(String contentType) throws SonicRespExcept...
method getPasteboard (line 198) | public byte[] getPasteboard(PasteboardType pasteboardType) throws Soni...
method getPageSource (line 208) | public String getPageSource() throws SonicRespException {
method setDefaultFindElementInterval (line 218) | public void setDefaultFindElementInterval(Integer retry, Integer inter...
method findElement (line 230) | public AndroidElement findElement(AndroidSelector androidSelector, Str...
method findElement (line 241) | public AndroidElement findElement(String uiaElementID) throws SonicRes...
method findElement (line 253) | public AndroidElement findElement(String selector, String value) throw...
method findElement (line 266) | public AndroidElement findElement(AndroidSelector androidSelector, Str...
method findElement (line 279) | public AndroidElement findElement(String selector, String value, Integ...
method findElement (line 293) | public AndroidElement findElement(AndroidSelector androidSelector, Str...
method findElement (line 307) | public AndroidElement findElement(String selector, String value, Integ...
method findElementList (line 319) | public List<AndroidElement> findElementList(AndroidSelector androidSel...
method findElementList (line 331) | public List<AndroidElement> findElementList(String selector, String va...
method findElementList (line 344) | public List<AndroidElement> findElementList(AndroidSelector androidSel...
method findElementList (line 357) | public List<AndroidElement> findElementList(String selector, String va...
method findElementList (line 371) | public List<AndroidElement> findElementList(AndroidSelector androidSel...
method findElementList (line 385) | public List<AndroidElement> findElementList(String selector, String va...
method screenshot (line 395) | public byte[] screenshot() throws SonicRespException {
method setAppiumSettings (line 405) | public void setAppiumSettings(JSONObject settings) throws SonicRespExc...
method tap (line 416) | public void tap(int x, int y) throws SonicRespException {
method longPress (line 428) | public void longPress(double x, double y, double ms) throws SonicRespE...
method swipe (line 441) | public void swipe(int fromX, int fromY, int toX, int toY) throws Sonic...
method swipe (line 455) | public void swipe(int fromX, int fromY, int toX, int toY, Integer dura...
method drag (line 472) | public void drag(int fromX, int fromY, int toX, int toY, Integer durat...
method touchAction (line 488) | public void touchAction(String methodType, int x, int y) throws SonicR...
FILE: src/main/java/org/cloud/sonic/driver/android/enmus/AndroidSelector.java
type AndroidSelector (line 19) | public enum AndroidSelector {
method AndroidSelector (line 30) | AndroidSelector(String selector) {
method getSelector (line 34) | public String getSelector() {
FILE: src/main/java/org/cloud/sonic/driver/android/service/AndroidElement.java
type AndroidElement (line 26) | public interface AndroidElement extends BaseElement {
method click (line 28) | void click() throws SonicRespException;
method sendKeys (line 30) | void sendKeys(String text) throws SonicRespException;
method sendKeys (line 32) | void sendKeys(String text, boolean isCover) throws SonicRespException;
method clear (line 34) | void clear() throws SonicRespException;
method getText (line 36) | String getText() throws SonicRespException;
method screenshot (line 38) | byte[] screenshot() throws SonicRespException;
FILE: src/main/java/org/cloud/sonic/driver/android/service/UiaClient.java
type UiaClient (line 31) | public interface UiaClient {
method setGlobalTimeOut (line 33) | void setGlobalTimeOut(int timeOut);
method getRespHandler (line 35) | RespHandler getRespHandler();
method setRespHandler (line 37) | void setRespHandler(RespHandler respHandler);
method getLogger (line 39) | Logger getLogger();
method showLog (line 41) | void showLog();
method disableLog (line 43) | void disableLog();
method getRemoteUrl (line 46) | String getRemoteUrl();
method setRemoteUrl (line 48) | void setRemoteUrl(String remoteUrl);
method getSessionId (line 50) | String getSessionId();
method setSessionId (line 52) | void setSessionId(String sessionId);
method newSession (line 54) | void newSession(JSONObject capabilities) throws SonicRespException;
method closeSession (line 56) | void closeSession() throws SonicRespException;
method checkSessionId (line 58) | void checkSessionId() throws SonicRespException;
method getWindowSize (line 61) | WindowSize getWindowSize() throws SonicRespException;
method sendKeys (line 64) | void sendKeys(String text, boolean isCover) throws SonicRespException;
method setPasteboard (line 66) | void setPasteboard(String contentType, String content) throws SonicRes...
method getPasteboard (line 68) | byte[] getPasteboard(String contentType) throws SonicRespException;
method pageSource (line 71) | String pageSource() throws SonicRespException;
method setDefaultFindElementInterval (line 74) | void setDefaultFindElementInterval(Integer retry, Integer interval);
method findElement (line 76) | AndroidElement findElement(String selector, String value, Integer retr...
method findElementList (line 78) | List<AndroidElement> findElementList(String selector, String value, In...
method screenshot (line 81) | byte[] screenshot() throws SonicRespException;
method setAppiumSettings (line 84) | void setAppiumSettings(JSONObject settings) throws SonicRespException;
method tap (line 86) | void tap(int x, int y) throws SonicRespException;
method longPress (line 88) | void longPress(double x, double y, double ms) throws SonicRespException;
method swipe (line 90) | void swipe(int fromX, int fromY, int toX, int toY, Integer duration) t...
method drag (line 92) | void drag(int fromX, int fromY, int toX, int toY, Integer duration, St...
method touchAction (line 95) | void touchAction(String methodType, int x, int y) throws SonicRespExce...
FILE: src/main/java/org/cloud/sonic/driver/android/service/impl/AndroidElementImpl.java
class AndroidElementImpl (line 31) | public class AndroidElementImpl implements AndroidElement {
method AndroidElementImpl (line 36) | public AndroidElementImpl(String id, UiaClient uiaClient) {
method click (line 42) | @Override
method sendKeys (line 56) | @Override
method sendKeys (line 61) | @Override
method clear (line 79) | @Override
method getText (line 93) | @Override
method getAttribute (line 108) | @Override
method getUniquelyIdentifies (line 123) | @Override
method getRect (line 128) | @Override
method screenshot (line 144) | @Override
method isDisplayed (line 159) | @Override
FILE: src/main/java/org/cloud/sonic/driver/android/service/impl/UiaClientImpl.java
class UiaClientImpl (line 35) | public class UiaClientImpl implements UiaClient {
method UiaClientImpl (line 46) | public UiaClientImpl() {
method checkBundleId (line 51) | private void checkBundleId(String bundleId) throws SonicRespException {
method parseElementId (line 58) | private String parseElementId(Object o) {
method setGlobalTimeOut (line 70) | @Override
method getRespHandler (line 75) | @Override
method setRespHandler (line 80) | @Override
method getLogger (line 85) | @Override
method showLog (line 90) | @Override
method disableLog (line 95) | @Override
method getRemoteUrl (line 100) | @Override
method setRemoteUrl (line 105) | @Override
method getSessionId (line 110) | @Override
method setSessionId (line 115) | @Override
method newSession (line 120) | @Override
method closeSession (line 137) | @Override
method checkSessionId (line 144) | @Override
method getWindowSize (line 152) | @Override
method sendKeys (line 168) | @Override
method setPasteboard (line 184) | @Override
method getPasteboard (line 200) | @Override
method pageSource (line 217) | @Override
method setDefaultFindElementInterval (line 230) | @Override
method findElement (line 240) | @Override
method findElementList (line 282) | @Override
method screenshot (line 329) | @Override
method setAppiumSettings (line 343) | @Override
method tap (line 358) | @Override
method longPress (line 374) | @Override
method swipe (line 393) | @Override
method drag (line 418) | @Override
method touchAction (line 438) | @Override
FILE: src/main/java/org/cloud/sonic/driver/common/enums/PasteboardType.java
type PasteboardType (line 19) | public enum PasteboardType {
method PasteboardType (line 26) | PasteboardType(String pasteboardType) {
method getType (line 30) | public String getType() {
FILE: src/main/java/org/cloud/sonic/driver/common/models/BaseElement.java
type BaseElement (line 5) | public interface BaseElement {
method getRect (line 6) | ElementRect getRect() throws SonicRespException;
method getAttribute (line 8) | String getAttribute(String name) throws SonicRespException;
method getUniquelyIdentifies (line 11) | String getUniquelyIdentifies() throws SonicRespException;
method isDisplayed (line 20) | boolean isDisplayed() throws SonicRespException;
FILE: src/main/java/org/cloud/sonic/driver/common/models/BaseResp.java
class BaseResp (line 22) | @Getter
method setErr (line 29) | public void setErr(ErrorMsg err) {
method setValue (line 33) | public void setValue(T value) {
FILE: src/main/java/org/cloud/sonic/driver/common/models/Capabilities.java
class Capabilities (line 22) | @ToString
FILE: src/main/java/org/cloud/sonic/driver/common/models/ElementRect.java
class ElementRect (line 23) | @Getter
class IOSRectCenter (line 32) | @Getter
method getCenter (line 40) | public IOSRectCenter getCenter() {
FILE: src/main/java/org/cloud/sonic/driver/common/models/ErrorMsg.java
class ErrorMsg (line 22) | @ToString
method getMessage (line 29) | public String getMessage() {
FILE: src/main/java/org/cloud/sonic/driver/common/models/SessionInfo.java
class SessionInfo (line 23) | @Getter
FILE: src/main/java/org/cloud/sonic/driver/common/models/WindowSize.java
class WindowSize (line 23) | @Getter
FILE: src/main/java/org/cloud/sonic/driver/common/tool/Logger.java
class Logger (line 22) | public class Logger {
method Logger (line 26) | public Logger() {
method showLog (line 31) | public void showLog() {
method disableLog (line 35) | public void disableLog() {
method print (line 39) | private void print(String level, String msg, Object... args) {
method info (line 46) | public void info(String msg, Object... args) {
method error (line 50) | public void error(String msg, Object... args) {
FILE: src/main/java/org/cloud/sonic/driver/common/tool/RespHandler.java
class RespHandler (line 30) | public class RespHandler {
method setRequestTimeOut (line 34) | public void setRequestTimeOut(int timeOut) {
method getResp (line 38) | public BaseResp getResp(HttpRequest httpRequest) throws SonicRespExcep...
method getResp (line 42) | public BaseResp getResp(HttpRequest httpRequest, int timeout) throws S...
method initResp (line 53) | public BaseResp initResp(String response) {
method initHeader (line 61) | public Map<String, String> initHeader() {
method initErrorMsg (line 67) | public BaseResp initErrorMsg(String resp) {
FILE: src/main/java/org/cloud/sonic/driver/common/tool/SonicRespException.java
class SonicRespException (line 19) | public class SonicRespException extends Exception {
method SonicRespException (line 20) | public SonicRespException(String message) {
method SonicRespException (line 24) | public SonicRespException(String message, Throwable cause) {
FILE: src/main/java/org/cloud/sonic/driver/ios/IOSDriver.java
class IOSDriver (line 37) | public class IOSDriver {
method IOSDriver (line 46) | public IOSDriver(String url) throws SonicRespException {
method IOSDriver (line 57) | public IOSDriver(String url, int timeOut) throws SonicRespException {
method IOSDriver (line 68) | public IOSDriver(String url, JSONObject cap) throws SonicRespException {
method IOSDriver (line 80) | public IOSDriver(String url, int timeOut, JSONObject cap) throws Sonic...
method getWdaClient (line 92) | public WdaClient getWdaClient() {
method getSessionId (line 101) | public String getSessionId() {
method closeDriver (line 110) | public void closeDriver() throws SonicRespException {
method showLog (line 117) | public void showLog() {
method disableLog (line 124) | public void disableLog() {
method getWindowSize (line 134) | public WindowSize getWindowSize() throws SonicRespException {
method isLocked (line 144) | public boolean isLocked() throws SonicRespException {
method lock (line 153) | public void lock() throws SonicRespException {
method unlock (line 162) | public void unlock() throws SonicRespException {
method tap (line 173) | public void tap(int x, int y) throws SonicRespException {
method doubleTap (line 183) | public void doubleTap(int x, int y) throws SonicRespException {
method longPress (line 195) | public void longPress(int x, int y, int ms) throws SonicRespException {
method swipe (line 208) | public void swipe(int fromX, int fromY, int toX, int toY) throws Sonic...
method swipe (line 222) | public void swipe(double fromX, double fromY, double toX, double toY, ...
method performTouchAction (line 232) | public void performTouchAction(TouchActions touchActions) throws Sonic...
method performTouchAction (line 236) | public void performTouchAction(TouchActions.FingerTouchAction fingerTo...
method pressButton (line 246) | public void pressButton(String systemButton) throws SonicRespException {
method pressButton (line 256) | public void pressButton(SystemButton systemButton) throws SonicRespExc...
method sendKeys (line 266) | public void sendKeys(String text) throws SonicRespException {
method sendKeys (line 277) | public void sendKeys(String text, int frequency) throws SonicRespExcep...
method sendKeys (line 287) | public void sendKeys(TextKey text) throws SonicRespException {
method sendKeys (line 298) | public void sendKeys(TextKey text, int frequency) throws SonicRespExce...
method setPasteboard (line 309) | public void setPasteboard(String contentType, String content) throws S...
method setPasteboard (line 320) | public void setPasteboard(PasteboardType pasteboardType, String conten...
method getPasteboard (line 331) | public byte[] getPasteboard(String contentType) throws SonicRespExcept...
method getPasteboard (line 342) | public byte[] getPasteboard(PasteboardType pasteboardType) throws Soni...
method getPageSource (line 352) | public String getPageSource() throws SonicRespException {
method sendSiriCommand (line 362) | public void sendSiriCommand(String command) throws SonicRespException {
method appActivate (line 372) | public void appActivate(String bundleId) throws SonicRespException {
method appTerminate (line 383) | public boolean appTerminate(String bundleId) throws SonicRespException {
method appRunBackground (line 393) | public void appRunBackground(int duration) throws SonicRespException {
method appAuthReset (line 403) | public void appAuthReset(int resource) throws SonicRespException {
method appAuthReset (line 413) | public void appAuthReset(AuthResource authResource) throws SonicRespEx...
method setDefaultFindElementInterval (line 423) | public void setDefaultFindElementInterval(Integer retry, Integer inter...
method findElement (line 435) | public IOSElement findElement(IOSSelector iosSelector, String value) t...
method findElement (line 446) | public IOSElement findElement(String wdaElementID) throws SonicRespExc...
method findElement (line 457) | public IOSElement findElement(XCUIElementType xcuiElementType) throws ...
method findElement (line 469) | public IOSElement findElement(String selector, String value) throws So...
method findElement (line 482) | public IOSElement findElement(IOSSelector iosSelector, String value, I...
method findElement (line 494) | public IOSElement findElement(XCUIElementType xcuiElementType, Integer...
method findElement (line 507) | public IOSElement findElement(String selector, String value, Integer r...
method findElement (line 521) | public IOSElement findElement(IOSSelector iosSelector, String value, I...
method findElement (line 534) | public IOSElement findElement(XCUIElementType xcuiElementType, Integer...
method findElement (line 548) | public IOSElement findElement(String selector, String value, Integer r...
method findElementList (line 560) | public List<IOSElement> findElementList(IOSSelector iosSelector, Strin...
method findElementList (line 571) | public List<IOSElement> findElementList(XCUIElementType xcuiElementTyp...
method findElementList (line 583) | public List<IOSElement> findElementList(String selector, String value)...
method findElementList (line 596) | public List<IOSElement> findElementList(IOSSelector iosSelector, Strin...
method findElementList (line 608) | public List<IOSElement> findElementList(XCUIElementType xcuiElementTyp...
method findElementList (line 621) | public List<IOSElement> findElementList(String selector, String value,...
method findElementList (line 635) | public List<IOSElement> findElementList(IOSSelector iosSelector, Strin...
method findElementList (line 648) | public List<IOSElement> findElementList(XCUIElementType xcuiElementTyp...
method findElementList (line 662) | public List<IOSElement> findElementList(String selector, String value,...
method activeElement (line 671) | public IOSElement activeElement() throws SonicRespException{
method screenshot (line 681) | public byte[] screenshot() throws SonicRespException {
method setAppiumSettings (line 691) | public void setAppiumSettings(JSONObject settings) throws SonicRespExc...
method rotate (line 699) | public void rotate(Orientation orientation) throws SonicRespException {
method getRotate (line 703) | public Orientation getRotate() throws SonicRespException {
FILE: src/main/java/org/cloud/sonic/driver/ios/enums/ActionType.java
type ActionType (line 19) | public enum ActionType {
method ActionType (line 27) | ActionType(String type) {
method getType (line 31) | public String getType() {
FILE: src/main/java/org/cloud/sonic/driver/ios/enums/AuthResource.java
type AuthResource (line 19) | public enum AuthResource {
method AuthResource (line 39) | AuthResource(int resource) {
method getResource (line 43) | public int getResource() {
FILE: src/main/java/org/cloud/sonic/driver/ios/enums/IOSSelector.java
type IOSSelector (line 19) | public enum IOSSelector {
method IOSSelector (line 34) | IOSSelector(String selector) {
method getSelector (line 38) | public String getSelector() {
FILE: src/main/java/org/cloud/sonic/driver/ios/enums/Orientation.java
type Orientation (line 8) | public enum Orientation {
method Orientation (line 17) | Orientation(int orientation) {
method getValue (line 21) | public JSONObject getValue() {
FILE: src/main/java/org/cloud/sonic/driver/ios/enums/SystemButton.java
type SystemButton (line 19) | public enum SystemButton {
method SystemButton (line 26) | SystemButton(String button) {
method getButton (line 30) | public String getButton() {
FILE: src/main/java/org/cloud/sonic/driver/ios/enums/TextKey.java
type TextKey (line 19) | public enum TextKey {
method TextKey (line 25) | TextKey(String key) {
method getKey (line 29) | public String getKey() {
FILE: src/main/java/org/cloud/sonic/driver/ios/enums/XCUIElementType.java
type XCUIElementType (line 19) | public enum XCUIElementType {
method XCUIElementType (line 119) | XCUIElementType(String type) {
method getType (line 123) | public String getType() {
FILE: src/main/java/org/cloud/sonic/driver/ios/models/TouchActions.java
class TouchActions (line 28) | @Getter
class FingerTouchAction (line 34) | @Getter
method FingerTouchAction (line 42) | public FingerTouchAction(String fingerName) {
method FingerTouchAction (line 47) | public FingerTouchAction() {
method press (line 51) | public FingerTouchAction press(int x, int y) {
method wait (line 58) | public FingerTouchAction wait(int ms) {
method move (line 65) | public FingerTouchAction move(int x, int y) {
method release (line 73) | public FingerTouchAction release() {
class TouchAction (line 80) | @Getter
method TouchAction (line 85) | public TouchAction(ActionType actionType) {
class MoveAction (line 90) | @Getter
method MoveAction (line 96) | public MoveAction() {
class PauseAction (line 101) | @Getter
method PauseAction (line 106) | public PauseAction() {
method TouchActions (line 111) | public TouchActions() {
method TouchActions (line 115) | public TouchActions(FingerTouchAction finger) {
method finger (line 120) | public FingerTouchAction finger(String name) {
FILE: src/main/java/org/cloud/sonic/driver/ios/service/IOSElement.java
type IOSElement (line 26) | public interface IOSElement extends BaseElement {
method click (line 28) | void click() throws SonicRespException;
method sendKeys (line 30) | void sendKeys(String text) throws SonicRespException;
method sendKeys (line 32) | void sendKeys(String text, int frequency) throws SonicRespException;
method clear (line 34) | void clear() throws SonicRespException;
method getText (line 36) | String getText() throws SonicRespException;
method screenshot (line 38) | byte[] screenshot() throws SonicRespException;
FILE: src/main/java/org/cloud/sonic/driver/ios/service/WdaClient.java
type WdaClient (line 33) | public interface WdaClient {
method setGlobalTimeOut (line 35) | void setGlobalTimeOut(int timeOut);
method getRespHandler (line 37) | RespHandler getRespHandler();
method setRespHandler (line 39) | void setRespHandler(RespHandler respHandler);
method getLogger (line 41) | Logger getLogger();
method showLog (line 43) | void showLog();
method disableLog (line 45) | void disableLog();
method getRemoteUrl (line 48) | String getRemoteUrl();
method setRemoteUrl (line 50) | void setRemoteUrl(String remoteUrl);
method getSessionId (line 52) | String getSessionId();
method setSessionId (line 54) | void setSessionId(String sessionId);
method newSession (line 56) | void newSession(JSONObject capabilities) throws SonicRespException;
method closeSession (line 58) | void closeSession() throws SonicRespException;
method checkSessionId (line 60) | void checkSessionId() throws SonicRespException;
method getWindowSize (line 63) | WindowSize getWindowSize() throws SonicRespException;
method isLocked (line 66) | boolean isLocked() throws SonicRespException;
method lock (line 68) | void lock() throws SonicRespException;
method unlock (line 70) | void unlock() throws SonicRespException;
method performTouchAction (line 73) | void performTouchAction(TouchActions touchActions) throws SonicRespExc...
method pressButton (line 76) | void pressButton(String buttonName) throws SonicRespException;
method doubleTap (line 78) | void doubleTap(int x, int y) throws SonicRespException;
method sendKeys (line 81) | void sendKeys(String text, Integer frequency) throws SonicRespException;
method setPasteboard (line 83) | void setPasteboard(String contentType, String content) throws SonicRes...
method getPasteboard (line 85) | byte[] getPasteboard(String contentType) throws SonicRespException;
method pageSource (line 88) | String pageSource() throws SonicRespException;
method sendSiriCommand (line 91) | void sendSiriCommand(String command) throws SonicRespException;
method appActivate (line 94) | void appActivate(String bundleId) throws SonicRespException;
method appTerminate (line 96) | boolean appTerminate(String bundleId) throws SonicRespException;
method appRunBackground (line 98) | void appRunBackground(int duration) throws SonicRespException;
method appAuthReset (line 100) | void appAuthReset(int resource) throws SonicRespException;
method setDefaultFindElementInterval (line 103) | void setDefaultFindElementInterval(Integer retry, Integer interval);
method findElement (line 105) | IOSElement findElement(String selector, String value, Integer retry, I...
method findElementList (line 107) | List<IOSElement> findElementList(String selector, String value, Intege...
method activeElement (line 110) | IOSElement activeElement() throws SonicRespException;
method screenshot (line 113) | byte[] screenshot() throws SonicRespException;
method setAppiumSettings (line 116) | void setAppiumSettings(JSONObject settings) throws SonicRespException;
method swipe (line 118) | void swipe(double fromX, double fromY, double toX, double toY, double ...
method rotate (line 119) | void rotate(Orientation orientation) throws SonicRespException;
method getRotate (line 120) | Orientation getRotate() throws SonicRespException;
FILE: src/main/java/org/cloud/sonic/driver/ios/service/impl/IOSElementImpl.java
class IOSElementImpl (line 31) | public class IOSElementImpl implements IOSElement {
method IOSElementImpl (line 36) | public IOSElementImpl(String id, WdaClient wdaClient) {
method click (line 42) | @Override
method sendKeys (line 56) | @Override
method sendKeys (line 61) | @Override
method clear (line 79) | @Override
method getText (line 93) | @Override
method getRect (line 108) | @Override
method getAttribute (line 124) | @Override
method getUniquelyIdentifies (line 139) | @Override
method screenshot (line 144) | @Override
method isDisplayed (line 159) | @Override
FILE: src/main/java/org/cloud/sonic/driver/ios/service/impl/WdaClientImpl.java
class WdaClientImpl (line 38) | public class WdaClientImpl implements WdaClient {
method WdaClientImpl (line 48) | public WdaClientImpl() {
method checkBundleId (line 53) | private void checkBundleId(String bundleId) throws SonicRespException {
method parseElementId (line 60) | private String parseElementId(Object o) {
method setGlobalTimeOut (line 72) | @Override
method getRespHandler (line 77) | @Override
method setRespHandler (line 82) | @Override
method getLogger (line 87) | @Override
method showLog (line 92) | @Override
method disableLog (line 97) | @Override
method getRemoteUrl (line 102) | @Override
method setRemoteUrl (line 107) | @Override
method getSessionId (line 112) | @Override
method setSessionId (line 117) | @Override
method newSession (line 122) | @Override
method closeSession (line 140) | @Override
method checkSessionId (line 147) | @Override
method getWindowSize (line 155) | @Override
method isLocked (line 168) | @Override
method lock (line 181) | @Override
method unlock (line 193) | @Override
method performTouchAction (line 205) | @Override
method pressButton (line 218) | @Override
method doubleTap (line 233) | @Override
method sendKeys (line 250) | @Override
method setPasteboard (line 266) | @Override
method getPasteboard (line 282) | @Override
method pageSource (line 299) | @Override
method sendSiriCommand (line 312) | @Override
method appActivate (line 332) | @Override
method appTerminate (line 348) | @Override
method appRunBackground (line 365) | @Override
method appAuthReset (line 380) | @Override
method setDefaultFindElementInterval (line 395) | @Override
method findElement (line 405) | @Override
method findElementList (line 447) | @Override
method activeElement (line 494) | @Override
method screenshot (line 520) | @Override
method setAppiumSettings (line 534) | @Override
method swipe (line 549) | @Override
method rotate (line 574) | @Override
method getRotate (line 586) | @Override
FILE: src/main/java/org/cloud/sonic/driver/poco/PocoDriver.java
class PocoDriver (line 34) | public class PocoDriver {
method PocoDriver (line 42) | public PocoDriver(PocoEngine pocoEngine) {
method PocoDriver (line 52) | public PocoDriver(PocoEngine pocoEngine, int port) {
method closeDriver (line 60) | public void closeDriver() {
method showLog (line 67) | public void showLog() {
method disableLog (line 74) | public void disableLog() {
method getPageSource (line 84) | public PocoElement getPageSource() throws SonicRespException {
method getPageSourceForJsonString (line 94) | public String getPageSourceForJsonString() throws SonicRespException {
method getPageSourceForXmlElement (line 104) | public Element getPageSourceForXmlElement() throws SonicRespException {
method findElements (line 114) | public List<PocoElement> findElements(String selector, String expressi...
method findElements (line 124) | public List<PocoElement> findElements(PocoSelector selector, String ex...
method findElement (line 134) | public PocoElement findElement(String selector, String expression) thr...
method findElement (line 144) | public PocoElement findElement(PocoSelector selector, String expressio...
method freezeSource (line 151) | public void freezeSource() {
method thawSource (line 158) | public void thawSource() {
method getScreenSize (line 168) | public WindowSize getScreenSize() throws SonicRespException {
FILE: src/main/java/org/cloud/sonic/driver/poco/enums/PocoEngine.java
type PocoEngine (line 19) | public enum PocoEngine {
method PocoEngine (line 31) | PocoEngine(String name, int defaultPort) {
method getDefaultPort (line 36) | public int getDefaultPort() {
FILE: src/main/java/org/cloud/sonic/driver/poco/enums/PocoSelector.java
type PocoSelector (line 19) | public enum PocoSelector {
method PocoSelector (line 26) | PocoSelector(String selector) {
method getSelector (line 30) | public String getSelector() {
FILE: src/main/java/org/cloud/sonic/driver/poco/models/PocoElement.java
class PocoElement (line 32) | @Getter
method getRect (line 44) | @Override
method getAttribute (line 53) | @Override
method getUniquelyIdentifies (line 58) | @Override
method isDisplayed (line 63) | @Override
class Payload (line 68) | @Getter
class ZOrders (line 89) | @Getter
method ZOrders (line 96) | public ZOrders() {
method Payload (line 100) | public Payload() {
method PocoElement (line 105) | public PocoElement(RootElement root) {
method PocoElement (line 112) | public PocoElement(RootElement root, Element currentNodeXmlElement) {
method getPayload (line 119) | public Payload getPayload() {
method getChildren (line 132) | public List<PocoElement> getChildren() {
method parseXmlNode (line 157) | public void parseXmlNode(Element xmlNode) {
method parseFloatAttrList (line 193) | private List<Float> parseFloatAttrList(String floatAttrStr) {
method currentTheNodeExists (line 203) | public Boolean currentTheNodeExists() {
method getParentNode (line 207) | public PocoElement getParentNode() {
FILE: src/main/java/org/cloud/sonic/driver/poco/models/RootElement.java
class RootElement (line 21) | public class RootElement {
method RootElement (line 25) | public RootElement() {
method RootElement (line 28) | public RootElement(Element XmlElement) {
method RootElement (line 32) | public RootElement(Element XmlElement, long version) {
method getXmlElement (line 38) | public Element getXmlElement() {
method setXmlElement (line 42) | public void setXmlElement(Element xmlElement) {
method getVersion (line 46) | public long getVersion() {
method setVersion (line 50) | public void setVersion(long version) {
method updateVersion (line 54) | public synchronized void updateVersion(Element rootXmlElement) {
FILE: src/main/java/org/cloud/sonic/driver/poco/service/PocoClient.java
type PocoClient (line 32) | public interface PocoClient {
method getLogger (line 34) | Logger getLogger();
method showLog (line 36) | void showLog();
method disableLog (line 38) | void disableLog();
method newClient (line 41) | void newClient(PocoEngine engine, int port);
method closeClient (line 43) | void closeClient();
method pageSource (line 46) | PocoElement pageSource() throws SonicRespException;
method pageSourceForJsonString (line 48) | String pageSourceForJsonString() throws SonicRespException;
method pageSourceForXmlElement (line 50) | Element pageSourceForXmlElement() throws SonicRespException;
method findElement (line 52) | PocoElement findElement(String selector, String expression) throws Son...
method findElements (line 54) | List<PocoElement> findElements(String selector, String expression) thr...
method freezeSource (line 56) | void freezeSource();
method thawSource (line 58) | void thawSource();
method getScreenSize (line 61) | WindowSize getScreenSize() throws SonicRespException;
FILE: src/main/java/org/cloud/sonic/driver/poco/service/PocoConnection.java
type PocoConnection (line 22) | public interface PocoConnection {
method connect (line 23) | void connect();
method disconnect (line 25) | void disconnect();
method sendAndReceive (line 27) | String sendAndReceive(JSONObject jsonObject) throws SonicRespException;
FILE: src/main/java/org/cloud/sonic/driver/poco/service/impl/PocoClientImpl.java
class PocoClientImpl (line 40) | public class PocoClientImpl implements PocoClient {
method PocoClientImpl (line 49) | public PocoClientImpl() {
method getLogger (line 54) | @Override
method showLog (line 59) | @Override
method disableLog (line 64) | @Override
method newClient (line 69) | @Override
method closeClient (line 80) | @Override
method pageSource (line 85) | @Override
method pageSourceForJsonString (line 91) | @Override
method pageSourceForXmlElement (line 108) | @Override
method findElement (line 119) | @Override
method findElements (line 125) | @Override
method parseAttr (line 166) | private String parseAttr(String express) {
method freezeSource (line 185) | @Override
method thawSource (line 190) | @Override
method getScreenSize (line 195) | @Override
FILE: src/main/java/org/cloud/sonic/driver/poco/service/impl/SocketClientImpl.java
class SocketClientImpl (line 32) | public class SocketClientImpl implements PocoConnection {
method SocketClientImpl (line 41) | public SocketClientImpl(int port, Logger logger) {
method sendAndReceive (line 46) | @Override
method connect (line 89) | @Override
method disconnect (line 117) | @Override
method intToByteArray (line 145) | private byte[] intToByteArray(int i) {
method toInt (line 154) | private int toInt(byte[] b) {
FILE: src/main/java/org/cloud/sonic/driver/poco/service/impl/WebSocketClientImpl.java
class WebSocketClientImpl (line 29) | public class WebSocketClientImpl implements PocoConnection {
method WebSocketClientImpl (line 36) | public WebSocketClientImpl(int port, Logger logger) {
method sendAndReceive (line 41) | @Override
method connect (line 74) | @Override
method disconnect (line 119) | @Override
FILE: src/main/java/org/cloud/sonic/driver/poco/util/PocoJsonToXml.java
class PocoJsonToXml (line 25) | public class PocoJsonToXml {
method jsonObjToXml (line 32) | public static String jsonObjToXml(JSONObject jo) throws SonicRespExcep...
method jsonToXml (line 44) | @SuppressWarnings("rawtypes")
method addTag (line 75) | public static void addTag(StringBuffer xmlStr, String gt, String tagNa...
method getAttrStr (line 86) | public static StringBuilder getAttrStr(JSONObject payload) {
method checkName (line 108) | private static boolean checkName(String name) {
method escapingSpecialCharacters (line 119) | private static String escapingSpecialCharacters(String originStr) {
FILE: src/main/java/org/cloud/sonic/driver/poco/util/PocoTool.java
class PocoTool (line 21) | public class PocoTool {
method checkPocoRpcResultID (line 22) | public static boolean checkPocoRpcResultID(String pocoRpcResult, Strin...
FILE: src/main/java/org/cloud/sonic/driver/poco/util/PocoXYTransformer.java
class PocoXYTransformer (line 22) | public class PocoXYTransformer {
method PocoTransformerVertical (line 35) | public static double[] PocoTransformerVertical(double x, double y, dou...
method VerticalTransformerPoco (line 63) | public static double[] VerticalTransformerPoco(double x, double y, dou...
FILE: src/test/java/org/cloud/sonic/driver/android/AndroidDriverTest.java
class AndroidDriverTest (line 19) | @RunWith(Parameterized.class)
method data (line 24) | @Parameterized.Parameters
method before (line 29) | @Before
method beforeClass (line 34) | @BeforeClass
method afterClass (line 52) | @AfterClass
method testSession (line 57) | @Test
method testSource (line 83) | @Test
method testGetWindowSize (line 88) | @Test
method testClipboard (line 96) | @Test
method testFindElement (line 102) | @Test
method testFindElementList (line 142) | @Test
method testScreenshot (line 148) | @Test
method testSetAppiumSettings (line 158) | @Test
method testSwipeAction (line 163) | @Test
method testTapAction (line 171) | @Test
method testLongPressAction (line 180) | @Test
method testDragAction (line 191) | @Test
method testTouchActionDown (line 197) | @Test
method testTouchActionMove (line 203) | @Test
method testTouchActionUp (line 209) | @Test
FILE: src/test/java/org/cloud/sonic/driver/android/service/UiaClientTest.java
class UiaClientTest (line 18) | public class UiaClientTest {
method before (line 23) | @BeforeClass
method testGetWindowSize (line 39) | @Test
method testSendKeys (line 53) | @Test
method testSetPasteboard (line 66) | @Test
method testGetPasteboard (line 79) | @Test
method testPageSource (line 92) | @Test
method testFindElement (line 105) | @Test
method testFindElements (line 118) | @Test
method testSetAppiumSettings (line 131) | @Test
method testScreenShot (line 144) | @Test
FILE: src/test/java/org/cloud/sonic/driver/common/tool/RespHandlerTest.java
class RespHandlerTest (line 7) | public class RespHandlerTest {
method testTimeOut (line 8) | @Test
FILE: src/test/java/org/cloud/sonic/driver/common/tool/SonicRespExceptionTest.java
class SonicRespExceptionTest (line 22) | public class SonicRespExceptionTest {
method testSonicRespExceptionTest (line 24) | @Test
method testSonicRespExceptionTestWithMsg (line 30) | @Test
FILE: src/test/java/org/cloud/sonic/driver/ios/IOSDriverTest.java
class IOSDriverTest (line 37) | @RunWith(Parameterized.class)
method data (line 42) | @Parameterized.Parameters
method before (line 47) | @Before
method beforeClass (line 52) | @BeforeClass
method testApp (line 75) | @Test
method testSiriAndSendKeys (line 102) | @Test
method testPasteboard (line 131) | @Test
method testSwipe (line 143) | @Test
method testSwipeWithTime (line 150) | @Test
method testTap (line 155) | @Test
method testLongPress (line 162) | @Test
method testPerformTouchAction (line 168) | @Test
method testMultiFingerTouchAction (line 175) | @Test
method testPressButton (line 192) | @Test
method testGetPageSource (line 203) | @Test
method testLock (line 208) | @Test
method testSession (line 216) | @Test
method testFindElement (line 242) | @Test
method testFindElementList (line 290) | @Test
method testScreenshot (line 297) | @Test
method testGetWindowSize (line 307) | @Test
method testSetAppiumSettings (line 315) | @Test
method testIsDisplayed (line 320) | @Test
method testDoubleTap (line 332) | @Test
method testActiveElement (line 338) | @Test
method testOrientation (line 345) | @Test
method after (line 357) | @AfterClass
FILE: src/test/java/org/cloud/sonic/driver/ios/service/WdaClientTest.java
class WdaClientTest (line 35) | public class WdaClientTest {
method before (line 40) | @BeforeClass
method testGetWindowSize (line 56) | @Test
method testLocked (line 69) | @Test
method testLock (line 82) | @Test
method testUnLock (line 95) | @Test
method testPerformTouchAction (line 108) | @Test
method testSendKeys (line 121) | @Test
method testSetPasteboard (line 134) | @Test
method testGetPasteboard (line 147) | @Test
method testPageSource (line 160) | @Test
method testPressButton (line 173) | @Test
method testSiriCommand (line 186) | @Test
method testAppActivate (line 199) | @Test
method testAppTerminate (line 212) | @Test
method testAppRunBackground (line 225) | @Test
method testAppAuthReset (line 238) | @Test
method testFindElement (line 251) | @Test
method testFindElements (line 264) | @Test
method testSetAppiumSettings (line 277) | @Test
method testScreenShot (line 290) | @Test
FILE: src/test/java/org/cloud/sonic/driver/poco/PocoDriverTest.java
class PocoDriverTest (line 15) | public class PocoDriverTest {
method beforeClass (line 18) | @BeforeClass
method testPageSource (line 25) | @Test
method testFindElement (line 33) | @Test
method testFreeze (line 47) | @Test
method testWindowsSize (line 61) | @Test
method testNodeExist (line 68) | @Test
method testGetParent (line 78) | @Test
method testElementGetChild (line 89) | @Test
method testUpdateRootCase (line 97) | @Test
method testGetAttribute (line 113) | @Test
method afterClass (line 121) | @AfterClass
FILE: src/test/java/org/cloud/sonic/driver/poco/PocoJsonToXmlTest.java
class PocoJsonToXmlTest (line 17) | public class PocoJsonToXmlTest {
method testToXml (line 19) | @Test
method mockPocoResultTest (line 24) | @Test
FILE: src/test/java/org/cloud/sonic/driver/poco/PocoXYTransformerTest.java
class PocoXYTransformerTest (line 7) | public class PocoXYTransformerTest {
method testOriToUP (line 10) | @Test
method testUPToOri (line 26) | @Test
Condensed preview — 60 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (277K chars).
[
{
"path": ".github/dependabot.yml",
"chars": 109,
"preview": "version: 2\nupdates:\n - package-ecosystem: \"maven\"\n directory: \"/\"\n schedule:\n interval: \"weekly\"\n"
},
{
"path": ".github/workflows/maven.yml",
"chars": 361,
"preview": "name: maven compile test\n\non: [pull_request]\n\njobs:\n build:\n\n runs-on: ubuntu-latest\n\n steps:\n - uses: actions"
},
{
"path": ".github/workflows/release.yml",
"chars": 3391,
"preview": "# name: release to github\n\n# on:\n# push:\n# tags:\n# - \"*.*.*\"\n\n# jobs:\n# doc:\n# runs-on: ubuntu-latest\n"
},
{
"path": ".gitignore",
"chars": 51,
"preview": "/.idea/\n/target/\n/logs/\n*.iml\n*/.DS_Store\n.DS_Store"
},
{
"path": "LICENSE",
"chars": 11356,
"preview": " Apache License\n Version 2.0, January 2004\n "
},
{
"path": "README.md",
"chars": 3711,
"preview": "<p align=\"center\">\n <img width=\"80px\" src=\"https://raw.githubusercontent.com/SonicCloudOrg/sonic-server/main/logo.png\">"
},
{
"path": "README_CN.md",
"chars": 2967,
"preview": "<p align=\"center\">\n <img width=\"80px\" src=\"https://raw.githubusercontent.com/SonicCloudOrg/sonic-server/main/logo.png\">"
},
{
"path": "pom.xml",
"chars": 7617,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n xmlns:xsi=\"http://www"
},
{
"path": "src/main/java/org/cloud/sonic/driver/android/AndroidDriver.java",
"chars": 13717,
"preview": "/*\n * Copyright (C) [SonicCloudOrg] Sonic Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "src/main/java/org/cloud/sonic/driver/android/enmus/AndroidSelector.java",
"chars": 1038,
"preview": "/*\n * Copyright (C) [SonicCloudOrg] Sonic Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "src/main/java/org/cloud/sonic/driver/android/service/AndroidElement.java",
"chars": 1229,
"preview": "/*\n * Copyright (C) [SonicCloudOrg] Sonic Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "src/main/java/org/cloud/sonic/driver/android/service/UiaClient.java",
"chars": 3026,
"preview": "/*\n * Copyright (C) [SonicCloudOrg] Sonic Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "src/main/java/org/cloud/sonic/driver/android/service/impl/AndroidElementImpl.java",
"chars": 6454,
"preview": "/*\n * Copyright (C) [SonicCloudOrg] Sonic Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "src/main/java/org/cloud/sonic/driver/android/service/impl/UiaClientImpl.java",
"chars": 18095,
"preview": "/*\n * Copyright (C) [SonicCloudOrg] Sonic Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "src/main/java/org/cloud/sonic/driver/common/enums/PasteboardType.java",
"chars": 947,
"preview": "/*\n * Copyright (C) [SonicCloudOrg] Sonic Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "src/main/java/org/cloud/sonic/driver/common/models/BaseElement.java",
"chars": 681,
"preview": "package org.cloud.sonic.driver.common.models;\n\nimport org.cloud.sonic.driver.common.tool.SonicRespException;\n\npublic int"
},
{
"path": "src/main/java/org/cloud/sonic/driver/common/models/BaseResp.java",
"chars": 1005,
"preview": "/*\n * Copyright (C) [SonicCloudOrg] Sonic Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "src/main/java/org/cloud/sonic/driver/common/models/Capabilities.java",
"chars": 923,
"preview": "/*\n * Copyright (C) [SonicCloudOrg] Sonic Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "src/main/java/org/cloud/sonic/driver/common/models/ElementRect.java",
"chars": 1138,
"preview": "/*\n * Copyright (C) [SonicCloudOrg] Sonic Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "src/main/java/org/cloud/sonic/driver/common/models/ErrorMsg.java",
"chars": 938,
"preview": "/*\n * Copyright (C) [SonicCloudOrg] Sonic Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "src/main/java/org/cloud/sonic/driver/common/models/SessionInfo.java",
"chars": 892,
"preview": "/*\n * Copyright (C) [SonicCloudOrg] Sonic Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "src/main/java/org/cloud/sonic/driver/common/models/WindowSize.java",
"chars": 869,
"preview": "/*\n * Copyright (C) [SonicCloudOrg] Sonic Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "src/main/java/org/cloud/sonic/driver/common/tool/Logger.java",
"chars": 1532,
"preview": "/*\n * Copyright (C) [SonicCloudOrg] Sonic Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "src/main/java/org/cloud/sonic/driver/common/tool/RespHandler.java",
"chars": 2620,
"preview": "/*\n * Copyright (C) [SonicCloudOrg] Sonic Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "src/main/java/org/cloud/sonic/driver/common/tool/SonicRespException.java",
"chars": 908,
"preview": "/*\n * Copyright (C) [SonicCloudOrg] Sonic Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "src/main/java/org/cloud/sonic/driver/ios/IOSDriver.java",
"chars": 18260,
"preview": "/*\n * Copyright (C) [SonicCloudOrg] Sonic Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "src/main/java/org/cloud/sonic/driver/ios/enums/ActionType.java",
"chars": 947,
"preview": "/*\n * Copyright (C) [SonicCloudOrg] Sonic Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "src/main/java/org/cloud/sonic/driver/ios/enums/AuthResource.java",
"chars": 1288,
"preview": "/*\n * Copyright (C) [SonicCloudOrg] Sonic Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "src/main/java/org/cloud/sonic/driver/ios/enums/IOSSelector.java",
"chars": 1142,
"preview": "/*\n * Copyright (C) [SonicCloudOrg] Sonic Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "src/main/java/org/cloud/sonic/driver/ios/enums/Orientation.java",
"chars": 918,
"preview": "package org.cloud.sonic.driver.ios.enums;\n\nimport com.alibaba.fastjson.JSON;\nimport com.alibaba.fastjson.JSONObject;\n\nim"
},
{
"path": "src/main/java/org/cloud/sonic/driver/ios/enums/SystemButton.java",
"chars": 943,
"preview": "/*\n * Copyright (C) [SonicCloudOrg] Sonic Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "src/main/java/org/cloud/sonic/driver/ios/enums/TextKey.java",
"chars": 887,
"preview": "/*\n * Copyright (C) [SonicCloudOrg] Sonic Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "src/main/java/org/cloud/sonic/driver/ios/enums/XCUIElementType.java",
"chars": 4419,
"preview": "/*\n * Copyright (C) [SonicCloudOrg] Sonic Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "src/main/java/org/cloud/sonic/driver/ios/models/TouchActions.java",
"chars": 3395,
"preview": "/*\n * Copyright (C) [SonicCloudOrg] Sonic Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "src/main/java/org/cloud/sonic/driver/ios/service/IOSElement.java",
"chars": 1219,
"preview": "/*\n * Copyright (C) [SonicCloudOrg] Sonic Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "src/main/java/org/cloud/sonic/driver/ios/service/WdaClient.java",
"chars": 3776,
"preview": "/*\n * Copyright (C) [SonicCloudOrg] Sonic Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "src/main/java/org/cloud/sonic/driver/ios/service/impl/IOSElementImpl.java",
"chars": 6907,
"preview": "/*\n * Copyright (C) [SonicCloudOrg] Sonic Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "src/main/java/org/cloud/sonic/driver/ios/service/impl/WdaClientImpl.java",
"chars": 23844,
"preview": "/*\n * Copyright (C) [SonicCloudOrg] Sonic Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "src/main/java/org/cloud/sonic/driver/poco/PocoDriver.java",
"chars": 4163,
"preview": "/*\n * Copyright (C) [SonicCloudOrg] Sonic Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "src/main/java/org/cloud/sonic/driver/poco/enums/PocoEngine.java",
"chars": 1204,
"preview": "/*\n * Copyright (C) [SonicCloudOrg] Sonic Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "src/main/java/org/cloud/sonic/driver/poco/enums/PocoSelector.java",
"chars": 951,
"preview": "/*\n * Copyright (C) [SonicCloudOrg] Sonic Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "src/main/java/org/cloud/sonic/driver/poco/models/PocoElement.java",
"chars": 7210,
"preview": "/*\n * Copyright (C) [SonicCloudOrg] Sonic Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "src/main/java/org/cloud/sonic/driver/poco/models/RootElement.java",
"chars": 1499,
"preview": "/*\n * Copyright (C) [SonicCloudOrg] Sonic Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "src/main/java/org/cloud/sonic/driver/poco/service/PocoClient.java",
"chars": 1798,
"preview": "/*\n * Copyright (C) [SonicCloudOrg] Sonic Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "src/main/java/org/cloud/sonic/driver/poco/service/PocoConnection.java",
"chars": 934,
"preview": "/*\n * Copyright (C) [SonicCloudOrg] Sonic Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "src/main/java/org/cloud/sonic/driver/poco/service/impl/PocoClientImpl.java",
"chars": 7651,
"preview": "/*\n * Copyright (C) [SonicCloudOrg] Sonic Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "src/main/java/org/cloud/sonic/driver/poco/service/impl/SocketClientImpl.java",
"chars": 5445,
"preview": "/*\n * Copyright (C) [SonicCloudOrg] Sonic Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "src/main/java/org/cloud/sonic/driver/poco/service/impl/WebSocketClientImpl.java",
"chars": 3813,
"preview": "/*\n * Copyright (C) [SonicCloudOrg] Sonic Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "src/main/java/org/cloud/sonic/driver/poco/util/PocoJsonToXml.java",
"chars": 4845,
"preview": "/*\n * Copyright (C) [SonicCloudOrg] Sonic Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "src/main/java/org/cloud/sonic/driver/poco/util/PocoTool.java",
"chars": 951,
"preview": "/*\n * Copyright (C) [SonicCloudOrg] Sonic Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "src/main/java/org/cloud/sonic/driver/poco/util/PocoXYTransformer.java",
"chars": 2928,
"preview": "/*\n * Copyright (C) [SonicCloudOrg] Sonic Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "src/test/java/org/cloud/sonic/driver/android/AndroidDriverTest.java",
"chars": 8229,
"preview": "package org.cloud.sonic.driver.android;\n\nimport com.alibaba.fastjson.JSONObject;\nimport org.cloud.sonic.driver.android.e"
},
{
"path": "src/test/java/org/cloud/sonic/driver/android/service/UiaClientTest.java",
"chars": 5192,
"preview": "package org.cloud.sonic.driver.android.service;\n\nimport com.alibaba.fastjson.JSONObject;\nimport org.cloud.sonic.driver.a"
},
{
"path": "src/test/java/org/cloud/sonic/driver/common/tool/RespHandlerTest.java",
"chars": 669,
"preview": "package org.cloud.sonic.driver.common.tool;\n\nimport cn.hutool.http.HttpUtil;\nimport org.junit.Assert;\nimport org.junit.T"
},
{
"path": "src/test/java/org/cloud/sonic/driver/common/tool/SonicRespExceptionTest.java",
"chars": 1218,
"preview": "/*\n * Copyright (C) [SonicCloudOrg] Sonic Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "src/test/java/org/cloud/sonic/driver/ios/IOSDriverTest.java",
"chars": 14320,
"preview": "/*\n * Copyright (C) [SonicCloudOrg] Sonic Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "src/test/java/org/cloud/sonic/driver/ios/service/WdaClientTest.java",
"chars": 9745,
"preview": "/*\n * Copyright (C) [SonicCloudOrg] Sonic Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "src/test/java/org/cloud/sonic/driver/poco/PocoDriverTest.java",
"chars": 5119,
"preview": "package org.cloud.sonic.driver.poco;\n\nimport org.cloud.sonic.driver.common.models.WindowSize;\nimport org.cloud.sonic.dri"
},
{
"path": "src/test/java/org/cloud/sonic/driver/poco/PocoJsonToXmlTest.java",
"chars": 14617,
"preview": "package org.cloud.sonic.driver.poco;\n\nimport com.alibaba.fastjson.JSON;\nimport org.cloud.sonic.driver.common.tool.SonicR"
},
{
"path": "src/test/java/org/cloud/sonic/driver/poco/PocoXYTransformerTest.java",
"chars": 1562,
"preview": "package org.cloud.sonic.driver.poco;\n\nimport org.cloud.sonic.driver.poco.util.PocoXYTransformer;\nimport org.junit.Assert"
}
]
About this extraction
This page contains the full source code of the SonicCloudOrg/sonic-driver-core GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 60 files (251.5 KB), approximately 61.9k tokens, and a symbol index with 568 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.