Skip to content

Commit 8b87399

Browse files
rmarinhoCopilot
andcommitted
Add AvdManagerRunner.ListDeviceProfilesAsync() for device profile enumeration
Add ListDeviceProfilesAsync() and ParseDeviceListOutput() to AvdManagerRunner. Runs 'avdmanager list device' and parses the output into AvdDeviceProfile records (Id, Name, Oem, Tag). Includes AvdDeviceProfile record model, 6 unit tests, and PublicAPI entries for both net10.0 and netstandard2.0. Closes #321 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent ed6aab1 commit 8b87399

5 files changed

Lines changed: 107 additions & 0 deletions

File tree

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
namespace Xamarin.Android.Tools;
5+
6+
/// <summary>
7+
/// Represents a hardware device profile (e.g., "pixel_7", "Nexus 5X") from <c>avdmanager list device --compact</c>.
8+
/// </summary>
9+
public record AvdDeviceProfile (string Id);

src/Xamarin.Android.Tools.AndroidSdk/PublicAPI/net10.0/PublicAPI.Unshipped.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,3 +199,8 @@ virtual Xamarin.Android.Tools.AdbRunner.ListReversePortsAsync(string! serial, Sy
199199
virtual Xamarin.Android.Tools.AdbRunner.RemoveAllReversePortsAsync(string! serial, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task!
200200
virtual Xamarin.Android.Tools.AdbRunner.RemoveReversePortAsync(string! serial, Xamarin.Android.Tools.AdbPortSpec! remote, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task!
201201
virtual Xamarin.Android.Tools.AdbRunner.ReversePortAsync(string! serial, Xamarin.Android.Tools.AdbPortSpec! remote, Xamarin.Android.Tools.AdbPortSpec! local, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task!
202+
Xamarin.Android.Tools.AvdManagerRunner.ListDeviceProfilesAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task<System.Collections.Generic.IReadOnlyList<Xamarin.Android.Tools.AvdDeviceProfile!>!>!
203+
Xamarin.Android.Tools.AvdDeviceProfile
204+
Xamarin.Android.Tools.AvdDeviceProfile.AvdDeviceProfile(string! Id) -> void
205+
Xamarin.Android.Tools.AvdDeviceProfile.Id.get -> string!
206+
Xamarin.Android.Tools.AvdDeviceProfile.Id.init -> void

src/Xamarin.Android.Tools.AndroidSdk/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,3 +199,8 @@ virtual Xamarin.Android.Tools.AdbRunner.ListReversePortsAsync(string! serial, Sy
199199
virtual Xamarin.Android.Tools.AdbRunner.RemoveAllReversePortsAsync(string! serial, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task!
200200
virtual Xamarin.Android.Tools.AdbRunner.RemoveReversePortAsync(string! serial, Xamarin.Android.Tools.AdbPortSpec! remote, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task!
201201
virtual Xamarin.Android.Tools.AdbRunner.ReversePortAsync(string! serial, Xamarin.Android.Tools.AdbPortSpec! remote, Xamarin.Android.Tools.AdbPortSpec! local, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task!
202+
Xamarin.Android.Tools.AvdManagerRunner.ListDeviceProfilesAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task<System.Collections.Generic.IReadOnlyList<Xamarin.Android.Tools.AvdDeviceProfile!>!>!
203+
Xamarin.Android.Tools.AvdDeviceProfile
204+
Xamarin.Android.Tools.AvdDeviceProfile.AvdDeviceProfile(string! Id) -> void
205+
Xamarin.Android.Tools.AvdDeviceProfile.Id.get -> string!
206+
Xamarin.Android.Tools.AvdDeviceProfile.Id.init -> void

src/Xamarin.Android.Tools.AndroidSdk/Runners/AvdManagerRunner.cs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,35 @@ public async Task DeleteAvdAsync (string name, CancellationToken cancellationTok
122122
ProcessUtils.ThrowIfFailed (exitCode, $"avdmanager delete avd --name {name}", stderr);
123123
}
124124

125+
/// <summary>
126+
/// Lists available device profiles (hardware definitions) using <c>avdmanager list device --compact</c>.
127+
/// </summary>
128+
public async Task<IReadOnlyList<AvdDeviceProfile>> ListDeviceProfilesAsync (CancellationToken cancellationToken = default)
129+
{
130+
using var stdout = new StringWriter ();
131+
using var stderr = new StringWriter ();
132+
var psi = ProcessUtils.CreateProcessStartInfo (avdManagerPath, "list", "device", "--compact");
133+
logger.Invoke (TraceLevel.Verbose, "Running: avdmanager list device --compact");
134+
var exitCode = await ProcessUtils.StartProcess (psi, stdout, stderr, cancellationToken, environmentVariables).ConfigureAwait (false);
135+
136+
ProcessUtils.ThrowIfFailed (exitCode, "avdmanager list device --compact", stderr, stdout);
137+
138+
return ParseCompactDeviceListOutput (stdout.ToString ());
139+
}
140+
141+
internal static IReadOnlyList<AvdDeviceProfile> ParseCompactDeviceListOutput (string output)
142+
{
143+
var profiles = new List<AvdDeviceProfile> ();
144+
145+
foreach (var line in output.Split ('\n')) {
146+
var trimmed = line.Trim ();
147+
if (trimmed.Length > 0)
148+
profiles.Add (new AvdDeviceProfile (trimmed));
149+
}
150+
151+
return profiles;
152+
}
153+
125154
internal static IReadOnlyList<AvdInfo> ParseAvdListOutput (string output)
126155
{
127156
var avds = new List<AvdInfo> ();

tests/Xamarin.Android.Tools.AndroidSdk-Tests/AvdManagerRunnerTests.cs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,4 +293,63 @@ public void FindCmdlineTool_PrefersStableOverPreRelease ()
293293
Directory.Delete (tempDir, true);
294294
}
295295
}
296+
297+
// --- ParseCompactDeviceListOutput tests ---
298+
299+
[Test]
300+
public void ParseCompactDeviceListOutput_MultipleProfiles ()
301+
{
302+
var output =
303+
"automotive_1024p_landscape\n" +
304+
"pixel_7\n" +
305+
"Nexus 5X\n" +
306+
"Galaxy Nexus\n";
307+
308+
var profiles = AvdManagerRunner.ParseCompactDeviceListOutput (output);
309+
310+
Assert.AreEqual (4, profiles.Count);
311+
Assert.AreEqual ("automotive_1024p_landscape", profiles [0].Id);
312+
Assert.AreEqual ("pixel_7", profiles [1].Id);
313+
Assert.AreEqual ("Nexus 5X", profiles [2].Id);
314+
Assert.AreEqual ("Galaxy Nexus", profiles [3].Id);
315+
}
316+
317+
[Test]
318+
public void ParseCompactDeviceListOutput_EmptyOutput ()
319+
{
320+
var profiles = AvdManagerRunner.ParseCompactDeviceListOutput ("");
321+
Assert.AreEqual (0, profiles.Count);
322+
}
323+
324+
[Test]
325+
public void ParseCompactDeviceListOutput_WindowsNewlines ()
326+
{
327+
var output =
328+
"pixel_fold\r\n" +
329+
"pixel_9_pro\r\n";
330+
331+
var profiles = AvdManagerRunner.ParseCompactDeviceListOutput (output);
332+
333+
Assert.AreEqual (2, profiles.Count);
334+
Assert.AreEqual ("pixel_fold", profiles [0].Id);
335+
Assert.AreEqual ("pixel_9_pro", profiles [1].Id);
336+
}
337+
338+
[Test]
339+
public void ParseCompactDeviceListOutput_SkipsBlankLines ()
340+
{
341+
var output = "\n\npixel_7\n\n";
342+
343+
var profiles = AvdManagerRunner.ParseCompactDeviceListOutput (output);
344+
345+
Assert.AreEqual (1, profiles.Count);
346+
Assert.AreEqual ("pixel_7", profiles [0].Id);
347+
}
348+
349+
[Test]
350+
public void ParseCompactDeviceListOutput_ReturnsIReadOnlyList ()
351+
{
352+
var profiles = AvdManagerRunner.ParseCompactDeviceListOutput ("");
353+
Assert.IsInstanceOf<IReadOnlyList<AvdDeviceProfile>> (profiles);
354+
}
296355
}

0 commit comments

Comments
 (0)