Skip to content
Open
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
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ on:
workflow_dispatch:
inputs:
version:
description: "Release version, for example 1.0.5"
description: "Release version, for example 1.0.6"
required: true
type: string

Expand Down
163 changes: 163 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
# 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 (`NekoIndexUpdateService`) 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). `NekoIndexUpdateService` checks the
channel and compares semver; `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.
28 changes: 18 additions & 10 deletions README-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@
[![License: MIT](https://img.shields.io/badge/License-MIT-0E7A5F.svg)](LICENSE)
[![.NET 10](https://img.shields.io/badge/.NET-10.0-512BD4.svg)](https://dotnet.microsoft.com/)
[![Avalonia 11.3](https://img.shields.io/badge/Avalonia-11.3-663399.svg)](https://avaloniaui.net/)
[![Platform: Windows](https://img.shields.io/badge/Platform-Windows-0078D6.svg)](#windows-使用说明)
[![Platform: Windows + macOS](https://img.shields.io/badge/Platform-Windows%20%2B%20macOS-0078D6.svg)](#使用说明)

[主文档](README.md) | **简体中文** | [English](README.en.md)

AndroidTreeView 是一个用于 Android 设备巡检、测试与管理的 Windows 桌面工具。主程序负责设备总览、详情、投屏、基础工具和设置;Mini 版本保持独立运行,常驻监听设备并自动投屏。
AndroidTreeView 是一个用于 Android 设备巡检、测试与管理的桌面工具,支持 Windows 与 macOS(Apple Silicon)。主程序负责设备总览、详情、投屏、基础工具和设置;Mini 版本保持独立运行,常驻监听设备并自动投屏。

当前版本:**v1.0.5**。
当前版本:**v1.0.6**。

## 产品样式展示

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

## 功能

Expand All @@ -36,13 +36,21 @@ dotnet run --project src/AndroidTreeView.App
dotnet run --project src/AndroidTreeView.Mini
```

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

## 使用说明

1. 安装 Android platform-tools,或让应用在启动时引导选择 `adb.exe`。
2. 在手机上开启开发者选项和 USB 调试。
3. 连接手机并允许 USB 调试授权。
4. 主程序会显示设备卡片;Mini 会自动监听并启动投屏。

### macOS 说明

- 从 Release 下载 `AndroidTreeView-<版本>-osx-arm64.zip`,解压后将 `AndroidTreeView.app` 拖入 `/Applications`。
- 首次打开若被 Gatekeeper 拦截,右键「打开」,或执行 `xattr -dr com.apple.quarantine AndroidTreeView.app` 放行。
- 设备卡片的「CLI 终端」在 macOS 上通过 Terminal.app 打开,编号菜单与 Windows 一致。

ADB 安装与排错见 [docs/adb-requirements.md](docs/adb-requirements.md)。

## 自动更新
Expand All @@ -61,13 +69,13 @@ ADB 安装与排错见 [docs/adb-requirements.md](docs/adb-requirements.md)。
./packaging/build-update-zip.ps1 -Product Mini -Rid win-x64
```

默认产物版本是 `1.0.5`。只发布 x64 架构。验证输出包含主程序和 Mini 的上传 ZIP,例如:
默认产物版本是 `1.0.6`。只发布 x64 架构。验证输出包含主程序和 Mini 的上传 ZIP,例如:

```text
artifacts/AndroidTreeView-1.0.5-win-x64.zip
artifacts/AndroidTreeView-1.0.5-osx-arm64.zip
artifacts/AndroidTreeView-Mini-1.0.5-win-x64.zip
artifacts/AndroidTreeView-Mini-1.0.5-osx-arm64.zip
artifacts/AndroidTreeView-1.0.6-win-x64.zip
artifacts/AndroidTreeView-1.0.6-osx-arm64.zip
artifacts/AndroidTreeView-Mini-1.0.6-win-x64.zip
artifacts/AndroidTreeView-Mini-1.0.6-osx-arm64.zip
```

更多细节见 [docs/packaging.md](docs/packaging.md)。
Expand Down
16 changes: 9 additions & 7 deletions README.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@

AndroidTreeView is a desktop tool for inspecting, testing, and managing Android devices through ADB. The full app shows device cards, detail pages, mirroring, tools, settings, and updates. The Mini app stays resident, watches for devices, and starts mirroring automatically after authorization.

Current version: **v1.0.5**. Current verification target: solution build passes, all tests pass, and GitHub Actions creates Windows x64 and macOS Apple Silicon ZIP artifacts for both App and Mini.
Current version: **v1.0.6**. Current verification target: solution build passes, all tests pass, and GitHub Actions creates Windows x64 and macOS Apple Silicon ZIP artifacts for both App and Mini.

## Product Preview

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

## Features

Expand Down Expand Up @@ -58,6 +58,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 @@ -78,7 +80,7 @@ See [docs/adb-requirements.md](docs/adb-requirements.md) for platform-tools setu

## Release ZIP Packaging

The product version is currently `1.0.5` and is kept in sync across runtime version, App/Mini assembly metadata, manifest, and the ZIP build script. Official releases are produced only by the GitHub Actions `Publish` workflow.
The product version is currently `1.0.6` and is kept in sync across runtime version, App/Mini assembly metadata, manifest, and the ZIP build script. Official releases are produced only by the GitHub Actions `Publish` workflow.

Local commands are for packaging validation only:

Expand All @@ -90,10 +92,10 @@ Local commands are for packaging validation only:
Example output:

```text
artifacts/AndroidTreeView-1.0.5-win-x64.zip
artifacts/AndroidTreeView-1.0.5-osx-arm64.zip
artifacts/AndroidTreeView-Mini-1.0.5-win-x64.zip
artifacts/AndroidTreeView-Mini-1.0.5-osx-arm64.zip
artifacts/AndroidTreeView-1.0.6-win-x64.zip
artifacts/AndroidTreeView-1.0.6-osx-arm64.zip
artifacts/AndroidTreeView-Mini-1.0.6-win-x64.zip
artifacts/AndroidTreeView-Mini-1.0.6-osx-arm64.zip
```

## Auto Update
Expand Down
29 changes: 19 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@
[![License: MIT](https://img.shields.io/badge/License-MIT-0E7A5F.svg)](LICENSE)
[![.NET 10](https://img.shields.io/badge/.NET-10.0-512BD4.svg)](https://dotnet.microsoft.com/)
[![Avalonia 11.3](https://img.shields.io/badge/Avalonia-11.3-663399.svg)](https://avaloniaui.net/)
[![Platform: Windows](https://img.shields.io/badge/Platform-Windows-0078D6.svg)](#windows-使用说明)
[![Platform: Windows + macOS](https://img.shields.io/badge/Platform-Windows%20%2B%20macOS-0078D6.svg)](#使用说明)

**简体中文** | [English](README.en.md) | [中文副本](README-CN.md)

AndroidTreeView 是一个用于 Android 设备巡检、测试与管理的 Windows 桌面工具。主程序负责设备总览、详情、投屏、基础工具、设置和更新;Mini 版本保持独立运行,常驻监听设备,并在授权后自动启动投屏。
AndroidTreeView 是一个用于 Android 设备巡检、测试与管理的桌面工具,支持 Windows 与 macOS(Apple Silicon)。主程序负责设备总览、详情、投屏、基础工具、设置和更新;Mini 版本保持独立运行,常驻监听设备,并在授权后自动启动投屏。

当前版本:**v1.0.5**。当前验证目标:App 构建通过、Mini 构建通过、全量测试通过,打包链路能为 App 和 Mini 分别生成 x64 上传 ZIP。
当前版本:**v1.0.6**。当前验证目标:App 构建通过、Mini 构建通过、全量测试通过,打包链路能为 App 和 Mini 分别生成 x64 上传 ZIP。

## 产品样式展示

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

## 核心能力

Expand All @@ -38,6 +38,7 @@ src/
AndroidTreeView.Shared
AndroidTreeView.App
AndroidTreeView.Mini
AndroidTreeView.Mini.Mac
tests/
AndroidTreeView.*.Tests
packaging/
Expand All @@ -58,6 +59,8 @@ dotnet run --project src/AndroidTreeView.App
dotnet run --project src/AndroidTreeView.Mini
```

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

如果找不到 ADB,主程序会显示 ADB 设置页。请安装 Android platform-tools 并加入 `PATH`,或手动选择 `adb.exe`。

## 开启 USB 调试
Expand All @@ -69,16 +72,22 @@ dotnet run --project src/AndroidTreeView.Mini

ADB 安装和排错见 [docs/adb-requirements.md](docs/adb-requirements.md)。

## Windows 使用说明
## 使用说明

1. 启动 AndroidTreeView。
2. 连接已开启并授权 USB 调试的 Android 设备。
3. 使用设备卡片查看状态、投屏、打开 CLI 或执行非破坏性工具。
4. 通过设置或关于页检查并安装更新。

### macOS 说明

- 从 Release 下载 `AndroidTreeView-<版本>-osx-arm64.zip`,解压后将 `AndroidTreeView.app` 拖入 `/Applications`。
- 首次打开若被 Gatekeeper 拦截(未签名),右键选择「打开」,或执行 `xattr -dr com.apple.quarantine AndroidTreeView.app` 放行。
- 设备卡片的「CLI 终端」在 macOS 上通过 Terminal.app 打开,提供与 Windows 一致的编号菜单(设备信息 / adb shell / logcat / 重启 / 关机 等)。

## Release ZIP 打包

当前版本号统一为 `1.0.5`,运行时版本、App/Mini 程序集版本、manifest 和 `build-update-zip.ps1` 默认版本保持一致。正式发布只通过 GitHub Actions 的 `Publish` 工作流完成,发布只接受 x64。
当前版本号统一为 `1.0.6`,运行时版本、App/Mini 程序集版本、manifest 和 `build-update-zip.ps1` 默认版本保持一致。正式发布只通过 GitHub Actions 的 `Publish` 工作流完成,发布只接受 x64。

本地命令仅用于验证打包链路:

Expand All @@ -90,10 +99,10 @@ ADB 安装和排错见 [docs/adb-requirements.md](docs/adb-requirements.md)。
示例输出:

```text
artifacts/AndroidTreeView-1.0.5-win-x64.zip
artifacts/AndroidTreeView-1.0.5-osx-arm64.zip
artifacts/AndroidTreeView-Mini-1.0.5-win-x64.zip
artifacts/AndroidTreeView-Mini-1.0.5-osx-arm64.zip
artifacts/AndroidTreeView-1.0.6-win-x64.zip
artifacts/AndroidTreeView-1.0.6-osx-arm64.zip
artifacts/AndroidTreeView-Mini-1.0.6-win-x64.zip
artifacts/AndroidTreeView-Mini-1.0.6-osx-arm64.zip
```

## 自动更新
Expand Down
2 changes: 1 addition & 1 deletion docs/app-contract.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

This document records the App-layer contract for the full app and the Mini companion.

Current product version: `1.0.5`.
Current product version: `1.0.6`.

## Shared Services

Expand Down
Loading