Record fact-sheet permissions and use the Google services label.

This commit is contained in:
franzap
2026-09-28 18:06:48 -03:00
parent 64224659d0
commit 324a854188
5 changed files with 18 additions and 15 deletions
@@ -108,7 +108,7 @@ class AppRecord(
/** /**
* [facts] in file order, one row per key. * [facts] in file order, one row per key.
* The file is a CSV with columns fact, value, and reason. * The file is a quoted CSV with columns fact, value, reason, and permissions.
* The sheet repeats a key once per library. A yes wins over a no. * The sheet repeats a key once per library. A yes wins over a no.
*/ */
val factRows: List<AppFact> val factRows: List<AppFact>
@@ -129,6 +129,7 @@ internal fun parseFactRows(facts: String): List<AppFact> {
val factIdx = header.indexOf("fact") val factIdx = header.indexOf("fact")
val valueIdx = header.indexOf("value") val valueIdx = header.indexOf("value")
val reasonIdx = header.indexOf("reason") val reasonIdx = header.indexOf("reason")
val permissionsIdx = header.indexOf("permissions")
if (factIdx < 0 || valueIdx < 0) return emptyList() if (factIdx < 0 || valueIdx < 0) return emptyList()
val rows = LinkedHashMap<String, AppFact>() val rows = LinkedHashMap<String, AppFact>()
for (record in table.drop(1)) { for (record in table.drop(1)) {
@@ -140,11 +141,13 @@ internal fun parseFactRows(facts: String): List<AppFact> {
else -> continue else -> continue
} }
val reason = if (reasonIdx < 0) "" else record.getOrNull(reasonIdx)?.trim().orEmpty() val reason = if (reasonIdx < 0) "" else record.getOrNull(reasonIdx)?.trim().orEmpty()
val permissions = if (permissionsIdx < 0) "" else record.getOrNull(permissionsIdx)?.trim().orEmpty()
val previous = rows[key] val previous = rows[key]
rows[key] = AppFact( rows[key] = AppFact(
key = key, key = key,
yes = previous?.yes == true || yes, yes = previous?.yes == true || yes,
reason = reason.ifBlank { previous?.reason.orEmpty() }, reason = reason.ifBlank { previous?.reason.orEmpty() },
permissions = permissions.ifBlank { previous?.permissions.orEmpty() },
) )
} }
return rows.values.toList() return rows.values.toList()
@@ -201,6 +204,7 @@ data class AppFact(
val key: String, val key: String,
val yes: Boolean, val yes: Boolean,
val reason: String = "", val reason: String = "",
val permissions: String = "",
) )
/** Kind 0 projection. `name`/`displayName` are already trimmed to non-blank. */ /** Kind 0 projection. `name`/`displayName` are already trimmed to non-blank. */
@@ -11,17 +11,18 @@ class CatalogArtifactsTest {
@Test @Test
fun parsesFactCsvAndKeepsReason() { fun parsesFactCsvAndKeepsReason() {
val rows = parseFactRows( val rows = parseFactRows(
"fact,value,reason\n" + "\"fact\",\"value\",\"reason\",\"permissions\"\n" +
"gms,no,\"no play services, com.google\"\n" + "\"google_services\",\"no\",\"Play services\",\"\"\n" +
"gms,yes,\n" + "\"google_services\",\"yes\",\"Firebase Cloud Messaging\",\"\"\n" +
"fcm,yes,\"uses, cloud\"\n", "\"location\",\"yes\",\"the map screen\",\"ACCESS_BACKGROUND_LOCATION,ACCESS_FINE_LOCATION\"\n",
) )
assertEquals(2, rows.size) assertEquals(2, rows.size)
assertEquals("gms", rows[0].key) assertEquals("google_services", rows[0].key)
assertTrue(rows[0].yes) assertTrue(rows[0].yes)
assertEquals("no play services, com.google", rows[0].reason) assertEquals("Firebase Cloud Messaging", rows[0].reason)
assertEquals("fcm", rows[1].key) assertEquals("location", rows[1].key)
assertEquals("uses, cloud", rows[1].reason) assertEquals("the map screen", rows[1].reason)
assertEquals("ACCESS_BACKGROUND_LOCATION,ACCESS_FINE_LOCATION", rows[1].permissions)
} }
@Test @Test
@@ -373,8 +373,7 @@ private fun FactPill(key: String, yes: Boolean) {
@Composable @Composable
private fun factLabel(key: String): String = when (key) { private fun factLabel(key: String): String = when (key) {
"gms" -> stringResource(R.string.fact_gms) "google_services" -> stringResource(R.string.fact_google_services)
"fcm" -> stringResource(R.string.fact_fcm)
"open_source" -> stringResource(R.string.fact_open_source) "open_source" -> stringResource(R.string.fact_open_source)
"e2ee" -> "E2EE" "e2ee" -> "E2EE"
else -> key.replace('_', ' ').replaceFirstChar { it.titlecase() } else -> key.replace('_', ' ').replaceFirstChar { it.titlecase() }
+1 -2
View File
@@ -71,9 +71,8 @@
<string name="copy">Copy</string> <string name="copy">Copy</string>
<string name="privacy_and_security">Privacy and security</string> <string name="privacy_and_security">Privacy and security</string>
<string name="fact_no">No %1$s</string> <string name="fact_no">No %1$s</string>
<string name="fact_gms">Google Play services</string> <string name="fact_google_services">Google services</string>
<string name="fact_open_source">Verified open source</string> <string name="fact_open_source">Verified open source</string>
<string name="fact_fcm">Firebase Cloud Messaging</string>
<string name="app_icon_description">%1$s icon</string> <string name="app_icon_description">%1$s icon</string>
<string name="screenshot_description">%1$s screenshot</string> <string name="screenshot_description">%1$s screenshot</string>
<string name="profile_avatar_description">%1$s avatar</string> <string name="profile_avatar_description">%1$s avatar</string>
@@ -8,8 +8,8 @@ import org.junit.Test
class FactPillTest { class FactPillTest {
@Test @Test
fun antifeatureAbsenceIsPositiveAndPresenceIsNot() { fun antifeatureAbsenceIsPositiveAndPresenceIsNot() {
assertTrue(factIsPositive("gms", yes = false)) assertTrue(factIsPositive("google_services", yes = false))
assertFalse(factIsPositive("gms", yes = true)) assertFalse(factIsPositive("google_services", yes = true))
assertFalse(factIsPositive("account_required", yes = true)) assertFalse(factIsPositive("account_required", yes = true))
assertTrue(factIsPositive("tracking", yes = false)) assertTrue(factIsPositive("tracking", yes = false))
} }