Sometimes I see error if my app run in Android Auto emulator.
2023-06-23 08:44:24.990 12425-12425 AndroidRuntime com.capsule E FATAL EXCEPTION: main
Process: com.capsule, PID: 12425
java.lang.RuntimeException: androidx.car.app.HostException: Remote getTemplate onSuccess call failed
at androidx.car.app.utils.RemoteUtils.lambda$dispatchCallFromHost$0(RemoteUtils.java:155)
at androidx.car.app.utils.RemoteUtils$$ExternalSyntheticLambda2.run(Unknown Source:6)
at androidx.car.app.utils.ThreadUtils.runOnMain(ThreadUtils.java:39)
at androidx.car.app.utils.RemoteUtils.dispatchCallFromHost(RemoteUtils.java:147)
at androidx.car.app.utils.RemoteUtils.lambda$dispatchCallFromHost$1(RemoteUtils.java:186)
at androidx.car.app.utils.RemoteUtils$$ExternalSyntheticLambda3.run(Unknown Source:8)
at android.os.Handler.handleCallback(Handler.java:914)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:224)
at android.app.ActivityThread.main(ActivityThread.java:7560)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:539)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)
Caused by: androidx.car.app.HostException: Remote getTemplate onSuccess call failed
at androidx.car.app.utils.RemoteUtils.dispatchCallToHostForResult(RemoteUtils.java:93)
at androidx.car.app.utils.RemoteUtils.dispatchCallToHost(RemoteUtils.java:106)
at androidx.car.app.utils.RemoteUtils.sendSuccessResponseToHost(RemoteUtils.java:222)
at androidx.car.app.utils.RemoteUtils.lambda$dispatchCallFromHost$0(RemoteUtils.java:150)
at androidx.car.app.utils.RemoteUtils$$ExternalSyntheticLambda2.run(Unknown Source:6)
at androidx.car.app.utils.ThreadUtils.runOnMain(ThreadUtils.java:39)
at androidx.car.app.utils.RemoteUtils.dispatchCallFromHost(RemoteUtils.java:147)
at androidx.car.app.utils.RemoteUtils.lambda$dispatchCallFromHost$1(RemoteUtils.java:186)
at androidx.car.app.utils.RemoteUtils$$ExternalSyntheticLambda3.run(Unknown Source:8)
at android.os.Handler.handleCallback(Handler.java:914)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:224)
at android.app.ActivityThread.main(ActivityThread.java:7560)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:539)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)
Caused by: java.lang.IllegalStateException: bnm: Unsupported template type as the last step in a task. [template: GridTemplate, ID: 79c973e6-e3a0-4cae-a540-8c4d9b86365f]
at android.os.Parcel.createException(Parcel.java:2082)
at android.os.Parcel.readException(Parcel.java:2042)
at android.os.Parcel.readException(Parcel.java:1990)
at androidx.car.app.IOnDoneCallback$Stub$Proxy.onSuccess(IOnDoneCallback.java:141)
at androidx.car.app.utils.RemoteUtils.lambda$sendSuccessResponseToHost$3(RemoteUtils.java:224)
at androidx.car.app.utils.RemoteUtils$$ExternalSyntheticLambda0.call(Unknown Source:6)
at androidx.car.app.utils.RemoteUtils.dispatchCallToHostForResult(RemoteUtils.java:87)
at androidx.car.app.utils.RemoteUtils.dispatchCallToHost(RemoteUtils.java:106)
at androidx.car.app.utils.RemoteUtils.sendSuccessResponseToHost(RemoteUtils.java:222)
at androidx.car.app.utils.RemoteUtils.lambda$dispatchCallFromHost$0(RemoteUtils.java:150)
at androidx.car.app.utils.RemoteUtils$$ExternalSyntheticLambda2.run(Unknown Source:6)
at androidx.car.app.utils.ThreadUtils.runOnMain(ThreadUtils.java:39)
at androidx.car.app.utils.RemoteUtils.dispatchCallFromHost(RemoteUtils.java:147)
at androidx.car.app.utils.RemoteUtils.lambda$dispatchCallFromHost$1(RemoteUtils.java:186)
at androidx.car.app.utils.RemoteUtils$$ExternalSyntheticLambda3.run(Unknown Source:8)
at android.os.Handler.handleCallback(Handler.java:914)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:224)
at android.app.ActivityThread.main(ActivityThread.java:7560)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:539)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)
2023-06-23 08:44:24.998 1897-5094 ActivityTaskManager system_server W Force finishing activity com.capsule/.MainActivity
Code of my CarPlayScreen class:
package com.capsule
import android.util.Log
import androidx.car.app.CarContext
import androidx.car.app.Screen
import androidx.car.app.model.*
import androidx.core.graphics.drawable.IconCompat
import com.tencent.mmkv.MMKV
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import org.json.JSONObject
class CarPlayScreen(carContext: CarContext) : Screen(carContext) {
private val LOG_TAG = "CarPlayScreen"
private var eventBus = EventBus.getDefault()
private var lastConnectedDeviceId: String? = null
private var pinCode: String? = null
private var capsuleState: CapsuleState? = null
private fun renderScreen() {
invalidate()
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onCapsuleStateUpdate(state: CapsuleState) {
capsuleState = state
renderScreen()
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onGetCurrentConnection(event: ConnectedDevice) {
Log.d(LOG_TAG, "onConnectToDevice() connection to ${event.currentConnection?.identifier}")
if (event.currentConnection != null)
lastConnectedDeviceId = event.currentConnection.identifier
else if (lastConnectedDeviceId != null)
eventBus.post(
BleManagerActions(
BleManagerActionTypes.CONNECT_DEVICE,
lastConnectedDeviceId
)
)
renderScreen()
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onConnectToDevice(device: AdvDevice) {
Log.d(LOG_TAG, "onConnectDevice() connected to ${device.identifier}")
lastConnectedDeviceId = device.identifier
renderScreen()
}
init {
eventBus.register(this)
MMKV.defaultMMKV().decodeString("StoreCapsuleControl")?.let {
val lastConnectedDevice = JSONObject(it)
if (!lastConnectedDevice.isNull("lastCapsuleBleDeviceId"))
lastConnectedDeviceId = lastConnectedDevice.getString("lastCapsuleBleDeviceId")
pinCode = lastConnectedDevice.getString("currentPIN")
eventBus.post(BleManagerActionTypes.GET_CONNECTED_DEVICE)
}
}
override fun onGetTemplate(): Template {
return if (lastConnectedDeviceId == null)
GridTemplate.Builder().apply {
setLoading(false)
setTitle("Need Capsule connection")
setHeaderAction(Action.APP_ICON)
val itemList = ItemList.Builder()
.setNoItemsMessage("Please use your mobile application first to connect to your Capsule")
.build()
setSingleList(itemList)
setHeaderAction(Action.APP_ICON)
}.build()
else if (capsuleState == null)
GridTemplate.Builder().apply {
setLoading(true)
setTitle("Wait Capsule connection")
setHeaderAction(Action.APP_ICON)
}.build()
else buildFullStateScreenTemplate()
}
private fun buildFullStateScreenTemplate(): Template {
val closedDoorIcon = CarIcon.Builder(
IconCompat.createWithResource(
carContext, R.drawable.locked_door
)
).build()
val openDoorIcon = CarIcon.Builder(
IconCompat.createWithResource(
carContext, R.drawable.open_door
)
).build()
val gridListBuilder = ItemList.Builder()
.apply {
// LeftDoor Mode
val leftDoor = GridItem.Builder()
when (capsuleState!!.leftDoorStatus) {
DoorState.CLOSED -> {
leftDoor.setTitle("OPEN")
leftDoor.setImage(closedDoorIcon)
leftDoor.setOnClickListener(capsuleCommand(2, 0x9))
}
DoorState.OPEN -> {
leftDoor.setTitle("CLOSE")
leftDoor.setImage(openDoorIcon)
leftDoor.setOnClickListener(capsuleCommand(2, 0xA))
}
else -> {
leftDoor.setLoading(true)
leftDoor.setTitle(capsuleState!!.leftDoorStatus.name.lowercase())
}
}
addItem(leftDoor.build())
// RightDoor Mode
val rightDoor = GridItem.Builder()
when (capsuleState!!.rightDoorStatus) {
DoorState.CLOSED -> {
rightDoor.setTitle("OPEN")
rightDoor.setImage(closedDoorIcon)
rightDoor.setOnClickListener(capsuleCommand(3, 0x9))
}
DoorState.OPEN -> {
rightDoor.setTitle("CLOSE")
rightDoor.setImage(openDoorIcon)
rightDoor.setOnClickListener(capsuleCommand(3, 0xA))
}
else -> {
rightDoor.setLoading(true)
rightDoor.setTitle(capsuleState!!.rightDoorStatus.name.lowercase())
}
}
addItem(rightDoor.build())
// Temperature
val temperatureState = GridItem.Builder()
temperatureState.setTitle("${capsuleState!!.temperature}°C")
val temperatureIcon = IconCompat.createWithResource(
carContext, R.drawable.temperature_icon
)
temperatureState.setImage(CarIcon.Builder(temperatureIcon).build())
addItem(temperatureState.build())
// Front Light Mode
val frontLight = GridItem.Builder()
var frontLightIcon = IconCompat.createWithResource(
carContext, R.drawable.frontlight_on
)
when (capsuleState!!.frontLightMode) {
LightState.OFF -> {
frontLight.setTitle("ON")
frontLightIcon = IconCompat.createWithResource(
carContext, R.drawable.frontlight_off
)
frontLight.setOnClickListener(capsuleCommand(0, 1))
}
LightState.ON -> {
frontLight.setTitle("OFF")
frontLight.setOnClickListener(capsuleCommand(0, 0))
}
LightState.STROBE -> {
frontLight.setTitle("OFF")
frontLight.setOnClickListener(capsuleCommand(0, 0))
}
}
frontLight.setImage(CarIcon.Builder(frontLightIcon).build())
addItem(frontLight.build())
// Front Sublight Mode
val frontSublight = GridItem.Builder()
var frontSublightIcon = IconCompat.createWithResource(
carContext, R.drawable.frontsublight_on
)
when (capsuleState!!.frontSubLightMode) {
LightState.OFF -> {
frontSublight.setTitle("ON")
frontSublightIcon = IconCompat.createWithResource(
carContext, R.drawable.frontsublight_off
)
frontSublight.setOnClickListener(capsuleCommand(1, 1))
}
LightState.ON -> {
frontSublight.setTitle("OFF")
frontSublight.setOnClickListener(capsuleCommand(1, 0))
}
LightState.STROBE -> {
frontSublight.setTitle("OFF")
frontSublight.setOnClickListener(capsuleCommand(1, 0))
}
}
frontSublight.setImage(CarIcon.Builder(frontSublightIcon).build())
addItem(frontSublight.build())
}
return GridTemplate.Builder().apply {
setHeaderAction(Action.APP_ICON)
setTitle("Capsule connected")
setSingleList(gridListBuilder.build())
}.build()
}
private fun capsuleCommand(command: Int, value: Int): OnClickListener {
return OnClickListener {
eventBus.post(
BleManagerActions(
BleManagerActionTypes.TRANSMIT_COMMAND,
CapsuleCommand(command, value, pinCode ?: "")
)
)
}
}
}
Rerender is happening on events from EventBus. Few rerenders works good but after half minute I see exception which ruins my application on an Android Auto emulator and on a phone.
I have met information this error may happens because Android Auto interface is too difficult and it have many steps for some business logic but in my case I have only one Screen with easy GridTemplate without any menus.