summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJanito Vaqueiro Ferreira Filho <janito@mullvad.net>2019-06-13 16:33:25 -0300
committerJanito Vaqueiro Ferreira Filho <janito@mullvad.net>2019-06-13 16:33:25 -0300
commit6e658fb0fef2912840896f35c8d6bde2842a69cf (patch)
tree73337ca1d46bac415473eb13014db5cb7f674edb
parentf1a976619e6aeca61629e49066bfc2ef70bffbd8 (diff)
parent4f5e344a2ee88a40d59c3c65be6c74fbb4efd952 (diff)
downloadmullvadvpn-6e658fb0fef2912840896f35c8d6bde2842a69cf.tar.xz
mullvadvpn-6e658fb0fef2912840896f35c8d6bde2842a69cf.zip
Merge branch 'show-location'
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectFragment.kt8
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/LocationInfo.kt70
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/MullvadDaemon.kt2
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/model/GeoIpLocation.kt3
-rw-r--r--android/src/main/res/layout/connect.xml10
-rw-r--r--android/src/main/res/values/strings.xml1
-rw-r--r--mullvad-jni/src/daemon_interface.rs12
-rw-r--r--mullvad-jni/src/into_java.rs24
-rw-r--r--mullvad-jni/src/lib.rs21
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",
+ &parameters,
+ )
+ .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>,