diff options
| author | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2019-05-22 18:14:28 -0300 |
|---|---|---|
| committer | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2019-05-22 18:14:28 -0300 |
| commit | f4faedbceb31316b796c530779d22365de7c0f16 (patch) | |
| tree | 367b9904455e3f52130ebb244bba1352d92d1ad8 | |
| parent | 11a05dad217354464ce8f47c2b66cb4851e090f1 (diff) | |
| parent | fd735631e62ccf5d375b454afb7a51ce6b7466e6 (diff) | |
| download | mullvadvpn-f4faedbceb31316b796c530779d22365de7c0f16.tar.xz mullvadvpn-f4faedbceb31316b796c530779d22365de7c0f16.zip | |
Merge branch 'auto-login-on-android'
16 files changed, 222 insertions, 5 deletions
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/LaunchFragment.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/LaunchFragment.kt new file mode 100644 index 0000000000..043c8efe15 --- /dev/null +++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/LaunchFragment.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.content.Context +import android.os.Bundle +import android.support.v4.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup + +class LaunchFragment : Fragment() { + private lateinit var accountTokenCheckJob: Deferred<Boolean> + private lateinit var advanceToNextScreenJob: Job + + override fun onAttach(context: Context) { + super.onAttach(context) + accountTokenCheckJob = checkForAccountToken() + advanceToNextScreenJob = advanceToNextScreen() + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ) = inflater.inflate(R.layout.launch, container, false) + + override fun onDestroy() { + accountTokenCheckJob.cancel() + advanceToNextScreenJob.cancel() + super.onDestroy() + } + + private fun checkForAccountToken() = GlobalScope.async(Dispatchers.Default) { + val parentActivity = activity as MainActivity + val daemon = parentActivity.asyncDaemon.await() + val settings = daemon.getSettings() + + settings.accountToken != null + } + + private fun advanceToNextScreen() = GlobalScope.launch(Dispatchers.Main) { + val accountTokenIsSet = accountTokenCheckJob.await() + + if (accountTokenIsSet) { + advanceToConnectScreen() + } else { + advanceToLoginScreen() + } + } + + private fun advanceToLoginScreen() { + fragmentManager?.beginTransaction()?.apply { + replace(R.id.main_fragment, LoginFragment()) + commit() + } + } + + private fun advanceToConnectScreen() { + fragmentManager?.beginTransaction()?.apply { + replace(R.id.main_fragment, ConnectFragment()) + commit() + } + } +} diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/LoginFragment.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/LoginFragment.kt index 3ead35333c..dd5fd1a41c 100644 --- a/android/src/main/kotlin/net/mullvad/mullvadvpn/LoginFragment.kt +++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/LoginFragment.kt @@ -65,6 +65,7 @@ class LoginFragment : Fragment() { val accountData = daemon.getAccountData(accountToken) if (accountData != null) { + daemon.setAccount(accountToken) true } else { false diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/MainActivity.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/MainActivity.kt index b751bf63d9..f9eb6d9a29 100644 --- a/android/src/main/kotlin/net/mullvad/mullvadvpn/MainActivity.kt +++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/MainActivity.kt @@ -38,7 +38,7 @@ class MainActivity : FragmentActivity() { private fun addInitialFragment() { supportFragmentManager?.beginTransaction()?.apply { - add(R.id.main_fragment, LoginFragment()) + add(R.id.main_fragment, LaunchFragment()) commit() } } diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/MullvadDaemon.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/MullvadDaemon.kt index c7025ea644..152eaac970 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.Settings class MullvadDaemon { init { @@ -9,6 +10,8 @@ class MullvadDaemon { } external fun getAccountData(accountToken: String): AccountData? + external fun getSettings(): Settings + external fun setAccount(accountToken: String?) private external fun initialize() } diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/model/Settings.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/model/Settings.kt new file mode 100644 index 0000000000..1254492b57 --- /dev/null +++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/model/Settings.kt @@ -0,0 +1,4 @@ +package net.mullvad.mullvadvpn.model + +data class Settings(var accountToken: String?) { +} diff --git a/android/src/main/res/drawable-hdpi/launch_logo.png b/android/src/main/res/drawable-hdpi/launch_logo.png Binary files differnew file mode 100644 index 0000000000..542ba7986f --- /dev/null +++ b/android/src/main/res/drawable-hdpi/launch_logo.png diff --git a/android/src/main/res/drawable-mdpi/launch_logo.png b/android/src/main/res/drawable-mdpi/launch_logo.png Binary files differnew file mode 100644 index 0000000000..2ee89ae828 --- /dev/null +++ b/android/src/main/res/drawable-mdpi/launch_logo.png diff --git a/android/src/main/res/drawable-xhdpi/launch_logo.png b/android/src/main/res/drawable-xhdpi/launch_logo.png Binary files differnew file mode 100644 index 0000000000..c68c053832 --- /dev/null +++ b/android/src/main/res/drawable-xhdpi/launch_logo.png diff --git a/android/src/main/res/drawable-xxhdpi/launch_logo.png b/android/src/main/res/drawable-xxhdpi/launch_logo.png Binary files differnew file mode 100644 index 0000000000..1604009282 --- /dev/null +++ b/android/src/main/res/drawable-xxhdpi/launch_logo.png diff --git a/android/src/main/res/drawable-xxxhdpi/launch_logo.png b/android/src/main/res/drawable-xxxhdpi/launch_logo.png Binary files differnew file mode 100644 index 0000000000..8a72edd366 --- /dev/null +++ b/android/src/main/res/drawable-xxxhdpi/launch_logo.png diff --git a/android/src/main/res/layout/launch.xml b/android/src/main/res/layout/launch.xml new file mode 100644 index 0000000000..d8cf918727 --- /dev/null +++ b/android/src/main/res/layout/launch.xml @@ -0,0 +1,37 @@ +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + > + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:orientation="vertical" + android:gravity="center" + > + <ImageView + android:layout_width="120dp" + android:layout_height="120dp" + android:layout_marginBottom="4dp" + android:src="@drawable/launch_logo" + /> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginBottom="4dp" + android:textColor="@color/white60" + android:textSize="24sp" + android:textStyle="bold" + android:text="@string/app_name" + android:textAllCaps="true" + /> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textColor="@color/white40" + android:textSize="14sp" + android:text="@string/connecting_to_daemon" + /> + </LinearLayout> +</FrameLayout> diff --git a/android/src/main/res/values/strings.xml b/android/src/main/res/values/strings.xml index 24f8c9867e..4a3d46b2c8 100644 --- a/android/src/main/res/values/strings.xml +++ b/android/src/main/res/values/strings.xml @@ -1,6 +1,8 @@ <resources> <string name="app_name">Mullvad VPN</string> + <string name="connecting_to_daemon">Connecting to daemon...</string> + <string name="login_title">Login</string> <string name="login_description">Enter your account number</string> <string name="login_hint">0000 0000 0000 0000</string> diff --git a/mullvad-jni/src/daemon_interface.rs b/mullvad-jni/src/daemon_interface.rs index 6b0e907eda..21dabea9aa 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; +use mullvad_types::{account::AccountData, settings::Settings}; #[derive(Debug, err_derive::Error)] pub enum Error { @@ -45,6 +45,22 @@ impl DaemonInterface { .map_err(Error::RpcError) } + pub fn get_settings(&self) -> Result<Settings> { + let (tx, rx) = oneshot::channel(); + + self.send_command(ManagementCommand::GetSettings(tx))?; + + Ok(rx.wait().map_err(|_| Error::NoResponse)?) + } + + pub fn set_account(&self, account_token: Option<String>) -> Result<()> { + let (tx, rx) = oneshot::channel(); + + self.send_command(ManagementCommand::SetAccount(tx, account_token))?; + + rx.wait().map_err(|_| Error::NoResponse) + } + fn send_command(&self, command: ManagementCommand) -> Result<()> { let sender = self.command_sender.as_ref().ok_or(Error::NoSender)?; diff --git a/mullvad-jni/src/from_java.rs b/mullvad-jni/src/from_java.rs index 526a83e1fb..11b98ad753 100644 --- a/mullvad-jni/src/from_java.rs +++ b/mullvad-jni/src/from_java.rs @@ -1,4 +1,8 @@ -use jni::{objects::JString, JNIEnv}; +use jni::{ + objects::{JObject, JString}, + JNIEnv, +}; +use std::ops::Deref; pub trait FromJava<'env> { type JavaType: 'env; @@ -6,6 +10,22 @@ pub trait FromJava<'env> { fn from_java(env: &JNIEnv<'env>, source: Self::JavaType) -> Self; } +impl<'env, T> FromJava<'env> for Option<T> +where + T: FromJava<'env>, + T::JavaType: Deref<Target = JObject<'env>>, +{ + type JavaType = T::JavaType; + + fn from_java(env: &JNIEnv<'env>, source: Self::JavaType) -> Self { + if source.is_null() { + None + } else { + Some(T::from_java(env, source)) + } + } +} + impl<'env> FromJava<'env> for String { type JavaType = JString<'env>; diff --git a/mullvad-jni/src/into_java.rs b/mullvad-jni/src/into_java.rs index 952338ccb7..4f8fc3f287 100644 --- a/mullvad-jni/src/into_java.rs +++ b/mullvad-jni/src/into_java.rs @@ -3,7 +3,7 @@ use jni::{ objects::{JObject, JString, JValue}, JNIEnv, }; -use mullvad_types::account::AccountData; +use mullvad_types::{account::AccountData, settings::Settings}; pub trait IntoJava<'env> { type JavaType; @@ -11,6 +11,21 @@ pub trait IntoJava<'env> { fn into_java(self, env: &JNIEnv<'env>) -> Self::JavaType; } +impl<'env, T> IntoJava<'env> for Option<T> +where + T: IntoJava<'env>, + T::JavaType: From<JObject<'env>>, +{ + type JavaType = T::JavaType; + + fn into_java(self, env: &JNIEnv<'env>) -> Self::JavaType { + match self { + Some(data) => data.into_java(env), + None => T::JavaType::from(JObject::null()), + } + } +} + impl<'env> IntoJava<'env> for String { type JavaType = JString<'env>; @@ -31,3 +46,16 @@ impl<'env> IntoJava<'env> for AccountData { .expect("Failed to create AccountData Java object") } } + +impl<'env> IntoJava<'env> for Settings { + type JavaType = JObject<'env>; + + fn into_java(self, env: &JNIEnv<'env>) -> Self::JavaType { + let class = get_class("net/mullvad/mullvadvpn/model/Settings"); + let account_token = env.auto_local(JObject::from(self.get_account_token().into_java(env))); + let parameters = [JValue::Object(account_token.as_obj())]; + + env.new_object(&class, "(Ljava/lang/String;)V", ¶meters) + .expect("Failed to create Settings Java object") + } +} diff --git a/mullvad-jni/src/lib.rs b/mullvad-jni/src/lib.rs index 35d3825dcf..6195b56b52 100644 --- a/mullvad-jni/src/lib.rs +++ b/mullvad-jni/src/lib.rs @@ -18,7 +18,10 @@ use talpid_types::{tunnel::TunnelStateTransition, ErrorExt}; const LOG_FILENAME: &str = "daemon.log"; -const CLASSES_TO_LOAD: &[&str] = &["net/mullvad/mullvadvpn/model/AccountData"]; +const CLASSES_TO_LOAD: &[&str] = &[ + "net/mullvad/mullvadvpn/model/AccountData", + "net/mullvad/mullvadvpn/model/Settings", +]; lazy_static! { static ref DAEMON_INTERFACE: Mutex<DaemonInterface> = Mutex::new(DaemonInterface::new()); @@ -162,3 +165,36 @@ 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_getSettings<'env, 'this>( + env: JNIEnv<'env>, + _: JObject<'this>, +) -> JObject<'env> { + let daemon = DAEMON_INTERFACE.lock(); + + match daemon.get_settings() { + Ok(settings) => settings.into_java(&env), + Err(error) => { + log::error!("{}", error.display_chain_with_msg("Failed to get settings")); + JObject::null() + } + } +} + +#[no_mangle] +#[allow(non_snake_case)] +pub extern "system" fn Java_net_mullvad_mullvadvpn_MullvadDaemon_setAccount( + env: JNIEnv, + _: JObject, + accountToken: JString, +) { + let daemon = DAEMON_INTERFACE.lock(); + + let account = <Option<String> as FromJava>::from_java(&env, accountToken); + + if let Err(error) = daemon.set_account(account) { + log::error!("{}", error.display_chain_with_msg("Failed to set account")); + } +} |
