The Problem

Android app testers spend too much time in a terminal typing adb commands, managing device state, and juggling screenshots. AdbPad replaces that workflow with a GUI that runs on Windows and macOS, so testers can interact with devices, send text, capture screenshots, and manage scrcpy displays without leaving the desktop.

What This Does

AdbPad is a Kotlin/Compose desktop application that wraps ADB and scrcpy into a visual interface. The core/domain module defines the business logic: command execution (ExecuteCommandUseCase.kt), device management (DeviceRepositoryImpl.kt), and scrcpy launch profiles (LaunchScrcpyUseCase.kt). The core/view module contains reusable UI components, and main/ wires everything together with dependency injection modules in main/kotlin/jp/kaleidot725/adbpad/di/.

State management follows an MVI pattern defined in core/mvi/, with MVIState.kt, MVIAction.kt, and MVISideEffect.kt as the core contracts. The app supports multiple languages (English, Japanese, Chinese, Turkish) and persists settings, device profiles, and command favorites to local files.

How It Is Wired

Execution starts at main/kotlin/jp/kaleidot725/adbpad/Main.kt, which initializes the Compose application. From there, AppContainer.kt builds the dependency graph, pulling repositories from RepositoryModule.kt and use cases from DomainModule.kt. The command screen (CommandScreen.kt) routes user actions through CommandStateHolder.kt, which calls use cases like ExecuteCommandUseCase.kt that ultimately invoke ADB via DeviceControlCommandRepositoryImpl.kt.

The module graph shows 1 internal module with 0 import edges and no circular dependencies—the architecture is cleanly layered: core/domain defines interfaces, core/data implements them, and main/ composes the application. The widest blast radius sits in core/domain/main/kotlin/jp/kaleidot725/adbpad/domain/model/command/NormalCommand.kt at 663 lines; it models the command tree that most UI components and repositories depend on. SettingRepositoryImpl.kt and SettingFileCreator.kt own filesystem persistence for user configuration.

How To Use It

git clone https://github.com/moses-y/adbpad
cd adbpad
./gradlew build
./gradlew run

The app requires a local ADB installation. After launch, configure the SDK path in Settings. macOS users can install via Homebrew: brew tap kaleidot725/app && brew install --cask adbpad. Windows binaries are built via GitHub Actions (.github/workflows/build_windows_binary.yml). The repo includes a Gradle wrapper, so no separate Gradle install is needed.

Real-World Use

A tester connects a physical Android device, launches AdbPad, and sees it in the device list. They select the device, send a text string via the Text Input tab, capture a screenshot, and create a virtual display for large-screen testing—all without opening a terminal. Command history and favorites persist across sessions, so repeated test flows become one-click operations.

Code Health & Issues

Static analysis (54 findings: 19 high, 35 medium) flags two structural concerns:

  • High - Deep nesting (49 instances) in SearchSortDropBox.kt, HorizontalPaneLayout.kt, and ThreePaneLayout.kt; max indentation depth 9 makes control flow hard to follow. Fix with early returns and guard clauses.
  • High - Duplicated code blocks: 342 repeated 6-line blocks across 56 files, concentrated in SettingFileCreator.kt and SettingRepositoryImpl.kt. Extract shared helpers.
  • Medium - Oversized file: NormalCommand.kt at 663 lines; split by responsibility.
  • Medium - High branching density in ScrcpyOptions.kt and LaunchScrcpyUseCase.kt (33 branch points over 61 lines); consider strategy dispatch.

SDLC observations: no test suite exists (215 source files, 0 tests). CI workflows lack least-privilege token permissions, dependency vulnerability scanning, and job timeouts. persist-credentials: false is missing from deploy_pages.yml checkout.

The Bottom Line

AdbPad is a well-layered Kotlin/Compose app with clean module boundaries and no dependency cycles. The main risks are code complexity in command modeling and zero test coverage—any refactor ships blind. It is a solid tool for Android testers who want a GUI alternative to raw ADB, but production use should be preceded by a test suite and CI hardening.