summaryrefslogtreecommitdiffhomepage
path: root/android/src
diff options
context:
space:
mode:
authorJanito Vaqueiro Ferreira Filho <janito@mullvad.net>2021-05-03 19:47:23 +0000
committerJanito Vaqueiro Ferreira Filho <janito@mullvad.net>2021-05-14 20:39:01 +0000
commitb8e2c4ff3fa54b972af27f901155332c37b859ae (patch)
tree21fcf58a07854b069a949ab8ab2f51b48e3fd006 /android/src
parent27d3139864b004f0843cb0e6c3cefdd000d6016e (diff)
downloadmullvadvpn-b8e2c4ff3fa54b972af27f901155332c37b859ae.tar.xz
mullvadvpn-b8e2c4ff3fa54b972af27f901155332c37b859ae.zip
Create a new flow-based `ServiceConnection` class
Diffstat (limited to 'android/src')
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/ipc/ServiceConnection.kt65
1 files changed, 65 insertions, 0 deletions
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/ipc/ServiceConnection.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/ipc/ServiceConnection.kt
new file mode 100644
index 0000000000..6211f79dc7
--- /dev/null
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/ipc/ServiceConnection.kt
@@ -0,0 +1,65 @@
+package net.mullvad.mullvadvpn.ipc
+
+import android.content.Context
+import android.content.Intent
+import android.os.IBinder
+import android.os.Looper
+import android.os.Messenger
+import kotlin.reflect.KClass
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.InternalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
+import net.mullvad.mullvadvpn.service.MullvadVpnService
+import net.mullvad.mullvadvpn.util.DispatchingFlow
+import net.mullvad.mullvadvpn.util.bindServiceFlow
+import net.mullvad.mullvadvpn.util.dispatchTo
+
+@InternalCoroutinesApi
+class ServiceConnection(context: Context, scope: CoroutineScope) {
+ private val connection = MutableStateFlow<Messenger?>(null)
+ private val handler = HandlerFlow(Looper.getMainLooper(), Event::fromMessage)
+ private val listener = Messenger(handler)
+
+ private lateinit var requestSinks: StateFlow<Messenger?>
+
+ init {
+ val dispatcher = handler
+ .filterNotNull()
+ .dispatchTo {
+ requestSinks = subscribeToState(Event.ListenerReady::class, scope) { connection }
+ }
+
+ scope.launch { connect(context) }
+ scope.launch { dispatcher.collect() }
+ scope.launch { requestSinks.collect { connection.value = it } }
+ }
+
+ private suspend fun connect(context: Context) {
+ val intent = Intent(context, MullvadVpnService::class.java)
+
+ context.bindServiceFlow(intent).collect { binder ->
+ connection.value = null
+ binder?.let(::registerListener)
+ }
+ }
+
+ private fun registerListener(binder: IBinder) {
+ val request = Request.RegisterListener(listener)
+ val messenger = Messenger(binder)
+
+ messenger.send(request.message)
+ }
+
+ private fun <V : Any, D> DispatchingFlow<in V>.subscribeToState(
+ event: KClass<V>,
+ scope: CoroutineScope,
+ dataExtractor: suspend V.() -> D
+ ) = subscribe(event).map(dataExtractor).stateIn(scope, SharingStarted.Lazily, null)
+}