Skip to content

Commit 6a21a1c

Browse files
authored
Add missing catch when interacting with network (#6264)
1 parent ae8bb51 commit 6a21a1c

File tree

19 files changed

+326
-78
lines changed

19 files changed

+326
-78
lines changed

app/src/full/kotlin/io/homeassistant/companion/android/matter/MatterManagerImpl.kt

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import io.homeassistant.companion.android.common.data.servers.ServerManager
1111
import io.homeassistant.companion.android.common.data.websocket.impl.entities.MatterCommissionResponse
1212
import io.homeassistant.companion.android.common.util.isAutomotive
1313
import javax.inject.Inject
14+
import kotlinx.coroutines.CancellationException
1415
import timber.log.Timber
1516

1617
class MatterManagerImpl @Inject constructor(
@@ -23,7 +24,14 @@ class MatterManagerImpl @Inject constructor(
2324

2425
override suspend fun coreSupportsCommissioning(serverId: Int): Boolean {
2526
if (!serverManager.isRegistered() || serverManager.getServer(serverId)?.user?.isAdmin != true) return false
26-
val config = serverManager.webSocketRepository(serverId).getConfig()
27+
val config = try {
28+
serverManager.webSocketRepository(serverId).getConfig()
29+
} catch (e: CancellationException) {
30+
throw e
31+
} catch (e: Exception) {
32+
Timber.e(e, "Failed to get config")
33+
null
34+
}
2735
return config != null && config.components.contains("matter")
2836
}
2937

@@ -54,6 +62,8 @@ class MatterManagerImpl @Inject constructor(
5462
override suspend fun commissionDevice(code: String, serverId: Int): MatterCommissionResponse? {
5563
return try {
5664
serverManager.webSocketRepository(serverId).commissionMatterDevice(code)
65+
} catch (e: CancellationException) {
66+
throw e
5767
} catch (e: Exception) {
5868
Timber.e(e, "Error while executing server commissioning request")
5969
null
@@ -63,6 +73,8 @@ class MatterManagerImpl @Inject constructor(
6373
override suspend fun commissionOnNetworkDevice(pin: Long, ip: String, serverId: Int): MatterCommissionResponse? {
6474
return try {
6575
serverManager.webSocketRepository(serverId).commissionMatterDeviceOnNetwork(pin, ip)
76+
} catch (e: CancellationException) {
77+
throw e
6678
} catch (e: Exception) {
6779
Timber.e(e, "Error while executing server commissioning request")
6880
null

app/src/full/kotlin/io/homeassistant/companion/android/settings/wear/SettingsWearRepository.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import io.homeassistant.companion.android.common.data.integration.impl.entities.
1111
import io.homeassistant.companion.android.common.data.servers.tryOnUrls
1212
import io.homeassistant.companion.android.common.util.FailFast
1313
import javax.inject.Inject
14+
import kotlinx.coroutines.CancellationException
1415
import kotlinx.serialization.json.JsonPrimitive
1516
import kotlinx.serialization.json.contentOrNull
1617
import okhttp3.HttpUrl
@@ -148,8 +149,10 @@ class SettingsWearRepository @Inject constructor(
148149
it.lastUpdated,
149150
)
150151
}
152+
} catch (e: CancellationException) {
153+
throw e
151154
} catch (e: IntegrationException) {
152-
Timber.e(e, "Fail to get entities")
155+
Timber.e(e, "Failed to get entities")
153156
emptyList()
154157
}
155158
}

app/src/main/kotlin/io/homeassistant/companion/android/assist/AssistViewModel.kt

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import io.homeassistant.companion.android.common.data.websocket.impl.entities.As
1818
import io.homeassistant.companion.android.common.util.AudioRecorder
1919
import io.homeassistant.companion.android.common.util.AudioUrlPlayer
2020
import javax.inject.Inject
21+
import kotlinx.coroutines.CancellationException
2122
import kotlinx.coroutines.launch
2223
import timber.log.Timber
2324

@@ -168,7 +169,15 @@ class AssistViewModel @Inject constructor(
168169
serverIds.forEach { serverId ->
169170
viewModelScope.launch {
170171
val server = serverManager.getServer(serverId)
171-
val serverPipelines = serverManager.webSocketRepository(serverId).getAssistPipelines()
172+
val serverPipelines = try {
173+
serverManager.webSocketRepository(serverId).getAssistPipelines()
174+
} catch (e: CancellationException) {
175+
throw e
176+
} catch (e: Exception) {
177+
Timber.e(e, "Failed to load assist pipelines")
178+
null
179+
}
180+
172181
allPipelines[serverId] = serverPipelines?.pipelines ?: emptyList()
173182
_pipelines.addAll(
174183
serverPipelines?.pipelines.orEmpty().map {
@@ -197,15 +206,28 @@ class AssistViewModel @Inject constructor(
197206
private suspend fun setPipeline(id: String?) {
198207
selectedPipeline =
199208
allPipelines[selectedServerId]?.firstOrNull { it.id == id }
200-
?: serverManager.webSocketRepository(selectedServerId).getAssistPipeline(id)
209+
?: try {
210+
serverManager.webSocketRepository(selectedServerId).getAssistPipeline(id)
211+
} catch (e: CancellationException) {
212+
throw e
213+
} catch (e: Exception) {
214+
Timber.e(e, "Failed to get assist pipeline")
215+
null
216+
}
201217
selectedPipeline?.let {
202218
currentPipeline = AssistUiPipeline(
203219
serverId = selectedServerId,
204220
serverName = serverManager.getServer(selectedServerId)?.friendlyName ?: "",
205221
id = it.id,
206222
name = it.name,
207223
)
208-
serverManager.integrationRepository(selectedServerId).setLastUsedPipeline(it.id, it.sttEngine != null)
224+
try {
225+
serverManager.integrationRepository(selectedServerId).setLastUsedPipeline(it.id, it.sttEngine != null)
226+
} catch (e: CancellationException) {
227+
throw e
228+
} catch (e: Exception) {
229+
Timber.e(e, "Failed to set last used pipeline")
230+
}
209231

210232
_conversation.clear()
211233
_conversation.add(startMessage)

app/src/main/kotlin/io/homeassistant/companion/android/settings/controls/ManageControlsViewModel.kt

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@ import io.homeassistant.companion.android.controls.HaControlsPanelActivity
2222
import io.homeassistant.companion.android.controls.HaControlsProviderService
2323
import io.homeassistant.companion.android.database.server.Server
2424
import javax.inject.Inject
25+
import kotlinx.coroutines.CancellationException
2526
import kotlinx.coroutines.async
2627
import kotlinx.coroutines.awaitAll
2728
import kotlinx.coroutines.launch
29+
import timber.log.Timber
2830

2931
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
3032
@HiltViewModel
@@ -85,13 +87,20 @@ class ManageControlsViewModel @Inject constructor(
8587

8688
servers.map { server ->
8789
async {
88-
val entities = serverManager.integrationRepository(server.id).getEntities()
89-
?.filter { it.domain in HaControlsProviderService.getSupportedDomains() }
90-
?.sortedWith(
91-
compareBy(String.CASE_INSENSITIVE_ORDER) {
92-
it.attributes["friendly_name"].toString()
93-
},
94-
)
90+
val entities = try {
91+
serverManager.integrationRepository(server.id).getEntities()
92+
?.filter { it.domain in HaControlsProviderService.getSupportedDomains() }
93+
?.sortedWith(
94+
compareBy(String.CASE_INSENSITIVE_ORDER) {
95+
it.attributes["friendly_name"].toString()
96+
},
97+
)
98+
} catch (e: CancellationException) {
99+
throw e
100+
} catch (e: Exception) {
101+
Timber.e(e, "Failed to get entities")
102+
null
103+
}
95104
if (entities != null) {
96105
entitiesList[server.id] = entities
97106
}

app/src/main/kotlin/io/homeassistant/companion/android/vehicle/EntityGridVehicleScreen.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import io.homeassistant.companion.android.util.vehicle.getDomainList
4242
import io.homeassistant.companion.android.util.vehicle.getDomainsGridItem
4343
import io.homeassistant.companion.android.util.vehicle.getHeaderBuilder
4444
import io.homeassistant.companion.android.util.vehicle.getNavigationGridItem
45+
import kotlinx.coroutines.CancellationException
4546
import kotlinx.coroutines.flow.Flow
4647
import kotlinx.coroutines.flow.StateFlow
4748
import kotlinx.coroutines.launch
@@ -195,7 +196,13 @@ class EntityGridVehicleScreen(
195196

196197
in SUPPORTED_DOMAINS -> {
197198
lifecycleScope.launch {
198-
entity.onPressed(integrationRepositoryProvider())
199+
try {
200+
entity.onPressed(integrationRepositoryProvider())
201+
} catch (e: CancellationException) {
202+
throw e
203+
} catch (e: Exception) {
204+
Timber.e(e, "Failed to handle entity onPressed")
205+
}
199206
}
200207
}
201208

app/src/main/kotlin/io/homeassistant/companion/android/vehicle/HaCarAppService.kt

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import io.homeassistant.companion.android.common.data.prefs.PrefsRepository
2020
import io.homeassistant.companion.android.common.data.servers.ServerManager
2121
import java.util.Collections
2222
import javax.inject.Inject
23+
import kotlinx.coroutines.CancellationException
2324
import kotlinx.coroutines.CoroutineScope
2425
import kotlinx.coroutines.Job
2526
import kotlinx.coroutines.flow.MutableStateFlow
@@ -136,17 +137,30 @@ class HaCarAppService : CarAppService() {
136137
serverId.value = id
137138
val entities: MutableMap<String, Entity>? =
138139
if (serverManager.getServer(id) != null) {
139-
serverManager.integrationRepository(id).getEntities()
140-
?.associate { it.entityId to it }
141-
?.toMutableMap()
140+
try {
141+
serverManager.integrationRepository(id).getEntities()
142+
?.associate { it.entityId to it }
143+
?.toMutableMap()
144+
} catch (e: CancellationException) {
145+
throw e
146+
} catch (e: Exception) {
147+
Timber.e(e, "Failed to get entities")
148+
null
149+
}
142150
} else {
143151
null
144152
}
145153
if (entities != null) {
146154
allEntities.emit(entities.toImmutableMap())
147-
serverManager.integrationRepository(id).getEntityUpdates()?.collect { entity ->
148-
entities[entity.entityId] = entity
149-
allEntities.emit(entities.toImmutableMap())
155+
try {
156+
serverManager.integrationRepository(id).getEntityUpdates()?.collect { entity ->
157+
entities[entity.entityId] = entity
158+
allEntities.emit(entities.toImmutableMap())
159+
}
160+
} catch (e: CancellationException) {
161+
throw e
162+
} catch (e: Exception) {
163+
Timber.e(e, "Failed to get entity updates")
150164
}
151165
} else {
152166
Timber.w("No entities found?")

app/src/main/kotlin/io/homeassistant/companion/android/vehicle/MainVehicleScreen.kt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,14 @@ import io.homeassistant.companion.android.util.vehicle.getDomainList
3232
import io.homeassistant.companion.android.util.vehicle.getHeaderBuilder
3333
import io.homeassistant.companion.android.util.vehicle.getNavigationGridItem
3434
import io.homeassistant.companion.android.util.vehicle.nativeModeAction
35+
import kotlinx.coroutines.CancellationException
3536
import kotlinx.coroutines.Job
3637
import kotlinx.coroutines.delay
3738
import kotlinx.coroutines.flow.Flow
3839
import kotlinx.coroutines.flow.StateFlow
3940
import kotlinx.coroutines.flow.flowOf
4041
import kotlinx.coroutines.launch
42+
import timber.log.Timber
4143

4244
@RequiresApi(Build.VERSION_CODES.O)
4345
class MainVehicleScreen(
@@ -89,7 +91,14 @@ class MainVehicleScreen(
8991
domainsAdded = false
9092
domainsAddedFor = server
9193
invalidate() // Show loading state
92-
entityRegistry = serverManager.webSocketRepository(server).getEntityRegistry()
94+
entityRegistry = try {
95+
serverManager.webSocketRepository(server).getEntityRegistry()
96+
} catch (e: CancellationException) {
97+
throw e
98+
} catch (e: Exception) {
99+
Timber.e(e, "Failed to get entity registry")
100+
null
101+
}
93102
}
94103

95104
if (domainsJob?.isActive == true) domainsJob?.cancel()

app/src/main/kotlin/io/homeassistant/companion/android/webview/addto/EntityAddToHandler.kt

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@ import io.homeassistant.companion.android.widgets.entity.EntityWidgetConfigureAc
2020
import io.homeassistant.companion.android.widgets.mediaplayer.MediaPlayerControlsWidgetConfigureActivity
2121
import io.homeassistant.companion.android.widgets.todo.TodoWidgetConfigureActivity
2222
import javax.inject.Inject
23+
import kotlinx.coroutines.CancellationException
2324
import kotlinx.coroutines.Dispatchers
2425
import kotlinx.coroutines.withContext
26+
import timber.log.Timber
2527

2628
/**
2729
* Handles the "Add To" functionality for Home Assistant entities, allowing users to add entities
@@ -71,29 +73,35 @@ class EntityAddToHandler @Inject constructor(
7173
return withContext(Dispatchers.Default) {
7274
val actions = mutableListOf<EntityAddToAction>()
7375
serverManager.getServer()?.let { server ->
74-
serverManager.integrationRepository(server.id).getEntity(entityId)
75-
?.let { entity ->
76-
if (!isAutomotive && !isQuest) {
77-
actions.add(EntityAddToAction.EntityWidget)
76+
try {
77+
serverManager.integrationRepository(server.id).getEntity(entityId)
78+
} catch (e: CancellationException) {
79+
throw e
80+
} catch (e: Exception) {
81+
Timber.e(e, "Failed to get entity for id $entityId")
82+
null
83+
}?.let { entity ->
84+
if (!isAutomotive && !isQuest) {
85+
actions.add(EntityAddToAction.EntityWidget)
7886

79-
if (entity.domain == MEDIA_PLAYER_DOMAIN) {
80-
actions.add(EntityAddToAction.MediaPlayerWidget)
81-
}
82-
83-
if (entity.domain == TODO_DOMAIN) {
84-
actions.add(EntityAddToAction.TodoWidget)
85-
}
87+
if (entity.domain == MEDIA_PLAYER_DOMAIN) {
88+
actions.add(EntityAddToAction.MediaPlayerWidget)
89+
}
8690

87-
if (entity.domain == CAMERA_DOMAIN || entity.domain == IMAGE_DOMAIN) {
88-
actions.add(EntityAddToAction.CameraWidget)
89-
}
91+
if (entity.domain == TODO_DOMAIN) {
92+
actions.add(EntityAddToAction.TodoWidget)
9093
}
9194

92-
if (isVehicleDomain(entity) && (isFullFlavor || isAutomotive)) {
93-
// We could check if it already exist but the action won't do anything so we can keep it
94-
actions.add(EntityAddToAction.AndroidAutoFavorite)
95+
if (entity.domain == CAMERA_DOMAIN || entity.domain == IMAGE_DOMAIN) {
96+
actions.add(EntityAddToAction.CameraWidget)
9597
}
9698
}
99+
100+
if (isVehicleDomain(entity) && (isFullFlavor || isAutomotive)) {
101+
// We could check if it already exist but the action won't do anything so we can keep it
102+
actions.add(EntityAddToAction.AndroidAutoFavorite)
103+
}
104+
}
97105
}
98106
actions
99107
}

app/src/main/kotlin/io/homeassistant/companion/android/widgets/assist/AssistShortcutViewModel.kt

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ import io.homeassistant.companion.android.common.data.servers.ServerManager
1212
import io.homeassistant.companion.android.common.data.websocket.impl.entities.AssistPipelineListResponse
1313
import io.homeassistant.companion.android.database.server.Server
1414
import javax.inject.Inject
15+
import kotlinx.coroutines.CancellationException
1516
import kotlinx.coroutines.launch
17+
import timber.log.Timber
1618

1719
@HiltViewModel
1820
class AssistShortcutViewModel @Inject constructor(val serverManager: ServerManager, application: Application) :
@@ -55,11 +57,27 @@ class AssistShortcutViewModel @Inject constructor(val serverManager: ServerManag
5557
supported = null
5658
pipelines = null
5759

60+
val config = try {
61+
serverManager.webSocketRepository(serverId).getConfig()
62+
} catch (e: CancellationException) {
63+
throw e
64+
} catch (e: Exception) {
65+
Timber.e(e, "Failed to get config")
66+
null
67+
}
68+
5869
// Update data
5970
supported = serverManager.getServer(serverId)?.version?.isAtLeast(2023, 5) == true &&
60-
serverManager.webSocketRepository(serverId).getConfig()?.components?.contains("assist_pipeline") == true
71+
config?.components?.contains("assist_pipeline") == true
6172
if (supported == true) {
62-
pipelines = serverManager.webSocketRepository(serverId).getAssistPipelines()
73+
pipelines = try {
74+
serverManager.webSocketRepository(serverId).getAssistPipelines()
75+
} catch (e: CancellationException) {
76+
throw e
77+
} catch (e: Exception) {
78+
Timber.e(e, "Failed to get assist pipelines")
79+
null
80+
}
6381
}
6482
}
6583
}

app/src/main/kotlin/io/homeassistant/companion/android/widgets/entity/EntityWidget.kt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import io.homeassistant.companion.android.database.widget.WidgetBackgroundType
2626
import io.homeassistant.companion.android.database.widget.WidgetTapAction
2727
import io.homeassistant.companion.android.util.getAttribute
2828
import io.homeassistant.companion.android.widgets.BaseWidgetProvider
29+
import kotlinx.coroutines.CancellationException
2930
import kotlinx.coroutines.launch
3031
import timber.log.Timber
3132

@@ -168,7 +169,14 @@ class EntityWidget : BaseWidgetProvider<StaticWidgetEntity, StaticWidgetDao>() {
168169
entity?.canSupportPrecision() == true &&
169170
serverManager.getServer(serverId)?.version?.isAtLeast(2023, 3) == true
170171
) {
171-
serverManager.webSocketRepository(serverId).getEntityRegistryFor(entity.entityId)?.options
172+
try {
173+
serverManager.webSocketRepository(serverId).getEntityRegistryFor(entity.entityId)?.options
174+
} catch (e: CancellationException) {
175+
throw e
176+
} catch (e: Exception) {
177+
Timber.e(e, "Failed to get options")
178+
null
179+
}
172180
} else {
173181
null
174182
}

0 commit comments

Comments
 (0)