summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md1
-rw-r--r--android/src/main/AndroidManifest.xml3
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadTileService.kt60
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadVpnService.kt10
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/service/tunnelstate/Persistence.kt59
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/service/tunnelstate/TunnelStateListener.kt36
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/service/tunnelstate/TunnelStateUpdater.kt14
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/ServiceConnection.kt4
8 files changed, 53 insertions, 134 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8b29bbfcfb..5a7cbad3c7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -59,6 +59,7 @@ Line wrap the file at 100 chars. Th
- Fix request to connect from notification or quick-settings tile not connecting if VPN permission
isn't granted to the app. The app will now show the UI to ask for the permission and correctly
connect after it is granted.
+- Fix quick-settings tile sometimes showing the wrong tunnel state.
## [2021.3] - 2021-04-28
diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml
index 1515835794..66edb7dc33 100644
--- a/android/src/main/AndroidManifest.xml
+++ b/android/src/main/AndroidManifest.xml
@@ -68,7 +68,8 @@
<service android:name="net.mullvad.mullvadvpn.service.MullvadTileService"
android:label="@string/app_name"
android:icon="@drawable/small_logo_black"
- android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
+ android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
+ android:process=":mullvadvpn_tile">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE" />
</intent-filter>
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadTileService.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadTileService.kt
index dfd3213811..db9662f5d6 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadTileService.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadTileService.kt
@@ -1,31 +1,52 @@
package net.mullvad.mullvadvpn.service
+import android.content.ComponentName
import android.content.Intent
import android.graphics.drawable.Icon
import android.os.Build
+import android.os.IBinder
+import android.os.Messenger
import android.service.quicksettings.Tile
import android.service.quicksettings.TileService
import kotlin.properties.Delegates.observable
import net.mullvad.mullvadvpn.R
import net.mullvad.mullvadvpn.model.TunnelState
-import net.mullvad.mullvadvpn.service.tunnelstate.TunnelStateListener
+import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnection
import net.mullvad.talpid.tunnel.ActionAfterDisconnect
class MullvadTileService : TileService() {
+ private val serviceConnectionManager = object : android.content.ServiceConnection {
+ override fun onServiceConnected(className: ComponentName, binder: IBinder) {
+ serviceConnection = ServiceConnection(Messenger(binder))
+ }
+
+ override fun onServiceDisconnected(className: ComponentName) {
+ serviceConnection = null
+ }
+ }
+
+ private var serviceConnection by observable<ServiceConnection?>(
+ null
+ ) { _, oldConnection, newConnection ->
+ oldConnection?.onDestroy()
+
+ newConnection?.connectionProxy?.run {
+ onStateChange.subscribe(this@MullvadTileService, ::updateTunnelState)
+ }
+ }
+
private var secured by observable(false) { _, wasSecured, isSecured ->
if (wasSecured != isSecured) {
updateTileState()
}
}
- private lateinit var listener: TunnelStateListener
private lateinit var securedIcon: Icon
private lateinit var unsecuredIcon: Icon
override fun onCreate() {
super.onCreate()
- listener = TunnelStateListener(this)
securedIcon = Icon.createWithResource(this, R.drawable.small_logo_white)
unsecuredIcon = Icon.createWithResource(this, R.drawable.small_logo_black)
}
@@ -33,19 +54,9 @@ class MullvadTileService : TileService() {
override fun onStartListening() {
super.onStartListening()
- listener.onStateChange = { state ->
- secured = when (state) {
- is TunnelState.Disconnected -> false
- is TunnelState.Connecting -> true
- is TunnelState.Connected -> true
- is TunnelState.Disconnecting -> {
- state.actionAfterDisconnect == ActionAfterDisconnect.Reconnect
- }
- is TunnelState.Error -> {
- state.errorState.isBlocking
- }
- }
- }
+ val intent = Intent(this, MullvadVpnService::class.java)
+
+ bindService(intent, serviceConnectionManager, BIND_IMPORTANT)
updateTileState()
}
@@ -69,9 +80,22 @@ class MullvadTileService : TileService() {
}
override fun onStopListening() {
- listener.onStateChange = null
+ unbindService(serviceConnectionManager)
+ serviceConnection = null
- super.onStartListening()
+ super.onStopListening()
+ }
+
+ private fun updateTunnelState(tunnelState: TunnelState) {
+ secured = when (tunnelState) {
+ is TunnelState.Disconnected -> false
+ is TunnelState.Connecting -> true
+ is TunnelState.Connected -> true
+ is TunnelState.Disconnecting -> {
+ tunnelState.actionAfterDisconnect == ActionAfterDisconnect.Reconnect
+ }
+ is TunnelState.Error -> tunnelState.errorState.isBlocking
+ }
}
private fun updateTileState() {
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadVpnService.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadVpnService.kt
index a4685b6dd8..177db1d712 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadVpnService.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadVpnService.kt
@@ -15,7 +15,6 @@ import kotlinx.coroutines.launch
import net.mullvad.mullvadvpn.model.Settings
import net.mullvad.mullvadvpn.service.endpoint.ServiceEndpoint
import net.mullvad.mullvadvpn.service.notifications.AccountExpiryNotification
-import net.mullvad.mullvadvpn.service.tunnelstate.TunnelStateUpdater
import net.mullvad.mullvadvpn.ui.MainActivity
import net.mullvad.talpid.TalpidVpnService
@@ -55,7 +54,6 @@ class MullvadVpnService : TalpidVpnService() {
private lateinit var endpoint: ServiceEndpoint
private lateinit var keyguardManager: KeyguardManager
private lateinit var notificationManager: ForegroundNotificationManager
- private lateinit var tunnelStateUpdater: TunnelStateUpdater
private var pendingAction by observable<PendingAction?>(null) { _, _, _ ->
endpoint.settingsListener.settings?.let { settings ->
@@ -91,8 +89,6 @@ class MullvadVpnService : TalpidVpnService() {
connectionProxy.reconnect()
}
- tunnelStateUpdater = TunnelStateUpdater(this, connectionProxy)
-
notificationManager =
ForegroundNotificationManager(this, connectionProxy, keyguardManager).apply {
acknowledgeStartForegroundService()
@@ -112,6 +108,12 @@ class MullvadVpnService : TalpidVpnService() {
start()
}
+
+ // Remove any leftover tunnel state persistence data
+ getSharedPreferences("tunnel_state", MODE_PRIVATE)
+ .edit()
+ .clear()
+ .commit()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/service/tunnelstate/Persistence.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/service/tunnelstate/Persistence.kt
deleted file mode 100644
index 73b5c6de7e..0000000000
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/service/tunnelstate/Persistence.kt
+++ /dev/null
@@ -1,59 +0,0 @@
-package net.mullvad.mullvadvpn.service.tunnelstate
-
-import android.content.Context
-import android.content.SharedPreferences.OnSharedPreferenceChangeListener
-import java.net.InetSocketAddress
-import net.mullvad.mullvadvpn.model.TunnelState
-import net.mullvad.talpid.net.Endpoint
-import net.mullvad.talpid.net.TransportProtocol
-import net.mullvad.talpid.net.TunnelEndpoint
-
-private const val SHARED_PREFERENCES = "tunnel_state"
-private const val KEY_TUNNEL_STATE = "tunnel_state"
-
-// TODO: Maybe replace using this with actually persisting the endpoint information
-private val dummyTunnelEndpoint = TunnelEndpoint(
- Endpoint(
- InetSocketAddress.createUnresolved("dummy", 53),
- TransportProtocol.Tcp
- )
-)
-
-internal class Persistence(context: Context) {
- val sharedPreferences =
- context.getSharedPreferences(SHARED_PREFERENCES, Context.MODE_PRIVATE)
-
- var state
- get() = loadState()
- set(value) {
- persistState(value)
- }
-
- var listener: OnSharedPreferenceChangeListener? = null
- set(value) {
- if (value != field) {
- if (field != null) {
- sharedPreferences.unregisterOnSharedPreferenceChangeListener(field)
- }
-
- if (value != null) {
- sharedPreferences.registerOnSharedPreferenceChangeListener(value)
- }
-
- field = value
- }
- }
-
- private fun loadState(): TunnelState {
- val description = sharedPreferences.getString(KEY_TUNNEL_STATE, TunnelState.DISCONNECTED)!!
-
- return TunnelState.fromString(description, dummyTunnelEndpoint)
- }
-
- private fun persistState(state: TunnelState) {
- sharedPreferences
- .edit()
- .putString(KEY_TUNNEL_STATE, state.toString())
- .commit()
- }
-}
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/service/tunnelstate/TunnelStateListener.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/service/tunnelstate/TunnelStateListener.kt
deleted file mode 100644
index 7f7832d3e4..0000000000
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/service/tunnelstate/TunnelStateListener.kt
+++ /dev/null
@@ -1,36 +0,0 @@
-package net.mullvad.mullvadvpn.service.tunnelstate
-
-import android.content.Context
-import android.content.SharedPreferences
-import android.content.SharedPreferences.OnSharedPreferenceChangeListener
-import net.mullvad.mullvadvpn.model.TunnelState
-
-class TunnelStateListener(context: Context) {
- private val persistence = Persistence(context)
-
- private val listener = object : OnSharedPreferenceChangeListener {
- override fun onSharedPreferenceChanged(preferences: SharedPreferences, key: String) {
- state = persistence.state
- }
- }
-
- var state = persistence.state
- private set(value) {
- if (field != value) {
- field = value
- onStateChange?.invoke(value)
- }
- }
-
- var onStateChange: ((TunnelState) -> Unit)? = null
- set(value) {
- field = value
-
- if (value == null) {
- persistence.listener = null
- } else {
- persistence.listener = listener
- state = persistence.state
- }
- }
-}
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/service/tunnelstate/TunnelStateUpdater.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/service/tunnelstate/TunnelStateUpdater.kt
deleted file mode 100644
index 4d33ec4896..0000000000
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/service/tunnelstate/TunnelStateUpdater.kt
+++ /dev/null
@@ -1,14 +0,0 @@
-package net.mullvad.mullvadvpn.service.tunnelstate
-
-import android.content.Context
-import net.mullvad.mullvadvpn.service.endpoint.ConnectionProxy
-
-class TunnelStateUpdater(context: Context, private val connectionProxy: ConnectionProxy) {
- private val persistence = Persistence(context)
-
- init {
- connectionProxy.onStateChange.subscribe(this) { newState ->
- persistence.state = newState
- }
- }
-}
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/ServiceConnection.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/ServiceConnection.kt
index 655a26f2d8..861a54a561 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/ServiceConnection.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/ServiceConnection.kt
@@ -21,7 +21,7 @@ import org.koin.core.scope.get
@OptIn(KoinApiExtension::class)
class ServiceConnection(
connection: Messenger,
- onServiceReady: (ServiceConnection) -> Unit
+ onServiceReady: ((ServiceConnection) -> Unit)? = null
) : KoinScopeComponent {
private val dispatcher = DispatchingHandler(Looper.getMainLooper()) { message ->
Event.fromMessage(message)
@@ -48,7 +48,7 @@ class ServiceConnection(
init {
dispatcher.registerHandler(Event.ListenerReady::class) { _ ->
- onServiceReady(this@ServiceConnection)
+ onServiceReady?.invoke(this@ServiceConnection)
}
registerListener(connection)