diff options
| -rw-r--r-- | CHANGELOG.md | 1 | ||||
| -rw-r--r-- | android/src/main/kotlin/net/mullvad/mullvadvpn/dataproxy/SettingsListener.kt | 26 | ||||
| -rw-r--r-- | android/src/main/kotlin/net/mullvad/mullvadvpn/model/Settings.kt | 3 | ||||
| -rw-r--r-- | android/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadDaemon.kt | 5 | ||||
| -rw-r--r-- | android/src/main/kotlin/net/mullvad/mullvadvpn/ui/PreferencesFragment.kt | 43 | ||||
| -rw-r--r-- | android/src/main/kotlin/net/mullvad/talpid/TalpidVpnService.kt | 2 | ||||
| -rw-r--r-- | android/src/main/res/layout/preferences.xml | 34 | ||||
| -rw-r--r-- | android/src/main/res/values/strings.xml | 4 | ||||
| -rw-r--r-- | mullvad-jni/src/daemon_interface.rs | 8 | ||||
| -rw-r--r-- | mullvad-jni/src/lib.rs | 22 | ||||
| -rw-r--r-- | mullvad-types/src/settings/mod.rs | 1 | ||||
| -rw-r--r-- | talpid-core/src/tunnel/tun_provider/android/mod.rs | 4 |
12 files changed, 130 insertions, 23 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 527360851a..ae3e998ca6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ Line wrap the file at 100 chars. Th #### Android - Add option to enable or disable local network sharing. - Show account history in login fragment +- Add option to enable auto-connecting behavior ### Changed - Change project copyright and company name from Amagicom AB to Mullvad VPN AB diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/dataproxy/SettingsListener.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/dataproxy/SettingsListener.kt index be27eb7b89..a79307811d 100644 --- a/android/src/main/kotlin/net/mullvad/mullvadvpn/dataproxy/SettingsListener.kt +++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/dataproxy/SettingsListener.kt @@ -3,15 +3,21 @@ package net.mullvad.mullvadvpn.dataproxy import net.mullvad.mullvadvpn.model.RelaySettings import net.mullvad.mullvadvpn.model.Settings import net.mullvad.mullvadvpn.service.MullvadDaemon +import net.mullvad.talpid.util.EventNotifier class SettingsListener(val daemon: MullvadDaemon) { + var settings: Settings = daemon.getSettings() + private set(value) { + settingsNotifier.notify(value) + field = value + } + + private val settingsNotifier: EventNotifier<Settings> = EventNotifier(settings) + private val listenerId = daemon.onSettingsChange.subscribe { maybeSettings -> maybeSettings?.let { settings -> handleNewSettings(settings) } } - var settings: Settings? = null - private set - var onAccountNumberChange: ((String?) -> Unit)? = null set(value) { synchronized(this) { @@ -43,6 +49,16 @@ class SettingsListener(val daemon: MullvadDaemon) { if (listenerId != -1) { daemon.onSettingsChange.unsubscribe(listenerId) } + + settingsNotifier.unsubscribeAll() + } + + fun subscribe(listener: (Settings) -> Unit): Int { + return settingsNotifier.subscribe(listener) + } + + fun unsubscribe(id: Int) { + settingsNotifier.unsubscribe(id) } private fun handleNewSettings(newSettings: Settings) { @@ -55,10 +71,6 @@ class SettingsListener(val daemon: MullvadDaemon) { onRelaySettingsChange?.invoke(newSettings.relaySettings) } - if (settings?.allowLan != newSettings.allowLan) { - onAllowLanChange?.invoke(newSettings.allowLan) - } - settings = newSettings } } diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/model/Settings.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/model/Settings.kt index 6cc83b157f..77a45e03a8 100644 --- a/android/src/main/kotlin/net/mullvad/mullvadvpn/model/Settings.kt +++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/model/Settings.kt @@ -3,5 +3,6 @@ package net.mullvad.mullvadvpn.model data class Settings( var accountToken: String?, var relaySettings: RelaySettings, - var allowLan: Boolean + var allowLan: Boolean, + var autoConnect: Boolean ) diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadDaemon.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadDaemon.kt index a0dabf1a53..df608dab69 100644 --- a/android/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadDaemon.kt +++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadDaemon.kt @@ -89,6 +89,10 @@ class MullvadDaemon(val vpnService: MullvadVpnService) { setAllowLan(daemonInterfaceAddress, allowLan) } + fun setAutoConnect(autoConnect: Boolean) { + setAutoConnect(daemonInterfaceAddress, autoConnect) + } + fun shutdown() { shutdown(daemonInterfaceAddress) } @@ -122,6 +126,7 @@ class MullvadDaemon(val vpnService: MullvadVpnService) { private external fun getWireguardKey(daemonInterfaceAddress: Long): PublicKey? private external fun setAccount(daemonInterfaceAddress: Long, accountToken: String?) private external fun setAllowLan(daemonInterfaceAddress: Long, allowLan: Boolean) + private external fun setAutoConnect(daemonInterfaceAddress: Long, alwaysOn: Boolean) private external fun shutdown(daemonInterfaceAddress: Long) private external fun updateRelaySettings( daemonInterfaceAddress: Long, diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/PreferencesFragment.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/PreferencesFragment.kt index 160caafd22..387864f26c 100644 --- a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/PreferencesFragment.kt +++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/PreferencesFragment.kt @@ -9,10 +9,13 @@ import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.Job import kotlinx.coroutines.launch import net.mullvad.mullvadvpn.R +import net.mullvad.mullvadvpn.model.Settings class PreferencesFragment : ServiceDependentFragment(OnNoService.GoBack) { private lateinit var allowLanToggle: CellSwitch + private lateinit var autoConnectToggle: CellSwitch + private var subscriptionId: Int? = null private var updateUiJob: Job? = null override fun onSafelyCreateView( @@ -28,11 +31,7 @@ class PreferencesFragment : ServiceDependentFragment(OnNoService.GoBack) { allowLanToggle = view.findViewById<CellSwitch>(R.id.allow_lan_toggle).apply { settingsListener.settings?.let { settings -> - if (settings.allowLan) { - forcefullySetState(CellSwitch.State.ON) - } else { - forcefullySetState(CellSwitch.State.OFF) - } + forcefullySetState(boolToSwitchState(settings.allowLan)) } listener = { state -> @@ -43,23 +42,41 @@ class PreferencesFragment : ServiceDependentFragment(OnNoService.GoBack) { } } - settingsListener.onAllowLanChange = { allowLan -> - updateUiJob?.cancel() - updateUiJob = updateUi(allowLan) + autoConnectToggle = view.findViewById<CellSwitch>(R.id.auto_connect_toggle).apply { + settingsListener.settings?.let { settings -> + forcefullySetState(boolToSwitchState(settings.autoConnect)) + } + + listener = { state -> + when (state) { + CellSwitch.State.ON -> daemon.setAutoConnect(true) + CellSwitch.State.OFF -> daemon.setAutoConnect(false) + } + } } + settingsListener.subscribe({ settings -> updateUi(settings) }) + return view } + private fun updateUi(settings: Settings) { + updateUiJob?.cancel() + updateUiJob = GlobalScope.launch(Dispatchers.Main) { + allowLanToggle.state = boolToSwitchState(settings.allowLan) + autoConnectToggle.state = boolToSwitchState(settings.autoConnect) + } + } + override fun onSafelyDestroyView() { - settingsListener.onAllowLanChange = null + subscriptionId?.let { id -> settingsListener.unsubscribe(id) } } - private fun updateUi(allowLan: Boolean) = GlobalScope.launch(Dispatchers.Main) { - if (allowLan) { - allowLanToggle.state = CellSwitch.State.ON + private fun boolToSwitchState(pref: Boolean): CellSwitch.State { + if (pref) { + return CellSwitch.State.ON } else { - allowLanToggle.state = CellSwitch.State.OFF + return CellSwitch.State.OFF } } } diff --git a/android/src/main/kotlin/net/mullvad/talpid/TalpidVpnService.kt b/android/src/main/kotlin/net/mullvad/talpid/TalpidVpnService.kt index 3d9200f345..e2ea8c5818 100644 --- a/android/src/main/kotlin/net/mullvad/talpid/TalpidVpnService.kt +++ b/android/src/main/kotlin/net/mullvad/talpid/TalpidVpnService.kt @@ -34,7 +34,7 @@ open class TalpidVpnService : VpnService() { val vpnInterface = builder.establish() - return vpnInterface.detachFd() + return vpnInterface?.detachFd() ?: 0 } fun bypass(socket: Int): Boolean { diff --git a/android/src/main/res/layout/preferences.xml b/android/src/main/res/layout/preferences.xml index 59d42635fe..a03726482d 100644 --- a/android/src/main/res/layout/preferences.xml +++ b/android/src/main/res/layout/preferences.xml @@ -41,6 +41,40 @@ android:textStyle="bold" android:text="@string/settings_preferences" /> + <LinearLayout android:id="@+id/auto_connect" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="24dp" + android:paddingHorizontal="16dp" + android:background="@drawable/cell_button_background" + android:gravity="center" + > + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="1" + android:paddingHorizontal="8dp" + android:paddingVertical="17dp" + android:textColor="@color/white" + android:textSize="20sp" + android:textStyle="bold" + android:text="@string/auto_connect" + /> + <net.mullvad.mullvadvpn.ui.CellSwitch android:id="@+id/auto_connect_toggle" + android:layout_width="52dp" + android:layout_height="32dp" + android:layout_weight="0" + /> + </LinearLayout> + <TextView android:id="@+id/auto_connect_footer" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingTop="8dp" + android:paddingHorizontal="24dp" + android:textColor="@color/white60" + android:textSize="13sp" + android:text="@string/auto_connect_footer" + /> <LinearLayout android:id="@+id/allow_lan" android:layout_width="match_parent" android:layout_height="wrap_content" diff --git a/android/src/main/res/values/strings.xml b/android/src/main/res/values/strings.xml index 0a87ff3736..f722cb845c 100644 --- a/android/src/main/res/values/strings.xml +++ b/android/src/main/res/values/strings.xml @@ -45,6 +45,10 @@ <string name="allow_lan_footer"> Allows access to other devices on the same network for sharing, printing etc. </string> + <string name="auto_connect">Auto-connect</string> + <string name="auto_connect_footer"> + Automatically connect to a server when the app launches. + </string> <string name="problem_report_description"> To help you more effectively, your app\'s log file will be attached to this message. Your diff --git a/mullvad-jni/src/daemon_interface.rs b/mullvad-jni/src/daemon_interface.rs index 5515668e08..a376fa6aa8 100644 --- a/mullvad-jni/src/daemon_interface.rs +++ b/mullvad-jni/src/daemon_interface.rs @@ -184,6 +184,14 @@ impl DaemonInterface { rx.wait().map_err(|_| Error::NoResponse) } + pub fn set_auto_connect(&self, auto_connect: bool) -> Result<()> { + let (tx, rx) = oneshot::channel(); + + self.send_command(ManagementCommand::SetAutoConnect(tx, auto_connect))?; + + rx.wait().map_err(|_| Error::NoResponse) + } + pub fn shutdown(&self) -> Result<()> { self.send_command(ManagementCommand::Shutdown) } diff --git a/mullvad-jni/src/lib.rs b/mullvad-jni/src/lib.rs index 5f4cae6e1c..dd1fd939b8 100644 --- a/mullvad-jni/src/lib.rs +++ b/mullvad-jni/src/lib.rs @@ -694,6 +694,28 @@ pub extern "system" fn Java_net_mullvad_mullvadvpn_service_MullvadDaemon_setAllo #[no_mangle] #[allow(non_snake_case)] +pub extern "system" fn Java_net_mullvad_mullvadvpn_service_MullvadDaemon_setAutoConnect( + env: JNIEnv<'_>, + _: JObject<'_>, + daemon_interface_address: jlong, + auto_connect: jboolean, +) { + let env = JnixEnv::from(env); + + if let Some(daemon_interface) = get_daemon_interface(daemon_interface_address) { + let auto_connect = bool::from_java(&env, auto_connect); + + if let Err(error) = daemon_interface.set_auto_connect(auto_connect) { + log::error!( + "{}", + error.display_chain_with_msg("Failed to set auto-connect") + ); + } + } +} + +#[no_mangle] +#[allow(non_snake_case)] pub extern "system" fn Java_net_mullvad_mullvadvpn_service_MullvadDaemon_shutdown( _: JNIEnv<'_>, _: JObject<'_>, diff --git a/mullvad-types/src/settings/mod.rs b/mullvad-types/src/settings/mod.rs index 19f350b7f7..ed7080f67d 100644 --- a/mullvad-types/src/settings/mod.rs +++ b/mullvad-types/src/settings/mod.rs @@ -71,7 +71,6 @@ pub struct Settings { #[cfg_attr(target_os = "android", jnix(skip))] block_when_disconnected: bool, /// If the daemon should connect the VPN tunnel directly on start or not. - #[cfg_attr(target_os = "android", jnix(skip))] auto_connect: bool, /// Options that should be applied to tunnels of a specific type regardless of where the relays /// might be located. diff --git a/talpid-core/src/tunnel/tun_provider/android/mod.rs b/talpid-core/src/tunnel/tun_provider/android/mod.rs index 6de6217a31..3b5b9c45dd 100644 --- a/talpid-core/src/tunnel/tun_provider/android/mod.rs +++ b/talpid-core/src/tunnel/tun_provider/android/mod.rs @@ -60,6 +60,9 @@ pub enum Error { #[error(display = "Timed out while waiting for tunnel device to receive data")] TunnelDeviceTimeout, + + #[error(display = "Failed to create tunnel device")] + TunnelDeviceError, } /// Factory of tunnel devices on Android. @@ -334,6 +337,7 @@ impl AndroidTunProvider { .map_err(|cause| Error::CallMethod("createTun", cause))?; match result { + JValue::Int(0) => Err(Error::TunnelDeviceError), JValue::Int(fd) => { Self::wait_for_tunnel_up(fd, &config)?; let tun = unsafe { File::from_raw_fd(fd) }; |
