summaryrefslogtreecommitdiffhomepage
path: root/android
diff options
context:
space:
mode:
authorJanito Vaqueiro Ferreira Filho <janito@mullvad.net>2020-07-20 12:36:11 -0300
committerJanito Vaqueiro Ferreira Filho <janito@mullvad.net>2020-07-20 12:36:11 -0300
commitf9c55e39194a22f78916ff0d0734eb9d79c4f388 (patch)
treee718af03694f87666ccf0a7e8cfbc66b081a8117 /android
parenta358f925e83ebbdd838aa6a2162c48fe15a9d025 (diff)
parentb02e868411d3c112a05d3ea09691c308e6bf5131 (diff)
downloadmullvadvpn-f9c55e39194a22f78916ff0d0734eb9d79c4f388.tar.xz
mullvadvpn-f9c55e39194a22f78916ff0d0734eb9d79c4f388.zip
Merge branch 'android-split-tunnelling'
Diffstat (limited to 'android')
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/applist/AppListAdapter.kt8
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/applist/AppListItemHolder.kt17
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadVpnService.kt16
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/service/ServiceInstance.kt3
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/service/SplitTunnelling.kt33
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/ui/ServiceConnection.kt1
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/ui/ServiceDependentFragment.kt4
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/ui/SplitTunnellingFragment.kt4
-rw-r--r--android/src/main/kotlin/net/mullvad/talpid/TalpidVpnService.kt18
9 files changed, 98 insertions, 6 deletions
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/applist/AppListAdapter.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/applist/AppListAdapter.kt
index fe9c223194..820ef12fb2 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/applist/AppListAdapter.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/applist/AppListAdapter.kt
@@ -6,9 +6,13 @@ import android.view.LayoutInflater
import android.view.ViewGroup
import kotlin.properties.Delegates.observable
import net.mullvad.mullvadvpn.R
+import net.mullvad.mullvadvpn.service.SplitTunnelling
import net.mullvad.mullvadvpn.util.JobTracker
-class AppListAdapter(context: Context) : Adapter<AppListItemHolder>() {
+class AppListAdapter(
+ context: Context,
+ private val splitTunnelling: SplitTunnelling
+) : Adapter<AppListItemHolder>() {
private val appList = ArrayList<AppInfo>()
private val jobTracker = JobTracker()
private val packageManager = context.packageManager
@@ -41,7 +45,7 @@ class AppListAdapter(context: Context) : Adapter<AppListItemHolder>() {
val inflater = LayoutInflater.from(parentView.context)
val view = inflater.inflate(R.layout.app_list_item, parentView, false)
- return AppListItemHolder(packageManager, jobTracker, view)
+ return AppListItemHolder(splitTunnelling, packageManager, jobTracker, view)
}
override fun onBindViewHolder(holder: AppListItemHolder, position: Int) {
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/applist/AppListItemHolder.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/applist/AppListItemHolder.kt
index 04bdd55686..b2d726f25e 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/applist/AppListItemHolder.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/applist/AppListItemHolder.kt
@@ -8,10 +8,12 @@ import android.widget.ImageView
import android.widget.TextView
import kotlin.properties.Delegates.observable
import net.mullvad.mullvadvpn.R
+import net.mullvad.mullvadvpn.service.SplitTunnelling
import net.mullvad.mullvadvpn.ui.CellSwitch
import net.mullvad.mullvadvpn.util.JobTracker
class AppListItemHolder(
+ private val splitTunnelling: SplitTunnelling,
private val packageManager: PackageManager,
private val jobTracker: JobTracker,
view: View
@@ -33,6 +35,12 @@ class AppListItemHolder(
hideIcon()
loadIcon(info)
}
+
+ if (splitTunnelling.isAppExcluded(info.info.packageName)) {
+ excluded.forcefullySetState(CellSwitch.State.ON)
+ } else {
+ excluded.forcefullySetState(CellSwitch.State.OFF)
+ }
} else {
name.text = ""
hideIcon()
@@ -43,6 +51,15 @@ class AppListItemHolder(
view.setOnClickListener {
excluded.toggle()
}
+
+ excluded.listener = { state ->
+ appInfo?.info?.packageName?.let { app ->
+ when (state) {
+ CellSwitch.State.ON -> splitTunnelling.excludeApp(app)
+ CellSwitch.State.OFF -> splitTunnelling.includeApp(app)
+ }
+ }
+ }
}
private fun hideIcon() {
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 edc0cfd21b..317ca72eed 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadVpnService.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadVpnService.kt
@@ -242,7 +242,21 @@ class MullvadVpnService : TalpidVpnService() {
pendingAction = null
}
- instance = ServiceInstance(daemon, connectionProxy, connectivityListener, settingsListener)
+ val splitTunnelling = SplitTunnelling().apply {
+ onChange = { excludedApps ->
+ disallowedApps = excludedApps
+ markTunAsStale()
+ connectionProxy.reconnect()
+ }
+ }
+
+ instance = ServiceInstance(
+ daemon,
+ connectionProxy,
+ connectivityListener,
+ settingsListener,
+ splitTunnelling
+ )
}
private fun stop() {
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/service/ServiceInstance.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/service/ServiceInstance.kt
index 273955bcef..ecca6b12f0 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/service/ServiceInstance.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/service/ServiceInstance.kt
@@ -6,7 +6,8 @@ class ServiceInstance(
val daemon: MullvadDaemon,
val connectionProxy: ConnectionProxy,
val connectivityListener: ConnectivityListener,
- val settingsListener: SettingsListener
+ val settingsListener: SettingsListener,
+ val splitTunnelling: SplitTunnelling
) {
val accountCache = AccountCache(daemon, settingsListener)
val keyStatusListener = KeyStatusListener(daemon)
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/service/SplitTunnelling.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/service/SplitTunnelling.kt
new file mode 100644
index 0000000000..0722c2fc56
--- /dev/null
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/service/SplitTunnelling.kt
@@ -0,0 +1,33 @@
+package net.mullvad.mullvadvpn.service
+
+import kotlin.properties.Delegates.observable
+
+class SplitTunnelling {
+ private val excludedApps = HashSet<String>()
+
+ val excludedAppList
+ get() = if (enabled) {
+ excludedApps.toList()
+ } else {
+ emptyList()
+ }
+
+ var enabled by observable(false) { _, _, _ -> update() }
+ var onChange: ((List<String>) -> Unit)? = null
+
+ fun isAppExcluded(appPackageName: String) = excludedApps.contains(appPackageName)
+
+ fun excludeApp(appPackageName: String) {
+ excludedApps.add(appPackageName)
+ update()
+ }
+
+ fun includeApp(appPackageName: String) {
+ excludedApps.remove(appPackageName)
+ update()
+ }
+
+ private fun update() {
+ onChange?.invoke(excludedAppList)
+ }
+}
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/ServiceConnection.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/ServiceConnection.kt
index b2717fb1ec..43ecb29ae2 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/ServiceConnection.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/ServiceConnection.kt
@@ -12,6 +12,7 @@ class ServiceConnection(private val service: ServiceInstance, val mainActivity:
val keyStatusListener = service.keyStatusListener
val locationInfoCache = service.locationInfoCache
val settingsListener = service.settingsListener
+ val splitTunnelling = service.splitTunnelling
val appVersionInfoCache = AppVersionInfoCache(mainActivity, daemon, settingsListener)
var relayListListener = RelayListListener(daemon, settingsListener)
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/ServiceDependentFragment.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/ServiceDependentFragment.kt
index 03dbd53f0d..29577058b8 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/ServiceDependentFragment.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/ServiceDependentFragment.kt
@@ -13,6 +13,7 @@ import net.mullvad.mullvadvpn.service.KeyStatusListener
import net.mullvad.mullvadvpn.service.LocationInfoCache
import net.mullvad.mullvadvpn.service.MullvadDaemon
import net.mullvad.mullvadvpn.service.SettingsListener
+import net.mullvad.mullvadvpn.service.SplitTunnelling
import net.mullvad.talpid.ConnectivityListener
abstract class ServiceDependentFragment(val onNoService: OnNoService) : ServiceAwareFragment() {
@@ -58,6 +59,8 @@ abstract class ServiceDependentFragment(val onNoService: OnNoService) : ServiceA
lateinit var settingsListener: SettingsListener
private set
+ lateinit var splitTunnelling: SplitTunnelling
+
override fun onNewServiceConnection(serviceConnection: ServiceConnection) {
// This method is always either called first or after an `onNoServiceConnection`, so the
// initialization of the fields doesn't have to be synchronized
@@ -70,6 +73,7 @@ abstract class ServiceDependentFragment(val onNoService: OnNoService) : ServiceA
locationInfoCache = serviceConnection.locationInfoCache
relayListListener = serviceConnection.relayListListener
settingsListener = serviceConnection.settingsListener
+ splitTunnelling = serviceConnection.splitTunnelling
synchronized(this) {
when (state) {
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/SplitTunnellingFragment.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/SplitTunnellingFragment.kt
index e00bda1d5e..b94883798d 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/SplitTunnellingFragment.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/SplitTunnellingFragment.kt
@@ -52,7 +52,7 @@ class SplitTunnellingFragment : ServiceDependentFragment(OnNoService.GoToLaunchS
override fun onAttach(context: Context) {
super.onAttach(context)
- appListAdapter = AppListAdapter(context)
+ appListAdapter = AppListAdapter(context, splitTunnelling)
}
override fun onSafelyCreateView(
@@ -133,10 +133,12 @@ class SplitTunnellingFragment : ServiceDependentFragment(OnNoService.GoToLaunchS
excludeApplications.visibility = View.VISIBLE
excludeApplicationsFadeOut.reverse()
+ splitTunnelling.enabled = true
}
private fun disable() {
appListAdapter.enabled = false
+ splitTunnelling.enabled = false
excludeApplicationsFadeOut.start()
}
diff --git a/android/src/main/kotlin/net/mullvad/talpid/TalpidVpnService.kt b/android/src/main/kotlin/net/mullvad/talpid/TalpidVpnService.kt
index 8f095641a1..3ad9809928 100644
--- a/android/src/main/kotlin/net/mullvad/talpid/TalpidVpnService.kt
+++ b/android/src/main/kotlin/net/mullvad/talpid/TalpidVpnService.kt
@@ -16,6 +16,9 @@ open class TalpidVpnService : VpnService() {
}
private var currentTunConfig = defaultTunConfig()
+ private var tunIsStale = false
+
+ protected var disallowedApps: List<String>? = null
val connectivityListener = ConnectivityListener()
@@ -31,13 +34,14 @@ open class TalpidVpnService : VpnService() {
synchronized(this) {
val tunDevice = activeTunDevice
- if (config == currentTunConfig && tunDevice != null) {
+ if (config == currentTunConfig && tunDevice != null && !tunIsStale) {
return tunDevice
} else {
val newTunDevice = createTun(config)
currentTunConfig = config
activeTunDevice = newTunDevice
+ tunIsStale = false
return newTunDevice
}
@@ -73,6 +77,12 @@ open class TalpidVpnService : VpnService() {
}
}
+ fun markTunAsStale() {
+ synchronized(this) {
+ tunIsStale = true
+ }
+ }
+
private fun createTun(config: TunConfig): Int {
if (VpnService.prepare(this) != null) {
// VPN permission wasn't granted
@@ -92,6 +102,12 @@ open class TalpidVpnService : VpnService() {
addRoute(route.address, route.prefixLength.toInt())
}
+ disallowedApps?.let { apps ->
+ for (app in apps) {
+ addDisallowedApplication(app)
+ }
+ }
+
setMtu(config.mtu)
setBlocking(false)
}