Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
164 changes: 164 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
# AGENTS.md

This file provides guidance to Codex (Codex.ai/code) when working with code in this repository.

## What this is

AndroidTreeView is a **.NET 10 + Avalonia** Windows desktop tool for inspecting, testing and managing
Android devices over ADB. Despite the name it is a C#/.NET solution, **not** a Java/Kotlin Android app.
It has two shipping executables that share the same core:

- **App** (`src/AndroidTreeView.App`) — the full Avalonia UI: device overview, per-category details,
screen mirroring (scrcpy), CLI tools, settings, updates.
- **Mini** (`src/AndroidTreeView.Mini`) — a lightweight WinForms tray/monitor app that stays resident,
watches for devices, and auto-launches scrcpy once a device is connected and authorized. Mini
deliberately does **not** carry the Avalonia/Skia runtime.

`Mini.Mac` is an Avalonia-based Mini variant for macOS.

## Commands

Requires the **.NET 10 SDK**. Run from the repo root.

```bash
dotnet restore AndroidTreeView.sln
dotnet build AndroidTreeView.sln
dotnet test AndroidTreeView.sln
dotnet run --project src/AndroidTreeView.App
dotnet run --project src/AndroidTreeView.Mini
```

Building on non-Windows (App/Mini target Windows) needs the targeting pack flag — CI uses it everywhere:

```bash
dotnet build AndroidTreeView.sln -p:EnableWindowsTargeting=true
```

Run a single test project / a single test:

```bash
dotnet test tests/AndroidTreeView.Adb.Tests
dotnet test AndroidTreeView.sln --filter "FullyQualifiedName~BatteryParser"
```

Format check (CI runs this, non-blocking — but keep it clean):

```bash
dotnet format AndroidTreeView.sln --verify-no-changes
```

Package/verify the release ZIP link locally (real releases only ship via the GitHub `Publish` workflow,
x64 only):

```powershell
./packaging/build-update-zip.ps1 -Product App -Rid win-x64
./packaging/build-update-zip.ps1 -Product Mini -Rid win-x64
```

There are ready-made Rider/VS run configs under `.run/`.

## Architecture

The layering is strict and enforced by project references — respect the dependency direction. Lower
layers never reference upper ones.

```
Models domain records/enums, no project deps
Core interfaces, options (AppSettings, AdbOptions), typed exceptions, DeviceMonitor
Adb / Infrastructure Adb: ProcessRunner, command builders, parsers, AdbDeviceService, LogcatService
↑ Infrastructure: SettingsService (JSON), logging, update check/install
Shared the shared composition root — AddAndroidTreeViewSharedServices() wires ADB, monitoring,
↑ scrcpy, settings, and update services identically for both App and Mini
App / Mini / Mini.Mac executables (each references Shared)
```

Key architectural rules (see `docs/architecture.md` for the full binding type/interface contract, and
`docs/app-contract.md`):

- **Shared is the single wiring point.** Both App and Mini call
`AddAndroidTreeViewSharedServices(...)` so their ADB/scrcpy/settings/update behavior can't drift.
When adding a service that both should use, register it there (it uses `TryAdd*`), not per-app.
- **App is strict MVVM** with CommunityToolkit.Mvvm (`[ObservableProperty]` / `[RelayCommand]`) and
`Microsoft.Extensions` DI/Hosting/Logging. `Program.cs` builds the host + `IServiceProvider`, then
Avalonia resolves `MainWindowViewModel`. `ViewLocator` maps `*.ViewModels.XxxViewModel` →
`*.Views.XxxView` by name convention.
- **All ADB is out-of-process** via `ProcessRunner` (async stdout/stderr, kills the whole process tree
on cancel/timeout). Device info comes from parsing ADB text output.
- **Parsers are pure and unit-tested.** ADB output parsing lives in `AndroidTreeView.Adb.Parsers` as
stateless/static functions (`GetPropParser`, `BatteryParser`, `AdbDevicesParser`, etc.). Any change to
parsing logic must come with a parser test — fixtures live under the Adb.Tests project.
- `AdbLocator` resolves adb (configured path → PATH → common SDK locations); `IAdbEnvironment` holds the
current location as a singleton. If adb is missing the App shows a Setup page instead of crashing.
- `DeviceMonitor` owns a `PeriodicTimer` background loop and raises `DevicesChanged`; VMs marshal to the
UI thread themselves.

## Conventions (from `.editorconfig` + `CONTRIBUTING.md`)

- File-scoped namespaces, 4-space indent, interfaces `I`-prefixed, `using` outside the namespace,
CRLF line endings, UTF-8.
- **Async-only for I/O**: `async` + `CancellationToken` propagated everywhere. No `.Result` / `.Wait()` /
`Task.Run` for ADB/process work. UI mutations only on the UI thread (`Dispatcher.UIThread.Post`).
- Views use **compiled bindings** (`x:DataType`) and bind only to members that exist on the VM. No
business logic or ADB calls in views.
- **No hardcoded user-facing strings.** Use localization for every user-visible string (see below).
- **Read-only / safe by design**: do not introduce ADB commands that modify, wipe, or flash a device.
- Keep files under ~400 lines; the App never crashes on normal ADB/device errors — map them to friendly
`ErrorMessage` state.

## Localization

Every user-facing string is localized — never hardcode display text. Default language is **Simplified
Chinese**; English is the neutral/fallback resource.

- **Contract**: `ILocalizationService` (`AndroidTreeView.Core/Interfaces`) — `Get(key)`, `Format(key, args)`,
the `this[key]` indexer, `SetLanguage(AppLanguage)`, and a `LanguageChanged` event. `AppLanguage` lives
in `AndroidTreeView.Core/Options/SettingsEnums.cs`. `Get` returns the key itself if a resource is
missing, so a missing translation is visible, not a crash.
- **Implementation**: `LocalizationService` in `src/AndroidTreeView.App/Localization`, backed by two ResX
files with **identical key sets** (keep them in sync — currently 217 keys each):
- `src/AndroidTreeView.App/Resources/Strings.resx` — English (neutral fallback)
- `src/AndroidTreeView.App/Resources/Strings.zh-Hans.resx` — Simplified Chinese (default)
- Keys are dotted/namespaced: `app.title`, `nav.devices`, `common.refresh`, etc.
- **In ViewModels**: inject `ILocalizationService` and call `_localization.Get("key")` / `.Format(...)`.
- **In XAML**: use the `{loc:Localize Key=some.key}` markup extension (`LocalizeExtension` +
`LocalizeKeyConverter`). Bindings watch `LocalizationService.LanguageTick` so text refreshes live when
the language changes (the indexer's own `INotifyPropertyChanged` was unreliable in this Avalonia
version — that's why the plain `LanguageTick` counter exists; keep using it for live-refresh bindings).

**When adding a string**: add the key to **both** ResX files, then reference it via `Get`/`Format` (VMs)
or `{loc:Localize}` (XAML). Never add a key to only one file.

## Tests

xUnit across four projects (`dotnet test AndroidTreeView.sln`, or target one project — see Commands).
Fixtures are **inline `const` strings** inside the test classes, not external `.txt` files.

- **`Adb.Tests`** — the bulk of the suite. `Parsers/` has one test class per parser/builder
(`BatteryParserTests`, `StorageParserTests`, `AdbDevicesParserTests`, `GetPropParserTests`,
`RootStatusParserTests`, `NetworkParserTests`, the `*BuilderTests`, etc.), `Commands/` covers argv
building (`AdbArgsTests`), `Services/` covers device-action/screen-capture services. **Any change to ADB
output parsing must add/update the matching parser test here** — this is where correctness is pinned.
- **`Core.Tests`** — `AppSettings` clone/serialize, `DeviceMonitor` start/stop (with a fake
`IDeviceService`), `SemanticVersion`, file-transfer service.
- **`Infrastructure.Tests`** — `SettingsService` persistence, update check (`GitHubUpdateService`) and
`UpdateInstaller`, using test doubles in `TestDoubles.cs`.
- **`App.Tests`** — ViewModel logic with fake services (`Fakes.cs`): device-list reconcile keeps
selection, RawProperties filtering, Logcat bounding, DI graph resolves (`ServiceGraphTests`), and a boot
smoke test via `Avalonia.Headless` (`TestAppBuilder.cs`, `BootSmokeTests.cs`). No real ADB, no on-screen
rendering.

## Versioning & updates

Version is unified across runtime version, App/Mini assembly versions, manifests, and
`packaging/build-update-zip.ps1` — keep them in sync when bumping (currently `1.0.6`). Update channels:
`android-tree-view-app` (App) and `android-tree-view-mini` (Mini). `GitHubUpdateService` checks the latest
GitHub Release, compares semver, and selects the matching product asset; `UpdateInstaller` downloads,
verifies SHA-256, unpacks the x64 ZIP, and runs a local update script. Loose ZIPs without a supported
`release.json` manifest are rejected.

## Bundled tools

`build/AndroidTreeView.Scrcpy.targets` downloads and bundles scrcpy (which ships adb) into `tools/scrcpy`
at build/publish time on Windows. `tools/verify-scrcpy-latest.ps1` checks for newer scrcpy releases.
35 changes: 27 additions & 8 deletions README-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ AndroidTreeView 是一个用于 Android 设备巡检、测试与管理的桌面

当前发布请查看上方 Release 徽章或 [GitHub Releases](https://github.com/Birditch/AndroidTreeView/releases/latest)。运行时版本、目标框架和打包配置以项目文件与发布工作流为准。

## 产品样式展示

![AndroidTreeView 设备总览](docs/images/product-devices-v1.0.5.png)

## 功能

- 设备卡片总览与详情页。
Expand All @@ -34,6 +38,8 @@ dotnet run --project src/AndroidTreeView.App
dotnet run --project src/AndroidTreeView.Mini
```

功能规划与实施文档入口见 [docs/roadmap-features.md](docs/roadmap-features.md)。

## 使用说明

1. 安装 Android platform-tools,或让应用在启动时引导选择 `adb.exe`。
Expand All @@ -56,6 +62,26 @@ ADB 安装与排错见 [docs/adb-requirements.md](docs/adb-requirements.md)。
- Windows 更新包使用带 `release.json` 的 x64 ZIP;GitHub Release 同时包含 macOS Apple Silicon ZIP。
- ZIP 中没有受支持的发布清单时会拒绝安装,避免用户手动替换文件。

## 打包

正式发布只通过 GitHub Actions 的 `Publish` 工作流完成。本地命令仅用于验证打包链路:

```powershell
./packaging/build-update-zip.ps1 -Product App -Rid win-x64
./packaging/build-update-zip.ps1 -Product Mini -Rid win-x64
```

产物版本由项目文件和发布工作流统一提供。验证输出包含主程序和 Mini 的上传 ZIP,例如:

```text
artifacts/AndroidTreeView-<版本>-win-x64.zip
artifacts/AndroidTreeView-<版本>-osx-arm64.zip
artifacts/AndroidTreeView-Mini-<版本>-win-x64.zip
artifacts/AndroidTreeView-Mini-<版本>-osx-arm64.zip
```

更多细节见 [docs/packaging.md](docs/packaging.md)。

## 验证

```bash
Expand All @@ -65,13 +91,6 @@ dotnet build src/AndroidTreeView.Mini.Mac/AndroidTreeView.Mini.Mac.csproj --no-r
dotnet test AndroidTreeView.sln --no-restore
```

## 许可证与致谢

<p>
<a href="LICENSE"><img alt="MIT License" src="https://img.shields.io/badge/license-MIT-0E7A5F.svg"></a>
<a href="https://www.jetbrains.com/rider/"><img alt="JetBrains Rider" src="https://img.shields.io/badge/JetBrains-Rider-000000.svg?logo=jetbrains&logoColor=white"></a>
<a href="https://dotnet.microsoft.com/"><img alt=".NET SDK" src="https://img.shields.io/badge/.NET-SDK-512BD4.svg?logo=dotnet&logoColor=white"></a>
<a href="https://avaloniaui.net/"><img alt="Avalonia UI" src="https://img.shields.io/badge/Avalonia-UI-663399.svg"></a>
</p>
## 许可证

AndroidTreeView 基于 [MIT License](LICENSE) 开源。
59 changes: 49 additions & 10 deletions README.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ AndroidTreeView is a desktop tool for inspecting, testing, and managing Android

See the Release badge above or [GitHub Releases](https://github.com/Birditch/AndroidTreeView/releases/latest) for the current published version. Runtime versions, target frameworks, and packaging settings are defined by the project files and release workflow.

## Product Preview

![AndroidTreeView device overview](docs/images/product-devices-v1.0.5.png)

## Features

- Card-first device overview with serial, model, Android version, battery, charging, temperature, cycle count, connection state, root state, and last refresh time.
Expand All @@ -24,9 +28,29 @@ See the Release badge above or [GitHub Releases](https://github.com/Birditch/And
- Update automation downloads packages, verifies SHA-256 metadata when available, extracts Windows x64 ZIP packages, and starts a local update script so users are not asked to manually replace files.
- Simplified Chinese and English UI, with Light / Dark / System theme modes.

## Repository Layout

```text
src/
AndroidTreeView.Models
AndroidTreeView.Core
AndroidTreeView.Adb
AndroidTreeView.Infrastructure
AndroidTreeView.Shared
AndroidTreeView.App
AndroidTreeView.Mini
AndroidTreeView.Mini.Mac
tests/
AndroidTreeView.*.Tests
packaging/
win-x64 / osx-arm64 ZIP packaging and optional WiX MSI packaging
build/
Shared MSBuild targets
```

## Build And Run

Install the .NET SDK targeted by the project files:
Requires the .NET 10 SDK:

```bash
dotnet restore AndroidTreeView.sln
Expand All @@ -36,6 +60,8 @@ dotnet run --project src/AndroidTreeView.App
dotnet run --project src/AndroidTreeView.Mini
```

See [docs/roadmap-features.md](docs/roadmap-features.md) for feature roadmaps and implementation plans.

If ADB is not found, the app opens an ADB setup screen. Install Android platform-tools and add it to `PATH`, or choose `adb.exe` manually.

## Enable USB Debugging
Expand All @@ -54,11 +80,31 @@ See [docs/adb-requirements.md](docs/adb-requirements.md) for platform-tools setu
3. Use the device cards for status, mirroring, CLI access, and non-destructive tools.
4. Use Settings or About to check and install updates.

## Release ZIP Packaging

Artifact versions are supplied consistently by the project files and release workflow. Official releases are produced only by the GitHub Actions `Publish` workflow.

Local commands are for packaging validation only:

```powershell
./packaging/build-update-zip.ps1 -Product App -Rid win-x64
./packaging/build-update-zip.ps1 -Product Mini -Rid win-x64
```

Example output:

```text
artifacts/AndroidTreeView-<version>-win-x64.zip
artifacts/AndroidTreeView-<version>-osx-arm64.zip
artifacts/AndroidTreeView-Mini-<version>-win-x64.zip
artifacts/AndroidTreeView-Mini-<version>-osx-arm64.zip
```

## Auto Update

- Full app update key: `android-tree-view-app`.
- Mini update key: `android-tree-view-mini`.
- `NekoIndexUpdateService` checks the internal update channel and compares semantic versions.
- `GitHubUpdateService` queries GitHub Releases and compares semantic versions.
- `UpdateInstaller` downloads, verifies, extracts, and launches the local update script.
- Supported Windows updater packages are x64 ZIP files with `release.json`; GitHub Releases also contain macOS Apple Silicon ZIPs.
- Loose-file ZIP replacement is intentionally rejected.
Expand All @@ -72,13 +118,6 @@ dotnet build src/AndroidTreeView.Mini.Mac/AndroidTreeView.Mini.Mac.csproj --no-r
dotnet test AndroidTreeView.sln --no-restore
```

## License And Credits

<p>
<a href="LICENSE"><img alt="MIT License" src="https://img.shields.io/badge/license-MIT-0E7A5F.svg"></a>
<a href="https://www.jetbrains.com/rider/"><img alt="JetBrains Rider" src="https://img.shields.io/badge/JetBrains-Rider-000000.svg?logo=jetbrains&logoColor=white"></a>
<a href="https://dotnet.microsoft.com/"><img alt=".NET SDK" src="https://img.shields.io/badge/.NET-SDK-512BD4.svg?logo=dotnet&logoColor=white"></a>
<a href="https://avaloniaui.net/"><img alt="Avalonia UI" src="https://img.shields.io/badge/Avalonia-UI-663399.svg"></a>
</p>
## License

AndroidTreeView is open source under the [MIT License](LICENSE).
Loading
Loading