diff options
| author | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2019-05-23 06:45:49 -0300 |
|---|---|---|
| committer | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2019-05-23 06:45:49 -0300 |
| commit | a995adbc781a4afd7142cb4d22fe6edffbe20607 (patch) | |
| tree | 051ff21120c1693e6a844469a62fe3b9405de9f0 | |
| parent | f4faedbceb31316b796c530779d22365de7c0f16 (diff) | |
| parent | 70ce3664e0e5b2b643181a4ce5e7685639cc9eed (diff) | |
| download | mullvadvpn-a995adbc781a4afd7142cb4d22fe6edffbe20607.tar.xz mullvadvpn-a995adbc781a4afd7142cb4d22fe6edffbe20607.zip | |
Merge branch 'show-relay-list-on-android'
14 files changed, 209 insertions, 199 deletions
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/MainActivity.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/MainActivity.kt index f9eb6d9a29..b68671afbd 100644 --- a/android/src/main/kotlin/net/mullvad/mullvadvpn/MainActivity.kt +++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/MainActivity.kt @@ -1,8 +1,10 @@ package net.mullvad.mullvadvpn import kotlinx.coroutines.async +import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import kotlinx.coroutines.CompletableDeferred +import kotlinx.coroutines.Deferred import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.Job @@ -10,6 +12,9 @@ import kotlinx.coroutines.Job import android.os.Bundle import android.support.v4.app.FragmentActivity +import net.mullvad.mullvadvpn.relaylist.RelayItem +import net.mullvad.mullvadvpn.relaylist.RelayList + class MainActivity : FragmentActivity() { val activityCreated = CompletableDeferred<Unit>() @@ -17,7 +22,12 @@ class MainActivity : FragmentActivity() { val daemon get() = runBlocking { asyncDaemon.await() } - var selectedRelayItemCode: String? = null + var asyncRelayList: Deferred<RelayList> = fetchRelayList() + private set + val relayList: RelayList + get() = runBlocking { asyncRelayList.await() } + + var selectedRelayItem: RelayItem? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -31,6 +41,7 @@ class MainActivity : FragmentActivity() { } override fun onDestroy() { + asyncRelayList.cancel() asyncDaemon.cancel() super.onDestroy() @@ -48,4 +59,8 @@ class MainActivity : FragmentActivity() { ApiRootCaFile().extract(this@MainActivity) MullvadDaemon() } + + private fun fetchRelayList() = GlobalScope.async(Dispatchers.Default) { + RelayList(asyncDaemon.await().getRelayLocations()) + } } diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/MullvadDaemon.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/MullvadDaemon.kt index 152eaac970..b01bccb5a4 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.RelayList import net.mullvad.mullvadvpn.model.Settings class MullvadDaemon { @@ -10,6 +11,7 @@ class MullvadDaemon { } external fun getAccountData(accountToken: String): AccountData? + external fun getRelayLocations(): RelayList external fun getSettings(): Settings external fun setAccount(accountToken: String?) diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/SelectLocationFragment.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/SelectLocationFragment.kt index 369e4d9289..7b1673c448 100644 --- a/android/src/main/kotlin/net/mullvad/mullvadvpn/SelectLocationFragment.kt +++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/SelectLocationFragment.kt @@ -10,6 +10,7 @@ import android.view.ViewGroup import android.widget.ImageButton import net.mullvad.mullvadvpn.relaylist.RelayItemDividerDecoration +import net.mullvad.mullvadvpn.relaylist.RelayList import net.mullvad.mullvadvpn.relaylist.RelayListAdapter class SelectLocationFragment : Fragment() { @@ -32,11 +33,12 @@ class SelectLocationFragment : Fragment() { } private fun configureRelayList(relayList: RecyclerView) { - val parentActivity = activity as MainActivity? - val relayListAdapter = RelayListAdapter(parentActivity?.selectedRelayItemCode) + val parentActivity = activity as MainActivity + val relayListAdapter = + RelayListAdapter(parentActivity.relayList, parentActivity.selectedRelayItem) - relayListAdapter.onSelect = { relayItemCode -> - parentActivity?.selectedRelayItemCode = relayItemCode + relayListAdapter.onSelect = { relayItem -> + parentActivity.selectedRelayItem = relayItem close() } diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/model/Relay.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/model/Relay.kt new file mode 100644 index 0000000000..85c062c4c6 --- /dev/null +++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/model/Relay.kt @@ -0,0 +1,4 @@ +package net.mullvad.mullvadvpn.model + +data class Relay(val hostname: String) { +} diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/model/RelayList.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/model/RelayList.kt new file mode 100644 index 0000000000..ac3b02096e --- /dev/null +++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/model/RelayList.kt @@ -0,0 +1,4 @@ +package net.mullvad.mullvadvpn.model + +data class RelayList(val countries: List<RelayListCountry>) { +} diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/model/RelayListCity.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/model/RelayListCity.kt new file mode 100644 index 0000000000..98dd1f2ce6 --- /dev/null +++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/model/RelayListCity.kt @@ -0,0 +1,4 @@ +package net.mullvad.mullvadvpn.model + +data class RelayListCity(val name: String, val code: String, val relays: List<Relay>) { +} diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/model/RelayListCountry.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/model/RelayListCountry.kt new file mode 100644 index 0000000000..037b055a0d --- /dev/null +++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/model/RelayListCountry.kt @@ -0,0 +1,4 @@ +package net.mullvad.mullvadvpn.model + +data class RelayListCountry(val name: String, val code: String, val cities: List<RelayListCity>) { +} diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayCity.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayCity.kt index 182a0ae3e5..a5e1d5cce8 100644 --- a/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayCity.kt +++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayCity.kt @@ -47,6 +47,4 @@ class RelayCity( } fun getRelayCount(): Int = relays.size - - fun findRelayByCode(code: String): RelayItem? = relays.find { relay -> relay.code == code } } diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayCountry.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayCountry.kt index ab78172b51..80b63875d5 100644 --- a/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayCountry.kt +++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayCountry.kt @@ -45,18 +45,4 @@ class RelayCountry( } fun getRelayCount(): Int = cities.map { city -> city.getRelayCount() }.sum() - - fun findRelayItemByCode(cityCode: String, relayCode: String?): RelayItem? { - for (city in cities) { - if (city.code == cityCode) { - if (relayCode != null) { - return city.findRelayByCode("$cityCode-$relayCode") - } else { - return city - } - } - } - - return null - } } diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayList.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayList.kt new file mode 100644 index 0000000000..a70ac13eaa --- /dev/null +++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayList.kt @@ -0,0 +1,17 @@ +package net.mullvad.mullvadvpn.relaylist + +class RelayList { + val countries: List<RelayCountry> + + constructor(model: net.mullvad.mullvadvpn.model.RelayList) { + countries = model.countries.map { country -> + val cities = country.cities.map { city -> + val relays = city.relays.map { relay -> Relay(relay.hostname) } + + RelayCity(city.name, city.code, false, relays) + } + + RelayCountry(country.name, country.code, false, cities) + } + } +} diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayListAdapter.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayListAdapter.kt index 583df4899c..de3336a4ea 100644 --- a/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayListAdapter.kt +++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayListAdapter.kt @@ -9,17 +9,14 @@ import android.view.ViewGroup import net.mullvad.mullvadvpn.R -class RelayListAdapter(private val initialSelectedItemCode: String?) : Adapter<RelayItemHolder>() { - private val relayList = fakeRelayList +class RelayListAdapter( + private val relayList: RelayList, + private var selectedItem: RelayItem? +) : Adapter<RelayItemHolder>() { private val activeIndices = LinkedList<WeakReference<RelayListAdapterPosition>>() - private var selectedItem: RelayItem? = null private var selectedItemHolder: RelayItemHolder? = null - var onSelect: ((String?) -> Unit)? = null - - init { - initialSelectedItemCode?.let { code -> selectedItem = findRelayItemByCode(code) } - } + var onSelect: ((RelayItem?) -> Unit)? = null override fun onCreateViewHolder(parentView: ViewGroup, type: Int): RelayItemHolder { val inflater = LayoutInflater.from(parentView.context) @@ -34,7 +31,7 @@ class RelayListAdapter(private val initialSelectedItemCode: String?) : Adapter<R override fun onBindViewHolder(holder: RelayItemHolder, position: Int) { var remaining = position - for (country in relayList) { + for (country in relayList.countries) { val itemOrCount = country.getItem(remaining) when (itemOrCount) { @@ -47,7 +44,8 @@ class RelayListAdapter(private val initialSelectedItemCode: String?) : Adapter<R } } - override fun getItemCount() = relayList.map { country -> country.visibleItemCount }.sum() + override fun getItemCount() = + relayList.countries.map { country -> country.visibleItemCount }.sum() fun selectItem(item: RelayItem?, holder: RelayItemHolder?) { selectedItemHolder?.selected = false @@ -56,7 +54,7 @@ class RelayListAdapter(private val initialSelectedItemCode: String?) : Adapter<R selectedItemHolder = holder selectedItemHolder?.apply { selected = true } - onSelect?.invoke(item?.code) + onSelect?.invoke(item) } fun expandItem(itemIndex: RelayListAdapterPosition, childCount: Int) { @@ -102,168 +100,4 @@ class RelayListAdapter(private val initialSelectedItemCode: String?) : Adapter<R holder.selected = false } } - - private fun findRelayItemByCode(code: String): RelayItem? { - val codeParts = code.split('-') - - for (country in relayList) { - if (country.code == codeParts[0]) { - if (codeParts.size == 1) { - return country - } else { - var relayCode: String? = null - - if (codeParts.size == 3) { - relayCode = codeParts[2] - } - - return country.findRelayItemByCode("${codeParts[0]}-${codeParts[1]}", relayCode) - } - } - } - - return null - } } - -val fakeRelayList = listOf( - RelayCountry( - "Australia", - "au", - false, - listOf( - RelayCity( - "Brisbane", - "au-bne", - false, - listOf(Relay("au-bne-001")) - ), - RelayCity( - "Melbourne", - "au-mel", - false, - listOf(Relay("au-mel-002"), Relay("au-mel-003"), Relay("au-mel-004")) - ), - RelayCity( - "Perth", - "au-per", - false, - listOf(Relay("au-per-001")) - ), - RelayCity( - "Sydney", - "au-syd", - false, - listOf( - Relay("au1-wireguard"), - Relay("au-syd-001"), - Relay("au-syd-002"), - Relay("au-mel-003") - ) - ) - ) - ), - RelayCountry( - "South Africa", - "za", - false, - listOf( - RelayCity( - "Johannesburg", - "za-jnb", - false, - listOf(Relay("za-jnb-001")) - ) - ) - ), - RelayCountry( - "Sweden", - "se", - false, - listOf( - RelayCity( - "Gothenburg", - "se-got", - false, - listOf( - Relay("se3-wireguard"), - Relay("se5-wireguard"), - Relay("se-got-001"), - Relay("se-got-002"), - Relay("se-got-003"), - Relay("se-got-004"), - Relay("se-got-005"), - Relay("se-got-006"), - Relay("se-got-007") - ) - ), - RelayCity( - "Helsingborg", - "se-hel", - false, - listOf( - Relay("se-hel-001"), - Relay("se-hel-002"), - Relay("se-hel-003"), - Relay("se-hel-004"), - Relay("se-hel-007"), - Relay("se-hel-008") - ) - ), - RelayCity( - "Malmö", - "se-mma", - false, - listOf( - Relay("se4-wireguard"), - Relay("se-mma-001"), - Relay("se-mma-002"), - Relay("se-mma-003"), - Relay("se-mma-004"), - Relay("se-mma-005"), - Relay("se-mma-006"), - Relay("se-mma-007"), - Relay("se-mma-008"), - Relay("se-mma-009"), - Relay("se-mma-010") - ) - ), - RelayCity( - "Stockholm", - "se-sto", - false, - listOf( - Relay("se2-wireguard"), - Relay("se6-wireguard"), - Relay("se7-wireguard"), - Relay("se8-wireguard"), - Relay("se-sto-001"), - Relay("se-sto-002"), - Relay("se-sto-003"), - Relay("se-sto-004"), - Relay("se-sto-005"), - Relay("se-sto-006"), - Relay("se-sto-007"), - Relay("se-sto-008"), - Relay("se-sto-009"), - Relay("se-sto-010"), - Relay("se-sto-011"), - Relay("se-sto-012"), - Relay("se-sto-013"), - Relay("se-sto-014"), - Relay("se-sto-015"), - Relay("se-sto-016"), - Relay("se-sto-017"), - Relay("se-sto-018"), - Relay("se-sto-019"), - Relay("se-sto-020"), - Relay("se-sto-021"), - Relay("se-sto-022"), - Relay("se-sto-023"), - Relay("se-sto-024"), - Relay("se-sto-025") - ) - ) - ) - ) -) diff --git a/mullvad-jni/src/daemon_interface.rs b/mullvad-jni/src/daemon_interface.rs index 21dabea9aa..e0ffa13c84 100644 --- a/mullvad-jni/src/daemon_interface.rs +++ b/mullvad-jni/src/daemon_interface.rs @@ -1,6 +1,6 @@ use futures::{sync::oneshot, Future}; use mullvad_daemon::{DaemonCommandSender, ManagementCommand}; -use mullvad_types::{account::AccountData, settings::Settings}; +use mullvad_types::{account::AccountData, relay_list::RelayList, settings::Settings}; #[derive(Debug, err_derive::Error)] pub enum Error { @@ -45,6 +45,14 @@ impl DaemonInterface { .map_err(Error::RpcError) } + pub fn get_relay_locations(&self) -> Result<RelayList> { + let (tx, rx) = oneshot::channel(); + + self.send_command(ManagementCommand::GetRelayLocations(tx))?; + + Ok(rx.wait().map_err(|_| Error::NoResponse)?) + } + pub fn get_settings(&self) -> Result<Settings> { let (tx, rx) = oneshot::channel(); diff --git a/mullvad-jni/src/into_java.rs b/mullvad-jni/src/into_java.rs index 4f8fc3f287..22b582bc1b 100644 --- a/mullvad-jni/src/into_java.rs +++ b/mullvad-jni/src/into_java.rs @@ -1,9 +1,14 @@ use crate::get_class; use jni::{ - objects::{JObject, JString, JValue}, + objects::{JList, JObject, JString, JValue}, + sys::jint, JNIEnv, }; -use mullvad_types::{account::AccountData, settings::Settings}; +use mullvad_types::{ + account::AccountData, + relay_list::{Relay, RelayList, RelayListCity, RelayListCountry}, + settings::Settings, +}; pub trait IntoJava<'env> { type JavaType; @@ -34,6 +39,36 @@ impl<'env> IntoJava<'env> for String { } } +impl<'env, T> IntoJava<'env> for Vec<T> +where + T: IntoJava<'env>, + JObject<'env>: From<T::JavaType>, +{ + type JavaType = JObject<'env>; + + fn into_java(self, env: &JNIEnv<'env>) -> Self::JavaType { + let class = get_class("java/util/ArrayList"); + let initial_capacity = self.len(); + let parameters = [JValue::Int(initial_capacity as jint)]; + + let list_object = env + .new_object(&class, "(I)V", ¶meters) + .expect("Failed to create ArrayList object"); + + let list = + JList::from_env(env, list_object).expect("Failed to create JList from ArrayList"); + + for element in self { + let java_element = env.auto_local(JObject::from(element.into_java(env))); + + list.add(java_element.as_obj()) + .expect("Failed to add element to ArrayList"); + } + + list_object + } +} + impl<'env> IntoJava<'env> for AccountData { type JavaType = JObject<'env>; @@ -47,6 +82,78 @@ impl<'env> IntoJava<'env> for AccountData { } } +impl<'env> IntoJava<'env> for RelayList { + type JavaType = JObject<'env>; + + fn into_java(self, env: &JNIEnv<'env>) -> Self::JavaType { + let class = get_class("net/mullvad/mullvadvpn/model/RelayList"); + let relay_countries = env.auto_local(self.countries.into_java(env)); + let parameters = [JValue::Object(relay_countries.as_obj())]; + + env.new_object(&class, "(Ljava/util/List;)V", ¶meters) + .expect("Failed to create RelayList Java object") + } +} + +impl<'env> IntoJava<'env> for RelayListCountry { + type JavaType = JObject<'env>; + + fn into_java(self, env: &JNIEnv<'env>) -> Self::JavaType { + let class = get_class("net/mullvad/mullvadvpn/model/RelayListCountry"); + let name = env.auto_local(JObject::from(self.name.into_java(env))); + let code = env.auto_local(JObject::from(self.code.into_java(env))); + let relay_cities = env.auto_local(self.cities.into_java(env)); + let parameters = [ + JValue::Object(name.as_obj()), + JValue::Object(code.as_obj()), + JValue::Object(relay_cities.as_obj()), + ]; + + env.new_object( + &class, + "(Ljava/lang/String;Ljava/lang/String;Ljava/util/List;)V", + ¶meters, + ) + .expect("Failed to create RelayListCountry Java object") + } +} + +impl<'env> IntoJava<'env> for RelayListCity { + type JavaType = JObject<'env>; + + fn into_java(self, env: &JNIEnv<'env>) -> Self::JavaType { + let class = get_class("net/mullvad/mullvadvpn/model/RelayListCity"); + let name = env.auto_local(JObject::from(self.name.into_java(env))); + let code = env.auto_local(JObject::from(self.code.into_java(env))); + let relays = env.auto_local(self.relays.into_java(env)); + let parameters = [ + JValue::Object(name.as_obj()), + JValue::Object(code.as_obj()), + JValue::Object(relays.as_obj()), + ]; + + env.new_object( + &class, + "(Ljava/lang/String;Ljava/lang/String;Ljava/util/List;)V", + ¶meters, + ) + .expect("Failed to create RelayListCity Java object") + } +} + +impl<'env> IntoJava<'env> for Relay { + type JavaType = JObject<'env>; + + fn into_java(self, env: &JNIEnv<'env>) -> Self::JavaType { + let class = get_class("net/mullvad/mullvadvpn/model/Relay"); + let hostname = env.auto_local(JObject::from(self.hostname.into_java(env))); + let parameters = [JValue::Object(hostname.as_obj())]; + + env.new_object(&class, "(Ljava/lang/String;)V", ¶meters) + .expect("Failed to create Relay Java object") + } +} + impl<'env> IntoJava<'env> for Settings { type JavaType = JObject<'env>; diff --git a/mullvad-jni/src/lib.rs b/mullvad-jni/src/lib.rs index 6195b56b52..95fccfb5ce 100644 --- a/mullvad-jni/src/lib.rs +++ b/mullvad-jni/src/lib.rs @@ -19,7 +19,12 @@ use talpid_types::{tunnel::TunnelStateTransition, ErrorExt}; const LOG_FILENAME: &str = "daemon.log"; const CLASSES_TO_LOAD: &[&str] = &[ + "java/util/ArrayList", "net/mullvad/mullvadvpn/model/AccountData", + "net/mullvad/mullvadvpn/model/Relay", + "net/mullvad/mullvadvpn/model/RelayList", + "net/mullvad/mullvadvpn/model/RelayListCity", + "net/mullvad/mullvadvpn/model/RelayListCountry", "net/mullvad/mullvadvpn/model/Settings", ]; @@ -168,6 +173,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_getRelayLocations<'env, 'this>( + env: JNIEnv<'env>, + _: JObject<'this>, +) -> JObject<'env> { + let daemon = DAEMON_INTERFACE.lock(); + + match daemon.get_relay_locations() { + Ok(relay_list) => relay_list.into_java(&env), + Err(error) => { + log::error!( + "{}", + error.display_chain_with_msg("Failed to get relay locations") + ); + JObject::null() + } + } +} + +#[no_mangle] +#[allow(non_snake_case)] pub extern "system" fn Java_net_mullvad_mullvadvpn_MullvadDaemon_getSettings<'env, 'this>( env: JNIEnv<'env>, _: JObject<'this>, |
