diff options
| author | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2019-06-13 16:33:25 -0300 |
|---|---|---|
| committer | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2019-06-13 16:33:25 -0300 |
| commit | 6e658fb0fef2912840896f35c8d6bde2842a69cf (patch) | |
| tree | 73337ca1d46bac415473eb13014db5cb7f674edb | |
| parent | f1a976619e6aeca61629e49066bfc2ef70bffbd8 (diff) | |
| parent | 4f5e344a2ee88a40d59c3c65be6c74fbb4efd952 (diff) | |
| download | mullvadvpn-6e658fb0fef2912840896f35c8d6bde2842a69cf.tar.xz mullvadvpn-6e658fb0fef2912840896f35c8d6bde2842a69cf.zip | |
Merge branch 'show-location'
| -rw-r--r-- | android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectFragment.kt | 8 | ||||
| -rw-r--r-- | android/src/main/kotlin/net/mullvad/mullvadvpn/LocationInfo.kt | 70 | ||||
| -rw-r--r-- | android/src/main/kotlin/net/mullvad/mullvadvpn/MullvadDaemon.kt | 2 | ||||
| -rw-r--r-- | android/src/main/kotlin/net/mullvad/mullvadvpn/model/GeoIpLocation.kt | 3 | ||||
| -rw-r--r-- | android/src/main/res/layout/connect.xml | 10 | ||||
| -rw-r--r-- | android/src/main/res/values/strings.xml | 1 | ||||
| -rw-r--r-- | mullvad-jni/src/daemon_interface.rs | 12 | ||||
| -rw-r--r-- | mullvad-jni/src/into_java.rs | 24 | ||||
| -rw-r--r-- | mullvad-jni/src/lib.rs | 21 |
9 files changed, 142 insertions, 9 deletions
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectFragment.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectFragment.kt index ae3194c5aa..c4b5fdb5cd 100644 --- a/android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectFragment.kt +++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectFragment.kt @@ -1,5 +1,6 @@ package net.mullvad.mullvadvpn +import kotlinx.coroutines.async import kotlinx.coroutines.launch import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.Deferred @@ -19,6 +20,7 @@ import android.view.View import android.view.ViewGroup import android.widget.Button +import net.mullvad.mullvadvpn.model.GeoIpLocation import net.mullvad.mullvadvpn.model.TunnelStateTransition class ConnectFragment : Fragment() { @@ -26,6 +28,7 @@ class ConnectFragment : Fragment() { private lateinit var headerBar: HeaderBar private lateinit var notificationBanner: NotificationBanner private lateinit var status: ConnectionStatus + private lateinit var locationInfo: LocationInfo private lateinit var parentActivity: MainActivity @@ -35,6 +38,8 @@ class ConnectFragment : Fragment() { private var fetchInitialStateJob = fetchInitialState() private var generateWireguardKeyJob = generateWireguardKey() + private var lastKnownRealLocation: GeoIpLocation? = null + private var activeAction: Job? = null private var attachListenerJob: Job? = null private var updateViewJob: Job? = null @@ -61,6 +66,7 @@ class ConnectFragment : Fragment() { headerBar = HeaderBar(view, context!!) notificationBanner = NotificationBanner(view) status = ConnectionStatus(view, context!!) + locationInfo = LocationInfo(view, daemon) actionButton = ConnectActionButton(view) actionButton.apply { @@ -149,6 +155,7 @@ class ConnectFragment : Fragment() { } private fun disconnect() { + updateView(TunnelStateTransition.Disconnecting()) activeAction?.cancel() activeAction = GlobalScope.launch(Dispatchers.Default) { @@ -172,6 +179,7 @@ class ConnectFragment : Fragment() { headerBar.setState(state) notificationBanner.setState(state) status.setState(state) + locationInfo.setState(state) } private fun openSwitchLocationScreen() { diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/LocationInfo.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/LocationInfo.kt new file mode 100644 index 0000000000..b25406c90e --- /dev/null +++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/LocationInfo.kt @@ -0,0 +1,70 @@ +package net.mullvad.mullvadvpn + +import kotlinx.coroutines.async +import kotlinx.coroutines.launch +import kotlinx.coroutines.Deferred +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.Job + +import android.view.View +import android.widget.TextView + +import net.mullvad.mullvadvpn.model.GeoIpLocation +import net.mullvad.mullvadvpn.model.TunnelStateTransition + +class LocationInfo(val parentView: View, val daemon: Deferred<MullvadDaemon>) { + private val country: TextView = parentView.findViewById(R.id.country) + private val city: TextView = parentView.findViewById(R.id.city) + private val hostname: TextView = parentView.findViewById(R.id.hostname) + + private var lastKnownRealLocation: GeoIpLocation? = null + + private var activeFetch: Job? = null + + var location: GeoIpLocation? = null + set(value) { + field = value + updateViews(value) + } + + fun setState(state: TunnelStateTransition) { + activeFetch?.cancel() + activeFetch = null + + when (state) { + is TunnelStateTransition.Disconnected -> activeFetch = fetchRealLocation() + is TunnelStateTransition.Connecting -> activeFetch = fetchRelayLocation() + is TunnelStateTransition.Connected -> activeFetch = fetchRelayLocation() + is TunnelStateTransition.Disconnecting -> location = lastKnownRealLocation + is TunnelStateTransition.Blocked -> location = null + } + } + + fun updateViews(location: GeoIpLocation?) { + country.text = location?.country ?: "" + city.text = location?.city ?: "" + hostname.text = location?.hostname ?: "" + } + + private fun fetchRealLocation() = GlobalScope.launch(Dispatchers.Main) { + var realLocation: GeoIpLocation? = null + var remainingAttempts = 10 + + while (realLocation == null && remainingAttempts > 0) { + realLocation = fetchLocation().await() + remainingAttempts -= 1 + } + + lastKnownRealLocation = realLocation + location = realLocation + } + + private fun fetchRelayLocation() = GlobalScope.launch(Dispatchers.Main) { + location = fetchLocation().await() + } + + private fun fetchLocation() = GlobalScope.async(Dispatchers.Default) { + daemon.await().getCurrentLocation() + } +} diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/MullvadDaemon.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/MullvadDaemon.kt index 5dd6401615..d16ba06a1a 100644 --- a/android/src/main/kotlin/net/mullvad/mullvadvpn/MullvadDaemon.kt +++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/MullvadDaemon.kt @@ -1,6 +1,7 @@ package net.mullvad.mullvadvpn import net.mullvad.mullvadvpn.model.AccountData +import net.mullvad.mullvadvpn.model.GeoIpLocation import net.mullvad.mullvadvpn.model.PublicKey import net.mullvad.mullvadvpn.model.RelayList import net.mullvad.mullvadvpn.model.RelaySettingsUpdate @@ -19,6 +20,7 @@ class MullvadDaemon(val vpnService: MullvadVpnService) { external fun disconnect() external fun generateWireguardKey(): Boolean external fun getAccountData(accountToken: String): AccountData? + external fun getCurrentLocation(): GeoIpLocation? external fun getRelayLocations(): RelayList external fun getSettings(): Settings external fun getState(): TunnelStateTransition diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/model/GeoIpLocation.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/model/GeoIpLocation.kt new file mode 100644 index 0000000000..ed7ccb7e66 --- /dev/null +++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/model/GeoIpLocation.kt @@ -0,0 +1,3 @@ +package net.mullvad.mullvadvpn.model + +data class GeoIpLocation(val country: String, val city: String?, val hostname: String?) diff --git a/android/src/main/res/layout/connect.xml b/android/src/main/res/layout/connect.xml index d35679aba4..19440b794f 100644 --- a/android/src/main/res/layout/connect.xml +++ b/android/src/main/res/layout/connect.xml @@ -96,31 +96,29 @@ android:text="@string/unsecured_connection" android:textAllCaps="true" /> - <TextView + <TextView android:id="@+id/country" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="@color/white" android:textSize="34sp" android:textStyle="bold" - android:text="@string/country" + android:text="" /> - <TextView + <TextView android:id="@+id/city" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="@color/white" android:textSize="34sp" android:textStyle="bold" android:text="" - android:visibility="invisible" /> - <TextView + <TextView android:id="@+id/hostname" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="@color/white" android:textSize="16sp" android:textStyle="bold" android:text="" - android:visibility="invisible" /> </LinearLayout> diff --git a/android/src/main/res/values/strings.xml b/android/src/main/res/values/strings.xml index 632feefb6f..fc8ec8d0c7 100644 --- a/android/src/main/res/values/strings.xml +++ b/android/src/main/res/values/strings.xml @@ -16,7 +16,6 @@ <string name="creating_secure_connection">Creating secure connection</string> <string name="secure_connection">Secure connection</string> <string name="blocking_internet">Blocking internet</string> - <string name="country">Country</string> <string name="connect">Secure my connection</string> <string name="cancel">Cancel</string> <string name="disconnect">Disconnect</string> diff --git a/mullvad-jni/src/daemon_interface.rs b/mullvad-jni/src/daemon_interface.rs index fb398c5461..1565a9fd0d 100644 --- a/mullvad-jni/src/daemon_interface.rs +++ b/mullvad-jni/src/daemon_interface.rs @@ -1,8 +1,8 @@ use futures::{sync::oneshot, Future}; use mullvad_daemon::{DaemonCommandSender, ManagementCommand}; use mullvad_types::{ - account::AccountData, relay_constraints::RelaySettingsUpdate, relay_list::RelayList, - settings::Settings, states::TargetState, + account::AccountData, location::GeoIpLocation, relay_constraints::RelaySettingsUpdate, + relay_list::RelayList, settings::Settings, states::TargetState, }; use talpid_types::{net::wireguard, tunnel::TunnelStateTransition}; @@ -82,6 +82,14 @@ impl DaemonInterface { .map_err(Error::RpcError) } + pub fn get_current_location(&self) -> Result<Option<GeoIpLocation>> { + let (tx, rx) = oneshot::channel(); + + self.send_command(ManagementCommand::GetCurrentLocation(tx))?; + + Ok(rx.wait().map_err(|_| Error::NoResponse)?) + } + pub fn get_relay_locations(&self) -> Result<RelayList> { let (tx, rx) = oneshot::channel(); diff --git a/mullvad-jni/src/into_java.rs b/mullvad-jni/src/into_java.rs index 06116d8c3b..c49ec4a2c8 100644 --- a/mullvad-jni/src/into_java.rs +++ b/mullvad-jni/src/into_java.rs @@ -8,6 +8,7 @@ use jni::{ }; use mullvad_types::{ account::AccountData, + location::GeoIpLocation, relay_constraints::{Constraint, LocationConstraint, RelayConstraints, RelaySettings}, relay_list::{Relay, RelayList, RelayListCity, RelayListCountry}, settings::Settings, @@ -215,6 +216,29 @@ impl<'env> IntoJava<'env> for TunConfig { } } +impl<'env> IntoJava<'env> for GeoIpLocation { + type JavaType = JObject<'env>; + + fn into_java(self, env: &JNIEnv<'env>) -> Self::JavaType { + let class = get_class("net/mullvad/mullvadvpn/model/GeoIpLocation"); + let country = env.auto_local(JObject::from(self.country.into_java(env))); + let city = env.auto_local(JObject::from(self.city.into_java(env))); + let hostname = env.auto_local(JObject::from(self.hostname.into_java(env))); + let parameters = [ + JValue::Object(country.as_obj()), + JValue::Object(city.as_obj()), + JValue::Object(hostname.as_obj()), + ]; + + env.new_object( + &class, + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V", + ¶meters, + ) + .expect("Failed to create GeoIpLocation Java object") + } +} + impl<'env> IntoJava<'env> for RelayList { type JavaType = JObject<'env>; diff --git a/mullvad-jni/src/lib.rs b/mullvad-jni/src/lib.rs index 62a6dbe277..d17fc13bd5 100644 --- a/mullvad-jni/src/lib.rs +++ b/mullvad-jni/src/lib.rs @@ -30,6 +30,7 @@ const CLASSES_TO_LOAD: &[&str] = &[ "net/mullvad/mullvadvpn/model/AccountData", "net/mullvad/mullvadvpn/model/Constraint$Any", "net/mullvad/mullvadvpn/model/Constraint$Only", + "net/mullvad/mullvadvpn/model/GeoIpLocation", "net/mullvad/mullvadvpn/model/InetNetwork", "net/mullvad/mullvadvpn/model/LocationConstraint$City", "net/mullvad/mullvadvpn/model/LocationConstraint$Country", @@ -263,6 +264,26 @@ pub extern "system" fn Java_net_mullvad_mullvadvpn_MullvadDaemon_getAccountData< #[no_mangle] #[allow(non_snake_case)] +pub extern "system" fn Java_net_mullvad_mullvadvpn_MullvadDaemon_getCurrentLocation<'env, 'this>( + env: JNIEnv<'env>, + _: JObject<'this>, +) -> JObject<'env> { + let daemon = DAEMON_INTERFACE.lock(); + + match daemon.get_current_location() { + Ok(location) => location.into_java(&env), + Err(error) => { + log::error!( + "{}", + error.display_chain_with_msg("Failed to get current location") + ); + JObject::null() + } + } +} + +#[no_mangle] +#[allow(non_snake_case)] pub extern "system" fn Java_net_mullvad_mullvadvpn_MullvadDaemon_getRelayLocations<'env, 'this>( env: JNIEnv<'env>, _: JObject<'this>, |
