diff --git a/gearslip/src/main/java/app/seb3thehacker/gearslip/car/CarLauncher.kt b/gearslip/src/main/java/app/seb3thehacker/gearslip/car/CarLauncher.kt index b5a4a6c..04f4b64 100644 --- a/gearslip/src/main/java/app/seb3thehacker/gearslip/car/CarLauncher.kt +++ b/gearslip/src/main/java/app/seb3thehacker/gearslip/car/CarLauncher.kt @@ -298,13 +298,10 @@ fun CarLauncher() { val showVehicleData = rememberVehicleDataShown() fun tileOf(entry: Entry): Tile { - // Only apps that don't work get a mark. The X rates an app's own car screens; a messenger - // shown on Gearslip's own Messages screen has none, so it never gets one. - val pkg = entry.packageName?.takeIf { entry.messaging == null } val id = entry.componentId return Tile( entry.builtIn?.let { context.getString(it.labelRes) } ?: entry.label, entry.icon, entry.builtIn?.glyph, - broken = pkg != null && (KnownApps.isBroken(context, pkg) || (entry.template != null && KnownApps.screenBroken(pkg))), + broken = markedBroken(context, entry), onLongClick = id?.let { { navigator.showAppMenu(it) } }, id = id, ) { @@ -357,8 +354,21 @@ fun CarLauncher() { } /** A red disc with a white X: marks a tile known not to work with Gearslip yet. */ +/** + * Whether [entry] gets the red X, in the car and in the phone's app list alike. Only apps that + * don't work get one, and a patched copy that does (Waze through Morphe) never does, since + * [KnownApps.isBroken] knows it by its signer. The X rates an app's own car screens; a messenger + * shown on Gearslip's own Messages screen has none, so it gets one only when it's one of + * Google's apps, which never work (Google Maps lists itself only as a messenger). + */ +internal fun markedBroken(context: android.content.Context, entry: Entry): Boolean { + val pkg = entry.packageName ?: return false + if (entry.messaging != null) return KnownApps.brokenAsMessenger(context, pkg) + return KnownApps.isBroken(context, pkg) || (entry.template != null && KnownApps.screenBroken(pkg)) +} + @Composable -private fun BrokenBadge(size: androidx.compose.ui.unit.Dp, modifier: Modifier = Modifier) { +internal fun BrokenBadge(size: androidx.compose.ui.unit.Dp, modifier: Modifier = Modifier) { Box( modifier.size(size).background(Color(0xFFD32F2F), CircleShape), contentAlignment = Alignment.Center, diff --git a/gearslip/src/main/java/app/seb3thehacker/gearslip/host/KnownApps.kt b/gearslip/src/main/java/app/seb3thehacker/gearslip/host/KnownApps.kt index 9319c3c..8a244f0 100644 --- a/gearslip/src/main/java/app/seb3thehacker/gearslip/host/KnownApps.kt +++ b/gearslip/src/main/java/app/seb3thehacker/gearslip/host/KnownApps.kt @@ -80,6 +80,10 @@ object KnownApps { fun startsHidden(context: Context, packageName: String, messaging: Boolean): Boolean = isBroken(context, packageName) && (!messaging || packageName in google) + /** Google's own apps get the red X even as a messenger: Google Maps shows only as one. */ + fun brokenAsMessenger(context: Context, packageName: String): Boolean = + packageName in google && isBroken(context, packageName) + /** * The certificate each broken app's own publisher signs it with. A copy signed with another * key has been patched to accept Gearslip, like Waze with the waze-gearslip Morphe patch, and diff --git a/gearslip/src/main/java/app/seb3thehacker/gearslip/ui/HomeCarSettings.kt b/gearslip/src/main/java/app/seb3thehacker/gearslip/ui/HomeCarSettings.kt index bbd479e..7240475 100644 --- a/gearslip/src/main/java/app/seb3thehacker/gearslip/ui/HomeCarSettings.kt +++ b/gearslip/src/main/java/app/seb3thehacker/gearslip/ui/HomeCarSettings.kt @@ -1,5 +1,7 @@ package app.seb3thehacker.gearslip.ui +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.offset import androidx.annotation.StringRes import androidx.compose.ui.res.stringResource import app.seb3thehacker.gearslip.R @@ -418,7 +420,20 @@ private fun AppRows() { entry.label, Modifier.toggleable(shown, role = Role.Checkbox) { CarSettings.setAppHidden(id, !it) }, subtitle = if (added) stringResource(R.string.car_apps_added_by_you) else null, - leading = { entry.icon?.let { Image(it, contentDescription = null, Modifier.size(40.dp)) } }, + leading = { + Box { + entry.icon?.let { Image(it, contentDescription = null, Modifier.size(40.dp)) } + // The same red X the car shows, so it's clear why the app starts unticked. + if (app.seb3thehacker.gearslip.car.markedBroken(context, entry)) { + app.seb3thehacker.gearslip.car.BrokenBadge( + 16.dp, + Modifier.align(Alignment.BottomEnd) + .offset(x = 4.dp, y = 3.dp) + .border(2.dp, MaterialTheme.colorScheme.surfaceContainerHigh, androidx.compose.foundation.shape.CircleShape), + ) + } + } + }, trailing = { Row(verticalAlignment = Alignment.CenterVertically) { if (added && pkg != null) {