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
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text.RegularExpressions;
using Microsoft.Android.Build.Tasks;
using Microsoft.Build.Framework;
Expand All @@ -24,6 +25,7 @@ enum DeviceType
// Pattern to match device lines: <serial> <state> [key:value ...]
// Example: emulator-5554 device product:sdk_gphone64_arm64 model:sdk_gphone64_arm64
static readonly Regex AdbDevicesRegex = new(@"^([^\s]+)\s+(device|offline|unauthorized|no permissions)\s*(.*)$", RegexOptions.Compiled);
static readonly Regex ApiRegex = new(@"\bApi\b", RegexOptions.Compiled);

readonly List<string> output = [];

Expand Down Expand Up @@ -198,8 +200,7 @@ static string MapAdbStateToStatus (string adbState)
var avdName = outputLines [0].Trim ();
// Verify it's not the "OK" response
if (!string.IsNullOrEmpty (avdName) && !avdName.Equals ("OK", StringComparison.OrdinalIgnoreCase)) {
// Format the AVD name: replace underscores with spaces
return avdName.Replace ('_', ' ');
return FormatDisplayName (serial, avdName);
}
}
} catch (Exception ex) {
Expand All @@ -208,4 +209,21 @@ static string MapAdbStateToStatus (string adbState)

return null;
}

/// <summary>
/// Formats the AVD name into a more user-friendly display name. Replace underscores with spaces and title case.
/// </summary>
public string FormatDisplayName (string serial, string avdName)
{
Log.LogDebugMessage ($"Emulator {serial}, original AVD name: {avdName}");

// Title case and replace underscores with spaces
var textInfo = CultureInfo.InvariantCulture.TextInfo;
avdName = textInfo.ToTitleCase (avdName.Replace ('_', ' '));

// Replace "Api" with "API"
avdName = ApiRegex.Replace (avdName, "API");
Log.LogDebugMessage ($"Emulator {serial}, formatted AVD display name: {avdName}");
return avdName;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -436,5 +436,125 @@ public void ParseAdbDaemonStarting ()
Assert.AreEqual ("Device", physical.GetMetadata ("Type"));
Assert.AreEqual ("Online", physical.GetMetadata ("Status"));
}

[Test]
public void FormatDisplayName_ReplacesUnderscoresWithSpaces ()
{
var task = new MockGetAvailableAndroidDevices {
BuildEngine = engine,
};

var result = task.FormatDisplayName ("emulator-5554", "pixel_7_pro");

Assert.AreEqual ("Pixel 7 Pro", result, "Should replace underscores with spaces");
}

[Test]
public void FormatDisplayName_AppliesTitleCase ()
{
var task = new MockGetAvailableAndroidDevices {
BuildEngine = engine,
};

var result = task.FormatDisplayName ("emulator-5554", "pixel 7 pro");

Assert.AreEqual ("Pixel 7 Pro", result, "Should apply title case");
}

[Test]
public void FormatDisplayName_ReplacesApiWithAPIUppercase ()
{
var task = new MockGetAvailableAndroidDevices {
BuildEngine = engine,
};

var result = task.FormatDisplayName ("emulator-5554", "pixel_5_api_34");

Assert.AreEqual ("Pixel 5 API 34", result, "Should replace 'Api' with 'API'");
}

[Test]
public void FormatDisplayName_HandlesMultipleApiOccurrences ()
{
var task = new MockGetAvailableAndroidDevices {
BuildEngine = engine,
};

var result = task.FormatDisplayName ("emulator-5554", "test_api_device_api_35");

Assert.AreEqual ("Test API Device API 35", result, "Should replace all 'Api' occurrences with 'API'");
}

[Test]
public void FormatDisplayName_HandlesMixedCaseInput ()
{
var task = new MockGetAvailableAndroidDevices {
BuildEngine = engine,
};

var result = task.FormatDisplayName ("emulator-5554", "PiXeL_7_API_35");

Assert.AreEqual ("Pixel 7 API 35", result, "Should normalize mixed case input");
}

[Test]
public void FormatDisplayName_HandlesComplexNames ()
{
var task = new MockGetAvailableAndroidDevices {
BuildEngine = engine,
};

var result = task.FormatDisplayName ("emulator-5554", "pixel_9_pro_xl_api_36");

Assert.AreEqual ("Pixel 9 Pro Xl API 36", result, "Should format complex names correctly");
}

[Test]
public void FormatDisplayName_PreservesNumbersAndSpecialChars ()
{
var task = new MockGetAvailableAndroidDevices {
BuildEngine = engine,
};

var result = task.FormatDisplayName ("emulator-5554", "pixel_7-pro_api_35");

Assert.AreEqual ("Pixel 7-Pro API 35", result, "Should preserve hyphens and numbers");
}

[Test]
public void FormatDisplayName_HandlesEmptyString ()
{
var task = new MockGetAvailableAndroidDevices {
BuildEngine = engine,
};

var result = task.FormatDisplayName ("emulator-5554", "");

Assert.AreEqual ("", result, "Should handle empty string");
}

[Test]
public void FormatDisplayName_HandlesSingleWord ()
{
var task = new MockGetAvailableAndroidDevices {
BuildEngine = engine,
};

var result = task.FormatDisplayName ("emulator-5554", "pixel");

Assert.AreEqual ("Pixel", result, "Should capitalize single word");
}

[Test]
public void FormatDisplayName_DoesNotReplaceApiInsideWords ()
{
var task = new MockGetAvailableAndroidDevices {
BuildEngine = engine,
};

var result = task.FormatDisplayName ("emulator-5554", "erapidevice");

Assert.AreEqual ("Erapidevice", result, "Should not replace 'api' when it's part of a larger word");
}
}
}
Loading