dotnet / dotnet/android

Add AdbRunner screencap and screenrecord APIs

Open
#12,086 0 comments 0 reactions 0 assignees View on GitHub
android-tools needs-triage
Dominant language
C#
Stars
2.1k
Forks
579
Avg merge
1d 20h
Merged PRs (30d)
257

Description

## Summary

Add screen capture APIs to `Xamarin.Android.Tools.AdbRunner` so the MAUI DevTools CLI can capture screenshots and screen recordings from Android devices/emulators without consumers shelling out to `adb shell screencap` / `screenrecord`.

## Context

Once the DevFlow agent is up, `maui devflow ui screenshot` captures the running MAUI app's view. But the agent is unavailable when (a) the app hasn't launched yet, (b) the app crashed at startup, (c) you want to capture the full device screen including system UI, or (d) you're driving a non-MAUI app from the same harness. For those, we need a typed `adb`-level wrapper. See [maui-labs#197](https://github.com/dotnet/maui-labs/issues/197) audit.

## Proposed API

```csharp
namespace Xamarin.Android.Tools;

public partial class AdbRunner
{
/// adb -s shell screencap -p /sdcard/.png && adb pull && adb shell rm
public virtual Task ScreenshotAsync(
string serial,
string outputPath,
ScreenshotOptions? options = null,
CancellationToken cancellationToken = default);

/// adb -s shell screenrecord [--time-limit N] [--bit-rate B] [--size WxH] /sdcard/.mp4
/// Returns a handle that the consumer disposes to stop the recording (sends SIGINT to screenrecord, then pulls).
public virtual IAsyncDisposable StartScreenRecordAsync(
string serial,
string outputPath,
ScreenRecordOptions? options = null,
CancellationToken cancellationToken = default);
}

public record ScreenshotOptions(
ScreenshotFormat Format = ScreenshotFormat.Png,
/// If true, capture the display via `screencap -d `. Useful for foldables / external displays.
int? DisplayId = null);

public enum ScreenshotFormat { Png /* default */, Jpeg /* via -j */ }

public record AdbScreenshotResult(string OutputPath, int Width, int Height, long FileSizeBytes);

public record ScreenRecordOptions(
TimeSpan? TimeLimit = null, // default 180s, max 180s per screenrecord
int? BitRateBitsPerSecond = null, // default 4000000
(int Width, int Height)? Size = null, // default native
bool VerboseStderr = false);
```

Implementation notes:
- Both methods write to a temp path under `/sdcard/` (or `getprop EXTERNAL_STORAGE`), pull, and delete. Use a UUID in the filename to avoid clashes between concurrent calls.
- `StartScreenRecordAsync` returns `IAsyncDisposable.DisposeAsync()` which: kills the device-side `screenrecord` process (find via `pidof screenrecord` then `kill -2`), waits a moment for the file to flush, pulls it, deletes the device copy. If the kill fails or the file is empty, `DisposeAsync` should throw so consumers know the recording was lost.
- `ScreenshotResult.Width`/`Height` populated by reading the PNG header after pull (use existing image-header parsing if available; otherwise just leave 0/0 and let consumers re-read the file).

## Consumer

- **MAUI DevTools CLI** ([dotnet/maui-labs](https://github.com/dotnet/maui-labs)) — `maui android device screenshot [--output …] [--json]` and `maui android device record-video [--output …] [--time-limit …] [--json]`. See [maui-labs#197](https://github.com/dotnet/maui-labs/issues/197) audit.
- **DevFlow integration tests** for full-screen captures during emulator-pre-launch and crash-on-startup repros.
- **Bug report tooling** — a scripted "capture device state" command that bundles a screenshot, `dumpsys`, and `getprop` output.

## Related

- dotnet/android#12071 — Add ADB wrapper (parent issue)
- maui-labs dotnet/android-tools#197 — DevFlow skill audit; current `references/android.md` "Raw fallbacks not yet in `maui` CLI" section

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.