diff --git a/androidApp/build.gradle.kts b/androidApp/build.gradle.kts index 35eefc88f..8d367a4d5 100644 --- a/androidApp/build.gradle.kts +++ b/androidApp/build.gradle.kts @@ -43,9 +43,24 @@ if (keystorePropertiesFile.exists()) { keystorePropertiesFile.inputStream().use { keystoreProperties.load(it) } } +// The templated Android Auto experience (CarAppService + HomeScreen) is a Google "templated +// messaging" beta feature that is publishable only to Closed/Internal tracks — Open/Production +// submissions are auto-rejected (https://developer.android.com/training/cars/communication/templated-messaging). +// Default builds therefore ship *notification-only* car messaging, which is GA and production-safe. +// Build a Closed-track templated AAB with: -PenableCarTemplates=true +// ponytail: gated by a gradle property + res override, not a full build flavor — templated is +// parked until it leaves Google's beta. Promote to a flavor dimension only if CI must ship both. +val enableCarTemplates = (findProperty("enableCarTemplates") as String?)?.toBoolean() ?: false + configure { namespace = "org.meshtastic.app" + // When templates are enabled, this res dir overrides feature:car's notification-only + // automotive_app_desc.xml with one that also declares . + if (enableCarTemplates) { + sourceSets.getByName("google").res.srcDir("src/googleCarTemplates/res") + } + signingConfigs { create("release") { keyAlias = keystoreProperties["keyAlias"] as String? @@ -115,6 +130,10 @@ configure { } ndk { abiFilters += listOf("armeabi-v7a", "arm64-v8a") } + // Activates the (google-only) CarAppService. Off by default so production builds ship + // notification-only car messaging; flipped on by -PenableCarTemplates=true for Closed tracks. + manifestPlaceholders["carTemplatesEnabled"] = enableCarTemplates.toString() + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } diff --git a/androidApp/src/googleCarTemplates/res/xml/automotive_app_desc.xml b/androidApp/src/googleCarTemplates/res/xml/automotive_app_desc.xml new file mode 100644 index 000000000..0c07d16d3 --- /dev/null +++ b/androidApp/src/googleCarTemplates/res/xml/automotive_app_desc.xml @@ -0,0 +1,12 @@ + + + + + + diff --git a/feature/car/build.gradle.kts b/feature/car/build.gradle.kts index 93592f82f..13418087d 100644 --- a/feature/car/build.gradle.kts +++ b/feature/car/build.gradle.kts @@ -30,6 +30,11 @@ android { defaultConfig { minSdk = 23 consumerProguardFiles("proguard-rules.pro") + // The CarAppService is disabled unless -PenableCarTemplates=true. feature:car resolves the + // placeholder in its OWN manifest, so it must read the property directly (the app's value does + // not override a library's own placeholder). Default false → production ships it disabled. + manifestPlaceholders["carTemplatesEnabled"] = + ((findProperty("enableCarTemplates") as String?)?.toBoolean() ?: false).toString() } // Robolectric provides the Android context that androidx.car.app TestCarContext/ScreenController need. diff --git a/feature/car/src/main/AndroidManifest.xml b/feature/car/src/main/AndroidManifest.xml index 34bbec51c..94c531ad4 100644 --- a/feature/car/src/main/AndroidManifest.xml +++ b/feature/car/src/main/AndroidManifest.xml @@ -2,8 +2,13 @@ + diff --git a/feature/car/src/main/kotlin/org/meshtastic/feature/car/screens/HomeScreen.kt b/feature/car/src/main/kotlin/org/meshtastic/feature/car/screens/HomeScreen.kt index 6e72e6022..650f098c6 100644 --- a/feature/car/src/main/kotlin/org/meshtastic/feature/car/screens/HomeScreen.kt +++ b/feature/car/src/main/kotlin/org/meshtastic/feature/car/screens/HomeScreen.kt @@ -144,8 +144,22 @@ class HomeScreen( carContext.getCarService(AppManager::class.java).showAlert(alert) } + // Any exception thrown out of onGetTemplate() crashes the Android Auto host ("content not able to + // load") and fails Play's Auto review. Degrade to a safe template instead and log for diagnosis. + // NOTE: this guards exceptions in OUR build path; a host-side template-contract rejection (e.g. the + // messaging surface must be a ListTemplate/SectionedItemTemplate of ConversationItems, not this + // TabTemplate dashboard) would not throw here — confirm against the Play pre-launch stack before + // promoting templated builds. See -PenableCarTemplates in androidApp/build.gradle.kts. + @Suppress("TooGenericExceptionCaught") + override fun onGetTemplate(): Template = try { + buildHomeTemplate() + } catch (e: Exception) { + Logger.e(tag = "HomeScreen", throwable = e) { "onGetTemplate failed; showing fallback template" } + buildDisconnectedTemplate() + } + @Suppress("ReturnCount") - override fun onGetTemplate(): Template { + private fun buildHomeTemplate(): Template { val connectionStatus = stateCoordinator.sessionState.value.connectionStatus if (connectionStatus == ConnectionState.Disconnected || connectionStatus == ConnectionState.DeviceSleep) { return buildDisconnectedTemplate() diff --git a/feature/car/src/main/res/xml/automotive_app_desc.xml b/feature/car/src/main/res/xml/automotive_app_desc.xml index 8b46ed0ee..3bed3278c 100644 --- a/feature/car/src/main/res/xml/automotive_app_desc.xml +++ b/feature/car/src/main/res/xml/automotive_app_desc.xml @@ -1,5 +1,10 @@ + -