diff --git a/composeApp/src/androidMain/AndroidManifest.xml b/composeApp/src/androidMain/AndroidManifest.xml
index 112aadd0..441fbe74 100644
--- a/composeApp/src/androidMain/AndroidManifest.xml
+++ b/composeApp/src/androidMain/AndroidManifest.xml
@@ -1,6 +1,8 @@
+
+
-
\ No newline at end of file
+
diff --git a/composeApp/src/androidMain/kotlin/org/ooni/engine/AndroidNetworkTypeFinder.kt b/composeApp/src/androidMain/kotlin/org/ooni/engine/AndroidNetworkTypeFinder.kt
new file mode 100644
index 00000000..c1b71d68
--- /dev/null
+++ b/composeApp/src/androidMain/kotlin/org/ooni/engine/AndroidNetworkTypeFinder.kt
@@ -0,0 +1,24 @@
+package org.ooni.engine
+
+import android.net.ConnectivityManager
+import android.net.NetworkCapabilities
+import org.ooni.engine.models.NetworkType
+
+class AndroidNetworkTypeFinder(
+ private val connectivityManager: ConnectivityManager?,
+) : NetworkTypeFinder {
+ override fun invoke(): NetworkType {
+ if (connectivityManager == null) return NetworkType.NoInternet
+
+ val capabilities =
+ connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)
+ ?: return NetworkType.NoInternet
+
+ return when {
+ capabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN) -> NetworkType.VPN
+ capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> NetworkType.Wifi
+ capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> NetworkType.Mobile
+ else -> NetworkType.NoInternet
+ }
+ }
+}
diff --git a/composeApp/src/androidMain/kotlin/org/ooni/probe/AndroidApplication.kt b/composeApp/src/androidMain/kotlin/org/ooni/probe/AndroidApplication.kt
index 476232df..a1fe912d 100644
--- a/composeApp/src/androidMain/kotlin/org/ooni/probe/AndroidApplication.kt
+++ b/composeApp/src/androidMain/kotlin/org/ooni/probe/AndroidApplication.kt
@@ -1,9 +1,11 @@
package org.ooni.probe
import android.app.Application
+import android.net.ConnectivityManager
import android.os.Build
import app.cash.sqldelight.db.SqlDriver
import app.cash.sqldelight.driver.android.AndroidSqliteDriver
+import org.ooni.engine.AndroidNetworkTypeFinder
import org.ooni.engine.AndroidOonimkallBridge
import org.ooni.probe.di.Dependencies
import org.ooni.probe.shared.Platform
@@ -21,6 +23,8 @@ class AndroidApplication : Application() {
baseFileDir = filesDir.absolutePath,
cacheDir = cacheDir.absolutePath,
databaseDriverFactory = ::buildDatabaseDriver,
+ networkTypeFinder =
+ AndroidNetworkTypeFinder(getSystemService(ConnectivityManager::class.java)),
)
}
diff --git a/composeApp/src/commonMain/kotlin/org/ooni/engine/Engine.kt b/composeApp/src/commonMain/kotlin/org/ooni/engine/Engine.kt
index 41df3e2d..3cac9418 100644
--- a/composeApp/src/commonMain/kotlin/org/ooni/engine/Engine.kt
+++ b/composeApp/src/commonMain/kotlin/org/ooni/engine/Engine.kt
@@ -37,12 +37,19 @@ class Engine(
channelFlow {
val taskSettings = buildTaskSettings(name, inputs, taskOrigin)
val settingsSerialized = json.encodeToString(taskSettings)
- val task = bridge.startTask(settingsSerialized)
- while (!task.isDone()) {
- val eventJson = task.waitForNextEvent()
- val taskEventResult = json.decodeFromString(eventJson)
- taskEventMapper(taskEventResult)?.let { send(it) }
+ var task: OonimkallBridge.Task? = null
+ try {
+ task = bridge.startTask(settingsSerialized)
+
+ while (!task.isDone()) {
+ val eventJson = task.waitForNextEvent()
+ val taskEventResult = json.decodeFromString(eventJson)
+ taskEventMapper(taskEventResult)?.let { send(it) }
+ }
+ } catch (e: Exception) {
+ task?.interrupt()
+ throw MkException(e)
}
invokeOnClose {
@@ -57,8 +64,12 @@ class Engine(
taskOrigin: TaskOrigin = TaskOrigin.OoniRun,
): SubmitMeasurementResults =
withContext(backgroundDispatcher) {
- val sessionConfig = buildSessionConfig(taskOrigin)
- session(sessionConfig).submitMeasurement(measurement)
+ try {
+ val sessionConfig = buildSessionConfig(taskOrigin)
+ session(sessionConfig).submitMeasurement(measurement)
+ } catch (e: Exception) {
+ throw MkException(e)
+ }
}
suspend fun checkIn(
@@ -66,18 +77,22 @@ class Engine(
taskOrigin: TaskOrigin,
): OonimkallBridge.CheckInResults =
withContext(backgroundDispatcher) {
- val sessionConfig = buildSessionConfig(taskOrigin)
- session(sessionConfig).checkIn(
- OonimkallBridge.CheckInConfig(
- charging = true,
- onWiFi = true,
- platform = platformInfo.platform.value,
- runType = taskOrigin.value,
- softwareName = sessionConfig.softwareName,
- softwareVersion = sessionConfig.softwareVersion,
- webConnectivityCategories = categories,
- ),
- )
+ try {
+ val sessionConfig = buildSessionConfig(taskOrigin)
+ session(sessionConfig).checkIn(
+ OonimkallBridge.CheckInConfig(
+ charging = true,
+ onWiFi = true,
+ platform = platformInfo.platform.value,
+ runType = taskOrigin.value,
+ softwareName = sessionConfig.softwareName,
+ softwareVersion = sessionConfig.softwareVersion,
+ webConnectivityCategories = categories,
+ ),
+ )
+ } catch (e: Exception) {
+ throw MkException(e)
+ }
}
suspend fun httpDo(
@@ -86,13 +101,17 @@ class Engine(
taskOrigin: TaskOrigin = TaskOrigin.OoniRun,
): String? =
withContext(backgroundDispatcher) {
- session(buildSessionConfig(taskOrigin))
- .httpDo(
- OonimkallBridge.HTTPRequest(
- method = method,
- url = url,
- ),
- ).body
+ try {
+ session(buildSessionConfig(taskOrigin))
+ .httpDo(
+ OonimkallBridge.HTTPRequest(
+ method = method,
+ url = url,
+ ),
+ ).body
+ } catch (e: Exception) {
+ throw MkException(e)
+ }
}
private fun session(sessionConfig: OonimkallBridge.SessionConfig): OonimkallBridge.Session = bridge.newSession(sessionConfig)
@@ -179,4 +198,6 @@ class Engine(
}
}
}
+
+ class MkException(e: Exception) : Exception(e)
}
diff --git a/composeApp/src/commonMain/kotlin/org/ooni/probe/di/Dependencies.kt b/composeApp/src/commonMain/kotlin/org/ooni/probe/di/Dependencies.kt
index c55c8fdd..9f2ba9ef 100644
--- a/composeApp/src/commonMain/kotlin/org/ooni/probe/di/Dependencies.kt
+++ b/composeApp/src/commonMain/kotlin/org/ooni/probe/di/Dependencies.kt
@@ -9,7 +9,6 @@ import org.ooni.engine.Engine
import org.ooni.engine.NetworkTypeFinder
import org.ooni.engine.OonimkallBridge
import org.ooni.engine.TaskEventMapper
-import org.ooni.engine.models.NetworkType
import org.ooni.probe.Database
import org.ooni.probe.data.models.TestResult
import org.ooni.probe.shared.PlatformInfo
@@ -23,8 +22,9 @@ class Dependencies(
private val baseFileDir: String,
private val cacheDir: String,
private val databaseDriverFactory: () -> SqlDriver,
+ private val networkTypeFinder: NetworkTypeFinder,
) {
- // Commong
+ // Common
private val backgroundDispatcher = Dispatchers.IO
@@ -35,8 +35,6 @@ class Dependencies(
// Engine
- private val networkTypeFinder by lazy { NetworkTypeFinder { NetworkType.Unknown("") } } // TODO
-
private val taskEventMapper by lazy { TaskEventMapper(networkTypeFinder, json) }
private val engine by lazy {
diff --git a/composeApp/src/commonMain/kotlin/org/ooni/probe/ui/dashboard/DashboardViewModel.kt b/composeApp/src/commonMain/kotlin/org/ooni/probe/ui/dashboard/DashboardViewModel.kt
index 74f75207..1a89bb22 100644
--- a/composeApp/src/commonMain/kotlin/org/ooni/probe/ui/dashboard/DashboardViewModel.kt
+++ b/composeApp/src/commonMain/kotlin/org/ooni/probe/ui/dashboard/DashboardViewModel.kt
@@ -6,6 +6,7 @@ import co.touchlab.kermit.Logger
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.launchIn
@@ -33,18 +34,27 @@ class DashboardViewModel(
_state.value = _state.value.copy(isRunning = true)
- val response =
- engine.httpDo(
- method = "GET",
- url = "https://api.dev.ooni.io/api/v2/oonirun/links/10426",
- )
- response?.let { Logger.d(it) }
+ try {
+ val response =
+ engine.httpDo(
+ method = "GET",
+ url = "https://api.dev.ooni.io/api/v2/oonirun/links/10426",
+ )
+ response?.let { Logger.d(it) }
+ } catch (e: Engine.MkException) {
+ Logger.e("httpDo failed", e)
+ }
val checkInResults =
- engine.checkIn(
- categories = listOf("NEWS"),
- taskOrigin = TaskOrigin.OoniRun,
- )
+ try {
+ engine.checkIn(
+ categories = listOf("NEWS"),
+ taskOrigin = TaskOrigin.OoniRun,
+ )
+ } catch (e: Engine.MkException) {
+ Logger.e("checkIn failed", e)
+ return@flatMapLatest emptyFlow()
+ }
engine
.startTask(
@@ -62,6 +72,9 @@ class DashboardViewModel(
}.onCompletion {
_state.update { it.copy(isRunning = false) }
}
+ .catch {
+ Logger.e("startTask failed", it)
+ }
}
}
}.launchIn(viewModelScope)
diff --git a/composeApp/src/iosMain/kotlin/org/ooni/probe/SetupDependencies.kt b/composeApp/src/iosMain/kotlin/org/ooni/probe/SetupDependencies.kt
index acde2781..2d9e8476 100644
--- a/composeApp/src/iosMain/kotlin/org/ooni/probe/SetupDependencies.kt
+++ b/composeApp/src/iosMain/kotlin/org/ooni/probe/SetupDependencies.kt
@@ -2,6 +2,7 @@ package org.ooni.probe
import app.cash.sqldelight.driver.native.NativeSqliteDriver
import org.ooni.engine.OonimkallBridge
+import org.ooni.engine.models.NetworkType
import org.ooni.probe.di.Dependencies
import org.ooni.probe.shared.Platform
import org.ooni.probe.shared.PlatformInfo
@@ -23,6 +24,8 @@ fun setupDependencies(bridge: OonimkallBridge) =
baseFileDir = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, true).first().toString(),
cacheDir = NSTemporaryDirectory(),
databaseDriverFactory = ::buildDatabaseDriver,
+ // TODO
+ networkTypeFinder = { NetworkType.Unknown("") },
)
private val platformInfo get() =