diff --git a/.buildsystem/deploy-github.sh b/.buildsystem/deploy-github.sh deleted file mode 100755 index 2980e730e..000000000 --- a/.buildsystem/deploy-github.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env bash -cd $(dirname $0)/.. - -if [ -z "$GITHUB_MAVEN_USERNAME" ]; then - echo "error: please set GITHUB_MAVEN_USERNAME environment variable" - exit 1 -fi - -if [ -z "$GITHUB_TOKEN" ]; then - echo "error: please set GITHUB_MAVEN_PASSWORD environment variable" - exit 1 -fi - -if [ -z "$GPG_PASSPHRASE" ]; then - echo "error: please set GPG_PASSPHRASE environment variable" - exit 1 -fi - -if [ -n "$GIT_TAG_NAME" ]; then - echo "on a tag -> deploy release version $GIT_TAG_NAME" - ./gradlew assemble -PreleaseMode=RELEASE - ./gradlew publishDefaultPublicationToGitHubRepository -PreleaseMode=RELEASE -else - echo "not on a tag -> deploy snapshot version" - ./gradlew assemble -PreleaseMode=SNAPSHOT - ./gradlew publishDefaultPublicationToGitHubRepository -PreleaseMode=SNAPSHOT -fi diff --git a/.buildsystem/deploy-sonatype.sh b/.buildsystem/deploy-sonatype.sh deleted file mode 100755 index 73001156f..000000000 --- a/.buildsystem/deploy-sonatype.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env bash -cd $(dirname $0)/.. - -if [ -z "$SONATYPE_USERNAME" ]; then - echo "error: please set SONATYPE_USERNAME environment variable" - exit 1 -fi - -if [ -z "$SONATYPE_PASSWORD" ]; then - echo "error: please set SONATYPE_PASSWORD environment variable" - exit 1 -fi - -if [ -z "$GPG_PASSPHRASE" ]; then - echo "error: please set GPG_PASSPHRASE environment variable" - exit 1 -fi - -if [ -z "$GIT_TAG_NAME" ]; then - echo "not on a tag -> deploy snapshot version" - ./gradlew assemble -PreleaseMode=SNAPSHOT - ./gradlew publishDefaultPublicationToOSSHRRepository -PreleaseMode=SNAPSHOT -else - echo "on a tag -> deploy release version $GIT_TAG_NAME" - ./gradlew assemble -PreleaseMode=RELEASE - ./gradlew publishDefaultPublicationToOSSHRRepository -PreleaseMode=RELEASE -fi diff --git a/.buildsystem/secring.gpg b/.buildsystem/secring.gpg deleted file mode 100644 index 42469d32d..000000000 Binary files a/.buildsystem/secring.gpg and /dev/null differ diff --git a/.github/git-commit-instructions.md b/.github/git-commit-instructions.md index c1d7f066a..2a0fc3d25 100644 --- a/.github/git-commit-instructions.md +++ b/.github/git-commit-instructions.md @@ -50,6 +50,10 @@ * `docs: clarify parameter usage in DataStore class` +### Updating Github Workflows + +* `ci: add workflow for automated release on tag` + --- ## Dependency Changes diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 3c401dcc9..1cd46aa04 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -5,12 +5,27 @@ on: - master - dev pull_request: + paths-ignore: + - '**/*.md' + - '.github/**.md' + - '.idea/**' + - 'jitpack.yml' + - '**/.gitignore' + - '.vscode/**' + - '**/.editorconfig' + - 'docs/**' + - 'LICENSE' + - 'NOTICE' workflow_dispatch: env: JAVA_VERSION: 17 JAVA_DISTRO: 'temurin' +concurrency: + group: ${{ github.ref }}-build + cancel-in-progress: ${{ github.ref != 'refs/heads/master' && github.ref != 'refs/heads/dev' }} + jobs: test: runs-on: ubuntu-latest @@ -25,7 +40,7 @@ jobs: - uses: malinskiy/action-android/install-sdk@release/0.1.7 - name: build & test - run: ./gradlew assemble test jacocoTestReport + run: ./gradlew assemble test :transport-ktor:test jacocoTestReport - name: Publish Test Report uses: mikepenz/action-junit-report@v6 if: always() @@ -35,7 +50,9 @@ jobs: - name: archive test results if: failure() - run: (cd adam/build/reports/tests/test; zip -r -X ../../../../../test-result.zip .) + run: | + cd adam/build/reports/tests/test + zip -r -X ../../../../../test-result.zip . - name: Save test output uses: actions/upload-artifact@v6 @@ -55,22 +72,13 @@ jobs: name: test-coverage path: test-coverage.zip - - name: codecov unit tests - uses: codecov/codecov-action@v5 - with: - token: ${{ secrets.CODECOV_TOKEN }} - files: ./adam/build/reports/jacoco/test/jacocoTestReport.xml - flags: unit - env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} - integration-test: needs: test runs-on: ubuntu-latest strategy: fail-fast: false matrix: - api: [ 24, 25, 26, 28, 29, 30, 31, 33, 34, 35 ] + api: [ 24, 34, 35 ] steps: - uses: actions/checkout@v6 - name: Set up JDK 17 @@ -167,13 +175,3 @@ jobs: with: name: logcat-${{ matrix.api }} path: artifacts/logcat.log - - - name: codecov integration tests - if: ${{ !cancelled() }} - uses: codecov/codecov-action@v5 - with: - token: ${{ secrets.CODECOV_TOKEN }} - files: ./adam/build/reports/jacoco/jacocoIntegrationTestReport/jacocoIntegrationTestReport.xml - flags: integration - env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/deploy-github-release.yaml b/.github/workflows/deploy-github-release.yaml deleted file mode 100644 index f8b28b884..000000000 --- a/.github/workflows/deploy-github-release.yaml +++ /dev/null @@ -1,21 +0,0 @@ -name: deploy-github-release -on: - push: - tags: '*' -jobs: - test: - runs-on: ubuntu-22.04 - steps: - - uses: actions/checkout@v1 - - name: Set up JDK 11 - uses: actions/setup-java@v2 - with: - distribution: 'temurin' - java-version: '11' - - uses: little-core-labs/get-git-tag@v3.0.2 - - name: deploy-release - run: .buildsystem/deploy-github.sh - env: - GITHUB_MAVEN_USERNAME: ${{ secrets.GITHUB_MAVEN_USERNAME }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} diff --git a/.github/workflows/deploy-sonatype-release.yaml b/.github/workflows/deploy-sonatype-release.yaml deleted file mode 100644 index ac4bcea01..000000000 --- a/.github/workflows/deploy-sonatype-release.yaml +++ /dev/null @@ -1,21 +0,0 @@ -name: deploy-sonatype-release -on: - push: - tags: '*' -jobs: - test: - runs-on: ubuntu-22.04 - steps: - - uses: actions/checkout@v1 - - name: Set up JDK 11 - uses: actions/setup-java@v2 - with: - distribution: 'temurin' - java-version: '11' - - uses: little-core-labs/get-git-tag@v3.0.2 - - name: deploy-release - run: .buildsystem/deploy-sonatype.sh - env: - SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }} - SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} - GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} diff --git a/.github/workflows/deploy-sonatype-snapshot.yaml b/.github/workflows/deploy-sonatype-snapshot.yaml deleted file mode 100644 index 12950685b..000000000 --- a/.github/workflows/deploy-sonatype-snapshot.yaml +++ /dev/null @@ -1,23 +0,0 @@ -name: deploy-sonatype-snapshot -on: - push: - branches: - - master - tags-ignore: - - '*' -jobs: - deploy: - runs-on: ubuntu-22.04 - steps: - - uses: actions/checkout@v1 - - name: Set up JDK 11 - uses: actions/setup-java@v2 - with: - distribution: 'temurin' - java-version: '11' - - name: deploy-snapshot - run: bash .buildsystem/deploy-sonatype.sh - env: - SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }} - SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} - GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} diff --git a/.github/workflows/github-pages.yml b/.github/workflows/github-pages.yml index efbfd4786..65564197e 100644 --- a/.github/workflows/github-pages.yml +++ b/.github/workflows/github-pages.yml @@ -1,26 +1,44 @@ -name: Build and deploy docs +name: Docs on: push: branches: - master + # pull_request: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: pages + cancel-in-progress: true + +env: + JAVA_VERSION: 17 + JAVA_DISTRO: 'temurin' jobs: github-pages: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - name: Set up JDK 11 - uses: actions/setup-java@v2 + - uses: actions/checkout@v6 + + - name: Set up JDK + uses: actions/setup-java@v5 with: - distribution: 'temurin' - java-version: '11' + java-version: ${{ env.JAVA_VERSION }} + distribution: ${{ env.JAVA_DISTRO }} + - name: Generate dokka files - run: ./gradlew :adam:dokkaHtml - - uses: helaili/jekyll-action@2.0.4 - env: - JEKYLL_PAT: ${{ secrets.JEKYLL_PAT }} + run: ./gradlew :adam:dokkaGeneratePublicationHtml + + - name: Upload Pages artifact + uses: actions/upload-pages-artifact@v4 with: - jekyll_src: docs - target_branch: gh-pages - gem_src: docs + path: docs/api + + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml new file mode 100644 index 000000000..8d3727df3 --- /dev/null +++ b/.github/workflows/lint.yaml @@ -0,0 +1,46 @@ +name: Run Lint + +on: + pull_request: + paths-ignore: + - '**.md' + - '**.txt' + - '.gitignore' + - 'LICENSE' + - 'docs/**' + - '.github/**' + - '!.github/workflows/**' + - 'renovate.json' + +env: + JAVA_VERSION: 17 + JAVA_DISTRO: 'temurin' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + lint: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Validate Gradle Wrapper + uses: gradle/actions/wrapper-validation@v5 + + - name: Set up JDK 17 + uses: actions/setup-java@v5 + with: + java-version: ${{ env.JAVA_VERSION }} + distribution: ${{ env.JAVA_DISTRO }} + + - name: Set up gradle + uses: gradle/actions/setup-gradle@v5 + + - name: Run Lint + run: | + git fetch origin dev + ./gradlew spotlessCheck diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml new file mode 100644 index 000000000..70fa4419f --- /dev/null +++ b/.github/workflows/publish.yaml @@ -0,0 +1,38 @@ +name: Publish GitHub Release +on: + release: + types: [ created ] + +env: + JAVA_VERSION: 17 + JAVA_DISTRO: 'temurin' + +jobs: + publish: + name: Publish to GitHub Packages + runs-on: macos-latest + permissions: + contents: read + packages: write + + steps: + - uses: actions/checkout@v6 + - uses: actions/setup-java@v5 + with: + java-version: ${{ env.JAVA_VERSION }} + distribution: ${{ env.JAVA_DISTRO }} + + - name: Publish to GitHub Packages + run: ./gradlew publishAllPublicationsToGitHubPackagesRepository --no-configuration-cache + env: + GITHUB_ACTOR: ${{ github.actor }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + RELEASE_TAG: ${{ github.event.release.tag_name }} + + - name: Upload build reports + if: failure() + uses: actions/upload-artifact@v6 + with: + name: build-reports + path: '**/build/reports/' + retention-days: 7 diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..706d584d6 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,100 @@ +# AGENTS.md + +## Build & Test + +- Build: `./gradlew build` +- Assemble only: `./gradlew assemble` +- Lint: `./gradlew spotlessApply` +- Run all tests: `./gradlew test` +- Run single test: `./gradlew :adam:test --tests "com.malinskiy.adam.ClassName.testMethod"` +- Run single test in other modules: `./gradlew :transport-ktor:test --tests "com.malinskiy.adam.transport.ktor.KtorSocketRegressionTest"` +- Ktor transport regression tests: `./gradlew :transport-ktor:test --tests "com.malinskiy.adam.transport.ktor.KtorSocketRegressionTest"` + - Guards Ktor byte-array offset/limit API semantics +- Integration tests: `./gradlew :adam:integrationTest` +- Coverage reports: `./gradlew jacocoTestReport` (unit), `./gradlew :adam:jacocoIntegrationTestReport` (integration) +- Combined coverage: `./gradlew :adam:jacocoCombinedTestReport` +- Generate docs: `./gradlew :adam:dokkaGeneratePublicationHtml` (output: `docs/api/`) + +## Architecture + +Kotlin coroutine-based ADB (Android Debug Bridge) client library. + +### Modules + +- **adam** — Core ADB client (requests, transport, protobuf/gRPC). Main package: `com.malinskiy.adam` +- **transport-ktor** — Ktor-based transport implementation +- **android-junit4** — Android JUnit4 test rules for adam +- **android-junit4-test-annotation-producer** — Android test annotation producer +- **android-testrunner-contract** — Android test runner contract interfaces +- **androidx-screencapture** — AndroidX screen capture helpers +- **server/** — Server stubs for testing (`server-stub`, `server-stub-junit4`, `server-stub-junit5`) +- **buildSrc** — Convention plugins and build logic + +### Key Types + +- `AndroidDebugBridgeClient` — Main entry point for ADB communication +- `Request` — Base class for all ADB requests; subclasses: `ComplexRequest`, `AsyncChannelRequest`, `MultiRequest` +- `Socket` — Interface for transport layer (implemented by `KtorSocket`) +- `Target` — Request targeting (HostTarget, DeviceTarget, etc.) + +## Key Dependencies + +- Kotlin 2.3.10, Coroutines 1.10.2 +- Ktor 3.4.0 (network/transport) +- Vert.x 5.0.7 (core, kotlin, coroutines) +- Protobuf 4.33.5 (javalite) + gRPC 1.79.0 +- Android Gradle Plugin 9.0.0 (compileSdk 36, minSdk 24, targetSdk 36) +- JVM target: 17 + +## Code Style + +### Formatting + +- Kotlin, JVM target 17 +- ktlint (IntelliJ IDEA style) via Spotless (`com.diffplug.spotless`) +- 4-space indent, UTF-8, max line length 120 +- Trailing commas allowed +- Trailing whitespace trimmed, final newline required +- Explicit API mode enabled for library modules (`kotlin.explicitApi()`) + +### Imports + +- No star imports (threshold set to 999 to force explicit imports) +- Import aliases for disambiguation: `import io.ktor.network.sockets.Socket as RealKtorSocket` + +### Naming Conventions + +- Classes: PascalCase (e.g., `AndroidDebugBridgeClient`, `ListDevicesRequest`) +- Functions/properties: camelCase (e.g., `execute`, `readElement`, `socketIdleTimeout`) +- Constants: `UPPER_SNAKE_CASE` in companion objects or objects +- Extension functions: placed in `extension/` package (e.g., `Socket.kt` extensions) +- Exception classes: suffix `Exception` (e.g., `RequestRejectedException`, `PushFailedException`) + +### Types + +- Use `public` modifier explicitly (explicit API mode) +- Prefer `suspend` functions for async operations +- Use `Result` or throw exceptions for error handling +- Prefer `ByteBuffer` and `ByteArray` for binary data +- Use Kotlin nullable types (`?`) for optional values + +### Error Handling + +- Custom exceptions extend `RuntimeException` (e.g., `RequestRejectedException`, `RequestValidationException`) +- Request validation uses `ValidationResponse` data class +- Socket operations catch exceptions during cleanup and log them + +### Logging + +- Use `AdamLogging.logger {}` to create a logger +- Log levels: `debug`, `info`, `warn`, `error`, `trace` +- Pattern: `log.debug(e) { "message" }` + +## Testing + +- JUnit 4 with `@Test`, `@Rule` +- assertk for assertions: `assertThat(value).isEqualTo(expected)` +- `runBlocking { }` for coroutine tests +- Server stubs from `:server:server-stub-junit4` for mocking ADB server +- Test naming: `test` (e.g., `testReturnsProperContent`) +- Integration tests in `src/integrationTest/kotlin/` diff --git a/CODEOWNERS b/CODEOWNERS index d32aeef37..b26313391 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1 +1 @@ -* @malinskiy \ No newline at end of file +* @ArthurKun21 \ No newline at end of file diff --git a/README.md b/README.md index ae43ea782..bce19f4c0 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,20 @@ +# adam + +Android Debug Bridge helper written in Kotlin + +## Links + +### Original project + ![Maven Central](https://img.shields.io/maven-central/v/com.malinskiy.adam/adam) -![Codecov](https://img.shields.io/codecov/c/github/Malinskiy/adam) ![Documentation](https://img.shields.io/badge/docs-documentation-green?link=https://malinskiy.github.io/adam/) -# adam -Android Debug Bridge helper written in Kotlin +### JitPack and GitHub Packages + +[![Release](https://jitpack.io/v/ArthurKun21/adam.svg)](https://jitpack.io/#ArthurKun21/adam) ## Motivation + The only way to get access to the adb programmatically from java world currently is to use the ddmlib java project. Unfortunately it has several limitations, namely: 1. Sub-optimal resources usage diff --git a/adam/build.gradle.kts b/adam/build.gradle.kts index 0f26b4217..79b75f459 100644 --- a/adam/build.gradle.kts +++ b/adam/build.gradle.kts @@ -1,3 +1,8 @@ +import adam.buildlogic.AdamPublishing +import adam.buildlogic.configureAdamPom +import adam.buildlogic.configureIntegrationTestSourceSet +import adam.buildlogic.configureIntegrationTestTasks +import adam.buildlogic.integrationTestImplementation import com.google.protobuf.gradle.id import com.google.protobuf.gradle.remove @@ -22,10 +27,19 @@ plugins { id("jacoco") id("org.jetbrains.dokka") alias(libs.plugins.protobuf) + alias(libs.plugins.vanniktech.maven.publish) id("idea") } +mavenPublishing { + coordinates(AdamPublishing.GROUP, "adam", version.toString()) + pom { + name.set("adam") + description.set("Android Debug Bridge helper - core library") + configureAdamPom() + } +} protobuf { protoc { @@ -62,39 +76,26 @@ protobuf { } } -sourceSets { - create("integrationTest") { - compileClasspath += sourceSets.main.get().output - runtimeClasspath += sourceSets.main.get().output - } -} - -val integrationTestImplementation: Configuration by configurations.getting { - extendsFrom(configurations.implementation.get()) -} - -configurations["integrationTestRuntimeOnly"].extendsFrom(configurations.runtimeOnly.get()) +configureIntegrationTestSourceSet() -fun DependencyHandler.`integrationTestImplementation`(dependencyNotation: Any): Dependency? = - add("integrationTestImplementation", dependencyNotation) +val integrationTestTasks = configureIntegrationTestTasks( + configureIntegrationTest = { jacocoIntegrationTestReport -> + finalizedBy(jacocoIntegrationTestReport) + }, + configureJacocoReport = { integrationTest -> + executionData(fileTree(layout.buildDirectory).include("jacoco/integrationTest.exec")) + mustRunAfter(integrationTest) + }, +) +val integrationTest = integrationTestTasks.integrationTest -val integrationTest = tasks.register("integrationTest") { - description = "Runs integration tests" - group = "verification" - - testClassesDirs = sourceSets["integrationTest"].output.classesDirs - classpath = sourceSets["integrationTest"].runtimeClasspath - shouldRunAfter("test") - - jacoco { - include("**") +val jacocoIntegrationTestReport = integrationTestTasks.jacocoIntegrationTestReport +jacocoIntegrationTestReport.configure { + reports { + xml.required.set(true) } } -integrationTest.configure { - outputs.upToDateWhen { false } - finalizedBy("jacocoIntegrationTestReport") -} // See https://github.com/jacoco/jacoco/issues/1357 tasks.withType { @@ -110,20 +111,6 @@ val connectedAndroidTest = tasks.register("connectedAndroidTest") { dependsOn(integrationTest) } -val jacocoIntegrationTestReport = tasks.register("jacocoIntegrationTestReport") { - description = "Generates code coverage report for integrationTest task" - group = "verification" - reports { - xml.required.set(true) - } - - executionData(fileTree(layout.buildDirectory).include("jacoco/integrationTest.exec")) - sourceSets(sourceSets.getByName("integrationTest")) - classDirectories.setFrom(sourceSets.getByName("main").output.classesDirs) - mustRunAfter(integrationTest) -} -tasks.check { dependsOn(integrationTest, jacocoIntegrationTestReport) } - val jacocoCombinedTestReport = tasks.register("jacocoCombinedTestReport") { description = "Generates code coverage report for all test tasks" group = "verification" @@ -134,21 +121,17 @@ val jacocoCombinedTestReport = tasks.register("jacocoCombinedTestR mustRunAfter(tasks["test"], integrationTest) } -tasks.jacocoTestReport { - reports { - xml.required.set(true) +dokka { + dokkaPublications.html { + outputDirectory.set(rootProject.rootDir.resolve("docs/api")) } } -tasks.dokkaHtml.configure { - outputDirectory.set(rootProject.rootDir.resolve("docs/api")) -} - dependencies { implementation(libs.annotations) implementation(kotlin("stdlib-jdk8")) implementation(libs.coroutines.core) - implementation(libs.logging) + implementation(libs.logcat) api(libs.protobuf.lite) api(libs.grpc.protobuf.lite) api(libs.grpc.kotlin.stub) diff --git a/adam/src/integrationTest/kotlin/com/malinskiy/adam/extension/File.kt b/adam/src/integrationTest/kotlin/com/malinskiy/adam/extension/File.kt index 12bb0c107..f7bb34d7a 100644 --- a/adam/src/integrationTest/kotlin/com/malinskiy/adam/extension/File.kt +++ b/adam/src/integrationTest/kotlin/com/malinskiy/adam/extension/File.kt @@ -25,4 +25,4 @@ fun File.md5(): String { return digested.joinToString("") { String.format("%02x", it) } -} \ No newline at end of file +} diff --git a/adam/src/integrationTest/kotlin/com/malinskiy/adam/extension/FileExtension.kt b/adam/src/integrationTest/kotlin/com/malinskiy/adam/extension/FileExtension.kt index 8ac0816c1..4e38df5f9 100644 --- a/adam/src/integrationTest/kotlin/com/malinskiy/adam/extension/FileExtension.kt +++ b/adam/src/integrationTest/kotlin/com/malinskiy/adam/extension/FileExtension.kt @@ -21,7 +21,9 @@ import kotlinx.coroutines.channels.ReceiveChannel import kotlinx.coroutines.channels.produce import java.io.File -fun CoroutineScope.sequentialRead(file: File, sizeChannel: ReceiveChannel): ReceiveChannel = produce(capacity = 1) { +fun CoroutineScope.sequentialRead(file: File, sizeChannel: ReceiveChannel): ReceiveChannel = produce( + capacity = 1, +) { file.inputStream().buffered().use { stream -> var position = 0 for (size in sizeChannel) { diff --git a/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/ApkE2ETest.kt b/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/ApkE2ETest.kt index 008d74f95..36ea47e42 100644 --- a/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/ApkE2ETest.kt +++ b/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/ApkE2ETest.kt @@ -75,14 +75,17 @@ class ApkE2ETest { client.execute( PushFileRequest(testFile, "/data/local/tmp/$fileName", coroutineContext = coroutineContext), this, - serial = adb.deviceSerial + serial = adb.deviceSerial, ) for (result in channel) { - //Do something with result + // Do something with result } - client.execute(InstallRemotePackageRequest("/data/local/tmp/$fileName", true), serial = adb.deviceSerial).let { + client.execute( + InstallRemotePackageRequest("/data/local/tmp/$fileName", true), + serial = adb.deviceSerial, + ).let { println(it) } }.let { println(it) } @@ -108,12 +111,12 @@ class ApkE2ETest { InstallSplitPackageRequest( ApkSplitInstallationPackage(appFile1, appFile2), listOf(), - true + true, ), - adb.deviceSerial + adb.deviceSerial, ) - //Takes some time until it shows in the pm list. Wait for 10 seconds max + // Takes some time until it shows in the pm list. Wait for 10 seconds max var packages: List = emptyList() for (i in 1..100) { packages = client.execute(PmListRequest(), serial = adb.deviceSerial) @@ -138,12 +141,12 @@ class ApkE2ETest { ApkSplitInstallationPackage(appFile1, appFile2), listOf(), true, - extraArgs = listOf("-t") + extraArgs = listOf("-t"), ), - adb.deviceSerial + adb.deviceSerial, ) - //Takes some time until it shows in the pm list. Wait for 10 seconds max + // Takes some time until it shows in the pm list. Wait for 10 seconds max var packages: List = emptyList() for (i in 1..100) { packages = client.execute(PmListRequest(), serial = adb.deviceSerial) diff --git a/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/E2ETest.kt b/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/E2ETest.kt index bba9cd1f7..2d7d578e5 100644 --- a/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/E2ETest.kt +++ b/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/E2ETest.kt @@ -44,7 +44,6 @@ import java.io.File import java.io.IOException import javax.imageio.ImageIO - class E2ETest { @Rule @JvmField @@ -55,7 +54,7 @@ class E2ETest { runBlocking { val image = adbRule.adb.execute( ScreenCaptureRequest(RawImageScreenCaptureAdapter()), - adbRule.deviceSerial + adbRule.deviceSerial, ).toBufferedImage() if (!ImageIO.write(image, "png", File("/tmp/screen.png"))) { @@ -75,13 +74,13 @@ class E2ETest { runBlocking { val response = adbRule.adb.execute( ShellCommandRequest("echo hello"), - adbRule.deviceSerial + adbRule.deviceSerial, ) assertThat(response).isEqualTo( ShellCommandResult( "hello${adbRule.lineSeparator}".toByteArray(Const.DEFAULT_TRANSPORT_ENCODING), - 0 - ) + 0, + ), ) } } @@ -91,7 +90,7 @@ class E2ETest { runBlocking { val response = adbRule.adb.execute( ShellCommandRequest("false"), - adbRule.deviceSerial + adbRule.deviceSerial, ) assertThat(response.exitCode).isNotEqualTo(0) } @@ -102,7 +101,7 @@ class E2ETest { runBlocking { val response = adbRule.adb.execute( ShellCommandRequest("echo -n 1"), - adbRule.deviceSerial + adbRule.deviceSerial, ) assertThat(response.exitCode).isEqualTo(0) assertThat(response.output).isEqualTo("1") @@ -114,12 +113,12 @@ class E2ETest { runBlocking { val lineSeparator = adbRule.adb.execute( ShellCommandRequest("echo"), - adbRule.deviceSerial + adbRule.deviceSerial, ).output val response = adbRule.adb.execute( ShellCommandRequest("uname"), - adbRule.deviceSerial + adbRule.deviceSerial, ) assertThat(response.output).endsWith(lineSeparator) } @@ -130,7 +129,7 @@ class E2ETest { runBlocking { val props = adbRule.adb.execute( GetPropRequest(), - adbRule.deviceSerial + adbRule.deviceSerial, ) assertThat(props["sys.boot_completed"]).isEqualTo("1") } @@ -141,7 +140,7 @@ class E2ETest { runBlocking { val response = adbRule.adb.execute( GetSinglePropRequest("sys.boot_completed"), - adbRule.deviceSerial + adbRule.deviceSerial, ) assertThat(response).isEqualTo("1${adbRule.lineSeparator}") } @@ -153,7 +152,7 @@ class E2ETest { val channel = adbRule.adb.execute( serial = adbRule.deviceSerial, request = ChanneledLogcatRequest(), - scope = this + scope = this, ) val line = channel.receive() @@ -167,7 +166,7 @@ class E2ETest { runBlocking { val list = adbRule.adb.execute( ListDevicesRequest(), - adbRule.deviceSerial + adbRule.deviceSerial, ) assertThat(list).hasSize(1) @@ -195,12 +194,12 @@ class E2ETest { @Test fun testFetchDeviceFeatures() = runBlocking { val features = adbRule.adb.execute(FetchDeviceFeaturesRequest(adbRule.deviceSerial)) - //No exception means it's working, but every emulator has a different feature set + // No exception means it's working, but every emulator has a different feature set } @Test fun testFetchHostFeatures() = runBlocking { adbRule.adb.execute(FetchHostFeaturesRequest()).let { println(it) } - //No exception means it's working + // No exception means it's working } } diff --git a/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/EmulatorE2ETest.kt b/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/EmulatorE2ETest.kt index 7385b311b..bef01c720 100644 --- a/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/EmulatorE2ETest.kt +++ b/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/EmulatorE2ETest.kt @@ -39,8 +39,8 @@ class EmulatorE2ETest { val output = adbRule.adb.execute( EmulatorCommandRequest( "help", - InetSocketAddress("localhost", port) - ) + InetSocketAddress("localhost", port), + ), ) assertThat(output).startsWith("Android console commands") } diff --git a/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/FileE2ETest.kt b/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/FileE2ETest.kt index 7d40830ba..bb6da1a4b 100644 --- a/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/FileE2ETest.kt +++ b/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/FileE2ETest.kt @@ -90,21 +90,28 @@ class FileE2ETest { val fileName = testFile.name runBlocking { val channel = - adbRule.adb.execute(PushFileRequest(testFile, "/data/local/tmp/$fileName"), this, serial = adbRule.deviceSerial) + adbRule.adb.execute( + PushFileRequest(testFile, "/data/local/tmp/$fileName"), + this, + serial = adbRule.deviceSerial, + ) var percentage = 0 - for(percentageDouble in channel) { + for (percentageDouble in channel) { val newPercentage = (percentageDouble * 100).roundToInt() if (newPercentage != percentage) { print('.') percentage = newPercentage } } - + val stats = adbRule.adb.execute(StatFileRequest("/data/local/tmp/app-debug.apk"), adbRule.deviceSerial) assertThat(stats.size).isEqualTo(testFile.length().toUInt()) - val sizeString = adbRule.adb.execute(ShellCommandRequest("${md5()} /data/local/tmp/app-debug.apk"), adbRule.deviceSerial) + val sizeString = adbRule.adb.execute( + ShellCommandRequest("${md5()} /data/local/tmp/app-debug.apk"), + adbRule.deviceSerial, + ) val split = sizeString.output.split(" ").filter { it != "" } /** @@ -113,7 +120,7 @@ class FileE2ETest { */ assertThat(split[0]).isEqualTo(testFile.md5()) - //TODO figure out why 644 is actually pushed as 666 + // TODO figure out why 644 is actually pushed as 666 assertThat(stats.mode).isEqualTo("100777".toUInt(radix = 8)) } } @@ -134,9 +141,16 @@ class FileE2ETest { withTimeout(10_000) { while (true) { var output = - adbRule.adb.execute(ShellCommandRequest("echo cafebabe > /data/local/tmp/testfile"), serial = adbRule.deviceSerial) + adbRule.adb.execute( + ShellCommandRequest("echo cafebabe > /data/local/tmp/testfile"), + serial = adbRule.deviceSerial, + ) println(output) - output = adbRule.adb.execute(ShellCommandRequest("cat /data/local/tmp/testfile"), serial = adbRule.deviceSerial) + output = + adbRule.adb.execute( + ShellCommandRequest("cat /data/local/tmp/testfile"), + serial = adbRule.deviceSerial, + ) println(output) if (output.output.contains("cafebabe") && output.exitCode == 0) { break @@ -148,11 +162,11 @@ class FileE2ETest { val channel = adbRule.adb.execute( PullFileRequest("/data/local/tmp/testfile", testFile, coroutineContext = coroutineContext), this, - adbRule.deviceSerial + adbRule.deviceSerial, ) var percentage = 0 - for(percentageDouble in channel) { + for (percentageDouble in channel) { val newPercentage = (percentageDouble * 100).roundToInt() if (newPercentage != percentage) { print('.') @@ -162,7 +176,10 @@ class FileE2ETest { println() }.join() - val sizeString = adbRule.adb.execute(ShellCommandRequest("ls -ln /data/local/tmp/testfile"), adbRule.deviceSerial) + val sizeString = adbRule.adb.execute( + ShellCommandRequest("ls -ln /data/local/tmp/testfile"), + adbRule.deviceSerial, + ) val split = sizeString.output.split(" ").filter { it != "" } /** @@ -187,11 +204,11 @@ class FileE2ETest { val channel = adbRule.adb.execute( PullFileRequest("/data/local/tmp/shoudnotexist", testFile, coroutineContext = coroutineContext), this, - adbRule.deviceSerial + adbRule.deviceSerial, ) var percentage = 0 - for(percentageDouble in channel) { + for (percentageDouble in channel) { val newPercentage = (percentageDouble * 100).roundToInt() if (newPercentage != percentage) { print('.') diff --git a/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/LogcatE2ETest.kt b/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/LogcatE2ETest.kt index 3d0260c22..919deadc0 100644 --- a/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/LogcatE2ETest.kt +++ b/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/LogcatE2ETest.kt @@ -44,7 +44,7 @@ import java.util.regex.Pattern private val BUFFER_BEGIN_RE = Pattern.compile("--------- beginning of (.*)") private val LOG_LINE_RE = Pattern.compile( "((?:(\\d\\d\\d\\d)-)?(\\d\\d)-(\\d\\d)\\s+(\\d\\d):(\\d\\d):(\\d\\d)\\.(\\d\\d\\d)\\s+(\\d+)\\s+(\\d+)\\s+(.)\\s+)(.*?):\\s(.*)", - Pattern.MULTILINE + Pattern.MULTILINE, ) private val sinceFormatter = DateTimeFormatter.ofPattern("MM-dd HH:mm:ss.SSS") .withZone(ZoneId.systemDefault()) @@ -66,10 +66,11 @@ class LogcatE2ETest { val deviceTimezone = TimeZone.getTimeZone(deviceTimezoneString) val nowInstant = Instant.now() - val request = SyncLogcatRequest(LogcatSinceFormat.DateString(nowInstant, deviceTimezoneString), modes = listOf()) + val request = + SyncLogcatRequest(LogcatSinceFormat.DateString(nowInstant, deviceTimezoneString), modes = listOf()) async { delay(100) - //Produce artificial message in logcat + // Produce artificial message in logcat adb.adb.execute(ShellCommandRequest("log -t TEST_TAG \"Test message\""), adb.deviceSerial) } @@ -88,11 +89,15 @@ class LogcatE2ETest { @Test fun testChanneledRequest() { runBlocking { - val deviceTimezoneString = adb.adb.execute(GetSinglePropRequest("persist.sys.timezone"), adb.deviceSerial).trim() + val deviceTimezoneString = adb.adb.execute( + GetSinglePropRequest("persist.sys.timezone"), + adb.deviceSerial, + ).trim() val deviceTimezone = TimeZone.getTimeZone(deviceTimezoneString) val nowInstant = Instant.now() - val request = ChanneledLogcatRequest(LogcatSinceFormat.DateString(nowInstant, deviceTimezoneString), modes = listOf()) + val request = + ChanneledLogcatRequest(LogcatSinceFormat.DateString(nowInstant, deviceTimezoneString), modes = listOf()) val content = mutableSetOf() val channel = adb.adb.execute(request, this, adb.deviceSerial) @@ -100,7 +105,7 @@ class LogcatE2ETest { val background: Deferred = async { while (isActive) { delay(100) - //Produce artificial message in logcat + // Produce artificial message in logcat adb.adb.execute(ShellCommandRequest("log -t TEST_TAG \"Test message\""), adb.deviceSerial) } } @@ -148,7 +153,9 @@ class LogcatE2ETest { val instant get() = ZonedDateTime.ofInstant(date.toInstant(), timeZone.toZoneId()) - override fun toString() = "[LogLine] ${sinceFormatter.format(date.toInstant())} $pid $tid $level $tag: $text" + override fun toString() = "[LogLine] ${sinceFormatter.format( + date.toInstant(), + )} $pid $tid $level $tag: $text" override fun equals(other: Any?): Boolean { if (this === other) return true diff --git a/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/ManualTest.kt b/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/ManualTest.kt index db8deb88f..771d4debe 100644 --- a/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/ManualTest.kt +++ b/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/ManualTest.kt @@ -37,7 +37,7 @@ class ManualTest { runBlocking { val execute = adbRule.adb.execute( request = AsyncDeviceMonitorRequest(), - scope = this + scope = this, ) for (i in 1..100) { println(execute.receive()) diff --git a/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/PortForwardE2ETest.kt b/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/PortForwardE2ETest.kt index dcf342ccc..1975d9672 100644 --- a/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/PortForwardE2ETest.kt +++ b/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/PortForwardE2ETest.kt @@ -67,12 +67,12 @@ class PortForwardE2ETest { runBlocking { adbRule.adb.execute( PortForwardRequest(LocalTcpPortSpec(12042), RemoteTcpPortSpec(12042), serial = adbRule.deviceSerial), - adbRule.deviceSerial + adbRule.deviceSerial, ) val portForwards = adbRule.adb.execute( ListPortForwardsRequest(adbRule.deviceSerial), - adbRule.deviceSerial + adbRule.deviceSerial, ) assertThat(portForwards).hasSize(1) @@ -84,10 +84,14 @@ class PortForwardE2ETest { assertThat(rule.remoteSpec).isInstanceOf(RemoteTcpPortSpec::class) assertThat((rule.remoteSpec as RemoteTcpPortSpec).port).isEqualTo(12042) - adbRule.adb.execute(RemovePortForwardRequest(LocalTcpPortSpec(12042), serial = adbRule.deviceSerial), adbRule.deviceSerial) + adbRule.adb.execute( + RemovePortForwardRequest(LocalTcpPortSpec(12042), serial = adbRule.deviceSerial), + adbRule.deviceSerial, + ) val afterAllForwards = adbRule.adb.execute( - ListPortForwardsRequest(adbRule.deviceSerial), adbRule.deviceSerial + ListPortForwardsRequest(adbRule.deviceSerial), + adbRule.deviceSerial, ) assertThat(afterAllForwards).isEmpty() @@ -99,15 +103,16 @@ class PortForwardE2ETest { runBlocking { val portString = adbRule.adb.execute( PortForwardRequest(LocalTcpPortSpec(), RemoteTcpPortSpec(12042), serial = adbRule.deviceSerial), - adbRule.deviceSerial + adbRule.deviceSerial, ) val currentPortForwards = adbRule.adb.execute( - ListPortForwardsRequest(adbRule.deviceSerial), adbRule.deviceSerial + ListPortForwardsRequest(adbRule.deviceSerial), + adbRule.deviceSerial, ) assertThat(portString).isNotNull() - val actual = portString!!.toInt() + val actual = portString!! val expected = (currentPortForwards.firstOrNull()?.localSpec as LocalTcpPortSpec).port assertThat(actual).isEqualTo(expected) @@ -119,17 +124,17 @@ class PortForwardE2ETest { runBlocking { adbRule.adb.execute( PortForwardRequest(LocalTcpPortSpec(12042), RemoteTcpPortSpec(12042), serial = adbRule.deviceSerial), - adbRule.deviceSerial + adbRule.deviceSerial, ) adbRule.adb.execute( RemovePortForwardRequest(LocalTcpPortSpec(12042), serial = adbRule.deviceSerial), - adbRule.deviceSerial + adbRule.deviceSerial, ) val portForwards = adbRule.adb.execute( ListPortForwardsRequest(adbRule.deviceSerial), - adbRule.deviceSerial + adbRule.deviceSerial, ) assertThat(portForwards).isEmpty() @@ -144,18 +149,18 @@ class PortForwardE2ETest { adbRule.adb.execute( ReversePortForwardRequest(RemoteTcpPortSpec(12043), LocalTcpPortSpec(12043)), - adbRule.deviceSerial + adbRule.deviceSerial, ) val list = adbRule.adb.execute(ListReversePortForwardsRequest(), adbRule.deviceSerial) assertThat(list).hasSize(1) - //Host serial is of form "host-$tid", we ignore it here for equality check + // Host serial is of form "host-$tid", we ignore it here for equality check assertThat(list.first().localSpec).isEqualTo(RemoteTcpPortSpec(12043)) assertThat(list.first().remoteSpec).isEqualTo(LocalTcpPortSpec(12043)) adbRule.adb.execute( RemoveReversePortForwardRequest(RemoteTcpPortSpec(12043)), - adbRule.deviceSerial + adbRule.deviceSerial, ) assertThat(adbRule.adb.execute(ListReversePortForwardsRequest(), adbRule.deviceSerial)).isEmpty() @@ -166,21 +171,22 @@ class PortForwardE2ETest { runBlocking { val portString = adbRule.adb.execute( ReversePortForwardRequest(RemoteTcpPortSpec(12042), LocalTcpPortSpec(12042)), - adbRule.deviceSerial + adbRule.deviceSerial, ) val currentPortForwards = adbRule.adb.execute( - ListReversePortForwardsRequest(), adbRule.deviceSerial + ListReversePortForwardsRequest(), + adbRule.deviceSerial, ) if (portString != null) { - //Some devices return the allocated port - val actual = portString.toInt() + // Some devices return the allocated port + val actual = portString val expected = (currentPortForwards.firstOrNull()?.localSpec as RemoteTcpPortSpec).port assertThat(actual).isEqualTo(expected) } else { - //Others do not + // Others do not val actual = currentPortForwards.any { it.remoteSpec == LocalTcpPortSpec(12042) && it.localSpec == RemoteTcpPortSpec(12042) } diff --git a/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/PullE2ETest.kt b/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/PullE2ETest.kt index 36c91aaf3..cbeff730a 100644 --- a/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/PullE2ETest.kt +++ b/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/PullE2ETest.kt @@ -55,36 +55,50 @@ class PullE2ETest { } } - @Test fun testPull() { runBlocking { adbRule.adb.execute(ShellCommandRequest("mkdir -p /data/local/tmp/testdir/X"), adbRule.deviceSerial) adbRule.adb.execute(ShellCommandRequest("mkdir -p /data/local/tmp/testdir/Y/Z"), adbRule.deviceSerial) - adbRule.adb.execute(ShellCommandRequest("echo Xcafebabe > /data/local/tmp/testdir/X/testfilex"), adbRule.deviceSerial) - adbRule.adb.execute(ShellCommandRequest("echo Ycafebabe > /data/local/tmp/testdir/Y/testfiley"), adbRule.deviceSerial) - adbRule.adb.execute(ShellCommandRequest("echo Zcafebabe > /data/local/tmp/testdir/Y/Z/testfilez"), adbRule.deviceSerial) - //Testing non-latin filenames - adbRule.adb.execute(ShellCommandRequest("echo кафебаба > /data/local/tmp/testdir/тестовыйфайл"), adbRule.deviceSerial) + adbRule.adb.execute( + ShellCommandRequest("echo Xcafebabe > /data/local/tmp/testdir/X/testfilex"), + adbRule.deviceSerial, + ) + adbRule.adb.execute( + ShellCommandRequest("echo Ycafebabe > /data/local/tmp/testdir/Y/testfiley"), + adbRule.deviceSerial, + ) + adbRule.adb.execute( + ShellCommandRequest("echo Zcafebabe > /data/local/tmp/testdir/Y/Z/testfilez"), + adbRule.deviceSerial, + ) + // Testing non-latin filenames + adbRule.adb.execute( + ShellCommandRequest("echo кафебаба > /data/local/tmp/testdir/тестовыйфайл"), + adbRule.deviceSerial, + ) val dst = temp.newFolder() val execute = - adbRule.adb.execute(PullRequest("/data/local/tmp/testdir", dst, adbRule.supportedFeatures), adbRule.deviceSerial) + adbRule.adb.execute( + PullRequest("/data/local/tmp/testdir", dst, adbRule.supportedFeatures), + adbRule.deviceSerial, + ) - //Should create a subdir since dst already exists + // Should create a subdir since dst already exists val testdir = File(dst, "testdir") - val X = File(testdir, "X") - val Y = File(testdir, "Y") - val Z = File(Y, "Z") - val x = File(X, "testfilex") - val y = File(Y, "testfiley") - val z = File(Z, "testfilez") + val xDir = File(testdir, "X") + val yDir = File(testdir, "Y") + val zDir = File(yDir, "Z") + val x = File(xDir, "testfilex") + val y = File(yDir, "testfiley") + val z = File(zDir, "testfilez") val q = File(testdir, "тестовыйфайл") - assertThat(X).isDirectory() - assertThat(Y).isDirectory() - assertThat(Z).isDirectory() + assertThat(xDir).isDirectory() + assertThat(yDir).isDirectory() + assertThat(zDir).isDirectory() assertThat(x).isFile() assertThat(y).isFile() @@ -102,28 +116,43 @@ class PullE2ETest { runBlocking { adbRule.adb.execute(ShellCommandRequest("mkdir -p /data/local/tmp/testdir/X"), adbRule.deviceSerial) adbRule.adb.execute(ShellCommandRequest("mkdir -p /data/local/tmp/testdir/Y/Z"), adbRule.deviceSerial) - adbRule.adb.execute(ShellCommandRequest("echo Xcafebabe > /data/local/tmp/testdir/X/testfilex"), adbRule.deviceSerial) - adbRule.adb.execute(ShellCommandRequest("echo Ycafebabe > /data/local/tmp/testdir/Y/testfiley"), adbRule.deviceSerial) - adbRule.adb.execute(ShellCommandRequest("echo Zcafebabe > /data/local/tmp/testdir/Y/Z/testfilez"), adbRule.deviceSerial) - //Testing non-latin filenames - adbRule.adb.execute(ShellCommandRequest("echo кафебаба > /data/local/tmp/testdir/тестовыйфайл"), adbRule.deviceSerial) + adbRule.adb.execute( + ShellCommandRequest("echo Xcafebabe > /data/local/tmp/testdir/X/testfilex"), + adbRule.deviceSerial, + ) + adbRule.adb.execute( + ShellCommandRequest("echo Ycafebabe > /data/local/tmp/testdir/Y/testfiley"), + adbRule.deviceSerial, + ) + adbRule.adb.execute( + ShellCommandRequest("echo Zcafebabe > /data/local/tmp/testdir/Y/Z/testfilez"), + adbRule.deviceSerial, + ) + // Testing non-latin filenames + adbRule.adb.execute( + ShellCommandRequest("echo кафебаба > /data/local/tmp/testdir/тестовыйфайл"), + adbRule.deviceSerial, + ) val dst = temp.newFolder() dst.delete() val execute = - adbRule.adb.execute(PullRequest("/data/local/tmp/testdir", dst, adbRule.supportedFeatures), adbRule.deviceSerial) - - val X = File(dst, "X") - val Y = File(dst, "Y") - val Z = File(Y, "Z") - val x = File(X, "testfilex") - val y = File(Y, "testfiley") - val z = File(Z, "testfilez") + adbRule.adb.execute( + PullRequest("/data/local/tmp/testdir", dst, adbRule.supportedFeatures), + adbRule.deviceSerial, + ) + + val xDir = File(dst, "X") + val yDir = File(dst, "Y") + val zDir = File(yDir, "Z") + val x = File(xDir, "testfilex") + val y = File(yDir, "testfiley") + val z = File(zDir, "testfilez") val q = File(dst, "тестовыйфайл") - assertThat(X).isDirectory() - assertThat(Y).isDirectory() - assertThat(Z).isDirectory() + assertThat(xDir).isDirectory() + assertThat(yDir).isDirectory() + assertThat(zDir).isDirectory() assertThat(x).isFile() assertThat(y).isFile() @@ -140,13 +169,16 @@ class PullE2ETest { fun testPullFileIntoADestinationFolder() { runBlocking { adbRule.adb.execute(ShellCommandRequest("mkdir -p /data/local/tmp/testdir/X"), adbRule.deviceSerial) - adbRule.adb.execute(ShellCommandRequest("echo Xcafebabe > /data/local/tmp/testdir/X/testfilex"), adbRule.deviceSerial) + adbRule.adb.execute( + ShellCommandRequest("echo Xcafebabe > /data/local/tmp/testdir/X/testfilex"), + adbRule.deviceSerial, + ) val dst = temp.newFolder() val execute = adbRule.adb.execute( PullRequest("/data/local/tmp/testdir/X/testfilex", dst, adbRule.supportedFeatures), - adbRule.deviceSerial + adbRule.deviceSerial, ) val x = File(dst, "testfilex") @@ -162,18 +194,21 @@ class PullE2ETest { runBlocking { adbRule.adb.execute(ShellCommandRequest("mkdir -p /data/local/tmp/testdir/X"), adbRule.deviceSerial) adbRule.adb.execute(ShellCommandRequest("touch /data/local/tmp/testdir/X/testfilex"), adbRule.deviceSerial) - adbRule.adb.execute(ShellCommandRequest("echo Xcafebabe > /data/local/tmp/testdir/X/testfiley"), adbRule.deviceSerial) + adbRule.adb.execute( + ShellCommandRequest("echo Xcafebabe > /data/local/tmp/testdir/X/testfiley"), + adbRule.deviceSerial, + ) val dst = temp.newFolder() val execute = adbRule.adb.execute( PullRequest("/data/local/tmp/testdir/X", dst, adbRule.supportedFeatures), - adbRule.deviceSerial + adbRule.deviceSerial, ) - val X = File(dst, "X") - val x = File(X, "testfilex") - val y = File(X, "testfiley") + val xDir = File(dst, "X") + val x = File(xDir, "testfilex") + val y = File(xDir, "testfiley") assertThat(x).isFile() assertThat(y).isFile() @@ -183,4 +218,3 @@ class PullE2ETest { } } } - diff --git a/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/PushE2ETest.kt b/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/PushE2ETest.kt index 566efa294..28723cab3 100644 --- a/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/PushE2ETest.kt +++ b/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/PushE2ETest.kt @@ -60,20 +60,35 @@ class PushE2ETest { @Test fun testPush() { val source = temp.newFolder() - val X = File(source, "X").apply { mkdir() } - val Y = File(source, "Y").apply { mkdir() } - val Z = File(Y, "Z").apply { mkdir() } - val x = File(X, "testfilex").apply { createNewFile(); writeText("Xcafebabe\n") } - val y = File(Y, "testfiley").apply { createNewFile(); writeText("Ycafebabe\n") } - val z = File(Z, "testfilez").apply { createNewFile(); writeText("Zcafebabe\n") } - //Testing non-latin filenames - val q = File(source, "тестовыйфайл").apply { createNewFile(); writeText("кафебаба\n") } + val xDir = File(source, "X").apply { mkdir() } + val yDir = File(source, "Y").apply { mkdir() } + val zDir = File(yDir, "Z").apply { mkdir() } + val x = File(xDir, "testfilex").apply { + createNewFile() + writeText("Xcafebabe\n") + } + val y = File(yDir, "testfiley").apply { + createNewFile() + writeText("Ycafebabe\n") + } + val z = File(zDir, "testfilez").apply { + createNewFile() + writeText("Zcafebabe\n") + } + // Testing non-latin filenames + val q = File(source, "тестовыйфайл").apply { + createNewFile() + writeText("кафебаба\n") + } runBlocking { val execute = - adbRule.adb.execute(PushRequest(source, "/data/local/tmp/testdir", adbRule.supportedFeatures), adbRule.deviceSerial) + adbRule.adb.execute( + PushRequest(source, "/data/local/tmp/testdir", adbRule.supportedFeatures), + adbRule.deviceSerial, + ) - //Should create a subdir since dst already exists + // Should create a subdir since dst already exists assertThat(statFile("/data/local/tmp/testdir").isDirectory()).isTrue() assertThat(statFile("/data/local/tmp/testdir/X").isDirectory()).isTrue() @@ -94,13 +109,19 @@ class PushE2ETest { @Test fun testPushCreatingSubdir() { val source = temp.newFolder("testdir with special 'chars()") - val x = File(source, "testfilex").apply { createNewFile(); writeText("Xcafebabe\n") } + val x = File(source, "testfilex").apply { + createNewFile() + writeText("Xcafebabe\n") + } runBlocking { val execute = - adbRule.adb.execute(PushRequest(source, "/data/local/tmp", adbRule.supportedFeatures), adbRule.deviceSerial) + adbRule.adb.execute( + PushRequest(source, "/data/local/tmp", adbRule.supportedFeatures), + adbRule.deviceSerial, + ) - //Should create a subdir since dst already exists + // Should create a subdir since dst already exists assertThat(statFile("/data/local/tmp/testdir with special 'chars()").isDirectory()).isTrue() assertThat(statFile("/data/local/tmp/testdir with special 'chars()/testfilex").isRegularFile()).isTrue() } @@ -116,28 +137,43 @@ class PushE2ETest { runBlocking { adbRule.adb.execute(ShellCommandRequest("mkdir -p /data/local/tmp/testdir/X"), adbRule.deviceSerial) adbRule.adb.execute(ShellCommandRequest("mkdir -p /data/local/tmp/testdir/Y/Z"), adbRule.deviceSerial) - adbRule.adb.execute(ShellCommandRequest("echo Xcafebabe > /data/local/tmp/testdir/X/testfilex"), adbRule.deviceSerial) - adbRule.adb.execute(ShellCommandRequest("echo Ycafebabe > /data/local/tmp/testdir/Y/testfiley"), adbRule.deviceSerial) - adbRule.adb.execute(ShellCommandRequest("echo Zcafebabe > /data/local/tmp/testdir/Y/Z/testfilez"), adbRule.deviceSerial) - //Testing non-latin filenames - adbRule.adb.execute(ShellCommandRequest("echo кафебаба > /data/local/tmp/testdir/тестовыйфайл"), adbRule.deviceSerial) + adbRule.adb.execute( + ShellCommandRequest("echo Xcafebabe > /data/local/tmp/testdir/X/testfilex"), + adbRule.deviceSerial, + ) + adbRule.adb.execute( + ShellCommandRequest("echo Ycafebabe > /data/local/tmp/testdir/Y/testfiley"), + adbRule.deviceSerial, + ) + adbRule.adb.execute( + ShellCommandRequest("echo Zcafebabe > /data/local/tmp/testdir/Y/Z/testfilez"), + adbRule.deviceSerial, + ) + // Testing non-latin filenames + adbRule.adb.execute( + ShellCommandRequest("echo кафебаба > /data/local/tmp/testdir/тестовыйфайл"), + adbRule.deviceSerial, + ) val dst = temp.newFolder() dst.delete() val execute = - adbRule.adb.execute(PullRequest("/data/local/tmp/testdir", dst, adbRule.supportedFeatures), adbRule.deviceSerial) - - val X = File(dst, "X") - val Y = File(dst, "Y") - val Z = File(Y, "Z") - val x = File(X, "testfilex") - val y = File(Y, "testfiley") - val z = File(Z, "testfilez") + adbRule.adb.execute( + PullRequest("/data/local/tmp/testdir", dst, adbRule.supportedFeatures), + adbRule.deviceSerial, + ) + + val xDir = File(dst, "X") + val yDir = File(dst, "Y") + val zDir = File(yDir, "Z") + val x = File(xDir, "testfilex") + val y = File(yDir, "testfiley") + val z = File(zDir, "testfilez") val q = File(dst, "тестовыйфайл") - assertThat(X).isDirectory() - assertThat(Y).isDirectory() - assertThat(Z).isDirectory() + assertThat(xDir).isDirectory() + assertThat(yDir).isDirectory() + assertThat(zDir).isDirectory() assertThat(x).isFile() assertThat(y).isFile() diff --git a/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/ShellV2E2ETest.kt b/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/ShellV2E2ETest.kt index aaec4ffcd..86c198002 100644 --- a/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/ShellV2E2ETest.kt +++ b/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/ShellV2E2ETest.kt @@ -50,18 +50,18 @@ class ShellV2E2ETest { fun testChanneled() = runBlocking { val stdio = Channel() val receiveChannel = adbRule.adb.execute(ChanneledShellCommandRequest("cat", stdio), this, adbRule.deviceSerial) - //Sending commands requires additional pool, otherwise we might deadlock + // Sending commands requires additional pool, otherwise we might deadlock val stdioJob = launch(Dispatchers.IO) { stdio.send( ShellCommandInputChunk( - stdin = "cafebabe".toByteArray(Const.DEFAULT_TRANSPORT_ENCODING) - ) + stdin = "cafebabe".toByteArray(Const.DEFAULT_TRANSPORT_ENCODING), + ), ) stdio.send( ShellCommandInputChunk( - close = true - ) + close = true, + ), ) } @@ -78,6 +78,5 @@ class ShellV2E2ETest { assertThat(stdoutBuilder.toString()).isEqualTo("cafebabe") assertThat(stderrBuilder.toString()).isEmpty() assertThat(exitCode).isEqualTo(0) - } } diff --git a/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/TestRunnerE2ETest.kt b/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/TestRunnerE2ETest.kt index 749260985..1bc09a174 100644 --- a/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/TestRunnerE2ETest.kt +++ b/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/TestRunnerE2ETest.kt @@ -77,10 +77,10 @@ class TestRunnerE2ETest { TestRunnerRequest( "com.example.test", InstrumentOptions( - clazz = listOf("com.example.AbstractFailingTest") + clazz = listOf("com.example.AbstractFailingTest"), ), rule.supportedFeatures, - this + this, ), serial = rule.deviceSerial, ) @@ -113,7 +113,7 @@ class TestRunnerE2ETest { TestRunnerRequest( "com.example.test", InstrumentOptions( - clazz = listOf("com.example.AbstractFailingTest") + clazz = listOf("com.example.AbstractFailingTest"), ), rule.supportedFeatures, this, @@ -128,19 +128,30 @@ class TestRunnerE2ETest { } assertThat(events).contains(TestRunStartedEvent(1)) - assertThat(events).contains(TestStarted(TestIdentifier("com.example.AbstractFailingTest", "testAlwaysFailing"))) - - assertThat(events.any { - it is TestFailed && it.id.className == "com.example.AbstractFailingTest" && it.id.testName == "testAlwaysFailing" && it.stackTrace.isNotEmpty() - }).isTrue() - - assertThat(events.any { - it is TestEnded && it.id.className == "com.example.AbstractFailingTest" && it.id.testName == "testAlwaysFailing" - }).isTrue() - - assertThat(events.any { - it is TestRunEnded && it.metrics.isEmpty() && it.elapsedTimeMillis > 0 - }) + assertThat( + events, + ).contains(TestStarted(TestIdentifier("com.example.AbstractFailingTest", "testAlwaysFailing"))) + + assertThat( + events.any { + it is TestFailed && it.id.className == "com.example.AbstractFailingTest" && + it.id.testName == "testAlwaysFailing" && + it.stackTrace.isNotEmpty() + }, + ).isTrue() + + assertThat( + events.any { + it is TestEnded && it.id.className == "com.example.AbstractFailingTest" && + it.id.testName == "testAlwaysFailing" + }, + ).isTrue() + + assertThat( + events.any { + it is TestRunEnded && it.metrics.isEmpty() && it.elapsedTimeMillis > 0 + }, + ) } } @@ -149,7 +160,7 @@ class TestRunnerE2ETest { rule.adb.execute( PushFileRequest(apk, "/data/local/tmp/$apkFileName", coroutineContext = coroutineContext), this, - serial = rule.deviceSerial + serial = rule.deviceSerial, ) for (i in channel) { @@ -158,7 +169,7 @@ class TestRunnerE2ETest { val result = rule.adb.execute( InstallRemotePackageRequest("/data/local/tmp/$apkFileName", true), - serial = rule.deviceSerial + serial = rule.deviceSerial, ) println(result) } diff --git a/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/feature/AbbE2ETest.kt b/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/feature/AbbE2ETest.kt index b4ed6a503..6e905f1b4 100644 --- a/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/feature/AbbE2ETest.kt +++ b/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/feature/AbbE2ETest.kt @@ -34,7 +34,10 @@ class AbbE2ETest { @Test fun testStreamingInstallRequest() { runBlocking { - var result = adbRule.adb.execute(AbbRequest(listOf("-l"), adbRule.supportedFeatures), serial = adbRule.deviceSerial) + var result = adbRule.adb.execute( + AbbRequest(listOf("-l"), adbRule.supportedFeatures), + serial = adbRule.deviceSerial, + ) assertThat(result.output).startsWith("Currently running services:") } } diff --git a/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/feature/AbbExecE2ETest.kt b/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/feature/AbbExecE2ETest.kt index 88634765d..8026b8afb 100644 --- a/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/feature/AbbExecE2ETest.kt +++ b/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/feature/AbbExecE2ETest.kt @@ -69,9 +69,9 @@ class AbbExecE2ETest { StreamingPackageInstallRequest( pkg = testFile, supportedFeatures = listOf(Feature.ABB_EXEC), - reinstall = false + reinstall = false, ), - adb.deviceSerial + adb.deviceSerial, ) }.let { println(it) } @@ -90,15 +90,15 @@ class AbbExecE2ETest { AtomicInstallPackageRequest( listOf( SingleFileInstallationPackage(appFile), - SingleFileInstallationPackage(testFile) + SingleFileInstallationPackage(testFile), ), listOf(Feature.ABB_EXEC), - true + true, ), - adb.deviceSerial + adb.deviceSerial, ) - //Takes some time until it shows in the pm list. Wait for 10 seconds max + // Takes some time until it shows in the pm list. Wait for 10 seconds max var packages: List = emptyList() for (i in 1..100) { packages = client.execute(PmListRequest(), serial = adb.deviceSerial) @@ -124,12 +124,12 @@ class AbbExecE2ETest { InstallSplitPackageRequest( ApkSplitInstallationPackage(appFile1, appFile2), listOf(Feature.ABB_EXEC), - true + true, ), - adb.deviceSerial + adb.deviceSerial, ) - //Takes some time until it shows in the pm list. Wait for 10 seconds max + // Takes some time until it shows in the pm list. Wait for 10 seconds max var packages: List = emptyList() for (i in 1..100) { packages = client.execute(PmListRequest(), serial = adb.deviceSerial) diff --git a/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/feature/CmdE2ETest.kt b/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/feature/CmdE2ETest.kt index 3a4f87478..43ae73c3c 100644 --- a/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/feature/CmdE2ETest.kt +++ b/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/feature/CmdE2ETest.kt @@ -75,9 +75,9 @@ class CmdE2ETest { StreamingPackageInstallRequest( pkg = testFile, supportedFeatures = listOf(Feature.CMD), - reinstall = false + reinstall = false, ), - adb.deviceSerial + adb.deviceSerial, ) }.let { println(it) } @@ -99,7 +99,7 @@ class CmdE2ETest { reinstall = false, extraArgs = listOf("-g", "-r"), ), - adb.deviceSerial + adb.deviceSerial, ) }.let { println(it) } @@ -120,12 +120,12 @@ class CmdE2ETest { ExecInRequest( "cmd package install -S ${testFile.length()}", channel, - blockSizeChannel + blockSizeChannel, ), - adb.deviceSerial + adb.deviceSerial, ) - //Takes some time until it shows in the pm list. Wait for 10 seconds max + // Takes some time until it shows in the pm list. Wait for 10 seconds max var packages: List = emptyList() for (i in 1..100) { packages = client.execute(PmListRequest(), serial = adb.deviceSerial) @@ -150,24 +150,24 @@ class CmdE2ETest { AtomicInstallPackageRequest( listOf( SingleFileInstallationPackage(appFile), - SingleFileInstallationPackage(testFile) + SingleFileInstallationPackage(testFile), ), listOf(Feature.CMD), - true + true, ), - adb.deviceSerial + adb.deviceSerial, ) } catch (e: RequestRejectedException) { if (e.message?.contains("Unknown option --multi-package") == true) { Assume.assumeTrue( "Device doesn't support `--multi-package` option", - false + false, ) } throw e } - //Takes some time until it shows in the pm list. Wait for 10 seconds max + // Takes some time until it shows in the pm list. Wait for 10 seconds max var packages: List = emptyList() for (i in 1..100) { packages = client.execute(PmListRequest(), serial = adb.deviceSerial) @@ -194,25 +194,25 @@ class CmdE2ETest { AtomicInstallPackageRequest( listOf( SingleFileInstallationPackage(appFile), - SingleFileInstallationPackage(testFile) + SingleFileInstallationPackage(testFile), ), listOf(Feature.CMD), true, - extraArgs = listOf("-r", "-g") + extraArgs = listOf("-r", "-g"), ), - adb.deviceSerial + adb.deviceSerial, ) } catch (e: RequestRejectedException) { if (e.message?.contains("Unknown option --multi-package") == true) { Assume.assumeTrue( "Device doesn't support `--multi-package` option", - false + false, ) } throw e } - //Takes some time until it shows in the pm list. Wait for 10 seconds max + // Takes some time until it shows in the pm list. Wait for 10 seconds max var packages: List = emptyList() for (i in 1..100) { packages = client.execute(PmListRequest(), serial = adb.deviceSerial) @@ -238,12 +238,12 @@ class CmdE2ETest { InstallSplitPackageRequest( ApkSplitInstallationPackage(appFile1, appFile2), listOf(Feature.CMD), - true + true, ), - adb.deviceSerial + adb.deviceSerial, ) - //Takes some time until it shows in the pm list. Wait for 10 seconds max + // Takes some time until it shows in the pm list. Wait for 10 seconds max var packages: List = emptyList() for (i in 1..100) { packages = client.execute(PmListRequest(), serial = adb.deviceSerial) diff --git a/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/feature/LsV2E2ETest.kt b/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/feature/LsV2E2ETest.kt index 746e3e54f..ec0a81dcf 100644 --- a/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/feature/LsV2E2ETest.kt +++ b/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/feature/LsV2E2ETest.kt @@ -36,14 +36,18 @@ class LsV2E2ETest { @Before fun setup() { runBlocking { - externalStorageMount = adbRule.adb.execute(ShellCommandRequest("echo \$EXTERNAL_STORAGE"), adbRule.deviceSerial).output.trim() + externalStorageMount = + adbRule.adb.execute(ShellCommandRequest("echo \$EXTERNAL_STORAGE"), adbRule.deviceSerial).output.trim() } } @Test fun testListFile() { runBlocking { - val list = adbRule.adb.execute(ListFileRequest(externalStorageMount, adbRule.supportedFeatures), adbRule.deviceSerial) + val list = adbRule.adb.execute( + ListFileRequest(externalStorageMount, adbRule.supportedFeatures), + adbRule.deviceSerial, + ) for (i in list) { println(i) } diff --git a/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/feature/SendRecvV2E2ETest.kt b/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/feature/SendRecvV2E2ETest.kt index f11d104ee..c7a075a61 100644 --- a/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/feature/SendRecvV2E2ETest.kt +++ b/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/feature/SendRecvV2E2ETest.kt @@ -54,9 +54,16 @@ class SendRecvV2E2ETest { withTimeout(10_000) { while (true) { var output = - adbRule.adb.execute(ShellCommandRequest("echo cafebabe > /data/local/tmp/testfile"), serial = adbRule.deviceSerial) + adbRule.adb.execute( + ShellCommandRequest("echo cafebabe > /data/local/tmp/testfile"), + serial = adbRule.deviceSerial, + ) println(output) - output = adbRule.adb.execute(ShellCommandRequest("cat /data/local/tmp/testfile"), serial = adbRule.deviceSerial) + output = + adbRule.adb.execute( + ShellCommandRequest("cat /data/local/tmp/testfile"), + serial = adbRule.deviceSerial, + ) println(output) if (output.output.contains("cafebabe") && output.exitCode == 0) { break @@ -80,13 +87,18 @@ class SendRecvV2E2ETest { val file = temp.newFile() val channel = adbRule.adb.execute( - PullFileRequest("/data/local/tmp/testfile", file, adbRule.supportedFeatures, coroutineContext = coroutineContext), + PullFileRequest( + "/data/local/tmp/testfile", + file, + adbRule.supportedFeatures, + coroutineContext = coroutineContext, + ), this, - adbRule.deviceSerial + adbRule.deviceSerial, ) var percentage = 0 - for(percentageDouble in channel) { + for (percentageDouble in channel) { val newPercentage = (percentageDouble * 100).roundToInt() if (newPercentage != percentage) { print('.') @@ -111,14 +123,14 @@ class SendRecvV2E2ETest { adbRule.supportedFeatures, "0644", false, - coroutineContext = coroutineContext + coroutineContext = coroutineContext, ), this, - serial = adbRule.deviceSerial + serial = adbRule.deviceSerial, ) var percentage = 0 - for(percentageDouble in channel) { + for (percentageDouble in channel) { val newPercentage = (percentageDouble * 100).roundToInt() if (newPercentage != percentage) { print('.') @@ -128,7 +140,10 @@ class SendRecvV2E2ETest { val stats = adbRule.adb.execute(StatFileRequest("/data/local/tmp/app-debug.apk"), adbRule.deviceSerial) assertThat(stats.size).isEqualTo(testFile.length().toUInt()) - val sizeString = adbRule.adb.execute(ShellCommandRequest("${md5()} /data/local/tmp/app-debug.apk"), adbRule.deviceSerial) + val sizeString = adbRule.adb.execute( + ShellCommandRequest("${md5()} /data/local/tmp/app-debug.apk"), + adbRule.deviceSerial, + ) val split = sizeString.output.split(" ").filter { it != "" } /** @@ -137,7 +152,7 @@ class SendRecvV2E2ETest { */ assertThat(split[0]).isEqualTo(testFile.md5()) - //TODO figure out why 644 is actually pushed as 666 + // TODO figure out why 644 is actually pushed as 666 assertThat(stats.mode).isEqualTo("100666".toUInt(radix = 8)) } } diff --git a/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/feature/StatV2E2ETest.kt b/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/feature/StatV2E2ETest.kt index a49a0e250..ccfa90668 100644 --- a/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/feature/StatV2E2ETest.kt +++ b/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/feature/StatV2E2ETest.kt @@ -46,11 +46,11 @@ class StatV2E2ETest { adbRule.adb.execute( PushFileRequest(testFile, "/data/local/tmp/$fileName", coroutineContext = coroutineContext), this, - serial = adbRule.deviceSerial + serial = adbRule.deviceSerial, ) var percentage = 0 - for(percentageDouble in channel) { + for (percentageDouble in channel) { val newPercentage = (percentageDouble * 100).roundToInt() if (newPercentage != percentage) { print('.') @@ -71,7 +71,10 @@ class StatV2E2ETest { fun testListFile() { runBlocking { val stats = - adbRule.adb.execute(StatFileRequest("/data/local/tmp/app-debug.apk", adbRule.supportedFeatures), adbRule.deviceSerial) + adbRule.adb.execute( + StatFileRequest("/data/local/tmp/app-debug.apk", adbRule.supportedFeatures), + adbRule.deviceSerial, + ) assertThat(stats.size).isEqualTo(testFile.length().toULong()) } } diff --git a/adam/src/integrationTest/kotlin/com/malinskiy/adam/rule/AdbDeviceRule.kt b/adam/src/integrationTest/kotlin/com/malinskiy/adam/rule/AdbDeviceRule.kt index 78641eb38..8b7255c8e 100644 --- a/adam/src/integrationTest/kotlin/com/malinskiy/adam/rule/AdbDeviceRule.kt +++ b/adam/src/integrationTest/kotlin/com/malinskiy/adam/rule/AdbDeviceRule.kt @@ -55,11 +55,11 @@ class AdbDeviceRule(val deviceType: DeviceType = DeviceType.ANY, vararg val requ override fun evaluate() { runBlocking { withTimeoutOrNull(initTimeout.toMillis()) { - //First we start the adb if it is not running + // First we start the adb if it is not running startAdb() - //Wait for compatible device - //boot + supported features + // Wait for compatible device + // boot + supported features val device = waitForDevice() deviceSerial = device.serial } ?: Assume.assumeTrue("Timeout waiting for device", false) @@ -80,7 +80,7 @@ class AdbDeviceRule(val deviceType: DeviceType = DeviceType.ANY, vararg val requ DeviceType.EMULATOR -> { Assume.assumeTrue( "No device of type $deviceType found", - device.serial.startsWith("emulator-") + device.serial.startsWith("emulator-"), ) } @@ -92,13 +92,13 @@ class AdbDeviceRule(val deviceType: DeviceType = DeviceType.ANY, vararg val requ Assume.assumeTrue( "No compatible device found for features $requiredFeatures", requiredFeatures.isEmpty() || - supportedFeatures.containsAll(requiredFeatures.asList()) + supportedFeatures.containsAll(requiredFeatures.asList()), ) } lineSeparator = adb.execute( ShellCommandRequest("echo"), - device.serial + device.serial, ).output return device diff --git a/adam/src/integrationTest/kotlin/com/malinskiy/adam/rule/DeviceType.kt b/adam/src/integrationTest/kotlin/com/malinskiy/adam/rule/DeviceType.kt index 176902d23..deafdfcf4 100644 --- a/adam/src/integrationTest/kotlin/com/malinskiy/adam/rule/DeviceType.kt +++ b/adam/src/integrationTest/kotlin/com/malinskiy/adam/rule/DeviceType.kt @@ -18,5 +18,5 @@ package com.malinskiy.adam.rule enum class DeviceType { EMULATOR, - ANY -} \ No newline at end of file + ANY, +} diff --git a/adam/src/main/kotlin/com/malinskiy/adam/AndroidDebugBridgeClient.kt b/adam/src/main/kotlin/com/malinskiy/adam/AndroidDebugBridgeClient.kt index ce327b7ce..fbfa67558 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/AndroidDebugBridgeClient.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/AndroidDebugBridgeClient.kt @@ -36,23 +36,25 @@ import java.io.Closeable import java.net.InetAddress import java.net.InetSocketAddress -class AndroidDebugBridgeClient( - val port: Int, - val host: InetAddress, - val socketFactory: SocketFactory +public class AndroidDebugBridgeClient( + public val port: Int, + public val host: InetAddress, + public val socketFactory: SocketFactory, ) : Closeable { private val socketAddress: InetSocketAddress = InetSocketAddress(host, port) - suspend fun execute(request: ComplexRequest, serial: String? = null): T { + public suspend fun execute(request: ComplexRequest, serial: String? = null): T { val validationResponse = request.validate() if (!validationResponse.success) { val requestSimpleClassName = request.javaClass.simpleName - throw RequestValidationException("Request $requestSimpleClassName did not pass validation: ${validationResponse.message}") + throw RequestValidationException( + "Request $requestSimpleClassName did not pass validation: ${validationResponse.message}", + ) } return socketFactory.tcp( socketAddress = socketAddress, - idleTimeout = request.socketIdleTimeout + idleTimeout = request.socketIdleTimeout, ).use { socket -> serial?.let { SetDeviceRequest(it).handshake(socket) @@ -61,16 +63,22 @@ class AndroidDebugBridgeClient( } } - fun execute(request: AsyncChannelRequest, scope: CoroutineScope, serial: String? = null): ReceiveChannel { + public fun execute( + request: AsyncChannelRequest, + scope: CoroutineScope, + serial: String? = null, + ): ReceiveChannel { val validationResponse = request.validate() if (!validationResponse.success) { val requestSimpleClassName = request.javaClass.simpleName - throw RequestValidationException("Request $requestSimpleClassName did not pass validation: ${validationResponse.message}") + throw RequestValidationException( + "Request $requestSimpleClassName did not pass validation: ${validationResponse.message}", + ) } return scope.produce { socketFactory.tcp( socketAddress = socketAddress, - idleTimeout = request.socketIdleTimeout + idleTimeout = request.socketIdleTimeout, ).use { socket -> var backChannel = request.channel var backChannelJob: Job? = null @@ -115,31 +123,33 @@ class AndroidDebugBridgeClient( } } - suspend fun execute(request: EmulatorCommandRequest): String { + public suspend fun execute(request: EmulatorCommandRequest): String { return socketFactory.tcp( socketAddress = request.address, - idleTimeout = request.idleTimeoutOverride + idleTimeout = request.idleTimeoutOverride, ).use { socket -> request.process(socket) } } - suspend fun execute(request: MultiRequest, serial: String? = null): T { + public suspend fun execute(request: MultiRequest, serial: String? = null): T { val validationResponse = request.validate() if (!validationResponse.success) { val requestSimpleClassName = request.javaClass.simpleName - throw RequestValidationException("Request $requestSimpleClassName did not pass validation: ${validationResponse.message}") + throw RequestValidationException( + "Request $requestSimpleClassName did not pass validation: ${validationResponse.message}", + ) } return request.execute(this, serial) } - companion object { + public companion object { private val log = AdamLogging.logger {} } /** * If you're reusing the socket factory across multiple clients then this will affect another client */ - override fun close() = socketFactory.close() + override fun close(): Unit = socketFactory.close() } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/AndroidDebugBridgeClientFactory.kt b/adam/src/main/kotlin/com/malinskiy/adam/AndroidDebugBridgeClientFactory.kt index c70a2f29c..6d512c0b7 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/AndroidDebugBridgeClientFactory.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/AndroidDebugBridgeClientFactory.kt @@ -23,22 +23,22 @@ import java.net.InetAddress import java.time.Duration import kotlin.coroutines.CoroutineContext -class AndroidDebugBridgeClientFactory { - var port: Int? = null - var host: InetAddress? = null - var coroutineContext: CoroutineContext? = null - var socketFactory: SocketFactory? = null - var idleTimeout: Duration? = null - var connectTimeout: Duration? = null +public class AndroidDebugBridgeClientFactory { + public var port: Int? = null + public var host: InetAddress? = null + public var coroutineContext: CoroutineContext? = null + public var socketFactory: SocketFactory? = null + public var idleTimeout: Duration? = null + public var connectTimeout: Duration? = null - fun build(): AndroidDebugBridgeClient { + public fun build(): AndroidDebugBridgeClient { return AndroidDebugBridgeClient( port = port ?: DiscoverAdbSocketInteractor().execute(), host = host ?: InetAddress.getByName(Const.DEFAULT_ADB_HOST), socketFactory = socketFactory ?: VertxSocketFactory( idleTimeout = idleTimeout?.toMillis() ?: 30_000, - connectTimeout = connectTimeout?.toMillis() ?: 10_000 - ) + connectTimeout = connectTimeout?.toMillis() ?: 10_000, + ), ) } } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/Const.kt b/adam/src/main/kotlin/com/malinskiy/adam/Const.kt index 00bd149d9..0bab0ed19 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/Const.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/Const.kt @@ -16,44 +16,58 @@ package com.malinskiy.adam -object Const { - const val MAX_REMOTE_PATH_LENGTH = 1024 - const val DEFAULT_BUFFER_SIZE = 1024 - val DEFAULT_TRANSPORT_ENCODING = Charsets.UTF_8 - const val DEFAULT_ADB_HOST = "127.0.0.1" - const val DEFAULT_ADB_PORT = 5037 +public object Const { + public const val MAX_REMOTE_PATH_LENGTH: Int = 1024 + public const val DEFAULT_BUFFER_SIZE: Int = 1024 + public val DEFAULT_TRANSPORT_ENCODING: java.nio.charset.Charset = Charsets.UTF_8 + public const val DEFAULT_ADB_HOST: String = "127.0.0.1" + public const val DEFAULT_ADB_PORT: Int = 5037 - const val SERVER_PORT_ENV_VAR = "ANDROID_ADB_SERVER_PORT" - const val MAX_PACKET_LENGTH = 16384 - const val MAX_FILE_PACKET_LENGTH = 64 * 1024 + public const val SERVER_PORT_ENV_VAR: String = "ANDROID_ADB_SERVER_PORT" + public const val MAX_PACKET_LENGTH: Int = 16384 + public const val MAX_FILE_PACKET_LENGTH: Int = 64 * 1024 - const val MAX_PROTOBUF_LOGCAT_LENGTH = 10_000 - const val MAX_PROTOBUF_PACKET_LENGTH = 10 * 1024 * 1024L //10Mb - const val TEST_LOGCAT_METRIC = "com.malinskiy.adam.logcat" + public const val MAX_PROTOBUF_LOGCAT_LENGTH: Int = 10_000 + public const val MAX_PROTOBUF_PACKET_LENGTH: Long = 10 * 1024 * 1024L // 10Mb + public const val TEST_LOGCAT_METRIC: String = "com.malinskiy.adam.logcat" - const val ANDROID_FILE_SEPARATOR = "/" - val SYNC_IGNORED_FILES = setOf(".", "..") + public const val ANDROID_FILE_SEPARATOR: String = "/" + public val SYNC_IGNORED_FILES: Set = setOf(".", "..") - object Message { - val OKAY = byteArrayOf('O'.code.toByte(), 'K'.code.toByte(), 'A'.code.toByte(), 'Y'.code.toByte()) - val FAIL = byteArrayOf('F'.code.toByte(), 'A'.code.toByte(), 'I'.code.toByte(), 'L'.code.toByte()) + public object Message { + public val OKAY: ByteArray = + byteArrayOf('O'.code.toByte(), 'K'.code.toByte(), 'A'.code.toByte(), 'Y'.code.toByte()) + public val FAIL: ByteArray = + byteArrayOf('F'.code.toByte(), 'A'.code.toByte(), 'I'.code.toByte(), 'L'.code.toByte()) - val DATA = byteArrayOf('D'.code.toByte(), 'A'.code.toByte(), 'T'.code.toByte(), 'A'.code.toByte()) - val DONE = byteArrayOf('D'.code.toByte(), 'O'.code.toByte(), 'N'.code.toByte(), 'E'.code.toByte()) + public val DATA: ByteArray = + byteArrayOf('D'.code.toByte(), 'A'.code.toByte(), 'T'.code.toByte(), 'A'.code.toByte()) + public val DONE: ByteArray = + byteArrayOf('D'.code.toByte(), 'O'.code.toByte(), 'N'.code.toByte(), 'E'.code.toByte()) - val LSTAT_V1 = byteArrayOf('S'.code.toByte(), 'T'.code.toByte(), 'A'.code.toByte(), 'T'.code.toByte()) - val LIST_V1 = byteArrayOf('L'.code.toByte(), 'I'.code.toByte(), 'S'.code.toByte(), 'T'.code.toByte()) - val DENT_V1 = byteArrayOf('D'.code.toByte(), 'E'.code.toByte(), 'N'.code.toByte(), 'T'.code.toByte()) - val SEND_V1 = byteArrayOf('S'.code.toByte(), 'E'.code.toByte(), 'N'.code.toByte(), 'D'.code.toByte()) - val RECV_V1 = byteArrayOf('R'.code.toByte(), 'E'.code.toByte(), 'C'.code.toByte(), 'V'.code.toByte()) + public val LSTAT_V1: ByteArray = + byteArrayOf('S'.code.toByte(), 'T'.code.toByte(), 'A'.code.toByte(), 'T'.code.toByte()) + public val LIST_V1: ByteArray = + byteArrayOf('L'.code.toByte(), 'I'.code.toByte(), 'S'.code.toByte(), 'T'.code.toByte()) + public val DENT_V1: ByteArray = + byteArrayOf('D'.code.toByte(), 'E'.code.toByte(), 'N'.code.toByte(), 'T'.code.toByte()) + public val SEND_V1: ByteArray = + byteArrayOf('S'.code.toByte(), 'E'.code.toByte(), 'N'.code.toByte(), 'D'.code.toByte()) + public val RECV_V1: ByteArray = + byteArrayOf('R'.code.toByte(), 'E'.code.toByte(), 'C'.code.toByte(), 'V'.code.toByte()) - val LIST_V2 = byteArrayOf('L'.code.toByte(), 'I'.code.toByte(), 'S'.code.toByte(), '2'.code.toByte()) - val DENT_V2 = byteArrayOf('D'.code.toByte(), 'N'.code.toByte(), 'T'.code.toByte(), '2'.code.toByte()) - val LSTAT_V2 = byteArrayOf('L'.code.toByte(), 'S'.code.toByte(), 'T'.code.toByte(), '2'.code.toByte()) - val RECV_V2 = byteArrayOf('R'.code.toByte(), 'C'.code.toByte(), 'V'.code.toByte(), '2'.code.toByte()) - val SEND_V2 = byteArrayOf('S'.code.toByte(), 'N'.code.toByte(), 'D'.code.toByte(), '2'.code.toByte()) + public val LIST_V2: ByteArray = + byteArrayOf('L'.code.toByte(), 'I'.code.toByte(), 'S'.code.toByte(), '2'.code.toByte()) + public val DENT_V2: ByteArray = + byteArrayOf('D'.code.toByte(), 'N'.code.toByte(), 'T'.code.toByte(), '2'.code.toByte()) + public val LSTAT_V2: ByteArray = + byteArrayOf('L'.code.toByte(), 'S'.code.toByte(), 'T'.code.toByte(), '2'.code.toByte()) + public val RECV_V2: ByteArray = + byteArrayOf('R'.code.toByte(), 'C'.code.toByte(), 'V'.code.toByte(), '2'.code.toByte()) + public val SEND_V2: ByteArray = + byteArrayOf('S'.code.toByte(), 'N'.code.toByte(), 'D'.code.toByte(), '2'.code.toByte()) - val DONEDONE = + public val DONEDONE: ByteArray = byteArrayOf( 'D'.code.toByte(), 'O'.code.toByte(), @@ -62,9 +76,9 @@ object Const { 'D'.code.toByte(), 'O'.code.toByte(), 'N'.code.toByte(), - 'E'.code.toByte() + 'E'.code.toByte(), ) - val FAILFAIL = + public val FAILFAIL: ByteArray = byteArrayOf( 'F'.code.toByte(), 'A'.code.toByte(), @@ -73,18 +87,18 @@ object Const { 'F'.code.toByte(), 'A'.code.toByte(), 'I'.code.toByte(), - 'L'.code.toByte() + 'L'.code.toByte(), ) } - object FileType { - val S_IFMT = "170000".toUInt(8) - val S_IFIFO = "10000".toUInt(8) - val S_IFCHR = "20000".toUInt(8) - val S_IFDIR = "40000".toUInt(8) - val S_IFBLK = "60000".toUInt(8) - val S_IFREG = "100000".toUInt(8) - val S_IFLNK = "120000".toUInt(8) - val S_IFSOCK = "140000".toUInt(8) + public object FileType { + public val S_IFMT: UInt = "170000".toUInt(8) + public val S_IFIFO: UInt = "10000".toUInt(8) + public val S_IFCHR: UInt = "20000".toUInt(8) + public val S_IFDIR: UInt = "40000".toUInt(8) + public val S_IFBLK: UInt = "60000".toUInt(8) + public val S_IFREG: UInt = "100000".toUInt(8) + public val S_IFLNK: UInt = "120000".toUInt(8) + public val S_IFSOCK: UInt = "140000".toUInt(8) } } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/annotation/Features.kt b/adam/src/main/kotlin/com/malinskiy/adam/annotation/Features.kt index 03d423970..2263c9b3a 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/annotation/Features.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/annotation/Features.kt @@ -25,4 +25,4 @@ import com.malinskiy.adam.request.Feature @Target(AnnotationTarget.CLASS) @Retention(AnnotationRetention.RUNTIME) @MustBeDocumented -annotation class Features(vararg val features: Feature) +public annotation class Features(vararg val features: Feature) diff --git a/adam/src/main/kotlin/com/malinskiy/adam/exception/PullFailedException.kt b/adam/src/main/kotlin/com/malinskiy/adam/exception/PullFailedException.kt index 9c0ec73d8..81ca92359 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/exception/PullFailedException.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/exception/PullFailedException.kt @@ -16,4 +16,4 @@ package com.malinskiy.adam.exception -class PullFailedException(message: String) : RuntimeException(message) \ No newline at end of file +public class PullFailedException(message: String) : RuntimeException(message) diff --git a/adam/src/main/kotlin/com/malinskiy/adam/exception/PushFailedException.kt b/adam/src/main/kotlin/com/malinskiy/adam/exception/PushFailedException.kt index c6c920280..8e123364b 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/exception/PushFailedException.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/exception/PushFailedException.kt @@ -16,4 +16,4 @@ package com.malinskiy.adam.exception -class PushFailedException(message: String) : RuntimeException(message) \ No newline at end of file +public class PushFailedException(message: String) : RuntimeException(message) diff --git a/adam/src/main/kotlin/com/malinskiy/adam/exception/RequestRejectedException.kt b/adam/src/main/kotlin/com/malinskiy/adam/exception/RequestRejectedException.kt index 2b4921c63..1b9957b07 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/exception/RequestRejectedException.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/exception/RequestRejectedException.kt @@ -16,4 +16,4 @@ package com.malinskiy.adam.exception -class RequestRejectedException(message: String) : RuntimeException(message) +public class RequestRejectedException(message: String) : RuntimeException(message) diff --git a/adam/src/main/kotlin/com/malinskiy/adam/exception/RequestValidationException.kt b/adam/src/main/kotlin/com/malinskiy/adam/exception/RequestValidationException.kt index 31adb3e0b..a86c87bc5 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/exception/RequestValidationException.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/exception/RequestValidationException.kt @@ -16,4 +16,4 @@ package com.malinskiy.adam.exception -class RequestValidationException(message: String) : RuntimeException(message) \ No newline at end of file +public class RequestValidationException(message: String) : RuntimeException(message) diff --git a/adam/src/main/kotlin/com/malinskiy/adam/exception/UnsupportedForwardingSpecException.kt b/adam/src/main/kotlin/com/malinskiy/adam/exception/UnsupportedForwardingSpecException.kt index 2374fe7d2..a595432e6 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/exception/UnsupportedForwardingSpecException.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/exception/UnsupportedForwardingSpecException.kt @@ -16,4 +16,6 @@ package com.malinskiy.adam.exception -class UnsupportedForwardingSpecException(type: String) : RuntimeException("Unknown type $type for forwarding spec") \ No newline at end of file +public class UnsupportedForwardingSpecException(type: String) : RuntimeException( + "Unknown type $type for forwarding spec", +) diff --git a/adam/src/main/kotlin/com/malinskiy/adam/exception/UnsupportedImageProtocolException.kt b/adam/src/main/kotlin/com/malinskiy/adam/exception/UnsupportedImageProtocolException.kt index 0b58245ce..3005679f6 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/exception/UnsupportedImageProtocolException.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/exception/UnsupportedImageProtocolException.kt @@ -16,4 +16,4 @@ package com.malinskiy.adam.exception -class UnsupportedImageProtocolException(version: Int?) : RuntimeException("Unsupported version $version") \ No newline at end of file +public class UnsupportedImageProtocolException(version: Int?) : RuntimeException("Unsupported version $version") diff --git a/adam/src/main/kotlin/com/malinskiy/adam/exception/UnsupportedSyncProtocolException.kt b/adam/src/main/kotlin/com/malinskiy/adam/exception/UnsupportedSyncProtocolException.kt index 32c2cfbbb..3b83639af 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/exception/UnsupportedSyncProtocolException.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/exception/UnsupportedSyncProtocolException.kt @@ -16,6 +16,6 @@ package com.malinskiy.adam.exception -class UnsupportedSyncProtocolException(message: String) : RuntimeException(message) { - constructor() : this("Unsupported sync: protocol response") +public class UnsupportedSyncProtocolException(message: String) : RuntimeException(message) { + public constructor() : this("Unsupported sync: protocol response") } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/extension/ByteArray.kt b/adam/src/main/kotlin/com/malinskiy/adam/extension/ByteArray.kt index fce6f26fa..742496cf9 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/extension/ByteArray.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/extension/ByteArray.kt @@ -16,28 +16,28 @@ package com.malinskiy.adam.extension -fun ByteArray.toInt(): Int { +public fun ByteArray.toInt(): Int { return (this[0].toInt() and 0x000000FF) or - (this[1].toInt() and 0x000000FF shl 8) or - (this[2].toInt() and 0x000000FF shl 16) or - (this[3].toInt() and 0x000000FF shl 24) + (this[1].toInt() and 0x000000FF shl 8) or + (this[2].toInt() and 0x000000FF shl 16) or + (this[3].toInt() and 0x000000FF shl 24) } -fun ByteArray.toUInt(): UInt { +public fun ByteArray.toUInt(): UInt { return toInt().toUInt() } -fun ByteArray.toLong(): Long { +public fun ByteArray.toLong(): Long { return (this[0].toInt() and 0x000000FF).toLong() or - (this[1].toInt() and 0x000000FF shl 8).toLong() or - (this[2].toInt() and 0x000000FF shl 16).toLong() or - (this[3].toInt() and 0x000000FF shl 24).toLong() or - (this[4].toInt() and 0x000000FF shl 32).toLong() or - (this[5].toInt() and 0x000000FF shl 40).toLong() or - (this[6].toInt() and 0x000000FF shl 48).toLong() or - (this[7].toInt() and 0x000000FF shl 56).toLong() + (this[1].toInt() and 0x000000FF shl 8).toLong() or + (this[2].toInt() and 0x000000FF shl 16).toLong() or + (this[3].toInt() and 0x000000FF shl 24).toLong() or + (this[4].toInt() and 0x000000FF shl 32).toLong() or + (this[5].toInt() and 0x000000FF shl 40).toLong() or + (this[6].toInt() and 0x000000FF shl 48).toLong() or + (this[7].toInt() and 0x000000FF shl 56).toLong() } -fun ByteArray.toULong(): ULong { +public fun ByteArray.toULong(): ULong { return toLong().toULong() } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/extension/ByteBuffer.kt b/adam/src/main/kotlin/com/malinskiy/adam/extension/ByteBuffer.kt index 6ca8a8d48..5f89f3dbd 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/extension/ByteBuffer.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/extension/ByteBuffer.kt @@ -24,8 +24,8 @@ import java.nio.ByteBuffer * * java.lang.NoSuchMethodError: java.nio.ByteBuffer.xxx()Ljava/nio/ByteBuffer; */ -fun ByteBuffer.compatRewind() = ((this as Buffer).rewind() as ByteBuffer) -fun ByteBuffer.compatLimit(newLimit: Int) = ((this as Buffer).limit(newLimit) as ByteBuffer) -fun ByteBuffer.compatPosition(newLimit: Int) = ((this as Buffer).position(newLimit) as ByteBuffer) -fun ByteBuffer.compatFlip() = ((this as Buffer).flip() as ByteBuffer) -fun ByteBuffer.compatClear() = ((this as Buffer).clear() as ByteBuffer) +public fun ByteBuffer.compatRewind(): ByteBuffer = ((this as Buffer).rewind() as ByteBuffer) +public fun ByteBuffer.compatLimit(newLimit: Int): ByteBuffer = ((this as Buffer).limit(newLimit) as ByteBuffer) +public fun ByteBuffer.compatPosition(newLimit: Int): ByteBuffer = ((this as Buffer).position(newLimit) as ByteBuffer) +public fun ByteBuffer.compatFlip(): ByteBuffer = ((this as Buffer).flip() as ByteBuffer) +public fun ByteBuffer.compatClear(): ByteBuffer = ((this as Buffer).clear() as ByteBuffer) diff --git a/adam/src/main/kotlin/com/malinskiy/adam/extension/Int.kt b/adam/src/main/kotlin/com/malinskiy/adam/extension/Int.kt index 9b69867ff..6049a310d 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/extension/Int.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/extension/Int.kt @@ -16,11 +16,11 @@ package com.malinskiy.adam.extension -fun Int.toByteArray(): ByteArray { +public fun Int.toByteArray(): ByteArray { return byteArrayOf( this.ushr(24).toByte(), ((this and 0xFF0000) shr 16).toByte(), ((this and 0xFF00) shr 8).toByte(), - (this and 0xFF).toByte() + (this and 0xFF).toByte(), ) -} \ No newline at end of file +} diff --git a/adam/src/main/kotlin/com/malinskiy/adam/extension/List.kt b/adam/src/main/kotlin/com/malinskiy/adam/extension/List.kt index 1aa470f6c..ad3f59467 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/extension/List.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/extension/List.kt @@ -16,6 +16,6 @@ package com.malinskiy.adam.extension -fun List.bashEscape() = "'" + joinToString(" ") { it.replace("'", "'\\''") } + "'" +public fun List.bashEscape(): String = "'" + joinToString(" ") { it.replace("'", "'\\''") } + "'" -fun String.bashEscape() = "'" + replace("'", "'\\''") + "'" +public fun String.bashEscape(): String = "'" + replace("'", "'\\''") + "'" diff --git a/adam/src/main/kotlin/com/malinskiy/adam/extension/Socket.kt b/adam/src/main/kotlin/com/malinskiy/adam/extension/Socket.kt index 770d4d026..3474bd7bb 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/extension/Socket.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/extension/Socket.kt @@ -35,7 +35,11 @@ import kotlin.coroutines.CoroutineContext /** * Copies up to limit bytes into transformer using buffer. If limit is null - copy until EOF */ -suspend fun Socket.copyTo(transformer: ResponseTransformer, buffer: ByteArray, limit: Long? = null): Long { +public suspend fun Socket.copyTo( + transformer: ResponseTransformer, + buffer: ByteArray, + limit: Long? = null, +): Long { var processed = 0L loop@ while (true) { val toRead = when { @@ -53,6 +57,7 @@ suspend fun Socket.copyTo(transformer: ResponseTransformer, buffer: ByteA val available = readAvailable(buffer, 0, toRead) when { processed == limit -> break@loop + available < 0 -> { break@loop } @@ -76,11 +81,18 @@ suspend fun Socket.copyTo(transformer: ResponseTransformer, buffer: ByteA * TODO: rewrite * Assumes buffer hasArray == true */ -suspend fun Socket.copyTo(transformer: ResponseTransformer, buffer: ByteBuffer) = copyTo(transformer, buffer.array()) -suspend fun Socket.copyTo(transformer: ResponseTransformer, buffer: ByteBuffer, limit: Long? = null) = +public suspend fun Socket.copyTo( + transformer: ResponseTransformer, + buffer: ByteBuffer, +): Long = copyTo(transformer, buffer.array()) +public suspend fun Socket.copyTo( + transformer: ResponseTransformer, + buffer: ByteBuffer, + limit: Long? = null, +): Long = copyTo(transformer, buffer.array(), limit) -suspend fun Socket.readOptionalProtocolString(): String? { +public suspend fun Socket.readOptionalProtocolString(): String? { val responseLength = withDefaultBuffer { val transformer = StringResponseTransformer() copyTo(transformer, this, limit = 4L) @@ -101,7 +113,7 @@ suspend fun Socket.readOptionalProtocolString(): String? { /** * @throws RequestRejectedException */ -suspend fun Socket.readProtocolString(): String { +public suspend fun Socket.readProtocolString(): String { withMaxPacketBuffer { val transformer = StringResponseTransformer() val copied = copyTo(transformer, this, limit = 4L) @@ -109,7 +121,8 @@ suspend fun Socket.readProtocolString(): String { if (copied != 4L) { throw RequestRejectedException("Unexpected string length: $length") } - val messageLength = length.toIntOrNull(16) ?: throw RequestRejectedException("Unexpected string length: $length") + val messageLength = + length.toIntOrNull(16) ?: throw RequestRejectedException("Unexpected string length: $length") compatClear() compatLimit(messageLength) @@ -127,7 +140,7 @@ private fun ByteBuffer.isOkay(): Boolean { return true } -suspend fun Socket.readStatus(): String { +public suspend fun Socket.readStatus(): String { withDefaultBuffer { val transformer = StringResponseTransformer() copyTo(transformer, this) @@ -135,11 +148,11 @@ suspend fun Socket.readStatus(): String { } } -suspend fun Socket.write(request: ByteArray, length: Int? = null) { +public suspend fun Socket.write(request: ByteArray, length: Int? = null) { writeFully(request, 0, length ?: request.size) } -suspend fun Socket.writeFile(file: File, coroutineContext: CoroutineContext) { +public suspend fun Socket.writeFile(file: File, coroutineContext: CoroutineContext) { AsyncFileReader(file, coroutineContext = coroutineContext).use { reader -> reader.start() while (true) { @@ -159,7 +172,7 @@ suspend fun Socket.writeFile(file: File, coroutineContext: CoroutineContext) { } } -suspend fun Socket.writeSyncRequest(type: ByteArray, remotePath: String) { +public suspend fun Socket.writeSyncRequest(type: ByteArray, remotePath: String) { val path = remotePath.toByteArray(Const.DEFAULT_TRANSPORT_ENCODING) val size = path.size.toByteArray().reversedArray() @@ -172,7 +185,7 @@ suspend fun Socket.writeSyncRequest(type: ByteArray, remotePath: String) { } } -suspend fun Socket.writeSyncV2Request(type: ByteArray, remotePath: String, flags: Int, mode: Int? = null) { +public suspend fun Socket.writeSyncV2Request(type: ByteArray, remotePath: String, flags: Int, mode: Int? = null) { val path = remotePath.toByteArray(Const.DEFAULT_TRANSPORT_ENCODING) withDefaultBuffer { @@ -194,7 +207,7 @@ suspend fun Socket.writeSyncV2Request(type: ByteArray, remotePath: String, flags } } -suspend fun Socket.readTransportResponse(): TransportResponse { +public suspend fun Socket.readTransportResponse(): TransportResponse { val ok = withDefaultBuffer { compatLimit(4) readFully(this) diff --git a/adam/src/main/kotlin/com/malinskiy/adam/interactor/AdbBinaryInteractor.kt b/adam/src/main/kotlin/com/malinskiy/adam/interactor/AdbBinaryInteractor.kt index b764e4c17..f9d569e41 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/interactor/AdbBinaryInteractor.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/interactor/AdbBinaryInteractor.kt @@ -22,11 +22,11 @@ import java.lang.ProcessBuilder.Redirect import java.util.* @Suppress("NewApi") -open class AdbBinaryInteractor { - suspend fun execute( +public open class AdbBinaryInteractor { + public suspend fun execute( adbBinary: File?, androidHome: File?, - vararg cmd: String + vararg cmd: String, ): Boolean { val androidEnvHome: File? = try { System.getenv("ANDROID_HOME") ?: System.getenv("ANDROID_SDK_ROOT") diff --git a/adam/src/main/kotlin/com/malinskiy/adam/interactor/DiscoverAdbSocketInteractor.kt b/adam/src/main/kotlin/com/malinskiy/adam/interactor/DiscoverAdbSocketInteractor.kt index 73179b7af..ef926c145 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/interactor/DiscoverAdbSocketInteractor.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/interactor/DiscoverAdbSocketInteractor.kt @@ -19,8 +19,8 @@ package com.malinskiy.adam.interactor import com.malinskiy.adam.Const import com.malinskiy.adam.log.AdamLogging -class DiscoverAdbSocketInteractor { - fun execute() = discover("system property") { System.getProperty(Const.SERVER_PORT_ENV_VAR) } +public class DiscoverAdbSocketInteractor { + public fun execute(): Int = discover("system property") { System.getProperty(Const.SERVER_PORT_ENV_VAR) } ?: discover("env var") { System.getenv(Const.SERVER_PORT_ENV_VAR) } ?: Const.DEFAULT_ADB_PORT @@ -49,7 +49,7 @@ class DiscoverAdbSocketInteractor { else -> true } - companion object { + public companion object { private val log = AdamLogging.logger {} } -} \ No newline at end of file +} diff --git a/adam/src/main/kotlin/com/malinskiy/adam/interactor/StartAdbInteractor.kt b/adam/src/main/kotlin/com/malinskiy/adam/interactor/StartAdbInteractor.kt index fc7304a6d..08a68cba8 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/interactor/StartAdbInteractor.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/interactor/StartAdbInteractor.kt @@ -19,10 +19,10 @@ package com.malinskiy.adam.interactor import com.malinskiy.adam.Const import java.io.File -class StartAdbInteractor : AdbBinaryInteractor() { - suspend fun execute( +public class StartAdbInteractor : AdbBinaryInteractor() { + public suspend fun execute( adbBinary: File? = null, androidHome: File? = null, - serverPort: Int = Const.DEFAULT_ADB_PORT - ) = execute(adbBinary, androidHome, "-P", serverPort.toString(), "start-server") -} \ No newline at end of file + serverPort: Int = Const.DEFAULT_ADB_PORT, + ): Boolean = execute(adbBinary, androidHome, "-P", serverPort.toString(), "start-server") +} diff --git a/adam/src/main/kotlin/com/malinskiy/adam/interactor/StopAdbInteractor.kt b/adam/src/main/kotlin/com/malinskiy/adam/interactor/StopAdbInteractor.kt index 6c6ccd94c..499e49374 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/interactor/StopAdbInteractor.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/interactor/StopAdbInteractor.kt @@ -19,10 +19,10 @@ package com.malinskiy.adam.interactor import com.malinskiy.adam.Const import java.io.File -class StopAdbInteractor : AdbBinaryInteractor() { - suspend fun execute( +public class StopAdbInteractor : AdbBinaryInteractor() { + public suspend fun execute( adbBinary: File? = null, androidHome: File? = null, - serverPort: Int = Const.DEFAULT_ADB_PORT - ) = execute(adbBinary, androidHome, "-P", serverPort.toString(), "kill-server") -} \ No newline at end of file + serverPort: Int = Const.DEFAULT_ADB_PORT, + ): Boolean = execute(adbBinary, androidHome, "-P", serverPort.toString(), "kill-server") +} diff --git a/adam/src/main/kotlin/com/malinskiy/adam/io/AsyncFileReader.kt b/adam/src/main/kotlin/com/malinskiy/adam/io/AsyncFileReader.kt index cb89931f4..f9eb4a5dc 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/io/AsyncFileReader.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/io/AsyncFileReader.kt @@ -35,19 +35,19 @@ import kotlin.coroutines.CoroutineContext /** * Reads file using passed coroutineContext and pushes updates of predefined structure using channel */ -class AsyncFileReader( +public class AsyncFileReader( file: File, private val start: Long = 0, private val offset: Int = 0, private val length: Int = Const.MAX_FILE_PACKET_LENGTH, - override val coroutineContext: CoroutineContext = Dispatchers.IO + override val coroutineContext: CoroutineContext = Dispatchers.IO, ) : CoroutineScope, SuspendCloseable { private val fileChannel = file.inputStream().buffered() private val bufferChannel: Channel = Channel(capacity = 2) private var job: Job? = null @Suppress("BlockingMethodInNonBlockingContext") - fun start() { + public fun start() { job = launch { fileChannel.use { readChannel -> readChannel.skip(start) @@ -59,6 +59,7 @@ class AsyncFileReader( AdamMaxFilePacketPool.recycle(byteBuffer) shouldClose = true } + else -> { byteBuffer.compatLimit(read + offset) bufferChannel.send(byteBuffer) @@ -70,7 +71,7 @@ class AsyncFileReader( } } - suspend fun read(block: suspend (ByteBuffer?) -> T): T { + public suspend fun read(block: suspend (ByteBuffer?) -> T): T { return block(bufferChannel.receiveCatching().getOrNull()) } @@ -80,7 +81,7 @@ class AsyncFileReader( } } -suspend fun AsyncFileReader.copyTo(socket: Socket) { +public suspend fun AsyncFileReader.copyTo(socket: Socket) { while (true) { val closed = read { try { @@ -95,7 +96,7 @@ suspend fun AsyncFileReader.copyTo(socket: Socket) { } } -suspend fun AsyncFileReader.copyTo(transformer: ResponseTransformer) { +public suspend fun AsyncFileReader.copyTo(transformer: ResponseTransformer) { while (true) { val closed = read { try { diff --git a/adam/src/main/kotlin/com/malinskiy/adam/io/AsyncFileWriter.kt b/adam/src/main/kotlin/com/malinskiy/adam/io/AsyncFileWriter.kt index b690566e5..3d2b246dd 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/io/AsyncFileWriter.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/io/AsyncFileWriter.kt @@ -28,9 +28,9 @@ import java.io.File import java.nio.ByteBuffer import kotlin.coroutines.CoroutineContext -class AsyncFileWriter( +public class AsyncFileWriter( file: File, - override val coroutineContext: CoroutineContext = Dispatchers.IO + override val coroutineContext: CoroutineContext = Dispatchers.IO, ) : CoroutineScope, SuspendCloseable { private val fileChannel by lazy { if (!file.exists()) { @@ -45,7 +45,7 @@ class AsyncFileWriter( private var job: Job? = null @Suppress("BlockingMethodInNonBlockingContext") - fun start() { + public fun start() { job = launch { for (buffer in bufferChannel) { fileChannel.write(buffer.array(), buffer.position(), buffer.limit()) @@ -54,7 +54,7 @@ class AsyncFileWriter( } } - suspend fun write(byteBuffer: ByteBuffer) { + public suspend fun write(byteBuffer: ByteBuffer) { bufferChannel.send(byteBuffer) } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/log/AdamLogging.kt b/adam/src/main/kotlin/com/malinskiy/adam/log/AdamLogging.kt index b1af01c5c..b97d60ec2 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/log/AdamLogging.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/log/AdamLogging.kt @@ -16,9 +16,72 @@ package com.malinskiy.adam.log -import mu.KLogger -import mu.KotlinLogging +import logcat.LogPriority +import logcat.asLog +import logcat.logcat -object AdamLogging { - fun logger(func: () -> Unit): KLogger = KotlinLogging.logger(func) -} \ No newline at end of file +public object AdamLogging { + public fun logger(func: () -> Unit): AdamLogger = AdamLogger() +} + +public class AdamLogger { + public inline fun debug(throwable: Throwable? = null, crossinline message: () -> String) { + logcat(LogPriority.DEBUG) { + buildString { + throwable?.let { + append(it.asLog()) + append("\n") + } + append(message()) + } + } + } + + public inline fun info(throwable: Throwable? = null, crossinline message: () -> String) { + logcat(LogPriority.INFO) { + buildString { + throwable?.let { + append(it.asLog()) + append("\n") + } + append(message()) + } + } + } + + public inline fun warn(throwable: Throwable? = null, crossinline message: () -> String) { + logcat(LogPriority.WARN) { + buildString { + throwable?.let { + append(it.asLog()) + append("\n") + } + append(message()) + } + } + } + + public inline fun error(throwable: Throwable? = null, crossinline message: () -> String) { + logcat(LogPriority.ERROR) { + buildString { + throwable?.let { + append(it.asLog()) + append("\n") + } + append(message()) + } + } + } + + public inline fun trace(throwable: Throwable? = null, crossinline message: () -> String) { + logcat(LogPriority.VERBOSE) { + buildString { + throwable?.let { + append(it.asLog()) + append("\n") + } + append(message()) + } + } + } +} diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/AccumulatingMultiRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/AccumulatingMultiRequest.kt index 0650090aa..f1c9821c1 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/AccumulatingMultiRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/AccumulatingMultiRequest.kt @@ -19,7 +19,7 @@ package com.malinskiy.adam.request /** * MultiRequest that accumulates char sequence responses */ -abstract class AccumulatingMultiRequest : MultiRequest() { +public abstract class AccumulatingMultiRequest : MultiRequest() { private val responseBuffer by lazy { StringBuilder() } protected val accumulatedResponse: String get() = responseBuffer.toString() diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/AsyncChannelRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/AsyncChannelRequest.kt index 68b1fedbe..9573e63ab 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/AsyncChannelRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/AsyncChannelRequest.kt @@ -24,25 +24,25 @@ import kotlinx.coroutines.channels.SendChannel * Read and write are called in sequence, hence you have to give the control flow back if you want * cooperative multitasking to happen */ -abstract class AsyncChannelRequest( - val channel: ReceiveChannel? = null, +public abstract class AsyncChannelRequest( + public val channel: ReceiveChannel? = null, target: Target = NonSpecifiedTarget, - socketIdleTimeout: Long? = null + socketIdleTimeout: Long? = null, ) : Request(target, socketIdleTimeout) { /** * Called after the initial OKAY confirmation */ - abstract suspend fun readElement(socket: Socket, sendChannel: SendChannel): Boolean + public abstract suspend fun readElement(socket: Socket, sendChannel: SendChannel): Boolean /** * Called after each readElement */ - abstract suspend fun writeElement(element: I, socket: Socket) + public abstract suspend fun writeElement(element: I, socket: Socket) /** * Optionally send a message * The transport connection is not available at this point */ - open suspend fun close(channel: SendChannel) = Unit + public open suspend fun close(channel: SendChannel): Unit = Unit } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/ComplexRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/ComplexRequest.kt index 961d5f573..88da7da48 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/ComplexRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/ComplexRequest.kt @@ -22,16 +22,16 @@ import com.malinskiy.adam.transport.Socket * This type of request starts with single serialized request * and then proceed to do several reads and writes that have dynamic size */ -abstract class ComplexRequest(target: Target = NonSpecifiedTarget, socketIdleTimeout: Long? = null) : +public abstract class ComplexRequest(target: Target = NonSpecifiedTarget, socketIdleTimeout: Long? = null) : Request(target, socketIdleTimeout) { /** * Some requests ignore the initial OKAY/FAIL response and instead stream the actual response * To implement these we allow overriding this method */ - open suspend fun process(socket: Socket): T { + public open suspend fun process(socket: Socket): T { handshake(socket) return readElement(socket) } - abstract suspend fun readElement(socket: Socket): T -} \ No newline at end of file + public abstract suspend fun readElement(socket: Socket): T +} diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/Feature.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/Feature.kt index 4a07a21d4..f3a9d65f1 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/Feature.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/Feature.kt @@ -21,7 +21,7 @@ import java.util.* /** * Each entry represents a service that is supported by the adbd on the device */ -enum class Feature { +public enum class Feature { SHELL_V2, /** @@ -99,15 +99,17 @@ enum class Feature { /** * adbd supports dry-run send for send/recv v2. */ - SENDRECV_V2_DRY_RUN_SEND; + SENDRECV_V2_DRY_RUN_SEND, - fun value() = name.lowercase(Locale.ENGLISH) + ; - companion object { + public fun value(): String = name.lowercase(Locale.ENGLISH) + + public companion object { /** * see adb/transport.cpp for up-to-date list */ - fun of(value: String) = when (value) { + public fun of(value: String): Feature? = when (value) { "shell_v2" -> SHELL_V2 "cmd" -> CMD "stat_v2" -> STAT_V2 diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/MultiRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/MultiRequest.kt index 1d049bd9a..1fd1075b6 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/MultiRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/MultiRequest.kt @@ -21,7 +21,7 @@ import com.malinskiy.adam.AndroidDebugBridgeClient /** * This type of request is a wrapper of a sequence of requests */ -abstract class MultiRequest { - abstract suspend fun execute(androidDebugBridgeClient: AndroidDebugBridgeClient, serial: String?): T - open fun validate(): ValidationResponse = ValidationResponse.Success +public abstract class MultiRequest { + public abstract suspend fun execute(androidDebugBridgeClient: AndroidDebugBridgeClient, serial: String?): T + public open fun validate(): ValidationResponse = ValidationResponse.Success } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/Request.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/Request.kt index 05a478dc7..183b06536 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/Request.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/Request.kt @@ -30,18 +30,18 @@ import java.io.UnsupportedEncodingException * * @param socketIdleTimeout override for socket idle timeout */ -abstract class Request( - val target: Target = HostTarget, - val socketIdleTimeout: Long? = null +public abstract class Request( + public val target: Target = HostTarget, + public val socketIdleTimeout: Long? = null, ) { /** * Some requests require a device serial to be passed to the request itself by means of * @see https://android.googlesource.com/platform/system/core/+/refs/heads/master/adb/SERVICES.TXT */ - abstract fun serialize(): ByteArray + public abstract fun serialize(): ByteArray - open suspend fun handshake(socket: Socket) { + public open suspend fun handshake(socket: Socket) { val request = serialize() socket.write(request) val response = socket.readTransportResponse() @@ -61,16 +61,16 @@ abstract class Request( val result = String.format("%04X%s", fullRequest.length, fullRequest) .toByteArray(Const.DEFAULT_TRANSPORT_ENCODING) - //Need to set proper length in case there are multi-byte characters + // Need to set proper length in case there are multi-byte characters val actualLength = result.size - 4 String.format("%04X", actualLength).toByteArray(Const.DEFAULT_TRANSPORT_ENCODING).copyInto(result, 0, 0, 4) return result } - open fun validate(): ValidationResponse = ValidationResponse.Success + public open fun validate(): ValidationResponse = ValidationResponse.Success - companion object { + public companion object { private val log = AdamLogging.logger {} } } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/SynchronousRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/SynchronousRequest.kt index 146e23843..d62cc0306 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/SynchronousRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/SynchronousRequest.kt @@ -21,7 +21,11 @@ import com.malinskiy.adam.transport.Socket import com.malinskiy.adam.transport.withMaxPacketBuffer import kotlinx.coroutines.yield -abstract class SynchronousRequest(target: Target = NonSpecifiedTarget) : ComplexRequest(target), ResponseTransformer { +public abstract class SynchronousRequest(target: Target = NonSpecifiedTarget) : + ComplexRequest( + target, + ), + ResponseTransformer { override suspend fun readElement(socket: Socket): T { withMaxPacketBuffer { loop@ do { @@ -34,6 +38,7 @@ abstract class SynchronousRequest(target: Target = NonSpecifiedTarget) yield() continue@loop } + count > 0 -> { process(data, 0, count) } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/Target.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/Target.kt index 3d073c473..8f50f1ff2 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/Target.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/Target.kt @@ -16,8 +16,8 @@ package com.malinskiy.adam.request -sealed class Target { - abstract fun serialize(): String +public sealed class Target { + public abstract fun serialize(): String } /** @@ -25,8 +25,8 @@ sealed class Target { * interpreted as 'any single device or emulator connected to/running on * the host'. */ -object HostTarget : Target() { - override fun serialize() = "host:" +public object HostTarget : Target() { + override fun serialize(): String = "host:" } /** @@ -34,26 +34,26 @@ object HostTarget : Target() { * prefix can be used to indicate that the client is asking the ADB server * for information related to a specific device. */ -class SerialTarget(private val serial: String) : Target() { - override fun serialize() = "host-serial:$serial:" +public class SerialTarget(private val serial: String) : Target() { + override fun serialize(): String = "host-serial:$serial:" } /** * A variant of host-serial used to target the single USB device connected * to the host. This will fail if there is none or more than one. */ -object UsbTarget : Target() { - override fun serialize() = "host-usb:" +public object UsbTarget : Target() { + override fun serialize(): String = "host-usb:" } /** * A variant of host-serial used to target the single emulator instance * running on the host. This will fail if there is none or more than one. */ -object LocalTarget : Target() { - override fun serialize() = "host-local:" +public object LocalTarget : Target() { + override fun serialize(): String = "host-local:" } -object NonSpecifiedTarget : Target() { - override fun serialize() = "" +public object NonSpecifiedTarget : Target() { + override fun serialize(): String = "" } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/ValidationResponse.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/ValidationResponse.kt index befb299b8..69e9d99ed 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/ValidationResponse.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/ValidationResponse.kt @@ -20,21 +20,28 @@ import com.malinskiy.adam.Const import java.io.File import java.util.* -data class ValidationResponse( - val success: Boolean, - val message: String? +public data class ValidationResponse( + public val success: Boolean, + public val message: String?, ) { - companion object { - val Success = ValidationResponse(true, null) + public companion object { + public val Success: ValidationResponse = ValidationResponse(true, null) - fun missingFeature(feature: Feature) = "${feature.name} is not supported by device" - fun missingEitherFeature(vararg feature: Feature) = "Supported features must include either of ${feature.joinToString()}" - fun oneOfFilesShouldBe(extension: String) = "At least one of the files has to be an ${extension.uppercase(Locale.ENGLISH)} file" - fun packageShouldExist(file: File) = "Package ${file.absolutePath} doesn't exist" - fun packageShouldBeRegularFile(file: File) = "Package ${file.absolutePath} is not a regular file" - fun packageShouldBeSupportedExtension(file: File, supported: Set) = + public fun missingFeature(feature: Feature): String = "${feature.name} is not supported by device" + public fun missingEitherFeature(vararg feature: Feature): String { + return "Supported features must include either of ${feature.joinToString()}" + } + + public fun oneOfFilesShouldBe(extension: String): String { + return "At least one of the files has to be an ${extension.uppercase(Locale.ENGLISH)} file" + } + public fun packageShouldExist(file: File): String = "Package ${file.absolutePath} doesn't exist" + public fun packageShouldBeRegularFile(file: File): String = "Package ${file.absolutePath} is not a regular file" + public fun packageShouldBeSupportedExtension(file: File, supported: Set): String = "Unsupported package extension ${file.extension}. Should be on of ${supported.joinToString()}}" - fun pathShouldNotBeLong() = "Remote path should be less that ${Const.MAX_REMOTE_PATH_LENGTH} bytes" + public fun pathShouldNotBeLong(): String { + return "Remote path should be less that ${Const.MAX_REMOTE_PATH_LENGTH} bytes" + } } } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/abb/AbbExecRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/abb/AbbExecRequest.kt index 8e4841446..b037160c4 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/abb/AbbExecRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/abb/AbbExecRequest.kt @@ -26,7 +26,10 @@ import com.malinskiy.adam.transport.Socket import com.malinskiy.adam.transport.withDefaultBuffer @Features(Feature.ABB_EXEC) -open class AbbExecRequest(private val args: List, private val supportedFeatures: List) : ComplexRequest() { +public open class AbbExecRequest( + private val args: List, + private val supportedFeatures: List, +) : ComplexRequest() { private val transformer = StringResponseTransformer() override suspend fun readElement(socket: Socket): String { @@ -36,7 +39,7 @@ open class AbbExecRequest(private val args: List, private val supportedF return transformer.transform() } - override fun serialize() = createBaseRequest("abb_exec:${args.joinToString(DELIMITER.toString())}") + override fun serialize(): ByteArray = createBaseRequest("abb_exec:${args.joinToString(DELIMITER.toString())}") override fun validate(): ValidationResponse { val response = super.validate() @@ -49,7 +52,7 @@ open class AbbExecRequest(private val args: List, private val supportedF } } - companion object { - const val DELIMITER = 0x00.toChar() + public companion object { + public const val DELIMITER: Char = 0x00.toChar() } } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/abb/AbbRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/abb/AbbRequest.kt index 81b1ac5f6..d9edda918 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/abb/AbbRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/abb/AbbRequest.kt @@ -24,10 +24,10 @@ import com.malinskiy.adam.request.shell.v2.ShellCommandResult import com.malinskiy.adam.request.shell.v2.SyncShellCommandRequest @Features(Feature.ABB) -class AbbRequest(private val args: List, private val supportedFeatures: List) : +public class AbbRequest(private val args: List, private val supportedFeatures: List) : SyncShellCommandRequest("") { - override fun serialize() = createBaseRequest("abb:${args.joinToString(DELIMITER.toString())}") - override fun convertResult(response: ShellCommandResult) = response + override fun serialize(): ByteArray = createBaseRequest("abb:${args.joinToString(DELIMITER.toString())}") + override fun convertResult(response: ShellCommandResult): ShellCommandResult = response override fun validate(): ValidationResponse { val response = super.validate() return if (!response.success) { diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/adbd/AdbdMode.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/adbd/AdbdMode.kt index 19008c6b7..9b671bff1 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/adbd/AdbdMode.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/adbd/AdbdMode.kt @@ -16,8 +16,8 @@ package com.malinskiy.adam.request.adbd -sealed class AdbdMode(val requestString: String) -object RootAdbdMode : AdbdMode("root:") -object UnrootAdbdMode : AdbdMode("unroot:") -object UsbAdbdMode : AdbdMode("usb:") -class TcpIpAdbdMode(port: Int) : AdbdMode("tcpip:$port") +public sealed class AdbdMode(public val requestString: String) +public object RootAdbdMode : AdbdMode("root:") +public object UnrootAdbdMode : AdbdMode("unroot:") +public object UsbAdbdMode : AdbdMode("usb:") +public class TcpIpAdbdMode(port: Int) : AdbdMode("tcpip:$port") diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/adbd/RestartAdbdRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/adbd/RestartAdbdRequest.kt index fef2aaabb..6e2621ed6 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/adbd/RestartAdbdRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/adbd/RestartAdbdRequest.kt @@ -19,12 +19,16 @@ package com.malinskiy.adam.request.adbd import com.malinskiy.adam.request.SynchronousRequest import com.malinskiy.adam.request.transform.StringResponseTransformer -class RestartAdbdRequest(private val mode: AdbdMode) : SynchronousRequest() { +public class RestartAdbdRequest(private val mode: AdbdMode) : SynchronousRequest() { private val transformer = StringResponseTransformer() - override suspend fun process(bytes: ByteArray, offset: Int, limit: Int) = transformer.process(bytes, offset, limit) + override suspend fun process(bytes: ByteArray, offset: Int, limit: Int): Unit = transformer.process( + bytes, + offset, + limit, + ) - override fun serialize() = createBaseRequest(mode.requestString) + override fun serialize(): ByteArray = createBaseRequest(mode.requestString) - override fun transform() = transformer.transform() + override fun transform(): String = transformer.transform() } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/device/AsyncDeviceMonitorRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/device/AsyncDeviceMonitorRequest.kt index f0f8604b3..431fc6167 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/device/AsyncDeviceMonitorRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/device/AsyncDeviceMonitorRequest.kt @@ -22,7 +22,10 @@ import com.malinskiy.adam.request.HostTarget import com.malinskiy.adam.transport.Socket import kotlinx.coroutines.channels.SendChannel -class AsyncDeviceMonitorRequest : AsyncChannelRequest, Unit>(target = HostTarget, socketIdleTimeout = Long.MAX_VALUE) { +public class AsyncDeviceMonitorRequest : AsyncChannelRequest, Unit>( + target = HostTarget, + socketIdleTimeout = Long.MAX_VALUE, +) { override suspend fun readElement(socket: Socket, sendChannel: SendChannel>): Boolean { val data = socket.readProtocolString() @@ -34,13 +37,13 @@ class AsyncDeviceMonitorRequest : AsyncChannelRequest, Unit>(target val split = line.split("\t") Device( serial = split[0], - state = DeviceState.from(split[1]) + state = DeviceState.from(split[1]), ) - } + }, ) return false } - override fun serialize() = createBaseRequest("track-devices") - override suspend fun writeElement(element: Unit, socket: Socket) = Unit + override fun serialize(): ByteArray = createBaseRequest("track-devices") + override suspend fun writeElement(element: Unit, socket: Socket): Unit = Unit } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/device/FetchDeviceFeaturesRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/device/FetchDeviceFeaturesRequest.kt index 57fdb8a1d..2276d3914 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/device/FetchDeviceFeaturesRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/device/FetchDeviceFeaturesRequest.kt @@ -22,9 +22,9 @@ import com.malinskiy.adam.request.Feature import com.malinskiy.adam.request.SerialTarget import com.malinskiy.adam.transport.Socket -class FetchDeviceFeaturesRequest(serial: String) : ComplexRequest>(target = SerialTarget(serial)) { +public class FetchDeviceFeaturesRequest(serial: String) : ComplexRequest>(target = SerialTarget(serial)) { - override fun serialize() = createBaseRequest("features") + override fun serialize(): ByteArray = createBaseRequest("features") override suspend fun readElement(socket: Socket): List { return socket.readProtocolString().split(',').mapNotNull { Feature.of(it) } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/device/ListDevicesRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/device/ListDevicesRequest.kt index fedbfb9fc..5eecae881 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/device/ListDevicesRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/device/ListDevicesRequest.kt @@ -21,8 +21,8 @@ import com.malinskiy.adam.request.ComplexRequest import com.malinskiy.adam.request.HostTarget import com.malinskiy.adam.transport.Socket -class ListDevicesRequest : ComplexRequest>(target = HostTarget) { - override fun serialize() = createBaseRequest("devices") +public class ListDevicesRequest : ComplexRequest>(target = HostTarget) { + override fun serialize(): ByteArray = createBaseRequest("devices") override suspend fun readElement(socket: Socket): List { return socket.readProtocolString().lines() @@ -32,15 +32,15 @@ class ListDevicesRequest : ComplexRequest>(target = HostTarget) { val split = line.split("\t") Device( serial = split[0], - state = DeviceState.from(split[1]) + state = DeviceState.from(split[1]), ) } } } -data class Device(val serial: String, val state: DeviceState) +public data class Device(public val serial: String, public val state: DeviceState) -enum class DeviceState { +public enum class DeviceState { OFFLINE, BOOTLOADER, DEVICE, @@ -51,10 +51,11 @@ enum class DeviceState { UNAUTHORIZED, AUTHORIZING, CONNECTING, - UNKNOWN; + UNKNOWN, + ; - companion object { - fun from(value: String) = + public companion object { + public fun from(value: String): DeviceState = when (value) { "offline" -> OFFLINE "bootloader" -> BOOTLOADER diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/emu/EmulatorCommandRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/emu/EmulatorCommandRequest.kt index 5a58b04bb..71ddbc6e0 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/emu/EmulatorCommandRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/emu/EmulatorCommandRequest.kt @@ -38,12 +38,12 @@ import java.net.InetSocketAddress * @param cleanResponse by default all responses contain the emulator auth output that is unnecessary. If you want the output to include * everything the emulator returns - set this to false */ -class EmulatorCommandRequest( +public class EmulatorCommandRequest( private val cmd: String, - val address: InetSocketAddress, + public val address: InetSocketAddress, private val authToken: String? = null, private val cleanResponse: Boolean = true, - val idleTimeoutOverride: Long? = null + public val idleTimeoutOverride: Long? = null, ) { private suspend fun readAuthToken(): String? { val authTokenFile = File(System.getProperty("user.home"), ".emulator_console_auth_token") @@ -59,7 +59,7 @@ class EmulatorCommandRequest( } } - suspend fun process(socket: Socket): String { + public suspend fun process(socket: Socket): String { val sessionBuilder = StringBuilder() val token = authToken ?: readAuthToken() ?: "" if (token.isNotEmpty()) { @@ -81,6 +81,7 @@ class EmulatorCommandRequest( count == 0 -> { continue@loop } + count > 0 -> { output.append(String(buffer, 0, count, Charsets.UTF_8)) } @@ -94,6 +95,7 @@ class EmulatorCommandRequest( * Additional confirmation of auth */ token.isNotBlank() -> output.indexOf(OUTPUT_DELIMITER, firstOkPosition + 1) + else -> firstOkPosition } @@ -105,7 +107,7 @@ class EmulatorCommandRequest( } } - companion object { + public companion object { /** * Note: the following messages are expected to be quite stable from emulator. * Emulator console will send the following message upon connection: @@ -123,6 +125,6 @@ class EmulatorCommandRequest( * So we try to search and skip first two "OK\r\n", return the rest. * */ - const val OUTPUT_DELIMITER: String = "OK\r\n" + public const val OUTPUT_DELIMITER: String = "OK\r\n" } } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/file/ListFilesRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/file/ListFilesRequest.kt index 9e5395496..a751896ee 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/file/ListFilesRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/file/ListFilesRequest.kt @@ -19,18 +19,19 @@ package com.malinskiy.adam.request.sync import com.malinskiy.adam.request.shell.v1.ShellCommandResult import com.malinskiy.adam.request.shell.v1.SyncShellCommandRequest - -class ListFilesRequest(private val directory: String) : SyncShellCommandRequest>( - cmd = "ls -l $directory" +public class ListFilesRequest(private val directory: String) : SyncShellCommandRequest>( + cmd = "ls -l $directory", ) { - private val lslRegex: Regex = ("^([bcdlsp-][-r][-w][-xsS][-r][-w][-xsS][-r][-w][-xstST])\\s+" + //permissions - "(?:\\d+\\s+)?" + //nlink - "(\\S+)\\s+" + //user - "(\\S+)\\s+" + //group - "([\\d\\s,]*)\\s+" + //size - "(\\d{4}-\\d\\d-\\d\\d)\\s+" + //date - "(\\d\\d:\\d\\d)\\s+" + //time - "(.*)$").toRegex() // + private val lslRegex: Regex = ( + "^([bcdlsp-][-r][-w][-xsS][-r][-w][-xsS][-r][-w][-xstST])\\s+" + // permissions + "(?:\\d+\\s+)?" + // nlink + "(\\S+)\\s+" + // user + "(\\S+)\\s+" + // group + "([\\d\\s,]*)\\s+" + // size + "(\\d{4}-\\d\\d-\\d\\d)\\s+" + // date + "(\\d\\d:\\d\\d)\\s+" + // time + "(.*)$" + ).toRegex() // override fun convertResult(response: ShellCommandResult): List { return response.output @@ -77,13 +78,13 @@ class ListFilesRequest(private val directory: String) : SyncShellCommandRequest< name = name, directory = directory, type = type, - link = link + link = link, ) } } } -enum class AndroidFileType { +public enum class AndroidFileType { REGULAR_FILE, DIRECTORY, BLOCK_SPECIAL_FILE, @@ -106,15 +107,15 @@ enum class AndroidFileType { * @property type file's type * @property link if the file is a symbolic link, this field is what the link points to */ -data class AndroidFile( - val permissions: String, - val owner: String, - val group: String, - val date: String, - val time: String, - val name: String, - val directory: String, - val size: Long, - val type: AndroidFileType, - val link: String? = null +public data class AndroidFile( + public val permissions: String, + public val owner: String, + public val group: String, + public val date: String, + public val time: String, + public val name: String, + public val directory: String, + public val size: Long, + public val type: AndroidFileType, + public val link: String? = null, ) diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/forwarding/ListPortForwardsRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/forwarding/ListPortForwardsRequest.kt index ace551099..3ab407d6c 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/forwarding/ListPortForwardsRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/forwarding/ListPortForwardsRequest.kt @@ -21,7 +21,9 @@ import com.malinskiy.adam.request.ComplexRequest import com.malinskiy.adam.request.SerialTarget import com.malinskiy.adam.transport.Socket -class ListPortForwardsRequest(serial: String) : ComplexRequest>(target = SerialTarget(serial)) { +public class ListPortForwardsRequest(serial: String) : ComplexRequest>( + target = SerialTarget(serial), +) { override suspend fun readElement(socket: Socket): List { return socket.readProtocolString().lines().mapNotNull { line -> if (line.isNotEmpty()) { @@ -29,7 +31,7 @@ class ListPortForwardsRequest(serial: String) : ComplexRequest(target = SerialTarget(serial)) { - override fun serialize() = + override fun serialize(): ByteArray = createBaseRequest("forward${mode.value}:${local.toSpec()};${remote.toSpec()}") override suspend fun readElement(socket: Socket): Int? { @@ -47,7 +47,7 @@ class PortForwardRequest( } } -enum class PortForwardingMode(val value: String) { +public enum class PortForwardingMode(public val value: String) { DEFAULT(""), - NO_REBIND(":norebind") + NO_REBIND(":norebind"), } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/forwarding/PortForwardingRule.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/forwarding/PortForwardingRule.kt index dbb93e424..d7dff29f4 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/forwarding/PortForwardingRule.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/forwarding/PortForwardingRule.kt @@ -16,8 +16,8 @@ package com.malinskiy.adam.request.forwarding -data class PortForwardingRule( - val serial: String, - val localSpec: LocalPortSpec, - val remoteSpec: RemotePortSpec -) \ No newline at end of file +public data class PortForwardingRule( + public val serial: String, + public val localSpec: LocalPortSpec, + public val remoteSpec: RemotePortSpec, +) diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/forwarding/RemotePortSpec.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/forwarding/RemotePortSpec.kt index 11fa53407..621944718 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/forwarding/RemotePortSpec.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/forwarding/RemotePortSpec.kt @@ -18,11 +18,11 @@ package com.malinskiy.adam.request.forwarding import com.malinskiy.adam.exception.UnsupportedForwardingSpecException -sealed class RemotePortSpec { - abstract fun toSpec(): String +public sealed class RemotePortSpec { + public abstract fun toSpec(): String - companion object { - fun parse(value: String): RemotePortSpec { + public companion object { + public fun parse(value: String): RemotePortSpec { val split = value.split(':') val type = split[0] return when (type) { @@ -38,26 +38,26 @@ sealed class RemotePortSpec { } } -data class RemoteTcpPortSpec(val port: Int) : RemotePortSpec() { - override fun toSpec() = "tcp:$port" +public data class RemoteTcpPortSpec(public val port: Int) : RemotePortSpec() { + override fun toSpec(): String = "tcp:$port" } -data class RemoteAbstractPortSpec(val unixDomainSocketName: String) : RemotePortSpec() { - override fun toSpec() = "localabstract:$unixDomainSocketName" +public data class RemoteAbstractPortSpec(public val unixDomainSocketName: String) : RemotePortSpec() { + override fun toSpec(): String = "localabstract:$unixDomainSocketName" } -data class RemoteReservedPortSpec(val unixDomainSocketName: String) : RemotePortSpec() { - override fun toSpec() = "localreserved:$unixDomainSocketName" +public data class RemoteReservedPortSpec(public val unixDomainSocketName: String) : RemotePortSpec() { + override fun toSpec(): String = "localreserved:$unixDomainSocketName" } -data class RemoteFilesystemPortSpec(val unixDomainSocketName: String) : RemotePortSpec() { - override fun toSpec() = "localfilesystem:$unixDomainSocketName" +public data class RemoteFilesystemPortSpec(public val unixDomainSocketName: String) : RemotePortSpec() { + override fun toSpec(): String = "localfilesystem:$unixDomainSocketName" } -data class RemoteDevPortSpec(val charDeviceName: String) : RemotePortSpec() { - override fun toSpec() = "dev:$charDeviceName" +public data class RemoteDevPortSpec(public val charDeviceName: String) : RemotePortSpec() { + override fun toSpec(): String = "dev:$charDeviceName" } -data class JDWPPortSpec(val processId: Int) : RemotePortSpec() { - override fun toSpec() = "jdwp:$processId" +public data class JDWPPortSpec(public val processId: Int) : RemotePortSpec() { + override fun toSpec(): String = "jdwp:$processId" } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/forwarding/RemoveAllPortForwardsRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/forwarding/RemoveAllPortForwardsRequest.kt index fe59a0a4c..498399af1 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/forwarding/RemoveAllPortForwardsRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/forwarding/RemoveAllPortForwardsRequest.kt @@ -19,10 +19,10 @@ package com.malinskiy.adam.request.forwarding import com.malinskiy.adam.request.SerialTarget import com.malinskiy.adam.request.SynchronousRequest -class RemoveAllPortForwardsRequest(serial: String) : SynchronousRequest(target = SerialTarget(serial)) { - override fun serialize() = createBaseRequest("killforward-all") +public class RemoveAllPortForwardsRequest(serial: String) : SynchronousRequest(target = SerialTarget(serial)) { + override fun serialize(): ByteArray = createBaseRequest("killforward-all") - override suspend fun process(bytes: ByteArray, offset: Int, limit: Int) = Unit + override suspend fun process(bytes: ByteArray, offset: Int, limit: Int): Unit = Unit - override fun transform() = Unit -} \ No newline at end of file + override fun transform(): Unit = Unit +} diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/forwarding/RemovePortForwardRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/forwarding/RemovePortForwardRequest.kt index d53a4ac4d..53c870b98 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/forwarding/RemovePortForwardRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/forwarding/RemovePortForwardRequest.kt @@ -19,14 +19,14 @@ package com.malinskiy.adam.request.forwarding import com.malinskiy.adam.request.SerialTarget import com.malinskiy.adam.request.SynchronousRequest -class RemovePortForwardRequest( +public class RemovePortForwardRequest( private val local: LocalTcpPortSpec, - serial: String + serial: String, ) : SynchronousRequest(target = SerialTarget(serial)) { - override fun serialize() = + override fun serialize(): ByteArray = createBaseRequest("killforward:${local.toSpec()}") - override suspend fun process(bytes: ByteArray, offset: Int, limit: Int) = Unit + override suspend fun process(bytes: ByteArray, offset: Int, limit: Int): Unit = Unit - override fun transform() = Unit + override fun transform(): Unit = Unit } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/framebuffer/BufferedImageScreenCaptureAdapter.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/framebuffer/BufferedImageScreenCaptureAdapter.kt index 2ef7d69fe..19645c043 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/framebuffer/BufferedImageScreenCaptureAdapter.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/framebuffer/BufferedImageScreenCaptureAdapter.kt @@ -21,10 +21,10 @@ import com.malinskiy.adam.transport.Socket import java.awt.image.BufferedImage import java.nio.ByteBuffer -class BufferedImageScreenCaptureAdapter( +public class BufferedImageScreenCaptureAdapter( private var recycledImage: BufferedImage? = null, buffer: ByteBuffer? = null, - colorModelFactory: ColorModelFactory = ColorModelFactory() + colorModelFactory: ColorModelFactory = ColorModelFactory(), ) : ScreenCaptureAdapter(colorModelFactory = colorModelFactory, buffer = buffer) { override suspend fun process( @@ -42,7 +42,7 @@ class BufferedImageScreenCaptureAdapter( alphaOffset: Int, alphaLength: Int, colorSpace: ColorSpace?, - socket: Socket + socket: Socket, ): BufferedImage { val imageBuffer: ByteBuffer = read(socket, size) imageBuffer.compatRewind() @@ -53,10 +53,15 @@ class BufferedImageScreenCaptureAdapter( val shortArray = ShortArray(imageBuffer.limit() / 2) imageBuffer.asShortBuffer().get(shortArray) it.raster.setDataElements( - 0, 0, width, height, shortArray + 0, + 0, + width, + height, + shortArray, ) } } + 32 -> { if (alphaOffset == 24 && alphaLength == 8 && blueOffset == 16 && blueLength == 8 && @@ -69,7 +74,11 @@ class BufferedImageScreenCaptureAdapter( createOrReuseBufferedImage(colorSpace, width, height, BufferedImage.TYPE_4BYTE_ABGR) .also { it.raster.setDataElements( - 0, 0, width, height, imageBuffer.array() + 0, + 0, + width, + height, + imageBuffer.array(), ) } } else { @@ -86,7 +95,7 @@ class BufferedImageScreenCaptureAdapter( blueOffset, blueLength, alphaOffset, - alphaLength + alphaLength, ) it.raster.setDataElements(x, y, bytes) } @@ -94,7 +103,10 @@ class BufferedImageScreenCaptureAdapter( } } } - else -> throw UnsupportedOperationException("BufferedImageScreenCaptureAdapter only works with 16 and 32 bit images") + + else -> throw UnsupportedOperationException( + "BufferedImageScreenCaptureAdapter only works with 16 and 32 bit images", + ) } } @@ -102,7 +114,7 @@ class BufferedImageScreenCaptureAdapter( colorSpace: ColorSpace?, width: Int, height: Int, - type: Int + type: Int, ): BufferedImage { val bufferedImage = when (val profileName = colorSpace?.getProfileName()) { null -> { @@ -117,6 +129,7 @@ class BufferedImageScreenCaptureAdapter( BufferedImage(width, height, type) } } + else -> { val colorModel = colorModelFactory.get(profileName, type) val localRecycledImage = recycledImage diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/framebuffer/Color.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/framebuffer/Color.kt index 161b7bd15..7f1dc8eec 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/framebuffer/Color.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/framebuffer/Color.kt @@ -14,13 +14,15 @@ * limitations under the License. */ +@file:Suppress("ktlint:standard:class-naming", "ktlint:standard:function-naming") + package com.malinskiy.adam.request.framebuffer import kotlin.math.roundToInt -object Color { - object RGB565_2BYTE { - fun toARGB8888_INT(first: Byte, second: Byte): Int { +public object Color { + public object RGB565_2BYTE { + public fun toARGB8888_INT(first: Byte, second: Byte): Int { var value = first.toInt() and 0x00FF value = value or (second.toInt() shl 8 and 0x0FF00) // Multiply by 255/31 to convert from 5 bits (31 max) to 8 bits (255) @@ -33,8 +35,8 @@ object Color { } } - object ARGB_INT { - fun toARGB8888_INT( + public object ARGB_INT { + public fun toARGB8888_INT( value: Int, redOffset: Int, redLength: Int, @@ -43,7 +45,7 @@ object Color { blueOffset: Int, blueLength: Int, alphaOffset: Int, - alphaLength: Int + alphaLength: Int, ): Int { val r = value.ushr(redOffset) and getMask(redLength) shl 8 - redLength val g = value.ushr(greenOffset) and getMask(greenLength) shl 8 - greenLength @@ -53,7 +55,7 @@ object Color { return a shl 24 or (r shl 16) or (g shl 8) or b } - fun toBGR_3BYTE( + public fun toBGR_3BYTE( value: Int, redOffset: Int, redLength: Int, @@ -62,7 +64,7 @@ object Color { blueOffset: Int, blueLength: Int, alphaOffset: Int, - alphaLength: Int + alphaLength: Int, ): ByteArray { val r = (value.ushr(redOffset) and getMask(redLength)) xshl (8 - redLength) val g = (value.ushr(greenOffset) and getMask(greenLength)) xshl (8 - greenLength) @@ -76,7 +78,7 @@ object Color { return byteArrayOf( (r * alphaMultiplier).roundToInt().toByte(), (g * alphaMultiplier).roundToInt().toByte(), - (b * alphaMultiplier).roundToInt().toByte() + (b * alphaMultiplier).roundToInt().toByte(), ) } } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/framebuffer/ColorModelFactory.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/framebuffer/ColorModelFactory.kt index c7d5f532a..b477e778f 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/framebuffer/ColorModelFactory.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/framebuffer/ColorModelFactory.kt @@ -26,10 +26,10 @@ import java.awt.image.DataBuffer import java.awt.image.DirectColorModel import java.io.IOException -class ColorModelFactory { +public class ColorModelFactory { private val cache = mutableMapOf() - fun get(profileName: String, type: Int): ColorModel { + public fun get(profileName: String, type: Int): ColorModel { cache[profileName]?.let { return it } synchronized(cache) { @@ -48,18 +48,20 @@ class ColorModelFactory { true, false, Transparency.TRANSLUCENT, - DataBuffer.TYPE_BYTE + DataBuffer.TYPE_BYTE, ) } + BufferedImage.TYPE_3BYTE_BGR -> { ComponentColorModel( colorSpace, false, false, Transparency.TRANSLUCENT, - DataBuffer.TYPE_BYTE + DataBuffer.TYPE_BYTE, ) } + BufferedImage.TYPE_INT_ARGB -> { DirectColorModel( colorSpace, @@ -69,14 +71,13 @@ class ColorModelFactory { 0x000000ff, -0x1000000, false, - DataBuffer.TYPE_INT + DataBuffer.TYPE_INT, ) } + else -> throw RuntimeException("Unsupported buffered image type $type") } return colorModel.also { cache[profileName] = it } } } - - } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/framebuffer/ColorSpace.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/framebuffer/ColorSpace.kt index 7df8f0f3a..e9216822c 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/framebuffer/ColorSpace.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/framebuffer/ColorSpace.kt @@ -16,19 +16,20 @@ package com.malinskiy.adam.request.framebuffer -enum class ColorSpace { +public enum class ColorSpace { UNKNOWN, SRGB, - P3; + P3, + ; - fun getProfileName(): String? = when (this) { + public fun getProfileName(): String? = when (this) { UNKNOWN -> null SRGB -> "sRGB.icc" P3 -> "DisplayP3.icc" } - companion object { - fun from(value: Int) = when (value) { + public companion object { + public fun from(value: Int): ColorSpace = when (value) { 1 -> SRGB 2 -> P3 else -> UNKNOWN diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/framebuffer/RawImage.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/framebuffer/RawImage.kt index d9b5833ec..cd7004812 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/framebuffer/RawImage.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/framebuffer/RawImage.kt @@ -18,34 +18,34 @@ package com.malinskiy.adam.request.framebuffer import java.awt.image.BufferedImage - -data class RawImage( - val version: Int, - val bitsPerPixel: Int, - val colorSpace: ColorSpace? = null, - val size: Int, - val width: Int, - val height: Int, - val redOffset: Int, - val redLength: Int, - val blueOffset: Int, - val blueLength: Int, - val greenOffset: Int, - val greenLength: Int, - val alphaOffset: Int, - val alphaLength: Int, - val buffer: ByteArray +public data class RawImage( + public val version: Int, + public val bitsPerPixel: Int, + public val colorSpace: ColorSpace? = null, + public val size: Int, + public val width: Int, + public val height: Int, + public val redOffset: Int, + public val redLength: Int, + public val blueOffset: Int, + public val blueLength: Int, + public val greenOffset: Int, + public val greenLength: Int, + public val alphaOffset: Int, + public val alphaLength: Int, + public val buffer: ByteArray, ) { - fun getARGB(index: Int): Int { + public fun getARGB(index: Int): Int { return when (bitsPerPixel) { 16 -> { Color.RGB565_2BYTE.toARGB8888_INT(buffer[index], buffer[index + 1]) } + 32 -> { val value = (buffer[index].toInt() and 0x00FF) or - (buffer[index + 1].toInt() and 0x00FF shl 8) or - (buffer[index + 2].toInt() and 0x00FF shl 16) or - (buffer[index + 3].toInt() and 0x00FF shl 24) + (buffer[index + 1].toInt() and 0x00FF shl 8) or + (buffer[index + 2].toInt() and 0x00FF shl 16) or + (buffer[index + 3].toInt() and 0x00FF shl 24) Color.ARGB_INT.toARGB8888_INT( value = value, redOffset = redOffset, @@ -55,9 +55,10 @@ data class RawImage( blueOffset = blueOffset, blueLength = blueLength, alphaOffset = alphaOffset, - alphaLength = alphaLength + alphaLength = alphaLength, ) } + else -> { throw UnsupportedOperationException("RawImage.getARGB(int) only works in 16 and 32 bit mode.") } @@ -67,11 +68,12 @@ data class RawImage( /** * @return TYPE_INT_ARGB buffered image */ - fun toBufferedImage(): BufferedImage { + public fun toBufferedImage(): BufferedImage { val bufferedImage = when (val profileName = colorSpace?.getProfileName()) { null -> { BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB) } + else -> { val colorModel = ColorModelFactory().get(profileName, BufferedImage.TYPE_INT_ARGB) val raster = colorModel.createCompatibleWritableRaster(width, height) @@ -89,4 +91,3 @@ data class RawImage( return bufferedImage } } - diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/framebuffer/RawImageScreenCaptureAdapter.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/framebuffer/RawImageScreenCaptureAdapter.kt index 291a31ffc..9f827f099 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/framebuffer/RawImageScreenCaptureAdapter.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/framebuffer/RawImageScreenCaptureAdapter.kt @@ -19,7 +19,9 @@ package com.malinskiy.adam.request.framebuffer import com.malinskiy.adam.transport.Socket import java.nio.ByteBuffer -class RawImageScreenCaptureAdapter(buffer: ByteBuffer? = null) : ScreenCaptureAdapter(buffer = buffer) { +public class RawImageScreenCaptureAdapter(buffer: ByteBuffer? = null) : ScreenCaptureAdapter( + buffer = buffer, +) { override suspend fun process( version: Int, @@ -36,7 +38,7 @@ class RawImageScreenCaptureAdapter(buffer: ByteBuffer? = null) : ScreenCaptureAd alphaOffset: Int, alphaLength: Int, colorSpace: ColorSpace?, - socket: Socket + socket: Socket, ): RawImage { val imageBuffer = read(socket, size) @@ -55,7 +57,7 @@ class RawImageScreenCaptureAdapter(buffer: ByteBuffer? = null) : ScreenCaptureAd blueLength = blueLength, alphaOffset = alphaOffset, alphaLength = alphaLength, - buffer = imageBuffer.array() + buffer = imageBuffer.array(), ) } } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/framebuffer/ScreenCaptureAdapter.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/framebuffer/ScreenCaptureAdapter.kt index 07e000aa1..c62032ded 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/framebuffer/ScreenCaptureAdapter.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/framebuffer/ScreenCaptureAdapter.kt @@ -27,11 +27,11 @@ import java.nio.ByteBuffer * @param buffer consider reusing the buffer between screencapture requests to reduce heap memory pressure * @param colorModelFactory reuse the color models required for image conversion */ -abstract class ScreenCaptureAdapter( +public abstract class ScreenCaptureAdapter( private var buffer: ByteBuffer? = null, - protected val colorModelFactory: ColorModelFactory = ColorModelFactory() + protected val colorModelFactory: ColorModelFactory = ColorModelFactory(), ) { - suspend fun read(socket: Socket, size: Int): ByteBuffer { + public suspend fun read(socket: Socket, size: Int): ByteBuffer { val localBuffer = buffer val imageBuffer = if (localBuffer != null && localBuffer.capacity() == size) { @@ -46,7 +46,7 @@ abstract class ScreenCaptureAdapter( return imageBuffer } - abstract suspend fun process( + public abstract suspend fun process( version: Int, bitsPerPixel: Int, size: Int, @@ -61,6 +61,6 @@ abstract class ScreenCaptureAdapter( alphaOffset: Int, alphaLength: Int, colorSpace: ColorSpace? = null, - socket: Socket + socket: Socket, ): T } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/framebuffer/ScreenCaptureRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/framebuffer/ScreenCaptureRequest.kt index 024b157e2..8d982f329 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/framebuffer/ScreenCaptureRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/framebuffer/ScreenCaptureRequest.kt @@ -26,7 +26,7 @@ import com.malinskiy.adam.transport.Socket import com.malinskiy.adam.transport.withDefaultBuffer import java.nio.ByteOrder -class ScreenCaptureRequest(private val adapter: ScreenCaptureAdapter) : ComplexRequest() { +public class ScreenCaptureRequest(private val adapter: ScreenCaptureAdapter) : ComplexRequest() { override suspend fun readElement(socket: Socket): T { withDefaultBuffer { compatLimit(4) @@ -35,9 +35,15 @@ class ScreenCaptureRequest(private val adapter: ScreenCaptureAdapter) : Co val protocolVersion = order(ByteOrder.LITTLE_ENDIAN).int val headerSize = when (protocolVersion) { - 1 -> 12 // bpp, size, width, height, 4*(length, offset) - 2 -> 13 // bpp, colorSpace, size, width, height, 4*(length, offset) - 16 -> 3 // compatibility mode: size, width, height. used previously to denote framebuffer depth + // bpp, size, width, height, 4*(length, offset) + 1 -> 12 + + // bpp, colorSpace, size, width, height, 4*(length, offset) + 2 -> 13 + + // compatibility mode: size, width, height. used previously to denote framebuffer depth + 16 -> 3 + /** * See https://android.googlesource.com/platform/packages/modules/adb/+/refs/heads/master/daemon/framebuffer_service.cpp#42 * for a possible new value for DDMS_RAWIMAGE_VERSION @@ -66,8 +72,9 @@ class ScreenCaptureRequest(private val adapter: ScreenCaptureAdapter) : Co blueLength = 5, alphaOffset = 0, alphaLength = 0, - socket = socket + socket = socket, ) + 1 -> adapter.process( version = protocolVersion, bitsPerPixel = int, @@ -82,8 +89,9 @@ class ScreenCaptureRequest(private val adapter: ScreenCaptureAdapter) : Co greenLength = int, alphaOffset = int, alphaLength = int, - socket = socket + socket = socket, ) + 2 -> adapter.process( version = protocolVersion, bitsPerPixel = int, @@ -99,12 +107,13 @@ class ScreenCaptureRequest(private val adapter: ScreenCaptureAdapter) : Co greenLength = int, alphaOffset = int, alphaLength = int, - socket = socket + socket = socket, ) + else -> throw UnsupportedImageProtocolException(protocolVersion) } } } - override fun serialize() = createBaseRequest("framebuffer:") + override fun serialize(): ByteArray = createBaseRequest("framebuffer:") } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/logcat/ChanneledLogcatRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/logcat/ChanneledLogcatRequest.kt index 5ba239e77..3698f9818 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/logcat/ChanneledLogcatRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/logcat/ChanneledLogcatRequest.kt @@ -18,32 +18,35 @@ package com.malinskiy.adam.request.logcat import com.malinskiy.adam.request.shell.v1.ChanneledShellCommandRequest -class ChanneledLogcatRequest( +public class ChanneledLogcatRequest( since: LogcatSinceFormat? = null, modes: List = listOf(LogcatReadMode.long), buffers: List = emptyList(), pid: Long? = null, lastReboot: Boolean? = null, - filters: List = emptyList() + filters: List = emptyList(), ) : ChanneledShellCommandRequest( cmd = "logcat" + - (since?.let { + ( + since?.let { " -T ${since.text}" - } ?: "") + - " ${modes.joinToString(separator = " ") { "-v $it" }}" + - if (buffers.isNotEmpty()) { - " ${buffers.joinToString(separator = " ") { "-b $it" }}" - } else { - "" - } + - "${pid?.let { " --pid=$it" } ?: ""}" + - "${lastReboot?.let { " -L" } ?: ""}" + - " ${filters.joinToString(separator = " ") { "${it.tag}:${it.level.name}" }}" - .trimEnd(), + } ?: "" + ) + + " ${modes.joinToString(separator = " ") { "-v $it" }}" + + if (buffers.isNotEmpty()) { + " ${buffers.joinToString(separator = " ") { "-b $it" }}" + } else { + "" + } + + "${pid?.let { " --pid=$it" } ?: ""}" + + "${lastReboot?.let { " -L" } ?: ""}" + + " ${filters.joinToString(separator = " ") { "${it.tag}:${it.level.name}" }}" + .trimEnd(), socketIdleTimeout = Long.MAX_VALUE, ) -enum class LogcatReadMode { +@Suppress("ktlint:standard:enum-entry-name-case") +public enum class LogcatReadMode { brief, long, process, @@ -53,70 +56,75 @@ enum class LogcatReadMode { threadtime, time, - //Show log buffer event descriptions. This modifier affects event log buffer messages only, and has no effect on the other non-binary buffers. The event descriptions come from the event-log-tags database. + // Show log buffer event descriptions. This modifier affects event log buffer messages only, and has no effect on the other non-binary buffers. The event descriptions come from the event-log-tags database. descriptive, - //Show each priority level with a different color + // Show each priority level with a different color color, - //Display time in seconds starting from Jan 1, 1970 + // Display time in seconds starting from Jan 1, 1970 epoch, - //Display time in CPU seconds starting from the last boot + // Display time in CPU seconds starting from the last boot monotonic, - //Ensure that any binary logging content is escaped + // Ensure that any binary logging content is escaped printable, - //If permitted by access controls, display the UID or Android ID of the logged process + // If permitted by access controls, display the UID or Android ID of the logged process uid, - //Display the time with precision down to microseconds + // Display the time with precision down to microseconds usec, - //Display time as UTC + // Display time as UTC UTC, - //Add the year to the displayed time + // Add the year to the displayed time year, - //Add the local time zone to the displayed time - zone + // Add the local time zone to the displayed time + zone, } -enum class LogcatBuffer { - //View the buffer that contains radio/telephony related messages +@Suppress("ktlint:standard:enum-entry-name-case") +public enum class LogcatBuffer { + // View the buffer that contains radio/telephony related messages radio, - //View the interpreted binary system event buffer messages + // View the interpreted binary system event buffer messages events, - //View the main log buffer (default) does not contain system and crash log messages + // View the main log buffer (default) does not contain system and crash log messages main, - //View the system log buffer (default) + // View the system log buffer (default) system, - //View the crash log buffer (default) + // View the crash log buffer (default) crash, - //View all buffers + // View all buffers all, - //Reports main, system, and crash buffers - default + // Reports main, system, and crash buffers + default, } -enum class LogcatVerbosityLevel { +public enum class LogcatVerbosityLevel { V, D, I, W, E, F, - S + S, } -data class LogcatFilterSpec(val tag: String, val level: LogcatVerbosityLevel) +public data class LogcatFilterSpec(public val tag: String, public val level: LogcatVerbosityLevel) -val SupressAll = LogcatFilterSpec("*", LogcatVerbosityLevel.S) +public val suppressAll: LogcatFilterSpec = LogcatFilterSpec("*", LogcatVerbosityLevel.S) + +@Deprecated("Use suppressAll", ReplaceWith("suppressAll")) +@Suppress("ktlint:standard:property-naming") +public val SupressAll: LogcatFilterSpec = suppressAll diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/logcat/LogcatSinceFormat.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/logcat/LogcatSinceFormat.kt index fbce4f2de..3bd7d170b 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/logcat/LogcatSinceFormat.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/logcat/LogcatSinceFormat.kt @@ -25,16 +25,16 @@ private val sinceFormatter = DateTimeFormatter.ofPattern("MM-dd HH:mm:ss.SSS") private val sinceYearFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS") -sealed class LogcatSinceFormat(val text: String) { +public sealed class LogcatSinceFormat(public val text: String) { // It formats with 'MM-dd HH:mm:ss.SSS' - class DateString(instant: Instant, timezone: String) : + public class DateString(instant: Instant, timezone: String) : LogcatSinceFormat("'${sinceFormatter.withZone(TimeZone.getTimeZone(timezone).toZoneId()).format(instant)}'") // It formats with 'yyyy-MM-dd HH:mm:ss.SSS' - class DateStringYear(instant: Instant, timezone: String) : + public class DateStringYear(instant: Instant, timezone: String) : LogcatSinceFormat("'${sinceYearFormatter.withZone(TimeZone.getTimeZone(timezone).toZoneId()).format(instant)}'") // It formats with 'SSS.0' - class TimeStamp(instant: Instant) : + public class TimeStamp(instant: Instant) : LogcatSinceFormat("${instant.toEpochMilli()}.0") } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/logcat/SyncLogcatRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/logcat/SyncLogcatRequest.kt index 6b16383aa..7da6ea3e8 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/logcat/SyncLogcatRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/logcat/SyncLogcatRequest.kt @@ -20,25 +20,27 @@ import com.malinskiy.adam.request.shell.v1.ShellCommandResult import com.malinskiy.adam.request.shell.v1.SyncShellCommandRequest import java.time.Instant -class SyncLogcatRequest( +public class SyncLogcatRequest( since: LogcatSinceFormat? = null, modes: List = listOf(LogcatReadMode.long), buffers: List = listOf(LogcatBuffer.default), pid: Long? = null, lastReboot: Boolean? = null, - filters: List = emptyList() + filters: List = emptyList(), ) : SyncShellCommandRequest( cmd = "logcat" + - " -d" + - (since?.let { + " -d" + + ( + since?.let { " -t ${since.text}" - } ?: "") + - " ${modes.joinToString(separator = " ") { "-v $it" }}" + - " ${buffers.joinToString(separator = " ") { "-b $it" }}" + - (pid?.let { " --pid=$it" } ?: "") + - (lastReboot?.let { " -L" } ?: "") + - " ${filters.joinToString(separator = " ") { "${it.tag}:${it.level.name}" }}" - .trimEnd() + } ?: "" + ) + + " ${modes.joinToString(separator = " ") { "-v $it" }}" + + " ${buffers.joinToString(separator = " ") { "-b $it" }}" + + (pid?.let { " --pid=$it" } ?: "") + + (lastReboot?.let { " -L" } ?: "") + + " ${filters.joinToString(separator = " ") { "${it.tag}:${it.level.name}" }}" + .trimEnd(), ) { - override fun convertResult(response: ShellCommandResult) = response.output + override fun convertResult(response: ShellCommandResult): String = response.output } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/mdns/ListMdnsServicesRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/mdns/ListMdnsServicesRequest.kt index 287090be3..8577f1a52 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/mdns/ListMdnsServicesRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/mdns/ListMdnsServicesRequest.kt @@ -21,9 +21,8 @@ import com.malinskiy.adam.request.ComplexRequest import com.malinskiy.adam.request.HostTarget import com.malinskiy.adam.transport.Socket -class ListMdnsServicesRequest : ComplexRequest>(target = HostTarget) { +public class ListMdnsServicesRequest : ComplexRequest>(target = HostTarget) { override suspend fun readElement(socket: Socket): List { - return socket.readProtocolString().lines() .filterNot { it.isEmpty() } .map { @@ -31,10 +30,10 @@ class ListMdnsServicesRequest : ComplexRequest>(target = HostT MdnsService( name = split[0].trim(), serviceType = split[1].trim(), - url = split[2].trim() + url = split[2].trim(), ) } } - override fun serialize() = createBaseRequest("mdns:services") + override fun serialize(): ByteArray = createBaseRequest("mdns:services") } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/mdns/MdnsCheckRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/mdns/MdnsCheckRequest.kt index cb479f710..22893a798 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/mdns/MdnsCheckRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/mdns/MdnsCheckRequest.kt @@ -24,7 +24,7 @@ import com.malinskiy.adam.transport.Socket /** * check if mdns discovery is available */ -class MdnsCheckRequest : ComplexRequest(target = HostTarget) { +public class MdnsCheckRequest : ComplexRequest(target = HostTarget) { override suspend fun readElement(socket: Socket): MdnsStatus { val string = socket.readProtocolString() return if (string.contains("mdns daemon unavailable")) { @@ -35,5 +35,5 @@ class MdnsCheckRequest : ComplexRequest(target = HostTarget) { } } - override fun serialize() = createBaseRequest("mdns:check") + override fun serialize(): ByteArray = createBaseRequest("mdns:check") } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/mdns/MdnsService.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/mdns/MdnsService.kt index 08e52a1e7..858f2f81e 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/mdns/MdnsService.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/mdns/MdnsService.kt @@ -16,8 +16,8 @@ package com.malinskiy.adam.request.mdns -data class MdnsService( - val name: String, - val serviceType: String, - val url: String +public data class MdnsService( + public val name: String, + public val serviceType: String, + public val url: String, ) diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/mdns/MdnsStatus.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/mdns/MdnsStatus.kt index 37f97411f..f9a42cd4f 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/mdns/MdnsStatus.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/mdns/MdnsStatus.kt @@ -16,7 +16,7 @@ package com.malinskiy.adam.request.mdns -data class MdnsStatus( - val available: Boolean, - val version: String? = null +public data class MdnsStatus( + public val available: Boolean, + public val version: String? = null, ) diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/misc/ConnectDeviceRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/misc/ConnectDeviceRequest.kt index 026219b4e..cd0bfee0d 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/misc/ConnectDeviceRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/misc/ConnectDeviceRequest.kt @@ -24,12 +24,12 @@ import com.malinskiy.adam.transport.Socket /** * Connects a remote device */ -class ConnectDeviceRequest( +public class ConnectDeviceRequest( private val host: String, - private val port: Int = 5555 + private val port: Int = 5555, ) : ComplexRequest(target = HostTarget) { - override fun serialize() = createBaseRequest("connect:$host:$port") + override fun serialize(): ByteArray = createBaseRequest("connect:$host:$port") - override suspend fun readElement(socket: Socket) = socket.readProtocolString() + override suspend fun readElement(socket: Socket): String = socket.readProtocolString() } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/misc/DisconnectDeviceRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/misc/DisconnectDeviceRequest.kt index ee396acb4..4e06891de 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/misc/DisconnectDeviceRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/misc/DisconnectDeviceRequest.kt @@ -27,12 +27,12 @@ import com.malinskiy.adam.transport.Socket * @param host target device that will be disconnected. if null then disconnects all devices * @param port target device's port. can be null in case of locally connected devices, i.e. physical phones and emulators */ -class DisconnectDeviceRequest( +public class DisconnectDeviceRequest( private val host: String? = null, - private val port: Int? = 5555 + private val port: Int? = 5555, ) : ComplexRequest(target = HostTarget) { - override fun serialize() = createBaseRequest( + override fun serialize(): ByteArray = createBaseRequest( "disconnect:${ if (host == null) { "" @@ -41,8 +41,8 @@ class DisconnectDeviceRequest( } else { "$host" } - }" + }", ) - override suspend fun readElement(socket: Socket) = socket.readProtocolString() + override suspend fun readElement(socket: Socket): String = socket.readProtocolString() } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/misc/ExecInRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/misc/ExecInRequest.kt index ae3f11d22..b2c6c772e 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/misc/ExecInRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/misc/ExecInRequest.kt @@ -26,30 +26,37 @@ import kotlinx.coroutines.channels.SendChannel /** * Executes the command and provides the channel as the input to the command. Does not return anything */ -class ExecInRequest( +public class ExecInRequest( private val cmd: String, private val channel: ReceiveChannel, private val sizeChannel: SendChannel, - socketIdleTimeout: Long? = null + socketIdleTimeout: Long? = null, ) : ComplexRequest(socketIdleTimeout = socketIdleTimeout) { override suspend fun readElement(socket: Socket) { while (true) { if (!channel.isClosedForReceive) { - //Should not request more if read channel is already closed + // Should not request more if read channel is already closed sizeChannel.send(Const.MAX_FILE_PACKET_LENGTH) } val result = channel.tryReceive() when { - result.isSuccess && result.getOrThrow().isNotEmpty() -> socket.writeFully(result.getOrThrow(), 0, result.getOrThrow().size) + result.isSuccess && result.getOrThrow().isNotEmpty() -> socket.writeFully( + result.getOrThrow(), + 0, + result.getOrThrow().size, + ) + result.isClosed -> break + result.isFailure -> continue + else -> break } } - //Have to poll + // Have to poll socket.readStatus() } - override fun serialize() = createBaseRequest("exec:$cmd") + override fun serialize(): ByteArray = createBaseRequest("exec:$cmd") } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/misc/FetchHostFeaturesRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/misc/FetchHostFeaturesRequest.kt index b91a614de..d9f0122f2 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/misc/FetchHostFeaturesRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/misc/FetchHostFeaturesRequest.kt @@ -22,9 +22,9 @@ import com.malinskiy.adam.request.Feature import com.malinskiy.adam.request.HostTarget import com.malinskiy.adam.transport.Socket -class FetchHostFeaturesRequest : ComplexRequest>(target = HostTarget) { +public class FetchHostFeaturesRequest : ComplexRequest>(target = HostTarget) { - override fun serialize() = createBaseRequest("host-features") + override fun serialize(): ByteArray = createBaseRequest("host-features") override suspend fun readElement(socket: Socket): List { return socket.readProtocolString().split(',').mapNotNull { Feature.of(it) } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/misc/GetAdbServerVersionRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/misc/GetAdbServerVersionRequest.kt index e27ffb756..f0cd85e68 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/misc/GetAdbServerVersionRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/misc/GetAdbServerVersionRequest.kt @@ -25,11 +25,11 @@ import com.malinskiy.adam.transport.Socket /** * @see https://android.googlesource.com/platform/system/core/+/refs/heads/master/adb/adb.h#62 */ -class GetAdbServerVersionRequest : ComplexRequest(target = HostTarget) { +public class GetAdbServerVersionRequest : ComplexRequest(target = HostTarget) { override suspend fun readElement(socket: Socket): Int { val version = socket.readOptionalProtocolString() return version?.toIntOrNull(radix = 16) ?: throw RequestRejectedException("Empty/corrupt response") } - override fun serialize() = createBaseRequest("version") + override fun serialize(): ByteArray = createBaseRequest("version") } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/misc/KillAdbRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/misc/KillAdbRequest.kt index e71dd4946..c8450b1f5 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/misc/KillAdbRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/misc/KillAdbRequest.kt @@ -19,10 +19,10 @@ package com.malinskiy.adam.request.misc import com.malinskiy.adam.request.HostTarget import com.malinskiy.adam.request.SynchronousRequest -class KillAdbRequest : SynchronousRequest(target = HostTarget) { - override fun serialize() = createBaseRequest("kill") +public class KillAdbRequest : SynchronousRequest(target = HostTarget) { + override fun serialize(): ByteArray = createBaseRequest("kill") - override suspend fun process(bytes: ByteArray, offset: Int, limit: Int) = Unit + override suspend fun process(bytes: ByteArray, offset: Int, limit: Int): Unit = Unit - override fun transform() = Unit + override fun transform(): Unit = Unit } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/misc/PairDeviceRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/misc/PairDeviceRequest.kt index 40b23e9d5..6f6e00e62 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/misc/PairDeviceRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/misc/PairDeviceRequest.kt @@ -27,12 +27,12 @@ import com.malinskiy.adam.transport.Socket * * @param url target device in the form of host[:port], port is optional */ -class PairDeviceRequest( +public class PairDeviceRequest( private val url: String, - private val pairingCode: String + private val pairingCode: String, ) : ComplexRequest(target = HostTarget) { - override suspend fun readElement(socket: Socket) = socket.readProtocolString() + override suspend fun readElement(socket: Socket): String = socket.readProtocolString() - override fun serialize() = createBaseRequest("pair:$pairingCode:$url") -} \ No newline at end of file + override fun serialize(): ByteArray = createBaseRequest("pair:$pairingCode:$url") +} diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/misc/RebootRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/misc/RebootRequest.kt index ce91140ab..6fc51c9f8 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/misc/RebootRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/misc/RebootRequest.kt @@ -18,18 +18,18 @@ package com.malinskiy.adam.request.misc import com.malinskiy.adam.request.SynchronousRequest -class RebootRequest(private val mode: RebootMode = RebootMode.DEFAULT) : SynchronousRequest() { - override suspend fun process(bytes: ByteArray, offset: Int, limit: Int) = Unit +public class RebootRequest(private val mode: RebootMode = RebootMode.DEFAULT) : SynchronousRequest() { + override suspend fun process(bytes: ByteArray, offset: Int, limit: Int): Unit = Unit - override fun serialize() = createBaseRequest("reboot:${mode.value}") + override fun serialize(): ByteArray = createBaseRequest("reboot:${mode.value}") - override fun transform() = Unit + override fun transform(): Unit = Unit } -enum class RebootMode(val value: String) { +public enum class RebootMode(public val value: String) { DEFAULT(""), RECOVERY("recovery"), BOOTLOADER("bootloader"), SIDELOAD("sideload"), - SIDELOAD_AUTO_REBOOT("sideload-auto-reboot") + SIDELOAD_AUTO_REBOOT("sideload-auto-reboot"), } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/misc/ReconnectRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/misc/ReconnectRequest.kt index 1d5f906f2..cf5bd87f6 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/misc/ReconnectRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/misc/ReconnectRequest.kt @@ -35,9 +35,9 @@ import com.malinskiy.adam.transport.withDefaultBuffer * * @param reconnectTarget default behaviour depends on the target serial that will be specified during execution */ -class ReconnectRequest( +public class ReconnectRequest( private val reconnectTarget: ReconnectTarget? = null, - target: Target = NonSpecifiedTarget + target: Target = NonSpecifiedTarget, ) : ComplexRequest(target = target) { override suspend fun readElement(socket: Socket): String { withDefaultBuffer { @@ -47,7 +47,7 @@ class ReconnectRequest( return if (array().copyOfRange(0, 4).contentEquals(done)) { "done" } else { - //This is length of a response string + // This is length of a response string val size = String(array(), 0, 4, Const.DEFAULT_TRANSPORT_ENCODING).toInt(radix = 16) compatClear() compatLimit(size) @@ -58,18 +58,18 @@ class ReconnectRequest( } } - override fun serialize() = when (reconnectTarget) { + override fun serialize(): ByteArray = when (reconnectTarget) { null -> createBaseRequest("reconnect") Device -> createBaseRequest("reconnect") Offline -> createBaseRequest("reconnect-offline") } - companion object { + public companion object { /** * For some reason this done is lowercase and doesn't use the DONE message as everything else * see daemon/services.cpp#reconnect_service */ - val done = byteArrayOf( + public val done: ByteArray = byteArrayOf( 'd'.code.toByte(), 'o'.code.toByte(), 'n'.code.toByte(), @@ -78,10 +78,10 @@ class ReconnectRequest( } } -sealed class ReconnectTarget -object Device : ReconnectTarget() +public sealed class ReconnectTarget +public object Device : ReconnectTarget() /** * Only supports host target */ -object Offline : ReconnectTarget() +public object Offline : ReconnectTarget() diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/misc/RemountPartitionsRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/misc/RemountPartitionsRequest.kt index f7b52d591..4fbc47114 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/misc/RemountPartitionsRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/misc/RemountPartitionsRequest.kt @@ -19,17 +19,21 @@ package com.malinskiy.adam.request.misc import com.malinskiy.adam.request.SynchronousRequest import com.malinskiy.adam.request.transform.StringResponseTransformer -class RemountPartitionsRequest(private val autoReboot: Boolean = false) : SynchronousRequest() { +public class RemountPartitionsRequest(private val autoReboot: Boolean = false) : SynchronousRequest() { private val transformer = StringResponseTransformer() - override suspend fun process(bytes: ByteArray, offset: Int, limit: Int) = transformer.process(bytes, offset, limit) + override suspend fun process(bytes: ByteArray, offset: Int, limit: Int): Unit = transformer.process( + bytes, + offset, + limit, + ) - override fun serialize() = createBaseRequest( + override fun serialize(): ByteArray = createBaseRequest( when (autoReboot) { true -> "remount:-R" false -> "remount:" - } + }, ) - override fun transform() = transformer.transform() -} \ No newline at end of file + override fun transform(): String = transformer.transform() +} diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/misc/SetDeviceRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/misc/SetDeviceRequest.kt index c7a4c600c..4e9afc723 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/misc/SetDeviceRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/misc/SetDeviceRequest.kt @@ -19,6 +19,6 @@ package com.malinskiy.adam.request.misc import com.malinskiy.adam.request.HostTarget import com.malinskiy.adam.request.Request -class SetDeviceRequest(private val serial: String) : Request(target = HostTarget) { - override fun serialize() = createBaseRequest("transport:$serial") +public class SetDeviceRequest(private val serial: String) : Request(target = HostTarget) { + override fun serialize(): ByteArray = createBaseRequest("transport:$serial") } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/AtomicInstallPackageRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/AtomicInstallPackageRequest.kt index 17cc18b9a..fc720e364 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/AtomicInstallPackageRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/AtomicInstallPackageRequest.kt @@ -46,14 +46,17 @@ import kotlin.coroutines.CoroutineContext * @see com.malinskiy.adam.request.device.FetchDeviceFeaturesRequest */ @Features(Feature.CMD, Feature.ABB_EXEC, Feature.APEX) -class AtomicInstallPackageRequest( +public class AtomicInstallPackageRequest( private val pkgList: List, private val supportedFeatures: List, private val reinstall: Boolean, private val extraArgs: List = emptyList(), - val coroutineContext: CoroutineContext = Dispatchers.IO + public val coroutineContext: CoroutineContext = Dispatchers.IO, ) : AccumulatingMultiRequest() { - override suspend fun execute(androidDebugBridgeClient: AndroidDebugBridgeClient, serial: String?) = with(androidDebugBridgeClient) { + override suspend fun execute( + androidDebugBridgeClient: AndroidDebugBridgeClient, + serial: String?, + ): String = with(androidDebugBridgeClient) { val (parentSessionId, output) = execute(CreateMultiPackageSessionRequest(pkgList, supportedFeatures, reinstall, extraArgs), serial) output.addToResponse() @@ -64,23 +67,33 @@ class AtomicInstallPackageRequest( val (childSessionId, output) = execute( CreateIndividualPackageSessionRequest(pkg, pkgList, supportedFeatures, reinstall, extraArgs), - serial + serial, ) output.addToResponse() when (pkg) { is SingleFileInstallationPackage -> { execute( - WriteIndividualPackageRequest(pkg.file, supportedFeatures, childSessionId, coroutineContext), - serial + WriteIndividualPackageRequest( + pkg.file, + supportedFeatures, + childSessionId, + coroutineContext, + ), + serial, ).addToResponse() } is ApkSplitInstallationPackage -> { for (file in pkg.fileList) { execute( - WriteIndividualPackageRequest(file, supportedFeatures, childSessionId, coroutineContext), - serial + WriteIndividualPackageRequest( + file, + supportedFeatures, + childSessionId, + coroutineContext, + ), + serial, ).addToResponse() } } @@ -96,7 +109,7 @@ class AtomicInstallPackageRequest( try { execute(InstallCommitRequest(parentSessionId, supportedFeatures, abandon = true), serial) } catch (e: Exception) { - //Ignore + // Ignore } throw e } @@ -113,7 +126,8 @@ class AtomicInstallPackageRequest( is SingleFileInstallationPackage -> listOf(it.file) is ApkSplitInstallationPackage -> it.fileList } - }.flatten().any { file -> file.extension == "apex" } && !supportedFeatures.contains(Feature.APEX)) { + }.flatten().any { file -> file.extension == "apex" } && !supportedFeatures.contains(Feature.APEX) + ) { ValidationResponse(false, ValidationResponse.missingFeature(Feature.APEX)) } else { ValidationResponse.Success diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/InstallRemotePackageRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/InstallRemotePackageRequest.kt index 7a572f662..2419f6538 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/InstallRemotePackageRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/InstallRemotePackageRequest.kt @@ -19,10 +19,10 @@ package com.malinskiy.adam.request.pkg import com.malinskiy.adam.request.ValidationResponse import com.malinskiy.adam.request.shell.v1.ShellCommandRequest -class InstallRemotePackageRequest( +public class InstallRemotePackageRequest( private val absoluteRemoteFilePath: String, reinstall: Boolean, - extraArgs: List = emptyList() + extraArgs: List = emptyList(), ) : ShellCommandRequest( cmd = StringBuilder().apply { append("pm install ") @@ -37,7 +37,7 @@ class InstallRemotePackageRequest( } append(absoluteRemoteFilePath) - }.toString() + }.toString(), ) { override fun validate(): ValidationResponse { val result = super.validate() @@ -46,7 +46,10 @@ class InstallRemotePackageRequest( } else if (absoluteRemoteFilePath.endsWith(".apex")) { ValidationResponse(false, "APEX packages are only not compatible with InstallRemotePackageRequest") } else if (!absoluteRemoteFilePath.endsWith(".apk")) { - ValidationResponse(false, "Unsupported package extension ${absoluteRemoteFilePath.substringAfterLast('.')}. Should be apk") + ValidationResponse( + false, + "Unsupported package extension ${absoluteRemoteFilePath.substringAfterLast('.')}. Should be apk", + ) } else { ValidationResponse.Success } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/InstallSplitPackageRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/InstallSplitPackageRequest.kt index 032488407..ab534d1d5 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/InstallSplitPackageRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/InstallSplitPackageRequest.kt @@ -49,34 +49,39 @@ import kotlin.coroutines.CoroutineContext * If both CMD and ABB_EXEC are missing, falls back to exec:pm */ @Features(Feature.CMD, Feature.ABB_EXEC) -class InstallSplitPackageRequest( +public class InstallSplitPackageRequest( private val pkg: ApkSplitInstallationPackage, private val supportedFeatures: List, private val reinstall: Boolean, private val extraArgs: List = emptyList(), - val coroutineContext: CoroutineContext = Dispatchers.IO + public val coroutineContext: CoroutineContext = Dispatchers.IO, ) : AccumulatingMultiRequest() { private val totalSize: Long by lazy { pkg.fileList.sumOf { it.length() } } - override suspend fun execute(androidDebugBridgeClient: AndroidDebugBridgeClient, serial: String?) = with(androidDebugBridgeClient) { + override suspend fun execute(androidDebugBridgeClient: AndroidDebugBridgeClient, serial: String?): String = with( + androidDebugBridgeClient, + ) { val (sessionId, output) = execute( CreateIndividualPackageSessionRequest( pkg, listOf(pkg), supportedFeatures, reinstall, - extraArgs + "-S${totalSize}" + extraArgs + "-S$totalSize", ), - serial + serial, ) output.addToResponse() try { for (file in pkg.fileList) { - execute(WriteIndividualPackageRequest(file, supportedFeatures, sessionId, coroutineContext), serial).addToResponse() + execute( + WriteIndividualPackageRequest(file, supportedFeatures, sessionId, coroutineContext), + serial, + ).addToResponse() } execute(InstallCommitRequest(sessionId, supportedFeatures), serial).addToResponse() @@ -85,7 +90,7 @@ class InstallSplitPackageRequest( try { execute(InstallCommitRequest(sessionId, supportedFeatures, abandon = true), serial) } catch (e: Exception) { - //Ignore + // Ignore } throw e } @@ -123,7 +128,7 @@ class InstallSplitPackageRequest( } } - companion object { - val SUPPORTED_EXTENSIONS = setOf("apk", "dm", "fsv_sig") + public companion object { + public val SUPPORTED_EXTENSIONS: Set = setOf("apk", "dm", "fsv_sig") } } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/LegacySideloadRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/LegacySideloadRequest.kt index aff540a1c..3778eb914 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/LegacySideloadRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/LegacySideloadRequest.kt @@ -30,9 +30,9 @@ import kotlin.coroutines.CoroutineContext /** * pre-KitKat */ -class LegacySideloadRequest( +public class LegacySideloadRequest( private val pkg: File, - val coroutineContext: CoroutineContext = Dispatchers.IO + public val coroutineContext: CoroutineContext = Dispatchers.IO, ) : ComplexRequest() { override fun validate(): ValidationResponse { val message = @@ -47,7 +47,7 @@ class LegacySideloadRequest( return ValidationResponse(message == null, message) } - override fun serialize() = createBaseRequest("sideload:${pkg.length()}") + override fun serialize(): ByteArray = createBaseRequest("sideload:${pkg.length()}") override suspend fun readElement(socket: Socket): Boolean { AsyncFileReader(pkg, coroutineContext = coroutineContext).use { reader -> diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/PmListRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/PmListRequest.kt index dd1fa85bf..62cd434f3 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/PmListRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/PmListRequest.kt @@ -19,12 +19,12 @@ package com.malinskiy.adam.request.pkg import com.malinskiy.adam.request.shell.v1.ShellCommandResult import com.malinskiy.adam.request.shell.v1.SyncShellCommandRequest -class PmListRequest(private val includePath: Boolean = false) : SyncShellCommandRequest>( +public class PmListRequest(private val includePath: Boolean = false) : SyncShellCommandRequest>( cmd = StringBuilder().apply { append("pm list packages") if (includePath) append(" -f") - }.toString() + }.toString(), ) { override fun convertResult(response: ShellCommandResult): List { return response.output @@ -38,17 +38,17 @@ class PmListRequest(private val includePath: Boolean = false) : SyncShellCommand true -> { Package(split[2], split[1]) } + false -> { Package(split[1]) } } - } } } } -data class Package( - val name: String, - val path: String? = null +public data class Package( + public val name: String, + public val path: String? = null, ) diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/SideloadRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/SideloadRequest.kt index e0565d5ce..2be4332f1 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/SideloadRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/SideloadRequest.kt @@ -24,11 +24,11 @@ import com.malinskiy.adam.transport.AdamMaxFilePacketPool import com.malinskiy.adam.transport.Socket import java.io.File -class SideloadRequest( +public class SideloadRequest( private val pkg: File, ) : ComplexRequest() { private val blockSize: Int = Const.MAX_FILE_PACKET_LENGTH - val buffer = ByteArray(blockSize) + public val buffer: ByteArray = ByteArray(blockSize) override suspend fun readElement(socket: Socket): Boolean { var reader: AsyncFileReader? = null @@ -42,12 +42,14 @@ class SideloadRequest( val bytes = buffer.copyOfRange(0, 8) when { bytes.contentEquals(Const.Message.DONEDONE) -> return true + bytes.contentEquals(Const.Message.FAILFAIL) -> return false + else -> { val blockId = String(bytes, 0, 8, Const.DEFAULT_TRANSPORT_ENCODING).toLong() val offset = blockId * blockSize if (offset != currentOffset) { - //We can't seek on the channels. Recreating the channel again + // We can't seek on the channels. Recreating the channel again reader?.close() reader = AsyncFileReader(pkg, start = offset) reader.start() @@ -90,5 +92,5 @@ class SideloadRequest( return ValidationResponse(message == null, message) } - override fun serialize() = createBaseRequest("sideload-host:${pkg.length()}:${blockSize}") + override fun serialize(): ByteArray = createBaseRequest("sideload-host:${pkg.length()}:$blockSize") } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/StreamingPackageInstallRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/StreamingPackageInstallRequest.kt index ad688c51d..e81be358d 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/StreamingPackageInstallRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/StreamingPackageInstallRequest.kt @@ -40,12 +40,12 @@ import kotlin.coroutines.CoroutineContext * @see com.malinskiy.adam.request.device.FetchDeviceFeaturesRequest */ @Features(Feature.CMD, Feature.ABB_EXEC, Feature.APEX) -class StreamingPackageInstallRequest( +public class StreamingPackageInstallRequest( private val pkg: File, private val supportedFeatures: List, private val reinstall: Boolean, private val extraArgs: List = emptyList(), - val coroutineContext: CoroutineContext = Dispatchers.IO + public val coroutineContext: CoroutineContext = Dispatchers.IO, ) : ComplexRequest() { private val transformer = StringResponseTransformer() @@ -81,7 +81,7 @@ class StreamingPackageInstallRequest( "package" } else { "exec:cmd package" - } + }, ) add("install") @@ -124,9 +124,9 @@ class StreamingPackageInstallRequest( return StreamingPackageInstallResult(output, success) } - companion object { - val SUPPORTED_EXTENSIONS = setOf("apk", "apex") + public companion object { + public val SUPPORTED_EXTENSIONS: Set = setOf("apk", "apex") } } -data class StreamingPackageInstallResult(val output: String, val success: Boolean) +public data class StreamingPackageInstallResult(public val output: String, public val success: Boolean) diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/UninstallRemotePackageRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/UninstallRemotePackageRequest.kt index fc894ed92..b7ab21a5f 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/UninstallRemotePackageRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/UninstallRemotePackageRequest.kt @@ -24,9 +24,9 @@ import com.malinskiy.adam.request.shell.v1.ShellCommandRequest * There is no way to remove the remaining data. * You will have to reinstall the application with the same signature, and fully uninstall it. */ -class UninstallRemotePackageRequest( +public class UninstallRemotePackageRequest( packageName: String, - keepData: Boolean = false + keepData: Boolean = false, ) : ShellCommandRequest( cmd = StringBuilder().apply { append("pm uninstall ") @@ -36,5 +36,5 @@ class UninstallRemotePackageRequest( } append(packageName) - }.toString() + }.toString(), ) diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/multi/AddSessionRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/multi/AddSessionRequest.kt index 4270abc97..69f3cb243 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/multi/AddSessionRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/multi/AddSessionRequest.kt @@ -23,10 +23,10 @@ import com.malinskiy.adam.request.Feature import com.malinskiy.adam.request.abb.AbbExecRequest import com.malinskiy.adam.transport.Socket -class AddSessionRequest( +public class AddSessionRequest( private val childSessions: List, private val parentSession: String, - private val supportedFeatures: List + private val supportedFeatures: List, ) : ComplexRequest() { override fun serialize(): ByteArray { val hasAbbExec = supportedFeatures.contains(Feature.ABB_EXEC) @@ -36,7 +36,7 @@ class AddSessionRequest( "package" } else { "exec:cmd package" - } + }, ) add("install-add-session") add(parentSession) @@ -55,7 +55,7 @@ class AddSessionRequest( if (!response.contains("Success")) { throw RequestRejectedException( "Failed to add child sessions ${childSessions.joinToString()} to a parent session " + - "$parentSession: $response" + "$parentSession: $response", ) } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/multi/CreateIndividualPackageSessionRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/multi/CreateIndividualPackageSessionRequest.kt index 26cf914ce..65473980d 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/multi/CreateIndividualPackageSessionRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/multi/CreateIndividualPackageSessionRequest.kt @@ -24,12 +24,12 @@ import com.malinskiy.adam.request.Feature import com.malinskiy.adam.request.abb.AbbExecRequest import com.malinskiy.adam.transport.Socket -class CreateIndividualPackageSessionRequest( +public class CreateIndividualPackageSessionRequest( private val pkg: InstallationPackage, private val pkgList: List, private val supportedFeatures: List, private val reinstall: Boolean, - private val extraArgs: List = emptyList() + private val extraArgs: List = emptyList(), ) : ComplexRequest() { override fun serialize(): ByteArray { @@ -38,10 +38,12 @@ class CreateIndividualPackageSessionRequest( add( when { supportedFeatures.contains(Feature.ABB_EXEC) -> "package" + supportedFeatures.contains(Feature.CMD) -> "exec:cmd package" - //User is responsible for checking if pm supports install-write in this case + + // User is responsible for checking if pm supports install-write in this case else -> "exec:pm" - } + }, ) add("install-create") diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/multi/CreateMultiPackageSessionRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/multi/CreateMultiPackageSessionRequest.kt index 7acf95d25..8ef93d55c 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/multi/CreateMultiPackageSessionRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/multi/CreateMultiPackageSessionRequest.kt @@ -28,11 +28,11 @@ import com.malinskiy.adam.transport.Socket import java.io.File @Features(Feature.CMD, Feature.ABB_EXEC) -class CreateMultiPackageSessionRequest( +public class CreateMultiPackageSessionRequest( private val pkgList: List, private val supportedFeatures: List, private val reinstall: Boolean, - private val extraArgs: List = emptyList() + private val extraArgs: List = emptyList(), ) : ComplexRequest() { override fun validate(): ValidationResponse { val response = super.validate() @@ -84,7 +84,7 @@ class CreateMultiPackageSessionRequest( "package" } else { "exec:cmd package" - } + }, ) add("install-create") @@ -134,7 +134,7 @@ class CreateMultiPackageSessionRequest( return CreateSessionResponse(sessionId, createSessionResponse) } - companion object { - val SUPPORTED_EXTENSIONS = setOf("apk", "apex") + public companion object { + public val SUPPORTED_EXTENSIONS: Set = setOf("apk", "apex") } } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/multi/CreateSessionResponse.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/multi/CreateSessionResponse.kt index 7d91c1b64..a597455ce 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/multi/CreateSessionResponse.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/multi/CreateSessionResponse.kt @@ -16,4 +16,4 @@ package com.malinskiy.adam.request.pkg.multi -data class CreateSessionResponse(val id: String, val output: String) +public data class CreateSessionResponse(public val id: String, public val output: String) diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/multi/InstallCommitRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/multi/InstallCommitRequest.kt index 5c3ff0714..2cf0a6734 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/multi/InstallCommitRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/multi/InstallCommitRequest.kt @@ -23,10 +23,10 @@ import com.malinskiy.adam.request.Feature import com.malinskiy.adam.request.abb.AbbExecRequest import com.malinskiy.adam.transport.Socket -class InstallCommitRequest( +public class InstallCommitRequest( private val parentSession: String, private val supportedFeatures: List, - private val abandon: Boolean = false + private val abandon: Boolean = false, ) : ComplexRequest() { override fun serialize(): ByteArray { val hasAbbExec = supportedFeatures.contains(Feature.ABB_EXEC) @@ -34,10 +34,12 @@ class InstallCommitRequest( add( when { supportedFeatures.contains(Feature.ABB_EXEC) -> "package" + supportedFeatures.contains(Feature.CMD) -> "exec:cmd package" - //User is responsible for checking if pm supports install-write in this case + + // User is responsible for checking if pm supports install-write in this case else -> "exec:pm" - } + }, ) if (abandon) { @@ -58,8 +60,8 @@ class InstallCommitRequest( override suspend fun readElement(socket: Socket): String { val result = socket.readStatus() - //Rather than checking for success, we check for Failure since some implementations of PackageManagerShellCommand ignore the - //logSuccess=true in doCommitSession + // Rather than checking for success, we check for Failure since some implementations of PackageManagerShellCommand ignore the + // logSuccess=true in doCommitSession if (result.contains("Failure")) { throw RequestRejectedException("Failed to finalize session $parentSession: $result") } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/multi/InstallationPackage.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/multi/InstallationPackage.kt index 5ae8d5907..300f4522c 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/multi/InstallationPackage.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/multi/InstallationPackage.kt @@ -18,13 +18,13 @@ package com.malinskiy.adam.request.pkg.multi import java.io.File -sealed class InstallationPackage +public sealed class InstallationPackage -data class SingleFileInstallationPackage(val file: File) : InstallationPackage() +public data class SingleFileInstallationPackage(public val file: File) : InstallationPackage() /** * Android 21+ */ -data class ApkSplitInstallationPackage(val fileList: List) : InstallationPackage() { - constructor(vararg files: File) : this(files.toList()) +public data class ApkSplitInstallationPackage(public val fileList: List) : InstallationPackage() { + public constructor(vararg files: File) : this(files.toList()) } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/multi/WriteIndividualPackageRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/multi/WriteIndividualPackageRequest.kt index b63f00420..153d16236 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/multi/WriteIndividualPackageRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/pkg/multi/WriteIndividualPackageRequest.kt @@ -27,11 +27,11 @@ import kotlinx.coroutines.Dispatchers import java.io.File import kotlin.coroutines.CoroutineContext -class WriteIndividualPackageRequest( +public class WriteIndividualPackageRequest( private val file: File, private val supportedFeatures: List, private val session: String, - private val coroutineContext: CoroutineContext = Dispatchers.IO + private val coroutineContext: CoroutineContext = Dispatchers.IO, ) : ComplexRequest() { override fun serialize(): ByteArray { val hasAbbExec = supportedFeatures.contains(Feature.ABB_EXEC) @@ -39,10 +39,12 @@ class WriteIndividualPackageRequest( add( when { supportedFeatures.contains(Feature.ABB_EXEC) -> "package" + supportedFeatures.contains(Feature.CMD) -> "exec:cmd package" - //User is responsible for checking if pm supports install-write in this case + + // User is responsible for checking if pm supports install-write in this case else -> "exec:pm" - } + }, ) add("install-write") diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/prop/GetPropRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/prop/GetPropRequest.kt index 158f584b0..3f28aed44 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/prop/GetPropRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/prop/GetPropRequest.kt @@ -19,7 +19,7 @@ package com.malinskiy.adam.request.prop import com.malinskiy.adam.request.shell.v1.ShellCommandResult import com.malinskiy.adam.request.shell.v1.SyncShellCommandRequest -class GetPropRequest : SyncShellCommandRequest>("getprop") { +public class GetPropRequest : SyncShellCommandRequest>("getprop") { override fun convertResult(response: ShellCommandResult): Map { return response.output .lines() diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/prop/GetSinglePropRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/prop/GetSinglePropRequest.kt index b9bc58435..bc616f010 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/prop/GetSinglePropRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/prop/GetSinglePropRequest.kt @@ -19,6 +19,6 @@ package com.malinskiy.adam.request.prop import com.malinskiy.adam.request.shell.v1.ShellCommandResult import com.malinskiy.adam.request.shell.v1.SyncShellCommandRequest -class GetSinglePropRequest(name: String) : SyncShellCommandRequest("getprop $name") { - override fun convertResult(response: ShellCommandResult) = response.output +public class GetSinglePropRequest(name: String) : SyncShellCommandRequest("getprop $name") { + override fun convertResult(response: ShellCommandResult): String = response.output } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/reverse/ListReversePortForwardsRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/reverse/ListReversePortForwardsRequest.kt index e1f78cc2d..7bb06b635 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/reverse/ListReversePortForwardsRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/reverse/ListReversePortForwardsRequest.kt @@ -26,7 +26,9 @@ import com.malinskiy.adam.transport.Socket /** * Doesn't work with SerialTarget, have to use the serial as a parameter for the execute method */ -class ListReversePortForwardsRequest : ComplexRequest>(target = NonSpecifiedTarget) { +public class ListReversePortForwardsRequest : ComplexRequest>( + target = NonSpecifiedTarget, +) { override suspend fun readElement(socket: Socket): List { return socket.readProtocolString().lines().mapNotNull { line -> if (line.isNotEmpty()) { @@ -34,7 +36,7 @@ class ListReversePortForwardsRequest : ComplexRequest(target = NonSpecifiedTarget) { - override fun serialize() = createBaseRequest("reverse:killforward-all") +public class RemoveAllReversePortForwardsRequest : SynchronousRequest(target = NonSpecifiedTarget) { + override fun serialize(): ByteArray = createBaseRequest("reverse:killforward-all") - override suspend fun process(bytes: ByteArray, offset: Int, limit: Int) = Unit + override suspend fun process(bytes: ByteArray, offset: Int, limit: Int): Unit = Unit - override fun transform() = Unit -} \ No newline at end of file + override fun transform(): Unit = Unit +} diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/reverse/RemoveReversePortForwardRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/reverse/RemoveReversePortForwardRequest.kt index 3d5a35496..5088e7ca0 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/reverse/RemoveReversePortForwardRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/reverse/RemoveReversePortForwardRequest.kt @@ -23,12 +23,12 @@ import com.malinskiy.adam.request.forwarding.RemotePortSpec /** * Doesn't work with SerialTarget, have to use the serial as a parameter for the execute method */ -class RemoveReversePortForwardRequest( - private val local: RemotePortSpec +public class RemoveReversePortForwardRequest( + private val local: RemotePortSpec, ) : SynchronousRequest(target = NonSpecifiedTarget) { - override fun serialize() = createBaseRequest("reverse:killforward:${local.toSpec()}") + override fun serialize(): ByteArray = createBaseRequest("reverse:killforward:${local.toSpec()}") - override suspend fun process(bytes: ByteArray, offset: Int, limit: Int) = Unit + override suspend fun process(bytes: ByteArray, offset: Int, limit: Int): Unit = Unit - override fun transform() = Unit -} \ No newline at end of file + override fun transform(): Unit = Unit +} diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/reverse/ReversePortForwardRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/reverse/ReversePortForwardRequest.kt index f42b31dbf..f0725d576 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/reverse/ReversePortForwardRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/reverse/ReversePortForwardRequest.kt @@ -31,14 +31,14 @@ import com.malinskiy.adam.transport.Socket * * Doesn't work with SerialTarget, have to use the serial as a parameter for the execute method */ -class ReversePortForwardRequest( +public class ReversePortForwardRequest( private val local: RemotePortSpec, private val remote: LocalPortSpec, - private val mode: PortForwardingMode = PortForwardingMode.DEFAULT + private val mode: PortForwardingMode = PortForwardingMode.DEFAULT, ) : ComplexRequest(target = NonSpecifiedTarget) { - override fun serialize() = + override fun serialize(): ByteArray = createBaseRequest("reverse:forward${mode.value}:${local.toSpec()};${remote.toSpec()}") override suspend fun readElement(socket: Socket): Int? { diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/reverse/ReversePortForwardingRule.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/reverse/ReversePortForwardingRule.kt index d1cc69f98..acbde8420 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/reverse/ReversePortForwardingRule.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/reverse/ReversePortForwardingRule.kt @@ -19,8 +19,8 @@ package com.malinskiy.adam.request.reverse import com.malinskiy.adam.request.forwarding.LocalPortSpec import com.malinskiy.adam.request.forwarding.RemotePortSpec -data class ReversePortForwardingRule( - val serial: String, - val localSpec: RemotePortSpec, - val remoteSpec: LocalPortSpec -) \ No newline at end of file +public data class ReversePortForwardingRule( + public val serial: String, + public val localSpec: RemotePortSpec, + public val remoteSpec: LocalPortSpec, +) diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/security/SetDmVerityCheckingRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/security/SetDmVerityCheckingRequest.kt index 5d6119b68..4b33f1d7c 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/security/SetDmVerityCheckingRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/security/SetDmVerityCheckingRequest.kt @@ -25,17 +25,21 @@ import com.malinskiy.adam.request.transform.StringResponseTransformer * Returns a string response of executing the command. * One possible value is "verity cannot be disabled/enabled - USER build" when the device is not a debug build */ -class SetDmVerityCheckingRequest(private val enabled: Boolean) : SynchronousRequest() { +public class SetDmVerityCheckingRequest(private val enabled: Boolean) : SynchronousRequest() { private val transformer = StringResponseTransformer() - override suspend fun process(bytes: ByteArray, offset: Int, limit: Int) = transformer.process(bytes, offset, limit) + override suspend fun process(bytes: ByteArray, offset: Int, limit: Int): Unit = transformer.process( + bytes, + offset, + limit, + ) - override fun serialize() = createBaseRequest( + override fun serialize(): ByteArray = createBaseRequest( when (enabled) { true -> "enable-verity:" false -> "disable-verity:" - } + }, ) - override fun transform() = transformer.transform() -} \ No newline at end of file + override fun transform(): String = transformer.transform() +} diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/shell/AsyncCompatShellCommandRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/shell/AsyncCompatShellCommandRequest.kt index 0a3f38a1a..a68faa0d1 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/shell/AsyncCompatShellCommandRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/shell/AsyncCompatShellCommandRequest.kt @@ -32,25 +32,27 @@ import kotlinx.coroutines.channels.SendChannel import kotlinx.coroutines.channels.produce import com.malinskiy.adam.request.shell.v2.ChanneledShellCommandRequest as V2ChanneledShellCommandRequest -abstract class AsyncCompatShellCommandRequest( - val cmd: String, +public abstract class AsyncCompatShellCommandRequest( + public val cmd: String, private val supportedFeatures: List, private val target: Target = NonSpecifiedTarget, private val coroutineScope: CoroutineScope, private val socketIdleTimeout: Long? = null, ) : MultiRequest>() { - abstract suspend fun convertChunk(response: ShellCommandResultChunk): T? + public abstract suspend fun convertChunk(response: ShellCommandResultChunk): T? override suspend fun execute( androidDebugBridgeClient: AndroidDebugBridgeClient, - serial: String? + serial: String?, ): ReceiveChannel { return when { supportedFeatures.contains(Feature.SHELL_V2) -> { val channel = Channel() val receiveChannel = androidDebugBridgeClient.execute( - V2ChanneledShellCommandRequest(cmd, channel, target, socketIdleTimeout), coroutineScope, serial, + V2ChanneledShellCommandRequest(cmd, channel, target, socketIdleTimeout), + coroutineScope, + serial, ) coroutineScope.produce { for (chunk in receiveChannel) { @@ -62,7 +64,9 @@ abstract class AsyncCompatShellCommandRequest( else -> { val receiveChannel: ReceiveChannel = androidDebugBridgeClient.execute( - ChanneledShellCommandRequest(cmd, target, socketIdleTimeout), coroutineScope, serial, + ChanneledShellCommandRequest(cmd, target, socketIdleTimeout), + coroutineScope, + serial, ) coroutineScope.produce { for (line in receiveChannel) { @@ -75,5 +79,5 @@ abstract class AsyncCompatShellCommandRequest( } } - abstract suspend fun close(channel: SendChannel) + public abstract suspend fun close(channel: SendChannel) } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/shell/v1/ChanneledShellCommandRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/shell/v1/ChanneledShellCommandRequest.kt index b9277adb1..c3bb9bc62 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/shell/v1/ChanneledShellCommandRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/shell/v1/ChanneledShellCommandRequest.kt @@ -24,10 +24,10 @@ import com.malinskiy.adam.transport.Socket import com.malinskiy.adam.transport.withMaxFilePacketBuffer import kotlinx.coroutines.channels.SendChannel -open class ChanneledShellCommandRequest( - val cmd: String, +public open class ChanneledShellCommandRequest( + public val cmd: String, target: Target = NonSpecifiedTarget, - socketIdleTimeout: Long? = null + socketIdleTimeout: Long? = null, ) : AsyncChannelRequest(target = target, socketIdleTimeout = socketIdleTimeout) { override suspend fun readElement(socket: Socket, sendChannel: SendChannel): Boolean { @@ -43,6 +43,6 @@ open class ChanneledShellCommandRequest( } } - override fun serialize() = createBaseRequest("shell:$cmd") - override suspend fun writeElement(element: Unit, socket: Socket) = Unit + override fun serialize(): ByteArray = createBaseRequest("shell:$cmd") + override suspend fun writeElement(element: Unit, socket: Socket): Unit = Unit } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/shell/v1/ShellCommandRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/shell/v1/ShellCommandRequest.kt index a85107422..6d20a5995 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/shell/v1/ShellCommandRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/shell/v1/ShellCommandRequest.kt @@ -16,6 +16,6 @@ package com.malinskiy.adam.request.shell.v1 -open class ShellCommandRequest(cmd: String) : SyncShellCommandRequest(cmd) { - override fun convertResult(response: ShellCommandResult) = response +public open class ShellCommandRequest(cmd: String) : SyncShellCommandRequest(cmd) { + override fun convertResult(response: ShellCommandResult): ShellCommandResult = response } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/shell/v1/ShellCommandResult.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/shell/v1/ShellCommandResult.kt index a08f79571..629626525 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/shell/v1/ShellCommandResult.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/shell/v1/ShellCommandResult.kt @@ -18,11 +18,11 @@ package com.malinskiy.adam.request.shell.v1 import com.malinskiy.adam.Const -data class ShellCommandResult( - val stdout: ByteArray, - val exitCode: Int +public data class ShellCommandResult( + public val stdout: ByteArray, + public val exitCode: Int, ) { - val output: String by lazy { + public val output: String by lazy { String(stdout, Const.DEFAULT_TRANSPORT_ENCODING) } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/shell/v1/ShellResultResponseTransformer.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/shell/v1/ShellResultResponseTransformer.kt index 6280a15c7..341d5851b 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/shell/v1/ShellResultResponseTransformer.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/shell/v1/ShellResultResponseTransformer.kt @@ -21,7 +21,7 @@ import com.malinskiy.adam.Const import com.malinskiy.adam.exception.RequestRejectedException import com.malinskiy.adam.request.transform.ResponseTransformer -class ShellResultResponseTransformer : ResponseTransformer { +public class ShellResultResponseTransformer : ResponseTransformer { override suspend fun process(bytes: ByteArray, offset: Int, limit: Int) { builder.write(bytes, 0, limit) } @@ -36,10 +36,11 @@ class ShellResultResponseTransformer : ResponseTransformer { } val stdout = output.substring(0 until indexOfDelimiter) val exitCodeString = output.substring(indexOfDelimiter + 1).trim() - val exitCode = exitCodeString.toIntOrNull() ?: throw RequestRejectedException("Unexpected exit code value $exitCodeString") + val exitCode = + exitCodeString.toIntOrNull() ?: throw RequestRejectedException("Unexpected exit code value $exitCodeString") return ShellCommandResult( stdout = stdout.toByteArray(Const.DEFAULT_TRANSPORT_ENCODING), - exitCode = exitCode + exitCode = exitCode, ) } } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/shell/v1/SyncShellCommandRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/shell/v1/SyncShellCommandRequest.kt index 341c5e763..d1cf8d4bb 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/shell/v1/SyncShellCommandRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/shell/v1/SyncShellCommandRequest.kt @@ -24,20 +24,24 @@ import com.malinskiy.adam.request.Target * shell v1 service doesn't support exit codes * we append an `echo $?` at the end to print the exit code as well and parse it */ -abstract class SyncShellCommandRequest(val cmd: String, target: Target = NonSpecifiedTarget) : +public abstract class SyncShellCommandRequest(public val cmd: String, target: Target = NonSpecifiedTarget) : SynchronousRequest(target) { /** * Descendants should override this method to map the response to appropriate output */ - abstract fun convertResult(response: ShellCommandResult): T + public abstract fun convertResult(response: ShellCommandResult): T private val responseTransformer = ShellResultResponseTransformer() - override suspend fun process(bytes: ByteArray, offset: Int, limit: Int) = responseTransformer.process(bytes, offset, limit) - override fun transform() = convertResult(responseTransformer.transform()) - override fun serialize() = createBaseRequest("shell:$cmd;echo ${EXIT_CODE_DELIMITER}$?") + override suspend fun process( + bytes: ByteArray, + offset: Int, + limit: Int, + ): Unit = responseTransformer.process(bytes, offset, limit) + override fun transform(): T = convertResult(responseTransformer.transform()) + override fun serialize(): ByteArray = createBaseRequest("shell:$cmd;echo ${EXIT_CODE_DELIMITER}$?") - companion object { - const val EXIT_CODE_DELIMITER = 'x' + public companion object { + public const val EXIT_CODE_DELIMITER: Char = 'x' } -} \ No newline at end of file +} diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/shell/v2/ChanneledShellCommandRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/shell/v2/ChanneledShellCommandRequest.kt index 4b313fc2c..5012597a6 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/shell/v2/ChanneledShellCommandRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/shell/v2/ChanneledShellCommandRequest.kt @@ -24,7 +24,7 @@ import com.malinskiy.adam.transport.withMaxPacketBuffer import kotlinx.coroutines.channels.ReceiveChannel import kotlinx.coroutines.channels.SendChannel -open class ChanneledShellCommandRequest( +public open class ChanneledShellCommandRequest( private val cmd: String, channel: ReceiveChannel, target: Target = NonSpecifiedTarget, @@ -32,7 +32,7 @@ open class ChanneledShellCommandRequest( ) : AsyncChannelRequest( target = target, channel = channel, - socketIdleTimeout = socketIdleTimeout + socketIdleTimeout = socketIdleTimeout, ) { override suspend fun readElement(socket: Socket, sendChannel: SendChannel): Boolean { @@ -60,7 +60,7 @@ open class ChanneledShellCommandRequest( } MessageType.EXIT -> { - //ignoredLength + // ignoredLength socket.readIntLittleEndian() val exitCode = socket.readByte().toInt() sendChannel.send(ShellCommandResultChunk(exitCode = exitCode)) @@ -90,13 +90,13 @@ open class ChanneledShellCommandRequest( } } - override fun serialize() = createBaseRequest("shell,v2,raw:$cmd") + override fun serialize(): ByteArray = createBaseRequest("shell,v2,raw:$cmd") } -data class ShellCommandResultChunk( - val stdout: ByteArray? = null, - val stderr: ByteArray? = null, - val exitCode: Int? = null +public data class ShellCommandResultChunk( + public val stdout: ByteArray? = null, + public val stderr: ByteArray? = null, + public val exitCode: Int? = null, ) { override fun equals(other: Any?): Boolean { if (this === other) return true @@ -107,11 +107,15 @@ data class ShellCommandResultChunk( if (stdout != null) { if (other.stdout == null) return false if (!stdout.contentEquals(other.stdout)) return false - } else if (other.stdout != null) return false + } else if (other.stdout != null) { + return false + } if (stderr != null) { if (other.stderr == null) return false if (!stderr.contentEquals(other.stderr)) return false - } else if (other.stderr != null) return false + } else if (other.stderr != null) { + return false + } if (exitCode != other.exitCode) return false return true @@ -125,9 +129,9 @@ data class ShellCommandResultChunk( } } -data class ShellCommandInputChunk( - val stdin: ByteArray? = null, - val close: Boolean = false +public data class ShellCommandInputChunk( + public val stdin: ByteArray? = null, + public val close: Boolean = false, ) { override fun equals(other: Any?): Boolean { if (this === other) return true @@ -138,7 +142,9 @@ data class ShellCommandInputChunk( if (stdin != null) { if (other.stdin == null) return false if (!stdin.contentEquals(other.stdin)) return false - } else if (other.stdin != null) return false + } else if (other.stdin != null) { + return false + } if (close != other.close) return false return true diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/shell/v2/MessageType.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/shell/v2/MessageType.kt index bfbfd45c1..aa21b92e9 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/shell/v2/MessageType.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/shell/v2/MessageType.kt @@ -16,7 +16,7 @@ package com.malinskiy.adam.request.shell.v2 -enum class MessageType { +public enum class MessageType { STDIN, STDOUT, STDERR, @@ -35,9 +35,11 @@ enum class MessageType { /** * Indicates an invalid or unknown packet */ - INVALID; + INVALID, - fun toValue() = when (this) { + ; + + public fun toValue(): Int = when (this) { STDIN -> 0 STDOUT -> 1 STDERR -> 2 @@ -47,8 +49,8 @@ enum class MessageType { INVALID -> 255 } - companion object { - fun of(value: Int) = when (value) { + public companion object { + public fun of(value: Int): MessageType = when (value) { 0 -> STDIN 1 -> STDOUT 2 -> STDERR @@ -58,4 +60,4 @@ enum class MessageType { else -> INVALID } } -} \ No newline at end of file +} diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/shell/v2/ShellCommandRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/shell/v2/ShellCommandRequest.kt index 25b0d039c..61fc36b39 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/shell/v2/ShellCommandRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/shell/v2/ShellCommandRequest.kt @@ -16,7 +16,7 @@ package com.malinskiy.adam.request.shell.v2 -open class ShellCommandRequest(cmd: String, socketIdleTimeout: Long? = null) : +public open class ShellCommandRequest(cmd: String, socketIdleTimeout: Long? = null) : SyncShellCommandRequest(cmd, socketIdleTimeout = socketIdleTimeout) { - override fun convertResult(response: ShellCommandResult) = response -} \ No newline at end of file + override fun convertResult(response: ShellCommandResult): ShellCommandResult = response +} diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/shell/v2/ShellCommandResult.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/shell/v2/ShellCommandResult.kt index f4daa0797..5f3962676 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/shell/v2/ShellCommandResult.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/shell/v2/ShellCommandResult.kt @@ -18,16 +18,16 @@ package com.malinskiy.adam.request.shell.v2 import com.malinskiy.adam.Const -data class ShellCommandResult( - val stdout: ByteArray, - val stderr: ByteArray, - val exitCode: Int +public data class ShellCommandResult( + public val stdout: ByteArray, + public val stderr: ByteArray, + public val exitCode: Int, ) { - val output: String by lazy { + public val output: String by lazy { String(stdout, Const.DEFAULT_TRANSPORT_ENCODING) } - val errorOutput: String by lazy { + public val errorOutput: String by lazy { String(stderr, Const.DEFAULT_TRANSPORT_ENCODING) } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/shell/v2/SyncShellCommandRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/shell/v2/SyncShellCommandRequest.kt index 505ccb774..8ad3f56fd 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/shell/v2/SyncShellCommandRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/shell/v2/SyncShellCommandRequest.kt @@ -27,7 +27,11 @@ import com.malinskiy.adam.transport.withMaxPacketBuffer /** * shell v2 service required for this request */ -abstract class SyncShellCommandRequest(val cmd: String, target: Target = NonSpecifiedTarget, socketIdleTimeout: Long? = null) : +public abstract class SyncShellCommandRequest( + public val cmd: String, + target: Target = NonSpecifiedTarget, + socketIdleTimeout: Long? = null, +) : ComplexRequest(target, socketIdleTimeout) { private val stdoutBuilder = ByteStreams.newDataOutput() @@ -37,9 +41,9 @@ abstract class SyncShellCommandRequest(val cmd: String, target: Target /** * Descendants should override this method to map the response to appropriate output */ - abstract fun convertResult(response: ShellCommandResult): T + public abstract fun convertResult(response: ShellCommandResult): T - override fun serialize() = createBaseRequest("shell,v2,raw:$cmd") + override fun serialize(): ByteArray = createBaseRequest("shell,v2,raw:$cmd") override suspend fun readElement(socket: Socket): T { withMaxPacketBuffer { val data = array() @@ -66,7 +70,7 @@ abstract class SyncShellCommandRequest(val cmd: String, target: Target } MessageType.EXIT -> { - //ignoredLength + // ignoredLength socket.readIntLittleEndian() exitCode = socket.readByte().toInt() break@loop @@ -82,7 +86,7 @@ abstract class SyncShellCommandRequest(val cmd: String, target: Target val shellCommandResult = ShellCommandResult( stdout = stdoutBuilder.toByteArray(), stderr = stderrBuilder.toByteArray(), - exitCode = exitCode + exitCode = exitCode, ) return convertResult(shellCommandResult) diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/sync/BFFSearch.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/sync/BFFSearch.kt index b0f97092d..e72b0e995 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/sync/BFFSearch.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/sync/BFFSearch.kt @@ -22,7 +22,13 @@ internal class BFFSearch { suspend fun execute( source: S, destination: D, - visitor: suspend (currentDir: S, newDirs: MutableList, newFiles: MutableList, newTargetDirs: MutableList, destinationRoot: D) -> Unit + visitor: suspend ( + currentDir: S, + newDirs: MutableList, + newFiles: MutableList, + newTargetDirs: MutableList, + destinationRoot: D, + ) -> Unit, ): Pair, List> { /** * Iterate instead of recursion @@ -32,7 +38,7 @@ internal class BFFSearch { var directoriesToTraverse = listOf(source) while (directoriesToTraverse.isNotEmpty()) { - //We have to use a second collection because we're iterating over directoriesToTraverse + // We have to use a second collection because we're iterating over directoriesToTraverse val currentDepthDirs = mutableListOf() for (dir in directoriesToTraverse) { visitor(dir, currentDepthDirs, fileList, dirList, destination) diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/sync/PullRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/sync/PullRequest.kt index d1bf3554d..a7547950e 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/sync/PullRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/sync/PullRequest.kt @@ -47,11 +47,11 @@ import kotlin.coroutines.CoroutineContext * @param source can be a file or a directory */ @Features(Feature.SENDRECV_V2, Feature.STAT_V2, Feature.LS_V2) -class PullRequest( +public class PullRequest( private val source: String, private val destination: File, private val supportedFeatures: List, - override val coroutineContext: CoroutineContext = Dispatchers.IO + override val coroutineContext: CoroutineContext = Dispatchers.IO, ) : MultiRequest(), CoroutineScope { /** @@ -69,8 +69,8 @@ class PullRequest( } remoteFileEntry.isRegularFile() || - remoteFileEntry.isBlockDevice() || - remoteFileEntry.isCharDevice() -> { + remoteFileEntry.isBlockDevice() || + remoteFileEntry.isCharDevice() -> { doPullFile(source, destination, remoteFileEntry.size().toLong(), serial) } @@ -78,16 +78,17 @@ class PullRequest( throw PushFailedException( "Source $source exists and is not a directory or a file: mode=${ remoteFileEntry.mode.toString( - 8 + 8, ) - }" + }", ) } !remoteFileEntry.exists() -> { throw PushFailedException("Source $source doesn't exist") } - //We exhausted all conditions above. This is just to make the compiler happy + + // We exhausted all conditions above. This is just to make the compiler happy else -> false } } @@ -102,8 +103,8 @@ class PullRequest( } remoteFileEntry.isRegularFile() || - remoteFileEntry.isBlockDevice() || - remoteFileEntry.isCharDevice() -> { + remoteFileEntry.isBlockDevice() || + remoteFileEntry.isCharDevice() -> { val name = source.substringAfterLast(Const.ANDROID_FILE_SEPARATOR) doPullFile(source, File(destination, name), remoteFileEntry.size().toLong(), serial) } @@ -112,16 +113,17 @@ class PullRequest( throw PushFailedException( "Source $source exists and is not a directory or a file: mode=${ remoteFileEntry.mode.toString( - 8 + 8, ) - }" + }", ) } !remoteFileEntry.exists() -> { throw PushFailedException("Source $source doesn't exist") } - //We exhausted all conditions above. This is just to make the compiler happy + + // We exhausted all conditions above. This is just to make the compiler happy else -> false } } @@ -138,17 +140,17 @@ class PullRequest( private suspend fun AndroidDebugBridgeClient.pullFolder( destination: File, - serial: String? + serial: String?, ): Boolean { - val (filesToPull, _) = BFFSearch().execute( source, - destination + destination, ) { currentDir, newDirs, newFiles, _, destinationRoot -> val ls = execute(CompatListFileRequest(currentDir, supportedFeatures), serial) for (file in ls.filterNot { Const.SYNC_IGNORED_FILES.contains(it.name) }) { when { file.isDirectory() -> newDirs.add(currentDir + Const.ANDROID_FILE_SEPARATOR + file.name) + file.isRegularFile() && file.size() == 0L.toULong() -> { val remotePath = currentDir + Const.ANDROID_FILE_SEPARATOR + file.name val remoteRelativePath = remotePath.substringAfter(source) @@ -168,8 +170,8 @@ class PullRequest( remote = remotePath, mtime = file.mtime.epochSecond, mode = file.mode, - size = file.size() - ) + size = file.size(), + ), ) } } @@ -191,11 +193,11 @@ class PullRequest( source: String, realDestination: File, size: Long, - serial: String? + serial: String?, ): Boolean { val channel = execute( CompatPullFileRequest(source, realDestination, supportedFeatures, this@PullRequest, size, coroutineContext), - serial + serial, ) var progress = 0.0 for (update in channel) { diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/sync/PushRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/sync/PushRequest.kt index d2f3e8daa..bc603eeef 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/sync/PushRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/sync/PushRequest.kt @@ -44,12 +44,12 @@ import kotlin.coroutines.CoroutineContext * @param source can be a file or a directory */ @Features(Feature.SENDRECV_V2, Feature.STAT_V2, Feature.LS_V2) -class PushRequest( +public class PushRequest( private val source: File, private val destination: String, private val supportedFeatures: List, private val mode: String = "0777", - override val coroutineContext: CoroutineContext = Dispatchers.IO + override val coroutineContext: CoroutineContext = Dispatchers.IO, ) : MultiRequest(), CoroutineScope { /** @@ -63,57 +63,67 @@ class PushRequest( source.isFile -> { when { remoteFileEntry.isDirectory() -> { - //Put into folder + // Put into folder doPushFile( source, - destination.removeSuffix(Const.ANDROID_FILE_SEPARATOR) + Const.ANDROID_FILE_SEPARATOR + source.name, + destination.removeSuffix(Const.ANDROID_FILE_SEPARATOR) + Const.ANDROID_FILE_SEPARATOR + + source.name, mode, - serial + serial, ) } + remoteFileEntry.isRegularFile() || !remoteFileEntry.exists() -> { doPushFile(source, destination, mode, serial) } + else -> { throw PushFailedException( "Target $destination exists and is not a directory or a file: mode=${ remoteFileEntry.mode.toString( - 8 + 8, ) - }" + }", ) } } } + source.isDirectory -> { when { remoteFileEntry.isDirectory() -> { - //Put into subfolder + // Put into subfolder pushFolder( - destination.removeSuffix(Const.ANDROID_FILE_SEPARATOR) + Const.ANDROID_FILE_SEPARATOR + source.name, - serial + destination.removeSuffix(Const.ANDROID_FILE_SEPARATOR) + Const.ANDROID_FILE_SEPARATOR + + source.name, + serial, ) } + remoteFileEntry.isRegularFile() -> { throw PushFailedException("Can't push folder $source: target $destination is a file") } + !remoteFileEntry.exists() -> { pushFolder(destination.removeSuffix(Const.ANDROID_FILE_SEPARATOR), serial) } + else -> { throw PushFailedException( "Target $destination exists and is not a directory or a file: mode=${ remoteFileEntry.mode.toString( - 8 + 8, ) - }" + }", ) } } } + !source.exists() -> { throw PushFailedException("Source $source doesn't exist") } + else -> { throw PushFailedException("Source $source is not a directory or a file") } @@ -126,7 +136,7 @@ class PushRequest( private suspend fun AndroidDebugBridgeClient.pushFolder(destination: String, serial: String?): Boolean { val (filesToPush, dirsToCreate) = BFFSearch().execute( source, - destination + destination, ) { currentDir, newDirs, newFiles, newTargetDirs, destinationRoot -> val ls = currentDir.listFiles()?.filterNot { Const.SYNC_IGNORED_FILES.contains(it.name) } if (ls.isNullOrEmpty()) return@execute @@ -138,6 +148,7 @@ class PushRequest( newTargetDirs.add(destinationRoot + Const.ANDROID_FILE_SEPARATOR + remoteRelativePath) newDirs.add(file) } + file.isFile -> { newFiles.add( SyncFile( @@ -145,8 +156,8 @@ class PushRequest( remote = destinationRoot + Const.ANDROID_FILE_SEPARATOR + remoteRelativePath, mtime = file.lastModified() / 1000, mode = mode.toUInt(8) and "0777".toUInt(8), - size = file.length().toULong() - ) + size = file.length().toULong(), + ), ) } } @@ -170,7 +181,7 @@ class PushRequest( private suspend fun AndroidDebugBridgeClient.createRemoteDirectories( destination: String, serial: String?, - dirsToCreate: List + dirsToCreate: List, ) { execute(ShellCommandRequest("mkdir -p ${listOf(destination).bashEscape()}"), serial) @@ -179,7 +190,7 @@ class PushRequest( val limit = 1024 * 4 for (dir in dirsToCreate) { val escapedDirArg = " ${listOf(dir).bashEscape()}" - //This check might fail for multi-byte encodings + // This check might fail for multi-byte encodings if (cmdBuilder.length + escapedDirArg.length > limit) { execute(ShellCommandRequest(cmdBuilder.toString()), serial) cmdBuilder.clear() @@ -200,11 +211,11 @@ class PushRequest( source: File, destination: String, mode: String, - serial: String? + serial: String?, ): Boolean { val channel = execute( CompatPushFileRequest(source, destination, supportedFeatures, this@PushRequest, mode, coroutineContext), - serial + serial, ) var progress = 0.0 for (update in channel) { diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/sync/base/BasePullFileRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/sync/base/BasePullFileRequest.kt index 7563be2e6..0b336b4ed 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/sync/base/BasePullFileRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/sync/base/BasePullFileRequest.kt @@ -37,20 +37,20 @@ import kotlin.coroutines.CoroutineContext /** * @param coroutineContext if you don't specify your context then you'll have no control over the `wait for file to finish writing`: closing the channel doesn't close the underlying resources */ -abstract class BasePullFileRequest( +public abstract class BasePullFileRequest( private val remotePath: String, local: File, private val size: Long? = null, - coroutineContext: CoroutineContext = Dispatchers.IO + coroutineContext: CoroutineContext = Dispatchers.IO, ) : AsyncChannelRequest() { private val fileWriter = AsyncFileWriter(local, coroutineContext) - var totalBytes = -1L - var currentPosition = 0L + public var totalBytes: Long = -1L + public var currentPosition: Long = 0L override suspend fun handshake(socket: Socket) { super.handshake(socket) - //If we don't have expected size, fetch it + // If we don't have expected size, fetch it totalBytes = size ?: StatFileRequest(remotePath).readElement(socket).size.toLong() if (totalBytes > 0) { fileWriter.start() @@ -73,6 +73,7 @@ abstract class BasePullFileRequest( } true } + header.contentEquals(Const.Message.DATA) -> { val available = data.copyOfRange(4, 8).toInt() if (available > Const.MAX_FILE_PACKET_LENGTH) { @@ -88,6 +89,7 @@ abstract class BasePullFileRequest( sendChannel.send(currentPosition.toDouble() / totalBytes) false } + header.contentEquals(Const.Message.FAIL) -> { val size = data.copyOfRange(4, 8).toInt() compatClear() @@ -98,14 +100,15 @@ abstract class BasePullFileRequest( val errorMessage = String(array(), 0, size) throw PullFailedException("Failed to pull file $remotePath: $errorMessage") } + else -> { throw UnsupportedSyncProtocolException( "Unexpected header message ${ String( header, - Const.DEFAULT_TRANSPORT_ENCODING + Const.DEFAULT_TRANSPORT_ENCODING, ) - }" + }", ) } } @@ -121,7 +124,7 @@ abstract class BasePullFileRequest( } } - override fun serialize() = createBaseRequest("sync:") + override fun serialize(): ByteArray = createBaseRequest("sync:") override fun validate(): ValidationResponse { return if (remotePath.length > Const.MAX_REMOTE_PATH_LENGTH) { @@ -131,6 +134,5 @@ abstract class BasePullFileRequest( } } - override suspend fun writeElement(element: Unit, socket: Socket) = Unit - + override suspend fun writeElement(element: Unit, socket: Socket): Unit = Unit } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/sync/base/BasePushFileRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/sync/base/BasePushFileRequest.kt index 5bd4716d2..99c24cb17 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/sync/base/BasePushFileRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/sync/base/BasePushFileRequest.kt @@ -32,21 +32,21 @@ import kotlinx.coroutines.channels.SendChannel import java.io.File import kotlin.coroutines.CoroutineContext -abstract class BasePushFileRequest( +public abstract class BasePushFileRequest( private val local: File, protected val remotePath: String, protected val mode: String = "0777", - coroutineContext: CoroutineContext = Dispatchers.IO + coroutineContext: CoroutineContext = Dispatchers.IO, ) : AsyncChannelRequest() { - protected val fileReader = AsyncFileReader( + protected val fileReader: AsyncFileReader = AsyncFileReader( file = local, start = 0, offset = 8, length = Const.MAX_FILE_PACKET_LENGTH - 8, - coroutineContext = coroutineContext + coroutineContext = coroutineContext, ) - protected var totalBytes = local.length() - protected var currentPosition = 0L + protected var totalBytes: Long = local.length() + protected var currentPosition: Long = 0L protected val modeValue: Int get() = mode.toInt(8) and "0777".toInt(8) @@ -73,9 +73,12 @@ abstract class BasePushFileRequest( sendChannel.send(1.0) true } else { - throw PushFailedException("adb didn't acknowledge the file transfer: ${transportResponse.message ?: ""}") + throw PushFailedException( + "adb didn't acknowledge the file transfer: ${transportResponse.message ?: ""}", + ) } } + buffer.limit() > 0 -> { Const.Message.DATA.copyInto(buffer.array()) val available = buffer.limit() - 8 @@ -88,6 +91,7 @@ abstract class BasePushFileRequest( sendChannel.send(currentPosition.toDouble() / totalBytes) false } + else -> false } } finally { @@ -96,13 +100,13 @@ abstract class BasePushFileRequest( } } - override fun serialize() = createBaseRequest("sync:") + override fun serialize(): ByteArray = createBaseRequest("sync:") override suspend fun close(channel: SendChannel) { fileReader.close() } - override suspend fun writeElement(element: Unit, socket: Socket) = Unit + override suspend fun writeElement(element: Unit, socket: Socket): Unit = Unit override fun validate(): ValidationResponse { val response = super.validate() diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/sync/compat/CompatListFileRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/sync/compat/CompatListFileRequest.kt index 46ee11a44..0cf5411d5 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/sync/compat/CompatListFileRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/sync/compat/CompatListFileRequest.kt @@ -23,16 +23,17 @@ import com.malinskiy.adam.request.sync.model.FileEntry import com.malinskiy.adam.request.sync.v1.ListFileRequest import com.malinskiy.adam.request.sync.v2.ListFileRequest as ListV2FileRequest -class CompatListFileRequest( +public class CompatListFileRequest( private val path: String, - private val supportedFeatures: List + private val supportedFeatures: List, ) : MultiRequest>() { override suspend fun execute(androidDebugBridgeClient: AndroidDebugBridgeClient, serial: String?): List { return when { supportedFeatures.contains(Feature.LS_V2) -> androidDebugBridgeClient.execute( ListV2FileRequest(path, supportedFeatures), - serial + serial, ) + else -> androidDebugBridgeClient.execute(ListFileRequest(path), serial) } } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/sync/compat/CompatPullFileRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/sync/compat/CompatPullFileRequest.kt index a3e6b2d27..0e3f3642e 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/sync/compat/CompatPullFileRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/sync/compat/CompatPullFileRequest.kt @@ -30,28 +30,32 @@ import com.malinskiy.adam.request.sync.v2.PullFileRequest as PullV2FileRequest /** * @param coroutineContext if you don't specify your context then you'll have no control over the `wait for file to finish writing`: closing the channel doesn't close the underlying resources */ -class CompatPullFileRequest( +public class CompatPullFileRequest( private val source: String, private val realDestination: File, private val supportedFeatures: List, private val coroutineScope: CoroutineScope, private val size: Long? = null, - private val coroutineContext: CoroutineContext = Dispatchers.IO + private val coroutineContext: CoroutineContext = Dispatchers.IO, ) : MultiRequest>() { - override suspend fun execute(androidDebugBridgeClient: AndroidDebugBridgeClient, serial: String?): ReceiveChannel { + override suspend fun execute( + androidDebugBridgeClient: AndroidDebugBridgeClient, + serial: String?, + ): ReceiveChannel { return when { supportedFeatures.contains(Feature.SENDRECV_V2) -> { androidDebugBridgeClient.execute( PullV2FileRequest(source, realDestination, supportedFeatures, size, coroutineContext), coroutineScope, - serial + serial, ) } + else -> { androidDebugBridgeClient.execute( PullFileRequest(source, realDestination, size, coroutineContext), coroutineScope, - serial + serial, ) } } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/sync/compat/CompatPushFileRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/sync/compat/CompatPushFileRequest.kt index 78e4bca05..74d89433d 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/sync/compat/CompatPushFileRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/sync/compat/CompatPushFileRequest.kt @@ -27,28 +27,32 @@ import java.io.File import kotlin.coroutines.CoroutineContext import com.malinskiy.adam.request.sync.v2.PushFileRequest as PushV2FileRequest -class CompatPushFileRequest( +public class CompatPushFileRequest( private val source: File, private val destination: String, private val supportedFeatures: List, private val coroutineScope: CoroutineScope, private val mode: String = "0777", - private val coroutineContext: CoroutineContext = Dispatchers.IO + private val coroutineContext: CoroutineContext = Dispatchers.IO, ) : MultiRequest>() { - override suspend fun execute(androidDebugBridgeClient: AndroidDebugBridgeClient, serial: String?): ReceiveChannel { + override suspend fun execute( + androidDebugBridgeClient: AndroidDebugBridgeClient, + serial: String?, + ): ReceiveChannel { return when { supportedFeatures.contains(Feature.SENDRECV_V2) -> { androidDebugBridgeClient.execute( PushV2FileRequest(source, destination, supportedFeatures, mode, false, coroutineContext), coroutineScope, - serial + serial, ) } + else -> { androidDebugBridgeClient.execute( PushFileRequest(source, destination, mode, coroutineContext), coroutineScope, - serial + serial, ) } } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/sync/compat/CompatStatFileRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/sync/compat/CompatStatFileRequest.kt index 37c3f576e..0055d9c2a 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/sync/compat/CompatStatFileRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/sync/compat/CompatStatFileRequest.kt @@ -23,16 +23,17 @@ import com.malinskiy.adam.request.sync.model.FileEntry import com.malinskiy.adam.request.sync.v1.StatFileRequest import com.malinskiy.adam.request.sync.v2.StatFileRequest as StatV2FileRequest -class CompatStatFileRequest( +public class CompatStatFileRequest( private val source: String, - private val supportedFeatures: List + private val supportedFeatures: List, ) : MultiRequest() { override suspend fun execute(androidDebugBridgeClient: AndroidDebugBridgeClient, serial: String?): FileEntry { return when { supportedFeatures.contains(Feature.STAT_V2) -> androidDebugBridgeClient.execute( StatV2FileRequest(source, supportedFeatures), - serial + serial, ) + else -> androidDebugBridgeClient.execute(StatFileRequest(source), serial) } } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/sync/model/FileEntry.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/sync/model/FileEntry.kt index 2c3a5989b..04a038cfb 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/sync/model/FileEntry.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/sync/model/FileEntry.kt @@ -19,47 +19,47 @@ package com.malinskiy.adam.request.sync.model import com.malinskiy.adam.Const import java.time.Instant -sealed class FileEntry { - abstract val mode: UInt - abstract val name: String? - abstract val mtime: Instant +public sealed class FileEntry { + public abstract val mode: UInt + public abstract val name: String? + public abstract val mtime: Instant - fun isDirectory() = (mode and Const.FileType.S_IFDIR) == Const.FileType.S_IFDIR - fun isRegularFile() = (mode and Const.FileType.S_IFREG) == Const.FileType.S_IFREG - fun isBlockDevice() = (mode and Const.FileType.S_IFBLK) == Const.FileType.S_IFBLK - fun isCharDevice() = (mode and Const.FileType.S_IFCHR) == Const.FileType.S_IFCHR - fun isLink() = (mode and Const.FileType.S_IFLNK) == Const.FileType.S_IFLNK + public fun isDirectory(): Boolean = (mode and Const.FileType.S_IFDIR) == Const.FileType.S_IFDIR + public fun isRegularFile(): Boolean = (mode and Const.FileType.S_IFREG) == Const.FileType.S_IFREG + public fun isBlockDevice(): Boolean = (mode and Const.FileType.S_IFBLK) == Const.FileType.S_IFBLK + public fun isCharDevice(): Boolean = (mode and Const.FileType.S_IFCHR) == Const.FileType.S_IFCHR + public fun isLink(): Boolean = (mode and Const.FileType.S_IFLNK) == Const.FileType.S_IFLNK - fun size() = when (this) { + public fun size(): ULong = when (this) { is FileEntryV1 -> size.toLong().toULong() is FileEntryV2 -> size } - abstract fun exists(): Boolean + public abstract fun exists(): Boolean } -data class FileEntryV1( +public data class FileEntryV1( override val name: String? = null, override val mode: UInt, - val size: UInt, - override val mtime: Instant + public val size: UInt, + override val mtime: Instant, ) : FileEntry() { - override fun exists() = !(size == 0.toUInt() && mode == 0.toUInt() && mtime.epochSecond == 0L) + override fun exists(): Boolean = !(size == 0.toUInt() && mode == 0.toUInt() && mtime.epochSecond == 0L) } -data class FileEntryV2( - val error: UInt, - val dev: ULong, - val ino: ULong, +public data class FileEntryV2( + public val error: UInt, + public val dev: ULong, + public val ino: ULong, override val mode: UInt, - val nlink: UInt, - val uid: UInt, - val gid: UInt, - val size: ULong, - val atime: Instant, + public val nlink: UInt, + public val uid: UInt, + public val gid: UInt, + public val size: ULong, + public val atime: Instant, override val mtime: Instant, - val ctime: Instant, - override val name: String? = null + public val ctime: Instant, + override val name: String? = null, ) : FileEntry() { - override fun exists() = !(size == 0.toULong() && mode == 0.toUInt() && mtime.epochSecond == 0L) + override fun exists(): Boolean = !(size == 0.toULong() && mode == 0.toUInt() && mtime.epochSecond == 0L) } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/sync/model/SyncFile.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/sync/model/SyncFile.kt index 597c8c310..cb9751d01 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/sync/model/SyncFile.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/sync/model/SyncFile.kt @@ -23,5 +23,5 @@ internal data class SyncFile( val remote: String, val mtime: Long, val mode: UInt, - val size: ULong + val size: ULong, ) diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/sync/v1/ListFileRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/sync/v1/ListFileRequest.kt index d097718e4..6eead1a8b 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/sync/v1/ListFileRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/sync/v1/ListFileRequest.kt @@ -26,8 +26,8 @@ import com.malinskiy.adam.transport.Socket import com.malinskiy.adam.transport.withDefaultBuffer import java.time.Instant -class ListFileRequest( - private val remotePath: String +public class ListFileRequest( + private val remotePath: String, ) : ComplexRequest>() { override fun validate(): ValidationResponse { @@ -45,7 +45,6 @@ class ListFileRequest( val data = array() val result = mutableListOf() loop@ while (true) { - socket.readFully(data, 0, 4) when { data.copyOfRange(0, 4).contentEquals(Const.Message.DENT_V1) -> { @@ -61,11 +60,13 @@ class ListFileRequest( mode = mode, size = size, mtime = mtime, - name = String(data, 0, nameLength, Const.DEFAULT_TRANSPORT_ENCODING) - ) + name = String(data, 0, nameLength, Const.DEFAULT_TRANSPORT_ENCODING), + ), ) } + data.copyOfRange(0, 4).contentEquals(Const.Message.DONE) -> break@loop + else -> break@loop } } @@ -74,5 +75,5 @@ class ListFileRequest( } } - override fun serialize() = createBaseRequest("sync:") + override fun serialize(): ByteArray = createBaseRequest("sync:") } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/sync/v1/PullFileRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/sync/v1/PullFileRequest.kt index f8691f342..7851ce188 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/sync/v1/PullFileRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/sync/v1/PullFileRequest.kt @@ -27,11 +27,11 @@ import kotlin.coroutines.CoroutineContext /** * @param coroutineContext if you don't specify your context then you'll have no control over the `wait for file to finish writing`: closing the channel doesn't close the underlying resources */ -class PullFileRequest( +public class PullFileRequest( private val remotePath: String, local: File, size: Long? = null, - coroutineContext: CoroutineContext = Dispatchers.IO + coroutineContext: CoroutineContext = Dispatchers.IO, ) : BasePullFileRequest(remotePath, local, size, coroutineContext) { override suspend fun handshake(socket: Socket) { super.handshake(socket) diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/sync/v1/PushFileRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/sync/v1/PushFileRequest.kt index 710418077..1234d04c2 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/sync/v1/PushFileRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/sync/v1/PushFileRequest.kt @@ -26,11 +26,11 @@ import kotlinx.coroutines.Dispatchers import java.io.File import kotlin.coroutines.CoroutineContext -class PushFileRequest( +public class PushFileRequest( local: File, remotePath: String, mode: String = "0777", - coroutineContext: CoroutineContext = Dispatchers.IO + coroutineContext: CoroutineContext = Dispatchers.IO, ) : BasePushFileRequest(local, remotePath, mode, coroutineContext) { override suspend fun handshake(socket: Socket) { diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/sync/v1/StatFileRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/sync/v1/StatFileRequest.kt index 009185669..bd88baa9a 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/sync/v1/StatFileRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/sync/v1/StatFileRequest.kt @@ -30,8 +30,8 @@ import com.malinskiy.adam.transport.Socket import com.malinskiy.adam.transport.withDefaultBuffer import java.time.Instant -class StatFileRequest( - private val remotePath: String +public class StatFileRequest( + private val remotePath: String, ) : ComplexRequest() { override suspend fun readElement(socket: Socket): FileEntryV1 { socket.writeSyncRequest(Const.Message.LSTAT_V1, remotePath) @@ -47,7 +47,7 @@ class StatFileRequest( return FileEntryV1( mode = bytes.copyOfRange(4, 8).toUInt(), size = bytes.copyOfRange(8, 12).toUInt(), - mtime = Instant.ofEpochSecond(bytes.copyOfRange(12, 16).toInt().toLong()) + mtime = Instant.ofEpochSecond(bytes.copyOfRange(12, 16).toInt().toLong()), ) } } @@ -60,6 +60,5 @@ class StatFileRequest( } } - override fun serialize() = createBaseRequest("sync:") + override fun serialize(): ByteArray = createBaseRequest("sync:") } - diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/sync/v2/CompressionType.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/sync/v2/CompressionType.kt index 57d70c56e..9cb0bc631 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/sync/v2/CompressionType.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/sync/v2/CompressionType.kt @@ -16,13 +16,14 @@ package com.malinskiy.adam.request.sync.v2 -enum class CompressionType { +public enum class CompressionType { NONE, BROTLI, LZ4, - Zstd; + Zstd, + ; - fun toFlag() = when (this) { + public fun toFlag(): Int = when (this) { NONE -> 0 BROTLI -> 1 LZ4 -> 2 diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/sync/v2/ListFileRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/sync/v2/ListFileRequest.kt index b8bf77ad1..491048ffc 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/sync/v2/ListFileRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/sync/v2/ListFileRequest.kt @@ -32,9 +32,9 @@ import com.malinskiy.adam.transport.withDefaultBuffer import java.time.Instant @Features(Feature.LS_V2) -class ListFileRequest( +public class ListFileRequest( private val remotePath: String, - private val supportedFeatures: List + private val supportedFeatures: List, ) : ComplexRequest>() { override fun validate(): ValidationResponse { @@ -89,11 +89,13 @@ class ListFileRequest( atime = atime, mtime = mtime, ctime = ctime, - name = String(data, 0, nameLength, Const.DEFAULT_TRANSPORT_ENCODING) - ) + name = String(data, 0, nameLength, Const.DEFAULT_TRANSPORT_ENCODING), + ), ) } + data.copyOfRange(0, 4).contentEquals(Const.Message.DONE) -> break@loop + else -> break@loop } } @@ -102,5 +104,5 @@ class ListFileRequest( } } - override fun serialize() = createBaseRequest("sync:") + override fun serialize(): ByteArray = createBaseRequest("sync:") } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/sync/v2/PullFileRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/sync/v2/PullFileRequest.kt index 019da427c..ab5b163ea 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/sync/v2/PullFileRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/sync/v2/PullFileRequest.kt @@ -31,12 +31,12 @@ import kotlin.coroutines.CoroutineContext * @param coroutineContext if you don't specify your context then you'll have no control over the `wait for file to finish writing`: closing the channel doesn't close the underlying resources */ @Features(Feature.SENDRECV_V2) -class PullFileRequest( +public class PullFileRequest( private val remotePath: String, local: File, private val supportedFeatures: List, size: Long? = null, - coroutineContext: CoroutineContext = Dispatchers.IO + coroutineContext: CoroutineContext = Dispatchers.IO, ) : BasePullFileRequest(remotePath, local, size, coroutineContext) { /** * We don't have support for any compression, so the only value is NONE diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/sync/v2/PushFileRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/sync/v2/PushFileRequest.kt index 973b95091..b5ab19dde 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/sync/v2/PushFileRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/sync/v2/PushFileRequest.kt @@ -31,13 +31,13 @@ import kotlin.coroutines.CoroutineContext * @param dryRun if true, requires SENDRECV_V2_DRY_RUN_SEND */ @Features(Feature.SENDRECV_V2, Feature.SENDRECV_V2_DRY_RUN_SEND) -class PushFileRequest( +public class PushFileRequest( local: File, remotePath: String, - val supportedFeatures: List, + public val supportedFeatures: List, mode: String = "0777", - val dryRun: Boolean = false, - coroutineContext: CoroutineContext = Dispatchers.IO + public val dryRun: Boolean = false, + coroutineContext: CoroutineContext = Dispatchers.IO, ) : BasePushFileRequest(local, remotePath, mode, coroutineContext) { /** * We don't have support for any compression, so the only value is NONE @@ -67,7 +67,7 @@ class PushFileRequest( } } - companion object { - val DRY_RUN_FLAG = 0x8000_0000 + public companion object { + public val DRY_RUN_FLAG: Long = 0x8000_0000 } } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/sync/v2/StatFileRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/sync/v2/StatFileRequest.kt index d968eac88..50a5308cd 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/sync/v2/StatFileRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/sync/v2/StatFileRequest.kt @@ -32,9 +32,9 @@ import com.malinskiy.adam.transport.withDefaultBuffer import java.time.Instant @Features(Feature.STAT_V2) -class StatFileRequest( +public class StatFileRequest( private val remotePath: String, - private val supportedFeatures: List + private val supportedFeatures: List, ) : ComplexRequest() { override suspend fun readElement(socket: Socket): FileEntryV2 { socket.writeSyncRequest(Const.Message.LSTAT_V2, remotePath) @@ -56,7 +56,7 @@ class StatFileRequest( size = bytes.copyOfRange(40, 48).toULong(), atime = Instant.ofEpochSecond(bytes.copyOfRange(48, 56).toLong()), mtime = Instant.ofEpochSecond(bytes.copyOfRange(56, 64).toLong()), - ctime = Instant.ofEpochSecond(bytes.copyOfRange(64, 72).toLong()) + ctime = Instant.ofEpochSecond(bytes.copyOfRange(64, 72).toLong()), ) } } @@ -74,6 +74,5 @@ class StatFileRequest( } } - override fun serialize() = createBaseRequest("sync:") + override fun serialize(): ByteArray = createBaseRequest("sync:") } - diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/InstrumentOptions.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/InstrumentOptions.kt index d2714a98c..3671164b5 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/InstrumentOptions.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/InstrumentOptions.kt @@ -53,20 +53,20 @@ import java.util.* * @param coverageFile Overrides the default location of the EMMA coverage file on the device. * Specify this value as a path and filename in UNIX format. The default filename is described in the entry for the [emma] key. */ -data class InstrumentOptions( - val pkg: List = emptyList(), - val clazz: List = emptyList(), - val functional: Boolean? = null, - val unit: Boolean? = null, - val filterSize: InstrumentationSizeOption? = null, - val performance: Boolean? = null, - val debug: Boolean? = null, - val log: Boolean? = null, - val emma: Boolean? = null, - val coverageFile: String? = null, - val overrides: Map = mapOf() +public data class InstrumentOptions( + public val pkg: List = emptyList(), + public val clazz: List = emptyList(), + public val functional: Boolean? = null, + public val unit: Boolean? = null, + public val filterSize: InstrumentationSizeOption? = null, + public val performance: Boolean? = null, + public val debug: Boolean? = null, + public val log: Boolean? = null, + public val emma: Boolean? = null, + public val coverageFile: String? = null, + public val overrides: Map = mapOf(), ) { - override fun toString() = StringBuilder().apply { + override fun toString(): String = StringBuilder().apply { if (pkg.isNotEmpty()) append(" -e package " + pkg.joinToString(separator = ",")) if (clazz.isNotEmpty()) append(" -e class " + clazz.joinToString(separator = ",")) if (functional != null) append(" -e func $functional") diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/InstrumentationSizeOption.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/InstrumentationSizeOption.kt index c63893037..c0f4d79ff 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/InstrumentationSizeOption.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/InstrumentationSizeOption.kt @@ -16,8 +16,8 @@ package com.malinskiy.adam.request.testrunner -enum class InstrumentationSizeOption { +public enum class InstrumentationSizeOption { SMALL, MEDIUM, - LARGE -} \ No newline at end of file + LARGE, +} diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/TestEvent.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/TestEvent.kt index d081ce7b9..03db48b64 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/TestEvent.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/TestEvent.kt @@ -16,16 +16,19 @@ package com.malinskiy.adam.request.testrunner -sealed class TestEvent +public sealed class TestEvent -data class TestRunStartedEvent(val testCount: Int) : TestEvent() -data class TestStarted(val id: TestIdentifier) : TestEvent() -data class TestFailed(val id: TestIdentifier, val stackTrace: String) : TestEvent() -data class TestAssumptionFailed(val id: TestIdentifier, val stackTrace: String) : TestEvent() -data class TestIgnored(val id: TestIdentifier) : TestEvent() -data class TestEnded(val id: TestIdentifier, val metrics: Map) : TestEvent() -data class TestRunFailed(val error: String) : TestEvent() -data class TestRunFailing(val error: String, val stackTrace: String) : TestEvent() -data class TestRunStopped(val elapsedTimeMillis: Long) : TestEvent() -data class TestRunEnded(val elapsedTimeMillis: Long, val metrics: Map) : TestEvent() -data class TestLogcat(val id: TestIdentifier, val log: String) +public data class TestRunStartedEvent(public val testCount: Int) : TestEvent() +public data class TestStarted(public val id: TestIdentifier) : TestEvent() +public data class TestFailed(public val id: TestIdentifier, public val stackTrace: String) : TestEvent() +public data class TestAssumptionFailed(public val id: TestIdentifier, public val stackTrace: String) : TestEvent() +public data class TestIgnored(public val id: TestIdentifier) : TestEvent() +public data class TestEnded(public val id: TestIdentifier, public val metrics: Map) : TestEvent() +public data class TestRunFailed(public val error: String) : TestEvent() +public data class TestRunFailing(public val error: String, public val stackTrace: String) : TestEvent() +public data class TestRunStopped(public val elapsedTimeMillis: Long) : TestEvent() +public data class TestRunEnded( + public val elapsedTimeMillis: Long, + public val metrics: Map, +) : TestEvent() +public data class TestLogcat(public val id: TestIdentifier, public val log: String) diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/TestIdentifier.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/TestIdentifier.kt index 3da627ca6..a05d7762b 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/TestIdentifier.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/TestIdentifier.kt @@ -16,7 +16,7 @@ package com.malinskiy.adam.request.testrunner -data class TestIdentifier( - val className: String, - val testName: String +public data class TestIdentifier( + public val className: String, + public val testName: String, ) diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/TestRunnerRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/TestRunnerRequest.kt index d3ef45943..8848b31ec 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/TestRunnerRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/TestRunnerRequest.kt @@ -44,7 +44,7 @@ import java.io.File * * @see https://android.googlesource.com/platform/frameworks/base/+/master/cmds/am/src/com/android/commands/am/Am.java#155 */ -class TestRunnerRequest( +public class TestRunnerRequest( private val testPackage: String, private val instrumentOptions: InstrumentOptions, private val supportedFeatures: List, @@ -59,7 +59,7 @@ class TestRunnerRequest( private val outputLogPath: String? = null, private val protobuf: Boolean = false, private val dumpFile: File? = null, - socketIdleTimeout: Long? = Long.MAX_VALUE + socketIdleTimeout: Long? = Long.MAX_VALUE, ) : AsyncCompatShellCommandRequest>( cmd = StringBuilder().apply { append("am instrument -w -r") diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/model/SessionResultCode.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/model/SessionResultCode.kt index 79f3130fd..32314ab33 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/model/SessionResultCode.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/model/SessionResultCode.kt @@ -16,7 +16,7 @@ package com.malinskiy.adam.request.testrunner.model -enum class SessionResultCode(val value: Int) { +public enum class SessionResultCode(public val value: Int) { FINISHED(-1), - ERROR(0) + ERROR(0), } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/model/State.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/model/State.kt index 846a6d582..15015c223 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/model/State.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/model/State.kt @@ -16,9 +16,9 @@ package com.malinskiy.adam.request.testrunner.model -sealed class State(val terminal: Boolean) +public sealed class State(public val terminal: Boolean) -object NotStarted : State(false) -object Running : State(false) -object Finished : State(true) -object Cancelled : State(true) +public object NotStarted : State(false) +public object Running : State(false) +public object Finished : State(true) +public object Cancelled : State(true) diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/model/Status.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/model/Status.kt index 8676356ef..6cb1909b4 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/model/Status.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/model/Status.kt @@ -16,7 +16,7 @@ package com.malinskiy.adam.request.testrunner.model -enum class Status(val value: Int) { +public enum class Status(public val value: Int) { SUCCESS(0), START(1), IN_PROGRESS(2), @@ -28,12 +28,13 @@ enum class Status(val value: Int) { FAILURE(-2), IGNORED(-3), ASSUMPTION_FAILURE(-4), - UNKNOWN(6666); + UNKNOWN(6666), + ; - fun isTerminal() = value < 0 + public fun isTerminal(): Boolean = value < 0 - companion object { - fun valueOf(value: Int?): Status { + public companion object { + public fun valueOf(value: Int?): Status { return when (value) { 0 -> SUCCESS 1 -> START diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/model/StatusKey.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/model/StatusKey.kt index 5d0a2e323..de69b8463 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/model/StatusKey.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/model/StatusKey.kt @@ -16,7 +16,7 @@ package com.malinskiy.adam.request.testrunner.model -enum class StatusKey(val value: String) { +public enum class StatusKey(public val value: String) { TEST("test"), CLASS("class"), STACK("stack"), @@ -26,10 +26,11 @@ enum class StatusKey(val value: String) { STREAM("stream"), CURRENT("current"), ID("id"), - UNKNOWN(""); + UNKNOWN(""), + ; - companion object { - fun of(value: String?) = when (value) { + public companion object { + public fun of(value: String?): StatusKey = when (value) { "test" -> TEST "class" -> CLASS "stack" -> STACK diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/model/TestStatusAggregator.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/model/TestStatusAggregator.kt index 673b7aaa5..06967bd0b 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/model/TestStatusAggregator.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/model/TestStatusAggregator.kt @@ -18,8 +18,8 @@ package com.malinskiy.adam.request.testrunner.model import com.malinskiy.adam.Const -data class TestStatusAggregator( - var statusCode: Status, - val logcatBuilder: StringBuilder = StringBuilder(Const.MAX_PROTOBUF_LOGCAT_LENGTH), - val metrics: MutableMap = mutableMapOf() +public data class TestStatusAggregator( + public var statusCode: Status, + public val logcatBuilder: StringBuilder = StringBuilder(Const.MAX_PROTOBUF_LOGCAT_LENGTH), + public val metrics: MutableMap = mutableMapOf(), ) diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/model/TokenType.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/model/TokenType.kt index 01b615c9f..6e268d8cb 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/model/TokenType.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/model/TokenType.kt @@ -16,10 +16,10 @@ package com.malinskiy.adam.request.testrunner.model -enum class TokenType { +public enum class TokenType { INSTRUMENTATION_STATUS, INSTRUMENTATION_STATUS_CODE, INSTRUMENTATION_RESULT, INSTRUMENTATION_CODE, - INSTRUMENTATION_FAILED + INSTRUMENTATION_FAILED, } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/transform/InstrumentationResponseTransformer.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/transform/InstrumentationResponseTransformer.kt index fd43a2e3b..4d86f3f94 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/transform/InstrumentationResponseTransformer.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/transform/InstrumentationResponseTransformer.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 Anton Malinskiy + * Copyright (C) 2021 Anton Malinskiy * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,8 +31,8 @@ import com.malinskiy.adam.request.testrunner.TestStarted import com.malinskiy.adam.request.testrunner.model.Status import com.malinskiy.adam.request.testrunner.model.TokenType -class InstrumentationResponseTransformer : ProgressiveResponseTransformer?> { - var buffer = StringBuffer() +public class InstrumentationResponseTransformer : ProgressiveResponseTransformer?> { + public var buffer: StringBuffer = StringBuffer() private var startReported = false private var finishReported = false @@ -61,8 +61,8 @@ class InstrumentationResponseTransformer : ProgressiveResponseTransformer { parseStatusCode(last, atom.subList(0, atom.size - 1)) } + last.startsWith(TokenType.INSTRUMENTATION_CODE.name) -> { finished = true parseInstrumentationCode(last, atom) } + last.startsWith(TokenType.INSTRUMENTATION_FAILED.name) -> { finished = true null } + else -> null } } @@ -150,6 +153,7 @@ class InstrumentationResponseTransformer : ProgressiveResponseTransformer { val className = parameters["class"] val testName = parameters["test"] @@ -157,9 +161,11 @@ class InstrumentationResponseTransformer : ProgressiveResponseTransformer { testMetrics.putAll(parameters.filterKeys { !KNOWN_KEYS.contains(it) }) } + Status.ERROR, Status.FAILURE -> { val className = parameters["class"] val testName = parameters["test"] @@ -177,6 +183,7 @@ class InstrumentationResponseTransformer : ProgressiveResponseTransformer { val className = parameters["class"] val testName = parameters["test"] @@ -188,6 +195,7 @@ class InstrumentationResponseTransformer : ProgressiveResponseTransformer { val className = parameters["class"] val testName = parameters["test"] @@ -200,6 +208,7 @@ class InstrumentationResponseTransformer : ProgressiveResponseTransformer TODO() } @@ -217,7 +226,7 @@ class InstrumentationResponseTransformer : ProgressiveResponseTransformer + atom: List, ): List? { val value = last.substring(TokenType.INSTRUMENTATION_CODE.name.length + 1).trim() val code = value.toIntOrNull() @@ -238,6 +247,7 @@ class InstrumentationResponseTransformer : ProgressiveResponseTransformer { finishReported = true var shortMessage: String? = null @@ -247,18 +257,23 @@ class InstrumentationResponseTransformer : ProgressiveResponseTransformer { time = line.substring(6).toDoubleOrNull()?.times(1000)?.toLong() ?: 0L } } } - listOf(TestRunFailed(shortMessage ?: "Unexpected INSTRUMENTATION_CODE: $code"), TestRunEnded(time, emptyMap())) + listOf( + TestRunFailed(shortMessage ?: "Unexpected INSTRUMENTATION_CODE: $code"), + TestRunEnded(time, emptyMap()), + ) } } } - companion object { - val KNOWN_KEYS = setOf("test", "class", "stack", "numtests", "Error", "shortMsg", "stream", "current", "id") + public companion object { + public val KNOWN_KEYS: Set = + setOf("test", "class", "stack", "numtests", "Error", "shortMsg", "stream", "current", "id") } } @@ -276,4 +291,3 @@ private fun List.toMap(delimiter: String = "INSTRUMENTATION_STATUS: "): Pair(trimmed.substring(0, delimiterIndex), trimmed.substring(delimiterIndex + 1, trimmed.length)) }.toMap() } - diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/transform/ProtoInstrumentationResponseTransformer.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/transform/ProtoInstrumentationResponseTransformer.kt index d2a8e4cfc..6f527335f 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/transform/ProtoInstrumentationResponseTransformer.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/testrunner/transform/ProtoInstrumentationResponseTransformer.kt @@ -19,9 +19,26 @@ package com.malinskiy.adam.request.transform import com.android.commands.am.InstrumentationData import com.google.protobuf.InvalidProtocolBufferException import com.malinskiy.adam.Const -import com.malinskiy.adam.extension.* -import com.malinskiy.adam.request.testrunner.* -import com.malinskiy.adam.request.testrunner.model.* +import com.malinskiy.adam.extension.compatLimit +import com.malinskiy.adam.extension.compatPosition +import com.malinskiy.adam.request.testrunner.TestAssumptionFailed +import com.malinskiy.adam.request.testrunner.TestEnded +import com.malinskiy.adam.request.testrunner.TestEvent +import com.malinskiy.adam.request.testrunner.TestFailed +import com.malinskiy.adam.request.testrunner.TestIdentifier +import com.malinskiy.adam.request.testrunner.TestIgnored +import com.malinskiy.adam.request.testrunner.TestRunEnded +import com.malinskiy.adam.request.testrunner.TestRunFailed +import com.malinskiy.adam.request.testrunner.TestRunStartedEvent +import com.malinskiy.adam.request.testrunner.TestStarted +import com.malinskiy.adam.request.testrunner.model.Finished +import com.malinskiy.adam.request.testrunner.model.NotStarted +import com.malinskiy.adam.request.testrunner.model.Running +import com.malinskiy.adam.request.testrunner.model.SessionResultCode +import com.malinskiy.adam.request.testrunner.model.State +import com.malinskiy.adam.request.testrunner.model.Status +import com.malinskiy.adam.request.testrunner.model.StatusKey +import com.malinskiy.adam.request.testrunner.model.TestStatusAggregator import java.io.File import java.io.RandomAccessFile import java.nio.MappedByteBuffer @@ -42,7 +59,7 @@ import java.nio.channels.FileChannel * * see frameworks/base/cmds/am/src/com/android/commands/am/Instrument.java#readLogcat */ -class ProtoInstrumentationResponseTransformer(maxProtobufPacketLength: Long = Const.MAX_PROTOBUF_PACKET_LENGTH) : +public class ProtoInstrumentationResponseTransformer(maxProtobufPacketLength: Long = Const.MAX_PROTOBUF_PACKET_LENGTH) : ProgressiveResponseTransformer?> { private val backingFile = RandomAccessFile(File.createTempFile("tmp-proto", null, null), "rw") private val channel = backingFile.channel @@ -67,7 +84,10 @@ class ProtoInstrumentationResponseTransformer(maxProtobufPacketLength: Long = Co for (status in session.testStatusList ?: emptyList()) { if (state == NotStarted) { val testCount = - status.results?.entriesList?.filter { entry -> entry.key?.let { it == StatusKey.NUMTESTS.value } ?: false } + status.results?.entriesList?.filter { entry -> + entry.key?.let { it == StatusKey.NUMTESTS.value } + ?: false + } ?.mapNotNull { it.valueInt } ?.firstOrNull() ?: 0 @@ -86,10 +106,21 @@ class ProtoInstrumentationResponseTransformer(maxProtobufPacketLength: Long = Co if (entry.key != null) { when (StatusKey.of(entry.key)) { StatusKey.TEST -> testMethodName = entry.valueString ?: testClassName + StatusKey.CLASS -> testClassName = entry.valueString ?: testMethodName + StatusKey.STACK -> stackTrace = entry.valueString ?: stackTrace - StatusKey.CURRENT -> Unit //Test index - StatusKey.NUMTESTS, StatusKey.ERROR, StatusKey.SHORTMSG, StatusKey.STREAM, StatusKey.ID -> Unit + + StatusKey.CURRENT -> Unit + + // Test index + StatusKey.NUMTESTS, + StatusKey.ERROR, + StatusKey.SHORTMSG, + StatusKey.STREAM, + StatusKey.ID, + -> Unit + StatusKey.UNKNOWN -> testMetrics[entry.key] = entry.valueToString() } } @@ -101,7 +132,10 @@ class ProtoInstrumentationResponseTransformer(maxProtobufPacketLength: Long = Co testClassName = previousTestStatus.key.className testMethodName = previousTestStatus.key.testName resultCodeOverride = previousTestStatus.value.statusCode - } ?: run { testClassName = ""; testMethodName = "" } + } ?: run { + testClassName = "" + testMethodName = "" + } } if (testClassName.isNotBlank() && testMethodName.isNotBlank()) { @@ -112,8 +146,8 @@ class ProtoInstrumentationResponseTransformer(maxProtobufPacketLength: Long = Co resultCodeOverride ?: Status.valueOf(status.resultCode), status.logcat, stackTrace, - testMetrics - ) + testMetrics, + ), ) } } @@ -139,6 +173,7 @@ class ProtoInstrumentationResponseTransformer(maxProtobufPacketLength: Long = Co } } } + InstrumentationData.SessionStatusCode.SESSION_ABORTED -> { val errorText = session.sessionStatus.errorText ?: "" val lastTest = testStatuses.entries.lastOrNull() @@ -152,6 +187,7 @@ class ProtoInstrumentationResponseTransformer(maxProtobufPacketLength: Long = Co events.add(TestRunFailed(errorText)) } + else -> Unit } @@ -162,7 +198,9 @@ class ProtoInstrumentationResponseTransformer(maxProtobufPacketLength: Long = Co if (sessionOutput != null) { val matchResult = timeRegex.find(sessionOutput) - val elapsedTime = matchResult?.groups?.get(1)?.let { it.value.toFloatOrNull() }?.let { (it * 1000).toLong() } ?: 0L + val elapsedTime = + matchResult?.groups?.get(1)?.let { it.value.toFloatOrNull() }?.let { (it * 1000).toLong() } + ?: 0L events.add(TestRunEnded(elapsedTime, testRunMetrics)) } } @@ -179,7 +217,7 @@ class ProtoInstrumentationResponseTransformer(maxProtobufPacketLength: Long = Co return events } catch (e: InvalidProtocolBufferException) { - //wait for more input + // wait for more input buffer.compatPosition(buffer.limit()) return null } @@ -197,7 +235,7 @@ class ProtoInstrumentationResponseTransformer(maxProtobufPacketLength: Long = Co resultCode: Status, logcat: String?, stackTrace: String, - testMetrics: Map + testMetrics: Map, ): List { val id = TestIdentifier(className, methodName) var events = mutableListOf() @@ -217,13 +255,16 @@ class ProtoInstrumentationResponseTransformer(maxProtobufPacketLength: Long = Co Status.ERROR, Status.FAILURE -> { events.add(TestFailed(id, stackTrace)) } + Status.IGNORED -> { events.add(TestIgnored(id)) statusAggregator.logcatBuilder.clear() } + Status.ASSUMPTION_FAILURE -> { events.add(TestAssumptionFailed(id, stackTrace)) } + Status.SUCCESS, Status.START, Status.IN_PROGRESS, Status.UNKNOWN -> Unit } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/transform/DumpResponseTransformer.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/transform/DumpResponseTransformer.kt index a79e31fee..9fa94be38 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/transform/DumpResponseTransformer.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/transform/DumpResponseTransformer.kt @@ -22,7 +22,7 @@ import java.io.File import java.io.FileOutputStream import kotlin.coroutines.CoroutineContext -class DumpResponseTransformer( +public class DumpResponseTransformer( private val file: File, private val delegate: ProgressiveResponseTransformer, private val dumpContext: CoroutineContext = Dispatchers.IO, @@ -37,4 +37,4 @@ class DumpResponseTransformer( override fun transform(): T { return delegate.transform() } -} \ No newline at end of file +} diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/transform/ProgressiveResponseTransformer.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/transform/ProgressiveResponseTransformer.kt index 9af68d785..6cbad986d 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/transform/ProgressiveResponseTransformer.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/transform/ProgressiveResponseTransformer.kt @@ -16,7 +16,7 @@ package com.malinskiy.adam.request.transform -interface ProgressiveResponseTransformer { - suspend fun process(bytes: ByteArray, offset: Int, limit: Int): T - fun transform(): T +public interface ProgressiveResponseTransformer { + public suspend fun process(bytes: ByteArray, offset: Int, limit: Int): T + public fun transform(): T } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/transform/ResponseTransformer.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/transform/ResponseTransformer.kt index caa28f8c1..b26825407 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/transform/ResponseTransformer.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/transform/ResponseTransformer.kt @@ -16,7 +16,7 @@ package com.malinskiy.adam.request.transform -interface ResponseTransformer { - suspend fun process(bytes: ByteArray, offset: Int, limit: Int) - fun transform(): T +public interface ResponseTransformer { + public suspend fun process(bytes: ByteArray, offset: Int, limit: Int) + public fun transform(): T } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/transform/StringResponseTransformer.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/transform/StringResponseTransformer.kt index f86f992c7..56670e9d6 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/transform/StringResponseTransformer.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/transform/StringResponseTransformer.kt @@ -18,7 +18,7 @@ package com.malinskiy.adam.request.transform import com.malinskiy.adam.Const -class StringResponseTransformer : ResponseTransformer { +public class StringResponseTransformer : ResponseTransformer { override suspend fun process(bytes: ByteArray, offset: Int, limit: Int) { val part = String(bytes, 0, limit, Const.DEFAULT_TRANSPORT_ENCODING) builder.append(part) @@ -29,4 +29,4 @@ class StringResponseTransformer : ResponseTransformer { override fun transform(): String { return builder.toString().trim() } -} \ No newline at end of file +} diff --git a/adam/src/main/kotlin/com/malinskiy/adam/transport/BufferFactory.kt b/adam/src/main/kotlin/com/malinskiy/adam/transport/BufferFactory.kt index ddea67bc0..c10544be8 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/transport/BufferFactory.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/transport/BufferFactory.kt @@ -28,11 +28,14 @@ import java.nio.ByteOrder internal const val DEFAULT_BUFFER_SIZE = 4088 -val AdamDefaultPool: ByteBufferPool = ByteBufferPool(poolSize = Const.DEFAULT_BUFFER_SIZE, bufferSize = DEFAULT_BUFFER_SIZE) -val AdamMaxPacketPool: ByteBufferPool = ByteBufferPool(poolSize = Const.DEFAULT_BUFFER_SIZE, bufferSize = Const.MAX_PACKET_LENGTH) -val AdamMaxFilePacketPool: ByteBufferPool = ByteBufferPool(poolSize = Const.DEFAULT_BUFFER_SIZE, bufferSize = Const.MAX_FILE_PACKET_LENGTH) +public val AdamDefaultPool: ByteBufferPool = + ByteBufferPool(poolSize = Const.DEFAULT_BUFFER_SIZE, bufferSize = DEFAULT_BUFFER_SIZE) +public val AdamMaxPacketPool: ByteBufferPool = + ByteBufferPool(poolSize = Const.DEFAULT_BUFFER_SIZE, bufferSize = Const.MAX_PACKET_LENGTH) +public val AdamMaxFilePacketPool: ByteBufferPool = + ByteBufferPool(poolSize = Const.DEFAULT_BUFFER_SIZE, bufferSize = Const.MAX_FILE_PACKET_LENGTH) -class ByteBufferPool(private val poolSize: Int, private val bufferSize: Int) { +public class ByteBufferPool(private val poolSize: Int, private val bufferSize: Int) { private val delegate: GenericObjectPool by lazy { val config = GenericObjectPoolConfig().apply { maxTotal = poolSize @@ -41,12 +44,12 @@ class ByteBufferPool(private val poolSize: Int, private val bufferSize: Int) { GenericObjectPool(ByteBufferObjectFactory(bufferSize), config) } - fun borrow(): ByteBuffer = delegate.borrowObject() + public fun borrow(): ByteBuffer = delegate.borrowObject() - fun recycle(buffer: ByteBuffer) = delegate.returnObject(buffer) + public fun recycle(buffer: ByteBuffer): Unit = delegate.returnObject(buffer) } -class ByteBufferObjectFactory(private val bufferSize: Int) : PooledObjectFactory { +public class ByteBufferObjectFactory(private val bufferSize: Int) : PooledObjectFactory { override fun activateObject(p: PooledObject?) { p?.`object`?.apply { compatClear() @@ -79,7 +82,7 @@ class ByteBufferObjectFactory(private val bufferSize: Int) : PooledObjectFactory } } -inline fun withDefaultBuffer(block: ByteBuffer.() -> R): R { +public inline fun withDefaultBuffer(block: ByteBuffer.() -> R): R { val instance = AdamDefaultPool.borrow() return try { block(instance) @@ -88,7 +91,7 @@ inline fun withDefaultBuffer(block: ByteBuffer.() -> R): R { } } -inline fun withMaxPacketBuffer(block: ByteBuffer.() -> R): R { +public inline fun withMaxPacketBuffer(block: ByteBuffer.() -> R): R { val instance = AdamMaxPacketPool.borrow() return try { block(instance) @@ -97,7 +100,7 @@ inline fun withMaxPacketBuffer(block: ByteBuffer.() -> R): R { } } -inline fun withMaxFilePacketBuffer(block: ByteBuffer.() -> R): R { +public inline fun withMaxFilePacketBuffer(block: ByteBuffer.() -> R): R { val instance = AdamMaxFilePacketPool.borrow() return try { block(instance) diff --git a/adam/src/main/kotlin/com/malinskiy/adam/transport/Socket.kt b/adam/src/main/kotlin/com/malinskiy/adam/transport/Socket.kt index d89e78316..ff0178983 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/transport/Socket.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/transport/Socket.kt @@ -18,22 +18,22 @@ package com.malinskiy.adam.transport import java.nio.ByteBuffer -interface Socket : SuspendCloseable { - val isClosedForWrite: Boolean - val isClosedForRead: Boolean +public interface Socket : SuspendCloseable { + public val isClosedForWrite: Boolean + public val isClosedForRead: Boolean - suspend fun writeFully(byteBuffer: ByteBuffer) - suspend fun writeFully(byteArray: ByteArray, offset: Int, limit: Int) + public suspend fun writeFully(byteBuffer: ByteBuffer) + public suspend fun writeFully(byteArray: ByteArray, offset: Int, limit: Int) - suspend fun readAvailable(buffer: ByteArray, offset: Int, limit: Int): Int - suspend fun readFully(buffer: ByteBuffer): Int - suspend fun readFully(buffer: ByteArray, offset: Int, limit: Int) + public suspend fun readAvailable(buffer: ByteArray, offset: Int, limit: Int): Int + public suspend fun readFully(buffer: ByteBuffer): Int + public suspend fun readFully(buffer: ByteArray, offset: Int, limit: Int) - suspend fun readByte(): Byte - suspend fun writeByte(value: Int) + public suspend fun readByte(): Byte + public suspend fun writeByte(value: Int) - suspend fun readIntLittleEndian(): Int - suspend fun writeIntLittleEndian(value: Int) + public suspend fun readIntLittleEndian(): Int + public suspend fun writeIntLittleEndian(value: Int) - suspend fun writeFully(byteArray: ByteArray) = writeFully(byteArray, 0, byteArray.size) + public suspend fun writeFully(byteArray: ByteArray): Unit = writeFully(byteArray, 0, byteArray.size) } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/transport/SocketFactory.kt b/adam/src/main/kotlin/com/malinskiy/adam/transport/SocketFactory.kt index 379077a26..97ba1446d 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/transport/SocketFactory.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/transport/SocketFactory.kt @@ -19,7 +19,11 @@ package com.malinskiy.adam.transport import java.io.Closeable import java.net.InetSocketAddress -interface SocketFactory : Closeable { - suspend fun tcp(socketAddress: InetSocketAddress, connectTimeout: Long? = null, idleTimeout: Long? = null): Socket +public interface SocketFactory : Closeable { + public suspend fun tcp( + socketAddress: InetSocketAddress, + connectTimeout: Long? = null, + idleTimeout: Long? = null, + ): Socket override fun close() } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/transport/SuspendCloseable.kt b/adam/src/main/kotlin/com/malinskiy/adam/transport/SuspendCloseable.kt index 9810d25ca..6e0372579 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/transport/SuspendCloseable.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/transport/SuspendCloseable.kt @@ -19,11 +19,11 @@ package com.malinskiy.adam.transport import kotlinx.coroutines.NonCancellable import kotlinx.coroutines.withContext -interface SuspendCloseable { - suspend fun close() +public interface SuspendCloseable { + public suspend fun close() } -suspend inline fun C.use(crossinline block: suspend (C) -> R): R { +public suspend inline fun C.use(crossinline block: suspend (C) -> R): R { var closed = false return try { @@ -38,7 +38,7 @@ suspend inline fun C.use(crossinline block: suspend (C try { Throwable::class.java.getMethod("addSuppressed", Throwable::class.java).invoke(this, second) } catch (t: Throwable) { - //Nothing to do + // Nothing to do } } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/transport/TransportResponse.kt b/adam/src/main/kotlin/com/malinskiy/adam/transport/TransportResponse.kt index 98bfce946..4ade9d045 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/transport/TransportResponse.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/transport/TransportResponse.kt @@ -16,7 +16,7 @@ package com.malinskiy.adam.transport -class TransportResponse( - val okay: Boolean, - val message: String? -) \ No newline at end of file +public class TransportResponse( + public val okay: Boolean, + public val message: String?, +) diff --git a/adam/src/main/kotlin/com/malinskiy/adam/transport/vertx/VariableSizeRecordParser.kt b/adam/src/main/kotlin/com/malinskiy/adam/transport/vertx/VariableSizeRecordParser.kt index 971afd112..d80f19f00 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/transport/vertx/VariableSizeRecordParser.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/transport/vertx/VariableSizeRecordParser.kt @@ -16,20 +16,18 @@ package com.malinskiy.adam.transport.vertx -import io.netty.buffer.Unpooled import io.vertx.core.Handler import io.vertx.core.buffer.Buffer -import io.vertx.core.impl.Arguments import io.vertx.core.streams.ReadStream import kotlin.math.min -class VariableSizeRecordParser( - private val stream: ReadStream? = null +public class VariableSizeRecordParser( + private val stream: ReadStream? = null, ) : Handler, ReadStream { // Empty and unmodifiable - private val EMPTY_BUFFER = Buffer.buffer(Unpooled.EMPTY_BUFFER) - private var buff = EMPTY_BUFFER - private val bufferLock = Object() + private val emptyBuffer: Buffer = Buffer.buffer() + private var buff: Buffer = emptyBuffer + private val bufferLock = Any() private var pos = 0 // Current position in buffer private var start = 0 // Position of beginning of current record private var requestedAtMost = 0 @@ -40,7 +38,7 @@ class VariableSizeRecordParser( private var exceptionHandler: Handler? = null private var streamEnded = false private val drained - get() = streamEnded && (buff.byteBuf.writerIndex() == 0) + get() = streamEnded && (buff.length() == 0) /** * This method is called to provide the parser with data.toChannel @@ -62,8 +60,8 @@ class VariableSizeRecordParser( } } - fun request(size: Int) { - Arguments.require(size > 0, "Size must be > 0") + public fun request(size: Int) { + require(size > 0) { "Size must be > 0" } requestedAtMost = size handleParsing() } @@ -103,7 +101,7 @@ class VariableSizeRecordParser( } while (true) val length = buff.length() if (start == length) { - buff = EMPTY_BUFFER + buff = emptyBuffer } else if (start > 0) { buff = buff.getBuffer(start, length) } @@ -135,19 +133,26 @@ class VariableSizeRecordParser( endHandler?.handle(null) } - override fun exceptionHandler(handler: Handler?) = apply { exceptionHandler = handler } + override fun exceptionHandler(handler: Handler?): VariableSizeRecordParser = apply { + exceptionHandler = + handler + } override fun handler(handler: Handler?): ReadStream { eventHandler = handler if (stream != null) { if (handler != null) { - stream.endHandler(Handler { - streamEnded = true - handleParsing() - }) - stream.exceptionHandler(Handler { err: Throwable -> - exceptionHandler?.handle(err) - }) + stream.endHandler( + Handler { + streamEnded = true + handleParsing() + }, + ) + stream.exceptionHandler( + Handler { err: Throwable -> + exceptionHandler?.handle(err) + }, + ) stream.handler(this) } else { stream.handler(null) @@ -158,10 +163,10 @@ class VariableSizeRecordParser( return this } - override fun pause() = apply { demand = 0L } + override fun pause(): VariableSizeRecordParser = apply { demand = 0L } override fun fetch(amount: Long): ReadStream { - Arguments.require(amount > 0, "Fetch amount must be > 0") + require(amount > 0) { "Fetch amount must be > 0" } demand += amount if (demand < 0L) { demand = Long.MAX_VALUE @@ -170,7 +175,7 @@ class VariableSizeRecordParser( return this } - override fun resume() = apply { fetch(Long.MAX_VALUE) } + override fun resume(): VariableSizeRecordParser = apply { fetch(Long.MAX_VALUE) } - override fun endHandler(handler: Handler?) = apply { endHandler = handler } + override fun endHandler(handler: Handler?): VariableSizeRecordParser = apply { endHandler = handler } } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/transport/vertx/VertxSocket.kt b/adam/src/main/kotlin/com/malinskiy/adam/transport/vertx/VertxSocket.kt index f5a0909e9..efe1982b8 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/transport/vertx/VertxSocket.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/transport/vertx/VertxSocket.kt @@ -32,7 +32,7 @@ import io.vertx.core.net.SocketAddress import io.vertx.core.net.impl.NetSocketImpl import io.vertx.core.streams.ReadStream import io.vertx.kotlin.coroutines.CoroutineVerticle -import io.vertx.kotlin.coroutines.await +import io.vertx.kotlin.coroutines.coAwait import io.vertx.kotlin.coroutines.dispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.channels.Channel @@ -45,9 +45,13 @@ import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicReference import kotlin.coroutines.CoroutineContext -class VertxSocket(private val socketAddress: SocketAddress, private val options: NetClientOptions) : CoroutineVerticle(), Socket { - var id: String? = null - var netClient: NetClient? = null +public class VertxSocket( + private val socketAddress: SocketAddress, + private val options: NetClientOptions, +) : CoroutineVerticle(), Socket { + + public var id: String? = null + public var netClient: NetClient? = null private lateinit var socket: NetSocketImpl private lateinit var recordParser: VariableSizeRecordParser private lateinit var readChannel: ReceiveChannel @@ -60,7 +64,7 @@ class VertxSocket(private val socketAddress: SocketAddress, private val options: netClient = client val connect = client.connect(socketAddress) state.change(State.CREATED, State.SYN_SENT) { "Socket connection error" } - socket = connect.await() as NetSocketImpl + socket = connect.coAwait() as NetSocketImpl state.change(State.SYN_SENT, State.ESTABLISHED) { "Socket connection error" } canRead.flip(false) { "Socket connection error: canRead was true, expected false" } @@ -95,18 +99,18 @@ class VertxSocket(private val socketAddress: SocketAddress, private val options: override suspend fun writeFully(byteBuffer: ByteBuffer) { if (isClosedForWrite) throw IllegalStateException("Socket write error: socket is not connected ${state.get()}") val appendBytes = Buffer.buffer().appendBytes(byteBuffer.array(), byteBuffer.position(), byteBuffer.remaining()) - socket.write(appendBytes).await() + socket.write(appendBytes).coAwait() } - suspend fun writeFully(buffer: Buffer) { + public suspend fun writeFully(buffer: Buffer) { if (isClosedForWrite) throw IllegalStateException("Socket write error: socket is not connected ${state.get()}") - socket.write(buffer).await() + socket.write(buffer).coAwait() } override suspend fun writeFully(byteArray: ByteArray, offset: Int, limit: Int) { if (isClosedForWrite) throw IllegalStateException("Socket write error: socket is not connected ${state.get()}") val appendBytes = Buffer.buffer().appendBytes(byteArray, offset, limit) - socket.write(appendBytes).await() + socket.write(appendBytes).coAwait() } override suspend fun readAvailable(buffer: ByteArray, offset: Int, limit: Int): Int { @@ -115,7 +119,7 @@ class VertxSocket(private val socketAddress: SocketAddress, private val options: recordParser.request(limit) } return readChannel.receiveCatching().getOrNull()?.let { - val actualLimit = it.byteBuf.writerIndex() + val actualLimit = it.length() assert(actualLimit <= limit) { "Received ${it.length()} more than we can chew $limit" } it.getBytes(0, actualLimit, buffer, offset) actualLimit @@ -181,7 +185,7 @@ class VertxSocket(private val socketAddress: SocketAddress, private val options: } override suspend fun close() { - socket.close().await() + socket.close().coAwait() /** * This should be maximum buffer that could've been requested in case: * 1. Read request for up to max initiated @@ -195,12 +199,12 @@ class VertxSocket(private val socketAddress: SocketAddress, private val options: } } id?.let { - vertx.undeploy(it).await() + vertx.undeploy(it).coAwait() } } } -fun ReadStream.toChannel(vertx: Vertx): ReceiveChannel { +public fun ReadStream.toChannel(vertx: Vertx): ReceiveChannel { return toChannel(vertx.orCreateContext) } @@ -209,12 +213,12 @@ fun ReadStream.toChannel(vertx: Vertx): ReceiveChannel { * * @param context the vertx context */ -fun ReadStream.toChannel(context: Context): ReceiveChannel { +public fun ReadStream.toChannel(context: Context): ReceiveChannel { this.pause() val ret = ChannelReadStream( stream = this, channel = Channel(16), - context = context + context = context, ) ret.subscribe() this.fetch(1) @@ -224,7 +228,7 @@ fun ReadStream.toChannel(context: Context): ReceiveChannel { private class ChannelReadStream( val stream: ReadStream, val channel: Channel, - context: Context + context: Context, ) : Channel by channel, CoroutineScope { private val logger = AdamLogging.logger { } @@ -256,7 +260,7 @@ private enum class State { SYN_SENT, ESTABLISHED, CLOSING, - CLOSE_WAIT + CLOSE_WAIT, } private fun AtomicBoolean.flip(expected: Boolean, error: () -> String) { diff --git a/adam/src/main/kotlin/com/malinskiy/adam/transport/vertx/VertxSocketFactory.kt b/adam/src/main/kotlin/com/malinskiy/adam/transport/vertx/VertxSocketFactory.kt index 4f0aa0292..c3c913c46 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/transport/vertx/VertxSocketFactory.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/transport/vertx/VertxSocketFactory.kt @@ -21,13 +21,13 @@ import com.malinskiy.adam.transport.SocketFactory import io.vertx.core.Vertx import io.vertx.core.net.NetClientOptions import io.vertx.core.net.SocketAddress -import io.vertx.kotlin.coroutines.await +import io.vertx.kotlin.coroutines.coAwait import java.net.InetSocketAddress import java.util.concurrent.atomic.AtomicBoolean -class VertxSocketFactory( +public class VertxSocketFactory( private val connectTimeout: Long = 10_000, - private val idleTimeout: Long = 30_000 + private val idleTimeout: Long = 30_000, ) : SocketFactory { private val vertx by lazy { Vertx.vertx().also { initialized.set(true) } @@ -35,11 +35,14 @@ class VertxSocketFactory( private val initialized = AtomicBoolean(false) override suspend fun tcp(socketAddress: InetSocketAddress, connectTimeout: Long?, idleTimeout: Long?): Socket { - val vertxSocket = VertxSocket(SocketAddress.inetSocketAddress(socketAddress), NetClientOptions().apply { - setConnectTimeout((connectTimeout ?: this@VertxSocketFactory.connectTimeout).toTimeoutInt()) - setIdleTimeout((idleTimeout ?: this@VertxSocketFactory.idleTimeout).toTimeoutInt()) - }) - val id = vertx.deployVerticle(vertxSocket).await() + val vertxSocket = VertxSocket( + SocketAddress.inetSocketAddress(socketAddress), + NetClientOptions().apply { + setConnectTimeout((connectTimeout ?: this@VertxSocketFactory.connectTimeout).toTimeoutInt()) + setIdleTimeout((idleTimeout ?: this@VertxSocketFactory.idleTimeout).toTimeoutInt()) + }, + ) + val id = vertx.deployVerticle(vertxSocket).coAwait() vertxSocket.id = id return vertxSocket } @@ -52,7 +55,10 @@ class VertxSocketFactory( private fun Long.toTimeoutInt(): Int { val toInt = toInt() - return if (toInt < 0) Int.MAX_VALUE - else toInt + return if (toInt < 0) { + Int.MAX_VALUE + } else { + toInt + } } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/AndroidDebugBridgeClientTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/AndroidDebugBridgeClientTest.kt index c74d339c3..4c995881d 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/AndroidDebugBridgeClientTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/AndroidDebugBridgeClientTest.kt @@ -93,16 +93,19 @@ class AndroidDebugBridgeClientTest { @Test(expected = RequestValidationException::class) fun testRequestValidation() { runBlocking { - client.execute(object : ComplexRequest() { - override fun validate() = ValidationResponse(false, "Fake") - override suspend fun readElement(socket: Socket): String { - TODO("Not yet implemented") - } + client.execute( + object : ComplexRequest() { + override fun validate() = ValidationResponse(false, "Fake") + override suspend fun readElement(socket: Socket): String { + TODO("Not yet implemented") + } - override fun serialize(): ByteArray { - TODO("Not yet implemented") - } - }, serial = "serial") + override fun serialize(): ByteArray { + TODO("Not yet implemented") + } + }, + serial = "serial", + ) } } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/extension/ByteArrayExtensions.kt b/adam/src/test/kotlin/com/malinskiy/adam/extension/ByteArrayExtensions.kt index 592258b5f..e1926d4c9 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/extension/ByteArrayExtensions.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/extension/ByteArrayExtensions.kt @@ -18,4 +18,4 @@ package com.malinskiy.adam.extension import com.malinskiy.adam.Const -fun ByteArray.toRequestString() = String(this, Const.DEFAULT_TRANSPORT_ENCODING) \ No newline at end of file +fun ByteArray.toRequestString() = String(this, Const.DEFAULT_TRANSPORT_ENCODING) diff --git a/adam/src/test/kotlin/com/malinskiy/adam/integration/AdbBinaryIntegrationTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/integration/AdbBinaryIntegrationTest.kt index 1a4c2c619..127551d62 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/integration/AdbBinaryIntegrationTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/integration/AdbBinaryIntegrationTest.kt @@ -39,6 +39,5 @@ class AdbBinaryIntegrationTest { startAdbInteractor.execute(serverPort = customServerPort) stopAdbInteractor.execute(serverPort = customServerPort) } - } -} \ No newline at end of file +} diff --git a/adam/src/test/kotlin/com/malinskiy/adam/interactor/DiscoverAdbSocketInteractorTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/interactor/DiscoverAdbSocketInteractorTest.kt index 17df7d504..0c1fa36c9 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/interactor/DiscoverAdbSocketInteractorTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/interactor/DiscoverAdbSocketInteractorTest.kt @@ -37,4 +37,4 @@ class DiscoverAdbSocketInteractorTest { assertThat(execute).isEqualTo(1234) } -} \ No newline at end of file +} diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/AsyncShellCommandRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/AsyncShellCommandRequestTest.kt index d2a420cb9..fa7d0d41d 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/AsyncShellCommandRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/AsyncShellCommandRequestTest.kt @@ -28,4 +28,4 @@ class AsyncShellCommandRequestTest { assertThat(String(ChanneledShellCommandRequest("test").serialize(), Const.DEFAULT_TRANSPORT_ENCODING)) .isEqualTo("000Ashell:test") } -} \ No newline at end of file +} diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/TargetTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/TargetTest.kt index d230ff60d..dbd677ea2 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/TargetTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/TargetTest.kt @@ -27,6 +27,5 @@ class TargetTest { assertThat(UsbTarget.serialize()).isEqualTo("host-usb:") assertThat(LocalTarget.serialize()).isEqualTo("host-local:") - } -} \ No newline at end of file +} diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/abb/AbbExecRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/abb/AbbExecRequestTest.kt index 15fe7d4b0..42e4beb1e 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/abb/AbbExecRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/abb/AbbExecRequestTest.kt @@ -38,7 +38,9 @@ class AbbExecRequestTest { @Test fun testSerialize() { - assertThat(AbbExecRequest(listOf("cmd", "package", "install"), listOf(Feature.ABB_EXEC)).serialize().toRequestString()) + assertThat( + AbbExecRequest(listOf("cmd", "package", "install"), listOf(Feature.ABB_EXEC)).serialize().toRequestString(), + ) .isEqualTo("001Cabb_exec:cmd\u0000package\u0000install") } @@ -59,7 +61,7 @@ class AbbExecRequestTest { runBlocking { StubSocket("cafebabe".toByteArray(Const.DEFAULT_TRANSPORT_ENCODING)).use { socket -> assertThat( - AbbExecRequest(listOf(), supportedFeatures = emptyList()).readElement(socket) + AbbExecRequest(listOf(), supportedFeatures = emptyList()).readElement(socket), ).isEqualTo("cafebabe") } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/device/FetchDeviceFeaturesRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/device/FetchDeviceFeaturesRequestTest.kt index 2c24220fc..27aefd964 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/device/FetchDeviceFeaturesRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/device/FetchDeviceFeaturesRequestTest.kt @@ -34,8 +34,8 @@ class FetchDeviceFeaturesRequestTest { assertThat( String( fetchDeviceFeaturesRequest.serialize(), - Const.DEFAULT_TRANSPORT_ENCODING - ) + Const.DEFAULT_TRANSPORT_ENCODING, + ), ).isEqualTo("001Dhost-serial:cafebabe:features") } @@ -45,7 +45,7 @@ class FetchDeviceFeaturesRequestTest { runBlocking { StubSocket( content = "0054fixed_push_symlink_timestamp,apex,fixed_push_mkdir,stat_v2,abb_exec,cmd,abb,shell_v2" - .toByteArray(Const.DEFAULT_TRANSPORT_ENCODING) + .toByteArray(Const.DEFAULT_TRANSPORT_ENCODING), ).use { socket -> val features = fetchDeviceFeaturesRequest.readElement(socket) @@ -57,7 +57,7 @@ class FetchDeviceFeaturesRequestTest { Feature.ABB_EXEC, Feature.CMD, Feature.ABB, - Feature.SHELL_V2 + Feature.SHELL_V2, ) } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/device/ListDevicesRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/device/ListDevicesRequestTest.kt index 58555859a..ab7bfd941 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/device/ListDevicesRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/device/ListDevicesRequestTest.kt @@ -48,7 +48,7 @@ class ListDevicesRequestTest { "emulator-5570" to "authorizing", "emulator-5572" to "connecting", "emulator-5574" to "wtf", - ) + ), ) } @@ -64,7 +64,7 @@ class ListDevicesRequestTest { Device("emulator-5568", DeviceState.UNAUTHORIZED), Device("emulator-5570", DeviceState.AUTHORIZING), Device("emulator-5572", DeviceState.CONNECTING), - Device("emulator-5574", DeviceState.UNKNOWN) + Device("emulator-5574", DeviceState.UNKNOWN), ) } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/forwarding/ListPortForwardsRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/forwarding/ListPortForwardsRequestTest.kt index e815a7dea..16482ba62 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/forwarding/ListPortForwardsRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/forwarding/ListPortForwardsRequestTest.kt @@ -46,8 +46,8 @@ class ListPortForwardsRequestTest { xx local:/tmp/socket localfilesystem:namedsocket xx local:/tmp/socket dev:/dev/chardev xx local:/tmp/socket jdwp:1001 - - """.trimIndent() + + """.trimIndent(), ) input.discard() @@ -58,9 +58,13 @@ class ListPortForwardsRequestTest { PortForwardingRule("xx", LocalTcpPortSpec(80), RemoteTcpPortSpec(80)), PortForwardingRule("xx", LocalUnixSocketPortSpec("/tmp/socket"), RemoteAbstractPortSpec("namedsocket")), PortForwardingRule("xx", LocalUnixSocketPortSpec("/tmp/socket"), RemoteReservedPortSpec("namedsocket")), - PortForwardingRule("xx", LocalUnixSocketPortSpec("/tmp/socket"), RemoteFilesystemPortSpec("namedsocket")), + PortForwardingRule( + "xx", + LocalUnixSocketPortSpec("/tmp/socket"), + RemoteFilesystemPortSpec("namedsocket"), + ), PortForwardingRule("xx", LocalUnixSocketPortSpec("/tmp/socket"), RemoteDevPortSpec("/dev/chardev")), - PortForwardingRule("xx", LocalUnixSocketPortSpec("/tmp/socket"), JDWPPortSpec(1001)) + PortForwardingRule("xx", LocalUnixSocketPortSpec("/tmp/socket"), JDWPPortSpec(1001)), ) assertThat(output.first().serial).isEqualTo("xx") diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/forwarding/LocalPortSpecTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/forwarding/LocalPortSpecTest.kt index eb16d3f27..d8f8dadd8 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/forwarding/LocalPortSpecTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/forwarding/LocalPortSpecTest.kt @@ -21,7 +21,6 @@ import assertk.assertions.isEqualTo import com.malinskiy.adam.exception.UnsupportedForwardingSpecException import org.junit.Test - class LocalPortSpecTest { @Test(expected = UnsupportedForwardingSpecException::class) fun testUnsupported() { @@ -32,4 +31,4 @@ class LocalPortSpecTest { fun testLocalUnixSocketPortSpec() { assertThat(LocalUnixSocketPortSpec("path").toSpec()).isEqualTo("local:path") } -} \ No newline at end of file +} diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/forwarding/PortForwardRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/forwarding/PortForwardRequestTest.kt index cfd0926a3..0b3391bd7 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/forwarding/PortForwardRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/forwarding/PortForwardRequestTest.kt @@ -46,7 +46,7 @@ class PortForwardRequestTest { LocalTcpPortSpec(80), RemoteTcpPortSpec(80), "emulator-5554", - mode = PortForwardingMode.NO_REBIND + mode = PortForwardingMode.NO_REBIND, ).serialize() assertThat(String(bytes, Const.DEFAULT_TRANSPORT_ENCODING)) diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/forwarding/RemotePortSpecTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/forwarding/RemotePortSpecTest.kt index 4bbd5cc9d..bfc3aff41 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/forwarding/RemotePortSpecTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/forwarding/RemotePortSpecTest.kt @@ -46,4 +46,4 @@ class RemotePortSpecTest { fun testJDWPPortSpec() { assertThat(JDWPPortSpec(1).toSpec()).isEqualTo("jdwp:1") } -} \ No newline at end of file +} diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/forwarding/RemovePortForwardRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/forwarding/RemovePortForwardRequestTest.kt index 6d6f64a7c..79937d4b9 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/forwarding/RemovePortForwardRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/forwarding/RemovePortForwardRequestTest.kt @@ -34,8 +34,12 @@ class RemovePortForwardRequestTest { @Test fun testDummy() { runBlocking { - assertThat(RemovePortForwardRequest(serial = "serial", local = LocalTcpPortSpec()).process(ByteArray(1), 0, 1)).isEqualTo(Unit) - assertThat(RemovePortForwardRequest(serial = "serial", local = LocalTcpPortSpec()).transform()).isEqualTo(Unit) + assertThat( + RemovePortForwardRequest(serial = "serial", local = LocalTcpPortSpec()).process(ByteArray(1), 0, 1), + ).isEqualTo(Unit) + assertThat( + RemovePortForwardRequest(serial = "serial", local = LocalTcpPortSpec()).transform(), + ).isEqualTo(Unit) } } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/framebuffer/ScreenCaptureRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/framebuffer/ScreenCaptureRequestTest.kt index 1a812510c..a47861b68 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/framebuffer/ScreenCaptureRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/framebuffer/ScreenCaptureRequestTest.kt @@ -25,7 +25,6 @@ import com.malinskiy.adam.AndroidDebugBridgeClient import com.malinskiy.adam.exception.UnsupportedImageProtocolException import com.malinskiy.adam.extension.newFileWithExtension import com.malinskiy.adam.server.junit4.AdbServerRule -import io.ktor.utils.io.writeIntLittleEndian import kotlinx.coroutines.runBlocking import org.junit.Rule import org.junit.Test @@ -35,7 +34,6 @@ import java.io.File import javax.imageio.ImageIO import kotlin.system.measureTimeMillis - class ScreenCaptureRequestTest { @Rule @JvmField @@ -288,7 +286,7 @@ class ScreenCaptureRequestTest { expectCmd { "host:transport:serial" }.accept() expectCmd { "framebuffer:" }.accept() - //Unsupported version + // Unsupported version output.writeIntLittleEndian(99) } @@ -298,7 +296,7 @@ class ScreenCaptureRequestTest { private fun compare( expected: BufferedImage, - actual: BufferedImage + actual: BufferedImage, ): ImageComparisonResult { val imageComparison = ImageComparison(expected, actual) val comparisonResult = imageComparison.compareImages() diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/framebuffer/screencapture/BufferedImageScreenCaptureAdapterTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/framebuffer/screencapture/BufferedImageScreenCaptureAdapterTest.kt index ecb3466c6..ee235ff64 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/framebuffer/screencapture/BufferedImageScreenCaptureAdapterTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/framebuffer/screencapture/BufferedImageScreenCaptureAdapterTest.kt @@ -43,7 +43,7 @@ class BufferedImageScreenCaptureAdapterTest { 0, 0, null, - socket + socket, ) } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/logcat/AsyncLogcatRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/logcat/AsyncLogcatRequestTest.kt index dbac53a24..10b924dd0 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/logcat/AsyncLogcatRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/logcat/AsyncLogcatRequestTest.kt @@ -26,7 +26,7 @@ class AsyncLogcatRequestTest { @Test fun testModeArguments() { val cmd = ChanneledLogcatRequest( - modes = listOf(LogcatReadMode.long, LogcatReadMode.epoch) + modes = listOf(LogcatReadMode.long, LogcatReadMode.epoch), ).serialize() assertThat(String(cmd, Const.DEFAULT_TRANSPORT_ENCODING)) @@ -36,7 +36,7 @@ class AsyncLogcatRequestTest { @Test fun testBuffers() { val cmd = ChanneledLogcatRequest( - buffers = listOf(LogcatBuffer.crash, LogcatBuffer.radio) + buffers = listOf(LogcatBuffer.crash, LogcatBuffer.radio), ).serialize() assertThat(String(cmd, Const.DEFAULT_TRANSPORT_ENCODING)) @@ -85,9 +85,9 @@ class AsyncLogcatRequestTest { SupressAll, LogcatFilterSpec( "SOMETAG", - LogcatVerbosityLevel.E - ) - ) + LogcatVerbosityLevel.E, + ), + ), ).serialize() assertThat(String(cmd, Const.DEFAULT_TRANSPORT_ENCODING)) diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/mdns/ListMdnsServicesRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/mdns/ListMdnsServicesRequestTest.kt index 63e6dcd63..9ca38c3fc 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/mdns/ListMdnsServicesRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/mdns/ListMdnsServicesRequestTest.kt @@ -35,7 +35,9 @@ class ListMdnsServicesRequestTest { @Test fun testReturnsContent() { runBlocking { - val response = "0027adb-serial\t_adb._tcp.\t192.168.1.2:9999\n".toByteArray(Const.DEFAULT_TRANSPORT_ENCODING) + val response = "0027adb-serial\t_adb._tcp.\t192.168.1.2:9999\n".toByteArray( + Const.DEFAULT_TRANSPORT_ENCODING, + ) StubSocket(response).use { socket -> val services = ListMdnsServicesRequest().readElement(socket) @@ -43,8 +45,8 @@ class ListMdnsServicesRequestTest { MdnsService( name = "adb-serial", serviceType = "_adb._tcp.", - url = "192.168.1.2:9999" - ) + url = "192.168.1.2:9999", + ), ) assertThat(services.first().name).isEqualTo("adb-serial") diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/mdns/MdnsCheckRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/mdns/MdnsCheckRequestTest.kt index 884dd20de..2e1d32156 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/mdns/MdnsCheckRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/mdns/MdnsCheckRequestTest.kt @@ -51,7 +51,6 @@ class MdnsCheckRequestTest { StubSocket(response).use { socket -> val value = MdnsCheckRequest().readElement(socket) assertThat(value).isEqualTo(MdnsStatus(false, null)) - } } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/misc/DisconnectDeviceRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/misc/DisconnectDeviceRequestTest.kt index 858e6dfe7..c89f84256 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/misc/DisconnectDeviceRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/misc/DisconnectDeviceRequestTest.kt @@ -62,4 +62,3 @@ class DisconnectDeviceRequestTest { } } } - diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/misc/FetchHostFeaturesRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/misc/FetchHostFeaturesRequestTest.kt index ded64dca1..6f20836b8 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/misc/FetchHostFeaturesRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/misc/FetchHostFeaturesRequestTest.kt @@ -50,7 +50,7 @@ class FetchHostFeaturesRequestTest { Feature.ABB_EXEC, Feature.CMD, Feature.ABB, - Feature.SHELL_V2 + Feature.SHELL_V2, ) } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/misc/RebootRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/misc/RebootRequestTest.kt index b2db45c0b..6f15f0f2b 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/misc/RebootRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/misc/RebootRequestTest.kt @@ -53,7 +53,9 @@ class RebootRequestTest { @Test fun testSideloadAutoReboot() { - val actual = RebootRequest(RebootMode.SIDELOAD_AUTO_REBOOT).serialize().toString(Const.DEFAULT_TRANSPORT_ENCODING) + val actual = RebootRequest( + RebootMode.SIDELOAD_AUTO_REBOOT, + ).serialize().toString(Const.DEFAULT_TRANSPORT_ENCODING) assertThat(actual) .isEqualTo("001Breboot:sideload-auto-reboot") } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/InstallRemotePackageRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/InstallRemotePackageRequestTest.kt index 5064067dc..ebb7564b2 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/InstallRemotePackageRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/InstallRemotePackageRequestTest.kt @@ -50,8 +50,14 @@ class InstallRemotePackageRequestTest { @Test fun testValidation() { - assertThat(InstallRemotePackageRequest("/data/local/tmp/file.apk", true, emptyList()).validate().success).isTrue() - assertThat(InstallRemotePackageRequest("/data/local/tmp/file.apex", true, emptyList()).validate().success).isFalse() - assertThat(InstallRemotePackageRequest("/data/local/tmp/file.bin", true, emptyList()).validate().success).isFalse() + assertThat( + InstallRemotePackageRequest("/data/local/tmp/file.apk", true, emptyList()).validate().success, + ).isTrue() + assertThat( + InstallRemotePackageRequest("/data/local/tmp/file.apex", true, emptyList()).validate().success, + ).isFalse() + assertThat( + InstallRemotePackageRequest("/data/local/tmp/file.bin", true, emptyList()).validate().success, + ).isFalse() } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/multi/AddSessionRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/multi/AddSessionRequestTest.kt index 32c210d13..292cda076 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/multi/AddSessionRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/multi/AddSessionRequestTest.kt @@ -33,10 +33,10 @@ class AddSessionRequestTest { val request = AddSessionRequest( childSessions = listOf("child-session-1", "child-session-2"), parentSession = "parent-session-1", - supportedFeatures = listOf(Feature.CMD) + supportedFeatures = listOf(Feature.CMD), ) assertThat( - request.serialize().toRequestString() + request.serialize().toRequestString(), ).isEqualTo("0055exec:cmd package install-add-session parent-session-1 child-session-1 child-session-2") } @@ -46,11 +46,13 @@ class AddSessionRequestTest { AddSessionRequest( childSessions = listOf("child-session-1", "child-session-2"), parentSession = "parent-session-1", - supportedFeatures = listOf(Feature.CMD, Feature.ABB_EXEC) + supportedFeatures = listOf(Feature.CMD, Feature.ABB_EXEC), ) assertThat( - request.serialize().toRequestString() - ).isEqualTo("0055abb_exec:package\u0000install-add-session\u0000parent-session-1\u0000child-session-1\u0000child-session-2") + request.serialize().toRequestString(), + ).isEqualTo( + "0055abb_exec:package\u0000install-add-session\u0000parent-session-1\u0000child-session-1\u0000child-session-2", + ) } @Test @@ -59,7 +61,7 @@ class AddSessionRequestTest { AddSessionRequest( childSessions = listOf("child-session-1", "child-session-2"), parentSession = "parent-session-1", - supportedFeatures = listOf(Feature.CMD) + supportedFeatures = listOf(Feature.CMD), ) val response = "Success".toByteArray(Const.DEFAULT_TRANSPORT_ENCODING) @@ -76,7 +78,7 @@ class AddSessionRequestTest { AddSessionRequest( childSessions = listOf("child-session-1", "child-session-2"), parentSession = "parent-session-1", - supportedFeatures = listOf(Feature.CMD) + supportedFeatures = listOf(Feature.CMD), ) val response = "Failure".toByteArray(Const.DEFAULT_TRANSPORT_ENCODING) diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/multi/CreateIndividualPackageSessionRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/multi/CreateIndividualPackageSessionRequestTest.kt index 2627143f5..80b0b3f2e 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/multi/CreateIndividualPackageSessionRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/multi/CreateIndividualPackageSessionRequestTest.kt @@ -50,7 +50,7 @@ class CreateIndividualPackageSessionRequestTest { supportedFeatures = listOf(Feature.CMD, Feature.ABB_EXEC), pkg = pkg, pkgList = listOf(pkg), - reinstall = false + reinstall = false, ) assertThat(request.serialize().toRequestString()) .isEqualTo("001Fabb_exec:package\u0000install-create") @@ -63,7 +63,7 @@ class CreateIndividualPackageSessionRequestTest { supportedFeatures = listOf(), pkg = pkg, pkgList = listOf(pkg), - reinstall = false + reinstall = false, ) assertThat(request.serialize().toRequestString()) .isEqualTo("0016exec:pm install-create") @@ -77,7 +77,7 @@ class CreateIndividualPackageSessionRequestTest { pkg = pkg, extraArgs = listOf("-g"), pkgList = listOf(pkg), - reinstall = true + reinstall = true, ) assertThat(request.serialize().toRequestString()) .isEqualTo("0027exec:cmd package install-create '-g' -r") @@ -91,7 +91,7 @@ class CreateIndividualPackageSessionRequestTest { pkg = pkg, extraArgs = listOf("-g"), pkgList = listOf(pkg), - reinstall = true + reinstall = true, ) assertThat(request.serialize().toRequestString()) .isEqualTo("0037exec:cmd package install-create '-g' -r --staged --apex") @@ -139,7 +139,7 @@ class CreateIndividualPackageSessionRequestTest { pkg = pkg, extraArgs = emptyList(), pkgList = listOf(pkg), - reinstall = false + reinstall = false, ) return request } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/multi/CreateMultiPackageSessionRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/multi/CreateMultiPackageSessionRequestTest.kt index dcb3eb783..d208c7cec 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/multi/CreateMultiPackageSessionRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/multi/CreateMultiPackageSessionRequestTest.kt @@ -28,9 +28,6 @@ import com.malinskiy.adam.request.Feature import com.malinskiy.adam.request.ValidationResponse import com.malinskiy.adam.server.stub.StubSocket import com.malinskiy.adam.transport.use -import io.ktor.utils.io.ByteChannelSequentialJVM -import io.ktor.utils.io.ByteWriteChannel -import io.ktor.utils.io.core.internal.ChunkBuffer import kotlinx.coroutines.runBlocking import org.junit.Rule import org.junit.Test @@ -56,7 +53,7 @@ class CreateMultiPackageSessionRequestTest { supportedFeatures = listOf(Feature.CMD, Feature.ABB_EXEC), extraArgs = emptyList(), pkgList = listOf(pkg), - reinstall = false + reinstall = false, ) assertThat(request.serialize().toRequestString()) .isEqualTo("002Fabb_exec:package\u0000install-create\u0000--multi-package") @@ -69,7 +66,7 @@ class CreateMultiPackageSessionRequestTest { supportedFeatures = listOf(Feature.CMD), extraArgs = listOf("-g"), pkgList = listOf(pkg), - reinstall = true + reinstall = true, ) assertThat(request.serialize().toRequestString()) .isEqualTo("0037exec:cmd package install-create --multi-package '-g' -r") @@ -82,7 +79,7 @@ class CreateMultiPackageSessionRequestTest { supportedFeatures = listOf(Feature.CMD), extraArgs = listOf("-g"), pkgList = listOf(pkg), - reinstall = true + reinstall = true, ) assertThat(request.serialize().toRequestString()) .isEqualTo("0040exec:cmd package install-create --multi-package '-g' -r --staged") @@ -90,12 +87,13 @@ class CreateMultiPackageSessionRequestTest { @Test fun serializeApkSplit() { - val pkg = ApkSplitInstallationPackage(listOf(temp.newFileWithExtension("apex"), temp.newFileWithExtension("apex"))) + val pkg = + ApkSplitInstallationPackage(listOf(temp.newFileWithExtension("apex"), temp.newFileWithExtension("apex"))) val request = CreateMultiPackageSessionRequest( supportedFeatures = listOf(Feature.CMD), extraArgs = listOf("-g"), pkgList = listOf(pkg), - reinstall = true + reinstall = true, ) assertThat(request.serialize().toRequestString()) .isEqualTo("0040exec:cmd package install-create --multi-package '-g' -r --staged") @@ -105,7 +103,6 @@ class CreateMultiPackageSessionRequestTest { fun testRead() { val request = stub() val response = "Success [my-session-id]".toByteArray(Const.DEFAULT_TRANSPORT_ENCODING) - val byteBufferChannel: ByteWriteChannel = ByteChannelSequentialJVM(ChunkBuffer.Empty, false) runBlocking { StubSocket(response).use { socket -> val (sessionId, output) = request.readElement(socket) @@ -119,7 +116,6 @@ class CreateMultiPackageSessionRequestTest { fun testReadException() { val request = stub() val response = "Failure".toByteArray(Const.DEFAULT_TRANSPORT_ENCODING) - val byteBufferChannel: ByteWriteChannel = ByteChannelSequentialJVM(ChunkBuffer.Empty, false) runBlocking { StubSocket(response).use { socket -> request.readElement(socket) @@ -150,7 +146,7 @@ class CreateMultiPackageSessionRequestTest { supportedFeatures = listOf(Feature.CMD), extraArgs = emptyList(), pkgList = listOf(pkg), - reinstall = false + reinstall = false, ) assertThat(request.validate().success).isFalse() } @@ -161,7 +157,7 @@ class CreateMultiPackageSessionRequestTest { val request = CreateMultiPackageSessionRequest( supportedFeatures = listOf(Feature.CMD), pkgList = listOf(pkg), - reinstall = false + reinstall = false, ) assertThat(request.validate().success).isFalse() } @@ -173,7 +169,7 @@ class CreateMultiPackageSessionRequestTest { supportedFeatures = listOf(Feature.CMD), extraArgs = emptyList(), pkgList = listOf(pkg), - reinstall = false + reinstall = false, ) assertThat(request.validate().success).isFalse() } @@ -185,7 +181,7 @@ class CreateMultiPackageSessionRequestTest { supportedFeatures = listOf(), extraArgs = emptyList(), pkgList = listOf(pkg), - reinstall = false + reinstall = false, ) assertThat(request.validate().success).isFalse() @@ -193,7 +189,7 @@ class CreateMultiPackageSessionRequestTest { supportedFeatures = listOf(Feature.ABB_EXEC), extraArgs = emptyList(), pkgList = listOf(pkg), - reinstall = false + reinstall = false, ) assertThat(request.validate().success).isTrue() @@ -201,7 +197,7 @@ class CreateMultiPackageSessionRequestTest { supportedFeatures = listOf(Feature.CMD), extraArgs = emptyList(), pkgList = listOf(pkg), - reinstall = false + reinstall = false, ) assertThat(request.validate().success).isTrue() } @@ -213,31 +209,35 @@ class CreateMultiPackageSessionRequestTest { supportedFeatures = listOf(Feature.CMD), extraArgs = emptyList(), pkgList = listOf(pkg), - reinstall = false + reinstall = false, ) assertThat(request.validate().success).isFalse() } @Test fun testValidationApkSplit() { - val pkg = ApkSplitInstallationPackage(listOf(temp.newFileWithExtension("apk"), temp.newFileWithExtension("apk"))) + val pkg = + ApkSplitInstallationPackage(listOf(temp.newFileWithExtension("apk"), temp.newFileWithExtension("apk"))) var request = CreateMultiPackageSessionRequest( supportedFeatures = listOf(Feature.CMD), extraArgs = emptyList(), pkgList = listOf(pkg), - reinstall = false + reinstall = false, ) assertThat(request.validate().success).isTrue() } @Test fun testValidationFailureApkSplit() { - val pkg = ApkSplitInstallationPackage(listOf(temp.newFileWithExtension("apk"), createTempFile(suffix = ".app"))) + val pkg = + ApkSplitInstallationPackage( + listOf(temp.newFileWithExtension("apk"), kotlin.io.path.createTempFile(suffix = ".app").toFile()), + ) var request = CreateMultiPackageSessionRequest( supportedFeatures = listOf(Feature.CMD), extraArgs = emptyList(), pkgList = listOf(pkg), - reinstall = false + reinstall = false, ) assertThat(request.validate().success).isFalse() } @@ -248,7 +248,7 @@ class CreateMultiPackageSessionRequestTest { supportedFeatures = listOf(Feature.CMD), extraArgs = emptyList(), pkgList = listOf(pkg), - reinstall = false + reinstall = false, ) return request } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/multi/InstallCommitRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/multi/InstallCommitRequestTest.kt index 8004697ee..8dc508d54 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/multi/InstallCommitRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/multi/InstallCommitRequestTest.kt @@ -39,7 +39,7 @@ class InstallCommitRequestTest { fun serializeAbb() { val request = InstallCommitRequest( supportedFeatures = listOf(Feature.CMD, Feature.ABB_EXEC), - parentSession = "parent-session-id" + parentSession = "parent-session-id", ) assertThat(request.serialize().toRequestString()) .isEqualTo("0031abb_exec:package\u0000install-commit\u0000parent-session-id") @@ -50,7 +50,7 @@ class InstallCommitRequestTest { val request = InstallCommitRequest( supportedFeatures = listOf(Feature.CMD, Feature.ABB_EXEC), parentSession = "parent-session-id", - abandon = true + abandon = true, ) assertThat(request.serialize().toRequestString()) .isEqualTo("0032abb_exec:package\u0000install-abandon\u0000parent-session-id") @@ -84,8 +84,8 @@ class InstallCommitRequestTest { InstallCommitRequest( supportedFeatures = listOf(), parentSession = "parent-session-id", - abandon = false - ).serialize().toRequestString() + abandon = false, + ).serialize().toRequestString(), ).isEqualTo("0028exec:pm install-commit parent-session-id") } @@ -93,7 +93,7 @@ class InstallCommitRequestTest { val request = InstallCommitRequest( supportedFeatures = listOf(Feature.CMD), parentSession = "parent-session-id", - abandon = false + abandon = false, ) return request } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/multi/WriteIndividualPackageRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/multi/WriteIndividualPackageRequestTest.kt index 717008c65..312f22755 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/multi/WriteIndividualPackageRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/multi/WriteIndividualPackageRequestTest.kt @@ -51,10 +51,12 @@ class WriteIndividualPackageRequestTest { val request = WriteIndividualPackageRequest( supportedFeatures = listOf(Feature.CMD, Feature.ABB_EXEC), file = File(WriteIndividualPackageRequestTest::class.java.getResource("/fixture/sample-fake.apk").file), - session = "session-id" + session = "session-id", ) assertThat(request.serialize().toRequestString()) - .isEqualTo("0042abb_exec:package\u0000install-write\u0000-S\u0000614\u0000session-id\u0000sample-fake.apk\u0000-") + .isEqualTo( + "0042abb_exec:package\u0000install-write\u0000-S\u0000614\u0000session-id\u0000sample-fake.apk\u0000-", + ) } @Test @@ -62,7 +64,7 @@ class WriteIndividualPackageRequestTest { val request = WriteIndividualPackageRequest( supportedFeatures = emptyList(), file = File(WriteIndividualPackageRequestTest::class.java.getResource("/fixture/sample-fake.apk").file), - session = "session-id" + session = "session-id", ) assertThat(request.serialize().toRequestString()) .isEqualTo("0039exec:pm install-write -S 614 session-id sample-fake.apk -") @@ -75,7 +77,7 @@ class WriteIndividualPackageRequestTest { val request = WriteIndividualPackageRequest( supportedFeatures = listOf(Feature.CMD), file = fixture, - session = "session-id" + session = "session-id", ) val response = "Success".toByteArray(Const.DEFAULT_TRANSPORT_ENCODING) val actual = temp.newFileWithExtension("apk") @@ -97,7 +99,7 @@ class WriteIndividualPackageRequestTest { val request = WriteIndividualPackageRequest( supportedFeatures = listOf(Feature.CMD), file = fixture, - session = "session-id" + session = "session-id", ) val response = "Failure".toByteArray(Const.DEFAULT_TRANSPORT_ENCODING) val actual = temp.newFileWithExtension("apk") @@ -115,7 +117,7 @@ class WriteIndividualPackageRequestTest { val request = WriteIndividualPackageRequest( supportedFeatures = listOf(Feature.CMD), file = File(WriteIndividualPackageRequestTest::class.java.getResource("/fixture/sample-fake.apk").file), - session = "session-id" + session = "session-id", ) return request } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/reverse/ListReversePortForwardsRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/reverse/ListReversePortForwardsRequestTest.kt index 65d8c6582..1abc1f159 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/reverse/ListReversePortForwardsRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/reverse/ListReversePortForwardsRequestTest.kt @@ -50,17 +50,29 @@ class ListReversePortForwardsRequestTest { xx localabstract:namedsocket local:/tmp/socket xx localreserved:namedsocket local:/tmp/socket xx localfilesystem:namedsocket local:/tmp/socket - - """.trimIndent() + + """.trimIndent(), ) } val output = client.execute(ListReversePortForwardsRequest(), serial = "xx") assertThat(output).containsExactly( ReversePortForwardingRule("xx", RemoteTcpPortSpec(80), LocalTcpPortSpec(80)), - ReversePortForwardingRule("xx", RemoteAbstractPortSpec("namedsocket"), LocalUnixSocketPortSpec("/tmp/socket")), - ReversePortForwardingRule("xx", RemoteReservedPortSpec("namedsocket"), LocalUnixSocketPortSpec("/tmp/socket")), - ReversePortForwardingRule("xx", RemoteFilesystemPortSpec("namedsocket"), LocalUnixSocketPortSpec("/tmp/socket")) + ReversePortForwardingRule( + "xx", + RemoteAbstractPortSpec("namedsocket"), + LocalUnixSocketPortSpec("/tmp/socket"), + ), + ReversePortForwardingRule( + "xx", + RemoteReservedPortSpec("namedsocket"), + LocalUnixSocketPortSpec("/tmp/socket"), + ), + ReversePortForwardingRule( + "xx", + RemoteFilesystemPortSpec("namedsocket"), + LocalUnixSocketPortSpec("/tmp/socket"), + ), ) assertThat(output.first().serial).isEqualTo("xx") diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/reverse/RemoveReversePortForwardRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/reverse/RemoveReversePortForwardRequestTest.kt index 6b7e4fe58..c581bcb8f 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/reverse/RemoveReversePortForwardRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/reverse/RemoveReversePortForwardRequestTest.kt @@ -36,7 +36,9 @@ class RemoveReversePortForwardRequestTest { fun testDummy() { runBlocking { assertThat(RemoveReversePortForwardRequest(RemoteTcpPortSpec(8080)).transform()).isEqualTo(Unit) - assertThat(RemoveReversePortForwardRequest(RemoteTcpPortSpec(8080)).process(ByteArray(1), 0, 1)).isEqualTo(Unit) + assertThat( + RemoveReversePortForwardRequest(RemoteTcpPortSpec(8080)).process(ByteArray(1), 0, 1), + ).isEqualTo(Unit) } } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/reverse/ReversePortForwardRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/reverse/ReversePortForwardRequestTest.kt index db72a683f..3b829ef6a 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/reverse/ReversePortForwardRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/reverse/ReversePortForwardRequestTest.kt @@ -48,7 +48,7 @@ class ReversePortForwardRequestTest { val bytes = ReversePortForwardRequest( RemoteTcpPortSpec(80), LocalTcpPortSpec(80), - mode = PortForwardingMode.NO_REBIND + mode = PortForwardingMode.NO_REBIND, ).serialize() assertThat(String(bytes, Const.DEFAULT_TRANSPORT_ENCODING)) @@ -64,7 +64,10 @@ class ReversePortForwardRequestTest { respondPortForward(true, 7070) } - val output = client.execute(ReversePortForwardRequest(RemoteTcpPortSpec(8080), LocalTcpPortSpec(0)), "serial") + val output = client.execute( + ReversePortForwardRequest(RemoteTcpPortSpec(8080), LocalTcpPortSpec(0)), + "serial", + ) assertThat(output).isEqualTo(7070) } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/shell/v1/ChanneledShellCommandRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/shell/v1/ChanneledShellCommandRequestTest.kt index 03fb3334a..65b2cbea5 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/shell/v1/ChanneledShellCommandRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/shell/v1/ChanneledShellCommandRequestTest.kt @@ -41,7 +41,11 @@ class ChanneledShellCommandRequestTest { .respond("something2-something2") } - val updates = client.execute(ChanneledShellCommandRequest("logcat -v"), scope = this, serial = "emulator-5554") + val updates = client.execute( + ChanneledShellCommandRequest("logcat -v"), + scope = this, + serial = "emulator-5554", + ) val stringBuffer = StringBuffer() for (update in updates) { diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/shell/v1/ShellCommandRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/shell/v1/ShellCommandRequestTest.kt index fab2afb46..e7b189c30 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/shell/v1/ShellCommandRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/shell/v1/ShellCommandRequestTest.kt @@ -24,7 +24,6 @@ import kotlinx.coroutines.runBlocking import org.junit.Rule import org.junit.Test - class ShellCommandRequestTest { @get:Rule val server = AdbServerRule() diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/shell/v1/ShellResultResponseTransformerTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/shell/v1/ShellResultResponseTransformerTest.kt index ea3b36551..088460134 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/shell/v1/ShellResultResponseTransformerTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/shell/v1/ShellResultResponseTransformerTest.kt @@ -40,4 +40,4 @@ class ShellResultResponseTransformerTest { }.transform() } } -} \ No newline at end of file +} diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/shell/v2/ChanneledShellCommandRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/shell/v2/ChanneledShellCommandRequestTest.kt index 09e1a65cd..3cfacfe64 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/shell/v2/ChanneledShellCommandRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/shell/v2/ChanneledShellCommandRequestTest.kt @@ -60,7 +60,7 @@ class ChanneledShellCommandRequestTest { val updates = client.execute( ChanneledShellCommandRequest("echo foo; echo bar >&2; exit 17", stdio), scope = this, - serial = "serial" + serial = "serial", ) val stdoutBuffer = StringBuffer() val stderrBuffer = StringBuffer() diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/shell/v2/ShellCommandRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/shell/v2/ShellCommandRequestTest.kt index d7cd52756..2e3780785 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/shell/v2/ShellCommandRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/shell/v2/ShellCommandRequestTest.kt @@ -45,7 +45,6 @@ class ShellCommandRequestTest { respondShellV2Exit(17) } - val output = client.execute(ShellCommandRequest("echo foo; echo bar >&2; exit 17"), serial = "serial") assertThat(output.output).isEqualTo("foo\n") assertThat(output.errorOutput).isEqualTo("bar\n") diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/ListFilesRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/ListFilesRequestTest.kt index c5dd79634..913d4c482 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/ListFilesRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/ListFilesRequestTest.kt @@ -51,7 +51,7 @@ class ListFilesRequestTest { drwxrwx--x 2 root sdcard_rw 4096 2020-10-24 16:29 Ringtones Orwxrwx--x 2 root sdcard_rw 4096 2020-10-24 16:29 XXX x0 - """.trimIndent() + """.trimIndent(), ) } @@ -67,7 +67,7 @@ class ListFilesRequestTest { owner = "root", size = 4096, time = "16:29", - type = AndroidFileType.REGULAR_FILE + type = AndroidFileType.REGULAR_FILE, ), AndroidFile( permissions = "brwxrwx--x", @@ -79,7 +79,7 @@ class ListFilesRequestTest { owner = "root", size = 4096, time = "16:29", - type = AndroidFileType.BLOCK_SPECIAL_FILE + type = AndroidFileType.BLOCK_SPECIAL_FILE, ), AndroidFile( permissions = "lrwxrwx--x", @@ -91,7 +91,7 @@ class ListFilesRequestTest { owner = "root", size = 4096, time = "16:29", - type = AndroidFileType.SYMBOLIC_LINK + type = AndroidFileType.SYMBOLIC_LINK, ), AndroidFile( permissions = "crwxrwx--x", @@ -103,7 +103,7 @@ class ListFilesRequestTest { owner = "root", size = 4096, time = "19:11", - type = AndroidFileType.CHARACTER_SPECIAL_FILE + type = AndroidFileType.CHARACTER_SPECIAL_FILE, ), AndroidFile( permissions = "srwxrwx--x", @@ -115,7 +115,7 @@ class ListFilesRequestTest { owner = "root", size = 4096, time = "16:29", - type = AndroidFileType.SOCKET_LINK + type = AndroidFileType.SOCKET_LINK, ), AndroidFile( permissions = "prwxrwx--x", @@ -127,7 +127,7 @@ class ListFilesRequestTest { owner = "root", size = 4096, time = "16:29", - type = AndroidFileType.FIFO + type = AndroidFileType.FIFO, ), AndroidFile( permissions = "drwxrwx--x", @@ -139,8 +139,8 @@ class ListFilesRequestTest { owner = "root", size = 4096, time = "16:29", - type = AndroidFileType.DIRECTORY - ) + type = AndroidFileType.DIRECTORY, + ), ) assertThat(files.first().permissions).isEqualTo("-rwxrwx--x") diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/compat/CompatListFileRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/compat/CompatListFileRequestTest.kt index 8a8d87167..7fbca3dfa 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/compat/CompatListFileRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/compat/CompatListFileRequestTest.kt @@ -46,12 +46,13 @@ class CompatListFileRequestTest { 420, 123, 1589042331, - "some-file" + "some-file", ).done() } val list = client.execute( - CompatListFileRequest("/sdcard/", emptyList()), "serial" + CompatListFileRequest("/sdcard/", emptyList()), + "serial", ) assertThat(list).containsExactly( @@ -59,8 +60,8 @@ class CompatListFileRequestTest { name = "some-file", mode = 123.toUInt(), mtime = Instant.ofEpochSecond(1589042331), - size = 420.toUInt() - ) + size = 420.toUInt(), + ), ) } } @@ -84,12 +85,13 @@ class CompatListFileRequestTest { gid = 1000, atime = 1589042331, mtime = 1589042332, - ctime = 1589042333 + ctime = 1589042333, ).done() } val list = client.execute( - CompatListFileRequest("/sdcard/", listOf(Feature.LS_V2)), "serial" + CompatListFileRequest("/sdcard/", listOf(Feature.LS_V2)), + "serial", ) assertThat(list).containsExactly( @@ -105,8 +107,8 @@ class CompatListFileRequestTest { gid = 1000.toUInt(), atime = Instant.ofEpochSecond(1589042331), mtime = Instant.ofEpochSecond(1589042332), - ctime = Instant.ofEpochSecond(1589042333) - ) + ctime = Instant.ofEpochSecond(1589042333), + ), ) } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/compat/CompatStatFileRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/compat/CompatStatFileRequestTest.kt index f722fd777..81d810975 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/compat/CompatStatFileRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/compat/CompatStatFileRequestTest.kt @@ -72,11 +72,14 @@ class CompatStatFileRequestTest { gid = 1000, atime = 1589042331, mtime = 1589042332, - ctime = 1589042333 + ctime = 1589042333, ) } - val result = client.execute(CompatStatFileRequest("/sdcard/testfile", listOf(Feature.STAT_V2)), serial = "serial") + val result = client.execute( + CompatStatFileRequest("/sdcard/testfile", listOf(Feature.STAT_V2)), + serial = "serial", + ) val output = result as FileEntryV2 assertThat(output).isEqualTo( FileEntryV2( @@ -90,8 +93,8 @@ class CompatStatFileRequestTest { gid = 1000.toUInt(), atime = Instant.ofEpochSecond(1589042331), mtime = Instant.ofEpochSecond(1589042332), - ctime = Instant.ofEpochSecond(1589042333) - ) + ctime = Instant.ofEpochSecond(1589042333), + ), ) } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v1/ListFileRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v1/ListFileRequestTest.kt index 919aae4cc..9c5455a39 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v1/ListFileRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v1/ListFileRequestTest.kt @@ -44,22 +44,22 @@ class ListFileRequestTest { 420, 123, 1589042331, - "some-file" + "some-file", ).done() } val list = client.execute( - ListFileRequest("/sdcard/"), "serial" + ListFileRequest("/sdcard/"), + "serial", ) - assertThat(list).containsExactly( FileEntryV1( name = "some-file", mode = 123.toUInt(), mtime = Instant.ofEpochSecond(1589042331), - size = 420.toUInt() - ) + size = 420.toUInt(), + ), ) assertThat(list.first().name).isEqualTo("some-file") diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v1/PullFileRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v1/PullFileRequestTest.kt index beaf7e4ce..ea45db03a 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v1/PullFileRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v1/PullFileRequestTest.kt @@ -24,7 +24,6 @@ import com.malinskiy.adam.exception.PullFailedException import com.malinskiy.adam.exception.UnsupportedSyncProtocolException import com.malinskiy.adam.server.junit4.AdbServerRule import io.ktor.utils.io.discard -import io.ktor.utils.io.writeIntLittleEndian import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import org.junit.Rule @@ -45,7 +44,12 @@ class PullFileRequestTest { @Test fun testSerialize() { - assertThat(String(PullFileRequest("/sdcard/testfile", File("/tmp/testfile")).serialize(), Const.DEFAULT_TRANSPORT_ENCODING)) + assertThat( + String( + PullFileRequest("/sdcard/testfile", File("/tmp/testfile")).serialize(), + Const.DEFAULT_TRANSPORT_ENCODING, + ), + ) .isEqualTo("0005sync:") } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v1/PushFileRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v1/PushFileRequestTest.kt index 41a936e7a..39ababf29 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v1/PushFileRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v1/PushFileRequestTest.kt @@ -106,7 +106,6 @@ class PushFileRequestTest { } }.join() - assertThat(receiveFile.readBytes()).isEqualTo(fixture.readBytes()) } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v1/StatFileRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v1/StatFileRequestTest.kt index 43feebf62..05e1bdd64 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v1/StatFileRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v1/StatFileRequestTest.kt @@ -25,7 +25,6 @@ import org.junit.Rule import org.junit.Test import java.time.Instant - class StatFileRequestTest { @get:Rule val server = AdbServerRule() diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v2/ListFileRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v2/ListFileRequestTest.kt index de44697a7..b3c785c30 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v2/ListFileRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v2/ListFileRequestTest.kt @@ -54,13 +54,14 @@ class ListFileRequestTest { gid = 1000, atime = 1589042331, mtime = 1589042332, - ctime = 1589042333 + ctime = 1589042333, ) output.respondDone() } val list = client.execute( - ListFileRequest("/sdcard/", listOf(Feature.LS_V2)), "serial" + ListFileRequest("/sdcard/", listOf(Feature.LS_V2)), + "serial", ) assertThat(list).containsExactly( @@ -76,8 +77,8 @@ class ListFileRequestTest { gid = 1000.toUInt(), atime = Instant.ofEpochSecond(1589042331), mtime = Instant.ofEpochSecond(1589042332), - ctime = Instant.ofEpochSecond(1589042333) - ) + ctime = Instant.ofEpochSecond(1589042333), + ), ) assertThat(list.first().name).isEqualTo("some-file") diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v2/PullFileRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v2/PullFileRequestTest.kt index 216dce597..de0a859db 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v2/PullFileRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v2/PullFileRequestTest.kt @@ -25,7 +25,6 @@ import com.malinskiy.adam.exception.UnsupportedSyncProtocolException import com.malinskiy.adam.request.Feature import com.malinskiy.adam.server.junit4.AdbServerRule import io.ktor.utils.io.discard -import io.ktor.utils.io.writeIntLittleEndian import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import org.junit.Rule @@ -49,8 +48,8 @@ class PullFileRequestTest { assertThat( String( PullFileRequest("/sdcard/testfile", File("/tmp/testfile"), listOf(Feature.SENDRECV_V2)).serialize(), - Const.DEFAULT_TRANSPORT_ENCODING - ) + Const.DEFAULT_TRANSPORT_ENCODING, + ), ) .isEqualTo("0005sync:") } @@ -77,7 +76,12 @@ class PullFileRequestTest { } val request = - PullFileRequest("/sdcard/testfile", tempFile, listOf(Feature.SENDRECV_V2), coroutineContext = coroutineContext) + PullFileRequest( + "/sdcard/testfile", + tempFile, + listOf(Feature.SENDRECV_V2), + coroutineContext = coroutineContext, + ) val execute = client.execute(request, this, "serial") var progress = 0.0 @@ -117,7 +121,12 @@ class PullFileRequestTest { } val request = - PullFileRequest("/sdcard/testfile", tempFile, listOf(Feature.SENDRECV_V2), coroutineContext = coroutineContext) + PullFileRequest( + "/sdcard/testfile", + tempFile, + listOf(Feature.SENDRECV_V2), + coroutineContext = coroutineContext, + ) val execute = client.execute(request, this, "serial") var progress = 0.0 diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v2/PushFileRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v2/PushFileRequestTest.kt index 4637b9743..805e38cbd 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v2/PushFileRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v2/PushFileRequestTest.kt @@ -75,7 +75,6 @@ class PushFileRequestTest { } assertThat(progress).isEqualTo(1.0) - }.join() assertThat(receiveFile.readBytes()).isEqualTo(fixture.readBytes()) diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v2/StatFileRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v2/StatFileRequestTest.kt index 4e0309956..b8c120482 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v2/StatFileRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v2/StatFileRequestTest.kt @@ -27,7 +27,6 @@ import org.junit.Rule import org.junit.Test import java.time.Instant - class StatFileRequestTest { @get:Rule val server = AdbServerRule() @@ -53,11 +52,14 @@ class StatFileRequestTest { gid = 1000, atime = 1589042331, mtime = 1589042332, - ctime = 1589042333 + ctime = 1589042333, ) } - val output: FileEntryV2 = client.execute(StatFileRequest("/sdcard/testfile", listOf(Feature.STAT_V2)), serial = "serial") + val output: FileEntryV2 = client.execute( + StatFileRequest("/sdcard/testfile", listOf(Feature.STAT_V2)), + serial = "serial", + ) assertThat(output).isEqualTo( FileEntryV2( mode = 123.toUInt(), @@ -70,10 +72,9 @@ class StatFileRequestTest { gid = 1000.toUInt(), atime = Instant.ofEpochSecond(1589042331), mtime = Instant.ofEpochSecond(1589042332), - ctime = Instant.ofEpochSecond(1589042333) - ) + ctime = Instant.ofEpochSecond(1589042333), + ), ) } } - } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/testrunner/InstrumentOptionsTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/testrunner/InstrumentOptionsTest.kt index ac607e159..95d266380 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/testrunner/InstrumentOptionsTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/testrunner/InstrumentOptionsTest.kt @@ -41,21 +41,21 @@ class InstrumentOptionsTest { functional = true, log = true, performance = true, - unit = true + unit = true, ) assertThat(options.toString()).isEqualTo( " -e package com.example " + - "-e class com.example.TestClass " + - "-e func true " + - "-e unit true " + - "-e size medium " + - "-e perf true " + - "-e debug true " + - "-e log true " + - "-e emma true " + - "-e coverageFile /sdcard/codecov " + - "-e test test" + "-e class com.example.TestClass " + + "-e func true " + + "-e unit true " + + "-e size medium " + + "-e perf true " + + "-e debug true " + + "-e log true " + + "-e emma true " + + "-e coverageFile /sdcard/codecov " + + "-e test test", ) } @@ -72,7 +72,7 @@ class InstrumentOptionsTest { functional = true, log = true, performance = true, - unit = true + unit = true, ) assertThat(options.pkg).containsExactly("com.example") @@ -93,13 +93,13 @@ class InstrumentOptionsTest { val options = InstrumentOptions( overrides = mapOf( "param1" to "value1", - "param2" to "value2" - ) + "param2" to "value2", + ), ) assertThat(options.toString()).isEqualTo( " -e param1 value1" + - " -e param2 value2" + " -e param2 value2", ) } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/testrunner/TestRunnerRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/testrunner/TestRunnerRequestTest.kt index 6feec4bc3..f6b076886 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/testrunner/TestRunnerRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/testrunner/TestRunnerRequestTest.kt @@ -50,13 +50,13 @@ class TestRunnerRequestTest { runnerClass = "com.example.test.AndroidTestRunner", userId = 1000, supportedFeatures = emptyList(), - coroutineScope = this + coroutineScope = this, ) assertThat(request.cmd) .isEqualTo( "am instrument -w -r --no-hidden-api-checks --no-window-animation --user 1000 --abi x86 " + - "-p /sdcard/profiling -f /sdcard/log com.example.test/com.example.test.AndroidTestRunner" + "-p /sdcard/profiling -f /sdcard/log com.example.test/com.example.test.AndroidTestRunner", ) } } @@ -68,12 +68,12 @@ class TestRunnerRequestTest { testPackage = "com.example.test", instrumentOptions = InstrumentOptions(), supportedFeatures = emptyList(), - coroutineScope = this + coroutineScope = this, ) assertThat(request.cmd) .isEqualTo( - "am instrument -w -r com.example.test/android.support.test.runner.AndroidJUnitRunner" + "am instrument -w -r com.example.test/android.support.test.runner.AndroidJUnitRunner", ) } } @@ -84,7 +84,9 @@ class TestRunnerRequestTest { launch { server.session { expectCmd { "host:transport:serial" }.accept() - expectShell { "am instrument -w -r com.example.test/android.support.test.runner.AndroidJUnitRunner" } + expectShell { + "am instrument -w -r com.example.test/android.support.test.runner.AndroidJUnitRunner" + } .accept() .respond( """ @@ -111,7 +113,7 @@ class TestRunnerRequestTest { INSTRUMENTATION_CODE: -1 - """.trimIndent() + """.trimIndent(), ) } @@ -120,7 +122,7 @@ class TestRunnerRequestTest { testPackage = "com.example.test", instrumentOptions = InstrumentOptions(), supportedFeatures = emptyList(), - coroutineScope = this + coroutineScope = this, ), serial = "serial", ) @@ -132,12 +134,14 @@ class TestRunnerRequestTest { assertThat(events).containsExactly( TestRunStartedEvent(testCount = 1), - TestStarted(id = TestIdentifier(className = "com.example.MainActivityAllureTest", testName = "testText")), + TestStarted( + id = TestIdentifier(className = "com.example.MainActivityAllureTest", testName = "testText"), + ), TestEnded( id = TestIdentifier(className = "com.example.MainActivityAllureTest", testName = "testText"), - metrics = emptyMap() + metrics = emptyMap(), ), - TestRunEnded(elapsedTimeMillis = 0, metrics = emptyMap()) + TestRunEnded(elapsedTimeMillis = 0, metrics = emptyMap()), ) }.join() } @@ -149,7 +153,9 @@ class TestRunnerRequestTest { launch { server.session { expectCmd { "host:transport:serial" }.accept() - expectShellV2 { "am instrument -w -r com.example.test/android.support.test.runner.AndroidJUnitRunner" } + expectShellV2 { + "am instrument -w -r com.example.test/android.support.test.runner.AndroidJUnitRunner" + } .accept() .respondStdout( """ @@ -176,7 +182,7 @@ class TestRunnerRequestTest { INSTRUMENTATION_CODE: -1 - """.trimIndent() + """.trimIndent(), ) .respondExit(0) } @@ -186,7 +192,7 @@ class TestRunnerRequestTest { testPackage = "com.example.test", instrumentOptions = InstrumentOptions(), supportedFeatures = listOf(Feature.SHELL_V2), - coroutineScope = this + coroutineScope = this, ), serial = "serial", ) @@ -198,12 +204,14 @@ class TestRunnerRequestTest { assertThat(events).containsExactly( TestRunStartedEvent(testCount = 1), - TestStarted(id = TestIdentifier(className = "com.example.MainActivityAllureTest", testName = "testText")), + TestStarted( + id = TestIdentifier(className = "com.example.MainActivityAllureTest", testName = "testText"), + ), TestEnded( id = TestIdentifier(className = "com.example.MainActivityAllureTest", testName = "testText"), - metrics = emptyMap() + metrics = emptyMap(), ), - TestRunEnded(elapsedTimeMillis = 0, metrics = emptyMap()) + TestRunEnded(elapsedTimeMillis = 0, metrics = emptyMap()), ) }.join() } @@ -215,7 +223,9 @@ class TestRunnerRequestTest { launch { server.session { expectCmd { "host:transport:serial" }.accept() - expectShellV2 { "am instrument -w -r com.example.test/android.support.test.runner.AndroidJUnitRunner" } + expectShellV2 { + "am instrument -w -r com.example.test/android.support.test.runner.AndroidJUnitRunner" + } .accept() .respondStdout( """ @@ -225,18 +235,18 @@ class TestRunnerRequestTest { INSTRUMENTATION_STATUS: numtests=1 INSTRUMENTATION_STATUS: stream= com.example.MainActivityAllureTest: - INSTRUMENTATION_STATUS: test=testText - """.trimIndent() + INSTRUMENTATION_STATUS: test=testText + """.trimIndent(), ) .respondStderr( """ s_glBindAttribLocation: bind attrib 0 name position s_glBindAttribLocation: bind attrib 1 name localCoord - """.trimIndent() + """.trimIndent(), ) .respondStdout( """ - + INSTRUMENTATION_STATUS_CODE: 1 INSTRUMENTATION_STATUS: class=com.example.MainActivityAllureTest INSTRUMENTATION_STATUS: current=1 @@ -253,7 +263,7 @@ class TestRunnerRequestTest { INSTRUMENTATION_CODE: -1 - """.trimIndent() + """.trimIndent(), ) .respondExit(0) } @@ -263,7 +273,7 @@ class TestRunnerRequestTest { testPackage = "com.example.test", instrumentOptions = InstrumentOptions(), supportedFeatures = listOf(Feature.SHELL_V2), - coroutineScope = this + coroutineScope = this, ), serial = "serial", ) @@ -274,12 +284,14 @@ class TestRunnerRequestTest { assertThat(events).containsExactly( TestRunStartedEvent(testCount = 1), - TestStarted(id = TestIdentifier(className = "com.example.MainActivityAllureTest", testName = "testText")), + TestStarted( + id = TestIdentifier(className = "com.example.MainActivityAllureTest", testName = "testText"), + ), TestEnded( id = TestIdentifier(className = "com.example.MainActivityAllureTest", testName = "testText"), - metrics = emptyMap() + metrics = emptyMap(), ), - TestRunEnded(elapsedTimeMillis = 0, metrics = emptyMap()) + TestRunEnded(elapsedTimeMillis = 0, metrics = emptyMap()), ) }.join() } @@ -291,7 +303,9 @@ class TestRunnerRequestTest { launch { server.session { expectCmd { "host:transport:serial" }.accept() - expectShell { "am instrument -w -r com.example.test/android.support.test.runner.AndroidJUnitRunner" } + expectShell { + "am instrument -w -r com.example.test/android.support.test.runner.AndroidJUnitRunner" + } .accept() .respond("something-something") } @@ -301,7 +315,7 @@ class TestRunnerRequestTest { testPackage = "com.example.test", instrumentOptions = InstrumentOptions(), supportedFeatures = emptyList(), - coroutineScope = this + coroutineScope = this, ), serial = "serial", ) diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/testrunner/transform/InstrumentationResponseTransformerTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/testrunner/transform/InstrumentationResponseTransformerTest.kt index 5923ec58d..1cd651b1b 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/testrunner/transform/InstrumentationResponseTransformerTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/testrunner/transform/InstrumentationResponseTransformerTest.kt @@ -45,7 +45,9 @@ class InstrumentationResponseTransformerTest { transformer.transform()?.let { events.addAll(it) } assertThat(events.map { it.toString() }.reduce { acc, s -> acc + "\n" + s }) - .isEqualTo(javaClass.getResourceAsStream("/instrumentation/log_3.expected").reader().readText().trimEnd()) + .isEqualTo( + javaClass.getResourceAsStream("/instrumentation/log_3.expected").reader().readText().trimEnd(), + ) } } @@ -66,7 +68,9 @@ class InstrumentationResponseTransformerTest { transformer.transform()?.let { events.addAll(it) } assertThat(events.map { it.toString() }.reduce { acc, s -> acc + "\n" + s }) - .isEqualTo(javaClass.getResourceAsStream("/instrumentation/log_2.expected").reader().readText().trimEnd()) + .isEqualTo( + javaClass.getResourceAsStream("/instrumentation/log_2.expected").reader().readText().trimEnd(), + ) } } @@ -87,7 +91,9 @@ class InstrumentationResponseTransformerTest { transformer.transform()?.let { events.addAll(it) } assertThat(events.map { it.toString() }.reduce { acc, s -> acc + "\n" + s }) - .isEqualTo(javaClass.getResourceAsStream("/instrumentation/log_1.expected").reader().readText().trimEnd()) + .isEqualTo( + javaClass.getResourceAsStream("/instrumentation/log_1.expected").reader().readText().trimEnd(), + ) } } @@ -117,7 +123,9 @@ class InstrumentationResponseTransformerTest { transformer.transform()?.let { events.addAll(it) } assertThat(events.map { it.toString() }.reduce { acc, s -> acc + "\n" + s }) - .isEqualTo(javaClass.getResourceAsStream("/instrumentation/log_4.expected").reader().readText().trimEnd()) + .isEqualTo( + javaClass.getResourceAsStream("/instrumentation/log_4.expected").reader().readText().trimEnd(), + ) } } @@ -138,7 +146,9 @@ class InstrumentationResponseTransformerTest { transformer.transform()?.let { events.addAll(it) } assertThat(events.map { it.toString() }.reduce { acc, s -> acc + "\n" + s }) - .isEqualTo(javaClass.getResourceAsStream("/instrumentation/log_5.expected").reader().readText().trimEnd()) + .isEqualTo( + javaClass.getResourceAsStream("/instrumentation/log_5.expected").reader().readText().trimEnd(), + ) } } @@ -160,20 +170,33 @@ class InstrumentationResponseTransformerTest { } transformer.transform()?.let { events.addAll(it) } + val expected = javaClass + .getResourceAsStream("/instrumentation/log_6.expected") + .reader() + .readText() + .trimEnd() + .trimEnd() + assertThat(events.map { it.toString() }.reduce { acc, s -> acc + "\n" + s }) - .isEqualTo(javaClass.getResourceAsStream("/instrumentation/log_6.expected").reader().readText().trimEnd().trimEnd()) + .isEqualTo(expected) } @Test fun testBufferFraming() = runBlocking { val transformer = InstrumentationResponseTransformer() - val lines = javaClass.getResourceAsStream("/instrumentation/log_6.input").reader().readLines() + val lines = javaClass + .getResourceAsStream("/instrumentation/log_6.input") + .reader() + .readLines() val events = mutableListOf() for (line in lines) { val part1 = line.substring(0, 7 * line.length / 8) - val part2 = line.substring(7 * line.length / 8, line.length) + val part2 = line.substring( + 7 * line.length / 8, + line.length, + ) val bytes1 = (part1).toByteArray(Const.DEFAULT_TRANSPORT_ENCODING) val bytes2 = (part2 + '\n').toByteArray(Const.DEFAULT_TRANSPORT_ENCODING) transformer.process(bytes1, 0, bytes1.size)?.let { @@ -185,8 +208,15 @@ class InstrumentationResponseTransformerTest { } transformer.transform()?.let { events.addAll(it) } + val expected = javaClass + .getResourceAsStream("/instrumentation/log_6.expected") + .reader() + .readText() + .trimEnd() + .trimEnd() + assertThat(events.map { it.toString() }.reduce { acc, s -> acc + "\n" + s }) - .isEqualTo(javaClass.getResourceAsStream("/instrumentation/log_6.expected").reader().readText().trimEnd().trimEnd()) + .isEqualTo(expected) } /** diff --git a/android-junit4-test-annotation-producer/build.gradle.kts b/android-junit4-test-annotation-producer/build.gradle.kts index a7eb33718..063ff20dc 100644 --- a/android-junit4-test-annotation-producer/build.gradle.kts +++ b/android-junit4-test-annotation-producer/build.gradle.kts @@ -1,3 +1,6 @@ +import adam.buildlogic.AdamPublishing +import adam.buildlogic.configureAdamPom + /* * Copyright (C) 2021 Anton Malinskiy * @@ -16,8 +19,17 @@ plugins { id("adam.android.library") - id("maven-publish") - id("org.jetbrains.dokka") + alias(libs.plugins.vanniktech.maven.publish) +} + +mavenPublishing { + coordinates(AdamPublishing.GROUP, "android-junit4-test-annotation-producer", version.toString()) + + pom { + name.set("android-junit4-test-annotation-producer") + description.set("Android Debug Bridge helper - Test annotation producer") + configureAdamPom() + } } android { @@ -26,4 +38,4 @@ android { dependencies { implementation(libs.kotlin.reflect) -} \ No newline at end of file +} diff --git a/android-junit4-test-annotation-producer/src/main/kotlin/com/malinskiy/adam/junit4/android/listener/TestAnnotationProducer.kt b/android-junit4-test-annotation-producer/src/main/kotlin/com/malinskiy/adam/junit4/android/listener/TestAnnotationProducer.kt index 23386da83..47ec4ba8b 100644 --- a/android-junit4-test-annotation-producer/src/main/kotlin/com/malinskiy/adam/junit4/android/listener/TestAnnotationProducer.kt +++ b/android-junit4-test-annotation-producer/src/main/kotlin/com/malinskiy/adam/junit4/android/listener/TestAnnotationProducer.kt @@ -42,12 +42,15 @@ import kotlin.reflect.full.memberProperties * INSTRUMENTATION_STATUS: stream=. * INSTRUMENTATION_STATUS: test=ignoreTest */ -class TestAnnotationProducer : RunListener() { +public class TestAnnotationProducer : RunListener() { override fun testStarted(description: Description?) { super.testStarted(description) if (description?.isTest == true) { val annotations: Set = - (description.annotations.toList() + description.testClass.annotations.toList()).mapNotNull { annotation -> + ( + description.annotations.toList() + + description.testClass.annotations.toList() + ).mapNotNull { annotation -> val fqn = annotation.annotationClass.qualifiedName val parameters = annotation.annotationClass.memberProperties.joinToString("") { @@ -60,7 +63,7 @@ class TestAnnotationProducer : RunListener() { val bundle = Bundle(1) bundle.putStringArrayList( "com.malinskiy.adam.junit4.android.listener.TestAnnotationProducer.v4", - ArrayList(annotations) + ArrayList(annotations), ) InstrumentationRegistry.getInstrumentation().sendStatus(2, bundle) } diff --git a/android-junit4/build.gradle.kts b/android-junit4/build.gradle.kts index 6cb52228b..a2e64e6f0 100644 --- a/android-junit4/build.gradle.kts +++ b/android-junit4/build.gradle.kts @@ -1,3 +1,6 @@ +import adam.buildlogic.AdamPublishing +import adam.buildlogic.configureAdamPom + /* * Copyright (C) 2021 Anton Malinskiy * @@ -16,8 +19,17 @@ plugins { id("adam.android.library") - id("maven-publish") - id("org.jetbrains.dokka") + alias(libs.plugins.vanniktech.maven.publish) +} + +mavenPublishing { + coordinates(AdamPublishing.GROUP, "android-junit4", version.toString()) + + pom { + name.set("android-junit4") + description.set("Android Debug Bridge helper - JUnit4 Android rules") + configureAdamPom() + } } android { @@ -29,4 +41,3 @@ dependencies { api(libs.coroutines.core) api(project(":android-testrunner-contract")) } - diff --git a/android-junit4/src/main/kotlin/com/malinskiy/adam/junit4/android/UnsafeAdbAccess.kt b/android-junit4/src/main/kotlin/com/malinskiy/adam/junit4/android/UnsafeAdbAccess.kt index 3c538430a..a21887642 100644 --- a/android-junit4/src/main/kotlin/com/malinskiy/adam/junit4/android/UnsafeAdbAccess.kt +++ b/android-junit4/src/main/kotlin/com/malinskiy/adam/junit4/android/UnsafeAdbAccess.kt @@ -3,8 +3,10 @@ package com.malinskiy.adam.junit4.android @Retention(value = AnnotationRetention.BINARY) @RequiresOptIn( level = RequiresOptIn.Level.WARNING, - message = "This implementation of adb is unsafe: unrestricted access to adb can introduce side-effects as well as unpredictable behaviour. " + - "Its usage should be marked with '@com.malinskiy.adam.junit4.android.UnsafeAdbAccess' or '@OptIn(com.malinskiy.adam.junit4.android.UnsafeAdbAccess::class)' " + - "if you accept the potential risks" + message = "This implementation of adb is unsafe: unrestricted access to adb can " + + "introduce side-effects as well as unpredictable behaviour. " + + "Its usage should be marked with '@com.malinskiy.adam.junit4.android.UnsafeAdbAccess'" + + " or '@OptIn(com.malinskiy.adam.junit4.android.UnsafeAdbAccess::class)' " + + "if you accept the potential risks", ) -annotation class UnsafeAdbAccess +public annotation class UnsafeAdbAccess diff --git a/android-junit4/src/main/kotlin/com/malinskiy/adam/junit4/android/rule/AdbRule.kt b/android-junit4/src/main/kotlin/com/malinskiy/adam/junit4/android/rule/AdbRule.kt index ff0402d55..b03808328 100644 --- a/android-junit4/src/main/kotlin/com/malinskiy/adam/junit4/android/rule/AdbRule.kt +++ b/android-junit4/src/main/kotlin/com/malinskiy/adam/junit4/android/rule/AdbRule.kt @@ -34,12 +34,16 @@ import kotlin.coroutines.CoroutineContext /** * @param coroutineContext it's your responsibility to cancel this context when needed */ -class AdbRule(private val mode: Mode = Mode.ASSERT, private val coroutineContext: CoroutineContext = Dispatchers.IO) : +@OptIn(UnsafeAdbAccess::class) +public class AdbRule( + private val mode: Mode = Mode.ASSERT, + private val coroutineContext: CoroutineContext = Dispatchers.IO, +) : TestRule { - lateinit var adb: SingleTargetAndroidDebugBridgeClient + public lateinit var adb: SingleTargetAndroidDebugBridgeClient @UnsafeAdbAccess - lateinit var adbUnsafe: AndroidDebugBridgeClient + public lateinit var adbUnsafe: AndroidDebugBridgeClient override fun apply(base: Statement, description: Description): Statement { return object : Statement() { @@ -60,7 +64,11 @@ class AdbRule(private val mode: Mode = Mode.ASSERT, private val coroutineContext } else { when (mode) { Mode.SKIP -> return - Mode.ASSUME -> throw AssumptionViolatedException("No access to adb port or device serial has been provided") + + Mode.ASSUME -> throw AssumptionViolatedException( + "No access to adb port or device serial has been provided", + ) + Mode.ASSERT -> throw AssertionError("No access to adb port or device serial has been provided") } } diff --git a/android-junit4/src/main/kotlin/com/malinskiy/adam/junit4/android/rule/EmulatorConsoleRule.kt b/android-junit4/src/main/kotlin/com/malinskiy/adam/junit4/android/rule/EmulatorConsoleRule.kt index c911428d2..113892df3 100644 --- a/android-junit4/src/main/kotlin/com/malinskiy/adam/junit4/android/rule/EmulatorConsoleRule.kt +++ b/android-junit4/src/main/kotlin/com/malinskiy/adam/junit4/android/rule/EmulatorConsoleRule.kt @@ -32,7 +32,10 @@ import kotlin.coroutines.CoroutineContext /** * @param coroutineContext it's your responsibility to cancel this context when needed */ -class EmulatorConsoleRule(private val mode: Mode = Mode.ASSERT, private val coroutineContext: CoroutineContext = Dispatchers.IO) : +public class EmulatorConsoleRule( + private val mode: Mode = Mode.ASSERT, + private val coroutineContext: CoroutineContext = Dispatchers.IO, +) : TestRule { private lateinit var client: AndroidDebugBridgeClient private lateinit var inetSocketAddress: InetSocketAddress @@ -54,8 +57,14 @@ class EmulatorConsoleRule(private val mode: Mode = Mode.ASSERT, private val coro } else { when (mode) { Mode.SKIP -> return - Mode.ASSUME -> throw AssumptionViolatedException("No access to console port: host = $host, port = $port, token = $authToken") - Mode.ASSERT -> throw AssertionError("No access to console port: host = $host, port = $port, token = $authToken") + + Mode.ASSUME -> throw AssumptionViolatedException( + "No access to console port: host = $host, port = $port, token = $authToken", + ) + + Mode.ASSERT -> throw AssertionError( + "No access to console port: host = $host, port = $port, token = $authToken", + ) } } @@ -68,5 +77,7 @@ class EmulatorConsoleRule(private val mode: Mode = Mode.ASSERT, private val coro } } - suspend fun execute(cmd: String) = client.execute(EmulatorCommandRequest(cmd, inetSocketAddress, authToken)) + public suspend fun execute(cmd: String): String = client.execute( + EmulatorCommandRequest(cmd, inetSocketAddress, authToken), + ) } diff --git a/android-junit4/src/main/kotlin/com/malinskiy/adam/junit4/android/rule/EmulatorGrpcRule.kt b/android-junit4/src/main/kotlin/com/malinskiy/adam/junit4/android/rule/EmulatorGrpcRule.kt index 8e0bfe9fd..406fdcce2 100644 --- a/android-junit4/src/main/kotlin/com/malinskiy/adam/junit4/android/rule/EmulatorGrpcRule.kt +++ b/android-junit4/src/main/kotlin/com/malinskiy/adam/junit4/android/rule/EmulatorGrpcRule.kt @@ -31,11 +31,11 @@ import org.junit.runner.Description import org.junit.runners.model.Statement import java.util.concurrent.TimeUnit -class EmulatorGrpcRule( - val mode: Mode = Mode.ASSERT, - private val coroutineDispatcher: CoroutineDispatcher = Dispatchers.IO +public class EmulatorGrpcRule( + public val mode: Mode = Mode.ASSERT, + private val coroutineDispatcher: CoroutineDispatcher = Dispatchers.IO, ) : TestRule { - lateinit var grpc: EmulatorControllerGrpcKt.EmulatorControllerCoroutineStub + public lateinit var grpc: EmulatorControllerGrpcKt.EmulatorControllerCoroutineStub private var channel: ManagedChannel? = null override fun apply(base: Statement, description: Description): Statement { @@ -55,8 +55,14 @@ class EmulatorGrpcRule( } else { when (mode) { Mode.SKIP -> return - Mode.ASSUME -> throw AssumptionViolatedException("No access to emulator's gRPC port has been provided: host = $grpcHost, port = $grpcPort") - Mode.ASSERT -> throw AssertionError("No access to emulator's gRPC port has been provided: host = $grpcHost, port = $grpcPort") + + Mode.ASSUME -> throw AssumptionViolatedException( + "No access to emulator's gRPC port has been provided: host = $grpcHost, port = $grpcPort", + ) + + Mode.ASSERT -> throw AssertionError( + "No access to emulator's gRPC port has been provided: host = $grpcHost, port = $grpcPort", + ) } } diff --git a/android-junit4/src/main/kotlin/com/malinskiy/adam/junit4/android/rule/Mode.kt b/android-junit4/src/main/kotlin/com/malinskiy/adam/junit4/android/rule/Mode.kt index 9db8056ac..9de400a2f 100644 --- a/android-junit4/src/main/kotlin/com/malinskiy/adam/junit4/android/rule/Mode.kt +++ b/android-junit4/src/main/kotlin/com/malinskiy/adam/junit4/android/rule/Mode.kt @@ -16,7 +16,7 @@ package com.malinskiy.adam.junit4.android.rule -enum class Mode { +public enum class Mode { /** * Do not execute test if the rule can't be satisfied */ @@ -30,5 +30,5 @@ enum class Mode { /** * Assert failure if the rule can't be satisfied */ - ASSERT + ASSERT, } diff --git a/android-junit4/src/main/kotlin/com/malinskiy/adam/junit4/android/rule/sandbox/SingleTargetAndroidDebugBridgeClient.kt b/android-junit4/src/main/kotlin/com/malinskiy/adam/junit4/android/rule/sandbox/SingleTargetAndroidDebugBridgeClient.kt index 4ee5dc422..2e7ef38f9 100644 --- a/android-junit4/src/main/kotlin/com/malinskiy/adam/junit4/android/rule/sandbox/SingleTargetAndroidDebugBridgeClient.kt +++ b/android-junit4/src/main/kotlin/com/malinskiy/adam/junit4/android/rule/sandbox/SingleTargetAndroidDebugBridgeClient.kt @@ -23,12 +23,17 @@ import com.malinskiy.adam.request.MultiRequest import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.channels.ReceiveChannel -class SingleTargetAndroidDebugBridgeClient(private val client: AndroidDebugBridgeClient, private val serial: String) { +public class SingleTargetAndroidDebugBridgeClient( + private val client: AndroidDebugBridgeClient, + private val serial: String, +) { - suspend fun execute(request: ComplexRequest): T = client.execute(request, serial) + public suspend fun execute(request: ComplexRequest): T = client.execute(request, serial) - fun execute(request: AsyncChannelRequest, scope: CoroutineScope): ReceiveChannel = - client.execute(request, scope, serial) + public fun execute( + request: AsyncChannelRequest, + scope: CoroutineScope, + ): ReceiveChannel = client.execute(request, scope, serial) - suspend fun execute(request: MultiRequest): T = client.execute(request, serial) + public suspend fun execute(request: MultiRequest): T = client.execute(request, serial) } diff --git a/android-testrunner-contract/build.gradle.kts b/android-testrunner-contract/build.gradle.kts index 0ad0e7dae..7f05aea21 100644 --- a/android-testrunner-contract/build.gradle.kts +++ b/android-testrunner-contract/build.gradle.kts @@ -1,3 +1,6 @@ +import adam.buildlogic.AdamPublishing +import adam.buildlogic.configureAdamPom + /* * Copyright (C) 2021 Anton Malinskiy * @@ -15,18 +18,16 @@ */ plugins { - id("java") + id("adam.java") + alias(libs.plugins.vanniktech.maven.publish) } -java { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 -} +mavenPublishing { + coordinates(AdamPublishing.GROUP, "android-testrunner-contract", version.toString()) -tasks.withType{ - compilerOptions { - jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_11) + pom { + name.set("android-testrunner-contract") + description.set("Android Debug Bridge helper - Test runner contract") + configureAdamPom() } } - - diff --git a/androidx-screencapture/build.gradle.kts b/androidx-screencapture/build.gradle.kts index 747a2f73e..02f8bd452 100644 --- a/androidx-screencapture/build.gradle.kts +++ b/androidx-screencapture/build.gradle.kts @@ -1,3 +1,6 @@ +import adam.buildlogic.AdamPublishing +import adam.buildlogic.configureAdamPom + /* * Copyright (C) 2021 Anton Malinskiy * @@ -16,8 +19,17 @@ plugins { id("adam.android.library") - id("maven-publish") - id("org.jetbrains.dokka") + alias(libs.plugins.vanniktech.maven.publish) +} + +mavenPublishing { + coordinates(AdamPublishing.GROUP, "androidx-screencapture", version.toString()) + + pom { + name.set("androidx-screencapture") + description.set("Android Debug Bridge helper - Screen capture support") + configureAdamPom() + } } android { diff --git a/androidx-screencapture/src/main/kotlin/com/malinskiy/adam/junit4/android/screencapture/AdamScreenCaptureProcessor.kt b/androidx-screencapture/src/main/kotlin/com/malinskiy/adam/junit4/android/screencapture/AdamScreenCaptureProcessor.kt index c03360c34..b8b80a730 100644 --- a/androidx-screencapture/src/main/kotlin/com/malinskiy/adam/junit4/android/screencapture/AdamScreenCaptureProcessor.kt +++ b/androidx-screencapture/src/main/kotlin/com/malinskiy/adam/junit4/android/screencapture/AdamScreenCaptureProcessor.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package com.malinskiy.adam.junit4.android.screencapture import android.os.Bundle @@ -42,7 +44,7 @@ import java.io.File * INSTRUMENTATION_STATUS: stream=. * INSTRUMENTATION_STATUS: test=ignoreTest */ -class AdamScreenCaptureProcessor : BasicScreenCaptureProcessor() { +public class AdamScreenCaptureProcessor : BasicScreenCaptureProcessor() { override fun process(capture: ScreenCapture): String? { val filename = super.process(capture) val absoluteScreenCapturePath = File(mDefaultScreenshotPath, filename) @@ -50,7 +52,7 @@ class AdamScreenCaptureProcessor : BasicScreenCaptureProcessor() { val bundle = Bundle(1) bundle.putString( "com.malinskiy.adam.junit4.android.screencapture.AdamScreenCaptureProcessor.v1", - absoluteScreenCapturePath.absolutePath + absoluteScreenCapturePath.absolutePath, ) InstrumentationRegistry.getInstrumentation().sendStatus(2, bundle) return filename diff --git a/androidx-screencapture/src/main/kotlin/com/malinskiy/adam/junit4/android/screencapture/AdamScreenCaptureRule.kt b/androidx-screencapture/src/main/kotlin/com/malinskiy/adam/junit4/android/screencapture/AdamScreenCaptureRule.kt index 86efa2a34..5e7ab15b2 100644 --- a/androidx-screencapture/src/main/kotlin/com/malinskiy/adam/junit4/android/screencapture/AdamScreenCaptureRule.kt +++ b/androidx-screencapture/src/main/kotlin/com/malinskiy/adam/junit4/android/screencapture/AdamScreenCaptureRule.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package com.malinskiy.adam.junit4.android.screencapture import androidx.test.runner.screenshot.Screenshot @@ -24,7 +26,7 @@ import org.junit.runners.model.Statement /** * JUnit4 rule that produces test events with screenshot paths */ -class AdamScreenCaptureRule : TestRule { +public class AdamScreenCaptureRule : TestRule { override fun apply(base: Statement, description: Description): Statement { return object : Statement() { override fun evaluate() { diff --git a/build.gradle.kts b/build.gradle.kts index fedf294c8..23384370b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,19 +1,29 @@ -import com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask -import java.util.* +import org.gradle.api.publish.PublishingExtension +import java.util.Locale plugins { - alias(libs.plugins.gradle.versions) + alias(libs.plugins.vanniktech.maven.publish) apply false } -fun isNonStable(version: String): Boolean { - val stableKeyword = listOf("RELEASE", "FINAL", "GA").any { version.uppercase(Locale.ENGLISH).contains(it) } - val regex = "^[0-9,.v-]+(-r)?$".toRegex() - val isStable = stableKeyword || regex.matches(version) - return isStable.not() -} +version = providers.environmentVariable("RELEASE_TAG") + .map { it.removePrefix("v") } + .getOrElse("0.1.0") + +subprojects { + version = rootProject.version -tasks.withType { - rejectVersionIf { - isNonStable(candidate.version) && !isNonStable(currentVersion) + plugins.withId("com.vanniktech.maven.publish") { + configure { + repositories { + maven { + name = "GitHubPackages" + url = uri("https://maven.pkg.github.com/ArthurKun21/adam") + credentials { + username = System.getenv("GITHUB_ACTOR") + password = System.getenv("GITHUB_TOKEN") + } + } + } + } } } diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt deleted file mode 100644 index 598e3d298..000000000 --- a/buildSrc/src/main/kotlin/Versions.kt +++ /dev/null @@ -1,3 +0,0 @@ -object Versions { - val adam = System.getenv("GIT_TAG_NAME") ?: "0.5.7" -} diff --git a/buildSrc/src/main/kotlin/adam.android.library.gradle.kts b/buildSrc/src/main/kotlin/adam.android.library.gradle.kts index e30ed2941..47b4986d8 100644 --- a/buildSrc/src/main/kotlin/adam.android.library.gradle.kts +++ b/buildSrc/src/main/kotlin/adam.android.library.gradle.kts @@ -4,7 +4,11 @@ import org.gradle.accessors.dm.LibrariesForLibs plugins { id("com.android.library") - // id("adam.code.lint") + id("adam.code.lint") +} + +kotlin { + explicitApi() } android { diff --git a/buildSrc/src/main/kotlin/adam.java.gradle.kts b/buildSrc/src/main/kotlin/adam.java.gradle.kts new file mode 100644 index 000000000..a71359e9b --- /dev/null +++ b/buildSrc/src/main/kotlin/adam.java.gradle.kts @@ -0,0 +1,17 @@ +import adam.buildlogic.ProjectConfig + +plugins { + id("java") + id("adam.code.lint") +} + +java { + sourceCompatibility = ProjectConfig.JavaVersion + targetCompatibility = ProjectConfig.JavaVersion +} + +tasks.withType { + compilerOptions { + jvmTarget.set(ProjectConfig.JvmTarget) + } +} diff --git a/buildSrc/src/main/kotlin/adam.jvm.gradle.kts b/buildSrc/src/main/kotlin/adam.jvm.gradle.kts index d94443022..86d3e6a4f 100644 --- a/buildSrc/src/main/kotlin/adam.jvm.gradle.kts +++ b/buildSrc/src/main/kotlin/adam.jvm.gradle.kts @@ -1,8 +1,13 @@ import adam.buildlogic.ProjectConfig +import org.gradle.testing.jacoco.tasks.JacocoReport plugins { kotlin("jvm") - // id("adam.code.lint") + id("adam.code.lint") +} + +kotlin { + explicitApi() } java { @@ -19,3 +24,11 @@ tasks.withType{ ) } } + +pluginManager.withPlugin("jacoco") { + tasks.withType().configureEach { + reports { + xml.required.set(true) + } + } +} diff --git a/buildSrc/src/main/kotlin/adam/buildlogic/IntegrationTestConfig.kt b/buildSrc/src/main/kotlin/adam/buildlogic/IntegrationTestConfig.kt new file mode 100644 index 000000000..6d02ecfaf --- /dev/null +++ b/buildSrc/src/main/kotlin/adam/buildlogic/IntegrationTestConfig.kt @@ -0,0 +1,87 @@ +package adam.buildlogic + +import org.gradle.api.Project +import org.gradle.api.artifacts.ConfigurationContainer +import org.gradle.api.artifacts.Dependency +import org.gradle.api.artifacts.dsl.DependencyHandler +import org.gradle.api.tasks.TaskProvider +import org.gradle.api.tasks.SourceSetContainer +import org.gradle.api.tasks.testing.Test +import org.gradle.testing.jacoco.plugins.JacocoTaskExtension +import org.gradle.testing.jacoco.tasks.JacocoReport +import org.gradle.kotlin.dsl.configure +import org.gradle.kotlin.dsl.getByName +import org.gradle.kotlin.dsl.named +import org.gradle.kotlin.dsl.register + +private const val INTEGRATION_TEST = "integrationTest" +private const val INTEGRATION_TEST_IMPLEMENTATION = "integrationTestImplementation" +private const val INTEGRATION_TEST_RUNTIME_ONLY = "integrationTestRuntimeOnly" +private const val JACOCO_INTEGRATION_TEST_REPORT = "jacocoIntegrationTestReport" + +fun Project.configureIntegrationTestSourceSet() { + extensions.configure { + create(INTEGRATION_TEST) { + compileClasspath += getByName("main").output + runtimeClasspath += getByName("main").output + } + } + + configurations.configureIntegrationTestConfigurations() +} + +fun DependencyHandler.integrationTestImplementation(dependencyNotation: Any): Dependency? = + add(INTEGRATION_TEST_IMPLEMENTATION, dependencyNotation) + +data class IntegrationTestTasks( + val integrationTest: TaskProvider, + val jacocoIntegrationTestReport: TaskProvider, +) + +fun Project.configureIntegrationTestTasks( + configureIntegrationTest: Test.(TaskProvider) -> Unit = {}, + configureJacocoReport: JacocoReport.(TaskProvider) -> Unit = {}, +): IntegrationTestTasks { + val sourceSets = extensions.getByType(SourceSetContainer::class.java) + + val integrationTest = tasks.register(INTEGRATION_TEST) { + description = "Runs integration tests" + group = "verification" + + testClassesDirs = sourceSets.getByName(INTEGRATION_TEST).output.classesDirs + classpath = sourceSets.getByName(INTEGRATION_TEST).runtimeClasspath + shouldRunAfter("test") + + extensions.configure(JacocoTaskExtension::class.java) { + includes = listOf("**") + } + } + + val jacocoIntegrationTestReport = tasks.register(JACOCO_INTEGRATION_TEST_REPORT) { + description = "Generates code coverage report for integrationTest task" + group = "verification" + + sourceSets(sourceSets.getByName(INTEGRATION_TEST)) + classDirectories.setFrom(sourceSets.getByName("main").output.classesDirs) + } + + integrationTest.configure { + outputs.upToDateWhen { false } + configureIntegrationTest(jacocoIntegrationTestReport) + } + + jacocoIntegrationTestReport.configure { + configureJacocoReport(integrationTest) + } + + tasks.named("check") { + dependsOn(integrationTest, jacocoIntegrationTestReport) + } + + return IntegrationTestTasks(integrationTest, jacocoIntegrationTestReport) +} + +private fun ConfigurationContainer.configureIntegrationTestConfigurations() { + getByName(INTEGRATION_TEST_IMPLEMENTATION).extendsFrom(getByName("implementation")) + getByName(INTEGRATION_TEST_RUNTIME_ONLY).extendsFrom(getByName("runtimeOnly")) +} diff --git a/buildSrc/src/main/kotlin/adam/buildlogic/MavenPomConfig.kt b/buildSrc/src/main/kotlin/adam/buildlogic/MavenPomConfig.kt new file mode 100644 index 000000000..25d111d7f --- /dev/null +++ b/buildSrc/src/main/kotlin/adam/buildlogic/MavenPomConfig.kt @@ -0,0 +1,30 @@ +package adam.buildlogic + +import org.gradle.api.publish.maven.MavenPom + +object AdamPublishing { + const val GROUP = "com.github.ArthurKun21" + const val REPOSITORY_URL = "https://github.com/ArthurKun21/adam" +} + +fun MavenPom.configureAdamPom() { + url.set(AdamPublishing.REPOSITORY_URL) + licenses { + license { + name.set("The Apache License, Version 2.0") + url.set("http://www.apache.org/licenses/LICENSE-2.0.txt") + } + } + developers { + developer { + id.set("ArthurKun21") + name.set("Arthur") + email.set("16458204+ArthurKun21@users.noreply.github.com") + } + } + scm { + connection.set("scm:git:git://github.com/ArthurKun21/adam.git") + developerConnection.set("scm:git:ssh://github.com/ArthurKun21/adam.git") + url.set(AdamPublishing.REPOSITORY_URL) + } +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a46077215..e59f4d596 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,28 +1,29 @@ [versions] -adam = "0.5.7" -kotlin = "1.9.10" -coroutines = "1.7.3" -annotations = "24.0.1" -ktor = "2.3.6" -logging = "3.0.5" -vertx = "4.4.6" -apacheCommonsPool2 = "2.11.1" -assertk = "0.27.0" +kotlin = "2.3.10" +coroutines = "1.10.2" +annotations = "26.0.2" +ktor = "3.4.0" +logcat = "0.4" +vertx = "5.0.7" +apacheCommonsPool2 = "2.13.1" +assertk = "0.28.1" junit4 = "4.13.2" -junit5 = "5.10.1" -junit5commons = "1.10.1" +junit5 = "6.0.2" +junit5commons = "6.0.2" imageComparison = "4.4.0" -dokka = "1.9.10" -grpc = "1.59.0" -grpcKotlin = "1.4.0" -grpcOkhttp = "1.59.0" -protobufGradle = "0.9.4" -protobuf = "3.25.0" + +grpc = "1.79.0" +grpcKotlin = "1.5.0" +grpcOkhttp = "1.79.0" +protobufGradle = "0.9.6" +protobuf = "4.33.5" javax = "1.3.2" androidGradle = "9.0.0" -testMonitor = "1.6.1" -testRunner = "1.5.2" -gradleVersionsPlugin = "0.49.0" +testMonitor = "1.8.0" +testRunner = "1.7.0" + +vanniktechMavenPublish = "0.36.0" +dokka = "2.1.0" spotless = "8.2.1" ktlint-core = "1.8.0" @@ -35,7 +36,7 @@ apache-commons-pool2 = { module = "org.apache.commons:commons-pool2", version.re coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines" } coroutines-debug = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-debug", version.ref = "coroutines" } ktor-network = { module = "io.ktor:ktor-network-jvm", version.ref = "ktor" } -logging = { module = "io.github.microutils:kotlin-logging", version.ref = "logging" } +logcat = { module = "com.squareup.logcat:logcat", version.ref = "logcat" } vertx-core = { module = "io.vertx:vertx-core", version.ref = "vertx" } vertx-kotlin = { module = "io.vertx:vertx-lang-kotlin", version.ref = "vertx" } vertx-coroutines = { module = "io.vertx:vertx-lang-kotlin-coroutines", version.ref = "vertx" } @@ -66,4 +67,4 @@ kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" } protobuf = { id = "com.google.protobuf", version.ref = "protobufGradle" } android-library = { id = "com.android.library", version.ref = "androidGradle" } -gradle-versions = { id = "com.github.ben-manes.versions", version.ref = "gradleVersionsPlugin" } +vanniktech-maven-publish = { id = "com.vanniktech.maven.publish", version.ref = "vanniktechMavenPublish" } diff --git a/server/server-stub-junit4/build.gradle.kts b/server/server-stub-junit4/build.gradle.kts index 7730cc603..5f0e3fa83 100644 --- a/server/server-stub-junit4/build.gradle.kts +++ b/server/server-stub-junit4/build.gradle.kts @@ -1,3 +1,6 @@ +import adam.buildlogic.AdamPublishing +import adam.buildlogic.configureAdamPom + /* * Copyright (C) 2021 Anton Malinskiy * @@ -17,16 +20,19 @@ plugins { id("adam.jvm") id("jacoco") + alias(libs.plugins.vanniktech.maven.publish) } +mavenPublishing { + coordinates(AdamPublishing.GROUP, "server-stub-junit4", version.toString()) -tasks.jacocoTestReport { - reports { - xml.required.set(true) + pom { + name.set("server-stub-junit4") + description.set("Android Debug Bridge helper - Server stub JUnit4") + configureAdamPom() } } - dependencies { api(project(":server:server-stub")) implementation(libs.junit4) diff --git a/server/server-stub-junit4/src/main/kotlin/com/malinskiy/adam/server/junit4/AdbServerRule.kt b/server/server-stub-junit4/src/main/kotlin/com/malinskiy/adam/server/junit4/AdbServerRule.kt index d73600524..1eceed60e 100644 --- a/server/server-stub-junit4/src/main/kotlin/com/malinskiy/adam/server/junit4/AdbServerRule.kt +++ b/server/server-stub-junit4/src/main/kotlin/com/malinskiy/adam/server/junit4/AdbServerRule.kt @@ -26,9 +26,9 @@ import org.junit.rules.TestRule import org.junit.runner.Description import org.junit.runners.model.Statement -class AdbServerRule : TestRule { - lateinit var server: AndroidDebugBridgeServer - val client: AndroidDebugBridgeClient +public class AdbServerRule : TestRule { + public lateinit var server: AndroidDebugBridgeServer + public val client: AndroidDebugBridgeClient get() = server.client override fun apply(base: Statement, description: Description): Statement { @@ -50,8 +50,7 @@ class AdbServerRule : TestRule { } } - fun session(block: suspend Session.() -> Unit) { + public fun session(block: suspend Session.() -> Unit) { server.session(block) } } - diff --git a/server/server-stub-junit4/src/test/kotlin/com/malinskiy/adam/server/junit4/AdbServerRuleTest.kt b/server/server-stub-junit4/src/test/kotlin/com/malinskiy/adam/server/junit4/AdbServerRuleTest.kt index 771c1fd98..33d40bec3 100644 --- a/server/server-stub-junit4/src/test/kotlin/com/malinskiy/adam/server/junit4/AdbServerRuleTest.kt +++ b/server/server-stub-junit4/src/test/kotlin/com/malinskiy/adam/server/junit4/AdbServerRuleTest.kt @@ -22,14 +22,14 @@ import kotlinx.coroutines.runBlocking import org.junit.Rule import org.junit.Test -class AdbServerRuleTest { +public class AdbServerRuleTest { @get:Rule - val server = AdbServerRule() - val client: AndroidDebugBridgeClient + public val server: AdbServerRule = AdbServerRule() + public val client: AndroidDebugBridgeClient get() = server.client @Test - fun test() { + public fun test() { server.session { expectAdbServerVersion() .accept() diff --git a/server/server-stub-junit5/build.gradle.kts b/server/server-stub-junit5/build.gradle.kts index 931ea8a0d..387483ec3 100644 --- a/server/server-stub-junit5/build.gradle.kts +++ b/server/server-stub-junit5/build.gradle.kts @@ -1,3 +1,6 @@ +import adam.buildlogic.AdamPublishing +import adam.buildlogic.configureAdamPom + /* * Copyright (C) 2021 Anton Malinskiy * @@ -17,11 +20,16 @@ plugins { id("adam.jvm") id("jacoco") + alias(libs.plugins.vanniktech.maven.publish) } -tasks.jacocoTestReport { - reports { - xml.required.set(true) +mavenPublishing { + coordinates(AdamPublishing.GROUP, "server-stub-junit5", version.toString()) + + pom { + name.set("server-stub-junit5") + description.set("Android Debug Bridge helper - Server stub JUnit5") + configureAdamPom() } } diff --git a/server/server-stub-junit5/src/main/kotlin/com/malinskiy/adam/server/junit5/AdbClient.kt b/server/server-stub-junit5/src/main/kotlin/com/malinskiy/adam/server/junit5/AdbClient.kt index 068db20d8..baf4bbe4b 100644 --- a/server/server-stub-junit5/src/main/kotlin/com/malinskiy/adam/server/junit5/AdbClient.kt +++ b/server/server-stub-junit5/src/main/kotlin/com/malinskiy/adam/server/junit5/AdbClient.kt @@ -18,4 +18,4 @@ package com.malinskiy.adam.server.junit5 @Target(AnnotationTarget.FIELD, AnnotationTarget.PROPERTY) @Retention(AnnotationRetention.RUNTIME) -annotation class AdbClient +public annotation class AdbClient diff --git a/server/server-stub-junit5/src/main/kotlin/com/malinskiy/adam/server/junit5/AdbServer.kt b/server/server-stub-junit5/src/main/kotlin/com/malinskiy/adam/server/junit5/AdbServer.kt index 6c798e109..4d5d22abb 100644 --- a/server/server-stub-junit5/src/main/kotlin/com/malinskiy/adam/server/junit5/AdbServer.kt +++ b/server/server-stub-junit5/src/main/kotlin/com/malinskiy/adam/server/junit5/AdbServer.kt @@ -18,4 +18,4 @@ package com.malinskiy.adam.server.junit5 @Target(AnnotationTarget.FIELD, AnnotationTarget.PROPERTY) @Retention(AnnotationRetention.RUNTIME) -annotation class AdbServer +public annotation class AdbServer diff --git a/server/server-stub-junit5/src/main/kotlin/com/malinskiy/adam/server/junit5/AdbServerExtension.kt b/server/server-stub-junit5/src/main/kotlin/com/malinskiy/adam/server/junit5/AdbServerExtension.kt index 85f0b19b0..3c1eaf9f3 100644 --- a/server/server-stub-junit5/src/main/kotlin/com/malinskiy/adam/server/junit5/AdbServerExtension.kt +++ b/server/server-stub-junit5/src/main/kotlin/com/malinskiy/adam/server/junit5/AdbServerExtension.kt @@ -31,13 +31,12 @@ import kotlin.reflect.full.hasAnnotation import kotlin.reflect.full.isSubtypeOf import kotlin.reflect.full.memberProperties - -class AdbServerExtension : BeforeEachCallback, AfterEachCallback { - lateinit var server: AndroidDebugBridgeServer - val client: AndroidDebugBridgeClient +public class AdbServerExtension : BeforeEachCallback, AfterEachCallback { + public lateinit var server: AndroidDebugBridgeServer + public val client: AndroidDebugBridgeClient get() = server.client - fun session(block: suspend Session.() -> Unit) { + public fun session(block: suspend Session.() -> Unit) { server.listen { input, output -> val session = Session(input, output) block(session) @@ -55,7 +54,10 @@ class AdbServerExtension : BeforeEachCallback, AfterEachCallback { private fun setupServerField(context: ExtensionContext) { val instance = context.testInstance.get() instance::class.memberProperties - .filter { it.hasAnnotation() && it.returnType.isSubtypeOf(AndroidDebugBridgeServer::class.createType()) } + .filter { + it.hasAnnotation() && + it.returnType.isSubtypeOf(AndroidDebugBridgeServer::class.createType()) + } .filterIsInstance>() .forEach { prop -> prop.setter.call(instance, server) @@ -65,14 +67,17 @@ class AdbServerExtension : BeforeEachCallback, AfterEachCallback { private fun setupClientField(context: ExtensionContext) { val instance = context.testInstance.get() instance::class.memberProperties - .filter { it.hasAnnotation() && it.returnType.isSubtypeOf(AndroidDebugBridgeClient::class.createType()) } + .filter { + it.hasAnnotation() && + it.returnType.isSubtypeOf(AndroidDebugBridgeClient::class.createType()) + } .filterIsInstance>() .forEach { prop -> prop.setter.call(instance, client) } } - override fun afterEach(context: ExtensionContext?) { + override fun afterEach(context: ExtensionContext) { runBlocking { withContext(NonCancellable) { server.dispose() @@ -80,4 +85,3 @@ class AdbServerExtension : BeforeEachCallback, AfterEachCallback { } } } - diff --git a/server/server-stub-junit5/src/main/kotlin/com/malinskiy/adam/server/junit5/AdbTest.kt b/server/server-stub-junit5/src/main/kotlin/com/malinskiy/adam/server/junit5/AdbTest.kt index f2a4d89c2..4771decb1 100644 --- a/server/server-stub-junit5/src/main/kotlin/com/malinskiy/adam/server/junit5/AdbTest.kt +++ b/server/server-stub-junit5/src/main/kotlin/com/malinskiy/adam/server/junit5/AdbTest.kt @@ -23,4 +23,4 @@ import java.lang.annotation.Inherited @ExtendWith(AdbServerExtension::class) @Inherited @Retention(AnnotationRetention.RUNTIME) -annotation class AdbTest +public annotation class AdbTest diff --git a/server/server-stub-junit5/src/test/kotlin/com/malinskiy/adam/server/junit5/AdbServerExtensionTest.kt b/server/server-stub-junit5/src/test/kotlin/com/malinskiy/adam/server/junit5/AdbServerExtensionTest.kt index f17dadd22..2d046a862 100644 --- a/server/server-stub-junit5/src/test/kotlin/com/malinskiy/adam/server/junit5/AdbServerExtensionTest.kt +++ b/server/server-stub-junit5/src/test/kotlin/com/malinskiy/adam/server/junit5/AdbServerExtensionTest.kt @@ -27,15 +27,15 @@ import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @ExtendWith(AdbServerExtension::class) -class AdbServerExtensionTest { +public class AdbServerExtensionTest { @AdbClient - lateinit var client: AndroidDebugBridgeClient + public lateinit var client: AndroidDebugBridgeClient @AdbServer - lateinit var server: AndroidDebugBridgeServer + public lateinit var server: AndroidDebugBridgeServer @Test - fun testX() { + public fun testX() { server.session { expectAdbServerVersion() .accept() @@ -49,7 +49,7 @@ class AdbServerExtensionTest { } @Test - fun testMultisession() { + public fun testMultisession() { runBlocking { server.multipleSessions { serial("emulator-5554") { diff --git a/server/server-stub/build.gradle.kts b/server/server-stub/build.gradle.kts index 93288d76b..082015ba1 100644 --- a/server/server-stub/build.gradle.kts +++ b/server/server-stub/build.gradle.kts @@ -1,3 +1,9 @@ +import adam.buildlogic.AdamPublishing +import adam.buildlogic.configureAdamPom +import adam.buildlogic.configureIntegrationTestSourceSet +import adam.buildlogic.configureIntegrationTestTasks +import adam.buildlogic.integrationTestImplementation + /* * Copyright (C) 2021 Anton Malinskiy * @@ -17,62 +23,34 @@ plugins { id("adam.jvm") id("jacoco") + alias(libs.plugins.vanniktech.maven.publish) } +mavenPublishing { + coordinates(AdamPublishing.GROUP, "server-stub", version.toString()) -sourceSets { - create("integrationTest") { - compileClasspath += sourceSets.main.get().output - runtimeClasspath += sourceSets.main.get().output + pom { + name.set("server-stub") + description.set("Android Debug Bridge helper - Server stub") + configureAdamPom() } } -val integrationTestImplementation: Configuration by configurations.getting { - extendsFrom(configurations.implementation.get()) -} - -configurations["integrationTestRuntimeOnly"].extendsFrom(configurations.runtimeOnly.get()) - -fun DependencyHandler.`integrationTestImplementation`(dependencyNotation: Any): Dependency? = - add("integrationTestImplementation", dependencyNotation) - +configureIntegrationTestSourceSet() -val integrationTest = tasks.register("integrationTest") { - description = "Runs integration tests" - group = "verification" +val integrationTestTasks = configureIntegrationTestTasks( + configureJacocoReport = { integrationTest -> + executionData(integrationTest) + }, +) - testClassesDirs = sourceSets["integrationTest"].output.classesDirs - classpath = sourceSets["integrationTest"].runtimeClasspath - shouldRunAfter("test") - - jacoco { - include("**") - } -} -integrationTest.configure { - outputs.upToDateWhen { false } -} - -val jacocoIntegrationTestReport = tasks.register("jacocoIntegrationTestReport") { - description = "Generates code coverage report for integrationTest task" - group = "verification" - reports { - xml.required.set(true) - } - - executionData(integrationTest) - sourceSets(sourceSets.getByName("integrationTest")) - classDirectories.setFrom(sourceSets.getByName("main").output.classesDirs) -} -tasks.check { dependsOn(integrationTest, jacocoIntegrationTestReport) } - -tasks.jacocoTestReport { +val jacocoIntegrationTestReport = integrationTestTasks.jacocoIntegrationTestReport +jacocoIntegrationTestReport.configure { reports { xml.required.set(true) } } - dependencies { implementation(kotlin("stdlib-jdk8")) implementation(libs.coroutines.core) diff --git a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/AndroidDebugBridgeServer.kt b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/AndroidDebugBridgeServer.kt index b3c8497c0..5a339de4c 100644 --- a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/AndroidDebugBridgeServer.kt +++ b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/AndroidDebugBridgeServer.kt @@ -20,7 +20,7 @@ import com.malinskiy.adam.AndroidDebugBridgeClient import com.malinskiy.adam.AndroidDebugBridgeClientFactory import com.malinskiy.adam.server.stub.dsl.Expectation import com.malinskiy.adam.server.stub.dsl.Session -import io.ktor.network.selector.ActorSelectorManager +import io.ktor.network.selector.SelectorManager import io.ktor.network.sockets.InetSocketAddress import io.ktor.network.sockets.ServerSocket import io.ktor.network.sockets.aSocket @@ -30,7 +30,6 @@ import io.ktor.network.sockets.toJavaAddress import io.ktor.util.network.port import io.ktor.utils.io.ByteReadChannel import io.ktor.utils.io.ByteWriteChannel -import io.ktor.utils.io.close import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob @@ -38,45 +37,45 @@ import kotlinx.coroutines.async import kotlinx.coroutines.cancelChildren import kotlinx.coroutines.isActive import kotlinx.coroutines.newFixedThreadPoolContext +import kotlinx.coroutines.runBlocking import kotlin.coroutines.CoroutineContext - -class AndroidDebugBridgeServer : CoroutineScope { +public class AndroidDebugBridgeServer : CoroutineScope { private val executionDispatcher by lazy { newFixedThreadPoolContext(4, "AndroidDebugBridgeServer") } override val coroutineContext: CoroutineContext get() = executionDispatcher - val client: AndroidDebugBridgeClient by lazy { + public val client: AndroidDebugBridgeClient by lazy { AndroidDebugBridgeClientFactory().apply { port = this@AndroidDebugBridgeServer.port }.build() } private val job = SupervisorJob() - var port: Int = 0 + public var port: Int = 0 - lateinit var server: ServerSocket - lateinit var selector: ActorSelectorManager + public lateinit var server: ServerSocket + public lateinit var selector: SelectorManager - fun start(): AndroidDebugBridgeClient { + public fun start(): AndroidDebugBridgeClient { val address = InetSocketAddress("127.0.0.1", port) - selector = ActorSelectorManager(Dispatchers.IO) - server = aSocket(selector).tcp().bind(address) + selector = SelectorManager(Dispatchers.IO) + server = runBlocking { aSocket(selector).tcp().bind(address) } port = server.localAddress.toJavaAddress().port return client } - fun session(block: suspend Session.() -> Unit) { + public fun session(block: suspend Session.() -> Unit) { listen { input, output -> val session = Session(input, output) block(session) } } - fun multipleSessions(block: suspend Expectation.() -> Unit) { + public fun multipleSessions(block: suspend Expectation.() -> Unit) { async(context = job) { val expectation = Expectation() block(expectation) @@ -94,14 +93,14 @@ class AndroidDebugBridgeServer : CoroutineScope { } catch (e: Throwable) { e.printStackTrace() } finally { - output.close() + output.flushAndClose() socket.close() } } } } - fun listen(block: suspend (input: ServerReadChannel, output: ServerWriteChannel) -> Unit) { + public fun listen(block: suspend (input: ServerReadChannel, output: ServerWriteChannel) -> Unit) { async(context = job) { try { val socket = server.accept() @@ -113,7 +112,7 @@ class AndroidDebugBridgeServer : CoroutineScope { } catch (e: Throwable) { e.printStackTrace() } finally { - output.close() + output.flushAndClose() socket.close() } } catch (e: Exception) { @@ -122,7 +121,7 @@ class AndroidDebugBridgeServer : CoroutineScope { } } - suspend fun dispose() { + public suspend fun dispose() { if (job.isActive) { job.complete() job.children.iterator().forEach { diff --git a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/ConsoleReadChannel.kt b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/ConsoleReadChannel.kt index 6ddf4d21e..fae3a10cc 100644 --- a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/ConsoleReadChannel.kt +++ b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/ConsoleReadChannel.kt @@ -20,10 +20,12 @@ import assertk.assertThat import assertk.assertions.isEqualTo import assertk.assertions.startsWith import io.ktor.utils.io.ByteReadChannel -import io.ktor.utils.io.readUTF8Line +import io.ktor.utils.io.readLine -class ConsoleReadChannel(private val delegate: ByteReadChannel) : ByteReadChannel by delegate { - suspend fun receiveCommand() = delegate.readUTF8Line()!! - suspend fun receiveAuth() = receiveCommand().apply { assertThat(this).startsWith("auth ") }.substringAfter("auth ") - suspend fun receiveExit() = receiveCommand().apply { assertThat(this).isEqualTo("quit") } +public class ConsoleReadChannel(private val delegate: ByteReadChannel) : ByteReadChannel by delegate { + public suspend fun receiveCommand(): String = delegate.readLine()!! + public suspend fun receiveAuth(): String = receiveCommand().apply { + assertThat(this).startsWith("auth ") + }.substringAfter("auth ") + public suspend fun receiveExit(): String = receiveCommand().apply { assertThat(this).isEqualTo("quit") } } diff --git a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/ConsoleWriteChannel.kt b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/ConsoleWriteChannel.kt index 026df0f08..0e4071603 100644 --- a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/ConsoleWriteChannel.kt +++ b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/ConsoleWriteChannel.kt @@ -19,8 +19,8 @@ package com.malinskiy.adam.server.stub import io.ktor.utils.io.ByteWriteChannel import io.ktor.utils.io.writeStringUtf8 -class ConsoleWriteChannel(private val delegate: ByteWriteChannel) : ByteWriteChannel by delegate { - suspend fun writeAuth() { +public class ConsoleWriteChannel(private val delegate: ByteWriteChannel) : ByteWriteChannel by delegate { + public suspend fun writeAuth() { delegate.writeStringUtf8("Android Console: Authentication required") delegate.writeStringUtf8("Android Console: type 'auth ' to authenticate") delegate.writeStringUtf8("Android Console: you can find your in") @@ -30,5 +30,7 @@ class ConsoleWriteChannel(private val delegate: ByteWriteChannel) : ByteWriteCha delegate.writeStringUtf8("OK\r\n") } - suspend fun respond(message: String) = delegate.writeStringUtf8(message) + public suspend fun respond(message: String) { + delegate.writeStringUtf8(message) + } } diff --git a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/EmulatorConsoleServer.kt b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/EmulatorConsoleServer.kt index 283359bcc..ca7d298b4 100644 --- a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/EmulatorConsoleServer.kt +++ b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/EmulatorConsoleServer.kt @@ -18,7 +18,7 @@ package com.malinskiy.adam.server.stub import com.malinskiy.adam.AndroidDebugBridgeClient import com.malinskiy.adam.AndroidDebugBridgeClientFactory -import io.ktor.network.selector.ActorSelectorManager +import io.ktor.network.selector.SelectorManager import io.ktor.network.sockets.InetSocketAddress import io.ktor.network.sockets.aSocket import io.ktor.network.sockets.openReadChannel @@ -27,7 +27,6 @@ import io.ktor.network.sockets.toJavaAddress import io.ktor.util.network.port import io.ktor.utils.io.ByteReadChannel import io.ktor.utils.io.ByteWriteChannel -import io.ktor.utils.io.close import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob @@ -40,7 +39,7 @@ import java.io.Closeable import kotlin.coroutines.CoroutineContext import java.net.InetSocketAddress as JavaInetSocketAddress -class EmulatorConsoleServer : CoroutineScope, Closeable { +public class EmulatorConsoleServer : CoroutineScope, Closeable { private val executionDispatcher by lazy { newFixedThreadPoolContext(4, "EmulatorConsoleServer") } @@ -48,11 +47,13 @@ class EmulatorConsoleServer : CoroutineScope, Closeable { get() = executionDispatcher private val job = SupervisorJob() - var port: Int = 0 + public var port: Int = 0 - suspend fun startAndListen(block: suspend (ConsoleReadChannel, ConsoleWriteChannel) -> Unit): Pair { + public suspend fun startAndListen( + block: suspend (ConsoleReadChannel, ConsoleWriteChannel) -> Unit, + ): Pair { val address = InetSocketAddress("127.0.0.1", port) - val server = aSocket(ActorSelectorManager(Dispatchers.IO)).tcp().bind(address) + val server = aSocket(SelectorManager(Dispatchers.IO)).tcp().bind(address) port = server.localAddress.toJavaAddress().port async(context = job) { @@ -66,7 +67,7 @@ class EmulatorConsoleServer : CoroutineScope, Closeable { } catch (e: Throwable) { e.printStackTrace() } finally { - output.close() + output.flushAndClose() socket.close() } } @@ -75,7 +76,7 @@ class EmulatorConsoleServer : CoroutineScope, Closeable { return Pair(AndroidDebugBridgeClientFactory().build(), JavaInetSocketAddress(address.hostname, port)) } - override fun close() = runBlocking { + override fun close(): Unit = runBlocking { job.cancelAndJoin() } } diff --git a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/ServerReadChannel.kt b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/ServerReadChannel.kt index 3db344b91..5d3a681b1 100644 --- a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/ServerReadChannel.kt +++ b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/ServerReadChannel.kt @@ -25,14 +25,24 @@ import com.malinskiy.adam.request.shell.v2.MessageType import com.malinskiy.adam.request.sync.v2.CompressionType import io.ktor.util.cio.writeChannel import io.ktor.utils.io.ByteReadChannel -import io.ktor.utils.io.close -import io.ktor.utils.io.readIntLittleEndian +import io.ktor.utils.io.readFully +import io.ktor.utils.io.writeFully import kotlinx.coroutines.Job import java.io.File import kotlin.coroutines.coroutineContext +import io.ktor.utils.io.readByte as channelReadByte +import io.ktor.utils.io.readInt as channelReadInt -class ServerReadChannel(private val delegate: ByteReadChannel) : ByteReadChannel by delegate { - suspend fun receiveCommand(): String { +public class ServerReadChannel(private val delegate: ByteReadChannel) : ByteReadChannel by delegate { + + public suspend fun readByte(): Byte = delegate.channelReadByte() + + public suspend fun readIntLittleEndian(): Int = Integer.reverseBytes(delegate.channelReadInt()) + + public suspend fun readFully(dst: ByteArray, offset: Int, length: Int) { + delegate.readFully(dst, offset, offset + length) + } + public suspend fun receiveCommand(): String { val bytes = ByteArray(4) readFully(bytes, 0, 4) val length = String(bytes, Const.DEFAULT_TRANSPORT_ENCODING).toInt(16) @@ -41,103 +51,119 @@ class ServerReadChannel(private val delegate: ByteReadChannel) : ByteReadChannel return String(request, Const.DEFAULT_TRANSPORT_ENCODING) } - suspend fun receiveBytes(length: Int): ByteArray { + public suspend fun receiveBytes(length: Int): ByteArray { val bytes = ByteArray(length) readFully(bytes, 0, length) return bytes } - suspend fun receiveStat(): String { + public suspend fun receiveStat(): String { val protocolMessage = receiveProtocolMessage() val message = String(protocolMessage, Const.DEFAULT_TRANSPORT_ENCODING) - if (message != "STAT") throw RuntimeException( - "Unexpected protocol message $message" - ) + if (message != "STAT") { + throw RuntimeException( + "Unexpected protocol message $message", + ) + } val size = readIntLittleEndian() val request = ByteArray(size) readFully(request, 0, size) return String(request, Const.DEFAULT_TRANSPORT_ENCODING) } - suspend fun receiveStatV2(): String { + public suspend fun receiveStatV2(): String { val protocolMessage = receiveProtocolMessage() val message = String(protocolMessage, Const.DEFAULT_TRANSPORT_ENCODING) - if (message != "LST2") throw RuntimeException( - "Unexpected protocol message $message" - ) + if (message != "LST2") { + throw RuntimeException( + "Unexpected protocol message $message", + ) + } val size = readIntLittleEndian() val request = ByteArray(size) readFully(request, 0, size) return String(request, Const.DEFAULT_TRANSPORT_ENCODING) } - suspend fun receiveList(): String { + public suspend fun receiveList(): String { val protocolMessage = receiveProtocolMessage() val message = String(protocolMessage, Const.DEFAULT_TRANSPORT_ENCODING) - if (message != "LIST") throw RuntimeException( - "Unexpected protocol message $message" - ) + if (message != "LIST") { + throw RuntimeException( + "Unexpected protocol message $message", + ) + } val size = readIntLittleEndian() val request = ByteArray(size) readFully(request, 0, size) return String(request, Const.DEFAULT_TRANSPORT_ENCODING) } - suspend fun receiveListV2(): String { + public suspend fun receiveListV2(): String { val protocolMessage = receiveProtocolMessage() val message = String(protocolMessage, Const.DEFAULT_TRANSPORT_ENCODING) - if (message != "LIS2") throw RuntimeException( - "Unexpected protocol message $message" - ) + if (message != "LIS2") { + throw RuntimeException( + "Unexpected protocol message $message", + ) + } val size = readIntLittleEndian() val request = ByteArray(size) readFully(request, 0, size) return String(request, Const.DEFAULT_TRANSPORT_ENCODING) } - suspend fun receiveSend(): String { + public suspend fun receiveSend(): String { val protocolMessage = receiveProtocolMessage() val message = String(protocolMessage, Const.DEFAULT_TRANSPORT_ENCODING) - if (message != "SEND") throw RuntimeException( - "Unexpected protocol message $message" - ) + if (message != "SEND") { + throw RuntimeException( + "Unexpected protocol message $message", + ) + } val size = readIntLittleEndian() val request = ByteArray(size) readFully(request, 0, size) return String(request, Const.DEFAULT_TRANSPORT_ENCODING) } - suspend fun receiveSendV2(): Triple { + public suspend fun receiveSendV2(): Triple { val protocolMessage = receiveProtocolMessage() var message = String(protocolMessage, Const.DEFAULT_TRANSPORT_ENCODING) - if (message != "SND2") throw RuntimeException( - "Unexpected protocol message $message" - ) + if (message != "SND2") { + throw RuntimeException( + "Unexpected protocol message $message", + ) + } val size = readIntLittleEndian() val request = ByteArray(size) readFully(request, 0, size) message = String(receiveProtocolMessage(), Const.DEFAULT_TRANSPORT_ENCODING) - if (message != "SND2") throw RuntimeException( - "Unexpected protocol message $message" - ) + if (message != "SND2") { + throw RuntimeException( + "Unexpected protocol message $message", + ) + } val mode = readIntLittleEndian() val flags = readIntLittleEndian() return Triple(String(request, Const.DEFAULT_TRANSPORT_ENCODING), mode, flags) } - suspend fun receiveProtocolMessage(): ByteArray { + public suspend fun receiveProtocolMessage(): ByteArray { val bytes = ByteArray(4) readFully(bytes, 0, 4) return bytes } - suspend fun receiveRecv(): String { + public suspend fun receiveRecv(): String { val protocolMessage = receiveProtocolMessage() val message = String(protocolMessage, Const.DEFAULT_TRANSPORT_ENCODING) - if (message != "RECV") throw RuntimeException( - "Unexpected protocol message $message" - ) + if (message != "RECV") { + throw RuntimeException( + "Unexpected protocol message $message", + ) + } val size = readIntLittleEndian() val request = ByteArray(size) @@ -145,7 +171,7 @@ class ServerReadChannel(private val delegate: ByteReadChannel) : ByteReadChannel return String(request, Const.DEFAULT_TRANSPORT_ENCODING) } - suspend fun receiveRecv2(): String { + public suspend fun receiveRecv2(): String { val protocolMessage = receiveProtocolMessage() var message = String(protocolMessage, Const.DEFAULT_TRANSPORT_ENCODING) if (message != "RCV2") throw RuntimeException("Unexpected protocol message $message") @@ -164,7 +190,7 @@ class ServerReadChannel(private val delegate: ByteReadChannel) : ByteReadChannel return String(request, Const.DEFAULT_TRANSPORT_ENCODING) } - suspend fun receiveFile(file: File): File { + public suspend fun receiveFile(file: File): File { val job = Job() val channel = file.writeChannel(coroutineContext + job) val headerBuffer = ByteArray(8) @@ -177,9 +203,10 @@ class ServerReadChannel(private val delegate: ByteReadChannel) : ByteReadChannel when { header.contentEquals(Const.Message.DONE) -> { channel.flush() - channel.close() + channel.flushAndClose() return file } + header.contentEquals(Const.Message.DATA) -> { val available = headerBuffer.copyOfRange(4, 8).toInt() if (available > Const.MAX_FILE_PACKET_LENGTH) { @@ -188,6 +215,7 @@ class ServerReadChannel(private val delegate: ByteReadChannel) : ByteReadChannel readFully(dataBuffer, 0, available) channel.writeFully(dataBuffer, 0, available) } + else -> throw RuntimeException("Something bad happened") } } @@ -197,7 +225,7 @@ class ServerReadChannel(private val delegate: ByteReadChannel) : ByteReadChannel } } - suspend fun receiveShellV2Stdin(): String { + public suspend fun receiveShellV2Stdin(): String { readByte().apply { assertThat(this).isEqualTo(MessageType.STDIN.toValue().toByte()) } val size = readIntLittleEndian() val request = ByteArray(size) @@ -205,7 +233,7 @@ class ServerReadChannel(private val delegate: ByteReadChannel) : ByteReadChannel return String(request, Const.DEFAULT_TRANSPORT_ENCODING) } - suspend fun receiveShellV2StdinClose() { + public suspend fun receiveShellV2StdinClose() { readByte().apply { assertThat(this).isEqualTo(MessageType.CLOSE_STDIN.toValue().toByte()) } assertThat(readIntLittleEndian()).isEqualTo(0) } diff --git a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/ServerWriteChannel.kt b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/ServerWriteChannel.kt index 038a02556..365f02161 100644 --- a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/ServerWriteChannel.kt +++ b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/ServerWriteChannel.kt @@ -19,33 +19,54 @@ package com.malinskiy.adam.server.stub import com.malinskiy.adam.Const import com.malinskiy.adam.request.shell.v2.MessageType import io.ktor.utils.io.ByteWriteChannel -import io.ktor.utils.io.writeByte import io.ktor.utils.io.writeFully -import io.ktor.utils.io.writeIntLittleEndian -import io.ktor.utils.io.writeLongLittleEndian import io.ktor.utils.io.writeStringUtf8 import java.nio.ByteBuffer +import io.ktor.utils.io.writeByte as channelWriteByte +import io.ktor.utils.io.writeInt as channelWriteInt +import io.ktor.utils.io.writeLong as channelWriteLong -class ServerWriteChannel(private val delegate: ByteWriteChannel) : ByteWriteChannel by delegate { +public class ServerWriteChannel(private val delegate: ByteWriteChannel) : ByteWriteChannel by delegate { private suspend fun write(request: ByteArray, length: Int? = null) { - val requestBuffer = ByteBuffer.wrap(request, 0, length ?: request.size) - delegate.writeFully(requestBuffer) + delegate.writeFully(request, 0, length ?: request.size) } - suspend fun respond(request: ByteArray, length: Int? = null) = write(request, length) + public suspend fun writeIntLittleEndian(value: Int) { + delegate.channelWriteInt(Integer.reverseBytes(value)) + } + + private suspend fun writeLongLittleEndian(value: Long) { + delegate.channelWriteLong(java.lang.Long.reverseBytes(value)) + } + + public suspend fun writeFully(src: ByteArray) { + delegate.writeFully(src) + } + + public suspend fun writeFully(src: ByteArray, offset: Int, length: Int) { + delegate.writeFully(src, offset, offset + length) + } + + public suspend fun writeByte(value: Byte) { + delegate.channelWriteByte(value) + } + + public suspend fun respond(request: ByteArray, length: Int? = null) { + write(request, length) + } - suspend fun respondOkay() { + public suspend fun respondOkay() { respond(Const.Message.OKAY) } - suspend fun respondStat(size: Int, mode: Int = 0, lastModified: Int = 0) { + public suspend fun respondStat(size: Int, mode: Int = 0, lastModified: Int = 0) { respond(Const.Message.LSTAT_V1) writeIntLittleEndian(mode) writeIntLittleEndian(size) writeIntLittleEndian(lastModified) } - suspend fun respondStatV2( + public suspend fun respondStatV2( mode: Int, size: Int, error: Int, @@ -56,7 +77,7 @@ class ServerWriteChannel(private val delegate: ByteWriteChannel) : ByteWriteChan gid: Int, atime: Int, mtime: Int, - ctime: Int + ctime: Int, ) { respond(Const.Message.LSTAT_V2) writeIntLittleEndian(error) @@ -72,25 +93,25 @@ class ServerWriteChannel(private val delegate: ByteWriteChannel) : ByteWriteChan writeLongLittleEndian(ctime.toLong()) } - suspend fun respondData(byteArray: ByteArray) { + public suspend fun respondData(byteArray: ByteArray) { respond(Const.Message.DATA) writeIntLittleEndian(byteArray.size) writeFully(byteArray, 0, byteArray.size) } - suspend fun respondDone() { + public suspend fun respondDone() { respond(Const.Message.DONE) } - suspend fun respondDoneDone() { + public suspend fun respondDoneDone() { respond(Const.Message.DONEDONE) } - suspend fun respondFailFail() { + public suspend fun respondFailFail() { respond(Const.Message.FAILFAIL) } - suspend fun respondList(size: Int, mode: Int = 0, lastModified: Int = 0, name: String) { + public suspend fun respondList(size: Int, mode: Int = 0, lastModified: Int = 0, name: String) { respond(Const.Message.DENT_V1) writeIntLittleEndian(mode) writeIntLittleEndian(size) @@ -99,7 +120,7 @@ class ServerWriteChannel(private val delegate: ByteWriteChannel) : ByteWriteChan writeStringUtf8(name) } - suspend fun respondListV2( + public suspend fun respondListV2( name: String, mode: Int = 0, size: Int, @@ -111,7 +132,7 @@ class ServerWriteChannel(private val delegate: ByteWriteChannel) : ByteWriteChan gid: Int, atime: Int, mtime: Int, - ctime: Int + ctime: Int, ) { respond(Const.Message.DENT_V2) writeIntLittleEndian(error) @@ -129,7 +150,7 @@ class ServerWriteChannel(private val delegate: ByteWriteChannel) : ByteWriteChan writeStringUtf8(name) } - suspend fun respondStringV1(message: String) { + public suspend fun respondStringV1(message: String) { val lengthString = message.length.toString(16) val prepend = 4 - lengthString.length assert(prepend >= 0) @@ -142,53 +163,53 @@ class ServerWriteChannel(private val delegate: ByteWriteChannel) : ByteWriteChan writeFully(message.toByteArray(Const.DEFAULT_TRANSPORT_ENCODING)) } - suspend fun respondStringV2(message: String) { + public suspend fun respondStringV2(message: String) { val bytes = message.toByteArray(Const.DEFAULT_TRANSPORT_ENCODING) writeIntLittleEndian(bytes.size) writeFully(bytes) } - suspend fun respondStringRaw(message: String) { + public suspend fun respondStringRaw(message: String) { respond(message.toByteArray(Const.DEFAULT_TRANSPORT_ENCODING)) } - suspend fun respondFail(message: String) { + public suspend fun respondFail(message: String) { respond(Const.Message.FAIL) writeIntLittleEndian(message.length) respondStringRaw(message) } - suspend fun respondShellV1(stdout: String) { + public suspend fun respondShellV1(stdout: String) { respondStringRaw(stdout) } - suspend fun respondShellV2(stdout: String, stderr: String, exitCode: Int) { + public suspend fun respondShellV2(stdout: String, stderr: String, exitCode: Int) { respondShellV2Stdout(stdout) respondShellV2Stderr(stderr) respondShellV2Exit(exitCode) } - suspend fun respondShellV2Exit(exitCode: Int) { - writeByte(MessageType.EXIT.toValue().toByte()) - writeInt(1) - writeByte(exitCode) + public suspend fun respondShellV2Exit(exitCode: Int) { + delegate.channelWriteByte(MessageType.EXIT.toValue().toByte()) + delegate.channelWriteInt(1) + delegate.channelWriteByte(exitCode.toByte()) } - suspend fun respondShellV2Stderr(stderr: String) { - writeByte(MessageType.STDERR.toValue().toByte()) + public suspend fun respondShellV2Stderr(stderr: String) { + delegate.channelWriteByte(MessageType.STDERR.toValue().toByte()) respondStringV2(stderr) } - suspend fun respondShellV2Stdout(stdout: String) { - writeByte(MessageType.STDOUT.toValue().toByte()) + public suspend fun respondShellV2Stdout(stdout: String) { + delegate.channelWriteByte(MessageType.STDOUT.toValue().toByte()) respondStringV2(stdout) } - suspend fun respondShellV2WindowSizeChange() { - writeByte(MessageType.WINDOW_SIZE_CHANGE.toValue().toByte()) + public suspend fun respondShellV2WindowSizeChange() { + delegate.channelWriteByte(MessageType.WINDOW_SIZE_CHANGE.toValue().toByte()) } - suspend fun respondShellV2Invalid() { - writeByte(MessageType.INVALID.toValue().toByte()) + public suspend fun respondShellV2Invalid() { + delegate.channelWriteByte(MessageType.INVALID.toValue().toByte()) } } diff --git a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/StubSocket.kt b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/StubSocket.kt index 4a8429d9a..855937092 100644 --- a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/StubSocket.kt +++ b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/StubSocket.kt @@ -17,41 +17,60 @@ package com.malinskiy.adam.server.stub import com.malinskiy.adam.transport.Socket -import io.ktor.utils.io.ByteChannelSequentialJVM +import io.ktor.utils.io.ByteChannel import io.ktor.utils.io.ByteReadChannel import io.ktor.utils.io.ByteWriteChannel import io.ktor.utils.io.cancel -import io.ktor.utils.io.close -import io.ktor.utils.io.core.internal.ChunkBuffer -import io.ktor.utils.io.readIntLittleEndian -import io.ktor.utils.io.writeByte -import io.ktor.utils.io.writeIntLittleEndian +import io.ktor.utils.io.readAvailable +import io.ktor.utils.io.readFully +import io.ktor.utils.io.readInt +import io.ktor.utils.io.writeFully +import io.ktor.utils.io.writeInt import java.nio.ByteBuffer +import io.ktor.utils.io.readByte as channelReadByte +import io.ktor.utils.io.writeByte as channelWriteByte -class StubSocket( - val readChannel: ByteReadChannel = ByteChannelSequentialJVM(ChunkBuffer.Empty, false), - val writeChannel: ByteWriteChannel = ByteChannelSequentialJVM(ChunkBuffer.Empty, false) +public class StubSocket( + public val readChannel: ByteReadChannel = ByteChannel(false), + public val writeChannel: ByteWriteChannel = ByteChannel(false), ) : Socket { override val isClosedForWrite: Boolean get() = writeChannel.isClosedForWrite override val isClosedForRead: Boolean get() = readChannel.isClosedForRead - constructor(content: ByteArray) : this(readChannel = ByteReadChannel(content)) + public constructor(content: ByteArray) : this(readChannel = ByteReadChannel(content)) - override suspend fun readFully(buffer: ByteBuffer): Int = readChannel.readFully(buffer) - override suspend fun readFully(buffer: ByteArray, offset: Int, limit: Int) = readChannel.readFully(buffer, offset, limit) - override suspend fun writeFully(byteBuffer: ByteBuffer) = writeChannel.writeFully(byteBuffer) - override suspend fun writeFully(byteArray: ByteArray, offset: Int, limit: Int) = writeChannel.writeFully(byteArray, offset, limit) - override suspend fun readAvailable(buffer: ByteArray, offset: Int, limit: Int): Int = readChannel.readAvailable(buffer, offset, limit) - override suspend fun readByte(): Byte = readChannel.readByte() - override suspend fun readIntLittleEndian(): Int = readChannel.readIntLittleEndian() - override suspend fun writeByte(value: Int) = writeChannel.writeByte(value) - override suspend fun writeIntLittleEndian(value: Int) = writeChannel.writeIntLittleEndian(value) + override suspend fun readFully(buffer: ByteBuffer): Int { + val count = buffer.remaining() + readChannel.readFully(buffer) + return count + } + + override suspend fun readFully(buffer: ByteArray, offset: Int, limit: Int) { + readChannel.readFully(buffer, offset, offset + limit) + } + + override suspend fun writeFully(byteBuffer: ByteBuffer) { + writeChannel.writeFully(byteBuffer) + } + + override suspend fun writeFully(byteArray: ByteArray, offset: Int, limit: Int) { + writeChannel.writeFully(byteArray, offset, offset + limit) + } + + override suspend fun readAvailable(buffer: ByteArray, offset: Int, limit: Int): Int { + return readChannel.readAvailable(buffer, offset, limit) + } + + override suspend fun readByte(): Byte = readChannel.channelReadByte() + override suspend fun readIntLittleEndian(): Int = Integer.reverseBytes(readChannel.readInt()) + override suspend fun writeByte(value: Int): Unit = writeChannel.channelWriteByte(value.toByte()) + override suspend fun writeIntLittleEndian(value: Int): Unit = writeChannel.writeInt(Integer.reverseBytes(value)) override suspend fun close() { try { - writeChannel.close() + writeChannel.flushAndClose() readChannel.cancel() } catch (e: Exception) { println("Exception during cleanup. Ignoring") diff --git a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/DeviceExpectation.kt b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/DeviceExpectation.kt index 184127b00..505d2b4d0 100644 --- a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/DeviceExpectation.kt +++ b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/DeviceExpectation.kt @@ -16,15 +16,15 @@ package com.malinskiy.adam.server.stub.dsl -data class DeviceExpectation( - val serialNo: String, - private val list: MutableList Unit> = mutableListOf() +public data class DeviceExpectation( + public val serialNo: String, + private val list: MutableList Unit> = mutableListOf(), ) { - fun session(block: suspend Session.() -> Unit) { + public fun session(block: suspend Session.() -> Unit) { list.add(block) } - suspend fun handle(session: Session) { + public suspend fun handle(session: Session) { assert(list.size > 0) { "No handles registered for request" } val head = list.removeAt(0) head(session) diff --git a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/DoneFailSubSession.kt b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/DoneFailSubSession.kt index f09b9cd37..5937e45f3 100644 --- a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/DoneFailSubSession.kt +++ b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/DoneFailSubSession.kt @@ -16,12 +16,12 @@ package com.malinskiy.adam.server.stub.dsl -class DoneFailSubSession(private val session: Session) { - suspend fun done() { +public class DoneFailSubSession(private val session: Session) { + public suspend fun done() { session.output.respondDone() } - suspend fun fail(message: String) { + public suspend fun fail(message: String) { session.output.respondFail(message) } } diff --git a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/ExecSubSession.kt b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/ExecSubSession.kt index 265ef5780..9f7b9658d 100644 --- a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/ExecSubSession.kt +++ b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/ExecSubSession.kt @@ -18,23 +18,23 @@ package com.malinskiy.adam.server.stub.dsl import java.io.File -class ExecSubSession(private val session: Session) { - suspend fun accept(): ExecSubSession { +public class ExecSubSession(private val session: Session) { + public suspend fun accept(): ExecSubSession { session.respondOkay() return this } - suspend fun respond(stdout: String): ExecSubSession { + public suspend fun respond(stdout: String): ExecSubSession { session.respondShellV1(stdout) return this } - suspend fun receiveFile(fixture: File): ExecSubSession { + public suspend fun receiveFile(fixture: File): ExecSubSession { session.expectBytesAsFile(fixture) return this } - suspend fun reject(message: String) { + public suspend fun reject(message: String) { session.respondTransport(false, message) } } diff --git a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/Expectation.kt b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/Expectation.kt index 5714a6920..3cbb709e7 100644 --- a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/Expectation.kt +++ b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/Expectation.kt @@ -16,30 +16,32 @@ package com.malinskiy.adam.server.stub.dsl -class Expectation { +public class Expectation { private val handlers = mutableMapOf() private var otherHandlers = mutableMapOf Unit>() - fun serial(serialNo: String, block: DeviceExpectation.() -> Unit) { + public fun serial(serialNo: String, block: DeviceExpectation.() -> Unit) { val deviceExpectation = handlers[serialNo] ?: DeviceExpectation(serialNo) handlers[serialNo] = deviceExpectation block(deviceExpectation) } - fun other(transportString: String, block: suspend Session.() -> Unit) { + public fun other(transportString: String, block: suspend Session.() -> Unit) { assert(!otherHandlers.contains(transportString)) { "Handler for $transportString already exists" } otherHandlers[transportString] = block } - suspend fun select(session: Session): Boolean { + public suspend fun select(session: Session): Boolean { val transportCmd = session.input.receiveCommand() return if (transportCmd.startsWith("host:transport:")) { val serial = transportCmd.substringAfter("host:transport:") - handlers[serial]?.let { it.handle(session); true } ?: false + handlers[serial]?.let { + it.handle(session) + true + } ?: false } else { otherHandlers[transportCmd]?.invoke(session) ?: return false return true } } } - diff --git a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/FramebufferSubSession.kt b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/FramebufferSubSession.kt index d840cf841..069f5af23 100644 --- a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/FramebufferSubSession.kt +++ b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/FramebufferSubSession.kt @@ -18,22 +18,22 @@ package com.malinskiy.adam.server.stub.dsl import java.io.File -class FramebufferSubSession(private val session: Session) { - suspend fun accept(): FramebufferSubSession { +public class FramebufferSubSession(private val session: Session) { + public suspend fun accept(): FramebufferSubSession { session.respondTransport(true) return this } - suspend fun reject(message: String): FramebufferSubSession { + public suspend fun reject(message: String): FramebufferSubSession { session.respondTransport(false, message) return this } - suspend fun respondScreencaptureV2(replay: File) { + public suspend fun respondScreencaptureV2(replay: File) { session.respondScreencaptureV2(replay) } - suspend fun respondScreencaptureV3(replay: File) { + public suspend fun respondScreencaptureV3(replay: File) { session.respondScreencaptureV3(replay) } } diff --git a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/GetAdbServerSubSession.kt b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/GetAdbServerSubSession.kt index a354f64ab..3be7612a0 100644 --- a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/GetAdbServerSubSession.kt +++ b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/GetAdbServerSubSession.kt @@ -16,18 +16,18 @@ package com.malinskiy.adam.server.stub.dsl -class GetAdbServerSubSession(private val session: Session) { - suspend fun accept(): GetAdbServerSubSession { +public class GetAdbServerSubSession(private val session: Session) { + public suspend fun accept(): GetAdbServerSubSession { session.respondTransport(true) return this } - suspend fun reject(message: String): GetAdbServerSubSession { + public suspend fun reject(message: String): GetAdbServerSubSession { session.respondTransport(false, message) return this } - suspend fun respondAdbServerVersion(version: Int) { + public suspend fun respondAdbServerVersion(version: Int) { session.respondAdbServerVersion(version) } } diff --git a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/LegacySideloadSubSession.kt b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/LegacySideloadSubSession.kt index 6a7dbc7ab..f5decb7a5 100644 --- a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/LegacySideloadSubSession.kt +++ b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/LegacySideloadSubSession.kt @@ -16,17 +16,17 @@ package com.malinskiy.adam.server.stub.dsl -class LegacySideloadSubSession(private val session: Session) { - suspend fun receive(size: Int): LegacySideloadSubSession { +public class LegacySideloadSubSession(private val session: Session) { + public suspend fun receive(size: Int): LegacySideloadSubSession { session.receiveBytes(size) return this } - suspend fun okay() { + public suspend fun okay() { session.respondOkay() } - suspend fun fail(message: String) { + public suspend fun fail(message: String) { session.respondTransport(false, message) } } diff --git a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/OkayFailSubSession.kt b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/OkayFailSubSession.kt index 891109d50..10bebe310 100644 --- a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/OkayFailSubSession.kt +++ b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/OkayFailSubSession.kt @@ -16,13 +16,13 @@ package com.malinskiy.adam.server.stub.dsl -open class OkayFailSubSession(private val session: Session) { - suspend fun accept(): OkayFailSubSession { +public open class OkayFailSubSession(private val session: Session) { + public suspend fun accept(): OkayFailSubSession { session.respondTransport(true) return this } - suspend fun reject(message: String): OkayFailSubSession { + public suspend fun reject(message: String): OkayFailSubSession { session.respondTransport(false, message) return this } diff --git a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/ReceiveFileSubSession.kt b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/ReceiveFileSubSession.kt index 5888f39b3..4f119b548 100644 --- a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/ReceiveFileSubSession.kt +++ b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/ReceiveFileSubSession.kt @@ -18,13 +18,13 @@ package com.malinskiy.adam.server.stub.dsl import java.io.File -class ReceiveFileSubSession(private val session: Session) { - suspend fun respondFile(fixture: File): ReceiveFileSubSession { +public class ReceiveFileSubSession(private val session: Session) { + public suspend fun respondFile(fixture: File): ReceiveFileSubSession { session.respondFile(fixture) return this } - suspend fun respondDoneDone() { + public suspend fun respondDoneDone() { session.output.respondDoneDone() } } diff --git a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/SendFileSubSession.kt b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/SendFileSubSession.kt index 8eb3cd5a3..9b1766098 100644 --- a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/SendFileSubSession.kt +++ b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/SendFileSubSession.kt @@ -19,17 +19,17 @@ package com.malinskiy.adam.server.stub.dsl import com.malinskiy.adam.Const import java.io.File -class SendFileSubSession(private val session: Session) { - suspend fun receiveFile(fixture: File): SendFileSubSession { +public class SendFileSubSession(private val session: Session) { + public suspend fun receiveFile(fixture: File): SendFileSubSession { session.receiveFile(fixture) return this } - suspend fun done() { + public suspend fun done() { session.respondOkay() } - suspend fun fail(message: String) { + public suspend fun fail(message: String) { session.output.respond(Const.Message.FAIL) session.output.respondStringV1(message) } diff --git a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/SendFileV2SubSession.kt b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/SendFileV2SubSession.kt index c69316d41..32726cffb 100644 --- a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/SendFileV2SubSession.kt +++ b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/SendFileV2SubSession.kt @@ -19,17 +19,17 @@ package com.malinskiy.adam.server.stub.dsl import com.malinskiy.adam.Const import java.io.File -class SendFileV2SubSession(private val session: Session) { - suspend fun receiveFile(fixture: File): SendFileV2SubSession { +public class SendFileV2SubSession(private val session: Session) { + public suspend fun receiveFile(fixture: File): SendFileV2SubSession { session.receiveFile(fixture) return this } - suspend fun done() { + public suspend fun done() { session.respondOkay() } - suspend fun fail(message: String) { + public suspend fun fail(message: String) { session.output.respond(Const.Message.FAIL) session.output.respondStringV2(message) } diff --git a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/Session.kt b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/Session.kt index 91ca6b23a..10ec478d6 100644 --- a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/Session.kt +++ b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/Session.kt @@ -21,42 +21,40 @@ import assertk.assertions.isEqualTo import com.malinskiy.adam.Const import com.malinskiy.adam.server.stub.ServerReadChannel import com.malinskiy.adam.server.stub.ServerWriteChannel -import io.ktor.utils.io.writeIntLittleEndian import java.io.File - -class Session(val input: ServerReadChannel, val output: ServerWriteChannel) { - suspend fun expectCmd(expected: () -> String): OkayFailSubSession { +public class Session(public val input: ServerReadChannel, public val output: ServerWriteChannel) { + public suspend fun expectCmd(expected: () -> String): OkayFailSubSession { val transportCmd = input.receiveCommand() assertThat(transportCmd).isEqualTo(expected()) return OkayFailSubSession(session = this) } - suspend fun expectShell(expected: () -> String): ShellV1SubSession { + public suspend fun expectShell(expected: () -> String): ShellV1SubSession { val transportCmd = input.receiveCommand() assertThat(transportCmd).isEqualTo("shell:${expected()}") return ShellV1SubSession(session = this) } - suspend fun expectShellV2(expected: () -> String): ShellV2SubSession { + public suspend fun expectShellV2(expected: () -> String): ShellV2SubSession { val transportCmd = input.receiveCommand() assertThat(transportCmd).isEqualTo("shell,v2,raw:${expected()}") return ShellV2SubSession(session = this) } - suspend fun expectExec(expected: () -> String): ExecSubSession { + public suspend fun expectExec(expected: () -> String): ExecSubSession { val transportCmd = input.receiveCommand() assertThat(transportCmd).isEqualTo("exec:${expected()}") return ExecSubSession(session = this) } - suspend fun respondTransport(success: Boolean, message: String? = null) { + public suspend fun respondTransport(success: Boolean, message: String? = null) { output.respond( when (success) { true -> Const.Message.OKAY false -> Const.Message.FAIL - } + }, ) if (!success && message != null) { @@ -64,17 +62,17 @@ class Session(val input: ServerReadChannel, val output: ServerWriteChannel) { } } - suspend fun respondShellV1(stdout: String) { + public suspend fun respondShellV1(stdout: String) { output.respondShellV1(stdout) } - suspend fun expectFramebuffer(): FramebufferSubSession { + public suspend fun expectFramebuffer(): FramebufferSubSession { expectCmd { "framebuffer:" } return FramebufferSubSession(this) } - suspend fun respondScreencaptureV2(replay: File) { - //Extended version + public suspend fun respondScreencaptureV2(replay: File) { + // Extended version output.writeIntLittleEndian(1) val sample = replay.readBytes() @@ -83,8 +81,8 @@ class Session(val input: ServerReadChannel, val output: ServerWriteChannel) { output.writeFully(sample, 48, sample.size - 48) } - suspend fun respondScreencaptureV3(replay: File) { - //Extended version + public suspend fun respondScreencaptureV3(replay: File) { + // Extended version output.writeIntLittleEndian(2) val sample = replay.readBytes() @@ -93,36 +91,36 @@ class Session(val input: ServerReadChannel, val output: ServerWriteChannel) { output.writeFully(sample, 52, sample.size - 52) } - suspend fun respondAdbServerVersion(x: Int) { + public suspend fun respondAdbServerVersion(x: Int) { output.respondStringV1(x.toString(16)) } - suspend fun respondPairDevice(message: String) { + public suspend fun respondPairDevice(message: String) { output.respondStringV1(message) } - suspend fun respondReconnectOffline(message: String) { + public suspend fun respondReconnectOffline(message: String) { output.respondStringV1(message) } - suspend fun respondReconnectSingleDevice(message: String) { + public suspend fun respondReconnectSingleDevice(message: String) { output.respondStringRaw(message) } - suspend fun respondRemountPartitions(message: () -> String) { + public suspend fun respondRemountPartitions(message: () -> String) { output.respondStringRaw(message()) } - suspend fun respondSideloadChunkRequested(part: String) { + public suspend fun respondSideloadChunkRequested(part: String) { output.respondStringRaw(part) } - suspend fun respondPortForward(success: Boolean, port: Int? = null) { + public suspend fun respondPortForward(success: Boolean, port: Int? = null) { output.respond( when (success) { true -> Const.Message.OKAY false -> Const.Message.FAIL - } + }, ) if (success && port != null) { @@ -130,49 +128,49 @@ class Session(val input: ServerReadChannel, val output: ServerWriteChannel) { } } - suspend fun respondSetDmVerityChecking(message: String) { + public suspend fun respondSetDmVerityChecking(message: String) { output.respondStringRaw(message) } - suspend fun expectShellV2Stdin(expected: String) { + public suspend fun expectShellV2Stdin(expected: String) { val stdin = input.receiveShellV2Stdin() assertThat(stdin).isEqualTo(expected) } - suspend fun expectShellV2StdinClose() { + public suspend fun expectShellV2StdinClose() { input.receiveShellV2StdinClose() } - suspend fun respondShellV2Stdout(message: String) { + public suspend fun respondShellV2Stdout(message: String) { output.respondShellV2Stdout(message) } - suspend fun respondShellV2Exit(exitCode: Int) { + public suspend fun respondShellV2Exit(exitCode: Int) { output.respondShellV2Exit(exitCode) } - suspend fun respondShellV2Stderr(stderr: String) { + public suspend fun respondShellV2Stderr(stderr: String) { output.respondShellV2Stderr(stderr) } - suspend fun respondShellV2WindowSizeChange() { + public suspend fun respondShellV2WindowSizeChange() { output.respondShellV2WindowSizeChange() } - suspend fun respondShellV2Invalid() { + public suspend fun respondShellV2Invalid() { output.respondShellV2Invalid() } - suspend fun expectStat(path: () -> String) { + public suspend fun expectStat(path: () -> String) { val receiveStat = input.receiveStat() assertThat(receiveStat).isEqualTo(path()) } - suspend fun respondStat(size: Int, mode: Int = 0, lastModified: Int = 0) { + public suspend fun respondStat(size: Int, mode: Int = 0, lastModified: Int = 0) { output.respondStat(size, mode, lastModified) } - suspend fun respondStatV2( + public suspend fun respondStatV2( mode: Int, size: Int, error: Int, @@ -183,23 +181,23 @@ class Session(val input: ServerReadChannel, val output: ServerWriteChannel) { gid: Int, atime: Int, mtime: Int, - ctime: Int + ctime: Int, ) { output.respondStatV2(mode, size, error, dev, ino, nlink, uid, gid, atime, mtime, ctime) } - suspend fun expectSend(message: () -> String): SendFileSubSession { + public suspend fun expectSend(message: () -> String): SendFileSubSession { val receiveCmd = input.receiveSend() assertThat(receiveCmd).isEqualTo(message()) return SendFileSubSession(this) } - suspend fun receiveFile(receiveFile: File) { + public suspend fun receiveFile(receiveFile: File) { input.receiveFile(receiveFile) } - suspend fun expectSendV2(receiveCmd: String, mode: String, flags: Int): SendFileV2SubSession { + public suspend fun expectSendV2(receiveCmd: String, mode: String, flags: Int): SendFileV2SubSession { val (actualReceiveCmd, actualMode, actualFlags) = input.receiveSendV2() assertThat(actualReceiveCmd).isEqualTo(receiveCmd) assertThat(actualMode.toString(8)).isEqualTo(mode) @@ -208,39 +206,39 @@ class Session(val input: ServerReadChannel, val output: ServerWriteChannel) { return SendFileV2SubSession(this) } - suspend fun expectRecv(path: () -> String): ReceiveFileSubSession { + public suspend fun expectRecv(path: () -> String): ReceiveFileSubSession { val recvPath = input.receiveRecv() assertThat(recvPath).isEqualTo(path()) return ReceiveFileSubSession(this) } - suspend fun respondFile(fixture: File) { + public suspend fun respondFile(fixture: File) { output.respondData(fixture.readBytes()) } - suspend fun expectRecv2(path: () -> String): ReceiveFileSubSession { + public suspend fun expectRecv2(path: () -> String): ReceiveFileSubSession { val recvPath = input.receiveRecv2() assertThat(recvPath).isEqualTo(path()) return ReceiveFileSubSession(this) } - suspend fun expectList(path: () -> String) { + public suspend fun expectList(path: () -> String) { val listPath = input.receiveList() assertThat(listPath).isEqualTo(path()) } - suspend fun respondList(size: Int, mode: Int = 0, lastModified: Int = 0, name: String): DoneFailSubSession { + public suspend fun respondList(size: Int, mode: Int = 0, lastModified: Int = 0, name: String): DoneFailSubSession { output.respondList(size, mode, lastModified, name) return DoneFailSubSession(this) } - suspend fun expectListV2(path: () -> String) { + public suspend fun expectListV2(path: () -> String) { val listPath = input.receiveListV2() assertThat(listPath).isEqualTo(path()) } - suspend fun respondListV2( + public suspend fun respondListV2( name: String, mode: Int = 0, size: Int, @@ -252,62 +250,61 @@ class Session(val input: ServerReadChannel, val output: ServerWriteChannel) { gid: Int, atime: Int, mtime: Int, - ctime: Int + ctime: Int, ): DoneFailSubSession { output.respondListV2(name, mode, size, error, dev, ino, nlink, uid, gid, atime, mtime, ctime) return DoneFailSubSession(this) } - suspend fun expectStatV2(path: () -> String) { + public suspend fun expectStatV2(path: () -> String) { val receiveStat = input.receiveStatV2() assertThat(receiveStat).isEqualTo(path()) } - suspend fun resondRestartAdbd(message: String) { + public suspend fun resondRestartAdbd(message: String) { output.respondStringRaw(message) } - suspend fun respondAsyncDeviceMonitor(serial: String, state: String) { + public suspend fun respondAsyncDeviceMonitor(serial: String, state: String) { output.respondStringV1("$serial\t$state\n") } - suspend fun respondListDevices(serialToState: Map) { + public suspend fun respondListDevices(serialToState: Map) { val response = serialToState.map { "${it.key}\t${it.value}\n" }.joinToString(separator = "") output.respondStringV1(response) } - suspend fun respondListPortForwards(response: String) { + public suspend fun respondListPortForwards(response: String) { output.respondStringV1(response) } - - suspend fun respondConnectDevice(response: String) { + public suspend fun respondConnectDevice(response: String) { output.respondStringV1(response) } - suspend fun respondDisconnectDevice(response: String) { + public suspend fun respondDisconnectDevice(response: String) { output.respondStringV1(response) } - suspend fun respondOkay() { + public suspend fun respondOkay() { output.respondOkay() } - suspend fun expectLegacySideload(size: Int): LegacySideloadSubSession { + public suspend fun expectLegacySideload(size: Int): LegacySideloadSubSession { expectCmd { "sideload:$size" }.accept() return LegacySideloadSubSession(this) } - suspend fun receiveBytes(size: Int): ByteArray { + public suspend fun receiveBytes(size: Int): ByteArray { return input.receiveBytes(size) } - suspend fun expectBytesAsFile(expected: File) { + public suspend fun expectBytesAsFile(expected: File) { val actual = receiveBytes(expected.length().toInt()) assertThat(actual).isEqualTo(expected.readBytes()) } - suspend fun expectAdbServerVersion(): GetAdbServerSubSession { + public suspend fun expectAdbServerVersion(): GetAdbServerSubSession { expectCmd { "host:version" } return GetAdbServerSubSession(this) } diff --git a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/ShellV1SubSession.kt b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/ShellV1SubSession.kt index 6ba6fc3e9..be22242c7 100644 --- a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/ShellV1SubSession.kt +++ b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/ShellV1SubSession.kt @@ -16,18 +16,18 @@ package com.malinskiy.adam.server.stub.dsl -class ShellV1SubSession(private val session: Session) { - suspend fun accept(): ShellV1SubSession { +public class ShellV1SubSession(private val session: Session) { + public suspend fun accept(): ShellV1SubSession { session.respondOkay() return this } - suspend fun respond(stdout: String): ShellV1SubSession { + public suspend fun respond(stdout: String): ShellV1SubSession { session.respondShellV1(stdout) return this } - suspend fun reject(message: String) { + public suspend fun reject(message: String) { session.respondTransport(false, message) } } diff --git a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/ShellV2SubSession.kt b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/ShellV2SubSession.kt index 895a99df8..740215316 100644 --- a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/ShellV2SubSession.kt +++ b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/ShellV2SubSession.kt @@ -16,28 +16,28 @@ package com.malinskiy.adam.server.stub.dsl -class ShellV2SubSession(private val session: Session) { - suspend fun accept(): ShellV2SubSession { +public class ShellV2SubSession(private val session: Session) { + public suspend fun accept(): ShellV2SubSession { session.respondOkay() return this } - suspend fun respondStdout(stdout: String): ShellV2SubSession { + public suspend fun respondStdout(stdout: String): ShellV2SubSession { session.respondShellV2Stdout(stdout) return this } - suspend fun respondStderr(stdout: String): ShellV2SubSession { + public suspend fun respondStderr(stdout: String): ShellV2SubSession { session.respondShellV2Stderr(stdout) return this } - suspend fun respondExit(exitCode: Int): ShellV2SubSession { + public suspend fun respondExit(exitCode: Int): ShellV2SubSession { session.respondShellV2Exit(exitCode) return this } - suspend fun reject(message: String) { + public suspend fun reject(message: String) { session.respondTransport(false, message) } } diff --git a/transport-ktor/build.gradle.kts b/transport-ktor/build.gradle.kts index c8f70dce5..0320da592 100644 --- a/transport-ktor/build.gradle.kts +++ b/transport-ktor/build.gradle.kts @@ -1,3 +1,6 @@ +import adam.buildlogic.AdamPublishing +import adam.buildlogic.configureAdamPom + /* * Copyright (C) 2021 Anton Malinskiy * @@ -16,10 +19,25 @@ plugins { id("adam.jvm") + alias(libs.plugins.vanniktech.maven.publish) +} + +mavenPublishing { + coordinates(AdamPublishing.GROUP, "transport-ktor", version.toString()) + + pom { + name.set("transport-ktor") + description.set("Android Debug Bridge helper - Ktor transport") + configureAdamPom() + } } dependencies { implementation(project(":adam")) implementation(libs.ktor.network) - implementation(libs.logging) + implementation(libs.logcat) + + testImplementation(libs.junit4) + testImplementation(libs.assertk) + testImplementation(libs.coroutines.core) } diff --git a/transport-ktor/src/main/kotlin/com/malinskiy/adam/transport/ktor/KtorSocket.kt b/transport-ktor/src/main/kotlin/com/malinskiy/adam/transport/ktor/KtorSocket.kt index 90f2f62b2..fdb62ff7e 100644 --- a/transport-ktor/src/main/kotlin/com/malinskiy/adam/transport/ktor/KtorSocket.kt +++ b/transport-ktor/src/main/kotlin/com/malinskiy/adam/transport/ktor/KtorSocket.kt @@ -23,14 +23,17 @@ import io.ktor.network.sockets.openWriteChannel import io.ktor.utils.io.ByteReadChannel import io.ktor.utils.io.ByteWriteChannel import io.ktor.utils.io.cancel -import io.ktor.utils.io.close -import io.ktor.utils.io.readIntLittleEndian -import io.ktor.utils.io.writeByte -import io.ktor.utils.io.writeIntLittleEndian +import io.ktor.utils.io.readAvailable +import io.ktor.utils.io.readFully +import io.ktor.utils.io.readInt +import io.ktor.utils.io.writeFully +import io.ktor.utils.io.writeInt import java.nio.ByteBuffer import io.ktor.network.sockets.Socket as RealKtorSocket +import io.ktor.utils.io.readByte as ktorReadByte +import io.ktor.utils.io.writeByte as ktorWriteByte -class KtorSocket(private val ktorSocket: RealKtorSocket) : Socket { +public class KtorSocket(private val ktorSocket: RealKtorSocket) : Socket { private val readChannel: ByteReadChannel = ktorSocket.openReadChannel() private val writeChannel: ByteWriteChannel = ktorSocket.openWriteChannel(autoFlush = true) override val isClosedForWrite: Boolean @@ -38,23 +41,45 @@ class KtorSocket(private val ktorSocket: RealKtorSocket) : Socket { override val isClosedForRead: Boolean get() = readChannel.isClosedForRead - override suspend fun readFully(buffer: ByteBuffer): Int = readChannel.readFully(buffer) - override suspend fun readFully(buffer: ByteArray, offset: Int, limit: Int) = readChannel.readFully(buffer, offset, limit) - override suspend fun writeFully(byteBuffer: ByteBuffer) = writeChannel.writeFully(byteBuffer) - override suspend fun writeFully(byteArray: ByteArray, offset: Int, limit: Int) = writeChannel.writeFully(byteArray, offset, limit) + override suspend fun readFully(buffer: ByteBuffer): Int { + val count = buffer.remaining() + readChannel.readFully(buffer) + return count + } + + override suspend fun readFully(buffer: ByteArray, offset: Int, limit: Int) { + readChannel.readFully(buffer, offset, offset + limit) + } + + override suspend fun writeFully(byteBuffer: ByteBuffer) { + writeChannel.writeFully(byteBuffer) + } + + override suspend fun writeFully(byteArray: ByteArray, offset: Int, limit: Int) { + writeChannel.writeFully(byteArray, offset, offset + limit) + } + + @OptIn(io.ktor.utils.io.InternalAPI::class, kotlinx.io.InternalIoApi::class) override suspend fun readAvailable(buffer: ByteArray, offset: Int, limit: Int): Int { - if (!readChannel.isClosedForRead && readChannel.availableForRead == 0) return 0 + if (!readChannel.isClosedForRead && readChannel.readBuffer.buffer.size == 0L) return 0 return readChannel.readAvailable(buffer, offset, limit) } - override suspend fun readByte(): Byte = readChannel.readByte() - override suspend fun readIntLittleEndian(): Int = readChannel.readIntLittleEndian() - override suspend fun writeByte(value: Int) = writeChannel.writeByte(value) - override suspend fun writeIntLittleEndian(value: Int) = writeChannel.writeIntLittleEndian(value) + override suspend fun readByte(): Byte = readChannel.ktorReadByte() + + override suspend fun readIntLittleEndian(): Int = Integer.reverseBytes(readChannel.readInt()) + + override suspend fun writeByte(value: Int) { + writeChannel.ktorWriteByte(value.toByte()) + } + + override suspend fun writeIntLittleEndian(value: Int) { + writeChannel.writeInt(Integer.reverseBytes(value)) + } override suspend fun close() { try { - writeChannel.close() + writeChannel.flushAndClose() readChannel.cancel() ktorSocket.close() } catch (e: Exception) { @@ -62,7 +87,7 @@ class KtorSocket(private val ktorSocket: RealKtorSocket) : Socket { } } - companion object { + private companion object { private val log = AdamLogging.logger {} } } diff --git a/transport-ktor/src/main/kotlin/com/malinskiy/adam/transport/ktor/KtorSocketFactory.kt b/transport-ktor/src/main/kotlin/com/malinskiy/adam/transport/ktor/KtorSocketFactory.kt index 8026060b5..58ff8496f 100644 --- a/transport-ktor/src/main/kotlin/com/malinskiy/adam/transport/ktor/KtorSocketFactory.kt +++ b/transport-ktor/src/main/kotlin/com/malinskiy/adam/transport/ktor/KtorSocketFactory.kt @@ -18,7 +18,6 @@ package com.malinskiy.adam.transport.ktor import com.malinskiy.adam.transport.Socket import com.malinskiy.adam.transport.SocketFactory -import io.ktor.network.selector.ActorSelectorManager import io.ktor.network.selector.SelectorManager import io.ktor.network.sockets.aSocket import java.net.InetSocketAddress @@ -26,12 +25,12 @@ import kotlin.coroutines.CoroutineContext import io.ktor.network.sockets.InetSocketAddress as KtorSocketAddress @Deprecated(message = "Deprecated due to stability and performance issues") -class KtorSocketFactory( +public class KtorSocketFactory( coroutineContext: CoroutineContext, private val connectTimeout: Long = 10_000, - private val idleTimeout: Long = 30_000 + private val idleTimeout: Long = 30_000, ) : SocketFactory { - private val selectorManager: SelectorManager = ActorSelectorManager(coroutineContext) + private val selectorManager: SelectorManager = SelectorManager(coroutineContext) override suspend fun tcp(socketAddress: InetSocketAddress, connectTimeout: Long?, idleTimeout: Long?): Socket { val ktorSocketAddress = KtorSocketAddress(socketAddress.hostName, socketAddress.port) @@ -40,7 +39,8 @@ class KtorSocketFactory( .tcp() .connect(ktorSocketAddress) { socketTimeout = idleTimeout ?: this@KtorSocketFactory.idleTimeout - }) + }, + ) } override fun close() { diff --git a/transport-ktor/src/test/kotlin/com/malinskiy/adam/transport/ktor/KtorSocketRegressionTest.kt b/transport-ktor/src/test/kotlin/com/malinskiy/adam/transport/ktor/KtorSocketRegressionTest.kt new file mode 100644 index 000000000..f579b0041 --- /dev/null +++ b/transport-ktor/src/test/kotlin/com/malinskiy/adam/transport/ktor/KtorSocketRegressionTest.kt @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2021 Anton Malinskiy + * + * 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 com.malinskiy.adam.transport.ktor + +import assertk.assertThat +import assertk.assertions.isEqualTo +import io.ktor.network.selector.SelectorManager +import io.ktor.network.sockets.aSocket +import io.ktor.network.sockets.openReadChannel +import io.ktor.network.sockets.openWriteChannel +import io.ktor.utils.io.readFully +import io.ktor.utils.io.writeFully +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.async +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withTimeout +import org.junit.Test + +public class KtorSocketRegressionTest { + + @Test + public fun readFullyUsesLimitAsLengthForByteArray(): Unit = runBlocking { + withTimeout(5_000) { + withSocketPair { clientSocket, serverSocket -> + val socket = KtorSocket(clientSocket) + try { + val expected = byteArrayOf(11, 22, 33, 44) + val writer = async { + serverSocket.openWriteChannel(autoFlush = true).writeFully(expected, 0, expected.size) + serverSocket.close() + } + + val target = ByteArray(10) + socket.readFully(target, 3, expected.size) + writer.await() + + assertThat(target.copyOfRange(0, 3).toList()).isEqualTo(byteArrayOf(0, 0, 0).toList()) + assertThat(target.copyOfRange(3, 7).toList()).isEqualTo(expected.toList()) + assertThat(target.copyOfRange(7, 10).toList()).isEqualTo(byteArrayOf(0, 0, 0).toList()) + } finally { + socket.close() + } + } + } + } + + @Test + public fun writeFullyUsesLimitAsLengthForByteArray(): Unit = runBlocking { + withTimeout(5_000) { + withSocketPair { clientSocket, serverSocket -> + val socket = KtorSocket(clientSocket) + try { + val source = byteArrayOf(7, 8, 9, 10, 11, 12) + val reader = async { + val buffer = ByteArray(3) + serverSocket.openReadChannel().readFully(buffer, 0, buffer.size) + buffer + } + + socket.writeFully(source, 2, 3) + + assertThat(reader.await().toList()).isEqualTo(byteArrayOf(9, 10, 11).toList()) + } finally { + socket.close() + } + } + } + } + + private suspend fun withSocketPair( + block: suspend ( + clientSocket: io.ktor.network.sockets.Socket, + serverSocket: io.ktor.network.sockets.Socket, + ) -> Unit, + ) { + val selector = SelectorManager(Dispatchers.IO) + val server = aSocket(selector).tcp().bind("127.0.0.1", 0) + try { + coroutineScope { + val accepted = async(Dispatchers.IO) { server.accept() } + val clientSocket = aSocket(selector).tcp().connect(server.localAddress) + val serverSocket = accepted.await() + try { + block(clientSocket, serverSocket) + } finally { + serverSocket.close() + } + } + } finally { + server.close() + selector.close() + } + } +}