Introduce a util method PrettyConcat

The method can be used when printing string list in a well-formated way
in user-facing messages.
This will be used in a follow up change.

Test: m nothing --no-skip-soong-tests
Change-Id: I77e3445a5333f82067dd8f1bb6ad892c69754ece
diff --git a/android/util.go b/android/util.go
index 3c0af2f..2d269b7 100644
--- a/android/util.go
+++ b/android/util.go
@@ -177,6 +177,41 @@
 	return m
 }
 
+// PrettyConcat returns the formatted concatenated string suitable for displaying user-facing
+// messages.
+func PrettyConcat(list []string, quote bool, lastSep string) string {
+	if len(list) == 0 {
+		return ""
+	}
+
+	quoteStr := func(v string) string {
+		if !quote {
+			return v
+		}
+		return fmt.Sprintf("%q", v)
+	}
+
+	if len(list) == 1 {
+		return quoteStr(list[0])
+	}
+
+	var sb strings.Builder
+	for i, val := range list {
+		if i > 0 {
+			sb.WriteString(", ")
+		}
+		if i == len(list)-1 {
+			sb.WriteString(lastSep)
+			if lastSep != "" {
+				sb.WriteString(" ")
+			}
+		}
+		sb.WriteString(quoteStr(val))
+	}
+
+	return sb.String()
+}
+
 // ListSetDifference checks if the two lists contain the same elements. It returns
 // a boolean which is true if there is a difference, and then returns lists of elements
 // that are in l1 but not l2, and l2 but not l1.
diff --git a/android/util_test.go b/android/util_test.go
index 6537d69..b76ffcf 100644
--- a/android/util_test.go
+++ b/android/util_test.go
@@ -867,3 +867,51 @@
 		})
 	}
 }
+
+var prettyConcatTestCases = []struct {
+	name          string
+	list          []string
+	quote         bool
+	lastSeparator string
+	expected      string
+}{
+	{
+		name:          "empty",
+		list:          []string{},
+		quote:         false,
+		lastSeparator: "and",
+		expected:      ``,
+	},
+	{
+		name:          "single",
+		list:          []string{"a"},
+		quote:         true,
+		lastSeparator: "and",
+		expected:      `"a"`,
+	},
+	{
+		name:          "with separator",
+		list:          []string{"a", "b", "c"},
+		quote:         true,
+		lastSeparator: "or",
+		expected:      `"a", "b", or "c"`,
+	},
+	{
+		name:          "without separator",
+		list:          []string{"a", "b", "c"},
+		quote:         false,
+		lastSeparator: "",
+		expected:      `a, b, c`,
+	},
+}
+
+func TestPrettyConcat(t *testing.T) {
+	for _, testCase := range prettyConcatTestCases {
+		t.Run(testCase.name, func(t *testing.T) {
+			concatString := PrettyConcat(testCase.list, testCase.quote, testCase.lastSeparator)
+			if !reflect.DeepEqual(concatString, testCase.expected) {
+				t.Errorf("expected %#v, got %#v", testCase.expected, concatString)
+			}
+		})
+	}
+}